summary refs log tree commit diff
path: root/drivers/net
diff options
context:
space:
mode:
authorJohn W. Linville <linville@tuxdriver.com>2011-08-22 14:28:50 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-08-22 14:28:50 -0400
commitb38d355eaa223e420d0c45ff7a3279ea811552c5 (patch)
tree4a6b3341e1b8b72afdc19e3b9bfe8c40219c04aa /drivers/net
parentca1ba7caa68520864e4b9227e67f3bbc6fed373b (diff)
parentaf2bf4b4ee58d262a9a5c1d4ce6f81835058f8b5 (diff)
downloadlinux-b38d355eaa223e420d0c45ff7a3279ea811552c5.tar.gz
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Conflicts:
	drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.c
	drivers/staging/ath6kl/os/linux/ar6000_drv.c
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/ath/Kconfig1
-rw-r--r--drivers/net/wireless/ath/Makefile1
-rw-r--r--drivers/net/wireless/ath/ath5k/ahb.c4
-rw-r--r--drivers/net/wireless/ath/ath5k/ani.c1
-rw-r--r--drivers/net/wireless/ath/ath5k/ani.h4
-rw-r--r--drivers/net/wireless/ath/ath5k/ath5k.h98
-rw-r--r--drivers/net/wireless/ath/ath5k/attach.c18
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c31
-rw-r--r--drivers/net/wireless/ath/ath5k/base.h55
-rw-r--r--drivers/net/wireless/ath/ath5k/caps.c2
-rw-r--r--drivers/net/wireless/ath/ath5k/debug.c15
-rw-r--r--drivers/net/wireless/ath/ath5k/desc.c1
-rw-r--r--drivers/net/wireless/ath/ath5k/dma.c1
-rw-r--r--drivers/net/wireless/ath/ath5k/eeprom.c10
-rw-r--r--drivers/net/wireless/ath/ath5k/gpio.c1
-rw-r--r--drivers/net/wireless/ath/ath5k/initvals.c1
-rw-r--r--drivers/net/wireless/ath/ath5k/led.c1
-rw-r--r--drivers/net/wireless/ath/ath5k/mac80211-ops.c5
-rw-r--r--drivers/net/wireless/ath/ath5k/pci.c4
-rw-r--r--drivers/net/wireless/ath/ath5k/pcu.c5
-rw-r--r--drivers/net/wireless/ath/ath5k/phy.c91
-rw-r--r--drivers/net/wireless/ath/ath5k/qcu.c10
-rw-r--r--drivers/net/wireless/ath/ath5k/reset.c79
-rw-r--r--drivers/net/wireless/ath/ath5k/rfkill.c2
-rw-r--r--drivers/net/wireless/ath/ath5k/sysfs.c1
-rw-r--r--drivers/net/wireless/ath/ath5k/trace.h3
-rw-r--r--drivers/net/wireless/ath/ath6kl/Kconfig15
-rw-r--r--drivers/net/wireless/ath/ath6kl/Makefile35
-rw-r--r--drivers/net/wireless/ath/ath6kl/bmi.c692
-rw-r--r--drivers/net/wireless/ath/ath6kl/bmi.h250
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c1538
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.h39
-rw-r--r--drivers/net/wireless/ath/ath6kl/common.h180
-rw-r--r--drivers/net/wireless/ath/ath6kl/core.h544
-rw-r--r--drivers/net/wireless/ath/ath6kl/debug.c150
-rw-r--r--drivers/net/wireless/ath/ath6kl/debug.h105
-rw-r--r--drivers/net/wireless/ath/ath6kl/hif-ops.h72
-rw-r--r--drivers/net/wireless/ath/ath6kl/hif.h207
-rw-r--r--drivers/net/wireless/ath/ath6kl/htc.c2457
-rw-r--r--drivers/net/wireless/ath/ath6kl/htc.h607
-rw-r--r--drivers/net/wireless/ath/ath6kl/htc_hif.c641
-rw-r--r--drivers/net/wireless/ath/ath6kl/htc_hif.h92
-rw-r--r--drivers/net/wireless/ath/ath6kl/init.c1303
-rw-r--r--drivers/net/wireless/ath/ath6kl/main.c1337
-rw-r--r--drivers/net/wireless/ath/ath6kl/node.c234
-rw-r--r--drivers/net/wireless/ath/ath6kl/sdio.c912
-rw-r--r--drivers/net/wireless/ath/ath6kl/target.h331
-rw-r--r--drivers/net/wireless/ath/ath6kl/txrx.c1457
-rw-r--r--drivers/net/wireless/ath/ath6kl/wmi.c2743
-rw-r--r--drivers/net/wireless/ath/ath6kl/wmi.h2018
-rw-r--r--drivers/net/wireless/ath/ath9k/ahb.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h190
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_eeprom.c150
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_mac.c15
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h6
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c18
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.c15
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c60
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_4k.c135
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_9287.c122
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_def.c150
-rw-r--r--drivers/net/wireless/ath/ath9k/gpio.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/htc.h3
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_init.c1
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c10
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h9
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c8
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.c16
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c10
-rw-r--r--drivers/net/wireless/ath/ath9k/pci.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.h6
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c10
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c12
-rw-r--r--drivers/net/wireless/ath/regd.h2
-rw-r--r--drivers/net/wireless/ath/regd_common.h2
-rw-r--r--drivers/net/wireless/b43/Kconfig6
-rw-r--r--drivers/net/wireless/b43/main.c2
-rw-r--r--drivers/net/wireless/b43legacy/b43legacy.h1
-rw-r--r--drivers/net/wireless/b43legacy/dma.c374
-rw-r--r--drivers/net/wireless/b43legacy/dma.h107
-rw-r--r--drivers/net/wireless/b43legacy/main.c4
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.c1
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-3945-led.c1
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-3945-rs.c1
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-3945.c1
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-4965-led.c1
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-4965-rs.c1
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-4965.c1
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-led.c1
-rw-r--r--drivers/net/wireless/iwlegacy/iwl3945-base.c1
-rw-r--r--drivers/net/wireless/iwlegacy/iwl4965-base.c1
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig17
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-1000.c16
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-2000.c24
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c13
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c20
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-calib.c69
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-hw.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-lib.c47
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.c1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rxon.c23
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-tx.c30
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c388
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h34
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h29
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-led.c1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c19
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.c10
-rw-r--r--drivers/net/wireless/libertas/cfg.c69
-rw-r--r--drivers/net/wireless/libertas/cfg.h1
-rw-r--r--drivers/net/wireless/libertas/cmd.c6
-rw-r--r--drivers/net/wireless/libertas/decl.h4
-rw-r--r--drivers/net/wireless/libertas/dev.h28
-rw-r--r--drivers/net/wireless/libertas/ethtool.c1
-rw-r--r--drivers/net/wireless/libertas/if_sdio.c277
-rw-r--r--drivers/net/wireless/libertas/if_spi.c4
-rw-r--r--drivers/net/wireless/libertas/if_usb.c13
-rw-r--r--drivers/net/wireless/libertas/main.c180
-rw-r--r--drivers/net/wireless/libertas/mesh.c77
-rw-r--r--drivers/net/wireless/libertas/mesh.h27
-rw-r--r--drivers/net/wireless/libertas/rx.c1
-rw-r--r--drivers/net/wireless/libertas/tx.c1
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c6
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c209
-rw-r--r--drivers/net/wireless/mwifiex/fw.h15
-rw-r--r--drivers/net/wireless/mwifiex/init.c21
-rw-r--r--drivers/net/wireless/mwifiex/ioctl.h5
-rw-r--r--drivers/net/wireless/mwifiex/join.c32
-rw-r--r--drivers/net/wireless/mwifiex/main.c4
-rw-r--r--drivers/net/wireless/mwifiex/main.h55
-rw-r--r--drivers/net/wireless/mwifiex/scan.c1578
-rw-r--r--drivers/net/wireless/mwifiex/sta_event.c9
-rw-r--r--drivers/net/wireless/mwifiex/sta_ioctl.c230
-rw-r--r--drivers/net/wireless/orinoco/wext.c1
-rw-r--r--drivers/net/wireless/rndis_wlan.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c39
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c39
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.c46
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c1
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c34
-rw-r--r--drivers/net/wireless/rtlwifi/pci.c37
-rw-r--r--drivers/net/wireless/rtlwifi/pci.h26
-rw-r--r--drivers/net/wireless/wl1251/cmd.h2
-rw-r--r--drivers/net/wireless/wl1251/wl12xx_80211.h2
-rw-r--r--drivers/net/wireless/wl12xx/cmd.h4
-rw-r--r--drivers/net/wireless/wl12xx/main.c2
-rw-r--r--drivers/net/wireless/wl12xx/scan.h6
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx.h4
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx_80211.h2
156 files changed, 20353 insertions, 3380 deletions
diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig
index d1b23067619f..073548836413 100644
--- a/drivers/net/wireless/ath/Kconfig
+++ b/drivers/net/wireless/ath/Kconfig
@@ -25,5 +25,6 @@ config ATH_DEBUG
 source "drivers/net/wireless/ath/ath5k/Kconfig"
 source "drivers/net/wireless/ath/ath9k/Kconfig"
 source "drivers/net/wireless/ath/carl9170/Kconfig"
+source "drivers/net/wireless/ath/ath6kl/Kconfig"
 
 endif
diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile
index 0e8f528c81c0..d1214696a35b 100644
--- a/drivers/net/wireless/ath/Makefile
+++ b/drivers/net/wireless/ath/Makefile
@@ -1,6 +1,7 @@
 obj-$(CONFIG_ATH5K)		+= ath5k/
 obj-$(CONFIG_ATH9K_HW)		+= ath9k/
 obj-$(CONFIG_CARL9170)		+= carl9170/
+obj-$(CONFIG_ATH6KL)		+= ath6kl/
 
 obj-$(CONFIG_ATH_COMMON)	+= ath.o
 
diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c
index a2a167363dbf..e5be7e701816 100644
--- a/drivers/net/wireless/ath/ath5k/ahb.c
+++ b/drivers/net/wireless/ath/ath5k/ahb.c
@@ -169,7 +169,7 @@ static int ath_ahb_probe(struct platform_device *pdev)
 			__set_bit(ATH_STAT_2G_DISABLED, ah->status);
 	}
 
-	ret = ath5k_init_softc(ah, &ath_ahb_bus_ops);
+	ret = ath5k_init_ah(ah, &ath_ahb_bus_ops);
 	if (ret != 0) {
 		dev_err(&pdev->dev, "failed to attach device, err=%d\n", ret);
 		ret = -ENODEV;
@@ -214,7 +214,7 @@ static int ath_ahb_remove(struct platform_device *pdev)
 		__raw_writel(reg, (void __iomem *) AR5K_AR5312_ENABLE);
 	}
 
-	ath5k_deinit_softc(ah);
+	ath5k_deinit_ah(ah);
 	platform_set_drvdata(pdev, NULL);
 	ieee80211_free_hw(hw);
 
diff --git a/drivers/net/wireless/ath/ath5k/ani.c b/drivers/net/wireless/ath/ath5k/ani.c
index 603ae15f139b..bea90e6be70e 100644
--- a/drivers/net/wireless/ath/ath5k/ani.c
+++ b/drivers/net/wireless/ath/ath5k/ani.c
@@ -15,7 +15,6 @@
  */
 
 #include "ath5k.h"
-#include "base.h"
 #include "reg.h"
 #include "debug.h"
 #include "ani.h"
diff --git a/drivers/net/wireless/ath/ath5k/ani.h b/drivers/net/wireless/ath/ath5k/ani.h
index 034015397093..7358b6c83c6c 100644
--- a/drivers/net/wireless/ath/ath5k/ani.h
+++ b/drivers/net/wireless/ath/ath5k/ani.h
@@ -16,6 +16,10 @@
 #ifndef ANI_H
 #define ANI_H
 
+#include "../ath.h"
+
+enum ath5k_phy_error_code;
+
 /* these thresholds are relative to the ATH5K_ANI_LISTEN_PERIOD */
 #define ATH5K_ANI_LISTEN_PERIOD		100
 #define ATH5K_ANI_OFDM_TRIG_HIGH	500
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index 277d5cbe0068..fecbcd9a4259 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -131,13 +131,6 @@
 #define AR5K_REG_DISABLE_BITS(ah, _reg, _flags)			\
 	ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) & ~(_flags), _reg)
 
-/* Access to PHY registers */
-#define AR5K_PHY_READ(ah, _reg)					\
-	ath5k_hw_reg_read(ah, (ah)->ah_phy + ((_reg) << 2))
-
-#define AR5K_PHY_WRITE(ah, _reg, _val)					\
-	ath5k_hw_reg_write(ah, _val, (ah)->ah_phy + ((_reg) << 2))
-
 /* Access QCU registers per queue */
 #define AR5K_REG_READ_Q(ah, _reg, _queue)				\
 	(ath5k_hw_reg_read(ah, _reg) & (1 << _queue))			\
@@ -166,7 +159,6 @@
 #define AR5K_TUNE_DMA_BEACON_RESP		2
 #define AR5K_TUNE_SW_BEACON_RESP		10
 #define AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF	0
-#define AR5K_TUNE_RADAR_ALERT			false
 #define AR5K_TUNE_MIN_TX_FIFO_THRES		1
 #define AR5K_TUNE_MAX_TX_FIFO_THRES	((IEEE80211_MAX_FRAME_LEN / 64) + 1)
 #define AR5K_TUNE_REGISTER_TIMEOUT		20000
@@ -295,17 +287,6 @@ enum ath5k_radio {
  * Common silicon revision/version values
  */
 
-enum ath5k_srev_type {
-	AR5K_VERSION_MAC,
-	AR5K_VERSION_RAD,
-};
-
-struct ath5k_srev_name {
-	const char		*sr_name;
-	enum ath5k_srev_type	sr_type;
-	u_int			sr_val;
-};
-
 #define AR5K_SREV_UNKNOWN	0xffff
 
 #define AR5K_SREV_AR5210	0x00 /* Crete */
@@ -424,7 +405,6 @@ enum ath5k_driver_mode {
 	AR5K_MODE_11A		=	0,
 	AR5K_MODE_11B		=	1,
 	AR5K_MODE_11G		=	2,
-	AR5K_MODE_XR		=	0,
 	AR5K_MODE_MAX		=	3
 };
 
@@ -694,33 +674,6 @@ struct ath5k_gain {
 #define AR5K_SLOT_TIME_20	880
 #define AR5K_SLOT_TIME_MAX	0xffff
 
-/* channel_flags */
-#define	CHANNEL_CW_INT	0x0008	/* Contention Window interference detected */
-#define	CHANNEL_CCK	0x0020	/* CCK channel */
-#define	CHANNEL_OFDM	0x0040	/* OFDM channel */
-#define	CHANNEL_2GHZ	0x0080	/* 2GHz channel. */
-#define	CHANNEL_5GHZ	0x0100	/* 5GHz channel */
-#define	CHANNEL_PASSIVE	0x0200	/* Only passive scan allowed */
-#define	CHANNEL_DYN	0x0400	/* Dynamic CCK-OFDM channel (for g operation) */
-#define	CHANNEL_XR	0x0800	/* XR channel */
-
-#define	CHANNEL_A	(CHANNEL_5GHZ | CHANNEL_OFDM)
-#define	CHANNEL_B	(CHANNEL_2GHZ | CHANNEL_CCK)
-#define	CHANNEL_G	(CHANNEL_2GHZ | CHANNEL_OFDM)
-#define	CHANNEL_X	(CHANNEL_5GHZ | CHANNEL_OFDM | CHANNEL_XR)
-
-#define	CHANNEL_ALL	(CHANNEL_OFDM | CHANNEL_CCK | \
-			 CHANNEL_2GHZ | CHANNEL_5GHZ)
-
-#define CHANNEL_MODES		CHANNEL_ALL
-
-/*
- * Used internally for ath5k_hw_reset_tx_queue().
- * Also see struct struct ieee80211_channel.
- */
-#define IS_CHAN_XR(_c)	((_c->hw_value & CHANNEL_XR) != 0)
-#define IS_CHAN_B(_c)	((_c->hw_value & CHANNEL_B) != 0)
-
 /*
  * The following structure is used to map 2GHz channels to
  * 5GHz Atheros channels.
@@ -977,7 +930,7 @@ enum ath5k_power_mode {
 struct ath5k_capabilities {
 	/*
 	 * Supported PHY modes
-	 * (ie. CHANNEL_A, CHANNEL_B, ...)
+	 * (ie. AR5K_MODE_11A, AR5K_MODE_11B, ...)
 	 */
 	DECLARE_BITMAP(cap_mode, AR5K_MODE_MAX);
 
@@ -1013,16 +966,6 @@ struct ath5k_nfcal_hist {
 	s16 nfval[ATH5K_NF_CAL_HIST_MAX];	/* last few noise floors */
 };
 
-/**
- * struct avg_val - Helper structure for average calculation
- * @avg: contains the actual average value
- * @avg_weight: is used internally during calculation to prevent rounding errors
- */
-struct ath5k_avg_val {
-	int avg;
-	int avg_weight;
-};
-
 #define ATH5K_LED_MAX_NAME_LEN 31
 
 /*
@@ -1148,7 +1091,6 @@ struct ath5k_hw {
 	bool			rx_pending;	/* rx tasklet pending */
 	bool			tx_pending;	/* tx tasklet pending */
 
-	u8			lladdr[ETH_ALEN];
 	u8			bssidmask[ETH_ALEN];
 
 	unsigned int		led_pin,	/* GPIO pin for driving LED */
@@ -1156,7 +1098,6 @@ struct ath5k_hw {
 
 	struct work_struct	reset_work;	/* deferred chip reset */
 
-	unsigned int		rxbufsize;	/* rx size based on mtu */
 	struct list_head	rxbuf;		/* receive buffer */
 	spinlock_t		rxbuflock;
 	u32			*rxlink;	/* link ptr in last RX desc */
@@ -1208,10 +1149,8 @@ struct ath5k_hw {
 
 	enum ath5k_version	ah_version;
 	enum ath5k_radio	ah_radio;
-	u32			ah_phy;
 	u32			ah_mac_srev;
 	u16			ah_mac_version;
-	u16			ah_mac_revision;
 	u16			ah_phy_revision;
 	u16			ah_radio_5ghz_revision;
 	u16			ah_radio_2ghz_revision;
@@ -1279,12 +1218,6 @@ struct ath5k_hw {
 		bool		txp_setup;
 	} ah_txpower;
 
-	struct {
-		bool		r_enabled;
-		int		r_last_alert;
-		struct ieee80211_channel r_last_channel;
-	} ah_radar;
-
 	struct ath5k_nfcal_hist ah_nfcal_hist;
 
 	/* average beacon RSSI in our BSS (used by ANI) */
@@ -1327,36 +1260,13 @@ struct ath_bus_ops {
 extern const struct ieee80211_ops ath5k_hw_ops;
 
 /* Initialization and detach functions */
-int ath5k_init_softc(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops);
-void ath5k_deinit_softc(struct ath5k_hw *ah);
 int ath5k_hw_init(struct ath5k_hw *ah);
 void ath5k_hw_deinit(struct ath5k_hw *ah);
 
 int ath5k_sysfs_register(struct ath5k_hw *ah);
 void ath5k_sysfs_unregister(struct ath5k_hw *ah);
 
-/* base.c */
-struct ath5k_buf;
-struct ath5k_txq;
-
-void ath5k_set_beacon_filter(struct ieee80211_hw *hw, bool enable);
-bool ath5k_any_vif_assoc(struct ath5k_hw *ah);
-void ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
-		    struct ath5k_txq *txq);
-int ath5k_start(struct ieee80211_hw *hw);
-void ath5k_stop(struct ieee80211_hw *hw);
-void ath5k_mode_setup(struct ath5k_hw *ah, struct ieee80211_vif *vif);
-void ath5k_update_bssid_mask_and_opmode(struct ath5k_hw *ah,
-					struct ieee80211_vif *vif);
-int ath5k_chan_set(struct ath5k_hw *ah, struct ieee80211_channel *chan);
-void ath5k_beacon_update_timers(struct ath5k_hw *ah, u64 bc_tsf);
-int ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
-void ath5k_beacon_config(struct ath5k_hw *ah);
-void ath5k_txbuf_free_skb(struct ath5k_hw *ah, struct ath5k_buf *bf);
-void ath5k_rxbuf_free_skb(struct ath5k_hw *ah, struct ath5k_buf *bf);
-
 /*Chip id helper functions */
-const char *ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val);
 int ath5k_hw_read_srev(struct ath5k_hw *ah);
 
 /* LED functions */
@@ -1367,7 +1277,7 @@ void ath5k_unregister_leds(struct ath5k_hw *ah);
 
 
 /* Reset Functions */
-int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial);
+int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel);
 int ath5k_hw_on_hold(struct ath5k_hw *ah);
 int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
 	   struct ieee80211_channel *channel, bool fast, bool skip_pcu);
@@ -1487,13 +1397,13 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel);
 
 /* PHY functions */
 /* Misc PHY functions */
-u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan);
+u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, enum ieee80211_band band);
 int ath5k_hw_phy_disable(struct ath5k_hw *ah);
 /* Gain_F optimization */
 enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah);
 int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah);
 /* PHY/RF channel functions */
-bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags);
+bool ath5k_channel_ok(struct ath5k_hw *ah, struct ieee80211_channel *channel);
 /* PHY calibration */
 void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah);
 int ath5k_hw_phy_calibrate(struct ath5k_hw *ah,
diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c
index f8a6b380d96d..91627dd2c26a 100644
--- a/drivers/net/wireless/ath/ath5k/attach.c
+++ b/drivers/net/wireless/ath/ath5k/attach.c
@@ -25,7 +25,6 @@
 #include "ath5k.h"
 #include "reg.h"
 #include "debug.h"
-#include "base.h"
 
 /**
  * ath5k_hw_post - Power On Self Test helper function
@@ -95,7 +94,7 @@ static int ath5k_hw_post(struct ath5k_hw *ah)
 /**
  * ath5k_hw_init - Check if hw is supported and init the needed structs
  *
- * @ah: The &struct ath5k_hw we got from the driver's init_softc function
+ * @ah: The &struct ath5k_hw associated with the device
  *
  * Check if the device is supported, perform a POST and initialize the needed
  * structs. Returns -ENOMEM if we don't have memory for the needed structs,
@@ -114,7 +113,6 @@ int ath5k_hw_init(struct ath5k_hw *ah)
 	/*
 	 * HW information
 	 */
-	ah->ah_radar.r_enabled = AR5K_TUNE_RADAR_ALERT;
 	ah->ah_bwmode = AR5K_BWMODE_DEFAULT;
 	ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
 	ah->ah_imr = 0;
@@ -137,9 +135,8 @@ int ath5k_hw_init(struct ath5k_hw *ah)
 	else
 		ah->ah_version = AR5K_AR5212;
 
-	/* Get the MAC revision */
+	/* Get the MAC version */
 	ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER);
-	ah->ah_mac_revision = AR5K_REG_MS(srev, AR5K_SREV_REV);
 
 	/* Fill the ath5k_hw struct with the needed functions */
 	ret = ath5k_hw_init_desc_functions(ah);
@@ -147,7 +144,7 @@ int ath5k_hw_init(struct ath5k_hw *ah)
 		goto err;
 
 	/* Bring device out of sleep and reset its units */
-	ret = ath5k_hw_nic_wakeup(ah, 0, true);
+	ret = ath5k_hw_nic_wakeup(ah, NULL);
 	if (ret)
 		goto err;
 
@@ -155,8 +152,7 @@ int ath5k_hw_init(struct ath5k_hw *ah)
 	ah->ah_phy_revision = ath5k_hw_reg_read(ah, AR5K_PHY_CHIP_ID) &
 			0xffffffff;
 	ah->ah_radio_5ghz_revision = ath5k_hw_radio_revision(ah,
-			CHANNEL_5GHZ);
-	ah->ah_phy = AR5K_PHY(0);
+			IEEE80211_BAND_5GHZ);
 
 	/* Try to identify radio chip based on its srev */
 	switch (ah->ah_radio_5ghz_revision & 0xf0) {
@@ -164,14 +160,14 @@ int ath5k_hw_init(struct ath5k_hw *ah)
 		ah->ah_radio = AR5K_RF5111;
 		ah->ah_single_chip = false;
 		ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
-							CHANNEL_2GHZ);
+							IEEE80211_BAND_2GHZ);
 		break;
 	case AR5K_SREV_RAD_5112:
 	case AR5K_SREV_RAD_2112:
 		ah->ah_radio = AR5K_RF5112;
 		ah->ah_single_chip = false;
 		ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
-							CHANNEL_2GHZ);
+							IEEE80211_BAND_2GHZ);
 		break;
 	case AR5K_SREV_RAD_2413:
 		ah->ah_radio = AR5K_RF2413;
@@ -208,7 +204,7 @@ int ath5k_hw_init(struct ath5k_hw *ah)
 			ah->ah_radio = AR5K_RF5111;
 			ah->ah_single_chip = false;
 			ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
-								CHANNEL_2GHZ);
+							IEEE80211_BAND_2GHZ);
 		} else if (ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4) ||
 			   ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4) ||
 			   ah->ah_phy_revision == AR5K_SREV_PHY_2425) {
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index c3119a6caace..e9ea38d0fff6 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -52,6 +52,7 @@
 #include <linux/uaccess.h>
 #include <linux/slab.h>
 #include <linux/etherdevice.h>
+#include <linux/nl80211.h>
 
 #include <net/ieee80211_radiotap.h>
 
@@ -61,6 +62,8 @@
 #include "reg.h"
 #include "debug.h"
 #include "ani.h"
+#include "ath5k.h"
+#include "../regd.h"
 
 #define CREATE_TRACE_POINTS
 #include "trace.h"
@@ -272,20 +275,18 @@ static unsigned int
 ath5k_setup_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels,
 		unsigned int mode, unsigned int max)
 {
-	unsigned int count, size, chfreq, freq, ch;
+	unsigned int count, size, freq, ch;
 	enum ieee80211_band band;
 
 	switch (mode) {
 	case AR5K_MODE_11A:
 		/* 1..220, but 2GHz frequencies are filtered by check_channel */
 		size = 220;
-		chfreq = CHANNEL_5GHZ;
 		band = IEEE80211_BAND_5GHZ;
 		break;
 	case AR5K_MODE_11B:
 	case AR5K_MODE_11G:
 		size = 26;
-		chfreq = CHANNEL_2GHZ;
 		band = IEEE80211_BAND_2GHZ;
 		break;
 	default:
@@ -300,26 +301,19 @@ ath5k_setup_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels,
 		if (freq == 0) /* mapping failed - not a standard channel */
 			continue;
 
+		/* Write channel info, needed for ath5k_channel_ok() */
+		channels[count].center_freq = freq;
+		channels[count].band = band;
+		channels[count].hw_value = mode;
+
 		/* Check if channel is supported by the chipset */
-		if (!ath5k_channel_ok(ah, freq, chfreq))
+		if (!ath5k_channel_ok(ah, &channels[count]))
 			continue;
 
 		if (!modparam_all_channels &&
 		    !ath5k_is_standard_channel(ch, band))
 			continue;
 
-		/* Write channel info and increment counter */
-		channels[count].center_freq = freq;
-		channels[count].band = band;
-		switch (mode) {
-		case AR5K_MODE_11A:
-		case AR5K_MODE_11G:
-			channels[count].hw_value = chfreq | CHANNEL_OFDM;
-			break;
-		case AR5K_MODE_11B:
-			channels[count].hw_value = CHANNEL_B;
-		}
-
 		count++;
 	}
 
@@ -2349,7 +2343,7 @@ ath5k_tx_complete_poll_work(struct work_struct *work)
 \*************************/
 
 int __devinit
-ath5k_init_softc(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops)
+ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops)
 {
 	struct ieee80211_hw *hw = ah->hw;
 	struct ath_common *common;
@@ -2867,7 +2861,6 @@ ath5k_init(struct ieee80211_hw *hw)
 	}
 
 	SET_IEEE80211_PERM_ADDR(hw, mac);
-	memcpy(&ah->lladdr, mac, ETH_ALEN);
 	/* All MAC address bits matter for ACKs */
 	ath5k_update_bssid_mask_and_opmode(ah, NULL);
 
@@ -2903,7 +2896,7 @@ err:
 }
 
 void
-ath5k_deinit_softc(struct ath5k_hw *ah)
+ath5k_deinit_ah(struct ath5k_hw *ah)
 {
 	struct ieee80211_hw *hw = ah->hw;
 
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h
index a81f28d5bddc..6c94c7ff2350 100644
--- a/drivers/net/wireless/ath/ath5k/base.h
+++ b/drivers/net/wireless/ath/ath5k/base.h
@@ -38,19 +38,27 @@
 /*
  * Definitions for the Atheros Wireless LAN controller driver.
  */
-#ifndef _DEV_ATH_ATHVAR_H
-#define _DEV_ATH_ATHVAR_H
+#ifndef _DEV_ATH5K_BASE_H
+#define _DEV_ATH5K_BASE_H
 
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/wireless.h>
-#include <linux/if_ether.h>
-#include <linux/rfkill.h>
-#include <linux/workqueue.h>
+struct ieee80211_vif;
+struct ieee80211_hw;
+struct ath5k_hw;
+struct ath5k_txq;
+struct ieee80211_channel;
+struct ath_bus_ops;
+enum nl80211_iftype;
 
-#include "ath5k.h"
-#include "../regd.h"
-#include "../ath.h"
+enum ath5k_srev_type {
+	AR5K_VERSION_MAC,
+	AR5K_VERSION_RAD,
+};
+
+struct ath5k_srev_name {
+	const char		*sr_name;
+	enum ath5k_srev_type	sr_type;
+	u_int			sr_val;
+};
 
 struct ath5k_buf {
 	struct list_head	list;
@@ -65,7 +73,6 @@ struct ath5k_vif {
 	enum nl80211_iftype	opmode;
 	int			bslot;
 	struct ath5k_buf	*bbuf; /* beacon buffer */
-	u8			lladdr[ETH_ALEN];
 };
 
 struct ath5k_vif_iter_data {
@@ -78,8 +85,30 @@ struct ath5k_vif_iter_data {
 	enum nl80211_iftype opmode;
 	int n_stas;
 };
+
 void ath5k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif);
+bool ath5k_any_vif_assoc(struct ath5k_hw *ah);
+
+int ath5k_start(struct ieee80211_hw *hw);
+void ath5k_stop(struct ieee80211_hw *hw);
+
+void ath5k_beacon_update_timers(struct ath5k_hw *ah, u64 bc_tsf);
+int ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
+void ath5k_beacon_config(struct ath5k_hw *ah);
+void ath5k_set_beacon_filter(struct ieee80211_hw *hw, bool enable);
+
+void ath5k_update_bssid_mask_and_opmode(struct ath5k_hw *ah,
+					struct ieee80211_vif *vif);
+int ath5k_chan_set(struct ath5k_hw *ah, struct ieee80211_channel *chan);
+void ath5k_txbuf_free_skb(struct ath5k_hw *ah, struct ath5k_buf *bf);
+void ath5k_rxbuf_free_skb(struct ath5k_hw *ah, struct ath5k_buf *bf);
+void ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
+		    struct ath5k_txq *txq);
+
+const char *ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val);
 
+int ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops);
+void ath5k_deinit_ah(struct ath5k_hw *ah);
 
 /* Check whether BSSID mask is supported */
 #define ath5k_hw_hasbssidmask(_ah) (ah->ah_version == AR5K_AR5212)
@@ -87,4 +116,4 @@ void ath5k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif);
 /* Check whether virtual EOL is supported */
 #define ath5k_hw_hasveol(_ah) (ah->ah_version != AR5K_AR5210)
 
-#endif
+#endif	/* _DEV_ATH5K_BASE_H */
diff --git a/drivers/net/wireless/ath/ath5k/caps.c b/drivers/net/wireless/ath/ath5k/caps.c
index eefe670e28a7..810fba96702b 100644
--- a/drivers/net/wireless/ath/ath5k/caps.c
+++ b/drivers/net/wireless/ath/ath5k/caps.c
@@ -24,7 +24,7 @@
 #include "ath5k.h"
 #include "reg.h"
 #include "debug.h"
-#include "base.h"
+#include "../regd.h"
 
 /*
  * Fill the capabilities struct
diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c
index ccca724de173..fce8c904eea9 100644
--- a/drivers/net/wireless/ath/ath5k/debug.c
+++ b/drivers/net/wireless/ath/ath5k/debug.c
@@ -58,19 +58,18 @@
  * THE POSSIBILITY OF SUCH DAMAGES.
  */
 
-#include "base.h"
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/list.h>
 #include "debug.h"
+#include "ath5k.h"
+#include "reg.h"
+#include "base.h"
 
 static unsigned int ath5k_debug;
 module_param_named(debug, ath5k_debug, uint, 0);
 
 
-#ifdef CONFIG_ATH5K_DEBUG
-
-#include <linux/seq_file.h>
-#include "reg.h"
-#include "ani.h"
-
 static int ath5k_debugfs_open(struct inode *inode, struct file *file)
 {
 	file->private_data = inode->i_private;
@@ -1031,5 +1030,3 @@ ath5k_debug_printtxbuf(struct ath5k_hw *ah, struct ath5k_buf *bf)
 		td->tx_stat.tx_status_0, td->tx_stat.tx_status_1,
 		done ? ' ' : (ts.ts_status == 0) ? '*' : '!');
 }
-
-#endif /* ifdef CONFIG_ATH5K_DEBUG */
diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c
index 846535f59efc..7e88dda82221 100644
--- a/drivers/net/wireless/ath/ath5k/desc.c
+++ b/drivers/net/wireless/ath/ath5k/desc.c
@@ -24,7 +24,6 @@
 #include "ath5k.h"
 #include "reg.h"
 #include "debug.h"
-#include "base.h"
 
 
 /************************\
diff --git a/drivers/net/wireless/ath/ath5k/dma.c b/drivers/net/wireless/ath/ath5k/dma.c
index 0d5d4033f12a..2481f9c7f4b6 100644
--- a/drivers/net/wireless/ath/ath5k/dma.c
+++ b/drivers/net/wireless/ath/ath5k/dma.c
@@ -35,7 +35,6 @@
 #include "ath5k.h"
 #include "reg.h"
 #include "debug.h"
-#include "base.h"
 
 
 /*********\
diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c
index 9068b9165265..cd708c15b774 100644
--- a/drivers/net/wireless/ath/ath5k/eeprom.c
+++ b/drivers/net/wireless/ath/ath5k/eeprom.c
@@ -26,7 +26,6 @@
 #include "ath5k.h"
 #include "reg.h"
 #include "debug.h"
-#include "base.h"
 
 
 /******************\
@@ -1780,13 +1779,12 @@ ath5k_eeprom_detach(struct ath5k_hw *ah)
 int
 ath5k_eeprom_mode_from_channel(struct ieee80211_channel *channel)
 {
-	switch (channel->hw_value & CHANNEL_MODES) {
-	case CHANNEL_A:
-	case CHANNEL_XR:
+	switch (channel->hw_value) {
+	case AR5K_MODE_11A:
 		return AR5K_EEPROM_MODE_11A;
-	case CHANNEL_G:
+	case AR5K_MODE_11G:
 		return AR5K_EEPROM_MODE_11G;
-	case CHANNEL_B:
+	case AR5K_MODE_11B:
 		return AR5K_EEPROM_MODE_11B;
 	default:
 		return -1;
diff --git a/drivers/net/wireless/ath/ath5k/gpio.c b/drivers/net/wireless/ath/ath5k/gpio.c
index bc90503f4b7a..859297811914 100644
--- a/drivers/net/wireless/ath/ath5k/gpio.c
+++ b/drivers/net/wireless/ath/ath5k/gpio.c
@@ -23,7 +23,6 @@
 #include "ath5k.h"
 #include "reg.h"
 #include "debug.h"
-#include "base.h"
 
 /*
  * Set led state
diff --git a/drivers/net/wireless/ath/ath5k/initvals.c b/drivers/net/wireless/ath/ath5k/initvals.c
index 5ab607f40e0e..1ffecc0fd3ed 100644
--- a/drivers/net/wireless/ath/ath5k/initvals.c
+++ b/drivers/net/wireless/ath/ath5k/initvals.c
@@ -22,7 +22,6 @@
 #include "ath5k.h"
 #include "reg.h"
 #include "debug.h"
-#include "base.h"
 
 /*
  * Mode-independent initial register writes
diff --git a/drivers/net/wireless/ath/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c
index 8c17a00f7dad..c1151c723711 100644
--- a/drivers/net/wireless/ath/ath5k/led.c
+++ b/drivers/net/wireless/ath/ath5k/led.c
@@ -41,7 +41,6 @@
 
 #include <linux/pci.h>
 #include "ath5k.h"
-#include "base.h"
 
 #define ATH_SDEVICE(subv, subd) \
 	.vendor = PCI_ANY_ID, .device = PCI_ANY_ID, \
diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
index 2a715ca0c5e4..0560234ec3f6 100644
--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c
+++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
@@ -41,8 +41,10 @@
  *
  */
 
+#include <net/mac80211.h>
 #include <asm/unaligned.h>
 
+#include "ath5k.h"
 #include "base.h"
 #include "reg.h"
 
@@ -137,11 +139,8 @@ ath5k_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 	/* Any MAC address is fine, all others are included through the
 	 * filter.
 	 */
-	memcpy(&ah->lladdr, vif->addr, ETH_ALEN);
 	ath5k_hw_set_lladdr(ah, vif->addr);
 
-	memcpy(&avf->lladdr, vif->addr, ETH_ALEN);
-
 	ath5k_update_bssid_mask_and_opmode(ah, vif);
 	ret = 0;
 end:
diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c
index eaf79b49341e..c1dff2ced044 100644
--- a/drivers/net/wireless/ath/ath5k/pci.c
+++ b/drivers/net/wireless/ath/ath5k/pci.c
@@ -261,7 +261,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
 	ah->iobase = mem; /* So we can unmap it on detach */
 
 	/* Initialize */
-	ret = ath5k_init_softc(ah, &ath_pci_bus_ops);
+	ret = ath5k_init_ah(ah, &ath_pci_bus_ops);
 	if (ret)
 		goto err_free;
 
@@ -287,7 +287,7 @@ ath5k_pci_remove(struct pci_dev *pdev)
 	struct ieee80211_hw *hw = pci_get_drvdata(pdev);
 	struct ath5k_hw *ah = hw->priv;
 
-	ath5k_deinit_softc(ah);
+	ath5k_deinit_ah(ah);
 	pci_iounmap(pdev, ah->iobase);
 	pci_release_region(pdev, 0);
 	pci_disable_device(pdev);
diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c
index 067313845060..a7eafa3edc21 100644
--- a/drivers/net/wireless/ath/ath5k/pcu.c
+++ b/drivers/net/wireless/ath/ath5k/pcu.c
@@ -29,7 +29,6 @@
 #include "ath5k.h"
 #include "reg.h"
 #include "debug.h"
-#include "base.h"
 
 /*
  * AR5212+ can use higher rates for ack transmission
@@ -152,7 +151,7 @@ unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah)
 	case AR5K_BWMODE_DEFAULT:
 	default:
 		slot_time = AR5K_INIT_SLOT_TIME_DEFAULT;
-		if ((channel->hw_value & CHANNEL_CCK) && !ah->ah_short_slot)
+		if ((channel->hw_value == AR5K_MODE_11B) && !ah->ah_short_slot)
 			slot_time = AR5K_INIT_SLOT_TIME_B;
 		break;
 	}
@@ -183,7 +182,7 @@ unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah)
 	case AR5K_BWMODE_DEFAULT:
 		sifs = AR5K_INIT_SIFS_DEFAULT_BG;
 	default:
-		if (channel->hw_value & CHANNEL_5GHZ)
+		if (channel->band == IEEE80211_BAND_5GHZ)
 			sifs = AR5K_INIT_SIFS_DEFAULT_A;
 		break;
 	}
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
index 81e465e70175..01cb72de44cb 100644
--- a/drivers/net/wireless/ath/ath5k/phy.c
+++ b/drivers/net/wireless/ath/ath5k/phy.c
@@ -26,9 +26,9 @@
 
 #include "ath5k.h"
 #include "reg.h"
-#include "base.h"
 #include "rfbuffer.h"
 #include "rfgain.h"
+#include "../regd.h"
 
 
 /******************\
@@ -38,7 +38,7 @@
 /*
  * Get the PHY Chip revision
  */
-u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan)
+u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, enum ieee80211_band band)
 {
 	unsigned int i;
 	u32 srev;
@@ -47,11 +47,11 @@ u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan)
 	/*
 	 * Set the radio chip access register
 	 */
-	switch (chan) {
-	case CHANNEL_2GHZ:
+	switch (band) {
+	case IEEE80211_BAND_2GHZ:
 		ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_2GHZ, AR5K_PHY(0));
 		break;
-	case CHANNEL_5GHZ:
+	case IEEE80211_BAND_5GHZ:
 		ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
 		break;
 	default:
@@ -84,14 +84,16 @@ u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan)
 /*
  * Check if a channel is supported
  */
-bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags)
+bool ath5k_channel_ok(struct ath5k_hw *ah, struct ieee80211_channel *channel)
 {
+	u16 freq = channel->center_freq;
+
 	/* Check if the channel is in our supported range */
-	if (flags & CHANNEL_2GHZ) {
+	if (channel->band == IEEE80211_BAND_2GHZ) {
 		if ((freq >= ah->ah_capabilities.cap_range.range_2ghz_min) &&
 		    (freq <= ah->ah_capabilities.cap_range.range_2ghz_max))
 			return true;
-	} else if (flags & CHANNEL_5GHZ)
+	} else if (channel->band == IEEE80211_BAND_5GHZ)
 		if ((freq >= ah->ah_capabilities.cap_range.range_5ghz_min) &&
 		    (freq <= ah->ah_capabilities.cap_range.range_5ghz_max))
 			return true;
@@ -224,7 +226,7 @@ static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah,
 		ds_coef_exp, ds_coef_man, clock;
 
 	BUG_ON(!(ah->ah_version == AR5K_AR5212) ||
-		!(channel->hw_value & CHANNEL_OFDM));
+		(channel->hw_value == AR5K_MODE_11B));
 
 	/* Get coefficient
 	 * ALGO: coef = (5 * clock / carrier_freq) / 2
@@ -298,7 +300,7 @@ static void ath5k_hw_wait_for_synth(struct ath5k_hw *ah,
 		u32 delay;
 		delay = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) &
 			AR5K_PHY_RX_DELAY_M;
-		delay = (channel->hw_value & CHANNEL_CCK) ?
+		delay = (channel->hw_value == AR5K_MODE_11B) ?
 			((delay << 2) / 22) : (delay / 10);
 		if (ah->ah_bwmode == AR5K_BWMODE_10MHZ)
 			delay = delay << 1;
@@ -798,9 +800,9 @@ static int ath5k_hw_rfregs_init(struct ath5k_hw *ah,
 	}
 
 	/* Set Output and Driver bias current (OB/DB) */
-	if (channel->hw_value & CHANNEL_2GHZ) {
+	if (channel->band == IEEE80211_BAND_2GHZ) {
 
-		if (channel->hw_value & CHANNEL_CCK)
+		if (channel->hw_value == AR5K_MODE_11B)
 			ee_mode = AR5K_EEPROM_MODE_11B;
 		else
 			ee_mode = AR5K_EEPROM_MODE_11G;
@@ -825,7 +827,7 @@ static int ath5k_hw_rfregs_init(struct ath5k_hw *ah,
 						AR5K_RF_DB_2GHZ, true);
 
 	/* RF5111 always needs OB/DB for 5GHz, even if we use 2GHz */
-	} else if ((channel->hw_value & CHANNEL_5GHZ) ||
+	} else if ((channel->band == IEEE80211_BAND_5GHZ) ||
 			(ah->ah_radio == AR5K_RF5111)) {
 
 		/* For 11a, Turbo and XR we need to choose
@@ -857,7 +859,7 @@ static int ath5k_hw_rfregs_init(struct ath5k_hw *ah,
 	if (ah->ah_radio == AR5K_RF5111) {
 
 		/* Set gain_F settings according to current step */
-		if (channel->hw_value & CHANNEL_OFDM) {
+		if (channel->hw_value != AR5K_MODE_11B) {
 
 			AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL,
 					AR5K_PHY_FRAME_CTL_TX_CLIP,
@@ -914,7 +916,7 @@ static int ath5k_hw_rfregs_init(struct ath5k_hw *ah,
 	if (ah->ah_radio == AR5K_RF5112) {
 
 		/* Set gain_F settings according to current step */
-		if (channel->hw_value & CHANNEL_OFDM) {
+		if (channel->hw_value != AR5K_MODE_11B) {
 
 			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[0],
 						AR5K_RF_MIXGAIN_OVR, true);
@@ -1026,7 +1028,7 @@ static int ath5k_hw_rfregs_init(struct ath5k_hw *ah,
 	}
 
 	if (ah->ah_radio == AR5K_RF5413 &&
-	channel->hw_value & CHANNEL_2GHZ) {
+	channel->band == IEEE80211_BAND_2GHZ) {
 
 		ath5k_hw_rfb_op(ah, rf_regs, 1, AR5K_RF_DERBY_CHAN_SEL_MODE,
 									true);
@@ -1138,7 +1140,7 @@ static int ath5k_hw_rf5111_channel(struct ath5k_hw *ah,
 	 */
 	data0 = data1 = 0;
 
-	if (channel->hw_value & CHANNEL_2GHZ) {
+	if (channel->band == IEEE80211_BAND_2GHZ) {
 		/* Map 2GHz channel to 5GHz Atheros channel ID */
 		ret = ath5k_hw_rf5111_chan2athchan(
 			ieee80211_frequency_to_channel(channel->center_freq),
@@ -1265,10 +1267,9 @@ static int ath5k_hw_channel(struct ath5k_hw *ah,
 	int ret;
 	/*
 	 * Check bounds supported by the PHY (we don't care about regulatory
-	 * restrictions at this point). Note: hw_value already has the band
-	 * (CHANNEL_2GHZ, or CHANNEL_5GHZ) so we inform ath5k_channel_ok()
-	 * of the band by that */
-	if (!ath5k_channel_ok(ah, channel->center_freq, channel->hw_value)) {
+	 * restrictions at this point).
+	 */
+	if (!ath5k_channel_ok(ah, channel)) {
 		ATH5K_ERR(ah,
 			"channel frequency (%u MHz) out of supported "
 			"band range\n",
@@ -1614,7 +1615,7 @@ int ath5k_hw_phy_calibrate(struct ath5k_hw *ah,
 	ret = ath5k_hw_rf511x_iq_calibrate(ah);
 
 	if ((ah->ah_radio == AR5K_RF5111 || ah->ah_radio == AR5K_RF5112) &&
-	    (channel->hw_value & CHANNEL_OFDM))
+	    (channel->hw_value != AR5K_MODE_11B))
 		ath5k_hw_request_rfgain_probe(ah);
 
 	return ret;
@@ -1641,7 +1642,7 @@ ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah,
 	/* Convert current frequency to fbin value (the same way channels
 	 * are stored on EEPROM, check out ath5k_eeprom_bin2freq) and scale
 	 * up by 2 so we can compare it later */
-	if (channel->hw_value & CHANNEL_2GHZ) {
+	if (channel->band == IEEE80211_BAND_2GHZ) {
 		chan_fbin = (channel->center_freq - 2300) * 10;
 		freq_band = AR5K_EEPROM_BAND_2GHZ;
 	} else {
@@ -1703,7 +1704,7 @@ ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah,
 			spur_freq_sigma_delta = (spur_delta_phase >> 10);
 			symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz / 4;
 		default:
-			if (channel->hw_value == CHANNEL_A) {
+			if (channel->band == IEEE80211_BAND_5GHZ) {
 				/* Both sample_freq and chip_freq are 40MHz */
 				spur_delta_phase = (spur_offset << 17) / 25;
 				spur_freq_sigma_delta =
@@ -2226,15 +2227,20 @@ ath5k_get_chan_pcal_surrounding_piers(struct ath5k_hw *ah,
 	idx_l = 0;
 	idx_r = 0;
 
-	if (!(channel->hw_value & CHANNEL_OFDM)) {
+	switch (channel->hw_value) {
+	case AR5K_EEPROM_MODE_11A:
+		pcinfo = ee->ee_pwr_cal_a;
+		mode = AR5K_EEPROM_MODE_11A;
+		break;
+	case AR5K_EEPROM_MODE_11B:
 		pcinfo = ee->ee_pwr_cal_b;
 		mode = AR5K_EEPROM_MODE_11B;
-	} else if (channel->hw_value & CHANNEL_2GHZ) {
+		break;
+	case AR5K_EEPROM_MODE_11G:
+	default:
 		pcinfo = ee->ee_pwr_cal_g;
 		mode = AR5K_EEPROM_MODE_11G;
-	} else {
-		pcinfo = ee->ee_pwr_cal_a;
-		mode = AR5K_EEPROM_MODE_11A;
+		break;
 	}
 	max = ee->ee_n_piers[mode] - 1;
 
@@ -2303,15 +2309,20 @@ ath5k_get_rate_pcal_data(struct ath5k_hw *ah,
 	idx_l = 0;
 	idx_r = 0;
 
-	if (!(channel->hw_value & CHANNEL_OFDM)) {
+	switch (channel->hw_value) {
+	case AR5K_MODE_11A:
+		rpinfo = ee->ee_rate_tpwr_a;
+		mode = AR5K_EEPROM_MODE_11A;
+		break;
+	case AR5K_MODE_11B:
 		rpinfo = ee->ee_rate_tpwr_b;
 		mode = AR5K_EEPROM_MODE_11B;
-	} else if (channel->hw_value & CHANNEL_2GHZ) {
+		break;
+	case AR5K_MODE_11G:
+	default:
 		rpinfo = ee->ee_rate_tpwr_g;
 		mode = AR5K_EEPROM_MODE_11G;
-	} else {
-		rpinfo = ee->ee_rate_tpwr_a;
-		mode = AR5K_EEPROM_MODE_11A;
+		break;
 	}
 	max = ee->ee_rate_target_pwr_num[mode] - 1;
 
@@ -2392,24 +2403,22 @@ ath5k_get_max_ctl_power(struct ath5k_hw *ah,
 
 	ctl_mode = ath_regd_get_band_ctl(regulatory, channel->band);
 
-	switch (channel->hw_value & CHANNEL_MODES) {
-	case CHANNEL_A:
+	switch (channel->hw_value) {
+	case AR5K_MODE_11A:
 		if (ah->ah_bwmode == AR5K_BWMODE_40MHZ)
 			ctl_mode |= AR5K_CTL_TURBO;
 		else
 			ctl_mode |= AR5K_CTL_11A;
 		break;
-	case CHANNEL_G:
+	case AR5K_MODE_11G:
 		if (ah->ah_bwmode == AR5K_BWMODE_40MHZ)
 			ctl_mode |= AR5K_CTL_TURBOG;
 		else
 			ctl_mode |= AR5K_CTL_11G;
 		break;
-	case CHANNEL_B:
+	case AR5K_MODE_11B:
 		ctl_mode |= AR5K_CTL_11B;
 		break;
-	case CHANNEL_XR:
-		/* Fall through */
 	default:
 		return;
 	}
@@ -3292,7 +3301,7 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
 
 	/* Write OFDM timings on 5212*/
 	if (ah->ah_version == AR5K_AR5212 &&
-		channel->hw_value & CHANNEL_OFDM) {
+		channel->hw_value != AR5K_MODE_11B) {
 
 		ret = ath5k_hw_write_ofdm_timings(ah, channel);
 		if (ret)
diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c
index 65f10398999e..776654228eaa 100644
--- a/drivers/net/wireless/ath/ath5k/qcu.c
+++ b/drivers/net/wireless/ath/ath5k/qcu.c
@@ -23,7 +23,6 @@ Queue Control Unit, DFS Control Unit Functions
 #include "ath5k.h"
 #include "reg.h"
 #include "debug.h"
-#include "base.h"
 
 
 /******************\
@@ -185,13 +184,6 @@ int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
 		case AR5K_TX_QUEUE_CAB:
 			queue = AR5K_TX_QUEUE_ID_CAB;
 			break;
-		case AR5K_TX_QUEUE_XR_DATA:
-			if (ah->ah_version != AR5K_AR5212)
-				ATH5K_ERR(ah,
-					"XR data queues only supported in"
-					" 5212!\n");
-			queue = AR5K_TX_QUEUE_ID_XR_DATA;
-			break;
 		default:
 			return -EINVAL;
 		}
@@ -544,7 +536,7 @@ int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time)
 	 *
 	 * Also we have different lowest rate for 802.11a
 	 */
-	if (channel->hw_value & CHANNEL_5GHZ)
+	if (channel->band == IEEE80211_BAND_5GHZ)
 		rate = &ah->sbands[IEEE80211_BAND_5GHZ].bitrates[0];
 	else
 		rate = &ah->sbands[IEEE80211_BAND_2GHZ].bitrates[0];
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index 0686c5d8d56e..2abac257b4b4 100644
--- a/drivers/net/wireless/ath/ath5k/reset.c
+++ b/drivers/net/wireless/ath/ath5k/reset.c
@@ -30,7 +30,6 @@
 #include <linux/platform_device.h>
 #include "ath5k.h"
 #include "reg.h"
-#include "base.h"
 #include "debug.h"
 
 
@@ -102,12 +101,18 @@ static void ath5k_hw_init_core_clock(struct ath5k_hw *ah)
 	/*
 	 * Set core clock frequency
 	 */
-	if (channel->hw_value & CHANNEL_5GHZ)
-		clock = 40; /* 802.11a */
-	else if (channel->hw_value & CHANNEL_CCK)
-		clock = 22; /* 802.11b */
-	else
-		clock = 44; /* 802.11g */
+	switch (channel->hw_value) {
+	case AR5K_MODE_11A:
+		clock = 40;
+		break;
+	case AR5K_MODE_11B:
+		clock = 22;
+		break;
+	case AR5K_MODE_11G:
+	default:
+		clock = 44;
+		break;
+	}
 
 	/* Use clock multiplier for non-default
 	 * bwmode */
@@ -581,8 +586,9 @@ int ath5k_hw_on_hold(struct ath5k_hw *ah)
 
 /*
  * Bring up MAC + PHY Chips and program PLL
+ * Channel is NULL for the initial wakeup.
  */
-int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
+int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel)
 {
 	struct pci_dev *pdev = ah->pdev;
 	u32 turbo, mode, clock, bus_flags;
@@ -592,7 +598,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
 	mode = 0;
 	clock = 0;
 
-	if ((ath5k_get_bus_type(ah) != ATH_AHB) || !initial) {
+	if ((ath5k_get_bus_type(ah) != ATH_AHB) || channel) {
 		/* Wakeup the device */
 		ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
 		if (ret) {
@@ -652,7 +658,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
 
 	/* On initialization skip PLL programming since we don't have
 	 * a channel / mode set yet */
-	if (initial)
+	if (!channel)
 		return 0;
 
 	if (ah->ah_version != AR5K_AR5210) {
@@ -668,13 +674,13 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
 			clock = AR5K_PHY_PLL_RF5111;		/*Zero*/
 		}
 
-		if (flags & CHANNEL_2GHZ) {
+		if (channel->band == IEEE80211_BAND_2GHZ) {
 			mode |= AR5K_PHY_MODE_FREQ_2GHZ;
 			clock |= AR5K_PHY_PLL_44MHZ;
 
-			if (flags & CHANNEL_CCK) {
+			if (channel->hw_value == AR5K_MODE_11B) {
 				mode |= AR5K_PHY_MODE_MOD_CCK;
-			} else if (flags & CHANNEL_OFDM) {
+			} else {
 				/* XXX Dynamic OFDM/CCK is not supported by the
 				 * AR5211 so we set MOD_OFDM for plain g (no
 				 * CCK headers) operation. We need to test
@@ -686,27 +692,16 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
 					mode |= AR5K_PHY_MODE_MOD_OFDM;
 				else
 					mode |= AR5K_PHY_MODE_MOD_DYN;
-			} else {
-				ATH5K_ERR(ah,
-					"invalid radio modulation mode\n");
-				return -EINVAL;
 			}
-		} else if (flags & CHANNEL_5GHZ) {
-			mode |= AR5K_PHY_MODE_FREQ_5GHZ;
+		} else if (channel->band == IEEE80211_BAND_5GHZ) {
+			mode |= (AR5K_PHY_MODE_FREQ_5GHZ |
+				 AR5K_PHY_MODE_MOD_OFDM);
 
 			/* Different PLL setting for 5413 */
 			if (ah->ah_radio == AR5K_RF5413)
 				clock = AR5K_PHY_PLL_40MHZ_5413;
 			else
 				clock |= AR5K_PHY_PLL_40MHZ;
-
-			if (flags & CHANNEL_OFDM)
-				mode |= AR5K_PHY_MODE_MOD_OFDM;
-			else {
-				ATH5K_ERR(ah,
-					"invalid radio modulation mode\n");
-				return -EINVAL;
-			}
 		} else {
 			ATH5K_ERR(ah, "invalid radio frequency mode\n");
 			return -EINVAL;
@@ -822,7 +817,7 @@ static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah,
 		u32 data;
 		ath5k_hw_reg_write(ah, AR5K_PHY_CCKTXCTL_WORLD,
 				AR5K_PHY_CCKTXCTL);
-		if (channel->hw_value & CHANNEL_5GHZ)
+		if (channel->band == IEEE80211_BAND_5GHZ)
 			data = 0xffb81020;
 		else
 			data = 0xffb80d20;
@@ -905,7 +900,7 @@ static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
 	/* Set CCK to OFDM power delta on tx power
 	 * adjustment register */
 	if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) {
-		if (channel->hw_value == CHANNEL_G)
+		if (channel->hw_value == AR5K_MODE_11G)
 			ath5k_hw_reg_write(ah,
 			AR5K_REG_SM((ee->ee_cck_ofdm_gain_delta * -1),
 				AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA) |
@@ -1084,37 +1079,23 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
 		ret = 0;
 	}
 
-	switch (channel->hw_value & CHANNEL_MODES) {
-	case CHANNEL_A:
-		mode = AR5K_MODE_11A;
+	mode = channel->hw_value;
+	switch (mode) {
+	case AR5K_MODE_11A:
 		break;
-	case CHANNEL_G:
-
+	case AR5K_MODE_11G:
 		if (ah->ah_version <= AR5K_AR5211) {
 			ATH5K_ERR(ah,
 				"G mode not available on 5210/5211");
 			return -EINVAL;
 		}
-
-		mode = AR5K_MODE_11G;
 		break;
-	case CHANNEL_B:
-
+	case AR5K_MODE_11B:
 		if (ah->ah_version < AR5K_AR5211) {
 			ATH5K_ERR(ah,
 				"B mode not available on 5210");
 			return -EINVAL;
 		}
-
-		mode = AR5K_MODE_11B;
-		break;
-	case CHANNEL_XR:
-		if (ah->ah_version == AR5K_AR5211) {
-			ATH5K_ERR(ah,
-				"XR mode not available on 5211");
-			return -EINVAL;
-		}
-		mode = AR5K_MODE_XR;
 		break;
 	default:
 		ATH5K_ERR(ah,
@@ -1200,7 +1181,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
 	}
 
 	/* Wakeup the device */
-	ret = ath5k_hw_nic_wakeup(ah, channel->hw_value, false);
+	ret = ath5k_hw_nic_wakeup(ah, channel);
 	if (ret)
 		return ret;
 
diff --git a/drivers/net/wireless/ath/ath5k/rfkill.c b/drivers/net/wireless/ath/ath5k/rfkill.c
index 945fc9f21e76..270a319f3aeb 100644
--- a/drivers/net/wireless/ath/ath5k/rfkill.c
+++ b/drivers/net/wireless/ath/ath5k/rfkill.c
@@ -33,7 +33,7 @@
  * THE POSSIBILITY OF SUCH DAMAGES.
  */
 
-#include "base.h"
+#include "ath5k.h"
 
 
 static inline void ath5k_rfkill_disable(struct ath5k_hw *ah)
diff --git a/drivers/net/wireless/ath/ath5k/sysfs.c b/drivers/net/wireless/ath/ath5k/sysfs.c
index 0244a36ba958..9364da7bd131 100644
--- a/drivers/net/wireless/ath/ath5k/sysfs.c
+++ b/drivers/net/wireless/ath/ath5k/sysfs.c
@@ -1,7 +1,6 @@
 #include <linux/device.h>
 #include <linux/pci.h>
 
-#include "base.h"
 #include "ath5k.h"
 #include "reg.h"
 
diff --git a/drivers/net/wireless/ath/ath5k/trace.h b/drivers/net/wireless/ath/ath5k/trace.h
index c741c871f4e9..39f002ed4a88 100644
--- a/drivers/net/wireless/ath/ath5k/trace.h
+++ b/drivers/net/wireless/ath/ath5k/trace.h
@@ -2,7 +2,6 @@
 #define __TRACE_ATH5K_H
 
 #include <linux/tracepoint.h>
-#include "base.h"
 
 #ifndef CONFIG_ATH5K_TRACER
 #undef TRACE_EVENT
@@ -11,6 +10,8 @@ static inline void trace_ ## name(proto) {}
 #endif
 
 struct sk_buff;
+struct ath5k_txq;
+struct ath5k_tx_status;
 
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM ath5k
diff --git a/drivers/net/wireless/ath/ath6kl/Kconfig b/drivers/net/wireless/ath/ath6kl/Kconfig
new file mode 100644
index 000000000000..3d5f8be20eac
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/Kconfig
@@ -0,0 +1,15 @@
+config ATH6KL
+	tristate "Atheros ath6kl support"
+	depends on MMC
+	depends on CFG80211
+	---help---
+	  This module adds support for wireless adapters based on
+	  Atheros AR6003 chipset running over SDIO. If you choose to
+	  build it as a module, it will be called ath6kl. Pls note
+	  that AR6002 and AR6001 are not supported by this driver.
+
+config ATH6KL_DEBUG
+	bool "Atheros ath6kl debugging"
+	depends on ATH6KL
+	---help---
+	  Enables debug support
diff --git a/drivers/net/wireless/ath/ath6kl/Makefile b/drivers/net/wireless/ath/ath6kl/Makefile
new file mode 100644
index 000000000000..e1bb07ea8e80
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/Makefile
@@ -0,0 +1,35 @@
+#------------------------------------------------------------------------------
+# Copyright (c) 2004-2010 Atheros Communications Inc.
+# All rights reserved.
+#
+#
+#
+# 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.
+#
+#
+#
+# Author(s): ="Atheros"
+#------------------------------------------------------------------------------
+
+obj-$(CONFIG_ATH6KL) := ath6kl.o
+ath6kl-y += debug.o
+ath6kl-y += htc_hif.o
+ath6kl-y += htc.o
+ath6kl-y += bmi.o
+ath6kl-y += cfg80211.o
+ath6kl-y += init.o
+ath6kl-y += main.o
+ath6kl-y += txrx.o
+ath6kl-y += wmi.o
+ath6kl-y += node.o
+ath6kl-y += sdio.o
diff --git a/drivers/net/wireless/ath/ath6kl/bmi.c b/drivers/net/wireless/ath/ath6kl/bmi.c
new file mode 100644
index 000000000000..84676697d7eb
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/bmi.c
@@ -0,0 +1,692 @@
+/*
+ * Copyright (c) 2004-2011 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.
+ */
+
+#include "core.h"
+#include "hif-ops.h"
+#include "target.h"
+#include "debug.h"
+
+static int ath6kl_get_bmi_cmd_credits(struct ath6kl *ar)
+{
+	u32 addr;
+	unsigned long timeout;
+	int ret;
+
+	ar->bmi.cmd_credits = 0;
+
+	/* Read the counter register to get the command credits */
+	addr = COUNT_DEC_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 4;
+
+	timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT);
+	while (time_before(jiffies, timeout) && !ar->bmi.cmd_credits) {
+
+		/*
+		 * Hit the credit counter with a 4-byte access, the first byte
+		 * read will hit the counter and cause a decrement, while the
+		 * remaining 3 bytes has no effect. The rationale behind this
+		 * is to make all HIF accesses 4-byte aligned.
+		 */
+		ret = hif_read_write_sync(ar, addr,
+					 (u8 *)&ar->bmi.cmd_credits, 4,
+					 HIF_RD_SYNC_BYTE_INC);
+		if (ret) {
+			ath6kl_err("Unable to decrement the command credit count register: %d\n",
+				   ret);
+			return ret;
+		}
+
+		/* The counter is only 8 bits.
+		 * Ignore anything in the upper 3 bytes
+		 */
+		ar->bmi.cmd_credits &= 0xFF;
+	}
+
+	if (!ar->bmi.cmd_credits) {
+		ath6kl_err("bmi communication timeout\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int ath6kl_bmi_get_rx_lkahd(struct ath6kl *ar, bool need_timeout)
+{
+	unsigned long timeout;
+	u32 rx_word = 0;
+	int ret = 0;
+
+	timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT);
+	while ((!need_timeout || time_before(jiffies, timeout)) && !rx_word) {
+		ret = hif_read_write_sync(ar, RX_LOOKAHEAD_VALID_ADDRESS,
+					  (u8 *)&rx_word, sizeof(rx_word),
+					  HIF_RD_SYNC_BYTE_INC);
+		if (ret) {
+			ath6kl_err("unable to read RX_LOOKAHEAD_VALID\n");
+			return ret;
+		}
+
+		 /* all we really want is one bit */
+		rx_word &= (1 << ENDPOINT1);
+	}
+
+	if (!rx_word) {
+		ath6kl_err("bmi_recv_buf FIFO empty\n");
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static int ath6kl_bmi_send_buf(struct ath6kl *ar, u8 *buf, u32 len)
+{
+	int ret;
+	u32 addr;
+
+	ret = ath6kl_get_bmi_cmd_credits(ar);
+	if (ret)
+		return ret;
+
+	addr = ar->mbox_info.htc_addr;
+
+	ret = hif_read_write_sync(ar, addr, buf, len,
+				  HIF_WR_SYNC_BYTE_INC);
+	if (ret)
+		ath6kl_err("unable to send the bmi data to the device\n");
+
+	return ret;
+}
+
+static int ath6kl_bmi_recv_buf(struct ath6kl *ar,
+			u8 *buf, u32 len, bool want_timeout)
+{
+	int ret;
+	u32 addr;
+
+	/*
+	 * During normal bootup, small reads may be required.
+	 * Rather than issue an HIF Read and then wait as the Target
+	 * adds successive bytes to the FIFO, we wait here until
+	 * we know that response data is available.
+	 *
+	 * This allows us to cleanly timeout on an unexpected
+	 * Target failure rather than risk problems at the HIF level.
+	 * In particular, this avoids SDIO timeouts and possibly garbage
+	 * data on some host controllers.  And on an interconnect
+	 * such as Compact Flash (as well as some SDIO masters) which
+	 * does not provide any indication on data timeout, it avoids
+	 * a potential hang or garbage response.
+	 *
+	 * Synchronization is more difficult for reads larger than the
+	 * size of the MBOX FIFO (128B), because the Target is unable
+	 * to push the 129th byte of data until AFTER the Host posts an
+	 * HIF Read and removes some FIFO data.  So for large reads the
+	 * Host proceeds to post an HIF Read BEFORE all the data is
+	 * actually available to read.  Fortunately, large BMI reads do
+	 * not occur in practice -- they're supported for debug/development.
+	 *
+	 * So Host/Target BMI synchronization is divided into these cases:
+	 *  CASE 1: length < 4
+	 *        Should not happen
+	 *
+	 *  CASE 2: 4 <= length <= 128
+	 *        Wait for first 4 bytes to be in FIFO
+	 *        If CONSERVATIVE_BMI_READ is enabled, also wait for
+	 *        a BMI command credit, which indicates that the ENTIRE
+	 *        response is available in the the FIFO
+	 *
+	 *  CASE 3: length > 128
+	 *        Wait for the first 4 bytes to be in FIFO
+	 *
+	 * For most uses, a small timeout should be sufficient and we will
+	 * usually see a response quickly; but there may be some unusual
+	 * (debug) cases of BMI_EXECUTE where we want an larger timeout.
+	 * For now, we use an unbounded busy loop while waiting for
+	 * BMI_EXECUTE.
+	 *
+	 * If BMI_EXECUTE ever needs to support longer-latency execution,
+	 * especially in production, this code needs to be enhanced to sleep
+	 * and yield.  Also note that BMI_COMMUNICATION_TIMEOUT is currently
+	 * a function of Host processor speed.
+	 */
+	if (len >= 4) { /* NB: Currently, always true */
+		ret = ath6kl_bmi_get_rx_lkahd(ar, want_timeout);
+		if (ret)
+			return ret;
+	}
+
+	addr = ar->mbox_info.htc_addr;
+	ret = hif_read_write_sync(ar, addr, buf, len,
+				  HIF_RD_SYNC_BYTE_INC);
+	if (ret) {
+		ath6kl_err("Unable to read the bmi data from the device: %d\n",
+			   ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+int ath6kl_bmi_done(struct ath6kl *ar)
+{
+	int ret;
+	u32 cid = BMI_DONE;
+
+	if (ar->bmi.done_sent) {
+		ath6kl_dbg(ATH6KL_DBG_BMI, "bmi done skipped\n");
+		return 0;
+	}
+
+	ar->bmi.done_sent = true;
+
+	ret = ath6kl_bmi_send_buf(ar, (u8 *)&cid, sizeof(cid));
+	if (ret) {
+		ath6kl_err("Unable to send bmi done: %d\n", ret);
+		return ret;
+	}
+
+	ath6kl_bmi_cleanup(ar);
+
+	return 0;
+}
+
+int ath6kl_bmi_get_target_info(struct ath6kl *ar,
+			       struct ath6kl_bmi_target_info *targ_info)
+{
+	int ret;
+	u32 cid = BMI_GET_TARGET_INFO;
+
+	if (ar->bmi.done_sent) {
+		ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
+		return -EACCES;
+	}
+
+	ret = ath6kl_bmi_send_buf(ar, (u8 *)&cid, sizeof(cid));
+	if (ret) {
+		ath6kl_err("Unable to send get target info: %d\n", ret);
+		return ret;
+	}
+
+	ret = ath6kl_bmi_recv_buf(ar, (u8 *)&targ_info->version,
+			sizeof(targ_info->version), true);
+	if (ret) {
+		ath6kl_err("Unable to recv target info: %d\n", ret);
+		return ret;
+	}
+
+	if (le32_to_cpu(targ_info->version) == TARGET_VERSION_SENTINAL) {
+		/* Determine how many bytes are in the Target's targ_info */
+		ret = ath6kl_bmi_recv_buf(ar,
+				   (u8 *)&targ_info->byte_count,
+				   sizeof(targ_info->byte_count),
+				   true);
+		if (ret) {
+			ath6kl_err("unable to read target info byte count: %d\n",
+				   ret);
+			return ret;
+		}
+
+		/*
+		 * The target's targ_info doesn't match the host's targ_info.
+		 * We need to do some backwards compatibility to make this work.
+		 */
+		if (le32_to_cpu(targ_info->byte_count) != sizeof(*targ_info)) {
+			WARN_ON(1);
+			return -EINVAL;
+		}
+
+		/* Read the remainder of the targ_info */
+		ret = ath6kl_bmi_recv_buf(ar,
+				   ((u8 *)targ_info) +
+				   sizeof(targ_info->byte_count),
+				   sizeof(*targ_info) -
+				   sizeof(targ_info->byte_count),
+				   true);
+
+		if (ret) {
+			ath6kl_err("Unable to read target info (%d bytes): %d\n",
+				   targ_info->byte_count, ret);
+			return ret;
+		}
+	}
+
+	ath6kl_dbg(ATH6KL_DBG_BMI, "target info (ver: 0x%x type: 0x%x)\n",
+		targ_info->version, targ_info->type);
+
+	return 0;
+}
+
+int ath6kl_bmi_read(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
+{
+	u32 cid = BMI_READ_MEMORY;
+	int ret;
+	u32 offset;
+	u32 len_remain, rx_len;
+	u16 size;
+
+	if (ar->bmi.done_sent) {
+		ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
+		return -EACCES;
+	}
+
+	size = BMI_DATASZ_MAX + sizeof(cid) + sizeof(addr) + sizeof(len);
+	if (size > MAX_BMI_CMDBUF_SZ) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	memset(ar->bmi.cmd_buf, 0, size);
+
+	ath6kl_dbg(ATH6KL_DBG_BMI,
+		   "bmi read memory: device: addr: 0x%x, len: %d\n",
+		   addr, len);
+
+	len_remain = len;
+
+	while (len_remain) {
+		rx_len = (len_remain < BMI_DATASZ_MAX) ?
+					len_remain : BMI_DATASZ_MAX;
+		offset = 0;
+		memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
+		offset += sizeof(cid);
+		memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
+		offset += sizeof(addr);
+		memcpy(&(ar->bmi.cmd_buf[offset]), &rx_len, sizeof(rx_len));
+		offset += sizeof(len);
+
+		ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
+		if (ret) {
+			ath6kl_err("Unable to write to the device: %d\n",
+				   ret);
+			return ret;
+		}
+		ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, rx_len, true);
+		if (ret) {
+			ath6kl_err("Unable to read from the device: %d\n",
+				   ret);
+			return ret;
+		}
+		memcpy(&buf[len - len_remain], ar->bmi.cmd_buf, rx_len);
+		len_remain -= rx_len; addr += rx_len;
+	}
+
+	return 0;
+}
+
+int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
+{
+	u32 cid = BMI_WRITE_MEMORY;
+	int ret;
+	u32 offset;
+	u32 len_remain, tx_len;
+	const u32 header = sizeof(cid) + sizeof(addr) + sizeof(len);
+	u8 aligned_buf[BMI_DATASZ_MAX];
+	u8 *src;
+
+	if (ar->bmi.done_sent) {
+		ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
+		return -EACCES;
+	}
+
+	if ((BMI_DATASZ_MAX + header) > MAX_BMI_CMDBUF_SZ) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	memset(ar->bmi.cmd_buf, 0, BMI_DATASZ_MAX + header);
+
+	ath6kl_dbg(ATH6KL_DBG_BMI,
+		  "bmi write memory: addr: 0x%x, len: %d\n", addr, len);
+
+	len_remain = len;
+	while (len_remain) {
+		src = &buf[len - len_remain];
+
+		if (len_remain < (BMI_DATASZ_MAX - header)) {
+			if (len_remain & 3) {
+				/* align it with 4 bytes */
+				len_remain = len_remain +
+					     (4 - (len_remain & 3));
+				memcpy(aligned_buf, src, len_remain);
+				src = aligned_buf;
+			}
+			tx_len = len_remain;
+		} else {
+			tx_len = (BMI_DATASZ_MAX - header);
+		}
+
+		offset = 0;
+		memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
+		offset += sizeof(cid);
+		memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
+		offset += sizeof(addr);
+		memcpy(&(ar->bmi.cmd_buf[offset]), &tx_len, sizeof(tx_len));
+		offset += sizeof(tx_len);
+		memcpy(&(ar->bmi.cmd_buf[offset]), src, tx_len);
+		offset += tx_len;
+
+		ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
+		if (ret) {
+			ath6kl_err("Unable to write to the device: %d\n",
+				   ret);
+			return ret;
+		}
+		len_remain -= tx_len; addr += tx_len;
+	}
+
+	return 0;
+}
+
+int ath6kl_bmi_execute(struct ath6kl *ar, u32 addr, u32 *param)
+{
+	u32 cid = BMI_EXECUTE;
+	int ret;
+	u32 offset;
+	u16 size;
+
+	if (ar->bmi.done_sent) {
+		ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
+		return -EACCES;
+	}
+
+	size = sizeof(cid) + sizeof(addr) + sizeof(param);
+	if (size > MAX_BMI_CMDBUF_SZ) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	memset(ar->bmi.cmd_buf, 0, size);
+
+	ath6kl_dbg(ATH6KL_DBG_BMI, "bmi execute: addr: 0x%x, param: %d)\n",
+		   addr, *param);
+
+	offset = 0;
+	memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
+	offset += sizeof(cid);
+	memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
+	offset += sizeof(addr);
+	memcpy(&(ar->bmi.cmd_buf[offset]), param, sizeof(*param));
+	offset += sizeof(*param);
+
+	ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
+	if (ret) {
+		ath6kl_err("Unable to write to the device: %d\n", ret);
+		return ret;
+	}
+
+	ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, sizeof(*param), false);
+	if (ret) {
+		ath6kl_err("Unable to read from the device: %d\n", ret);
+		return ret;
+	}
+
+	memcpy(param, ar->bmi.cmd_buf, sizeof(*param));
+
+	return 0;
+}
+
+int ath6kl_bmi_set_app_start(struct ath6kl *ar, u32 addr)
+{
+	u32 cid = BMI_SET_APP_START;
+	int ret;
+	u32 offset;
+	u16 size;
+
+	if (ar->bmi.done_sent) {
+		ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
+		return -EACCES;
+	}
+
+	size = sizeof(cid) + sizeof(addr);
+	if (size > MAX_BMI_CMDBUF_SZ) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	memset(ar->bmi.cmd_buf, 0, size);
+
+	ath6kl_dbg(ATH6KL_DBG_BMI, "bmi set app start: addr: 0x%x\n", addr);
+
+	offset = 0;
+	memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
+	offset += sizeof(cid);
+	memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
+	offset += sizeof(addr);
+
+	ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
+	if (ret) {
+		ath6kl_err("Unable to write to the device: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+int ath6kl_bmi_reg_read(struct ath6kl *ar, u32 addr, u32 *param)
+{
+	u32 cid = BMI_READ_SOC_REGISTER;
+	int ret;
+	u32 offset;
+	u16 size;
+
+	if (ar->bmi.done_sent) {
+		ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
+		return -EACCES;
+	}
+
+	size = sizeof(cid) + sizeof(addr);
+	if (size > MAX_BMI_CMDBUF_SZ) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	memset(ar->bmi.cmd_buf, 0, size);
+
+	ath6kl_dbg(ATH6KL_DBG_BMI, "bmi read SOC reg: addr: 0x%x\n", addr);
+
+	offset = 0;
+	memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
+	offset += sizeof(cid);
+	memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
+	offset += sizeof(addr);
+
+	ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
+	if (ret) {
+		ath6kl_err("Unable to write to the device: %d\n", ret);
+		return ret;
+	}
+
+	ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, sizeof(*param), true);
+	if (ret) {
+		ath6kl_err("Unable to read from the device: %d\n", ret);
+		return ret;
+	}
+	memcpy(param, ar->bmi.cmd_buf, sizeof(*param));
+
+	return 0;
+}
+
+int ath6kl_bmi_reg_write(struct ath6kl *ar, u32 addr, u32 param)
+{
+	u32 cid = BMI_WRITE_SOC_REGISTER;
+	int ret;
+	u32 offset;
+	u16 size;
+
+	if (ar->bmi.done_sent) {
+		ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
+		return -EACCES;
+	}
+
+	size = sizeof(cid) + sizeof(addr) + sizeof(param);
+	if (size > MAX_BMI_CMDBUF_SZ) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	memset(ar->bmi.cmd_buf, 0, size);
+
+	ath6kl_dbg(ATH6KL_DBG_BMI,
+		   "bmi write SOC reg: addr: 0x%x, param: %d\n",
+		    addr, param);
+
+	offset = 0;
+	memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
+	offset += sizeof(cid);
+	memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
+	offset += sizeof(addr);
+	memcpy(&(ar->bmi.cmd_buf[offset]), &param, sizeof(param));
+	offset += sizeof(param);
+
+	ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
+	if (ret) {
+		ath6kl_err("Unable to write to the device: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+int ath6kl_bmi_lz_data(struct ath6kl *ar, u8 *buf, u32 len)
+{
+	u32 cid = BMI_LZ_DATA;
+	int ret;
+	u32 offset;
+	u32 len_remain, tx_len;
+	const u32 header = sizeof(cid) + sizeof(len);
+	u16 size;
+
+	if (ar->bmi.done_sent) {
+		ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
+		return -EACCES;
+	}
+
+	size = BMI_DATASZ_MAX + header;
+	if (size > MAX_BMI_CMDBUF_SZ) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	memset(ar->bmi.cmd_buf, 0, size);
+
+	ath6kl_dbg(ATH6KL_DBG_BMI, "bmi send LZ data: len: %d)\n",
+		   len);
+
+	len_remain = len;
+	while (len_remain) {
+		tx_len = (len_remain < (BMI_DATASZ_MAX - header)) ?
+			  len_remain : (BMI_DATASZ_MAX - header);
+
+		offset = 0;
+		memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
+		offset += sizeof(cid);
+		memcpy(&(ar->bmi.cmd_buf[offset]), &tx_len, sizeof(tx_len));
+		offset += sizeof(tx_len);
+		memcpy(&(ar->bmi.cmd_buf[offset]), &buf[len - len_remain],
+			tx_len);
+		offset += tx_len;
+
+		ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
+		if (ret) {
+			ath6kl_err("Unable to write to the device: %d\n",
+				   ret);
+			return ret;
+		}
+
+		len_remain -= tx_len;
+	}
+
+	return 0;
+}
+
+int ath6kl_bmi_lz_stream_start(struct ath6kl *ar, u32 addr)
+{
+	u32 cid = BMI_LZ_STREAM_START;
+	int ret;
+	u32 offset;
+	u16 size;
+
+	if (ar->bmi.done_sent) {
+		ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
+		return -EACCES;
+	}
+
+	size = sizeof(cid) + sizeof(addr);
+	if (size > MAX_BMI_CMDBUF_SZ) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	memset(ar->bmi.cmd_buf, 0, size);
+
+	ath6kl_dbg(ATH6KL_DBG_BMI,
+		   "bmi LZ stream start: addr: 0x%x)\n",
+		    addr);
+
+	offset = 0;
+	memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
+	offset += sizeof(cid);
+	memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
+	offset += sizeof(addr);
+
+	ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
+	if (ret) {
+		ath6kl_err("Unable to start LZ stream to the device: %d\n",
+			   ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+int ath6kl_bmi_fast_download(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
+{
+	int ret;
+	u32 last_word = 0;
+	u32 last_word_offset = len & ~0x3;
+	u32 unaligned_bytes = len & 0x3;
+
+	ret = ath6kl_bmi_lz_stream_start(ar, addr);
+	if (ret)
+		return ret;
+
+	if (unaligned_bytes) {
+		/* copy the last word into a zero padded buffer */
+		memcpy(&last_word, &buf[last_word_offset], unaligned_bytes);
+	}
+
+	ret = ath6kl_bmi_lz_data(ar, buf, last_word_offset);
+	if (ret)
+		return ret;
+
+	if (unaligned_bytes)
+		ret = ath6kl_bmi_lz_data(ar, (u8 *)&last_word, 4);
+
+	if (!ret) {
+		/* Close compressed stream and open a new (fake) one.
+		 * This serves mainly to flush Target caches. */
+		ret = ath6kl_bmi_lz_stream_start(ar, 0x00);
+	}
+	return ret;
+}
+
+int ath6kl_bmi_init(struct ath6kl *ar)
+{
+	ar->bmi.cmd_buf = kzalloc(MAX_BMI_CMDBUF_SZ, GFP_ATOMIC);
+
+	if (!ar->bmi.cmd_buf)
+		return -ENOMEM;
+
+	return 0;
+}
+
+void ath6kl_bmi_cleanup(struct ath6kl *ar)
+{
+	kfree(ar->bmi.cmd_buf);
+	ar->bmi.cmd_buf = NULL;
+}
diff --git a/drivers/net/wireless/ath/ath6kl/bmi.h b/drivers/net/wireless/ath/ath6kl/bmi.h
new file mode 100644
index 000000000000..83546d76d979
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/bmi.h
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2004-2011 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 BMI_H
+#define BMI_H
+
+/*
+ * Bootloader Messaging Interface (BMI)
+ *
+ * BMI is a very simple messaging interface used during initialization
+ * to read memory, write memory, execute code, and to define an
+ * application entry PC.
+ *
+ * It is used to download an application to ATH6KL, to provide
+ * patches to code that is already resident on ATH6KL, and generally
+ * to examine and modify state.  The Host has an opportunity to use
+ * BMI only once during bootup.  Once the Host issues a BMI_DONE
+ * command, this opportunity ends.
+ *
+ * The Host writes BMI requests to mailbox0, and reads BMI responses
+ * from mailbox0.   BMI requests all begin with a command
+ * (see below for specific commands), and are followed by
+ * command-specific data.
+ *
+ * Flow control:
+ * The Host can only issue a command once the Target gives it a
+ * "BMI Command Credit", using ATH6KL Counter #4.  As soon as the
+ * Target has completed a command, it issues another BMI Command
+ * Credit (so the Host can issue the next command).
+ *
+ * BMI handles all required Target-side cache flushing.
+ */
+
+#define MAX_BMI_CMDBUF_SZ (BMI_DATASZ_MAX + \
+			   (sizeof(u32) * 3 /* cmd + addr + len */))
+
+/* Maximum data size used for BMI transfers */
+#define BMI_DATASZ_MAX                      256
+
+/* BMI Commands */
+
+#define BMI_NO_COMMAND                      0
+
+#define BMI_DONE                            1
+/*
+ * Semantics: Host is done using BMI
+ * Request format:
+ *    u32 command (BMI_DONE)
+ * Response format: none
+ */
+
+#define BMI_READ_MEMORY                     2
+/*
+ * Semantics: Host reads ATH6KL memory
+ * Request format:
+ *    u32 command (BMI_READ_MEMORY)
+ *    u32 address
+ *    u32 length, at most BMI_DATASZ_MAX
+ * Response format:
+ *    u8 data[length]
+ */
+
+#define BMI_WRITE_MEMORY                    3
+/*
+ * Semantics: Host writes ATH6KL memory
+ * Request format:
+ *    u32 command (BMI_WRITE_MEMORY)
+ *    u32 address
+ *    u32 length, at most BMI_DATASZ_MAX
+ *    u8 data[length]
+ * Response format: none
+ */
+
+#define BMI_EXECUTE                         4
+/*
+ * Semantics: Causes ATH6KL to execute code
+ * Request format:
+ *    u32 command (BMI_EXECUTE)
+ *    u32 address
+ *    u32 parameter
+ * Response format:
+ *    u32 return value
+ */
+
+#define BMI_SET_APP_START                   5
+/*
+ * Semantics: Set Target application starting address
+ * Request format:
+ *    u32 command (BMI_SET_APP_START)
+ *    u32 address
+ * Response format: none
+ */
+
+#define BMI_READ_SOC_REGISTER               6
+/*
+ * Semantics: Read a 32-bit Target SOC register.
+ * Request format:
+ *    u32 command (BMI_READ_REGISTER)
+ *    u32 address
+ * Response format:
+ *    u32 value
+ */
+
+#define BMI_WRITE_SOC_REGISTER              7
+/*
+ * Semantics: Write a 32-bit Target SOC register.
+ * Request format:
+ *    u32 command (BMI_WRITE_REGISTER)
+ *    u32 address
+ *    u32 value
+ *
+ * Response format: none
+ */
+
+#define BMI_GET_TARGET_ID                  8
+#define BMI_GET_TARGET_INFO                8
+/*
+ * Semantics: Fetch the 4-byte Target information
+ * Request format:
+ *    u32 command (BMI_GET_TARGET_ID/INFO)
+ * Response format1 (old firmware):
+ *    u32 TargetVersionID
+ * Response format2 (newer firmware):
+ *    u32 TARGET_VERSION_SENTINAL
+ *    struct bmi_target_info;
+ */
+
+#define TARGET_VERSION_SENTINAL 0xffffffff
+#define TARGET_TYPE_AR6003	3
+
+#define BMI_ROMPATCH_INSTALL               9
+/*
+ * Semantics: Install a ROM Patch.
+ * Request format:
+ *    u32 command (BMI_ROMPATCH_INSTALL)
+ *    u32 Target ROM Address
+ *    u32 Target RAM Address or Value (depending on Target Type)
+ *    u32 Size, in bytes
+ *    u32 Activate? 1-->activate;
+ *                            0-->install but do not activate
+ * Response format:
+ *    u32 PatchID
+ */
+
+#define BMI_ROMPATCH_UNINSTALL             10
+/*
+ * Semantics: Uninstall a previously-installed ROM Patch,
+ * automatically deactivating, if necessary.
+ * Request format:
+ *    u32 command (BMI_ROMPATCH_UNINSTALL)
+ *    u32 PatchID
+ *
+ * Response format: none
+ */
+
+#define BMI_ROMPATCH_ACTIVATE              11
+/*
+ * Semantics: Activate a list of previously-installed ROM Patches.
+ * Request format:
+ *    u32 command (BMI_ROMPATCH_ACTIVATE)
+ *    u32 rompatch_count
+ *    u32 PatchID[rompatch_count]
+ *
+ * Response format: none
+ */
+
+#define BMI_ROMPATCH_DEACTIVATE            12
+/*
+ * Semantics: Deactivate a list of active ROM Patches.
+ * Request format:
+ *    u32 command (BMI_ROMPATCH_DEACTIVATE)
+ *    u32 rompatch_count
+ *    u32 PatchID[rompatch_count]
+ *
+ * Response format: none
+ */
+
+
+#define BMI_LZ_STREAM_START                13
+/*
+ * Semantics: Begin an LZ-compressed stream of input
+ * which is to be uncompressed by the Target to an
+ * output buffer at address.  The output buffer must
+ * be sufficiently large to hold the uncompressed
+ * output from the compressed input stream.  This BMI
+ * command should be followed by a series of 1 or more
+ * BMI_LZ_DATA commands.
+ *    u32 command (BMI_LZ_STREAM_START)
+ *    u32 address
+ * Note: Not supported on all versions of ROM firmware.
+ */
+
+#define BMI_LZ_DATA                        14
+/*
+ * Semantics: Host writes ATH6KL memory with LZ-compressed
+ * data which is uncompressed by the Target.  This command
+ * must be preceded by a BMI_LZ_STREAM_START command. A series
+ * of BMI_LZ_DATA commands are considered part of a single
+ * input stream until another BMI_LZ_STREAM_START is issued.
+ * Request format:
+ *    u32 command (BMI_LZ_DATA)
+ *    u32 length (of compressed data),
+ *                  at most BMI_DATASZ_MAX
+ *    u8 CompressedData[length]
+ * Response format: none
+ * Note: Not supported on all versions of ROM firmware.
+ */
+
+#define BMI_COMMUNICATION_TIMEOUT       1000 /* in msec */
+
+struct ath6kl;
+struct ath6kl_bmi_target_info {
+	__le32 byte_count;   /* size of this structure */
+	__le32 version;      /* target version id */
+	__le32 type;         /* target type */
+} __packed;
+
+int ath6kl_bmi_init(struct ath6kl *ar);
+void ath6kl_bmi_cleanup(struct ath6kl *ar);
+int ath6kl_bmi_done(struct ath6kl *ar);
+int ath6kl_bmi_get_target_info(struct ath6kl *ar,
+			       struct ath6kl_bmi_target_info *targ_info);
+int ath6kl_bmi_read(struct ath6kl *ar, u32 addr, u8 *buf, u32 len);
+int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len);
+int ath6kl_bmi_execute(struct ath6kl *ar,
+		       u32 addr, u32 *param);
+int ath6kl_bmi_set_app_start(struct ath6kl *ar,
+			     u32 addr);
+int ath6kl_bmi_reg_read(struct ath6kl *ar, u32 addr, u32 *param);
+int ath6kl_bmi_reg_write(struct ath6kl *ar, u32 addr, u32 param);
+int ath6kl_bmi_lz_data(struct ath6kl *ar,
+		       u8 *buf, u32 len);
+int ath6kl_bmi_lz_stream_start(struct ath6kl *ar,
+			       u32 addr);
+int ath6kl_bmi_fast_download(struct ath6kl *ar,
+			     u32 addr, u8 *buf, u32 len);
+#endif
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
new file mode 100644
index 000000000000..14559ffb1453
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -0,0 +1,1538 @@
+/*
+ * Copyright (c) 2004-2011 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.
+ */
+
+#include "core.h"
+#include "cfg80211.h"
+#include "debug.h"
+
+#define RATETAB_ENT(_rate, _rateid, _flags) {   \
+	.bitrate    = (_rate),                  \
+	.flags      = (_flags),                 \
+	.hw_value   = (_rateid),                \
+}
+
+#define CHAN2G(_channel, _freq, _flags) {   \
+	.band           = IEEE80211_BAND_2GHZ,  \
+	.hw_value       = (_channel),           \
+	.center_freq    = (_freq),              \
+	.flags          = (_flags),             \
+	.max_antenna_gain   = 0,                \
+	.max_power      = 30,                   \
+}
+
+#define CHAN5G(_channel, _flags) {		    \
+	.band           = IEEE80211_BAND_5GHZ,      \
+	.hw_value       = (_channel),               \
+	.center_freq    = 5000 + (5 * (_channel)),  \
+	.flags          = (_flags),                 \
+	.max_antenna_gain   = 0,                    \
+	.max_power      = 30,                       \
+}
+
+static struct ieee80211_rate ath6kl_rates[] = {
+	RATETAB_ENT(10, 0x1, 0),
+	RATETAB_ENT(20, 0x2, 0),
+	RATETAB_ENT(55, 0x4, 0),
+	RATETAB_ENT(110, 0x8, 0),
+	RATETAB_ENT(60, 0x10, 0),
+	RATETAB_ENT(90, 0x20, 0),
+	RATETAB_ENT(120, 0x40, 0),
+	RATETAB_ENT(180, 0x80, 0),
+	RATETAB_ENT(240, 0x100, 0),
+	RATETAB_ENT(360, 0x200, 0),
+	RATETAB_ENT(480, 0x400, 0),
+	RATETAB_ENT(540, 0x800, 0),
+};
+
+#define ath6kl_a_rates     (ath6kl_rates + 4)
+#define ath6kl_a_rates_size    8
+#define ath6kl_g_rates     (ath6kl_rates + 0)
+#define ath6kl_g_rates_size    12
+
+static struct ieee80211_channel ath6kl_2ghz_channels[] = {
+	CHAN2G(1, 2412, 0),
+	CHAN2G(2, 2417, 0),
+	CHAN2G(3, 2422, 0),
+	CHAN2G(4, 2427, 0),
+	CHAN2G(5, 2432, 0),
+	CHAN2G(6, 2437, 0),
+	CHAN2G(7, 2442, 0),
+	CHAN2G(8, 2447, 0),
+	CHAN2G(9, 2452, 0),
+	CHAN2G(10, 2457, 0),
+	CHAN2G(11, 2462, 0),
+	CHAN2G(12, 2467, 0),
+	CHAN2G(13, 2472, 0),
+	CHAN2G(14, 2484, 0),
+};
+
+static struct ieee80211_channel ath6kl_5ghz_a_channels[] = {
+	CHAN5G(34, 0), CHAN5G(36, 0),
+	CHAN5G(38, 0), CHAN5G(40, 0),
+	CHAN5G(42, 0), CHAN5G(44, 0),
+	CHAN5G(46, 0), CHAN5G(48, 0),
+	CHAN5G(52, 0), CHAN5G(56, 0),
+	CHAN5G(60, 0), CHAN5G(64, 0),
+	CHAN5G(100, 0), CHAN5G(104, 0),
+	CHAN5G(108, 0), CHAN5G(112, 0),
+	CHAN5G(116, 0), CHAN5G(120, 0),
+	CHAN5G(124, 0), CHAN5G(128, 0),
+	CHAN5G(132, 0), CHAN5G(136, 0),
+	CHAN5G(140, 0), CHAN5G(149, 0),
+	CHAN5G(153, 0), CHAN5G(157, 0),
+	CHAN5G(161, 0), CHAN5G(165, 0),
+	CHAN5G(184, 0), CHAN5G(188, 0),
+	CHAN5G(192, 0), CHAN5G(196, 0),
+	CHAN5G(200, 0), CHAN5G(204, 0),
+	CHAN5G(208, 0), CHAN5G(212, 0),
+	CHAN5G(216, 0),
+};
+
+static struct ieee80211_supported_band ath6kl_band_2ghz = {
+	.n_channels = ARRAY_SIZE(ath6kl_2ghz_channels),
+	.channels = ath6kl_2ghz_channels,
+	.n_bitrates = ath6kl_g_rates_size,
+	.bitrates = ath6kl_g_rates,
+};
+
+static struct ieee80211_supported_band ath6kl_band_5ghz = {
+	.n_channels = ARRAY_SIZE(ath6kl_5ghz_a_channels),
+	.channels = ath6kl_5ghz_a_channels,
+	.n_bitrates = ath6kl_a_rates_size,
+	.bitrates = ath6kl_a_rates,
+};
+
+static int ath6kl_set_wpa_version(struct ath6kl *ar,
+				  enum nl80211_wpa_versions wpa_version)
+{
+	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: %u\n", __func__, wpa_version);
+
+	if (!wpa_version) {
+		ar->auth_mode = NONE_AUTH;
+	} else if (wpa_version & NL80211_WPA_VERSION_2) {
+		ar->auth_mode = WPA2_AUTH;
+	} else if (wpa_version & NL80211_WPA_VERSION_1) {
+		ar->auth_mode = WPA_AUTH;
+	} else {
+		ath6kl_err("%s: %u not supported\n", __func__, wpa_version);
+		return -ENOTSUPP;
+	}
+
+	return 0;
+}
+
+static int ath6kl_set_auth_type(struct ath6kl *ar,
+				enum nl80211_auth_type auth_type)
+{
+
+	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, auth_type);
+
+	switch (auth_type) {
+	case NL80211_AUTHTYPE_OPEN_SYSTEM:
+		ar->dot11_auth_mode = OPEN_AUTH;
+		break;
+	case NL80211_AUTHTYPE_SHARED_KEY:
+		ar->dot11_auth_mode = SHARED_AUTH;
+		break;
+	case NL80211_AUTHTYPE_NETWORK_EAP:
+		ar->dot11_auth_mode = LEAP_AUTH;
+		break;
+
+	case NL80211_AUTHTYPE_AUTOMATIC:
+		ar->dot11_auth_mode = OPEN_AUTH;
+		ar->auto_auth_stage = AUTH_OPEN_IN_PROGRESS;
+		break;
+
+	default:
+		ath6kl_err("%s: 0x%x not spported\n", __func__, auth_type);
+		return -ENOTSUPP;
+	}
+
+	return 0;
+}
+
+static int ath6kl_set_cipher(struct ath6kl *ar, u32 cipher, bool ucast)
+{
+	u8 *ar_cipher = ucast ? &ar->prwise_crypto : &ar->grp_crypto;
+	u8 *ar_cipher_len = ucast ? &ar->prwise_crypto_len : &ar->grp_crpto_len;
+
+	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: cipher 0x%x, ucast %u\n",
+		   __func__, cipher, ucast);
+
+	switch (cipher) {
+	case 0:
+		/* our own hack to use value 0 as no crypto used */
+		*ar_cipher = NONE_CRYPT;
+		*ar_cipher_len = 0;
+		break;
+	case WLAN_CIPHER_SUITE_WEP40:
+		*ar_cipher = WEP_CRYPT;
+		*ar_cipher_len = 5;
+		break;
+	case WLAN_CIPHER_SUITE_WEP104:
+		*ar_cipher = WEP_CRYPT;
+		*ar_cipher_len = 13;
+		break;
+	case WLAN_CIPHER_SUITE_TKIP:
+		*ar_cipher = TKIP_CRYPT;
+		*ar_cipher_len = 0;
+		break;
+	case WLAN_CIPHER_SUITE_CCMP:
+		*ar_cipher = AES_CRYPT;
+		*ar_cipher_len = 0;
+		break;
+	default:
+		ath6kl_err("cipher 0x%x not supported\n", cipher);
+		return -ENOTSUPP;
+	}
+
+	return 0;
+}
+
+static void ath6kl_set_key_mgmt(struct ath6kl *ar, u32 key_mgmt)
+{
+	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, key_mgmt);
+
+	if (key_mgmt == WLAN_AKM_SUITE_PSK) {
+		if (ar->auth_mode == WPA_AUTH)
+			ar->auth_mode = WPA_PSK_AUTH;
+		else if (ar->auth_mode == WPA2_AUTH)
+			ar->auth_mode = WPA2_PSK_AUTH;
+	} else if (key_mgmt != WLAN_AKM_SUITE_8021X) {
+		ar->auth_mode = NONE_AUTH;
+	}
+}
+
+static bool ath6kl_cfg80211_ready(struct ath6kl *ar)
+{
+	if (!test_bit(WMI_READY, &ar->flag)) {
+		ath6kl_err("wmi is not ready\n");
+		return false;
+	}
+
+	if (!test_bit(WLAN_ENABLED, &ar->flag)) {
+		ath6kl_err("wlan disabled\n");
+		return false;
+	}
+
+	return true;
+}
+
+static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
+				   struct cfg80211_connect_params *sme)
+{
+	struct ath6kl *ar = ath6kl_priv(dev);
+	int status;
+
+	ar->sme_state = SME_CONNECTING;
+
+	if (!ath6kl_cfg80211_ready(ar))
+		return -EIO;
+
+	if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
+		ath6kl_err("destroy in progress\n");
+		return -EBUSY;
+	}
+
+	if (test_bit(SKIP_SCAN, &ar->flag) &&
+	    ((sme->channel && sme->channel->center_freq == 0) ||
+	     (sme->bssid && is_zero_ether_addr(sme->bssid)))) {
+		ath6kl_err("SkipScan: channel or bssid invalid\n");
+		return -EINVAL;
+	}
+
+	if (down_interruptible(&ar->sem)) {
+		ath6kl_err("busy, couldn't get access\n");
+		return -ERESTARTSYS;
+	}
+
+	if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
+		ath6kl_err("busy, destroy in progress\n");
+		up(&ar->sem);
+		return -EBUSY;
+	}
+
+	if (ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)]) {
+		/*
+		 * sleep until the command queue drains
+		 */
+		wait_event_interruptible_timeout(ar->event_wq,
+			ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0,
+			WMI_TIMEOUT);
+		if (signal_pending(current)) {
+			ath6kl_err("cmd queue drain timeout\n");
+			up(&ar->sem);
+			return -EINTR;
+		}
+	}
+
+	if (test_bit(CONNECTED, &ar->flag) &&
+	    ar->ssid_len == sme->ssid_len &&
+	    !memcmp(ar->ssid, sme->ssid, ar->ssid_len)) {
+		ar->reconnect_flag = true;
+		status = ath6kl_wmi_reconnect_cmd(ar->wmi, ar->req_bssid,
+						  ar->ch_hint);
+
+		up(&ar->sem);
+		if (status) {
+			ath6kl_err("wmi_reconnect_cmd failed\n");
+			return -EIO;
+		}
+		return 0;
+	} else if (ar->ssid_len == sme->ssid_len &&
+		   !memcmp(ar->ssid, sme->ssid, ar->ssid_len)) {
+		ath6kl_disconnect(ar);
+	}
+
+	memset(ar->ssid, 0, sizeof(ar->ssid));
+	ar->ssid_len = sme->ssid_len;
+	memcpy(ar->ssid, sme->ssid, sme->ssid_len);
+
+	if (sme->channel)
+		ar->ch_hint = sme->channel->center_freq;
+
+	memset(ar->req_bssid, 0, sizeof(ar->req_bssid));
+	if (sme->bssid && !is_broadcast_ether_addr(sme->bssid))
+		memcpy(ar->req_bssid, sme->bssid, sizeof(ar->req_bssid));
+
+	ath6kl_set_wpa_version(ar, sme->crypto.wpa_versions);
+
+	status = ath6kl_set_auth_type(ar, sme->auth_type);
+	if (status) {
+		up(&ar->sem);
+		return status;
+	}
+
+	if (sme->crypto.n_ciphers_pairwise)
+		ath6kl_set_cipher(ar, sme->crypto.ciphers_pairwise[0], true);
+	else
+		ath6kl_set_cipher(ar, 0, true);
+
+	ath6kl_set_cipher(ar, sme->crypto.cipher_group, false);
+
+	if (sme->crypto.n_akm_suites)
+		ath6kl_set_key_mgmt(ar, sme->crypto.akm_suites[0]);
+
+	if ((sme->key_len) &&
+	    (ar->auth_mode == NONE_AUTH) && (ar->prwise_crypto == WEP_CRYPT)) {
+		struct ath6kl_key *key = NULL;
+
+		if (sme->key_idx < WMI_MIN_KEY_INDEX ||
+		    sme->key_idx > WMI_MAX_KEY_INDEX) {
+			ath6kl_err("key index %d out of bounds\n",
+				   sme->key_idx);
+			up(&ar->sem);
+			return -ENOENT;
+		}
+
+		key = &ar->keys[sme->key_idx];
+		key->key_len = sme->key_len;
+		memcpy(key->key, sme->key, key->key_len);
+		key->cipher = ar->prwise_crypto;
+		ar->def_txkey_index = sme->key_idx;
+
+		ath6kl_wmi_addkey_cmd(ar->wmi, sme->key_idx,
+				      ar->prwise_crypto,
+				      GROUP_USAGE | TX_USAGE,
+				      key->key_len,
+				      NULL,
+				      key->key, KEY_OP_INIT_VAL, NULL,
+				      NO_SYNC_WMIFLAG);
+	}
+
+	if (!ar->usr_bss_filter) {
+		if (ath6kl_wmi_bssfilter_cmd(ar->wmi, ALL_BSS_FILTER, 0) != 0) {
+			ath6kl_err("couldn't set bss filtering\n");
+			up(&ar->sem);
+			return -EIO;
+		}
+	}
+
+	ar->nw_type = ar->next_mode;
+
+	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+		   "%s: connect called with authmode %d dot11 auth %d"
+		   " PW crypto %d PW crypto len %d GRP crypto %d"
+		   " GRP crypto len %d channel hint %u\n",
+		   __func__,
+		   ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto,
+		   ar->prwise_crypto_len, ar->grp_crypto,
+		   ar->grp_crpto_len, ar->ch_hint);
+
+	ar->reconnect_flag = 0;
+	status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type,
+					ar->dot11_auth_mode, ar->auth_mode,
+					ar->prwise_crypto,
+					ar->prwise_crypto_len,
+					ar->grp_crypto, ar->grp_crpto_len,
+					ar->ssid_len, ar->ssid,
+					ar->req_bssid, ar->ch_hint,
+					ar->connect_ctrl_flags);
+
+	up(&ar->sem);
+
+	if (status == -EINVAL) {
+		memset(ar->ssid, 0, sizeof(ar->ssid));
+		ar->ssid_len = 0;
+		ath6kl_err("invalid request\n");
+		return -ENOENT;
+	} else if (status) {
+		ath6kl_err("ath6kl_wmi_connect_cmd failed\n");
+		return -EIO;
+	}
+
+	if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) &&
+	    ((ar->auth_mode == WPA_PSK_AUTH)
+	     || (ar->auth_mode == WPA2_PSK_AUTH))) {
+		mod_timer(&ar->disconnect_timer,
+			  jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL));
+	}
+
+	ar->connect_ctrl_flags &= ~CONNECT_DO_WPA_OFFLOAD;
+	set_bit(CONNECT_PEND, &ar->flag);
+
+	return 0;
+}
+
+void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel,
+				   u8 *bssid, u16 listen_intvl,
+				   u16 beacon_intvl,
+				   enum network_type nw_type,
+				   u8 beacon_ie_len, u8 assoc_req_len,
+				   u8 assoc_resp_len, u8 *assoc_info)
+{
+	u16 size = 0;
+	u16 capability = 0;
+	struct cfg80211_bss *bss = NULL;
+	struct ieee80211_mgmt *mgmt = NULL;
+	struct ieee80211_channel *ibss_ch = NULL;
+	s32 signal = 50 * 100;
+	u8 ie_buf_len = 0;
+	unsigned char ie_buf[256];
+	unsigned char *ptr_ie_buf = ie_buf;
+	unsigned char *ieeemgmtbuf = NULL;
+	u8 source_mac[ETH_ALEN];
+	u16 capa_mask;
+	u16 capa_val;
+
+	/* capinfo + listen interval */
+	u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16);
+
+	/* capinfo + status code +  associd */
+	u8 assoc_resp_ie_offset = sizeof(u16) + sizeof(u16) + sizeof(u16);
+
+	u8 *assoc_req_ie = assoc_info + beacon_ie_len + assoc_req_ie_offset;
+	u8 *assoc_resp_ie = assoc_info + beacon_ie_len + assoc_req_len +
+	    assoc_resp_ie_offset;
+
+	assoc_req_len -= assoc_req_ie_offset;
+	assoc_resp_len -= assoc_resp_ie_offset;
+
+	ar->auto_auth_stage = AUTH_IDLE;
+
+	if (nw_type & ADHOC_NETWORK) {
+		if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) {
+			ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+				   "%s: ath6k not in ibss mode\n", __func__);
+			return;
+		}
+	}
+
+	if (nw_type & INFRA_NETWORK) {
+		if (ar->wdev->iftype != NL80211_IFTYPE_STATION) {
+			ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+				   "%s: ath6k not in station mode\n", __func__);
+			return;
+		}
+	}
+
+	if (nw_type & ADHOC_NETWORK) {
+		capa_mask = WLAN_CAPABILITY_IBSS;
+		capa_val = WLAN_CAPABILITY_IBSS;
+	} else {
+		capa_mask = WLAN_CAPABILITY_ESS;
+		capa_val = WLAN_CAPABILITY_ESS;
+	}
+
+	/* Before informing the join/connect event, make sure that
+	 * bss entry is present in scan list, if it not present
+	 * construct and insert into scan list, otherwise that
+	 * event will be dropped on the way by cfg80211, due to
+	 * this keys will not be plumbed in case of WEP and
+	 * application will not be aware of join/connect status. */
+	bss = cfg80211_get_bss(ar->wdev->wiphy, NULL, bssid,
+			       ar->wdev->ssid, ar->wdev->ssid_len,
+			       capa_mask, capa_val);
+
+	/*
+	 * Earlier we were updating the cfg about bss by making a beacon frame
+	 * only if the entry for bss is not there. This can have some issue if
+	 * ROAM event is generated and a heavy traffic is ongoing. The ROAM
+	 * event is handled through a work queue and by the time it really gets
+	 * handled, BSS would have been aged out. So it is better to update the
+	 * cfg about BSS irrespective of its entry being present right now or
+	 * not.
+	 */
+
+	if (nw_type & ADHOC_NETWORK) {
+		/* construct 802.11 mgmt beacon */
+		if (ptr_ie_buf) {
+			*ptr_ie_buf++ = WLAN_EID_SSID;
+			*ptr_ie_buf++ = ar->ssid_len;
+			memcpy(ptr_ie_buf, ar->ssid, ar->ssid_len);
+			ptr_ie_buf += ar->ssid_len;
+
+			*ptr_ie_buf++ = WLAN_EID_IBSS_PARAMS;
+			*ptr_ie_buf++ = 2;	/* length */
+			*ptr_ie_buf++ = 0;	/* ATIM window */
+			*ptr_ie_buf++ = 0;	/* ATIM window */
+
+			/* TODO: update ibss params and include supported rates,
+			 * DS param set, extened support rates, wmm. */
+
+			ie_buf_len = ptr_ie_buf - ie_buf;
+		}
+
+		capability |= WLAN_CAPABILITY_IBSS;
+
+		if (ar->prwise_crypto == WEP_CRYPT)
+			capability |= WLAN_CAPABILITY_PRIVACY;
+
+		memcpy(source_mac, ar->net_dev->dev_addr, ETH_ALEN);
+		ptr_ie_buf = ie_buf;
+	} else {
+		capability = *(u16 *) (&assoc_info[beacon_ie_len]);
+		memcpy(source_mac, bssid, ETH_ALEN);
+		ptr_ie_buf = assoc_req_ie;
+		ie_buf_len = assoc_req_len;
+	}
+
+	size = offsetof(struct ieee80211_mgmt, u)
+	+ sizeof(mgmt->u.beacon)
+	+ ie_buf_len;
+
+	ieeemgmtbuf = kzalloc(size, GFP_ATOMIC);
+	if (!ieeemgmtbuf) {
+		ath6kl_err("ieee mgmt buf alloc error\n");
+		cfg80211_put_bss(bss);
+		return;
+	}
+
+	mgmt = (struct ieee80211_mgmt *)ieeemgmtbuf;
+	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+					  IEEE80211_STYPE_BEACON);
+	memset(mgmt->da, 0xff, ETH_ALEN);	/* broadcast addr */
+	memcpy(mgmt->sa, source_mac, ETH_ALEN);
+	memcpy(mgmt->bssid, bssid, ETH_ALEN);
+	mgmt->u.beacon.beacon_int = cpu_to_le16(beacon_intvl);
+	mgmt->u.beacon.capab_info = cpu_to_le16(capability);
+	memcpy(mgmt->u.beacon.variable, ptr_ie_buf, ie_buf_len);
+
+	ibss_ch = ieee80211_get_channel(ar->wdev->wiphy, (int)channel);
+
+	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+		   "%s: inform bss with bssid %pM channel %d beacon_intvl %d capability 0x%x\n",
+		   __func__, mgmt->bssid, ibss_ch->hw_value,
+		   beacon_intvl, capability);
+
+	bss = cfg80211_inform_bss_frame(ar->wdev->wiphy,
+					ibss_ch, mgmt,
+					size, signal, GFP_KERNEL);
+	kfree(ieeemgmtbuf);
+	cfg80211_put_bss(bss);
+
+	if (nw_type & ADHOC_NETWORK) {
+		cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL);
+		return;
+	}
+
+	if (ar->sme_state == SME_CONNECTING) {
+		/* inform connect result to cfg80211 */
+		ar->sme_state = SME_CONNECTED;
+		cfg80211_connect_result(ar->net_dev, bssid,
+					assoc_req_ie, assoc_req_len,
+					assoc_resp_ie, assoc_resp_len,
+					WLAN_STATUS_SUCCESS, GFP_KERNEL);
+	} else if (ar->sme_state == SME_CONNECTED) {
+		/* inform roam event to cfg80211 */
+		cfg80211_roamed(ar->net_dev, ibss_ch, bssid,
+				assoc_req_ie, assoc_req_len,
+				assoc_resp_ie, assoc_resp_len, GFP_KERNEL);
+	}
+}
+
+static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
+				      struct net_device *dev, u16 reason_code)
+{
+	struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
+
+	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__,
+		   reason_code);
+
+	if (!ath6kl_cfg80211_ready(ar))
+		return -EIO;
+
+	if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
+		ath6kl_err("busy, destroy in progress\n");
+		return -EBUSY;
+	}
+
+	if (down_interruptible(&ar->sem)) {
+		ath6kl_err("busy, couldn't get access\n");
+		return -ERESTARTSYS;
+	}
+
+	ar->reconnect_flag = 0;
+	ath6kl_disconnect(ar);
+	memset(ar->ssid, 0, sizeof(ar->ssid));
+	ar->ssid_len = 0;
+
+	if (!test_bit(SKIP_SCAN, &ar->flag))
+		memset(ar->req_bssid, 0, sizeof(ar->req_bssid));
+
+	up(&ar->sem);
+
+	return 0;
+}
+
+void ath6kl_cfg80211_disconnect_event(struct ath6kl *ar, u8 reason,
+				      u8 *bssid, u8 assoc_resp_len,
+				      u8 *assoc_info, u16 proto_reason)
+{
+	struct ath6kl_key *key = NULL;
+	u16 status;
+
+	if (ar->scan_req) {
+		cfg80211_scan_done(ar->scan_req, true);
+		ar->scan_req = NULL;
+	}
+
+	if (ar->nw_type & ADHOC_NETWORK) {
+		if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) {
+			ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+				   "%s: ath6k not in ibss mode\n", __func__);
+			return;
+		}
+		memset(bssid, 0, ETH_ALEN);
+		cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL);
+		return;
+	}
+
+	if (ar->nw_type & INFRA_NETWORK) {
+		if (ar->wdev->iftype != NL80211_IFTYPE_STATION) {
+			ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+				   "%s: ath6k not in station mode\n", __func__);
+			return;
+		}
+	}
+
+	if (!test_bit(CONNECT_PEND, &ar->flag)) {
+		if (reason != DISCONNECT_CMD)
+			ath6kl_wmi_disconnect_cmd(ar->wmi);
+
+		return;
+	}
+
+	if (reason == NO_NETWORK_AVAIL) {
+		/* connect cmd failed */
+		ath6kl_wmi_disconnect_cmd(ar->wmi);
+		return;
+	}
+
+	if (reason != DISCONNECT_CMD)
+		return;
+
+	if (!ar->auto_auth_stage) {
+		clear_bit(CONNECT_PEND, &ar->flag);
+
+		if (ar->sme_state == SME_CONNECTING) {
+			cfg80211_connect_result(ar->net_dev,
+						bssid, NULL, 0,
+						NULL, 0,
+						WLAN_STATUS_UNSPECIFIED_FAILURE,
+						GFP_KERNEL);
+		} else {
+			cfg80211_disconnected(ar->net_dev, reason,
+					      NULL, 0, GFP_KERNEL);
+		}
+
+		ar->sme_state = SME_DISCONNECTED;
+		return;
+	}
+
+	if (ar->dot11_auth_mode != OPEN_AUTH)
+		return;
+
+	/*
+	 * If the current auth algorithm is open, try shared and
+	 * make autoAuthStage idle. We do not make it leap for now
+	 * being.
+	 */
+	key = &ar->keys[ar->def_txkey_index];
+	if (down_interruptible(&ar->sem)) {
+		ath6kl_err("busy, couldn't get access\n");
+		return;
+	}
+
+	ar->dot11_auth_mode = SHARED_AUTH;
+	ar->auto_auth_stage = AUTH_IDLE;
+
+	ath6kl_wmi_addkey_cmd(ar->wmi,
+			      ar->def_txkey_index,
+			      ar->prwise_crypto,
+			      GROUP_USAGE | TX_USAGE,
+			      key->key_len, NULL,
+			      key->key,
+			      KEY_OP_INIT_VAL, NULL,
+			      NO_SYNC_WMIFLAG);
+
+	status = ath6kl_wmi_connect_cmd(ar->wmi,
+					ar->nw_type,
+					ar->dot11_auth_mode,
+					ar->auth_mode,
+					ar->prwise_crypto,
+					ar->prwise_crypto_len,
+					ar->grp_crypto,
+					ar->grp_crpto_len,
+					ar->ssid_len,
+					ar->ssid,
+					ar->req_bssid,
+					ar->ch_hint,
+					ar->connect_ctrl_flags);
+	up(&ar->sem);
+}
+
+static inline bool is_ch_11a(u16 ch)
+{
+	return (!((ch >= 2412) && (ch <= 2484)));
+}
+
+/* struct ath6kl_node_table::nt_nodelock is locked when calling this */
+void ath6kl_cfg80211_scan_node(struct wiphy *wiphy, struct bss *ni)
+{
+	u16 size;
+	unsigned char *ieeemgmtbuf = NULL;
+	struct ieee80211_mgmt *mgmt;
+	struct ieee80211_channel *channel;
+	struct ieee80211_supported_band *band;
+	struct ath6kl_common_ie *cie;
+	s32 signal;
+	int freq;
+
+	cie = &ni->ni_cie;
+
+	if (is_ch_11a(cie->ie_chan))
+		band = wiphy->bands[IEEE80211_BAND_5GHZ]; /* 11a */
+	else if ((cie->ie_erp) || (cie->ie_xrates))
+		band = wiphy->bands[IEEE80211_BAND_2GHZ]; /* 11g */
+	else
+		band = wiphy->bands[IEEE80211_BAND_2GHZ]; /* 11b */
+
+	size = ni->ni_framelen + offsetof(struct ieee80211_mgmt, u);
+	ieeemgmtbuf = kmalloc(size, GFP_ATOMIC);
+	if (!ieeemgmtbuf) {
+		ath6kl_err("ieee mgmt buf alloc error\n");
+		return;
+	}
+
+	/*
+	 * TODO: Update target to include 802.11 mac header while sending
+	 * bss info. Target removes 802.11 mac header while sending the bss
+	 * info to host, cfg80211 needs it, for time being just filling the
+	 * da, sa and bssid fields alone.
+	 */
+	mgmt = (struct ieee80211_mgmt *)ieeemgmtbuf;
+	memset(mgmt->da, 0xff, ETH_ALEN);	/*broadcast addr */
+	memcpy(mgmt->sa, ni->ni_macaddr, ETH_ALEN);
+	memcpy(mgmt->bssid, ni->ni_macaddr, ETH_ALEN);
+	memcpy(ieeemgmtbuf + offsetof(struct ieee80211_mgmt, u),
+	       ni->ni_buf, ni->ni_framelen);
+
+	freq = cie->ie_chan;
+	channel = ieee80211_get_channel(wiphy, freq);
+	signal = ni->ni_snr * 100;
+
+	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+		   "%s: bssid %pM ch %d freq %d size %d\n", __func__,
+		   mgmt->bssid, channel->hw_value, freq, size);
+	cfg80211_inform_bss_frame(wiphy, channel, mgmt,
+				  size, signal, GFP_ATOMIC);
+
+	kfree(ieeemgmtbuf);
+}
+
+static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
+				struct cfg80211_scan_request *request)
+{
+	struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
+	int ret = 0;
+
+	if (!ath6kl_cfg80211_ready(ar))
+		return -EIO;
+
+	if (!ar->usr_bss_filter) {
+		if (ath6kl_wmi_bssfilter_cmd(ar->wmi,
+					     (test_bit(CONNECTED, &ar->flag) ?
+					     ALL_BUT_BSS_FILTER :
+					     ALL_BSS_FILTER), 0) != 0) {
+			ath6kl_err("couldn't set bss filtering\n");
+			return -EIO;
+		}
+	}
+
+	if (request->n_ssids && request->ssids[0].ssid_len) {
+		u8 i;
+
+		if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1))
+			request->n_ssids = MAX_PROBED_SSID_INDEX - 1;
+
+		for (i = 0; i < request->n_ssids; i++)
+			ath6kl_wmi_probedssid_cmd(ar->wmi, i + 1,
+						  SPECIFIC_SSID_FLAG,
+						  request->ssids[i].ssid_len,
+						  request->ssids[i].ssid);
+	}
+
+	if (ath6kl_wmi_startscan_cmd(ar->wmi, WMI_LONG_SCAN, 0,
+				     false, 0, 0, 0, NULL) != 0) {
+		ath6kl_err("wmi_startscan_cmd failed\n");
+		ret = -EIO;
+	}
+
+	ar->scan_req = request;
+
+	return ret;
+}
+
+void ath6kl_cfg80211_scan_complete_event(struct ath6kl *ar, int status)
+{
+	int i;
+
+	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status %d\n", __func__, status);
+
+	if (!ar->scan_req)
+		return;
+
+	if ((status == -ECANCELED) || (status == -EBUSY)) {
+		cfg80211_scan_done(ar->scan_req, true);
+		goto out;
+	}
+
+	/* Translate data to cfg80211 mgmt format */
+	wlan_iterate_nodes(&ar->scan_table, ar->wdev->wiphy);
+
+	cfg80211_scan_done(ar->scan_req, false);
+
+	if (ar->scan_req->n_ssids && ar->scan_req->ssids[0].ssid_len) {
+		for (i = 0; i < ar->scan_req->n_ssids; i++) {
+			ath6kl_wmi_probedssid_cmd(ar->wmi, i + 1,
+						  DISABLE_SSID_FLAG,
+						  0, NULL);
+		}
+	}
+
+out:
+	ar->scan_req = NULL;
+}
+
+static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
+				   u8 key_index, bool pairwise,
+				   const u8 *mac_addr,
+				   struct key_params *params)
+{
+	struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
+	struct ath6kl_key *key = NULL;
+	u8 key_usage;
+	u8 key_type;
+	int status = 0;
+
+	if (!ath6kl_cfg80211_ready(ar))
+		return -EIO;
+
+	if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
+		ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+			   "%s: key index %d out of bounds\n", __func__,
+			   key_index);
+		return -ENOENT;
+	}
+
+	key = &ar->keys[key_index];
+	memset(key, 0, sizeof(struct ath6kl_key));
+
+	if (pairwise)
+		key_usage = PAIRWISE_USAGE;
+	else
+		key_usage = GROUP_USAGE;
+
+	if (params) {
+		if (params->key_len > WLAN_MAX_KEY_LEN ||
+		    params->seq_len > sizeof(key->seq))
+			return -EINVAL;
+
+		key->key_len = params->key_len;
+		memcpy(key->key, params->key, key->key_len);
+		key->seq_len = params->seq_len;
+		memcpy(key->seq, params->seq, key->seq_len);
+		key->cipher = params->cipher;
+	}
+
+	switch (key->cipher) {
+	case WLAN_CIPHER_SUITE_WEP40:
+	case WLAN_CIPHER_SUITE_WEP104:
+		key_type = WEP_CRYPT;
+		break;
+
+	case WLAN_CIPHER_SUITE_TKIP:
+		key_type = TKIP_CRYPT;
+		break;
+
+	case WLAN_CIPHER_SUITE_CCMP:
+		key_type = AES_CRYPT;
+		break;
+
+	default:
+		return -ENOTSUPP;
+	}
+
+	if (((ar->auth_mode == WPA_PSK_AUTH)
+	     || (ar->auth_mode == WPA2_PSK_AUTH))
+	    && (key_usage & GROUP_USAGE))
+		del_timer(&ar->disconnect_timer);
+
+	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+		   "%s: index %d, key_len %d, key_type 0x%x, key_usage 0x%x, seq_len %d\n",
+		   __func__, key_index, key->key_len, key_type,
+		   key_usage, key->seq_len);
+
+	ar->def_txkey_index = key_index;
+	status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index,
+				       key_type, key_usage, key->key_len,
+				       key->seq, key->key, KEY_OP_INIT_VAL,
+				       (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
+
+	if (status)
+		return -EIO;
+
+	return 0;
+}
+
+static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
+				   u8 key_index, bool pairwise,
+				   const u8 *mac_addr)
+{
+	struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
+
+	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
+
+	if (!ath6kl_cfg80211_ready(ar))
+		return -EIO;
+
+	if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
+		ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+			   "%s: key index %d out of bounds\n", __func__,
+			   key_index);
+		return -ENOENT;
+	}
+
+	if (!ar->keys[key_index].key_len) {
+		ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+			   "%s: index %d is empty\n", __func__, key_index);
+		return 0;
+	}
+
+	ar->keys[key_index].key_len = 0;
+
+	return ath6kl_wmi_deletekey_cmd(ar->wmi, key_index);
+}
+
+static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
+				   u8 key_index, bool pairwise,
+				   const u8 *mac_addr, void *cookie,
+				   void (*callback) (void *cookie,
+						     struct key_params *))
+{
+	struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
+	struct ath6kl_key *key = NULL;
+	struct key_params params;
+
+	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
+
+	if (!ath6kl_cfg80211_ready(ar))
+		return -EIO;
+
+	if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
+		ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+			   "%s: key index %d out of bounds\n", __func__,
+			   key_index);
+		return -ENOENT;
+	}
+
+	key = &ar->keys[key_index];
+	memset(&params, 0, sizeof(params));
+	params.cipher = key->cipher;
+	params.key_len = key->key_len;
+	params.seq_len = key->seq_len;
+	params.seq = key->seq;
+	params.key = key->key;
+
+	callback(cookie, &params);
+
+	return key->key_len ? 0 : -ENOENT;
+}
+
+static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
+					   struct net_device *ndev,
+					   u8 key_index, bool unicast,
+					   bool multicast)
+{
+	struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
+	struct ath6kl_key *key = NULL;
+	int status = 0;
+	u8 key_usage;
+
+	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
+
+	if (!ath6kl_cfg80211_ready(ar))
+		return -EIO;
+
+	if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
+		ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+			   "%s: key index %d out of bounds\n",
+			   __func__, key_index);
+		return -ENOENT;
+	}
+
+	if (!ar->keys[key_index].key_len) {
+		ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: invalid key index %d\n",
+			   __func__, key_index);
+		return -EINVAL;
+	}
+
+	ar->def_txkey_index = key_index;
+	key = &ar->keys[ar->def_txkey_index];
+	key_usage = GROUP_USAGE;
+	if (ar->prwise_crypto == WEP_CRYPT)
+		key_usage |= TX_USAGE;
+
+	status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index,
+				       ar->prwise_crypto, key_usage,
+				       key->key_len, key->seq, key->key,
+				       KEY_OP_INIT_VAL, NULL,
+				       SYNC_BOTH_WMIFLAG);
+	if (status)
+		return -EIO;
+
+	return 0;
+}
+
+void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl *ar, u8 keyid,
+				       bool ismcast)
+{
+	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+		   "%s: keyid %d, ismcast %d\n", __func__, keyid, ismcast);
+
+	cfg80211_michael_mic_failure(ar->net_dev, ar->bssid,
+				     (ismcast ? NL80211_KEYTYPE_GROUP :
+				      NL80211_KEYTYPE_PAIRWISE), keyid, NULL,
+				     GFP_KERNEL);
+}
+
+static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
+{
+	struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
+	int ret;
+
+	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: changed 0x%x\n", __func__,
+		   changed);
+
+	if (!ath6kl_cfg80211_ready(ar))
+		return -EIO;
+
+	if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
+		ret = ath6kl_wmi_set_rts_cmd(ar->wmi, wiphy->rts_threshold);
+		if (ret != 0) {
+			ath6kl_err("ath6kl_wmi_set_rts_cmd failed\n");
+			return -EIO;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * The type nl80211_tx_power_setting replaces the following
+ * data type from 2.6.36 onwards
+*/
+static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
+				       enum nl80211_tx_power_setting type,
+				       int dbm)
+{
+	struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
+	u8 ath6kl_dbm;
+
+	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
+		   type, dbm);
+
+	if (!ath6kl_cfg80211_ready(ar))
+		return -EIO;
+
+	switch (type) {
+	case NL80211_TX_POWER_AUTOMATIC:
+		return 0;
+	case NL80211_TX_POWER_LIMITED:
+		ar->tx_pwr = ath6kl_dbm = dbm;
+		break;
+	default:
+		ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
+			   __func__, type);
+		return -EOPNOTSUPP;
+	}
+
+	ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, ath6kl_dbm);
+
+	return 0;
+}
+
+static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
+{
+	struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
+
+	if (!ath6kl_cfg80211_ready(ar))
+		return -EIO;
+
+	if (test_bit(CONNECTED, &ar->flag)) {
+		ar->tx_pwr = 0;
+
+		if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi) != 0) {
+			ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n");
+			return -EIO;
+		}
+
+		wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 0,
+						 5 * HZ);
+
+		if (signal_pending(current)) {
+			ath6kl_err("target did not respond\n");
+			return -EINTR;
+		}
+	}
+
+	*dbm = ar->tx_pwr;
+	return 0;
+}
+
+static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
+					  struct net_device *dev,
+					  bool pmgmt, int timeout)
+{
+	struct ath6kl *ar = ath6kl_priv(dev);
+	struct wmi_power_mode_cmd mode;
+
+	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n",
+		   __func__, pmgmt, timeout);
+
+	if (!ath6kl_cfg80211_ready(ar))
+		return -EIO;
+
+	if (pmgmt) {
+		ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
+		mode.pwr_mode = REC_POWER;
+	} else {
+		ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
+		mode.pwr_mode = MAX_PERF_POWER;
+	}
+
+	if (ath6kl_wmi_powermode_cmd(ar->wmi, mode.pwr_mode) != 0) {
+		ath6kl_err("wmi_powermode_cmd failed\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
+					struct net_device *ndev,
+					enum nl80211_iftype type, u32 *flags,
+					struct vif_params *params)
+{
+	struct ath6kl *ar = ath6kl_priv(ndev);
+	struct wireless_dev *wdev = ar->wdev;
+
+	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
+
+	if (!ath6kl_cfg80211_ready(ar))
+		return -EIO;
+
+	switch (type) {
+	case NL80211_IFTYPE_STATION:
+		ar->next_mode = INFRA_NETWORK;
+		break;
+	case NL80211_IFTYPE_ADHOC:
+		ar->next_mode = ADHOC_NETWORK;
+		break;
+	default:
+		ath6kl_err("invalid interface type %u\n", type);
+		return -EOPNOTSUPP;
+	}
+
+	wdev->iftype = type;
+
+	return 0;
+}
+
+static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
+				     struct net_device *dev,
+				     struct cfg80211_ibss_params *ibss_param)
+{
+	struct ath6kl *ar = ath6kl_priv(dev);
+	int status;
+
+	if (!ath6kl_cfg80211_ready(ar))
+		return -EIO;
+
+	ar->ssid_len = ibss_param->ssid_len;
+	memcpy(ar->ssid, ibss_param->ssid, ar->ssid_len);
+
+	if (ibss_param->channel)
+		ar->ch_hint = ibss_param->channel->center_freq;
+
+	if (ibss_param->channel_fixed) {
+		/*
+		 * TODO: channel_fixed: The channel should be fixed, do not
+		 * search for IBSSs to join on other channels. Target
+		 * firmware does not support this feature, needs to be
+		 * updated.
+		 */
+		return -EOPNOTSUPP;
+	}
+
+	memset(ar->req_bssid, 0, sizeof(ar->req_bssid));
+	if (ibss_param->bssid && !is_broadcast_ether_addr(ibss_param->bssid))
+		memcpy(ar->req_bssid, ibss_param->bssid, sizeof(ar->req_bssid));
+
+	ath6kl_set_wpa_version(ar, 0);
+
+	status = ath6kl_set_auth_type(ar, NL80211_AUTHTYPE_OPEN_SYSTEM);
+	if (status)
+		return status;
+
+	if (ibss_param->privacy) {
+		ath6kl_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, true);
+		ath6kl_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, false);
+	} else {
+		ath6kl_set_cipher(ar, 0, true);
+		ath6kl_set_cipher(ar, 0, false);
+	}
+
+	ar->nw_type = ar->next_mode;
+
+	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+		   "%s: connect called with authmode %d dot11 auth %d"
+		   " PW crypto %d PW crypto len %d GRP crypto %d"
+		   " GRP crypto len %d channel hint %u\n",
+		   __func__,
+		   ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto,
+		   ar->prwise_crypto_len, ar->grp_crypto,
+		   ar->grp_crpto_len, ar->ch_hint);
+
+	status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type,
+					ar->dot11_auth_mode, ar->auth_mode,
+					ar->prwise_crypto,
+					ar->prwise_crypto_len,
+					ar->grp_crypto, ar->grp_crpto_len,
+					ar->ssid_len, ar->ssid,
+					ar->req_bssid, ar->ch_hint,
+					ar->connect_ctrl_flags);
+	set_bit(CONNECT_PEND, &ar->flag);
+
+	return 0;
+}
+
+static int ath6kl_cfg80211_leave_ibss(struct wiphy *wiphy,
+				      struct net_device *dev)
+{
+	struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
+
+	if (!ath6kl_cfg80211_ready(ar))
+		return -EIO;
+
+	ath6kl_disconnect(ar);
+	memset(ar->ssid, 0, sizeof(ar->ssid));
+	ar->ssid_len = 0;
+
+	return 0;
+}
+
+static const u32 cipher_suites[] = {
+	WLAN_CIPHER_SUITE_WEP40,
+	WLAN_CIPHER_SUITE_WEP104,
+	WLAN_CIPHER_SUITE_TKIP,
+	WLAN_CIPHER_SUITE_CCMP,
+};
+
+static bool is_rate_legacy(s32 rate)
+{
+	static const s32 legacy[] = { 1000, 2000, 5500, 11000,
+		6000, 9000, 12000, 18000, 24000,
+		36000, 48000, 54000
+	};
+	u8 i;
+
+	for (i = 0; i < ARRAY_SIZE(legacy); i++)
+		if (rate == legacy[i])
+			return true;
+
+	return false;
+}
+
+static bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi)
+{
+	static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000,
+		52000, 58500, 65000, 72200
+	};
+	u8 i;
+
+	for (i = 0; i < ARRAY_SIZE(ht20); i++) {
+		if (rate == ht20[i]) {
+			if (i == ARRAY_SIZE(ht20) - 1)
+				/* last rate uses sgi */
+				*sgi = true;
+			else
+				*sgi = false;
+
+			*mcs = i;
+			return true;
+		}
+	}
+	return false;
+}
+
+static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi)
+{
+	static const s32 ht40[] = { 13500, 27000, 40500, 54000,
+		81000, 108000, 121500, 135000,
+		150000
+	};
+	u8 i;
+
+	for (i = 0; i < ARRAY_SIZE(ht40); i++) {
+		if (rate == ht40[i]) {
+			if (i == ARRAY_SIZE(ht40) - 1)
+				/* last rate uses sgi */
+				*sgi = true;
+			else
+				*sgi = false;
+
+			*mcs = i;
+			return true;
+		}
+	}
+
+	return false;
+}
+
+static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
+			      u8 *mac, struct station_info *sinfo)
+{
+	struct ath6kl *ar = ath6kl_priv(dev);
+	long left;
+	bool sgi;
+	s32 rate;
+	int ret;
+	u8 mcs;
+
+	if (memcmp(mac, ar->bssid, ETH_ALEN) != 0)
+		return -ENOENT;
+
+	if (down_interruptible(&ar->sem))
+		return -EBUSY;
+
+	set_bit(STATS_UPDATE_PEND, &ar->flag);
+
+	ret = ath6kl_wmi_get_stats_cmd(ar->wmi);
+
+	if (ret != 0) {
+		up(&ar->sem);
+		return -EIO;
+	}
+
+	left = wait_event_interruptible_timeout(ar->event_wq,
+						!test_bit(STATS_UPDATE_PEND,
+							  &ar->flag),
+						WMI_TIMEOUT);
+
+	up(&ar->sem);
+
+	if (left == 0)
+		return -ETIMEDOUT;
+	else if (left < 0)
+		return left;
+
+	if (ar->target_stats.rx_byte) {
+		sinfo->rx_bytes = ar->target_stats.rx_byte;
+		sinfo->filled |= STATION_INFO_RX_BYTES;
+		sinfo->rx_packets = ar->target_stats.rx_pkt;
+		sinfo->filled |= STATION_INFO_RX_PACKETS;
+	}
+
+	if (ar->target_stats.tx_byte) {
+		sinfo->tx_bytes = ar->target_stats.tx_byte;
+		sinfo->filled |= STATION_INFO_TX_BYTES;
+		sinfo->tx_packets = ar->target_stats.tx_pkt;
+		sinfo->filled |= STATION_INFO_TX_PACKETS;
+	}
+
+	sinfo->signal = ar->target_stats.cs_rssi;
+	sinfo->filled |= STATION_INFO_SIGNAL;
+
+	rate = ar->target_stats.tx_ucast_rate;
+
+	if (is_rate_legacy(rate)) {
+		sinfo->txrate.legacy = rate / 100;
+	} else if (is_rate_ht20(rate, &mcs, &sgi)) {
+		if (sgi) {
+			sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+			sinfo->txrate.mcs = mcs - 1;
+		} else {
+			sinfo->txrate.mcs = mcs;
+		}
+
+		sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
+	} else if (is_rate_ht40(rate, &mcs, &sgi)) {
+		if (sgi) {
+			sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+			sinfo->txrate.mcs = mcs - 1;
+		} else {
+			sinfo->txrate.mcs = mcs;
+		}
+
+		sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
+		sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
+	} else {
+		ath6kl_warn("invalid rate: %d\n", rate);
+		return 0;
+	}
+
+	sinfo->filled |= STATION_INFO_TX_BITRATE;
+
+	return 0;
+}
+
+static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
+			    struct cfg80211_pmksa *pmksa)
+{
+	struct ath6kl *ar = ath6kl_priv(netdev);
+	return ath6kl_wmi_setpmkid_cmd(ar->wmi, pmksa->bssid,
+				       pmksa->pmkid, true);
+}
+
+static int ath6kl_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
+			    struct cfg80211_pmksa *pmksa)
+{
+	struct ath6kl *ar = ath6kl_priv(netdev);
+	return ath6kl_wmi_setpmkid_cmd(ar->wmi, pmksa->bssid,
+				       pmksa->pmkid, false);
+}
+
+static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
+{
+	struct ath6kl *ar = ath6kl_priv(netdev);
+	if (test_bit(CONNECTED, &ar->flag))
+		return ath6kl_wmi_setpmkid_cmd(ar->wmi, ar->bssid, NULL, false);
+	return 0;
+}
+
+static struct cfg80211_ops ath6kl_cfg80211_ops = {
+	.change_virtual_intf = ath6kl_cfg80211_change_iface,
+	.scan = ath6kl_cfg80211_scan,
+	.connect = ath6kl_cfg80211_connect,
+	.disconnect = ath6kl_cfg80211_disconnect,
+	.add_key = ath6kl_cfg80211_add_key,
+	.get_key = ath6kl_cfg80211_get_key,
+	.del_key = ath6kl_cfg80211_del_key,
+	.set_default_key = ath6kl_cfg80211_set_default_key,
+	.set_wiphy_params = ath6kl_cfg80211_set_wiphy_params,
+	.set_tx_power = ath6kl_cfg80211_set_txpower,
+	.get_tx_power = ath6kl_cfg80211_get_txpower,
+	.set_power_mgmt = ath6kl_cfg80211_set_power_mgmt,
+	.join_ibss = ath6kl_cfg80211_join_ibss,
+	.leave_ibss = ath6kl_cfg80211_leave_ibss,
+	.get_station = ath6kl_get_station,
+	.set_pmksa = ath6kl_set_pmksa,
+	.del_pmksa = ath6kl_del_pmksa,
+	.flush_pmksa = ath6kl_flush_pmksa,
+};
+
+struct wireless_dev *ath6kl_cfg80211_init(struct device *dev)
+{
+	int ret = 0;
+	struct wireless_dev *wdev;
+
+	wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
+	if (!wdev) {
+		ath6kl_err("couldn't allocate wireless device\n");
+		return NULL;
+	}
+
+	/* create a new wiphy for use with cfg80211 */
+	wdev->wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
+	if (!wdev->wiphy) {
+		ath6kl_err("couldn't allocate wiphy device\n");
+		kfree(wdev);
+		return NULL;
+	}
+
+	/* set device pointer for wiphy */
+	set_wiphy_dev(wdev->wiphy, dev);
+
+	wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+	    BIT(NL80211_IFTYPE_ADHOC);
+	/* max num of ssids that can be probed during scanning */
+	wdev->wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
+	wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
+	wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
+	wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+
+	wdev->wiphy->cipher_suites = cipher_suites;
+	wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+
+	ret = wiphy_register(wdev->wiphy);
+	if (ret < 0) {
+		ath6kl_err("couldn't register wiphy device\n");
+		wiphy_free(wdev->wiphy);
+		kfree(wdev);
+		return NULL;
+	}
+
+	return wdev;
+}
+
+void ath6kl_cfg80211_deinit(struct ath6kl *ar)
+{
+	struct wireless_dev *wdev = ar->wdev;
+
+	if (ar->scan_req) {
+		cfg80211_scan_done(ar->scan_req, true);
+		ar->scan_req = NULL;
+	}
+
+	if (!wdev)
+		return;
+
+	wiphy_unregister(wdev->wiphy);
+	wiphy_free(wdev->wiphy);
+	kfree(wdev);
+}
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h
new file mode 100644
index 000000000000..a84adc249c61
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2011 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 ATH6KL_CFG80211_H
+#define ATH6KL_CFG80211_H
+
+struct wireless_dev *ath6kl_cfg80211_init(struct device *dev);
+void ath6kl_cfg80211_deinit(struct ath6kl *ar);
+
+void ath6kl_cfg80211_scan_complete_event(struct ath6kl *ar, int status);
+
+void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel,
+				   u8 *bssid, u16 listen_intvl,
+				   u16 beacon_intvl,
+				   enum network_type nw_type,
+				   u8 beacon_ie_len, u8 assoc_req_len,
+				   u8 assoc_resp_len, u8 *assoc_info);
+
+void ath6kl_cfg80211_disconnect_event(struct ath6kl *ar, u8 reason,
+				      u8 *bssid, u8 assoc_resp_len,
+				      u8 *assoc_info, u16 proto_reason);
+
+void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl *ar, u8 keyid,
+				     bool ismcast);
+
+#endif /* ATH6KL_CFG80211_H */
diff --git a/drivers/net/wireless/ath/ath6kl/common.h b/drivers/net/wireless/ath/ath6kl/common.h
new file mode 100644
index 000000000000..6b0d45642fe3
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/common.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2010-2011 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 COMMON_H
+#define COMMON_H
+
+#include <linux/netdevice.h>
+
+#define ATH6KL_MAX_IE			256
+
+extern int ath6kl_printk(const char *level, const char *fmt, ...);
+
+#define A_CACHE_LINE_PAD            128
+
+/*
+ * Reflects the version of binary interface exposed by ATH6KL target
+ * firmware. Needs to be incremented by 1 for any change in the firmware
+ * that requires upgrade of the driver on the host side for the change to
+ * work correctly
+ */
+#define ATH6KL_ABI_VERSION        1
+
+#define SIGNAL_QUALITY_METRICS_NUM_MAX    2
+
+enum {
+	SIGNAL_QUALITY_METRICS_SNR = 0,
+	SIGNAL_QUALITY_METRICS_RSSI,
+	SIGNAL_QUALITY_METRICS_ALL,
+};
+
+/*
+ * Data Path
+ */
+
+#define WMI_MAX_TX_DATA_FRAME_LENGTH	      \
+	(1500 + sizeof(struct wmi_data_hdr) + \
+	 sizeof(struct ethhdr) +      \
+	 sizeof(struct ath6kl_llc_snap_hdr))
+
+/* An AMSDU frame */ /* The MAX AMSDU length of AR6003 is 3839 */
+#define WMI_MAX_AMSDU_RX_DATA_FRAME_LENGTH    \
+	(3840 + sizeof(struct wmi_data_hdr) + \
+	 sizeof(struct ethhdr) +      \
+	 sizeof(struct ath6kl_llc_snap_hdr))
+
+#define EPPING_ALIGNMENT_PAD			       \
+	(((sizeof(struct htc_frame_hdr) + 3) & (~0x3)) \
+	 - sizeof(struct htc_frame_hdr))
+
+struct ath6kl_llc_snap_hdr {
+	u8 dsap;
+	u8 ssap;
+	u8 cntl;
+	u8 org_code[3];
+	__be16 eth_type;
+} __packed;
+
+enum crypto_type {
+	NONE_CRYPT          = 0x01,
+	WEP_CRYPT           = 0x02,
+	TKIP_CRYPT          = 0x04,
+	AES_CRYPT           = 0x08,
+};
+
+#define ATH6KL_NODE_HASHSIZE 32
+/* simple hash is enough for variation of macaddr */
+#define ATH6KL_NODE_HASH(addr)   \
+	(((const u8 *)(addr))[ETH_ALEN - 1] % \
+	 ATH6KL_NODE_HASHSIZE)
+
+/*
+ * Table of ath6kl_node instances.  Each ieee80211com
+ * has at least one for holding the scan candidates.
+ * When operating as an access point or in ibss mode there
+ * is a second table for associated stations or neighbors.
+ */
+struct ath6kl_node_table {
+	spinlock_t nt_nodelock;	/* on node table */
+	struct bss *nt_node_first;	/* information of all nodes */
+	struct bss *nt_node_last;	/* information of all nodes */
+	struct bss *nt_hash[ATH6KL_NODE_HASHSIZE];
+	const char *nt_name;	/* for debugging */
+	u32 nt_node_age;		/* node aging time */
+};
+
+#define WLAN_NODE_INACT_TIMEOUT_MSEC    120000
+#define WLAN_NODE_INACT_CNT		4
+
+struct ath6kl_common_ie {
+	u16 ie_chan;
+	u8 *ie_tstamp;
+	u8 *ie_ssid;
+	u8 *ie_rates;
+	u8 *ie_xrates;
+	u8 *ie_country;
+	u8 *ie_wpa;
+	u8 *ie_rsn;
+	u8 *ie_wmm;
+	u8 *ie_ath;
+	u16 ie_capInfo;
+	u16 ie_beaconInt;
+	u8 *ie_tim;
+	u8 *ie_chswitch;
+	u8 ie_erp;
+	u8 *ie_wsc;
+	u8 *ie_htcap;
+	u8 *ie_htop;
+};
+
+struct bss {
+	u8 ni_macaddr[ETH_ALEN];
+	u8 ni_snr;
+	s16 ni_rssi;
+	struct bss *ni_list_next;
+	struct bss *ni_list_prev;
+	struct bss *ni_hash_next;
+	struct bss *ni_hash_prev;
+	struct ath6kl_common_ie ni_cie;
+	u8 *ni_buf;
+	u16 ni_framelen;
+	struct ath6kl_node_table *ni_table;
+	u32 ni_refcnt;
+
+	u32 ni_tstamp;
+	u32 ni_actcnt;
+};
+
+struct htc_endpoint_credit_dist;
+struct ath6kl;
+enum htc_credit_dist_reason;
+struct htc_credit_state_info;
+
+struct bss *wlan_node_alloc(int wh_size);
+void wlan_node_free(struct bss *ni);
+void wlan_setup_node(struct ath6kl_node_table *nt, struct bss *ni,
+		     const u8 *mac_addr);
+struct bss *wlan_find_node(struct ath6kl_node_table *nt,
+			   const u8 *mac_addr);
+void wlan_node_reclaim(struct ath6kl_node_table *nt, struct bss *ni);
+void wlan_free_allnodes(struct ath6kl_node_table *nt);
+void wlan_iterate_nodes(struct ath6kl_node_table *nt, void *arg);
+
+void wlan_node_table_init(struct ath6kl_node_table *nt);
+void wlan_node_table_cleanup(struct ath6kl_node_table *nt);
+
+void wlan_refresh_inactive_nodes(struct ath6kl *ar);
+
+struct bss *wlan_find_ssid_node(struct ath6kl_node_table *nt, u8 *ssid,
+				  u32 ssid_len, bool is_wpa2, bool match_ssid);
+
+void wlan_node_return(struct ath6kl_node_table *nt, struct bss *ni);
+
+int ath6k_setup_credit_dist(void *htc_handle,
+			    struct htc_credit_state_info *cred_info);
+void ath6k_credit_distribute(struct htc_credit_state_info *cred_inf,
+			     struct list_head *epdist_list,
+			     enum htc_credit_dist_reason reason);
+void ath6k_credit_init(struct htc_credit_state_info *cred_inf,
+		       struct list_head *ep_list,
+		       int tot_credits);
+void ath6k_seek_credits(struct htc_credit_state_info *cred_inf,
+			struct htc_endpoint_credit_dist *ep_dist);
+struct ath6kl *ath6kl_core_alloc(struct device *sdev);
+int ath6kl_core_init(struct ath6kl *ar);
+int ath6kl_unavail_ev(struct ath6kl *ar);
+struct sk_buff *ath6kl_buf_alloc(int size);
+#endif /* COMMON_H */
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
new file mode 100644
index 000000000000..74170229523f
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -0,0 +1,544 @@
+/*
+ * Copyright (c) 2010-2011 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 CORE_H
+#define CORE_H
+
+#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/firmware.h>
+#include <linux/sched.h>
+#include <net/cfg80211.h>
+#include "htc.h"
+#include "wmi.h"
+#include "bmi.h"
+
+#define MAX_ATH6KL                        1
+#define ATH6KL_MAX_RX_BUFFERS             16
+#define ATH6KL_BUFFER_SIZE                1664
+#define ATH6KL_MAX_AMSDU_RX_BUFFERS       4
+#define ATH6KL_AMSDU_REFILL_THRESHOLD     3
+#define ATH6KL_AMSDU_BUFFER_SIZE     (WMI_MAX_AMSDU_RX_DATA_FRAME_LENGTH + 128)
+#define MAX_MSDU_SUBFRAME_PAYLOAD_LEN	1508
+#define MIN_MSDU_SUBFRAME_PAYLOAD_LEN	46
+
+#define USER_SAVEDKEYS_STAT_INIT     0
+#define USER_SAVEDKEYS_STAT_RUN      1
+
+#define ATH6KL_TX_TIMEOUT      10
+#define ATH6KL_MAX_ENDPOINTS   4
+#define MAX_NODE_NUM           15
+
+/* MAX_HI_COOKIE_NUM are reserved for high priority traffic */
+#define MAX_DEF_COOKIE_NUM                180
+#define MAX_HI_COOKIE_NUM                 18	/* 10% of MAX_COOKIE_NUM */
+#define MAX_COOKIE_NUM                 (MAX_DEF_COOKIE_NUM + MAX_HI_COOKIE_NUM)
+
+#define MAX_DEFAULT_SEND_QUEUE_DEPTH      (MAX_DEF_COOKIE_NUM / WMM_NUM_AC)
+
+#define DISCON_TIMER_INTVAL               10000  /* in msec */
+#define A_DEFAULT_LISTEN_INTERVAL         100
+#define A_MAX_WOW_LISTEN_INTERVAL         1000
+
+/* AR6003 1.0 definitions */
+#define AR6003_REV1_VERSION                 0x300002ba
+
+/* AR6003 2.0 definitions */
+#define AR6003_REV2_VERSION                 0x30000384
+#define AR6003_REV2_PATCH_DOWNLOAD_ADDRESS  0x57e910
+#define AR6003_REV2_OTP_FILE                "ath6k/AR6003/hw2.0/otp.bin.z77"
+#define AR6003_REV2_FIRMWARE_FILE           "ath6k/AR6003/hw2.0/athwlan.bin.z77"
+#define AR6003_REV2_PATCH_FILE              "ath6k/AR6003/hw2.0/data.patch.bin"
+#define AR6003_REV2_BOARD_DATA_FILE         "ath6k/AR6003/hw2.0/bdata.bin"
+#define AR6003_REV2_DEFAULT_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.SD31.bin"
+
+/* AR6003 3.0 definitions */
+#define AR6003_REV3_VERSION                 0x30000582
+#define AR6003_REV3_OTP_FILE                "ath6k/AR6003/hw2.1.1/otp.bin"
+#define AR6003_REV3_FIRMWARE_FILE           "ath6k/AR6003/hw2.1.1/athwlan.bin"
+#define AR6003_REV3_PATCH_FILE            "ath6k/AR6003/hw2.1.1/data.patch.bin"
+#define AR6003_REV3_BOARD_DATA_FILE       "ath6k/AR6003/hw2.1.1/bdata.bin"
+#define AR6003_REV3_DEFAULT_BOARD_DATA_FILE	\
+	"ath6k/AR6003/hw2.1.1/bdata.SD31.bin"
+
+/* Per STA data, used in AP mode */
+#define STA_PS_AWAKE		BIT(0)
+#define	STA_PS_SLEEP		BIT(1)
+#define	STA_PS_POLLED		BIT(2)
+
+/* HTC TX packet tagging definitions */
+#define ATH6KL_CONTROL_PKT_TAG    HTC_TX_PACKET_TAG_USER_DEFINED
+#define ATH6KL_DATA_PKT_TAG       (ATH6KL_CONTROL_PKT_TAG + 1)
+
+#define AR6003_CUST_DATA_SIZE 16
+
+#define AGGR_WIN_IDX(x, y)          ((x) % (y))
+#define AGGR_INCR_IDX(x, y)         AGGR_WIN_IDX(((x) + 1), (y))
+#define AGGR_DCRM_IDX(x, y)         AGGR_WIN_IDX(((x) - 1), (y))
+#define ATH6KL_MAX_SEQ_NO		0xFFF
+#define ATH6KL_NEXT_SEQ_NO(x)		(((x) + 1) & ATH6KL_MAX_SEQ_NO)
+
+#define NUM_OF_TIDS         8
+#define AGGR_SZ_DEFAULT     8
+
+#define AGGR_WIN_SZ_MIN     2
+#define AGGR_WIN_SZ_MAX     8
+
+#define TID_WINDOW_SZ(_x)   ((_x) << 1)
+
+#define AGGR_NUM_OF_FREE_NETBUFS    16
+
+#define AGGR_RX_TIMEOUT     400	/* in ms */
+
+#define WMI_TIMEOUT (2 * HZ)
+
+#define MBOX_YIELD_LIMIT 99
+
+/* configuration lags */
+/*
+ * ATH6KL_CONF_IGNORE_ERP_BARKER: Ignore the barker premable in
+ * ERP IE of beacon to determine the short premable support when
+ * sending (Re)Assoc req.
+ * ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN: Don't send the power
+ * module state transition failure events which happen during
+ * scan, to the host.
+ */
+#define ATH6KL_CONF_IGNORE_ERP_BARKER		BIT(0)
+#define ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN  BIT(1)
+#define ATH6KL_CONF_ENABLE_11N			BIT(2)
+#define ATH6KL_CONF_ENABLE_TX_BURST		BIT(3)
+
+enum wlan_low_pwr_state {
+	WLAN_POWER_STATE_ON,
+	WLAN_POWER_STATE_CUT_PWR,
+	WLAN_POWER_STATE_DEEP_SLEEP,
+	WLAN_POWER_STATE_WOW
+};
+
+enum sme_state {
+	SME_DISCONNECTED,
+	SME_CONNECTING,
+	SME_CONNECTED
+};
+
+struct skb_hold_q {
+	struct sk_buff *skb;
+	bool is_amsdu;
+	u16 seq_no;
+};
+
+struct rxtid {
+	bool aggr;
+	bool progress;
+	bool timer_mon;
+	u16 win_sz;
+	u16 seq_next;
+	u32 hold_q_sz;
+	struct skb_hold_q *hold_q;
+	struct sk_buff_head q;
+	spinlock_t lock;
+};
+
+struct rxtid_stats {
+	u32 num_into_aggr;
+	u32 num_dups;
+	u32 num_oow;
+	u32 num_mpdu;
+	u32 num_amsdu;
+	u32 num_delivered;
+	u32 num_timeouts;
+	u32 num_hole;
+	u32 num_bar;
+};
+
+struct aggr_info {
+	u8 aggr_sz;
+	u8 timer_scheduled;
+	struct timer_list timer;
+	struct net_device *dev;
+	struct rxtid rx_tid[NUM_OF_TIDS];
+	struct sk_buff_head free_q;
+	struct rxtid_stats stat[NUM_OF_TIDS];
+};
+
+struct ath6kl_wep_key {
+	u8 key_index;
+	u8 key_len;
+	u8 key[64];
+};
+
+#define ATH6KL_KEY_SEQ_LEN 8
+
+struct ath6kl_key {
+	u8 key[WLAN_MAX_KEY_LEN];
+	u8 key_len;
+	u8 seq[ATH6KL_KEY_SEQ_LEN];
+	u8 seq_len;
+	u32 cipher;
+};
+
+struct ath6kl_node_mapping {
+	u8 mac_addr[ETH_ALEN];
+	u8 ep_id;
+	u8 tx_pend;
+};
+
+struct ath6kl_cookie {
+	struct sk_buff *skb;
+	u32 map_no;
+	struct htc_packet htc_pkt;
+	struct ath6kl_cookie *arc_list_next;
+};
+
+struct ath6kl_sta {
+	u16 sta_flags;
+	u8 mac[ETH_ALEN];
+	u8 aid;
+	u8 keymgmt;
+	u8 ucipher;
+	u8 auth;
+	u8 wpa_ie[ATH6KL_MAX_IE];
+	struct sk_buff_head psq;
+	spinlock_t psq_lock;
+};
+
+struct ath6kl_version {
+	u32 target_ver;
+	u32 wlan_ver;
+	u32 abi_ver;
+};
+
+struct ath6kl_bmi {
+	u32 cmd_credits;
+	bool done_sent;
+	u8 *cmd_buf;
+};
+
+struct target_stats {
+	u64 tx_pkt;
+	u64 tx_byte;
+	u64 tx_ucast_pkt;
+	u64 tx_ucast_byte;
+	u64 tx_mcast_pkt;
+	u64 tx_mcast_byte;
+	u64 tx_bcast_pkt;
+	u64 tx_bcast_byte;
+	u64 tx_rts_success_cnt;
+	u64 tx_pkt_per_ac[4];
+
+	u64 tx_err;
+	u64 tx_fail_cnt;
+	u64 tx_retry_cnt;
+	u64 tx_mult_retry_cnt;
+	u64 tx_rts_fail_cnt;
+
+	u64 rx_pkt;
+	u64 rx_byte;
+	u64 rx_ucast_pkt;
+	u64 rx_ucast_byte;
+	u64 rx_mcast_pkt;
+	u64 rx_mcast_byte;
+	u64 rx_bcast_pkt;
+	u64 rx_bcast_byte;
+	u64 rx_frgment_pkt;
+
+	u64 rx_err;
+	u64 rx_crc_err;
+	u64 rx_key_cache_miss;
+	u64 rx_decrypt_err;
+	u64 rx_dupl_frame;
+
+	u64 tkip_local_mic_fail;
+	u64 tkip_cnter_measures_invoked;
+	u64 tkip_replays;
+	u64 tkip_fmt_err;
+	u64 ccmp_fmt_err;
+	u64 ccmp_replays;
+
+	u64 pwr_save_fail_cnt;
+
+	u64 cs_bmiss_cnt;
+	u64 cs_low_rssi_cnt;
+	u64 cs_connect_cnt;
+	u64 cs_discon_cnt;
+
+	s32 tx_ucast_rate;
+	s32 rx_ucast_rate;
+
+	u32 lq_val;
+
+	u32 wow_pkt_dropped;
+	u16 wow_evt_discarded;
+
+	s16 noise_floor_calib;
+	s16 cs_rssi;
+	s16 cs_ave_beacon_rssi;
+	u8 cs_ave_beacon_snr;
+	u8 cs_last_roam_msec;
+	u8 cs_snr;
+
+	u8 wow_host_pkt_wakeups;
+	u8 wow_host_evt_wakeups;
+
+	u32 arp_received;
+	u32 arp_matched;
+	u32 arp_replied;
+};
+
+struct ath6kl_mbox_info {
+	u32 htc_addr;
+	u32 htc_ext_addr;
+	u32 htc_ext_sz;
+
+	u32 block_size;
+
+	u32 gmbox_addr;
+
+	u32 gmbox_sz;
+};
+
+/*
+ * 802.11i defines an extended IV for use with non-WEP ciphers.
+ * When the EXTIV bit is set in the key id byte an additional
+ * 4 bytes immediately follow the IV for TKIP.  For CCMP the
+ * EXTIV bit is likewise set but the 8 bytes represent the
+ * CCMP header rather than IV+extended-IV.
+ */
+
+#define ATH6KL_KEYBUF_SIZE 16
+#define ATH6KL_MICBUF_SIZE (8+8)	/* space for both tx and rx */
+
+#define ATH6KL_KEY_XMIT  0x01
+#define ATH6KL_KEY_RECV  0x02
+#define ATH6KL_KEY_DEFAULT   0x80	/* default xmit key */
+
+/*
+ * WPA/RSN get/set key request.  Specify the key/cipher
+ * type and whether the key is to be used for sending and/or
+ * receiving.  The key index should be set only when working
+ * with global keys (use IEEE80211_KEYIX_NONE for ``no index'').
+ * Otherwise a unicast/pairwise key is specified by the bssid
+ * (on a station) or mac address (on an ap).  They key length
+ * must include any MIC key data; otherwise it should be no
+ * more than ATH6KL_KEYBUF_SIZE.
+ */
+struct ath6kl_req_key {
+	u8 ik_type;	/* key/cipher type */
+	u8 ik_pad;
+	u16 ik_keyix;	/* key index */
+	u8 ik_keylen;	/* key length in bytes */
+	u8 ik_flags;
+	u8 ik_macaddr[ETH_ALEN];
+	u64 ik_keyrsc;	/* key receive sequence counter */
+	u64 ik_keytsc;	/* key transmit sequence counter */
+	u8 ik_keydata[ATH6KL_KEYBUF_SIZE + ATH6KL_MICBUF_SIZE];
+};
+
+/* Flag info */
+#define WMI_ENABLED	0
+#define WMI_READY	1
+#define CONNECTED	2
+#define STATS_UPDATE_PEND 3
+#define CONNECT_PEND	  4
+#define WMM_ENABLED	  5
+#define NETQ_STOPPED	  6
+#define WMI_CTRL_EP_FULL  7
+#define DTIM_EXPIRED	  8
+#define DESTROY_IN_PROGRESS  9
+#define NETDEV_REGISTERED    10
+#define SKIP_SCAN	     11
+#define WLAN_ENABLED	     12
+
+struct ath6kl {
+	struct device *dev;
+	struct net_device *net_dev;
+	struct ath6kl_bmi bmi;
+	const struct ath6kl_hif_ops *hif_ops;
+	struct wmi *wmi;
+	int tx_pending[ENDPOINT_MAX];
+	int total_tx_data_pend;
+	struct htc_target *htc_target;
+	void *hif_priv;
+	spinlock_t lock;
+	struct semaphore sem;
+	int ssid_len;
+	u8 ssid[IEEE80211_MAX_SSID_LEN];
+	u8 next_mode;
+	u8 nw_type;
+	u8 dot11_auth_mode;
+	u8 auth_mode;
+	u8 prwise_crypto;
+	u8 prwise_crypto_len;
+	u8 grp_crypto;
+	u8 grp_crpto_len;
+	u8 def_txkey_index;
+	struct ath6kl_wep_key wep_key_list[WMI_MAX_KEY_INDEX + 1];
+	u8 bssid[ETH_ALEN];
+	u8 req_bssid[ETH_ALEN];
+	u16 ch_hint;
+	u16 bss_ch;
+	u16 listen_intvl_b;
+	u16 listen_intvl_t;
+	struct ath6kl_version version;
+	u32 target_type;
+	u8 tx_pwr;
+	struct net_device_stats net_stats;
+	struct target_stats target_stats;
+	struct ath6kl_node_mapping node_map[MAX_NODE_NUM];
+	u8 ibss_ps_enable;
+	u8 node_num;
+	u8 next_ep_id;
+	struct ath6kl_cookie *cookie_list;
+	u32 cookie_count;
+	enum htc_endpoint_id ac2ep_map[WMM_NUM_AC];
+	bool ac_stream_active[WMM_NUM_AC];
+	u8 ac_stream_pri_map[WMM_NUM_AC];
+	u8 hiac_stream_active_pri;
+	u8 ep2ac_map[ENDPOINT_MAX];
+	enum htc_endpoint_id ctrl_ep;
+	struct htc_credit_state_info credit_state_info;
+	u32 connect_ctrl_flags;
+	u32 user_key_ctrl;
+	u8 usr_bss_filter;
+	struct ath6kl_sta sta_list[AP_MAX_NUM_STA];
+	u8 sta_list_index;
+	struct ath6kl_req_key ap_mode_bkey;
+	struct sk_buff_head mcastpsq;
+	spinlock_t mcastpsq_lock;
+	u8 intra_bss;
+	struct aggr_info *aggr_cntxt;
+	struct wmi_ap_mode_stat ap_stats;
+	u8 ap_country_code[3];
+	struct list_head amsdu_rx_buffer_queue;
+	struct timer_list disconnect_timer;
+	u8 rx_meta_ver;
+	struct wireless_dev *wdev;
+	struct cfg80211_scan_request *scan_req;
+	struct ath6kl_key keys[WMI_MAX_KEY_INDEX + 1];
+	enum sme_state sme_state;
+	enum wlan_low_pwr_state wlan_pwr_state;
+	struct wmi_scan_params_cmd sc_params;
+#define AR_MCAST_FILTER_MAC_ADDR_SIZE  4
+	u8 auto_auth_stage;
+
+	u16 conf_flags;
+	wait_queue_head_t event_wq;
+	struct ath6kl_mbox_info mbox_info;
+
+	struct ath6kl_cookie cookie_mem[MAX_COOKIE_NUM];
+	int reconnect_flag;
+	unsigned long flag;
+
+	u8 *fw_board;
+	size_t fw_board_len;
+
+	u8 *fw_otp;
+	size_t fw_otp_len;
+
+	u8 *fw;
+	size_t fw_len;
+
+	u8 *fw_patch;
+	size_t fw_patch_len;
+
+	struct workqueue_struct *ath6kl_wq;
+
+	struct ath6kl_node_table scan_table;
+};
+
+static inline void *ath6kl_priv(struct net_device *dev)
+{
+	return wdev_priv(dev->ieee80211_ptr);
+}
+
+static inline void ath6kl_deposit_credit_to_ep(struct htc_credit_state_info
+					       *cred_info,
+					       struct htc_endpoint_credit_dist
+					       *ep_dist, int credits)
+{
+	ep_dist->credits += credits;
+	ep_dist->cred_assngd += credits;
+	cred_info->cur_free_credits -= credits;
+}
+
+void ath6kl_destroy(struct net_device *dev, unsigned int unregister);
+int ath6kl_configure_target(struct ath6kl *ar);
+void ath6kl_detect_error(unsigned long ptr);
+void disconnect_timer_handler(unsigned long ptr);
+void init_netdev(struct net_device *dev);
+void ath6kl_cookie_init(struct ath6kl *ar);
+void ath6kl_cookie_cleanup(struct ath6kl *ar);
+void ath6kl_rx(struct htc_target *target, struct htc_packet *packet);
+void ath6kl_tx_complete(void *context, struct list_head *packet_queue);
+enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
+					       struct htc_packet *packet);
+void ath6kl_stop_txrx(struct ath6kl *ar);
+void ath6kl_cleanup_amsdu_rxbufs(struct ath6kl *ar);
+int ath6kl_access_datadiag(struct ath6kl *ar, u32 address,
+			   u8 *data, u32 length, bool read);
+int ath6kl_read_reg_diag(struct ath6kl *ar, u32 *address, u32 *data);
+void ath6kl_init_profile_info(struct ath6kl *ar);
+void ath6kl_tx_data_cleanup(struct ath6kl *ar);
+void ath6kl_stop_endpoint(struct net_device *dev, bool keep_profile,
+			  bool get_dbglogs);
+
+struct ath6kl_cookie *ath6kl_alloc_cookie(struct ath6kl *ar);
+void ath6kl_free_cookie(struct ath6kl *ar, struct ath6kl_cookie *cookie);
+int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev);
+
+struct aggr_info *aggr_init(struct net_device *dev);
+void ath6kl_rx_refill(struct htc_target *target,
+		      enum htc_endpoint_id endpoint);
+void ath6kl_refill_amsdu_rxbufs(struct ath6kl *ar, int count);
+struct htc_packet *ath6kl_alloc_amsdu_rxbuf(struct htc_target *target,
+					    enum htc_endpoint_id endpoint,
+					    int len);
+void aggr_module_destroy(struct aggr_info *aggr_info);
+void aggr_reset_state(struct aggr_info *aggr_info);
+
+struct ath6kl_sta *ath6kl_find_sta(struct ath6kl *ar, u8 * node_addr);
+struct ath6kl_sta *ath6kl_find_sta_by_aid(struct ath6kl *ar, u8 aid);
+
+void ath6kl_ready_event(void *devt, u8 * datap, u32 sw_ver, u32 abi_ver);
+int ath6kl_control_tx(void *devt, struct sk_buff *skb,
+		      enum htc_endpoint_id eid);
+void ath6kl_connect_event(struct ath6kl *ar, u16 channel,
+			  u8 *bssid, u16 listen_int,
+			  u16 beacon_int, enum network_type net_type,
+			  u8 beacon_ie_len, u8 assoc_req_len,
+			  u8 assoc_resp_len, u8 *assoc_info);
+void ath6kl_disconnect_event(struct ath6kl *ar, u8 reason,
+			     u8 *bssid, u8 assoc_resp_len,
+			     u8 *assoc_info, u16 prot_reason_status);
+void ath6kl_tkip_micerr_event(struct ath6kl *ar, u8 keyid, bool ismcast);
+void ath6kl_txpwr_rx_evt(void *devt, u8 tx_pwr);
+void ath6kl_scan_complete_evt(struct ath6kl *ar, int status);
+void ath6kl_tgt_stats_event(struct ath6kl *ar, u8 *ptr, u32 len);
+void ath6kl_indicate_tx_activity(void *devt, u8 traffic_class, bool active);
+enum htc_endpoint_id ath6kl_ac2_endpoint_id(void *devt, u8 ac);
+
+void ath6kl_pspoll_event(struct ath6kl *ar, u8 aid);
+
+void ath6kl_dtimexpiry_event(struct ath6kl *ar);
+void ath6kl_disconnect(struct ath6kl *ar);
+void aggr_recv_delba_req_evt(struct ath6kl *ar, u8 tid);
+void aggr_recv_addba_req_evt(struct ath6kl *ar, u8 tid, u16 seq_no,
+			     u8 win_sz);
+void ath6kl_wakeup_event(void *dev);
+void ath6kl_target_failure(struct ath6kl *ar);
+
+void ath6kl_cfg80211_scan_node(struct wiphy *wiphy, struct bss *ni);
+#endif /* CORE_H */
diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c
new file mode 100644
index 000000000000..316136c8b903
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/debug.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2004-2011 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.
+ */
+
+#include "core.h"
+#include "debug.h"
+
+int ath6kl_printk(const char *level, const char *fmt, ...)
+{
+	struct va_format vaf;
+	va_list args;
+	int rtn;
+
+	va_start(args, fmt);
+
+	vaf.fmt = fmt;
+	vaf.va = &args;
+
+	rtn = printk("%sath6kl: %pV", level, &vaf);
+
+	va_end(args);
+
+	return rtn;
+}
+
+#ifdef CONFIG_ATH6KL_DEBUG
+void ath6kl_dump_registers(struct ath6kl_device *dev,
+			   struct ath6kl_irq_proc_registers *irq_proc_reg,
+			   struct ath6kl_irq_enable_reg *irq_enable_reg)
+{
+
+	ath6kl_dbg(ATH6KL_DBG_ANY, ("<------- Register Table -------->\n"));
+
+	if (irq_proc_reg != NULL) {
+		ath6kl_dbg(ATH6KL_DBG_ANY,
+			"Host Int status:           0x%x\n",
+			irq_proc_reg->host_int_status);
+		ath6kl_dbg(ATH6KL_DBG_ANY,
+			   "CPU Int status:            0x%x\n",
+			irq_proc_reg->cpu_int_status);
+		ath6kl_dbg(ATH6KL_DBG_ANY,
+			   "Error Int status:          0x%x\n",
+			irq_proc_reg->error_int_status);
+		ath6kl_dbg(ATH6KL_DBG_ANY,
+			   "Counter Int status:        0x%x\n",
+			irq_proc_reg->counter_int_status);
+		ath6kl_dbg(ATH6KL_DBG_ANY,
+			   "Mbox Frame:                0x%x\n",
+			irq_proc_reg->mbox_frame);
+		ath6kl_dbg(ATH6KL_DBG_ANY,
+			   "Rx Lookahead Valid:        0x%x\n",
+			irq_proc_reg->rx_lkahd_valid);
+		ath6kl_dbg(ATH6KL_DBG_ANY,
+			   "Rx Lookahead 0:            0x%x\n",
+			irq_proc_reg->rx_lkahd[0]);
+		ath6kl_dbg(ATH6KL_DBG_ANY,
+			   "Rx Lookahead 1:            0x%x\n",
+			irq_proc_reg->rx_lkahd[1]);
+
+		if (dev->ar->mbox_info.gmbox_addr != 0) {
+			/*
+			 * If the target supports GMBOX hardware, dump some
+			 * additional state.
+			 */
+			ath6kl_dbg(ATH6KL_DBG_ANY,
+				"GMBOX Host Int status 2:   0x%x\n",
+				irq_proc_reg->host_int_status2);
+			ath6kl_dbg(ATH6KL_DBG_ANY,
+				"GMBOX RX Avail:            0x%x\n",
+				irq_proc_reg->gmbox_rx_avail);
+			ath6kl_dbg(ATH6KL_DBG_ANY,
+				"GMBOX lookahead alias 0:   0x%x\n",
+				irq_proc_reg->rx_gmbox_lkahd_alias[0]);
+			ath6kl_dbg(ATH6KL_DBG_ANY,
+				"GMBOX lookahead alias 1:   0x%x\n",
+				irq_proc_reg->rx_gmbox_lkahd_alias[1]);
+		}
+
+	}
+
+	if (irq_enable_reg != NULL) {
+		ath6kl_dbg(ATH6KL_DBG_ANY,
+			"Int status Enable:         0x%x\n",
+			irq_enable_reg->int_status_en);
+		ath6kl_dbg(ATH6KL_DBG_ANY, "Counter Int status Enable: 0x%x\n",
+			irq_enable_reg->cntr_int_status_en);
+	}
+	ath6kl_dbg(ATH6KL_DBG_ANY, "<------------------------------->\n");
+}
+
+static void dump_cred_dist(struct htc_endpoint_credit_dist *ep_dist)
+{
+	ath6kl_dbg(ATH6KL_DBG_ANY,
+		   "--- endpoint: %d  svc_id: 0x%X ---\n",
+		   ep_dist->endpoint, ep_dist->svc_id);
+	ath6kl_dbg(ATH6KL_DBG_ANY, " dist_flags     : 0x%X\n",
+		   ep_dist->dist_flags);
+	ath6kl_dbg(ATH6KL_DBG_ANY, " cred_norm      : %d\n",
+		   ep_dist->cred_norm);
+	ath6kl_dbg(ATH6KL_DBG_ANY, " cred_min       : %d\n",
+		   ep_dist->cred_min);
+	ath6kl_dbg(ATH6KL_DBG_ANY, " credits        : %d\n",
+		   ep_dist->credits);
+	ath6kl_dbg(ATH6KL_DBG_ANY, " cred_assngd    : %d\n",
+		   ep_dist->cred_assngd);
+	ath6kl_dbg(ATH6KL_DBG_ANY, " seek_cred      : %d\n",
+		   ep_dist->seek_cred);
+	ath6kl_dbg(ATH6KL_DBG_ANY, " cred_sz        : %d\n",
+		   ep_dist->cred_sz);
+	ath6kl_dbg(ATH6KL_DBG_ANY, " cred_per_msg   : %d\n",
+		   ep_dist->cred_per_msg);
+	ath6kl_dbg(ATH6KL_DBG_ANY, " cred_to_dist   : %d\n",
+		   ep_dist->cred_to_dist);
+	ath6kl_dbg(ATH6KL_DBG_ANY, " txq_depth      : %d\n",
+		   get_queue_depth(&((struct htc_endpoint *)
+				     ep_dist->htc_rsvd)->txq));
+	ath6kl_dbg(ATH6KL_DBG_ANY,
+		   "----------------------------------\n");
+}
+
+void dump_cred_dist_stats(struct htc_target *target)
+{
+	struct htc_endpoint_credit_dist *ep_list;
+
+	if (!AR_DBG_LVL_CHECK(ATH6KL_DBG_TRC))
+		return;
+
+	list_for_each_entry(ep_list, &target->cred_dist_list, list)
+		dump_cred_dist(ep_list);
+
+	ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "ctxt:%p dist:%p\n",
+		   target->cred_dist_cntxt, NULL);
+	ath6kl_dbg(ATH6KL_DBG_TRC, "credit distribution, total : %d, free : %d\n",
+		   target->cred_dist_cntxt->total_avail_credits,
+		   target->cred_dist_cntxt->cur_free_credits);
+}
+
+#endif
diff --git a/drivers/net/wireless/ath/ath6kl/debug.h b/drivers/net/wireless/ath/ath6kl/debug.h
new file mode 100644
index 000000000000..66b399962f01
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/debug.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2011 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 DEBUG_H
+#define DEBUG_H
+
+#include "htc_hif.h"
+
+enum ATH6K_DEBUG_MASK {
+	ATH6KL_DBG_WLAN_CONNECT = BIT(0),     /* wlan connect */
+	ATH6KL_DBG_WLAN_SCAN    = BIT(1),     /* wlan scan */
+	ATH6KL_DBG_WLAN_TX      = BIT(2),     /* wlan tx */
+	ATH6KL_DBG_WLAN_RX      = BIT(3),     /* wlan rx */
+	ATH6KL_DBG_BMI		= BIT(4),     /* bmi tracing */
+	ATH6KL_DBG_HTC_SEND     = BIT(5),     /* htc send */
+	ATH6KL_DBG_HTC_RECV     = BIT(6),     /* htc recv */
+	ATH6KL_DBG_IRQ		= BIT(7),     /* interrupt processing */
+	ATH6KL_DBG_PM           = BIT(8),     /* power management */
+	ATH6KL_DBG_WLAN_NODE    = BIT(9),     /* general wlan node tracing */
+	ATH6KL_DBG_WMI          = BIT(10),    /* wmi tracing */
+	ATH6KL_DBG_TRC	        = BIT(11),    /* generic func tracing */
+	ATH6KL_DBG_SCATTER	= BIT(12),    /* hif scatter tracing */
+	ATH6KL_DBG_WLAN_CFG     = BIT(13),    /* cfg80211 i/f file tracing */
+	ATH6KL_DBG_RAW_BYTES    = BIT(14),    /* dump tx/rx and wmi frames */
+	ATH6KL_DBG_AGGR		= BIT(15),    /* aggregation */
+	ATH6KL_DBG_ANY	        = 0xffffffff  /* enable all logs */
+};
+
+extern unsigned int debug_mask;
+extern int ath6kl_printk(const char *level, const char *fmt, ...)
+	__attribute__ ((format (printf, 2, 3)));
+
+#define ath6kl_info(fmt, ...)				\
+	ath6kl_printk(KERN_INFO, fmt, ##__VA_ARGS__)
+#define ath6kl_err(fmt, ...)					\
+	ath6kl_printk(KERN_ERR, fmt, ##__VA_ARGS__)
+#define ath6kl_warn(fmt, ...)					\
+	ath6kl_printk(KERN_WARNING, fmt, ##__VA_ARGS__)
+
+#define AR_DBG_LVL_CHECK(mask)	(debug_mask & mask)
+
+#ifdef CONFIG_ATH6KL_DEBUG
+#define ath6kl_dbg(mask, fmt, ...)					\
+	({								\
+	 int rtn;							\
+	 if (debug_mask & mask)						\
+		rtn = ath6kl_printk(KERN_DEBUG, fmt, ##__VA_ARGS__);	\
+	 else								\
+		rtn = 0;						\
+									\
+	 rtn;								\
+	 })
+
+static inline void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask,
+				   const char *msg, const void *buf,
+				   size_t len)
+{
+	if (debug_mask & mask) {
+		ath6kl_dbg(mask, "%s\n", msg);
+		print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buf, len);
+	}
+}
+
+void ath6kl_dump_registers(struct ath6kl_device *dev,
+			   struct ath6kl_irq_proc_registers *irq_proc_reg,
+			   struct ath6kl_irq_enable_reg *irq_en_reg);
+void dump_cred_dist_stats(struct htc_target *target);
+#else
+static inline int ath6kl_dbg(enum ATH6K_DEBUG_MASK dbg_mask,
+			     const char *fmt, ...)
+{
+	return 0;
+}
+
+static inline void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask,
+				   const char *msg, const void *buf,
+				   size_t len)
+{
+}
+
+static inline void ath6kl_dump_registers(struct ath6kl_device *dev,
+		struct ath6kl_irq_proc_registers *irq_proc_reg,
+		struct ath6kl_irq_enable_reg *irq_en_reg)
+{
+
+}
+static inline void dump_cred_dist_stats(struct htc_target *target)
+{
+}
+#endif
+
+#endif
diff --git a/drivers/net/wireless/ath/ath6kl/hif-ops.h b/drivers/net/wireless/ath/ath6kl/hif-ops.h
new file mode 100644
index 000000000000..c923979776a0
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/hif-ops.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2004-2011 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 HIF_OPS_H
+#define HIF_OPS_H
+
+#include "hif.h"
+
+static inline int hif_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf,
+				      u32 len, u32 request)
+{
+	return ar->hif_ops->read_write_sync(ar, addr, buf, len, request);
+}
+
+static inline int hif_write_async(struct ath6kl *ar, u32 address, u8 *buffer,
+				  u32 length, u32 request,
+				  struct htc_packet *packet)
+{
+	return ar->hif_ops->write_async(ar, address, buffer, length,
+					request, packet);
+}
+static inline void ath6kl_hif_irq_enable(struct ath6kl *ar)
+{
+	return ar->hif_ops->irq_enable(ar);
+}
+
+static inline void ath6kl_hif_irq_disable(struct ath6kl *ar)
+{
+	return ar->hif_ops->irq_disable(ar);
+}
+
+static inline struct hif_scatter_req *hif_scatter_req_get(struct ath6kl *ar)
+{
+	return ar->hif_ops->scatter_req_get(ar);
+}
+
+static inline void hif_scatter_req_add(struct ath6kl *ar,
+				       struct hif_scatter_req *s_req)
+{
+	return ar->hif_ops->scatter_req_add(ar, s_req);
+}
+
+static inline int ath6kl_hif_enable_scatter(struct ath6kl *ar)
+{
+	return ar->hif_ops->enable_scatter(ar);
+}
+
+static inline int ath6kl_hif_scat_req_rw(struct ath6kl *ar,
+					 struct hif_scatter_req *scat_req)
+{
+	return ar->hif_ops->scat_req_rw(ar, scat_req);
+}
+
+static inline void ath6kl_hif_cleanup_scatter(struct ath6kl *ar)
+{
+	return ar->hif_ops->cleanup_scatter(ar);
+}
+
+#endif
diff --git a/drivers/net/wireless/ath/ath6kl/hif.h b/drivers/net/wireless/ath/ath6kl/hif.h
new file mode 100644
index 000000000000..5ceff54775a1
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/hif.h
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2004-2011 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 HIF_H
+#define HIF_H
+
+#include "common.h"
+#include "core.h"
+
+#include <linux/scatterlist.h>
+
+#define BUS_REQUEST_MAX_NUM                64
+#define HIF_MBOX_BLOCK_SIZE                128
+#define HIF_MBOX0_BLOCK_SIZE               1
+
+#define HIF_DMA_BUFFER_SIZE (32 * 1024)
+#define CMD53_FIXED_ADDRESS 1
+#define CMD53_INCR_ADDRESS  2
+
+#define MAX_SCATTER_REQUESTS             4
+#define MAX_SCATTER_ENTRIES_PER_REQ      16
+#define MAX_SCATTER_REQ_TRANSFER_SIZE    (32 * 1024)
+
+#define MANUFACTURER_ID_AR6003_BASE        0x300
+    /* SDIO manufacturer ID and Codes */
+#define MANUFACTURER_ID_ATH6KL_BASE_MASK     0xFF00
+#define MANUFACTURER_CODE                  0x271	/* Atheros */
+
+/* Mailbox address in SDIO address space */
+#define HIF_MBOX_BASE_ADDR                 0x800
+#define HIF_MBOX_WIDTH                     0x800
+
+#define HIF_MBOX_END_ADDR  (HTC_MAILBOX_NUM_MAX * HIF_MBOX_WIDTH - 1)
+
+/* version 1 of the chip has only a 12K extended mbox range */
+#define HIF_MBOX0_EXT_BASE_ADDR  0x4000
+#define HIF_MBOX0_EXT_WIDTH      (12*1024)
+
+/* GMBOX addresses */
+#define HIF_GMBOX_BASE_ADDR                0x7000
+#define HIF_GMBOX_WIDTH                    0x4000
+
+/* interrupt mode register */
+#define CCCR_SDIO_IRQ_MODE_REG         0xF0
+
+/* mode to enable special 4-bit interrupt assertion without clock */
+#define SDIO_IRQ_MODE_ASYNC_4BIT_IRQ   (1 << 0)
+
+struct bus_request {
+	struct list_head list;
+
+	/* request data */
+	u32 address;
+
+	u8 *buffer;
+	u32 length;
+	u32 request;
+	struct htc_packet *packet;
+	int status;
+
+	/* this is a scatter request */
+	struct hif_scatter_req *scat_req;
+};
+
+/* direction of transfer (read/write) */
+#define HIF_READ                    0x00000001
+#define HIF_WRITE                   0x00000002
+#define HIF_DIR_MASK                (HIF_READ | HIF_WRITE)
+
+/*
+ *     emode - This indicates the whether the command is to be executed in a
+ *             blocking or non-blocking fashion (HIF_SYNCHRONOUS/
+ *             HIF_ASYNCHRONOUS). The read/write data paths in HTC have been
+ *             implemented using the asynchronous mode allowing the the bus
+ *             driver to indicate the completion of operation through the
+ *             registered callback routine. The requirement primarily comes
+ *             from the contexts these operations get called from (a driver's
+ *             transmit context or the ISR context in case of receive).
+ *             Support for both of these modes is essential.
+ */
+#define HIF_SYNCHRONOUS             0x00000010
+#define HIF_ASYNCHRONOUS            0x00000020
+#define HIF_EMODE_MASK              (HIF_SYNCHRONOUS | HIF_ASYNCHRONOUS)
+
+/*
+ *     dmode - An interface may support different kinds of commands based on
+ *             the tradeoff between the amount of data it can carry and the
+ *             setup time. Byte and Block modes are supported (HIF_BYTE_BASIS/
+ *             HIF_BLOCK_BASIS). In case of latter, the data is rounded off
+ *             to the nearest block size by padding. The size of the block is
+ *             configurable at compile time using the HIF_BLOCK_SIZE and is
+ *             negotiated with the target during initialization after the
+ *             ATH6KL interrupts are enabled.
+ */
+#define HIF_BYTE_BASIS              0x00000040
+#define HIF_BLOCK_BASIS             0x00000080
+#define HIF_DMODE_MASK              (HIF_BYTE_BASIS | HIF_BLOCK_BASIS)
+
+/*
+ *     amode - This indicates if the address has to be incremented on ATH6KL
+ *             after every read/write operation (HIF?FIXED_ADDRESS/
+ *             HIF_INCREMENTAL_ADDRESS).
+ */
+#define HIF_FIXED_ADDRESS           0x00000100
+#define HIF_INCREMENTAL_ADDRESS     0x00000200
+#define HIF_AMODE_MASK		  (HIF_FIXED_ADDRESS | HIF_INCREMENTAL_ADDRESS)
+
+#define HIF_WR_ASYNC_BYTE_INC					\
+	(HIF_WRITE | HIF_ASYNCHRONOUS |				\
+	 HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS)
+
+#define HIF_WR_ASYNC_BLOCK_INC					\
+	(HIF_WRITE | HIF_ASYNCHRONOUS |				\
+	 HIF_BLOCK_BASIS | HIF_INCREMENTAL_ADDRESS)
+
+#define HIF_WR_SYNC_BYTE_FIX					\
+	(HIF_WRITE | HIF_SYNCHRONOUS |				\
+	 HIF_BYTE_BASIS | HIF_FIXED_ADDRESS)
+
+#define HIF_WR_SYNC_BYTE_INC					\
+	(HIF_WRITE | HIF_SYNCHRONOUS |				\
+	 HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS)
+
+#define HIF_WR_SYNC_BLOCK_INC					\
+	(HIF_WRITE | HIF_SYNCHRONOUS |				\
+	 HIF_BLOCK_BASIS | HIF_INCREMENTAL_ADDRESS)
+
+#define HIF_RD_SYNC_BYTE_INC						\
+	(HIF_READ | HIF_SYNCHRONOUS |					\
+	 HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS)
+
+#define HIF_RD_SYNC_BYTE_FIX						\
+	(HIF_READ | HIF_SYNCHRONOUS |					\
+	 HIF_BYTE_BASIS | HIF_FIXED_ADDRESS)
+
+#define HIF_RD_ASYNC_BLOCK_FIX						\
+	(HIF_READ | HIF_ASYNCHRONOUS |					\
+	 HIF_BLOCK_BASIS | HIF_FIXED_ADDRESS)
+
+#define HIF_RD_SYNC_BLOCK_FIX						\
+	(HIF_READ | HIF_SYNCHRONOUS |					\
+	 HIF_BLOCK_BASIS | HIF_FIXED_ADDRESS)
+
+struct hif_scatter_item {
+	u8 *buf;
+	int len;
+	struct htc_packet *packet;
+};
+
+struct hif_scatter_req {
+	struct list_head list;
+	/* address for the read/write operation */
+	u32 addr;
+
+	/* request flags */
+	u32 req;
+
+	/* total length of entire transfer */
+	u32 len;
+
+	bool virt_scat;
+
+	void (*complete) (struct htc_target *, struct hif_scatter_req *);
+	int status;
+	int scat_entries;
+
+	struct bus_request *busrequest;
+	struct scatterlist *sgentries;
+
+	/* bounce buffer for upper layers to copy to/from */
+	u8 *virt_dma_buf;
+
+	struct hif_scatter_item scat_list[1];
+};
+
+struct ath6kl_hif_ops {
+	int (*read_write_sync)(struct ath6kl *ar, u32 addr, u8 *buf,
+			       u32 len, u32 request);
+	int (*write_async)(struct ath6kl *ar, u32 address, u8 *buffer,
+			   u32 length, u32 request, struct htc_packet *packet);
+
+	void (*irq_enable)(struct ath6kl *ar);
+	void (*irq_disable)(struct ath6kl *ar);
+
+	struct hif_scatter_req *(*scatter_req_get)(struct ath6kl *ar);
+	void (*scatter_req_add)(struct ath6kl *ar,
+				struct hif_scatter_req *s_req);
+	int (*enable_scatter)(struct ath6kl *ar);
+	int (*scat_req_rw) (struct ath6kl *ar,
+			    struct hif_scatter_req *scat_req);
+	void (*cleanup_scatter)(struct ath6kl *ar);
+};
+
+#endif
diff --git a/drivers/net/wireless/ath/ath6kl/htc.c b/drivers/net/wireless/ath/ath6kl/htc.c
new file mode 100644
index 000000000000..a8dc5c3ea567
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/htc.c
@@ -0,0 +1,2457 @@
+/*
+ * Copyright (c) 2007-2011 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.
+ */
+
+#include "core.h"
+#include "htc_hif.h"
+#include "debug.h"
+#include "hif-ops.h"
+#include <asm/unaligned.h>
+
+#define CALC_TXRX_PADDED_LEN(dev, len)  (__ALIGN_MASK((len), (dev)->block_mask))
+
+static void htc_prep_send_pkt(struct htc_packet *packet, u8 flags, int ctrl0,
+			      int ctrl1)
+{
+	struct htc_frame_hdr *hdr;
+
+	packet->buf -= HTC_HDR_LENGTH;
+	hdr =  (struct htc_frame_hdr *)packet->buf;
+
+	/* Endianess? */
+	put_unaligned((u16)packet->act_len, &hdr->payld_len);
+	hdr->flags = flags;
+	hdr->eid = packet->endpoint;
+	hdr->ctrl[0] = ctrl0;
+	hdr->ctrl[1] = ctrl1;
+}
+
+static void htc_reclaim_txctrl_buf(struct htc_target *target,
+				   struct htc_packet *pkt)
+{
+	spin_lock_bh(&target->htc_lock);
+	list_add_tail(&pkt->list, &target->free_ctrl_txbuf);
+	spin_unlock_bh(&target->htc_lock);
+}
+
+static struct htc_packet *htc_get_control_buf(struct htc_target *target,
+					      bool tx)
+{
+	struct htc_packet *packet = NULL;
+	struct list_head *buf_list;
+
+	buf_list = tx ? &target->free_ctrl_txbuf : &target->free_ctrl_rxbuf;
+
+	spin_lock_bh(&target->htc_lock);
+
+	if (list_empty(buf_list)) {
+		spin_unlock_bh(&target->htc_lock);
+		return NULL;
+	}
+
+	packet = list_first_entry(buf_list, struct htc_packet, list);
+	list_del(&packet->list);
+	spin_unlock_bh(&target->htc_lock);
+
+	if (tx)
+		packet->buf = packet->buf_start + HTC_HDR_LENGTH;
+
+	return packet;
+}
+
+static void htc_tx_comp_update(struct htc_target *target,
+			       struct htc_endpoint *endpoint,
+			       struct htc_packet *packet)
+{
+	packet->completion = NULL;
+	packet->buf += HTC_HDR_LENGTH;
+
+	if (!packet->status)
+		return;
+
+	ath6kl_err("req failed (status:%d, ep:%d, len:%d creds:%d)\n",
+		   packet->status, packet->endpoint, packet->act_len,
+		   packet->info.tx.cred_used);
+
+	/* on failure to submit, reclaim credits for this packet */
+	spin_lock_bh(&target->tx_lock);
+	endpoint->cred_dist.cred_to_dist +=
+				packet->info.tx.cred_used;
+	endpoint->cred_dist.txq_depth = get_queue_depth(&endpoint->txq);
+
+	ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "ctxt:0x%p dist:0x%p\n",
+		   target->cred_dist_cntxt, &target->cred_dist_list);
+
+	ath6k_credit_distribute(target->cred_dist_cntxt,
+				&target->cred_dist_list,
+				HTC_CREDIT_DIST_SEND_COMPLETE);
+
+	spin_unlock_bh(&target->tx_lock);
+}
+
+static void htc_tx_complete(struct htc_endpoint *endpoint,
+			    struct list_head *txq)
+{
+	if (list_empty(txq))
+		return;
+
+	ath6kl_dbg(ATH6KL_DBG_HTC_SEND,
+		   "send complete ep %d, (%d pkts)\n",
+		   endpoint->eid, get_queue_depth(txq));
+
+	ath6kl_tx_complete(endpoint->target->dev->ar, txq);
+}
+
+static void htc_tx_comp_handler(struct htc_target *target,
+				struct htc_packet *packet)
+{
+	struct htc_endpoint *endpoint = &target->endpoint[packet->endpoint];
+	struct list_head container;
+
+	htc_tx_comp_update(target, endpoint, packet);
+	INIT_LIST_HEAD(&container);
+	list_add_tail(&packet->list, &container);
+	/* do completion */
+	htc_tx_complete(endpoint, &container);
+}
+
+static void htc_async_tx_scat_complete(struct htc_target *target,
+				       struct hif_scatter_req *scat_req)
+{
+	struct htc_endpoint *endpoint;
+	struct htc_packet *packet;
+	struct list_head tx_compq;
+	int i;
+
+	INIT_LIST_HEAD(&tx_compq);
+
+	ath6kl_dbg(ATH6KL_DBG_HTC_SEND,
+		"htc_async_tx_scat_complete  total len: %d  entries: %d\n",
+		scat_req->len, scat_req->scat_entries);
+
+	if (scat_req->status)
+		ath6kl_err("send scatter req failed: %d\n", scat_req->status);
+
+	packet = scat_req->scat_list[0].packet;
+	endpoint = &target->endpoint[packet->endpoint];
+
+	/* walk through the scatter list and process */
+	for (i = 0; i < scat_req->scat_entries; i++) {
+		packet = scat_req->scat_list[i].packet;
+		if (!packet) {
+			WARN_ON(1);
+			return;
+		}
+
+		packet->status = scat_req->status;
+		htc_tx_comp_update(target, endpoint, packet);
+		list_add_tail(&packet->list, &tx_compq);
+	}
+
+	/* free scatter request */
+	hif_scatter_req_add(target->dev->ar, scat_req);
+
+	/* complete all packets */
+	htc_tx_complete(endpoint, &tx_compq);
+}
+
+static int htc_issue_send(struct htc_target *target, struct htc_packet *packet)
+{
+	int status;
+	bool sync = false;
+	u32 padded_len, send_len;
+
+	if (!packet->completion)
+		sync = true;
+
+	send_len = packet->act_len + HTC_HDR_LENGTH;
+
+	ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "%s: transmit len : %d (%s)\n",
+		   __func__, send_len, sync ? "sync" : "async");
+
+	padded_len = CALC_TXRX_PADDED_LEN(target, send_len);
+
+	ath6kl_dbg(ATH6KL_DBG_HTC_SEND,
+		"DevSendPacket, padded len: %d mbox:0x%X (mode:%s)\n",
+		padded_len,
+		target->dev->ar->mbox_info.htc_addr,
+		sync ? "sync" : "async");
+
+	if (sync) {
+		status = hif_read_write_sync(target->dev->ar,
+				target->dev->ar->mbox_info.htc_addr,
+				 packet->buf, padded_len,
+				 HIF_WR_SYNC_BLOCK_INC);
+
+		packet->status = status;
+		 packet->buf += HTC_HDR_LENGTH;
+	} else
+		status = hif_write_async(target->dev->ar,
+				target->dev->ar->mbox_info.htc_addr,
+				packet->buf, padded_len,
+				HIF_WR_ASYNC_BLOCK_INC, packet);
+
+	return status;
+}
+
+static int htc_check_credits(struct htc_target *target,
+			     struct htc_endpoint *ep, u8 *flags,
+			     enum htc_endpoint_id eid, unsigned int len,
+			     int *req_cred)
+{
+
+	*req_cred = (len > target->tgt_cred_sz) ?
+		     DIV_ROUND_UP(len, target->tgt_cred_sz) : 1;
+
+	ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "creds required:%d got:%d\n",
+		   *req_cred, ep->cred_dist.credits);
+
+	if (ep->cred_dist.credits < *req_cred) {
+		if (eid == ENDPOINT_0)
+			return -EINVAL;
+
+		/* Seek more credits */
+		ep->cred_dist.seek_cred = *req_cred - ep->cred_dist.credits;
+
+		ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "ctxt:0x%p dist:0x%p\n",
+			   target->cred_dist_cntxt, &ep->cred_dist);
+
+		ath6k_seek_credits(target->cred_dist_cntxt, &ep->cred_dist);
+
+		ep->cred_dist.seek_cred = 0;
+
+		if (ep->cred_dist.credits < *req_cred) {
+			ath6kl_dbg(ATH6KL_DBG_HTC_SEND,
+				   "not enough credits for ep %d - leaving packet in queue\n",
+				   eid);
+			return -EINVAL;
+		}
+	}
+
+	ep->cred_dist.credits -= *req_cred;
+	ep->ep_st.cred_cosumd += *req_cred;
+
+	 /* When we are getting low on credits, ask for more */
+	if (ep->cred_dist.credits < ep->cred_dist.cred_per_msg) {
+		ep->cred_dist.seek_cred =
+		ep->cred_dist.cred_per_msg - ep->cred_dist.credits;
+
+		ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "ctxt:0x%p dist:0x%p\n",
+			   target->cred_dist_cntxt, &ep->cred_dist);
+
+		ath6k_seek_credits(target->cred_dist_cntxt, &ep->cred_dist);
+
+		/* see if we were successful in getting more */
+		if (ep->cred_dist.credits < ep->cred_dist.cred_per_msg) {
+			/* tell the target we need credits ASAP! */
+			*flags |= HTC_FLAGS_NEED_CREDIT_UPDATE;
+			ep->ep_st.cred_low_indicate += 1;
+			ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "host needs credits\n");
+		}
+	}
+
+	return 0;
+}
+
+static void htc_tx_pkts_get(struct htc_target *target,
+			    struct htc_endpoint *endpoint,
+			    struct list_head *queue)
+{
+	int req_cred;
+	u8 flags;
+	struct htc_packet *packet;
+	unsigned int len;
+
+	while (true) {
+
+		flags = 0;
+
+		if (list_empty(&endpoint->txq))
+			break;
+		packet = list_first_entry(&endpoint->txq, struct htc_packet,
+					  list);
+
+		ath6kl_dbg(ATH6KL_DBG_HTC_SEND,
+			"got head pkt:0x%p , queue depth: %d\n",
+			packet, get_queue_depth(&endpoint->txq));
+
+		len = CALC_TXRX_PADDED_LEN(target,
+					   packet->act_len + HTC_HDR_LENGTH);
+
+		if (htc_check_credits(target, endpoint, &flags,
+				      packet->endpoint, len, &req_cred))
+			break;
+
+		/* now we can fully move onto caller's queue */
+		packet = list_first_entry(&endpoint->txq, struct htc_packet,
+					  list);
+		list_move_tail(&packet->list, queue);
+
+		/* save the number of credits this packet consumed */
+		packet->info.tx.cred_used = req_cred;
+
+		/* all TX packets are handled asynchronously */
+		packet->completion = htc_tx_comp_handler;
+		packet->context = target;
+		endpoint->ep_st.tx_issued += 1;
+
+		/* save send flags */
+		packet->info.tx.flags = flags;
+		packet->info.tx.seqno = endpoint->seqno;
+		endpoint->seqno++;
+	}
+}
+
+/* See if the padded tx length falls on a credit boundary */
+static int htc_get_credit_padding(unsigned int cred_sz, int *len,
+				  struct htc_endpoint *ep)
+{
+	int rem_cred, cred_pad;
+
+	rem_cred = *len % cred_sz;
+
+	/* No padding needed */
+	if  (!rem_cred)
+		return 0;
+
+	if (!(ep->conn_flags & HTC_FLGS_TX_BNDL_PAD_EN))
+		return -1;
+
+	/*
+	 * The transfer consumes a "partial" credit, this
+	 * packet cannot be bundled unless we add
+	 * additional "dummy" padding (max 255 bytes) to
+	 * consume the entire credit.
+	 */
+	cred_pad = *len < cred_sz ? (cred_sz - *len) : rem_cred;
+
+	if ((cred_pad > 0) && (cred_pad <= 255))
+		*len += cred_pad;
+	else
+		/* The amount of padding is too large, send as non-bundled */
+		return -1;
+
+	return cred_pad;
+}
+
+static int htc_setup_send_scat_list(struct htc_target *target,
+				    struct htc_endpoint *endpoint,
+				    struct hif_scatter_req *scat_req,
+				    int n_scat,
+				    struct list_head *queue)
+{
+	struct htc_packet *packet;
+	int i, len, rem_scat, cred_pad;
+	int status = 0;
+
+	rem_scat = target->max_tx_bndl_sz;
+
+	for (i = 0; i < n_scat; i++) {
+		scat_req->scat_list[i].packet = NULL;
+
+		if (list_empty(queue))
+			break;
+
+		packet = list_first_entry(queue, struct htc_packet, list);
+		len = CALC_TXRX_PADDED_LEN(target,
+					   packet->act_len + HTC_HDR_LENGTH);
+
+		cred_pad = htc_get_credit_padding(target->tgt_cred_sz,
+						  &len, endpoint);
+		if (cred_pad < 0) {
+			status = -EINVAL;
+			break;
+		}
+
+		if (rem_scat < len) {
+			/* exceeds what we can transfer */
+			status = -ENOSPC;
+			break;
+		}
+
+		rem_scat -= len;
+		/* now remove it from the queue */
+		packet = list_first_entry(queue, struct htc_packet, list);
+		list_del(&packet->list);
+
+		scat_req->scat_list[i].packet = packet;
+		/* prepare packet and flag message as part of a send bundle */
+		htc_prep_send_pkt(packet,
+				packet->info.tx.flags | HTC_FLAGS_SEND_BUNDLE,
+				cred_pad, packet->info.tx.seqno);
+		scat_req->scat_list[i].buf = packet->buf;
+		scat_req->scat_list[i].len = len;
+
+		scat_req->len += len;
+		scat_req->scat_entries++;
+		ath6kl_dbg(ATH6KL_DBG_HTC_SEND,
+			   "%d, adding pkt : 0x%p len:%d (remaining space:%d)\n",
+			   i, packet, len, rem_scat);
+	}
+
+	/* Roll back scatter setup in case of any failure */
+	if (status || (scat_req->scat_entries < HTC_MIN_HTC_MSGS_TO_BUNDLE)) {
+		for (i = scat_req->scat_entries - 1; i >= 0; i--) {
+			packet = scat_req->scat_list[i].packet;
+			if (packet) {
+				packet->buf += HTC_HDR_LENGTH;
+				list_add(&packet->list, queue);
+			}
+		}
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * htc_issue_send_bundle: drain a queue and send as bundles
+ * this function may return without fully draining the queue
+ * when
+ *
+ *    1. scatter resources are exhausted
+ *    2. a message that will consume a partial credit will stop the
+ *    bundling process early
+ *    3. we drop below the minimum number of messages for a bundle
+ */
+static void htc_issue_send_bundle(struct htc_endpoint *endpoint,
+				  struct list_head *queue,
+				  int *sent_bundle, int *n_bundle_pkts)
+{
+	struct htc_target *target = endpoint->target;
+	struct hif_scatter_req *scat_req = NULL;
+	int n_scat, n_sent_bundle = 0, tot_pkts_bundle = 0;
+
+	while (true) {
+		n_scat = get_queue_depth(queue);
+		n_scat = min(n_scat, target->msg_per_bndl_max);
+
+		if (n_scat < HTC_MIN_HTC_MSGS_TO_BUNDLE)
+			/* not enough to bundle */
+			break;
+
+		scat_req = hif_scatter_req_get(target->dev->ar);
+
+		if (!scat_req) {
+			/* no scatter resources  */
+			ath6kl_dbg(ATH6KL_DBG_HTC_SEND,
+				"no more scatter resources\n");
+			break;
+		}
+
+		ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "pkts to scatter: %d\n",
+			   n_scat);
+
+		scat_req->len = 0;
+		scat_req->scat_entries = 0;
+
+		if (htc_setup_send_scat_list(target, endpoint, scat_req,
+					     n_scat, queue)) {
+			hif_scatter_req_add(target->dev->ar, scat_req);
+			break;
+		}
+
+		/* send path is always asynchronous */
+		scat_req->complete = htc_async_tx_scat_complete;
+		n_sent_bundle++;
+		tot_pkts_bundle += scat_req->scat_entries;
+
+		ath6kl_dbg(ATH6KL_DBG_HTC_SEND,
+			   "send scatter total bytes: %d , entries: %d\n",
+			   scat_req->len, scat_req->scat_entries);
+		ath6kldev_submit_scat_req(target->dev, scat_req, false);
+	}
+
+	*sent_bundle = n_sent_bundle;
+	*n_bundle_pkts = tot_pkts_bundle;
+	ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "htc_issue_send_bundle (sent:%d)\n",
+		   n_sent_bundle);
+
+	return;
+}
+
+static void htc_tx_from_ep_txq(struct htc_target *target,
+			       struct htc_endpoint *endpoint)
+{
+	struct list_head txq;
+	struct htc_packet *packet;
+	int bundle_sent;
+	int n_pkts_bundle;
+
+	spin_lock_bh(&target->tx_lock);
+
+	endpoint->tx_proc_cnt++;
+	if (endpoint->tx_proc_cnt > 1) {
+		endpoint->tx_proc_cnt--;
+		spin_unlock_bh(&target->tx_lock);
+		ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "htc_try_send (busy)\n");
+		return;
+	}
+
+	/*
+	 * drain the endpoint TX queue for transmission as long
+	 * as we have enough credits.
+	 */
+	INIT_LIST_HEAD(&txq);
+
+	while (true) {
+
+		if (list_empty(&endpoint->txq))
+			break;
+
+		htc_tx_pkts_get(target, endpoint, &txq);
+
+		if (list_empty(&txq))
+			break;
+
+		spin_unlock_bh(&target->tx_lock);
+
+		bundle_sent = 0;
+		n_pkts_bundle = 0;
+
+		while (true) {
+			/* try to send a bundle on each pass */
+			if ((target->tx_bndl_enable) &&
+			    (get_queue_depth(&txq) >=
+			    HTC_MIN_HTC_MSGS_TO_BUNDLE)) {
+				int temp1 = 0, temp2 = 0;
+
+				htc_issue_send_bundle(endpoint, &txq,
+						      &temp1, &temp2);
+				bundle_sent += temp1;
+				n_pkts_bundle += temp2;
+			}
+
+			if (list_empty(&txq))
+				break;
+
+			packet = list_first_entry(&txq, struct htc_packet,
+						  list);
+			list_del(&packet->list);
+
+			htc_prep_send_pkt(packet, packet->info.tx.flags,
+					  0, packet->info.tx.seqno);
+			htc_issue_send(target, packet);
+		}
+
+		spin_lock_bh(&target->tx_lock);
+
+		endpoint->ep_st.tx_bundles += bundle_sent;
+		endpoint->ep_st.tx_pkt_bundled += n_pkts_bundle;
+	}
+
+	endpoint->tx_proc_cnt = 0;
+	spin_unlock_bh(&target->tx_lock);
+}
+
+static bool htc_try_send(struct htc_target *target,
+			 struct htc_endpoint *endpoint,
+			 struct htc_packet *tx_pkt)
+{
+	struct htc_ep_callbacks ep_cb;
+	int txq_depth;
+	bool overflow = false;
+
+	ep_cb = endpoint->ep_cb;
+
+	spin_lock_bh(&target->tx_lock);
+	txq_depth = get_queue_depth(&endpoint->txq);
+	spin_unlock_bh(&target->tx_lock);
+
+	if (txq_depth >= endpoint->max_txq_depth)
+		overflow = true;
+
+	if (overflow)
+		ath6kl_dbg(ATH6KL_DBG_HTC_SEND,
+			   "ep %d, tx queue will overflow :%d , tx depth:%d, max:%d\n",
+			   endpoint->eid, overflow, txq_depth,
+			   endpoint->max_txq_depth);
+
+	if (overflow && ep_cb.tx_full) {
+		ath6kl_dbg(ATH6KL_DBG_HTC_SEND,
+			   "indicating overflowed tx packet: 0x%p\n", tx_pkt);
+
+		if (ep_cb.tx_full(endpoint->target, tx_pkt) ==
+		    HTC_SEND_FULL_DROP) {
+			endpoint->ep_st.tx_dropped += 1;
+			return false;
+		}
+	}
+
+	spin_lock_bh(&target->tx_lock);
+	list_add_tail(&tx_pkt->list, &endpoint->txq);
+	spin_unlock_bh(&target->tx_lock);
+
+	htc_tx_from_ep_txq(target, endpoint);
+
+	return true;
+}
+
+static void htc_chk_ep_txq(struct htc_target *target)
+{
+	struct htc_endpoint *endpoint;
+	struct htc_endpoint_credit_dist *cred_dist;
+
+	/*
+	 * Run through the credit distribution list to see if there are
+	 * packets queued. NOTE: no locks need to be taken since the
+	 * distribution list is not dynamic (cannot be re-ordered) and we
+	 * are not modifying any state.
+	 */
+	list_for_each_entry(cred_dist, &target->cred_dist_list, list) {
+		endpoint = (struct htc_endpoint *)cred_dist->htc_rsvd;
+
+		spin_lock_bh(&target->tx_lock);
+		if (!list_empty(&endpoint->txq)) {
+			ath6kl_dbg(ATH6KL_DBG_HTC_SEND,
+				   "ep %d has %d credits and %d packets in tx queue\n",
+				   cred_dist->endpoint,
+				   endpoint->cred_dist.credits,
+				   get_queue_depth(&endpoint->txq));
+			spin_unlock_bh(&target->tx_lock);
+			/*
+			 * Try to start the stalled queue, this list is
+			 * ordered by priority. If there are credits
+			 * available the highest priority queue will get a
+			 * chance to reclaim credits from lower priority
+			 * ones.
+			 */
+			htc_tx_from_ep_txq(target, endpoint);
+			spin_lock_bh(&target->tx_lock);
+		}
+		spin_unlock_bh(&target->tx_lock);
+	}
+}
+
+static int htc_setup_tx_complete(struct htc_target *target)
+{
+	struct htc_packet *send_pkt = NULL;
+	int status;
+
+	send_pkt = htc_get_control_buf(target, true);
+
+	if (!send_pkt)
+		return -ENOMEM;
+
+	if (target->htc_tgt_ver >= HTC_VERSION_2P1) {
+		struct htc_setup_comp_ext_msg *setup_comp_ext;
+		u32 flags = 0;
+
+		setup_comp_ext =
+		    (struct htc_setup_comp_ext_msg *)send_pkt->buf;
+		memset(setup_comp_ext, 0, sizeof(*setup_comp_ext));
+		setup_comp_ext->msg_id =
+			cpu_to_le16(HTC_MSG_SETUP_COMPLETE_EX_ID);
+
+		if (target->msg_per_bndl_max > 0) {
+			/* Indicate HTC bundling to the target */
+			flags |= HTC_SETUP_COMP_FLG_RX_BNDL_EN;
+			setup_comp_ext->msg_per_rxbndl =
+						target->msg_per_bndl_max;
+		}
+
+		memcpy(&setup_comp_ext->flags, &flags,
+		       sizeof(setup_comp_ext->flags));
+		set_htc_pkt_info(send_pkt, NULL, (u8 *) setup_comp_ext,
+				       sizeof(struct htc_setup_comp_ext_msg),
+				       ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG);
+
+	} else {
+		struct htc_setup_comp_msg *setup_comp;
+		setup_comp = (struct htc_setup_comp_msg *)send_pkt->buf;
+		memset(setup_comp, 0, sizeof(struct htc_setup_comp_msg));
+		setup_comp->msg_id = cpu_to_le16(HTC_MSG_SETUP_COMPLETE_ID);
+		set_htc_pkt_info(send_pkt, NULL, (u8 *) setup_comp,
+				       sizeof(struct htc_setup_comp_msg),
+				       ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG);
+	}
+
+	/* we want synchronous operation */
+	send_pkt->completion = NULL;
+	htc_prep_send_pkt(send_pkt, 0, 0, 0);
+	status = htc_issue_send(target, send_pkt);
+
+	if (send_pkt != NULL)
+		htc_reclaim_txctrl_buf(target, send_pkt);
+
+	return status;
+}
+
+void ath6kl_htc_set_credit_dist(struct htc_target *target,
+				struct htc_credit_state_info *cred_dist_cntxt,
+				u16 srvc_pri_order[], int list_len)
+{
+	struct htc_endpoint *endpoint;
+	int i, ep;
+
+	target->cred_dist_cntxt = cred_dist_cntxt;
+
+	list_add_tail(&target->endpoint[ENDPOINT_0].cred_dist.list,
+		      &target->cred_dist_list);
+
+	for (i = 0; i < list_len; i++) {
+		for (ep = ENDPOINT_1; ep < ENDPOINT_MAX; ep++) {
+			endpoint = &target->endpoint[ep];
+			if (endpoint->svc_id == srvc_pri_order[i]) {
+				list_add_tail(&endpoint->cred_dist.list,
+					      &target->cred_dist_list);
+				break;
+			}
+		}
+		if (ep >= ENDPOINT_MAX) {
+			WARN_ON(1);
+			return;
+		}
+	}
+}
+
+int ath6kl_htc_tx(struct htc_target *target, struct htc_packet *packet)
+{
+	struct htc_endpoint *endpoint;
+	struct list_head queue;
+
+	ath6kl_dbg(ATH6KL_DBG_HTC_SEND,
+		   "htc_tx: ep id: %d, buf: 0x%p, len: %d\n",
+		   packet->endpoint, packet->buf, packet->act_len);
+
+	if (packet->endpoint >= ENDPOINT_MAX) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	endpoint = &target->endpoint[packet->endpoint];
+
+	if (!htc_try_send(target, endpoint, packet)) {
+		packet->status = (target->htc_flags & HTC_OP_STATE_STOPPING) ?
+				 -ECANCELED : -ENOSPC;
+		INIT_LIST_HEAD(&queue);
+		list_add(&packet->list, &queue);
+		htc_tx_complete(endpoint, &queue);
+	}
+
+	return 0;
+}
+
+/* flush endpoint TX queue */
+void ath6kl_htc_flush_txep(struct htc_target *target,
+			   enum htc_endpoint_id eid, u16 tag)
+{
+	struct htc_packet *packet, *tmp_pkt;
+	struct list_head discard_q, container;
+	struct htc_endpoint *endpoint = &target->endpoint[eid];
+
+	if (!endpoint->svc_id) {
+		WARN_ON(1);
+		return;
+	}
+
+	/* initialize the discard queue */
+	INIT_LIST_HEAD(&discard_q);
+
+	spin_lock_bh(&target->tx_lock);
+
+	list_for_each_entry_safe(packet, tmp_pkt, &endpoint->txq, list) {
+		if ((tag == HTC_TX_PACKET_TAG_ALL) ||
+		    (tag == packet->info.tx.tag))
+			list_move_tail(&packet->list, &discard_q);
+	}
+
+	spin_unlock_bh(&target->tx_lock);
+
+	list_for_each_entry_safe(packet, tmp_pkt, &discard_q, list) {
+		packet->status = -ECANCELED;
+		list_del(&packet->list);
+		ath6kl_dbg(ATH6KL_DBG_TRC,
+			"flushing tx pkt:0x%p, len:%d, ep:%d tag:0x%X\n",
+			packet, packet->act_len,
+			packet->endpoint, packet->info.tx.tag);
+
+		INIT_LIST_HEAD(&container);
+		list_add_tail(&packet->list, &container);
+		htc_tx_complete(endpoint, &container);
+	}
+
+}
+
+static void ath6kl_htc_flush_txep_all(struct htc_target *target)
+{
+	struct htc_endpoint *endpoint;
+	int i;
+
+	dump_cred_dist_stats(target);
+
+	for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) {
+		endpoint = &target->endpoint[i];
+		if (endpoint->svc_id == 0)
+			/* not in use.. */
+			continue;
+		ath6kl_htc_flush_txep(target, i, HTC_TX_PACKET_TAG_ALL);
+	}
+}
+
+void ath6kl_htc_indicate_activity_change(struct htc_target *target,
+					 enum htc_endpoint_id eid, bool active)
+{
+	struct htc_endpoint *endpoint = &target->endpoint[eid];
+	bool dist = false;
+
+	if (endpoint->svc_id == 0) {
+		WARN_ON(1);
+		return;
+	}
+
+	spin_lock_bh(&target->tx_lock);
+
+	if (active) {
+		if (!(endpoint->cred_dist.dist_flags & HTC_EP_ACTIVE)) {
+			endpoint->cred_dist.dist_flags |= HTC_EP_ACTIVE;
+			dist = true;
+		}
+	} else {
+		if (endpoint->cred_dist.dist_flags & HTC_EP_ACTIVE) {
+			endpoint->cred_dist.dist_flags &= ~HTC_EP_ACTIVE;
+			dist = true;
+		}
+	}
+
+	if (dist) {
+		endpoint->cred_dist.txq_depth =
+			get_queue_depth(&endpoint->txq);
+
+		ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "ctxt:0x%p dist:0x%p\n",
+			   target->cred_dist_cntxt, &target->cred_dist_list);
+
+		ath6k_credit_distribute(target->cred_dist_cntxt,
+					&target->cred_dist_list,
+					HTC_CREDIT_DIST_ACTIVITY_CHANGE);
+	}
+
+	spin_unlock_bh(&target->tx_lock);
+
+	if (dist && !active)
+		htc_chk_ep_txq(target);
+}
+
+/* HTC Rx */
+
+static inline void htc_update_rx_stats(struct htc_endpoint *endpoint,
+				       int n_look_ahds)
+{
+	endpoint->ep_st.rx_pkts++;
+	if (n_look_ahds == 1)
+		endpoint->ep_st.rx_lkahds++;
+	else if (n_look_ahds > 1)
+		endpoint->ep_st.rx_bundle_lkahd++;
+}
+
+static inline bool htc_valid_rx_frame_len(struct htc_target *target,
+					  enum htc_endpoint_id eid, int len)
+{
+	return (eid == target->dev->ar->ctrl_ep) ?
+		len <= ATH6KL_BUFFER_SIZE : len <= ATH6KL_AMSDU_BUFFER_SIZE;
+}
+
+static int htc_add_rxbuf(struct htc_target *target, struct htc_packet *packet)
+{
+	struct list_head queue;
+
+	INIT_LIST_HEAD(&queue);
+	list_add_tail(&packet->list, &queue);
+	return ath6kl_htc_add_rxbuf_multiple(target, &queue);
+}
+
+static void htc_reclaim_rxbuf(struct htc_target *target,
+			      struct htc_packet *packet,
+			      struct htc_endpoint *ep)
+{
+	if (packet->info.rx.rx_flags & HTC_RX_PKT_NO_RECYCLE) {
+		htc_rxpkt_reset(packet);
+		packet->status = -ECANCELED;
+		ep->ep_cb.rx(ep->target, packet);
+	} else {
+		htc_rxpkt_reset(packet);
+		htc_add_rxbuf((void *)(target), packet);
+	}
+}
+
+static void reclaim_rx_ctrl_buf(struct htc_target *target,
+				struct htc_packet *packet)
+{
+	spin_lock_bh(&target->htc_lock);
+	list_add_tail(&packet->list, &target->free_ctrl_rxbuf);
+	spin_unlock_bh(&target->htc_lock);
+}
+
+static int dev_rx_pkt(struct htc_target *target, struct htc_packet *packet,
+		      u32 rx_len)
+{
+	struct ath6kl_device *dev = target->dev;
+	u32 padded_len;
+	int status;
+
+	padded_len = CALC_TXRX_PADDED_LEN(target, rx_len);
+
+	if (padded_len > packet->buf_len) {
+		ath6kl_err("not enough receive space for packet - padlen:%d recvlen:%d bufferlen:%d\n",
+			   padded_len, rx_len, packet->buf_len);
+		return -ENOMEM;
+	}
+
+	ath6kl_dbg(ATH6KL_DBG_HTC_RECV,
+		   "dev_rx_pkt (0x%p : hdr:0x%X) padded len: %d mbox:0x%X (mode:%s)\n",
+		   packet, packet->info.rx.exp_hdr,
+		   padded_len, dev->ar->mbox_info.htc_addr, "sync");
+
+	status = hif_read_write_sync(dev->ar,
+				     dev->ar->mbox_info.htc_addr,
+				     packet->buf, padded_len,
+				     HIF_RD_SYNC_BLOCK_FIX);
+
+	packet->status = status;
+
+	return status;
+}
+
+/*
+ * optimization for recv packets, we can indicate a
+ * "hint" that there are more  single-packets to fetch
+ * on this endpoint.
+ */
+static void set_rxpkt_indication_flag(u32 lk_ahd,
+				      struct htc_endpoint *endpoint,
+				      struct htc_packet *packet)
+{
+	struct htc_frame_hdr *htc_hdr = (struct htc_frame_hdr *)&lk_ahd;
+
+	if (htc_hdr->eid == packet->endpoint) {
+		if (!list_empty(&endpoint->rx_bufq))
+			packet->info.rx.indicat_flags |=
+					HTC_RX_FLAGS_INDICATE_MORE_PKTS;
+	}
+}
+
+static void chk_rx_water_mark(struct htc_endpoint *endpoint)
+{
+	struct htc_ep_callbacks ep_cb = endpoint->ep_cb;
+
+	if (ep_cb.rx_refill_thresh > 0) {
+		spin_lock_bh(&endpoint->target->rx_lock);
+		if (get_queue_depth(&endpoint->rx_bufq)
+		    < ep_cb.rx_refill_thresh) {
+			spin_unlock_bh(&endpoint->target->rx_lock);
+			ep_cb.rx_refill(endpoint->target, endpoint->eid);
+			return;
+		}
+		spin_unlock_bh(&endpoint->target->rx_lock);
+	}
+}
+
+/* This function is called with rx_lock held */
+static int htc_setup_rxpkts(struct htc_target *target, struct htc_endpoint *ep,
+			    u32 *lk_ahds, struct list_head *queue, int n_msg)
+{
+	struct htc_packet *packet;
+	/* FIXME: type of lk_ahds can't be right */
+	struct htc_frame_hdr *htc_hdr = (struct htc_frame_hdr *)lk_ahds;
+	struct htc_ep_callbacks ep_cb;
+	int status = 0, j, full_len;
+	bool no_recycle;
+
+	full_len = CALC_TXRX_PADDED_LEN(target,
+					le16_to_cpu(htc_hdr->payld_len) +
+					sizeof(*htc_hdr));
+
+	if (!htc_valid_rx_frame_len(target, ep->eid, full_len)) {
+		ath6kl_warn("Rx buffer requested with invalid length\n");
+		return -EINVAL;
+	}
+
+	ep_cb = ep->ep_cb;
+	for (j = 0; j < n_msg; j++) {
+
+		/*
+		 * Reset flag, any packets allocated using the
+		 * rx_alloc() API cannot be recycled on
+		 * cleanup,they must be explicitly returned.
+		 */
+		no_recycle = false;
+
+		if (ep_cb.rx_allocthresh &&
+		    (full_len > ep_cb.rx_alloc_thresh)) {
+			ep->ep_st.rx_alloc_thresh_hit += 1;
+			ep->ep_st.rxalloc_thresh_byte +=
+				le16_to_cpu(htc_hdr->payld_len);
+
+			spin_unlock_bh(&target->rx_lock);
+			no_recycle = true;
+
+			packet = ep_cb.rx_allocthresh(ep->target, ep->eid,
+						      full_len);
+			spin_lock_bh(&target->rx_lock);
+		} else {
+			/* refill handler is being used */
+			if (list_empty(&ep->rx_bufq)) {
+				if (ep_cb.rx_refill) {
+					spin_unlock_bh(&target->rx_lock);
+					ep_cb.rx_refill(ep->target, ep->eid);
+					spin_lock_bh(&target->rx_lock);
+				}
+			}
+
+			if (list_empty(&ep->rx_bufq))
+				packet = NULL;
+			else {
+				packet = list_first_entry(&ep->rx_bufq,
+						struct htc_packet, list);
+				list_del(&packet->list);
+			}
+		}
+
+		if (!packet) {
+			target->rx_st_flags |= HTC_RECV_WAIT_BUFFERS;
+			target->ep_waiting = ep->eid;
+			return -ENOSPC;
+		}
+
+		/* clear flags */
+		packet->info.rx.rx_flags = 0;
+		packet->info.rx.indicat_flags = 0;
+		packet->status = 0;
+
+		if (no_recycle)
+			/*
+			 * flag that these packets cannot be
+			 * recycled, they have to be returned to
+			 * the user
+			 */
+			packet->info.rx.rx_flags |= HTC_RX_PKT_NO_RECYCLE;
+
+		/* Caller needs to free this upon any failure */
+		list_add_tail(&packet->list, queue);
+
+		if (target->htc_flags & HTC_OP_STATE_STOPPING) {
+			status = -ECANCELED;
+			break;
+		}
+
+		if (j) {
+			packet->info.rx.rx_flags |= HTC_RX_PKT_REFRESH_HDR;
+			packet->info.rx.exp_hdr = 0xFFFFFFFF;
+		} else
+			/* set expected look ahead */
+			packet->info.rx.exp_hdr = *lk_ahds;
+
+		packet->act_len = le16_to_cpu(htc_hdr->payld_len) +
+			HTC_HDR_LENGTH;
+	}
+
+	return status;
+}
+
+static int alloc_and_prep_rxpkts(struct htc_target *target,
+				 u32 lk_ahds[], int msg,
+				 struct htc_endpoint *endpoint,
+				 struct list_head *queue)
+{
+	int status = 0;
+	struct htc_packet *packet, *tmp_pkt;
+	struct htc_frame_hdr *htc_hdr;
+	int i, n_msg;
+
+	spin_lock_bh(&target->rx_lock);
+
+	for (i = 0; i < msg; i++) {
+
+		htc_hdr = (struct htc_frame_hdr *)&lk_ahds[i];
+
+		if (htc_hdr->eid >= ENDPOINT_MAX) {
+			ath6kl_err("invalid ep in look-ahead: %d\n",
+				   htc_hdr->eid);
+			status = -ENOMEM;
+			break;
+		}
+
+		if (htc_hdr->eid != endpoint->eid) {
+			ath6kl_err("invalid ep in look-ahead: %d should be : %d (index:%d)\n",
+				   htc_hdr->eid, endpoint->eid, i);
+			status = -ENOMEM;
+			break;
+		}
+
+		if (le16_to_cpu(htc_hdr->payld_len) > HTC_MAX_PAYLOAD_LENGTH) {
+			ath6kl_err("payload len %d exceeds max htc : %d !\n",
+				   htc_hdr->payld_len,
+				   (u32) HTC_MAX_PAYLOAD_LENGTH);
+			status = -ENOMEM;
+			break;
+		}
+
+		if (endpoint->svc_id == 0) {
+			ath6kl_err("ep %d is not connected !\n", htc_hdr->eid);
+			status = -ENOMEM;
+			break;
+		}
+
+		if (htc_hdr->flags & HTC_FLG_RX_BNDL_CNT) {
+			/*
+			 * HTC header indicates that every packet to follow
+			 * has the same padded length so that it can be
+			 * optimally fetched as a full bundle.
+			 */
+			n_msg = (htc_hdr->flags & HTC_FLG_RX_BNDL_CNT) >>
+				HTC_FLG_RX_BNDL_CNT_S;
+
+			/* the count doesn't include the starter frame */
+			n_msg++;
+			if (n_msg > target->msg_per_bndl_max) {
+				status = -ENOMEM;
+				break;
+			}
+
+			endpoint->ep_st.rx_bundle_from_hdr += 1;
+			ath6kl_dbg(ATH6KL_DBG_HTC_RECV,
+				   "htc hdr indicates :%d msg can be fetched as a bundle\n",
+				   n_msg);
+		} else
+			/* HTC header only indicates 1 message to fetch */
+			n_msg = 1;
+
+		/* Setup packet buffers for each message */
+		status = htc_setup_rxpkts(target, endpoint, &lk_ahds[i], queue,
+					  n_msg);
+
+		/*
+		 * This is due to unavailabilty of buffers to rx entire data.
+		 * Return no error so that free buffers from queue can be used
+		 * to receive partial data.
+		 */
+		if (status == -ENOSPC) {
+			spin_unlock_bh(&target->rx_lock);
+			return 0;
+		}
+
+		if (status)
+			break;
+	}
+
+	spin_unlock_bh(&target->rx_lock);
+
+	if (status) {
+		list_for_each_entry_safe(packet, tmp_pkt, queue, list) {
+			list_del(&packet->list);
+			htc_reclaim_rxbuf(target, packet,
+					  &target->endpoint[packet->endpoint]);
+		}
+	}
+
+	return status;
+}
+
+static void htc_ctrl_rx(struct htc_target *context, struct htc_packet *packets)
+{
+	if (packets->endpoint != ENDPOINT_0) {
+		WARN_ON(1);
+		return;
+	}
+
+	if (packets->status == -ECANCELED) {
+		reclaim_rx_ctrl_buf(context, packets);
+		return;
+	}
+
+	if (packets->act_len > 0) {
+		ath6kl_err("htc_ctrl_rx, got message with len:%zu\n",
+			packets->act_len + HTC_HDR_LENGTH);
+
+		ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES,
+			     "Unexpected ENDPOINT 0 Message",
+			     packets->buf - HTC_HDR_LENGTH,
+			     packets->act_len + HTC_HDR_LENGTH);
+	}
+
+	htc_reclaim_rxbuf(context, packets, &context->endpoint[0]);
+}
+
+static void htc_proc_cred_rpt(struct htc_target *target,
+			      struct htc_credit_report *rpt,
+			      int n_entries,
+			      enum htc_endpoint_id from_ep)
+{
+	struct htc_endpoint *endpoint;
+	int tot_credits = 0, i;
+	bool dist = false;
+
+	ath6kl_dbg(ATH6KL_DBG_HTC_SEND,
+		   "htc_proc_cred_rpt, credit report entries:%d\n", n_entries);
+
+	spin_lock_bh(&target->tx_lock);
+
+	for (i = 0; i < n_entries; i++, rpt++) {
+		if (rpt->eid >= ENDPOINT_MAX) {
+			WARN_ON(1);
+			spin_unlock_bh(&target->tx_lock);
+			return;
+		}
+
+		endpoint = &target->endpoint[rpt->eid];
+
+		ath6kl_dbg(ATH6KL_DBG_HTC_SEND, " ep %d got %d credits\n",
+			rpt->eid, rpt->credits);
+
+		endpoint->ep_st.tx_cred_rpt += 1;
+		endpoint->ep_st.cred_retnd += rpt->credits;
+
+		if (from_ep == rpt->eid) {
+			/*
+			 * This credit report arrived on the same endpoint
+			 * indicating it arrived in an RX packet.
+			 */
+			endpoint->ep_st.cred_from_rx += rpt->credits;
+			endpoint->ep_st.cred_rpt_from_rx += 1;
+		} else if (from_ep == ENDPOINT_0) {
+			/* credit arrived on endpoint 0 as a NULL message */
+			endpoint->ep_st.cred_from_ep0 += rpt->credits;
+			endpoint->ep_st.cred_rpt_ep0 += 1;
+		} else {
+			endpoint->ep_st.cred_from_other += rpt->credits;
+			endpoint->ep_st.cred_rpt_from_other += 1;
+		}
+
+		if (rpt->eid == ENDPOINT_0)
+			/* always give endpoint 0 credits back */
+			endpoint->cred_dist.credits += rpt->credits;
+		else {
+			endpoint->cred_dist.cred_to_dist += rpt->credits;
+			dist = true;
+		}
+
+		/*
+		 * Refresh tx depth for distribution function that will
+		 * recover these credits NOTE: this is only valid when
+		 * there are credits to recover!
+		 */
+		endpoint->cred_dist.txq_depth =
+			get_queue_depth(&endpoint->txq);
+
+		tot_credits += rpt->credits;
+	}
+
+	ath6kl_dbg(ATH6KL_DBG_HTC_SEND,
+		   "report indicated %d credits to distribute\n",
+		   tot_credits);
+
+	if (dist) {
+		/*
+		 * This was a credit return based on a completed send
+		 * operations note, this is done with the lock held
+		 */
+		ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "ctxt:0x%p dist:0x%p\n",
+			   target->cred_dist_cntxt, &target->cred_dist_list);
+
+		ath6k_credit_distribute(target->cred_dist_cntxt,
+					&target->cred_dist_list,
+					HTC_CREDIT_DIST_SEND_COMPLETE);
+	}
+
+	spin_unlock_bh(&target->tx_lock);
+
+	if (tot_credits)
+		htc_chk_ep_txq(target);
+}
+
+static int htc_parse_trailer(struct htc_target *target,
+			     struct htc_record_hdr *record,
+			     u8 *record_buf, u32 *next_lk_ahds,
+			     enum htc_endpoint_id endpoint,
+			     int *n_lk_ahds)
+{
+	struct htc_bundle_lkahd_rpt *bundle_lkahd_rpt;
+	struct htc_lookahead_report *lk_ahd;
+	int len;
+
+	switch (record->rec_id) {
+	case HTC_RECORD_CREDITS:
+		len = record->len / sizeof(struct htc_credit_report);
+		if (!len) {
+			WARN_ON(1);
+			return -EINVAL;
+		}
+
+		htc_proc_cred_rpt(target,
+				  (struct htc_credit_report *) record_buf,
+				  len, endpoint);
+		break;
+	case HTC_RECORD_LOOKAHEAD:
+		len = record->len / sizeof(*lk_ahd);
+		if (!len) {
+			WARN_ON(1);
+			return -EINVAL;
+		}
+
+		lk_ahd = (struct htc_lookahead_report *) record_buf;
+		if ((lk_ahd->pre_valid == ((~lk_ahd->post_valid) & 0xFF))
+		    && next_lk_ahds) {
+
+			ath6kl_dbg(ATH6KL_DBG_HTC_RECV,
+				   "lk_ahd report found (pre valid:0x%X, post valid:0x%X)\n",
+				   lk_ahd->pre_valid, lk_ahd->post_valid);
+
+			/* look ahead bytes are valid, copy them over */
+			memcpy((u8 *)&next_lk_ahds[0], lk_ahd->lk_ahd, 4);
+
+			ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Next Look Ahead",
+					next_lk_ahds, 4);
+
+			*n_lk_ahds = 1;
+		}
+		break;
+	case HTC_RECORD_LOOKAHEAD_BUNDLE:
+		len = record->len / sizeof(*bundle_lkahd_rpt);
+		if (!len || (len > HTC_HOST_MAX_MSG_PER_BUNDLE)) {
+			WARN_ON(1);
+			return -EINVAL;
+		}
+
+		if (next_lk_ahds) {
+			int i;
+
+			bundle_lkahd_rpt =
+				(struct htc_bundle_lkahd_rpt *) record_buf;
+
+			ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Bundle lk_ahd",
+					record_buf, record->len);
+
+			for (i = 0; i < len; i++) {
+				memcpy((u8 *)&next_lk_ahds[i],
+				       bundle_lkahd_rpt->lk_ahd, 4);
+				bundle_lkahd_rpt++;
+			}
+
+			*n_lk_ahds = i;
+		}
+		break;
+	default:
+		ath6kl_err("unhandled record: id:%d len:%d\n",
+			   record->rec_id, record->len);
+		break;
+	}
+
+	return 0;
+
+}
+
+static int htc_proc_trailer(struct htc_target *target,
+			    u8 *buf, int len, u32 *next_lk_ahds,
+			    int *n_lk_ahds, enum htc_endpoint_id endpoint)
+{
+	struct htc_record_hdr *record;
+	int orig_len;
+	int status;
+	u8 *record_buf;
+	u8 *orig_buf;
+
+	ath6kl_dbg(ATH6KL_DBG_HTC_RECV, "+htc_proc_trailer (len:%d)\n", len);
+
+	ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Recv Trailer", buf, len);
+
+	orig_buf = buf;
+	orig_len = len;
+	status = 0;
+
+	while (len > 0) {
+
+		if (len < sizeof(struct htc_record_hdr)) {
+			status = -ENOMEM;
+			break;
+		}
+		/* these are byte aligned structs */
+		record = (struct htc_record_hdr *) buf;
+		len -= sizeof(struct htc_record_hdr);
+		buf += sizeof(struct htc_record_hdr);
+
+		if (record->len > len) {
+			ath6kl_err("invalid record len: %d (id:%d) buf has: %d bytes left\n",
+				   record->len, record->rec_id, len);
+			status = -ENOMEM;
+			break;
+		}
+		record_buf = buf;
+
+		status = htc_parse_trailer(target, record, record_buf,
+					   next_lk_ahds, endpoint, n_lk_ahds);
+
+		if (status)
+			break;
+
+		/* advance buffer past this record for next time around */
+		buf += record->len;
+		len -= record->len;
+	}
+
+	if (status)
+		ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "BAD Recv Trailer",
+				orig_buf, orig_len);
+
+	return status;
+}
+
+static int htc_proc_rxhdr(struct htc_target *target,
+			  struct htc_packet *packet,
+			  u32 *next_lkahds, int *n_lkahds)
+{
+	int status = 0;
+	u16 payload_len;
+	u32 lk_ahd;
+	struct htc_frame_hdr *htc_hdr = (struct htc_frame_hdr *)packet->buf;
+
+	if (n_lkahds != NULL)
+		*n_lkahds = 0;
+
+	ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "HTC Recv PKT", packet->buf,
+			packet->act_len);
+
+	/*
+	 * NOTE: we cannot assume the alignment of buf, so we use the safe
+	 * macros to retrieve 16 bit fields.
+	 */
+	payload_len = le16_to_cpu(get_unaligned(&htc_hdr->payld_len));
+
+	memcpy((u8 *)&lk_ahd, packet->buf, sizeof(lk_ahd));
+
+	if (packet->info.rx.rx_flags & HTC_RX_PKT_REFRESH_HDR) {
+		/*
+		 * Refresh the expected header and the actual length as it
+		 * was unknown when this packet was grabbed as part of the
+		 * bundle.
+		 */
+		packet->info.rx.exp_hdr = lk_ahd;
+		packet->act_len = payload_len + HTC_HDR_LENGTH;
+
+		/* validate the actual header that was refreshed  */
+		if (packet->act_len > packet->buf_len) {
+			ath6kl_err("refreshed hdr payload len (%d) in bundled recv is invalid (hdr: 0x%X)\n",
+				   payload_len, lk_ahd);
+			/*
+			 * Limit this to max buffer just to print out some
+			 * of the buffer.
+			 */
+			packet->act_len = min(packet->act_len, packet->buf_len);
+			status = -ENOMEM;
+			goto fail_rx;
+		}
+
+		if (packet->endpoint != htc_hdr->eid) {
+			ath6kl_err("refreshed hdr ep (%d) does not match expected ep (%d)\n",
+				   htc_hdr->eid, packet->endpoint);
+			status = -ENOMEM;
+			goto fail_rx;
+		}
+	}
+
+	if (lk_ahd != packet->info.rx.exp_hdr) {
+		ath6kl_err("htc_proc_rxhdr, lk_ahd mismatch! (pPkt:0x%p flags:0x%X)\n",
+			   packet, packet->info.rx.rx_flags);
+		ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Expected Message lk_ahd",
+				&packet->info.rx.exp_hdr, 4);
+		ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Current Frame Header",
+				(u8 *)&lk_ahd, sizeof(lk_ahd));
+		status = -ENOMEM;
+		goto fail_rx;
+	}
+
+	if (htc_hdr->flags & HTC_FLG_RX_TRAILER) {
+		if (htc_hdr->ctrl[0] < sizeof(struct htc_record_hdr) ||
+		    htc_hdr->ctrl[0] > payload_len) {
+			ath6kl_err("htc_proc_rxhdr, invalid hdr (payload len should be :%d, CB[0] is:%d)\n",
+				   payload_len, htc_hdr->ctrl[0]);
+			status = -ENOMEM;
+			goto fail_rx;
+		}
+
+		if (packet->info.rx.rx_flags & HTC_RX_PKT_IGNORE_LOOKAHEAD) {
+			next_lkahds = NULL;
+			n_lkahds = NULL;
+		}
+
+		status = htc_proc_trailer(target, packet->buf + HTC_HDR_LENGTH
+					  + payload_len - htc_hdr->ctrl[0],
+					  htc_hdr->ctrl[0], next_lkahds,
+					   n_lkahds, packet->endpoint);
+
+		if (status)
+			goto fail_rx;
+
+		packet->act_len -= htc_hdr->ctrl[0];
+	}
+
+	packet->buf += HTC_HDR_LENGTH;
+	packet->act_len -= HTC_HDR_LENGTH;
+
+fail_rx:
+	if (status)
+		ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "BAD HTC Recv PKT",
+				packet->buf,
+				packet->act_len < 256 ? packet->act_len : 256);
+	else {
+		if (packet->act_len > 0)
+			ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES,
+					"HTC - Application Msg",
+					packet->buf, packet->act_len);
+	}
+
+	return status;
+}
+
+static void do_rx_completion(struct htc_endpoint *endpoint,
+			     struct htc_packet *packet)
+{
+		ath6kl_dbg(ATH6KL_DBG_HTC_RECV,
+			   "htc calling ep %d recv callback on packet 0x%p\n",
+			   endpoint->eid, packet);
+		endpoint->ep_cb.rx(endpoint->target, packet);
+}
+
+static int htc_issue_rxpkt_bundle(struct htc_target *target,
+				  struct list_head *rxq,
+				  struct list_head *sync_compq,
+				  int *n_pkt_fetched, bool part_bundle)
+{
+	struct hif_scatter_req *scat_req;
+	struct htc_packet *packet;
+	int rem_space = target->max_rx_bndl_sz;
+	int n_scat_pkt, status = 0, i, len;
+
+	n_scat_pkt = get_queue_depth(rxq);
+	n_scat_pkt = min(n_scat_pkt, target->msg_per_bndl_max);
+
+	if ((get_queue_depth(rxq) - n_scat_pkt) > 0) {
+		/*
+		 * We were forced to split this bundle receive operation
+		 * all packets in this partial bundle must have their
+		 * lookaheads ignored.
+		 */
+		part_bundle = true;
+
+		/*
+		 * This would only happen if the target ignored our max
+		 * bundle limit.
+		 */
+		ath6kl_warn("htc_issue_rxpkt_bundle : partial bundle detected num:%d , %d\n",
+			    get_queue_depth(rxq), n_scat_pkt);
+	}
+
+	len = 0;
+
+	ath6kl_dbg(ATH6KL_DBG_HTC_RECV,
+		"htc_issue_rxpkt_bundle (numpackets: %d , actual : %d)\n",
+		get_queue_depth(rxq), n_scat_pkt);
+
+	scat_req = hif_scatter_req_get(target->dev->ar);
+
+	if (scat_req == NULL)
+		goto fail_rx_pkt;
+
+	for (i = 0; i < n_scat_pkt; i++) {
+		int pad_len;
+
+		packet = list_first_entry(rxq, struct htc_packet, list);
+		list_del(&packet->list);
+
+		pad_len = CALC_TXRX_PADDED_LEN(target,
+						   packet->act_len);
+
+		if ((rem_space - pad_len) < 0) {
+			list_add(&packet->list, rxq);
+			break;
+		}
+
+		rem_space -= pad_len;
+
+		if (part_bundle || (i < (n_scat_pkt - 1)))
+			/*
+			 * Packet 0..n-1 cannot be checked for look-aheads
+			 * since we are fetching a bundle the last packet
+			 * however can have it's lookahead used
+			 */
+			packet->info.rx.rx_flags |=
+			    HTC_RX_PKT_IGNORE_LOOKAHEAD;
+
+		/* NOTE: 1 HTC packet per scatter entry */
+		scat_req->scat_list[i].buf = packet->buf;
+		scat_req->scat_list[i].len = pad_len;
+
+		packet->info.rx.rx_flags |= HTC_RX_PKT_PART_OF_BUNDLE;
+
+		list_add_tail(&packet->list, sync_compq);
+
+		WARN_ON(!scat_req->scat_list[i].len);
+		len += scat_req->scat_list[i].len;
+	}
+
+	scat_req->len = len;
+	scat_req->scat_entries = i;
+
+	status = ath6kldev_submit_scat_req(target->dev, scat_req, true);
+
+	if (!status)
+		*n_pkt_fetched = i;
+
+	/* free scatter request */
+	hif_scatter_req_add(target->dev->ar, scat_req);
+
+fail_rx_pkt:
+
+	return status;
+}
+
+static int htc_proc_fetched_rxpkts(struct htc_target *target,
+				   struct list_head *comp_pktq, u32 lk_ahds[],
+				   int *n_lk_ahd)
+{
+	struct htc_packet *packet, *tmp_pkt;
+	struct htc_endpoint *ep;
+	int status = 0;
+
+	list_for_each_entry_safe(packet, tmp_pkt, comp_pktq, list) {
+		list_del(&packet->list);
+		ep = &target->endpoint[packet->endpoint];
+
+		/* process header for each of the recv packet */
+		status = htc_proc_rxhdr(target, packet, lk_ahds, n_lk_ahd);
+		if (status)
+			return status;
+
+		if (list_empty(comp_pktq)) {
+			/*
+			 * Last packet's more packet flag is set
+			 * based on the lookahead.
+			 */
+			if (*n_lk_ahd > 0)
+				set_rxpkt_indication_flag(lk_ahds[0],
+							  ep, packet);
+		} else
+			/*
+			 * Packets in a bundle automatically have
+			 * this flag set.
+			 */
+			packet->info.rx.indicat_flags |=
+				HTC_RX_FLAGS_INDICATE_MORE_PKTS;
+
+		htc_update_rx_stats(ep, *n_lk_ahd);
+
+		if (packet->info.rx.rx_flags & HTC_RX_PKT_PART_OF_BUNDLE)
+			ep->ep_st.rx_bundl += 1;
+
+		do_rx_completion(ep, packet);
+	}
+
+	return status;
+}
+
+static int htc_fetch_rxpkts(struct htc_target *target,
+			    struct list_head *rx_pktq,
+			    struct list_head *comp_pktq)
+{
+	int fetched_pkts;
+	bool part_bundle = false;
+	int status = 0;
+
+	/* now go fetch the list of HTC packets */
+	while (!list_empty(rx_pktq)) {
+		fetched_pkts = 0;
+
+		if (target->rx_bndl_enable && (get_queue_depth(rx_pktq) > 1)) {
+			/*
+			 * There are enough packets to attempt a
+			 * bundle transfer and recv bundling is
+			 * allowed.
+			 */
+			status = htc_issue_rxpkt_bundle(target, rx_pktq,
+							comp_pktq,
+							&fetched_pkts,
+							part_bundle);
+			if (status)
+				return status;
+
+			if (!list_empty(rx_pktq))
+				part_bundle = true;
+		}
+
+		if (!fetched_pkts) {
+			struct htc_packet *packet;
+
+			packet = list_first_entry(rx_pktq, struct htc_packet,
+						   list);
+
+			list_del(&packet->list);
+
+			/* fully synchronous */
+			packet->completion = NULL;
+
+			if (!list_empty(rx_pktq))
+				/*
+				 * look_aheads in all packet
+				 * except the last one in the
+				 * bundle must be ignored
+				 */
+				packet->info.rx.rx_flags |=
+					HTC_RX_PKT_IGNORE_LOOKAHEAD;
+
+			/* go fetch the packet */
+			status = dev_rx_pkt(target, packet, packet->act_len);
+			if (status)
+				return status;
+
+			list_add_tail(&packet->list, comp_pktq);
+		}
+	}
+
+	return status;
+}
+
+int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target,
+				     u32 msg_look_ahead[], int *num_pkts)
+{
+	struct htc_packet *packets, *tmp_pkt;
+	struct htc_endpoint *endpoint;
+	struct list_head rx_pktq, comp_pktq;
+	int status = 0;
+	u32 look_aheads[HTC_HOST_MAX_MSG_PER_BUNDLE];
+	int num_look_ahead = 1;
+	enum htc_endpoint_id id;
+	int n_fetched = 0;
+
+	*num_pkts = 0;
+
+	/*
+	 * On first entry copy the look_aheads into our temp array for
+	 * processing
+	 */
+	memcpy(look_aheads, msg_look_ahead, sizeof(look_aheads));
+
+	while (true) {
+
+		/*
+		 * First lookahead sets the expected endpoint IDs for all
+		 * packets in a bundle.
+		 */
+		id = ((struct htc_frame_hdr *)&look_aheads[0])->eid;
+		endpoint = &target->endpoint[id];
+
+		if (id >= ENDPOINT_MAX) {
+			ath6kl_err("MsgPend, invalid endpoint in look-ahead: %d\n",
+				   id);
+			status = -ENOMEM;
+			break;
+		}
+
+		INIT_LIST_HEAD(&rx_pktq);
+		INIT_LIST_HEAD(&comp_pktq);
+
+		/*
+		 * Try to allocate as many HTC RX packets indicated by the
+		 * look_aheads.
+		 */
+		status = alloc_and_prep_rxpkts(target, look_aheads,
+					       num_look_ahead, endpoint,
+					       &rx_pktq);
+		if (status)
+			break;
+
+		if (get_queue_depth(&rx_pktq) >= 2)
+			/*
+			 * A recv bundle was detected, force IRQ status
+			 * re-check again
+			 */
+			target->chk_irq_status_cnt = 1;
+
+		n_fetched += get_queue_depth(&rx_pktq);
+
+		num_look_ahead = 0;
+
+		status = htc_fetch_rxpkts(target, &rx_pktq, &comp_pktq);
+
+		if (!status)
+			chk_rx_water_mark(endpoint);
+
+		/* Process fetched packets */
+		status = htc_proc_fetched_rxpkts(target, &comp_pktq,
+						 look_aheads, &num_look_ahead);
+
+		if (!num_look_ahead || status)
+			break;
+
+		/*
+		 * For SYNCH processing, if we get here, we are running
+		 * through the loop again due to a detected lookahead. Set
+		 * flag that we should re-check IRQ status registers again
+		 * before leaving IRQ processing, this can net better
+		 * performance in high throughput situations.
+		 */
+		target->chk_irq_status_cnt = 1;
+	}
+
+	if (status) {
+		ath6kl_err("failed to get pending recv messages: %d\n",
+			   status);
+		/*
+		 * Cleanup any packets we allocated but didn't use to
+		 * actually fetch any packets.
+		 */
+		list_for_each_entry_safe(packets, tmp_pkt, &rx_pktq, list) {
+			list_del(&packets->list);
+			htc_reclaim_rxbuf(target, packets,
+					&target->endpoint[packets->endpoint]);
+		}
+
+		/* cleanup any packets in sync completion queue */
+		list_for_each_entry_safe(packets, tmp_pkt, &comp_pktq, list) {
+			list_del(&packets->list);
+			htc_reclaim_rxbuf(target, packets,
+					  &target->endpoint[packets->endpoint]);
+		}
+
+		if (target->htc_flags & HTC_OP_STATE_STOPPING) {
+			ath6kl_warn("host is going to stop blocking receiver for htc_stop\n");
+			ath6kldev_rx_control(target->dev, false);
+		}
+	}
+
+	/*
+	 * Before leaving, check to see if host ran out of buffers and
+	 * needs to stop the receiver.
+	 */
+	if (target->rx_st_flags & HTC_RECV_WAIT_BUFFERS) {
+		ath6kl_warn("host has no rx buffers blocking receiver to prevent overrun\n");
+		ath6kldev_rx_control(target->dev, false);
+	}
+	*num_pkts = n_fetched;
+
+	return status;
+}
+
+/*
+ * Synchronously wait for a control message from the target,
+ * This function is used at initialization time ONLY.  At init messages
+ * on ENDPOINT 0 are expected.
+ */
+static struct htc_packet *htc_wait_for_ctrl_msg(struct htc_target *target)
+{
+	struct htc_packet *packet = NULL;
+	struct htc_frame_hdr *htc_hdr;
+	u32 look_ahead;
+
+	if (ath6kldev_poll_mboxmsg_rx(target->dev, &look_ahead,
+			       HTC_TARGET_RESPONSE_TIMEOUT))
+		return NULL;
+
+	ath6kl_dbg(ATH6KL_DBG_HTC_RECV,
+		"htc_wait_for_ctrl_msg: look_ahead : 0x%X\n", look_ahead);
+
+	htc_hdr = (struct htc_frame_hdr *)&look_ahead;
+
+	if (htc_hdr->eid != ENDPOINT_0)
+		return NULL;
+
+	packet = htc_get_control_buf(target, false);
+
+	if (!packet)
+		return NULL;
+
+	packet->info.rx.rx_flags = 0;
+	packet->info.rx.exp_hdr = look_ahead;
+	packet->act_len = le16_to_cpu(htc_hdr->payld_len) + HTC_HDR_LENGTH;
+
+	if (packet->act_len > packet->buf_len)
+		goto fail_ctrl_rx;
+
+	/* we want synchronous operation */
+	packet->completion = NULL;
+
+	/* get the message from the device, this will block */
+	if (dev_rx_pkt(target, packet, packet->act_len))
+		goto fail_ctrl_rx;
+
+	/* process receive header */
+	packet->status = htc_proc_rxhdr(target, packet, NULL, NULL);
+
+	if (packet->status) {
+		ath6kl_err("htc_wait_for_ctrl_msg, htc_proc_rxhdr failed (status = %d)\n",
+			   packet->status);
+		goto fail_ctrl_rx;
+	}
+
+	return packet;
+
+fail_ctrl_rx:
+	if (packet != NULL) {
+		htc_rxpkt_reset(packet);
+		reclaim_rx_ctrl_buf(target, packet);
+	}
+
+	return NULL;
+}
+
+int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target,
+				  struct list_head *pkt_queue)
+{
+	struct htc_endpoint *endpoint;
+	struct htc_packet *first_pkt;
+	bool rx_unblock = false;
+	int status = 0, depth;
+
+	if (list_empty(pkt_queue))
+		return -ENOMEM;
+
+	first_pkt = list_first_entry(pkt_queue, struct htc_packet, list);
+
+	if (first_pkt->endpoint >= ENDPOINT_MAX)
+		return status;
+
+	depth = get_queue_depth(pkt_queue);
+
+	ath6kl_dbg(ATH6KL_DBG_HTC_RECV,
+		"htc_add_rxbuf_multiple: ep id: %d, cnt:%d, len: %d\n",
+		first_pkt->endpoint, depth, first_pkt->buf_len);
+
+	endpoint = &target->endpoint[first_pkt->endpoint];
+
+	if (target->htc_flags & HTC_OP_STATE_STOPPING) {
+		struct htc_packet *packet, *tmp_pkt;
+
+		/* walk through queue and mark each one canceled */
+		list_for_each_entry_safe(packet, tmp_pkt, pkt_queue, list) {
+			packet->status = -ECANCELED;
+			list_del(&packet->list);
+			do_rx_completion(endpoint, packet);
+		}
+
+		return status;
+	}
+
+	spin_lock_bh(&target->rx_lock);
+
+	list_splice_tail_init(pkt_queue, &endpoint->rx_bufq);
+
+	/* check if we are blocked waiting for a new buffer */
+	if (target->rx_st_flags & HTC_RECV_WAIT_BUFFERS) {
+		if (target->ep_waiting == first_pkt->endpoint) {
+			ath6kl_dbg(ATH6KL_DBG_HTC_RECV,
+				"receiver was blocked on ep:%d, unblocking.\n",
+				target->ep_waiting);
+			target->rx_st_flags &= ~HTC_RECV_WAIT_BUFFERS;
+			target->ep_waiting = ENDPOINT_MAX;
+			rx_unblock = true;
+		}
+	}
+
+	spin_unlock_bh(&target->rx_lock);
+
+	if (rx_unblock && !(target->htc_flags & HTC_OP_STATE_STOPPING))
+		/* TODO : implement a buffer threshold count? */
+		ath6kldev_rx_control(target->dev, true);
+
+	return status;
+}
+
+void ath6kl_htc_flush_rx_buf(struct htc_target *target)
+{
+	struct htc_endpoint *endpoint;
+	struct htc_packet *packet, *tmp_pkt;
+	int i;
+
+	for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) {
+		endpoint = &target->endpoint[i];
+		if (!endpoint->svc_id)
+			/* not in use.. */
+			continue;
+
+		spin_lock_bh(&target->rx_lock);
+		list_for_each_entry_safe(packet, tmp_pkt,
+					 &endpoint->rx_bufq, list) {
+			list_del(&packet->list);
+			spin_unlock_bh(&target->rx_lock);
+			ath6kl_dbg(ATH6KL_DBG_HTC_RECV,
+				   "flushing rx pkt:0x%p, len:%d, ep:%d\n",
+				   packet, packet->buf_len,
+				   packet->endpoint);
+			dev_kfree_skb(packet->pkt_cntxt);
+			spin_lock_bh(&target->rx_lock);
+		}
+		spin_unlock_bh(&target->rx_lock);
+	}
+}
+
+int ath6kl_htc_conn_service(struct htc_target *target,
+			    struct htc_service_connect_req *conn_req,
+			    struct htc_service_connect_resp *conn_resp)
+{
+	struct htc_packet *rx_pkt = NULL;
+	struct htc_packet *tx_pkt = NULL;
+	struct htc_conn_service_resp *resp_msg;
+	struct htc_conn_service_msg *conn_msg;
+	struct htc_endpoint *endpoint;
+	enum htc_endpoint_id assigned_ep = ENDPOINT_MAX;
+	unsigned int max_msg_sz = 0;
+	int status = 0;
+
+	ath6kl_dbg(ATH6KL_DBG_TRC,
+		   "htc_conn_service, target:0x%p service id:0x%X\n",
+		   target, conn_req->svc_id);
+
+	if (conn_req->svc_id == HTC_CTRL_RSVD_SVC) {
+		/* special case for pseudo control service */
+		assigned_ep = ENDPOINT_0;
+		max_msg_sz = HTC_MAX_CTRL_MSG_LEN;
+	} else {
+		/* allocate a packet to send to the target */
+		tx_pkt = htc_get_control_buf(target, true);
+
+		if (!tx_pkt)
+			return -ENOMEM;
+
+		conn_msg = (struct htc_conn_service_msg *)tx_pkt->buf;
+		memset(conn_msg, 0, sizeof(*conn_msg));
+		conn_msg->msg_id = cpu_to_le16(HTC_MSG_CONN_SVC_ID);
+		conn_msg->svc_id = cpu_to_le16(conn_req->svc_id);
+		conn_msg->conn_flags = cpu_to_le16(conn_req->conn_flags);
+
+		set_htc_pkt_info(tx_pkt, NULL, (u8 *) conn_msg,
+				 sizeof(*conn_msg) + conn_msg->svc_meta_len,
+				 ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG);
+
+		/* we want synchronous operation */
+		tx_pkt->completion = NULL;
+		htc_prep_send_pkt(tx_pkt, 0, 0, 0);
+		status = htc_issue_send(target, tx_pkt);
+
+		if (status)
+			goto fail_tx;
+
+		/* wait for response */
+		rx_pkt = htc_wait_for_ctrl_msg(target);
+
+		if (!rx_pkt) {
+			status = -ENOMEM;
+			goto fail_tx;
+		}
+
+		resp_msg = (struct htc_conn_service_resp *)rx_pkt->buf;
+
+		if ((le16_to_cpu(resp_msg->msg_id) != HTC_MSG_CONN_SVC_RESP_ID)
+		    || (rx_pkt->act_len < sizeof(*resp_msg))) {
+			status = -ENOMEM;
+			goto fail_tx;
+		}
+
+		conn_resp->resp_code = resp_msg->status;
+		/* check response status */
+		if (resp_msg->status != HTC_SERVICE_SUCCESS) {
+			ath6kl_err("target failed service 0x%X connect request (status:%d)\n",
+				   resp_msg->svc_id, resp_msg->status);
+			status = -ENOMEM;
+			goto fail_tx;
+		}
+
+		assigned_ep = (enum htc_endpoint_id)resp_msg->eid;
+		max_msg_sz = le16_to_cpu(resp_msg->max_msg_sz);
+	}
+
+	if (assigned_ep >= ENDPOINT_MAX || !max_msg_sz) {
+		status = -ENOMEM;
+		goto fail_tx;
+	}
+
+	endpoint = &target->endpoint[assigned_ep];
+	endpoint->eid = assigned_ep;
+	if (endpoint->svc_id) {
+		status = -ENOMEM;
+		goto fail_tx;
+	}
+
+	/* return assigned endpoint to caller */
+	conn_resp->endpoint = assigned_ep;
+	conn_resp->len_max = max_msg_sz;
+
+	/* setup the endpoint */
+
+	/* this marks the endpoint in use */
+	endpoint->svc_id = conn_req->svc_id;
+
+	endpoint->max_txq_depth = conn_req->max_txq_depth;
+	endpoint->len_max = max_msg_sz;
+	endpoint->ep_cb = conn_req->ep_cb;
+	endpoint->cred_dist.svc_id = conn_req->svc_id;
+	endpoint->cred_dist.htc_rsvd = endpoint;
+	endpoint->cred_dist.endpoint = assigned_ep;
+	endpoint->cred_dist.cred_sz = target->tgt_cred_sz;
+
+	if (conn_req->max_rxmsg_sz) {
+		/*
+		 * Override cred_per_msg calculation, this optimizes
+		 * the credit-low indications since the host will actually
+		 * issue smaller messages in the Send path.
+		 */
+		if (conn_req->max_rxmsg_sz > max_msg_sz) {
+			status = -ENOMEM;
+			goto fail_tx;
+		}
+		endpoint->cred_dist.cred_per_msg =
+		    conn_req->max_rxmsg_sz / target->tgt_cred_sz;
+	} else
+		endpoint->cred_dist.cred_per_msg =
+		    max_msg_sz / target->tgt_cred_sz;
+
+	if (!endpoint->cred_dist.cred_per_msg)
+		endpoint->cred_dist.cred_per_msg = 1;
+
+	/* save local connection flags */
+	endpoint->conn_flags = conn_req->flags;
+
+fail_tx:
+	if (tx_pkt)
+		htc_reclaim_txctrl_buf(target, tx_pkt);
+
+	if (rx_pkt) {
+		htc_rxpkt_reset(rx_pkt);
+		reclaim_rx_ctrl_buf(target, rx_pkt);
+	}
+
+	return status;
+}
+
+static void reset_ep_state(struct htc_target *target)
+{
+	struct htc_endpoint *endpoint;
+	int i;
+
+	for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) {
+		endpoint = &target->endpoint[i];
+		memset(&endpoint->cred_dist, 0, sizeof(endpoint->cred_dist));
+		endpoint->svc_id = 0;
+		endpoint->len_max = 0;
+		endpoint->max_txq_depth = 0;
+		memset(&endpoint->ep_st, 0,
+		       sizeof(endpoint->ep_st));
+		INIT_LIST_HEAD(&endpoint->rx_bufq);
+		INIT_LIST_HEAD(&endpoint->txq);
+		endpoint->target = target;
+	}
+
+	/* reset distribution list */
+	INIT_LIST_HEAD(&target->cred_dist_list);
+}
+
+int ath6kl_htc_get_rxbuf_num(struct htc_target *target,
+			     enum htc_endpoint_id endpoint)
+{
+	int num;
+
+	spin_lock_bh(&target->rx_lock);
+	num = get_queue_depth(&(target->endpoint[endpoint].rx_bufq));
+	spin_unlock_bh(&target->rx_lock);
+	return num;
+}
+
+static void htc_setup_msg_bndl(struct htc_target *target)
+{
+	/* limit what HTC can handle */
+	target->msg_per_bndl_max = min(HTC_HOST_MAX_MSG_PER_BUNDLE,
+				       target->msg_per_bndl_max);
+
+	if (ath6kl_hif_enable_scatter(target->dev->ar)) {
+		target->msg_per_bndl_max = 0;
+		return;
+	}
+
+	/* limit bundle what the device layer can handle */
+	target->msg_per_bndl_max = min(target->max_scat_entries,
+				       target->msg_per_bndl_max);
+
+	ath6kl_dbg(ATH6KL_DBG_TRC,
+		   "htc bundling allowed. max msg per htc bundle: %d\n",
+		   target->msg_per_bndl_max);
+
+	/* Max rx bundle size is limited by the max tx bundle size */
+	target->max_rx_bndl_sz = target->max_xfer_szper_scatreq;
+	/* Max tx bundle size if limited by the extended mbox address range */
+	target->max_tx_bndl_sz = min(HIF_MBOX0_EXT_WIDTH,
+				     target->max_xfer_szper_scatreq);
+
+	ath6kl_dbg(ATH6KL_DBG_ANY, "max recv: %d max send: %d\n",
+		   target->max_rx_bndl_sz, target->max_tx_bndl_sz);
+
+	if (target->max_tx_bndl_sz)
+		target->tx_bndl_enable = true;
+
+	if (target->max_rx_bndl_sz)
+		target->rx_bndl_enable = true;
+
+	if ((target->tgt_cred_sz % target->block_sz) != 0) {
+		ath6kl_warn("credit size: %d is not block aligned! Disabling send bundling\n",
+			    target->tgt_cred_sz);
+
+		/*
+		 * Disallow send bundling since the credit size is
+		 * not aligned to a block size the I/O block
+		 * padding will spill into the next credit buffer
+		 * which is fatal.
+		 */
+		target->tx_bndl_enable = false;
+	}
+}
+
+int ath6kl_htc_wait_target(struct htc_target *target)
+{
+	struct htc_packet *packet = NULL;
+	struct htc_ready_ext_msg *rdy_msg;
+	struct htc_service_connect_req connect;
+	struct htc_service_connect_resp resp;
+	int status;
+
+	/* we should be getting 1 control message that the target is ready */
+	packet = htc_wait_for_ctrl_msg(target);
+
+	if (!packet)
+		return -ENOMEM;
+
+	/* we controlled the buffer creation so it's properly aligned */
+	rdy_msg = (struct htc_ready_ext_msg *)packet->buf;
+
+	if ((le16_to_cpu(rdy_msg->ver2_0_info.msg_id) != HTC_MSG_READY_ID) ||
+	    (packet->act_len < sizeof(struct htc_ready_msg))) {
+		status = -ENOMEM;
+		goto fail_wait_target;
+	}
+
+	if (!rdy_msg->ver2_0_info.cred_cnt || !rdy_msg->ver2_0_info.cred_sz) {
+		status = -ENOMEM;
+		goto fail_wait_target;
+	}
+
+	target->tgt_creds = le16_to_cpu(rdy_msg->ver2_0_info.cred_cnt);
+	target->tgt_cred_sz = le16_to_cpu(rdy_msg->ver2_0_info.cred_sz);
+
+	ath6kl_dbg(ATH6KL_DBG_HTC_RECV,
+		   "target ready: credits: %d credit size: %d\n",
+		   target->tgt_creds, target->tgt_cred_sz);
+
+	/* check if this is an extended ready message */
+	if (packet->act_len >= sizeof(struct htc_ready_ext_msg)) {
+		/* this is an extended message */
+		target->htc_tgt_ver = rdy_msg->htc_ver;
+		target->msg_per_bndl_max = rdy_msg->msg_per_htc_bndl;
+	} else {
+		/* legacy */
+		target->htc_tgt_ver = HTC_VERSION_2P0;
+		target->msg_per_bndl_max = 0;
+	}
+
+	ath6kl_dbg(ATH6KL_DBG_TRC, "using htc protocol version : %s (%d)\n",
+		  (target->htc_tgt_ver == HTC_VERSION_2P0) ? "2.0" : ">= 2.1",
+		  target->htc_tgt_ver);
+
+	if (target->msg_per_bndl_max > 0)
+		htc_setup_msg_bndl(target);
+
+	/* setup our pseudo HTC control endpoint connection */
+	memset(&connect, 0, sizeof(connect));
+	memset(&resp, 0, sizeof(resp));
+	connect.ep_cb.rx = htc_ctrl_rx;
+	connect.ep_cb.rx_refill = NULL;
+	connect.ep_cb.tx_full = NULL;
+	connect.max_txq_depth = NUM_CONTROL_BUFFERS;
+	connect.svc_id = HTC_CTRL_RSVD_SVC;
+
+	/* connect fake service */
+	status = ath6kl_htc_conn_service((void *)target, &connect, &resp);
+
+	if (status)
+		ath6kl_hif_cleanup_scatter(target->dev->ar);
+
+fail_wait_target:
+	if (packet) {
+		htc_rxpkt_reset(packet);
+		reclaim_rx_ctrl_buf(target, packet);
+	}
+
+	return status;
+}
+
+/*
+ * Start HTC, enable interrupts and let the target know
+ * host has finished setup.
+ */
+int ath6kl_htc_start(struct htc_target *target)
+{
+	struct htc_packet *packet;
+	int status;
+
+	/* Disable interrupts at the chip level */
+	ath6kldev_disable_intrs(target->dev);
+
+	target->htc_flags = 0;
+	target->rx_st_flags = 0;
+
+	/* Push control receive buffers into htc control endpoint */
+	while ((packet = htc_get_control_buf(target, false)) != NULL) {
+		status = htc_add_rxbuf(target, packet);
+		if (status)
+			return status;
+	}
+
+	/* NOTE: the first entry in the distribution list is ENDPOINT_0 */
+	ath6k_credit_init(target->cred_dist_cntxt, &target->cred_dist_list,
+			  target->tgt_creds);
+
+	dump_cred_dist_stats(target);
+
+	/* Indicate to the target of the setup completion */
+	status = htc_setup_tx_complete(target);
+
+	if (status)
+		return status;
+
+	/* unmask interrupts */
+	status = ath6kldev_unmask_intrs(target->dev);
+
+	if (status)
+		ath6kl_htc_stop(target);
+
+	return status;
+}
+
+/* htc_stop: stop interrupt reception, and flush all queued buffers */
+void ath6kl_htc_stop(struct htc_target *target)
+{
+	spin_lock_bh(&target->htc_lock);
+	target->htc_flags |= HTC_OP_STATE_STOPPING;
+	spin_unlock_bh(&target->htc_lock);
+
+	/*
+	 * Masking interrupts is a synchronous operation, when this
+	 * function returns all pending HIF I/O has completed, we can
+	 * safely flush the queues.
+	 */
+	ath6kldev_mask_intrs(target->dev);
+
+	ath6kl_htc_flush_txep_all(target);
+
+	ath6kl_htc_flush_rx_buf(target);
+
+	reset_ep_state(target);
+}
+
+void *ath6kl_htc_create(struct ath6kl *ar)
+{
+	struct htc_target *target = NULL;
+	struct htc_packet *packet;
+	int status = 0, i = 0;
+	u32 block_size, ctrl_bufsz;
+
+	target = kzalloc(sizeof(*target), GFP_KERNEL);
+	if (!target) {
+		ath6kl_err("unable to allocate memory\n");
+		return NULL;
+	}
+
+	target->dev = kzalloc(sizeof(*target->dev), GFP_KERNEL);
+	if (!target->dev) {
+		ath6kl_err("unable to allocate memory\n");
+		status = -ENOMEM;
+		goto fail_create_htc;
+	}
+
+	spin_lock_init(&target->htc_lock);
+	spin_lock_init(&target->rx_lock);
+	spin_lock_init(&target->tx_lock);
+
+	INIT_LIST_HEAD(&target->free_ctrl_txbuf);
+	INIT_LIST_HEAD(&target->free_ctrl_rxbuf);
+	INIT_LIST_HEAD(&target->cred_dist_list);
+
+	target->dev->ar = ar;
+	target->dev->htc_cnxt = target;
+	target->ep_waiting = ENDPOINT_MAX;
+
+	reset_ep_state(target);
+
+	status = ath6kldev_setup(target->dev);
+
+	if (status)
+		goto fail_create_htc;
+
+	block_size = ar->mbox_info.block_size;
+
+	ctrl_bufsz = (block_size > HTC_MAX_CTRL_MSG_LEN) ?
+		      (block_size + HTC_HDR_LENGTH) :
+		      (HTC_MAX_CTRL_MSG_LEN + HTC_HDR_LENGTH);
+
+	for (i = 0; i < NUM_CONTROL_BUFFERS; i++) {
+		packet = kzalloc(sizeof(*packet), GFP_KERNEL);
+		if (!packet)
+			break;
+
+		packet->buf_start = kzalloc(ctrl_bufsz, GFP_KERNEL);
+		if (!packet->buf_start) {
+			kfree(packet);
+			break;
+		}
+
+		packet->buf_len = ctrl_bufsz;
+		if (i < NUM_CONTROL_RX_BUFFERS) {
+			packet->act_len = 0;
+			packet->buf = packet->buf_start;
+			packet->endpoint = ENDPOINT_0;
+			list_add_tail(&packet->list, &target->free_ctrl_rxbuf);
+		} else
+			list_add_tail(&packet->list, &target->free_ctrl_txbuf);
+	}
+
+fail_create_htc:
+	if (i != NUM_CONTROL_BUFFERS || status) {
+		if (target) {
+			ath6kl_htc_cleanup(target);
+			target = NULL;
+		}
+	}
+
+	return target;
+}
+
+/* cleanup the HTC instance */
+void ath6kl_htc_cleanup(struct htc_target *target)
+{
+	struct htc_packet *packet, *tmp_packet;
+
+	ath6kl_hif_cleanup_scatter(target->dev->ar);
+
+	list_for_each_entry_safe(packet, tmp_packet,
+			&target->free_ctrl_txbuf, list) {
+		list_del(&packet->list);
+		kfree(packet->buf_start);
+		kfree(packet);
+	}
+
+	list_for_each_entry_safe(packet, tmp_packet,
+			&target->free_ctrl_rxbuf, list) {
+		list_del(&packet->list);
+		kfree(packet->buf_start);
+		kfree(packet);
+	}
+
+	kfree(target->dev);
+	kfree(target);
+}
diff --git a/drivers/net/wireless/ath/ath6kl/htc.h b/drivers/net/wireless/ath/ath6kl/htc.h
new file mode 100644
index 000000000000..8ce0c2c07ded
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/htc.h
@@ -0,0 +1,607 @@
+/*
+ * Copyright (c) 2004-2011 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 HTC_H
+#define HTC_H
+
+#include "common.h"
+
+/* frame header flags */
+
+/* send direction */
+#define HTC_FLAGS_NEED_CREDIT_UPDATE (1 << 0)
+#define HTC_FLAGS_SEND_BUNDLE        (1 << 1)
+
+/* receive direction */
+#define HTC_FLG_RX_UNUSED        (1 << 0)
+#define HTC_FLG_RX_TRAILER       (1 << 1)
+/* Bundle count maske and shift */
+#define HTC_FLG_RX_BNDL_CNT	 (0xF0)
+#define HTC_FLG_RX_BNDL_CNT_S	 4
+
+#define HTC_HDR_LENGTH  (sizeof(struct htc_frame_hdr))
+#define HTC_MAX_PAYLOAD_LENGTH   (4096 - sizeof(struct htc_frame_hdr))
+
+/* HTC control message IDs */
+
+#define HTC_MSG_READY_ID		1
+#define HTC_MSG_CONN_SVC_ID		2
+#define HTC_MSG_CONN_SVC_RESP_ID	3
+#define HTC_MSG_SETUP_COMPLETE_ID	4
+#define HTC_MSG_SETUP_COMPLETE_EX_ID	5
+
+#define HTC_MAX_CTRL_MSG_LEN  256
+
+#define HTC_VERSION_2P0  0x00
+#define HTC_VERSION_2P1  0x01
+
+#define HTC_SERVICE_META_DATA_MAX_LENGTH 128
+
+#define HTC_CONN_FLGS_THRESH_LVL_QUAT		0x0
+#define HTC_CONN_FLGS_THRESH_LVL_HALF		0x1
+#define HTC_CONN_FLGS_THRESH_LVL_THREE_QUAT	0x2
+#define HTC_CONN_FLGS_REDUCE_CRED_DRIB		0x4
+#define HTC_CONN_FLGS_THRESH_MASK		0x3
+
+/* connect response status codes */
+#define HTC_SERVICE_SUCCESS      0
+#define HTC_SERVICE_NOT_FOUND    1
+#define HTC_SERVICE_FAILED       2
+
+/* no resources (i.e. no more endpoints) */
+#define HTC_SERVICE_NO_RESOURCES 3
+
+/* specific service is not allowing any more endpoints */
+#define HTC_SERVICE_NO_MORE_EP   4
+
+/* report record IDs */
+#define HTC_RECORD_NULL             0
+#define HTC_RECORD_CREDITS          1
+#define HTC_RECORD_LOOKAHEAD        2
+#define HTC_RECORD_LOOKAHEAD_BUNDLE 3
+
+#define HTC_SETUP_COMP_FLG_RX_BNDL_EN     (1 << 0)
+
+#define MAKE_SERVICE_ID(group, index) \
+	(int)(((int)group << 8) | (int)(index))
+
+/* NOTE: service ID of 0x0000 is reserved and should never be used */
+#define HTC_CTRL_RSVD_SVC MAKE_SERVICE_ID(RSVD_SERVICE_GROUP, 1)
+#define WMI_CONTROL_SVC   MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 0)
+#define WMI_DATA_BE_SVC   MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 1)
+#define WMI_DATA_BK_SVC   MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 2)
+#define WMI_DATA_VI_SVC   MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 3)
+#define WMI_DATA_VO_SVC   MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 4)
+#define WMI_MAX_SERVICES  5
+
+/* reserved and used to flush ALL packets */
+#define HTC_TX_PACKET_TAG_ALL          0
+#define HTC_SERVICE_TX_PACKET_TAG      1
+#define HTC_TX_PACKET_TAG_USER_DEFINED (HTC_SERVICE_TX_PACKET_TAG + 9)
+
+/* more packets on this endpoint are being fetched */
+#define HTC_RX_FLAGS_INDICATE_MORE_PKTS  (1 << 0)
+
+/* TODO.. for BMI */
+#define ENDPOINT1 0
+/* TODO -remove me, but we have to fix BMI first */
+#define HTC_MAILBOX_NUM_MAX    4
+
+/* enable send bundle padding for this endpoint */
+#define HTC_FLGS_TX_BNDL_PAD_EN	 (1 << 0)
+#define HTC_EP_ACTIVE                            ((u32) (1u << 31))
+
+/* HTC operational parameters */
+#define HTC_TARGET_RESPONSE_TIMEOUT        2000	/* in ms */
+#define HTC_TARGET_DEBUG_INTR_MASK         0x01
+#define HTC_TARGET_CREDIT_INTR_MASK        0xF0
+
+#define HTC_HOST_MAX_MSG_PER_BUNDLE        8
+#define HTC_MIN_HTC_MSGS_TO_BUNDLE         2
+
+/* packet flags */
+
+#define HTC_RX_PKT_IGNORE_LOOKAHEAD      (1 << 0)
+#define HTC_RX_PKT_REFRESH_HDR           (1 << 1)
+#define HTC_RX_PKT_PART_OF_BUNDLE        (1 << 2)
+#define HTC_RX_PKT_NO_RECYCLE            (1 << 3)
+
+#define NUM_CONTROL_BUFFERS     8
+#define NUM_CONTROL_TX_BUFFERS  2
+#define NUM_CONTROL_RX_BUFFERS  (NUM_CONTROL_BUFFERS - NUM_CONTROL_TX_BUFFERS)
+
+#define HTC_RECV_WAIT_BUFFERS        (1 << 0)
+#define HTC_OP_STATE_STOPPING        (1 << 0)
+
+/*
+ * The frame header length and message formats defined herein were selected
+ * to accommodate optimal alignment for target processing. This reduces
+ * code size and improves performance. Any changes to the header length may
+ * alter the alignment and cause exceptions on the target. When adding to
+ * the messagestructures insure that fields are properly aligned.
+ */
+
+/* HTC frame header
+ *
+ * NOTE: do not remove or re-arrange the fields, these are minimally
+ * required to take advantage of 4-byte lookaheads in some hardware
+ * implementations.
+ */
+struct htc_frame_hdr {
+	u8 eid;
+	u8 flags;
+
+	/* length of data (including trailer) that follows the header */
+	__le16 payld_len;
+
+	/* end of 4-byte lookahead */
+
+	u8 ctrl[2];
+} __packed;
+
+/* HTC ready message */
+struct htc_ready_msg {
+	__le16 msg_id;
+	__le16 cred_cnt;
+	__le16 cred_sz;
+	u8 max_ep;
+	u8 pad;
+} __packed;
+
+/* extended HTC ready message */
+struct htc_ready_ext_msg {
+	struct htc_ready_msg ver2_0_info;
+	u8 htc_ver;
+	u8 msg_per_htc_bndl;
+} __packed;
+
+/* connect service */
+struct htc_conn_service_msg {
+	__le16 msg_id;
+	__le16 svc_id;
+	__le16 conn_flags;
+	u8 svc_meta_len;
+	u8 pad;
+} __packed;
+
+/* connect response */
+struct htc_conn_service_resp {
+	__le16 msg_id;
+	__le16 svc_id;
+	u8 status;
+	u8 eid;
+	__le16 max_msg_sz;
+	u8 svc_meta_len;
+	u8 pad;
+} __packed;
+
+struct htc_setup_comp_msg {
+	__le16 msg_id;
+} __packed;
+
+/* extended setup completion message */
+struct htc_setup_comp_ext_msg {
+	__le16 msg_id;
+	__le32 flags;
+	u8 msg_per_rxbndl;
+	u8 Rsvd[3];
+} __packed;
+
+struct htc_record_hdr {
+	u8 rec_id;
+	u8 len;
+} __packed;
+
+struct htc_credit_report {
+	u8 eid;
+	u8 credits;
+} __packed;
+
+/*
+ * NOTE: The lk_ahd array is guarded by a pre_valid
+ * and Post Valid guard bytes. The pre_valid bytes must
+ * equal the inverse of the post_valid byte.
+ */
+struct htc_lookahead_report {
+	u8 pre_valid;
+	u8 lk_ahd[4];
+	u8 post_valid;
+} __packed;
+
+struct htc_bundle_lkahd_rpt {
+	u8 lk_ahd[4];
+} __packed;
+
+/* Current service IDs */
+
+enum htc_service_grp_ids {
+	RSVD_SERVICE_GROUP = 0,
+	WMI_SERVICE_GROUP = 1,
+
+	HTC_TEST_GROUP = 254,
+	HTC_SERVICE_GROUP_LAST = 255
+};
+
+/* ------ endpoint IDS ------ */
+
+enum htc_endpoint_id {
+	ENDPOINT_UNUSED = -1,
+	ENDPOINT_0 = 0,
+	ENDPOINT_1 = 1,
+	ENDPOINT_2 = 2,
+	ENDPOINT_3,
+	ENDPOINT_4,
+	ENDPOINT_5,
+	ENDPOINT_6,
+	ENDPOINT_7,
+	ENDPOINT_8,
+	ENDPOINT_MAX,
+};
+
+struct htc_tx_packet_info {
+	u16 tag;
+	int cred_used;
+	u8 flags;
+	int seqno;
+};
+
+struct htc_rx_packet_info {
+	u32 exp_hdr;
+	u32 rx_flags;
+	u32 indicat_flags;
+};
+
+struct htc_target;
+
+/* wrapper around endpoint-specific packets */
+struct htc_packet {
+	struct list_head list;
+
+	/* caller's per packet specific context */
+	void *pkt_cntxt;
+
+	/*
+	 * the true buffer start , the caller can store the real
+	 * buffer start here.  In receive callbacks, the HTC layer
+	 * sets buf to the start of the payload past the header.
+	 * This field allows the caller to reset buf when it recycles
+	 * receive packets back to HTC.
+	 */
+	u8 *buf_start;
+
+	/*
+	 * Pointer to the start of the buffer. In the transmit
+	 * direction this points to the start of the payload. In the
+	 * receive direction, however, the buffer when queued up
+	 * points to the start of the HTC header but when returned
+	 * to the caller points to the start of the payload
+	 */
+	u8 *buf;
+	u32 buf_len;
+
+	/* actual length of payload */
+	u32 act_len;
+
+	/* endpoint that this packet was sent/recv'd from */
+	enum htc_endpoint_id endpoint;
+
+	/* completion status */
+
+	int status;
+	union {
+		struct htc_tx_packet_info tx;
+		struct htc_rx_packet_info rx;
+	} info;
+
+	void (*completion) (struct htc_target *, struct htc_packet *);
+	struct htc_target *context;
+};
+
+enum htc_send_full_action {
+	HTC_SEND_FULL_KEEP = 0,
+	HTC_SEND_FULL_DROP = 1,
+};
+
+struct htc_ep_callbacks {
+	void (*rx) (struct htc_target *, struct htc_packet *);
+	void (*rx_refill) (struct htc_target *, enum htc_endpoint_id endpoint);
+	enum htc_send_full_action (*tx_full) (struct htc_target *,
+					      struct htc_packet *);
+	struct htc_packet *(*rx_allocthresh) (struct htc_target *,
+					      enum htc_endpoint_id, int);
+	int rx_alloc_thresh;
+	int rx_refill_thresh;
+};
+
+/* service connection information */
+struct htc_service_connect_req {
+	u16 svc_id;
+	u16 conn_flags;
+	struct htc_ep_callbacks ep_cb;
+	int max_txq_depth;
+	u32 flags;
+	unsigned int max_rxmsg_sz;
+};
+
+/* service connection response information */
+struct htc_service_connect_resp {
+	u8 buf_len;
+	u8 act_len;
+	enum htc_endpoint_id endpoint;
+	unsigned int len_max;
+	u8 resp_code;
+};
+
+/* endpoint distributionstructure */
+struct htc_endpoint_credit_dist {
+	struct list_head list;
+
+	/* Service ID (set by HTC) */
+	u16 svc_id;
+
+	/* endpoint for this distributionstruct (set by HTC) */
+	enum htc_endpoint_id endpoint;
+
+	u32 dist_flags;
+
+	/*
+	 * credits for normal operation, anything above this
+	 * indicates the endpoint is over-subscribed.
+	 */
+	int cred_norm;
+
+	/* floor for credit distribution */
+	int cred_min;
+
+	int cred_assngd;
+
+	/* current credits available */
+	int credits;
+
+	/*
+	 * pending credits to distribute on this endpoint, this
+	 * is set by HTC when credit reports arrive.  The credit
+	 * distribution functions sets this to zero when it distributes
+	 * the credits.
+	 */
+	int cred_to_dist;
+
+	/*
+	 * the number of credits that the current pending TX packet needs
+	 * to transmit. This is set by HTC when endpoint needs credits in
+	 * order to transmit.
+	 */
+	int seek_cred;
+
+	/* size in bytes of each credit */
+	int cred_sz;
+
+	/* credits required for a maximum sized messages */
+	int cred_per_msg;
+
+	/* reserved for HTC use */
+	void *htc_rsvd;
+
+	/*
+	 * current depth of TX queue , i.e. messages waiting for credits
+	 * This field is valid only when HTC_CREDIT_DIST_ACTIVITY_CHANGE
+	 * or HTC_CREDIT_DIST_SEND_COMPLETE is indicated on an endpoint
+	 * that has non-zero credits to recover.
+	 */
+	int txq_depth;
+};
+
+/*
+ * credit distibution code that is passed into the distrbution function,
+ * there are mandatory and optional codes that must be handled
+ */
+enum htc_credit_dist_reason {
+	HTC_CREDIT_DIST_SEND_COMPLETE = 0,
+	HTC_CREDIT_DIST_ACTIVITY_CHANGE = 1,
+	HTC_CREDIT_DIST_SEEK_CREDITS,
+};
+
+struct htc_credit_state_info {
+	int total_avail_credits;
+	int cur_free_credits;
+	struct list_head lowestpri_ep_dist;
+};
+
+/* endpoint statistics */
+struct htc_endpoint_stats {
+	/*
+	 * number of times the host set the credit-low flag in a send
+	 * message on this endpoint
+	 */
+	u32 cred_low_indicate;
+
+	u32 tx_issued;
+	u32 tx_pkt_bundled;
+	u32 tx_bundles;
+	u32 tx_dropped;
+
+	/* running count of total credit reports received for this endpoint */
+	u32 tx_cred_rpt;
+
+	/* credit reports received from this endpoint's RX packets */
+	u32 cred_rpt_from_rx;
+
+	/* credit reports received from RX packets of other endpoints */
+	u32 cred_rpt_from_other;
+
+	/* credit reports received from endpoint 0 RX packets */
+	u32 cred_rpt_ep0;
+
+	/* count of credits received via Rx packets on this endpoint */
+	u32 cred_from_rx;
+
+	/* count of credits received via another endpoint */
+	u32 cred_from_other;
+
+	/* count of credits received via another endpoint */
+	u32 cred_from_ep0;
+
+	/* count of consummed credits */
+	u32 cred_cosumd;
+
+	/* count of credits returned */
+	u32 cred_retnd;
+
+	u32 rx_pkts;
+
+	/* count of lookahead records found in Rx msg */
+	u32 rx_lkahds;
+
+	/* count of recv packets received in a bundle */
+	u32 rx_bundl;
+
+	/* count of number of bundled lookaheads */
+	u32 rx_bundle_lkahd;
+
+	/* count of the number of bundle indications from the HTC header */
+	u32 rx_bundle_from_hdr;
+
+	/* the number of times the recv allocation threshold was hit */
+	u32 rx_alloc_thresh_hit;
+
+	/* total number of bytes */
+	u32 rxalloc_thresh_byte;
+};
+
+struct htc_endpoint {
+	enum htc_endpoint_id eid;
+	u16 svc_id;
+	struct list_head txq;
+	struct list_head rx_bufq;
+	struct htc_endpoint_credit_dist cred_dist;
+	struct htc_ep_callbacks ep_cb;
+	int max_txq_depth;
+	int len_max;
+	int tx_proc_cnt;
+	int rx_proc_cnt;
+	struct htc_target *target;
+	u8 seqno;
+	u32 conn_flags;
+	struct htc_endpoint_stats ep_st;
+};
+
+struct htc_control_buffer {
+	struct htc_packet packet;
+	u8 *buf;
+};
+
+struct ath6kl_device;
+
+/* our HTC target state */
+struct htc_target {
+	struct htc_endpoint endpoint[ENDPOINT_MAX];
+	struct list_head cred_dist_list;
+	struct list_head free_ctrl_txbuf;
+	struct list_head free_ctrl_rxbuf;
+	struct htc_credit_state_info *cred_dist_cntxt;
+	int tgt_creds;
+	unsigned int tgt_cred_sz;
+	spinlock_t htc_lock;
+	spinlock_t rx_lock;
+	spinlock_t tx_lock;
+	struct ath6kl_device *dev;
+	u32 htc_flags;
+	u32 rx_st_flags;
+	enum htc_endpoint_id ep_waiting;
+	u8 htc_tgt_ver;
+
+	/* max messages per bundle for HTC */
+	int msg_per_bndl_max;
+
+	bool tx_bndl_enable;
+	int rx_bndl_enable;
+	int max_rx_bndl_sz;
+	int max_tx_bndl_sz;
+
+	u32 block_sz;
+	u32 block_mask;
+
+	int max_scat_entries;
+	int max_xfer_szper_scatreq;
+
+	int chk_irq_status_cnt;
+};
+
+void *ath6kl_htc_create(struct ath6kl *ar);
+void ath6kl_htc_set_credit_dist(struct htc_target *target,
+				struct htc_credit_state_info *cred_info,
+				u16 svc_pri_order[], int len);
+int ath6kl_htc_wait_target(struct htc_target *target);
+int ath6kl_htc_start(struct htc_target *target);
+int ath6kl_htc_conn_service(struct htc_target *target,
+			    struct htc_service_connect_req *req,
+			    struct htc_service_connect_resp *resp);
+int ath6kl_htc_tx(struct htc_target *target, struct htc_packet *packet);
+void ath6kl_htc_stop(struct htc_target *target);
+void ath6kl_htc_cleanup(struct htc_target *target);
+void ath6kl_htc_flush_txep(struct htc_target *target,
+			   enum htc_endpoint_id endpoint, u16 tag);
+void ath6kl_htc_flush_rx_buf(struct htc_target *target);
+void ath6kl_htc_indicate_activity_change(struct htc_target *target,
+					 enum htc_endpoint_id endpoint,
+					 bool active);
+int ath6kl_htc_get_rxbuf_num(struct htc_target *target,
+			     enum htc_endpoint_id endpoint);
+int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target,
+				  struct list_head *pktq);
+int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target,
+				     u32 msg_look_ahead[], int *n_pkts);
+
+static inline void set_htc_pkt_info(struct htc_packet *packet, void *context,
+				    u8 *buf, unsigned int len,
+				    enum htc_endpoint_id eid, u16 tag)
+{
+	packet->pkt_cntxt = context;
+	packet->buf = buf;
+	packet->act_len = len;
+	packet->endpoint = eid;
+	packet->info.tx.tag = tag;
+}
+
+static inline void htc_rxpkt_reset(struct htc_packet *packet)
+{
+	packet->buf = packet->buf_start;
+	packet->act_len = 0;
+}
+
+static inline void set_htc_rxpkt_info(struct htc_packet *packet, void *context,
+				      u8 *buf, unsigned long len,
+				      enum htc_endpoint_id eid)
+{
+	packet->pkt_cntxt = context;
+	packet->buf = buf;
+	packet->buf_start = buf;
+	packet->buf_len = len;
+	packet->endpoint = eid;
+}
+
+static inline int get_queue_depth(struct list_head *queue)
+{
+	struct list_head *tmp_list;
+	int depth = 0;
+
+	list_for_each(tmp_list, queue)
+	    depth++;
+
+	return depth;
+}
+
+#endif
diff --git a/drivers/net/wireless/ath/ath6kl/htc_hif.c b/drivers/net/wireless/ath/ath6kl/htc_hif.c
new file mode 100644
index 000000000000..86b1cc7409c2
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/htc_hif.c
@@ -0,0 +1,641 @@
+/*
+ * Copyright (c) 2007-2011 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.
+ */
+
+#include "core.h"
+#include "target.h"
+#include "hif-ops.h"
+#include "htc_hif.h"
+#include "debug.h"
+
+#define MAILBOX_FOR_BLOCK_SIZE          1
+
+#define ATH6KL_TIME_QUANTUM	10  /* in ms */
+
+static int ath6kldev_cp_scat_dma_buf(struct hif_scatter_req *req, bool from_dma)
+{
+	u8 *buf;
+	int i;
+
+	buf = req->virt_dma_buf;
+
+	for (i = 0; i < req->scat_entries; i++) {
+
+		if (from_dma)
+			memcpy(req->scat_list[i].buf, buf,
+			       req->scat_list[i].len);
+		else
+			memcpy(buf, req->scat_list[i].buf,
+			       req->scat_list[i].len);
+
+		buf += req->scat_list[i].len;
+	}
+
+	return 0;
+}
+
+int ath6kldev_rw_comp_handler(void *context, int status)
+{
+	struct htc_packet *packet = context;
+
+	ath6kl_dbg(ATH6KL_DBG_HTC_RECV,
+		   "ath6kldev_rw_comp_handler (pkt:0x%p , status: %d\n",
+		   packet, status);
+
+	packet->status = status;
+	packet->completion(packet->context, packet);
+
+	return 0;
+}
+
+static int ath6kldev_proc_dbg_intr(struct ath6kl_device *dev)
+{
+	u32 dummy;
+	int status;
+
+	ath6kl_err("target debug interrupt\n");
+
+	ath6kl_target_failure(dev->ar);
+
+	/*
+	 * read counter to clear the interrupt, the debug error interrupt is
+	 * counter 0.
+	 */
+	status = hif_read_write_sync(dev->ar, COUNT_DEC_ADDRESS,
+				     (u8 *)&dummy, 4, HIF_RD_SYNC_BYTE_INC);
+	if (status)
+		WARN_ON(1);
+
+	return status;
+}
+
+/* mailbox recv message polling */
+int ath6kldev_poll_mboxmsg_rx(struct ath6kl_device *dev, u32 *lk_ahd,
+			      int timeout)
+{
+	struct ath6kl_irq_proc_registers *rg;
+	int status = 0, i;
+	u8 htc_mbox = 1 << HTC_MAILBOX;
+
+	for (i = timeout / ATH6KL_TIME_QUANTUM; i > 0; i--) {
+		/* this is the standard HIF way, load the reg table */
+		status = hif_read_write_sync(dev->ar, HOST_INT_STATUS_ADDRESS,
+					     (u8 *) &dev->irq_proc_reg,
+					     sizeof(dev->irq_proc_reg),
+					     HIF_RD_SYNC_BYTE_INC);
+
+		if (status) {
+			ath6kl_err("failed to read reg table\n");
+			return status;
+		}
+
+		/* check for MBOX data and valid lookahead */
+		if (dev->irq_proc_reg.host_int_status & htc_mbox) {
+			if (dev->irq_proc_reg.rx_lkahd_valid &
+			    htc_mbox) {
+				/*
+				 * Mailbox has a message and the look ahead
+				 * is valid.
+				 */
+				rg = &dev->irq_proc_reg;
+				*lk_ahd =
+					le32_to_cpu(rg->rx_lkahd[HTC_MAILBOX]);
+				break;
+			}
+		}
+
+		/* delay a little  */
+		mdelay(ATH6KL_TIME_QUANTUM);
+		ath6kl_dbg(ATH6KL_DBG_HTC_RECV, "retry mbox poll : %d\n", i);
+	}
+
+	if (i == 0) {
+		ath6kl_err("timeout waiting for recv message\n");
+		status = -ETIME;
+		/* check if the target asserted */
+		if (dev->irq_proc_reg.counter_int_status &
+		    ATH6KL_TARGET_DEBUG_INTR_MASK)
+			/*
+			 * Target failure handler will be called in case of
+			 * an assert.
+			 */
+			ath6kldev_proc_dbg_intr(dev);
+	}
+
+	return status;
+}
+
+/*
+ * Disable packet reception (used in case the host runs out of buffers)
+ * using the interrupt enable registers through the host I/F
+ */
+int ath6kldev_rx_control(struct ath6kl_device *dev, bool enable_rx)
+{
+	struct ath6kl_irq_enable_reg regs;
+	int status = 0;
+
+	/* take the lock to protect interrupt enable shadows */
+	spin_lock_bh(&dev->lock);
+
+	if (enable_rx)
+		dev->irq_en_reg.int_status_en |=
+			SM(INT_STATUS_ENABLE_MBOX_DATA, 0x01);
+	else
+		dev->irq_en_reg.int_status_en &=
+		    ~SM(INT_STATUS_ENABLE_MBOX_DATA, 0x01);
+
+	memcpy(&regs, &dev->irq_en_reg, sizeof(regs));
+
+	spin_unlock_bh(&dev->lock);
+
+	status = hif_read_write_sync(dev->ar, INT_STATUS_ENABLE_ADDRESS,
+				     &regs.int_status_en,
+				     sizeof(struct ath6kl_irq_enable_reg),
+				     HIF_WR_SYNC_BYTE_INC);
+
+	return status;
+}
+
+int ath6kldev_submit_scat_req(struct ath6kl_device *dev,
+			      struct hif_scatter_req *scat_req, bool read)
+{
+	int status = 0;
+
+	if (read) {
+		scat_req->req = HIF_RD_SYNC_BLOCK_FIX;
+		scat_req->addr = dev->ar->mbox_info.htc_addr;
+	} else {
+		scat_req->req = HIF_WR_ASYNC_BLOCK_INC;
+
+		scat_req->addr =
+			(scat_req->len > HIF_MBOX_WIDTH) ?
+			dev->ar->mbox_info.htc_ext_addr :
+			dev->ar->mbox_info.htc_addr;
+	}
+
+	ath6kl_dbg((ATH6KL_DBG_HTC_RECV | ATH6KL_DBG_HTC_SEND),
+		   "ath6kldev_submit_scat_req, entries: %d, total len: %d mbox:0x%X (mode: %s : %s)\n",
+		   scat_req->scat_entries, scat_req->len,
+		   scat_req->addr, !read ? "async" : "sync",
+		   (read) ? "rd" : "wr");
+
+	if (!read && scat_req->virt_scat) {
+		status = ath6kldev_cp_scat_dma_buf(scat_req, false);
+		if (status) {
+			scat_req->status = status;
+			scat_req->complete(dev->ar->htc_target, scat_req);
+			return 0;
+		}
+	}
+
+	status = ath6kl_hif_scat_req_rw(dev->ar, scat_req);
+
+	if (read) {
+		/* in sync mode, we can touch the scatter request */
+		scat_req->status = status;
+		if (!status && scat_req->virt_scat)
+			scat_req->status =
+				ath6kldev_cp_scat_dma_buf(scat_req, true);
+	}
+
+	return status;
+}
+
+static int ath6kldev_proc_counter_intr(struct ath6kl_device *dev)
+{
+	u8 counter_int_status;
+
+	ath6kl_dbg(ATH6KL_DBG_IRQ, "counter interrupt\n");
+
+	counter_int_status = dev->irq_proc_reg.counter_int_status &
+			     dev->irq_en_reg.cntr_int_status_en;
+
+	ath6kl_dbg(ATH6KL_DBG_IRQ,
+		"valid interrupt source(s) in COUNTER_INT_STATUS: 0x%x\n",
+		counter_int_status);
+
+	/*
+	 * NOTE: other modules like GMBOX may use the counter interrupt for
+	 * credit flow control on other counters, we only need to check for
+	 * the debug assertion counter interrupt.
+	 */
+	if (counter_int_status & ATH6KL_TARGET_DEBUG_INTR_MASK)
+		return ath6kldev_proc_dbg_intr(dev);
+
+	return 0;
+}
+
+static int ath6kldev_proc_err_intr(struct ath6kl_device *dev)
+{
+	int status;
+	u8 error_int_status;
+	u8 reg_buf[4];
+
+	ath6kl_dbg(ATH6KL_DBG_IRQ, "error interrupt\n");
+
+	error_int_status = dev->irq_proc_reg.error_int_status & 0x0F;
+	if (!error_int_status) {
+		WARN_ON(1);
+		return -EIO;
+	}
+
+	ath6kl_dbg(ATH6KL_DBG_IRQ,
+		   "valid interrupt source(s) in ERROR_INT_STATUS: 0x%x\n",
+		   error_int_status);
+
+	if (MS(ERROR_INT_STATUS_WAKEUP, error_int_status))
+		ath6kl_dbg(ATH6KL_DBG_IRQ, "error : wakeup\n");
+
+	if (MS(ERROR_INT_STATUS_RX_UNDERFLOW, error_int_status))
+		ath6kl_err("rx underflow\n");
+
+	if (MS(ERROR_INT_STATUS_TX_OVERFLOW, error_int_status))
+		ath6kl_err("tx overflow\n");
+
+	/* Clear the interrupt */
+	dev->irq_proc_reg.error_int_status &= ~error_int_status;
+
+	/* set W1C value to clear the interrupt, this hits the register first */
+	reg_buf[0] = error_int_status;
+	reg_buf[1] = 0;
+	reg_buf[2] = 0;
+	reg_buf[3] = 0;
+
+	status = hif_read_write_sync(dev->ar, ERROR_INT_STATUS_ADDRESS,
+				     reg_buf, 4, HIF_WR_SYNC_BYTE_FIX);
+
+	if (status)
+		WARN_ON(1);
+
+	return status;
+}
+
+static int ath6kldev_proc_cpu_intr(struct ath6kl_device *dev)
+{
+	int status;
+	u8 cpu_int_status;
+	u8 reg_buf[4];
+
+	ath6kl_dbg(ATH6KL_DBG_IRQ, "cpu interrupt\n");
+
+	cpu_int_status = dev->irq_proc_reg.cpu_int_status &
+			 dev->irq_en_reg.cpu_int_status_en;
+	if (!cpu_int_status) {
+		WARN_ON(1);
+		return -EIO;
+	}
+
+	ath6kl_dbg(ATH6KL_DBG_IRQ,
+		"valid interrupt source(s) in CPU_INT_STATUS: 0x%x\n",
+		cpu_int_status);
+
+	/* Clear the interrupt */
+	dev->irq_proc_reg.cpu_int_status &= ~cpu_int_status;
+
+	/*
+	 * Set up the register transfer buffer to hit the register 4 times ,
+	 * this is done to make the access 4-byte aligned to mitigate issues
+	 * with host bus interconnects that restrict bus transfer lengths to
+	 * be a multiple of 4-bytes.
+	 */
+
+	/* set W1C value to clear the interrupt, this hits the register first */
+	reg_buf[0] = cpu_int_status;
+	/* the remaining are set to zero which have no-effect  */
+	reg_buf[1] = 0;
+	reg_buf[2] = 0;
+	reg_buf[3] = 0;
+
+	status = hif_read_write_sync(dev->ar, CPU_INT_STATUS_ADDRESS,
+				     reg_buf, 4, HIF_WR_SYNC_BYTE_FIX);
+
+	if (status)
+		WARN_ON(1);
+
+	return status;
+}
+
+/* process pending interrupts synchronously */
+static int proc_pending_irqs(struct ath6kl_device *dev, bool *done)
+{
+	struct ath6kl_irq_proc_registers *rg;
+	int status = 0;
+	u8 host_int_status = 0;
+	u32 lk_ahd = 0;
+	u8 htc_mbox = 1 << HTC_MAILBOX;
+
+	ath6kl_dbg(ATH6KL_DBG_IRQ, "proc_pending_irqs: (dev: 0x%p)\n", dev);
+
+	/*
+	 * NOTE: HIF implementation guarantees that the context of this
+	 * call allows us to perform SYNCHRONOUS I/O, that is we can block,
+	 * sleep or call any API that can block or switch thread/task
+	 * contexts. This is a fully schedulable context.
+	 */
+
+	/*
+	 * Process pending intr only when int_status_en is clear, it may
+	 * result in unnecessary bus transaction otherwise. Target may be
+	 * unresponsive at the time.
+	 */
+	if (dev->irq_en_reg.int_status_en) {
+		/*
+		 * Read the first 28 bytes of the HTC register table. This
+		 * will yield us the value of different int status
+		 * registers and the lookahead registers.
+		 *
+		 *    length = sizeof(int_status) + sizeof(cpu_int_status)
+		 *             + sizeof(error_int_status) +
+		 *             sizeof(counter_int_status) +
+		 *             sizeof(mbox_frame) + sizeof(rx_lkahd_valid)
+		 *             + sizeof(hole) + sizeof(rx_lkahd) +
+		 *             sizeof(int_status_en) +
+		 *             sizeof(cpu_int_status_en) +
+		 *             sizeof(err_int_status_en) +
+		 *             sizeof(cntr_int_status_en);
+		 */
+		status = hif_read_write_sync(dev->ar, HOST_INT_STATUS_ADDRESS,
+					     (u8 *) &dev->irq_proc_reg,
+					     sizeof(dev->irq_proc_reg),
+					     HIF_RD_SYNC_BYTE_INC);
+		if (status)
+			goto out;
+
+		if (AR_DBG_LVL_CHECK(ATH6KL_DBG_IRQ))
+			ath6kl_dump_registers(dev, &dev->irq_proc_reg,
+					 &dev->irq_en_reg);
+
+		/* Update only those registers that are enabled */
+		host_int_status = dev->irq_proc_reg.host_int_status &
+				  dev->irq_en_reg.int_status_en;
+
+		/* Look at mbox status */
+		if (host_int_status & htc_mbox) {
+			/*
+			 * Mask out pending mbox value, we use "lookAhead as
+			 * the real flag for mbox processing.
+			 */
+			host_int_status &= ~htc_mbox;
+			if (dev->irq_proc_reg.rx_lkahd_valid &
+			    htc_mbox) {
+				rg = &dev->irq_proc_reg;
+				lk_ahd = le32_to_cpu(rg->rx_lkahd[HTC_MAILBOX]);
+				if (!lk_ahd)
+					ath6kl_err("lookAhead is zero!\n");
+			}
+		}
+	}
+
+	if (!host_int_status && !lk_ahd) {
+		*done = true;
+		goto out;
+	}
+
+	if (lk_ahd) {
+		int fetched = 0;
+
+		ath6kl_dbg(ATH6KL_DBG_IRQ,
+			   "pending mailbox msg, lk_ahd: 0x%X\n", lk_ahd);
+		/*
+		 * Mailbox Interrupt, the HTC layer may issue async
+		 * requests to empty the mailbox. When emptying the recv
+		 * mailbox we use the async handler above called from the
+		 * completion routine of the callers read request. This can
+		 * improve performance by reducing context switching when
+		 * we rapidly pull packets.
+		 */
+		status = ath6kl_htc_rxmsg_pending_handler(dev->htc_cnxt,
+							  &lk_ahd, &fetched);
+		if (status)
+			goto out;
+
+		if (!fetched)
+			/*
+			 * HTC could not pull any messages out due to lack
+			 * of resources.
+			 */
+			dev->htc_cnxt->chk_irq_status_cnt = 0;
+	}
+
+	/* now handle the rest of them */
+	ath6kl_dbg(ATH6KL_DBG_IRQ,
+		   "valid interrupt source(s) for other interrupts: 0x%x\n",
+		   host_int_status);
+
+	if (MS(HOST_INT_STATUS_CPU, host_int_status)) {
+		/* CPU Interrupt */
+		status = ath6kldev_proc_cpu_intr(dev);
+		if (status)
+			goto out;
+	}
+
+	if (MS(HOST_INT_STATUS_ERROR, host_int_status)) {
+		/* Error Interrupt */
+		status = ath6kldev_proc_err_intr(dev);
+		if (status)
+			goto out;
+	}
+
+	if (MS(HOST_INT_STATUS_COUNTER, host_int_status))
+		/* Counter Interrupt */
+		status = ath6kldev_proc_counter_intr(dev);
+
+out:
+	/*
+	 * An optimization to bypass reading the IRQ status registers
+	 * unecessarily which can re-wake the target, if upper layers
+	 * determine that we are in a low-throughput mode, we can rely on
+	 * taking another interrupt rather than re-checking the status
+	 * registers which can re-wake the target.
+	 *
+	 * NOTE : for host interfaces that makes use of detecting pending
+	 * mbox messages at hif can not use this optimization due to
+	 * possible side effects, SPI requires the host to drain all
+	 * messages from the mailbox before exiting the ISR routine.
+	 */
+
+	ath6kl_dbg(ATH6KL_DBG_IRQ,
+		   "bypassing irq status re-check, forcing done\n");
+
+	if (!dev->htc_cnxt->chk_irq_status_cnt)
+		*done = true;
+
+	ath6kl_dbg(ATH6KL_DBG_IRQ,
+		   "proc_pending_irqs: (done:%d, status=%d\n", *done, status);
+
+	return status;
+}
+
+/* interrupt handler, kicks off all interrupt processing */
+int ath6kldev_intr_bh_handler(struct ath6kl *ar)
+{
+	struct ath6kl_device *dev = ar->htc_target->dev;
+	int status = 0;
+	bool done = false;
+
+	/*
+	 * Reset counter used to flag a re-scan of IRQ status registers on
+	 * the target.
+	 */
+	dev->htc_cnxt->chk_irq_status_cnt = 0;
+
+	/*
+	 * IRQ processing is synchronous, interrupt status registers can be
+	 * re-read.
+	 */
+	while (!done) {
+		status = proc_pending_irqs(dev, &done);
+		if (status)
+			break;
+	}
+
+	return status;
+}
+
+static int ath6kldev_enable_intrs(struct ath6kl_device *dev)
+{
+	struct ath6kl_irq_enable_reg regs;
+	int status;
+
+	spin_lock_bh(&dev->lock);
+
+	/* Enable all but ATH6KL CPU interrupts */
+	dev->irq_en_reg.int_status_en =
+			SM(INT_STATUS_ENABLE_ERROR, 0x01) |
+			SM(INT_STATUS_ENABLE_CPU, 0x01) |
+			SM(INT_STATUS_ENABLE_COUNTER, 0x01);
+
+	/*
+	 * NOTE: There are some cases where HIF can do detection of
+	 * pending mbox messages which is disabled now.
+	 */
+	dev->irq_en_reg.int_status_en |= SM(INT_STATUS_ENABLE_MBOX_DATA, 0x01);
+
+	/* Set up the CPU Interrupt status Register */
+	dev->irq_en_reg.cpu_int_status_en = 0;
+
+	/* Set up the Error Interrupt status Register */
+	dev->irq_en_reg.err_int_status_en =
+		SM(ERROR_STATUS_ENABLE_RX_UNDERFLOW, 0x01) |
+		SM(ERROR_STATUS_ENABLE_TX_OVERFLOW, 0x1);
+
+	/*
+	 * Enable Counter interrupt status register to get fatal errors for
+	 * debugging.
+	 */
+	dev->irq_en_reg.cntr_int_status_en = SM(COUNTER_INT_STATUS_ENABLE_BIT,
+						ATH6KL_TARGET_DEBUG_INTR_MASK);
+	memcpy(&regs, &dev->irq_en_reg, sizeof(regs));
+
+	spin_unlock_bh(&dev->lock);
+
+	status = hif_read_write_sync(dev->ar, INT_STATUS_ENABLE_ADDRESS,
+				     &regs.int_status_en, sizeof(regs),
+				     HIF_WR_SYNC_BYTE_INC);
+
+	if (status)
+		ath6kl_err("failed to update interrupt ctl reg err: %d\n",
+			   status);
+
+	return status;
+}
+
+int ath6kldev_disable_intrs(struct ath6kl_device *dev)
+{
+	struct ath6kl_irq_enable_reg regs;
+
+	spin_lock_bh(&dev->lock);
+	/* Disable all interrupts */
+	dev->irq_en_reg.int_status_en = 0;
+	dev->irq_en_reg.cpu_int_status_en = 0;
+	dev->irq_en_reg.err_int_status_en = 0;
+	dev->irq_en_reg.cntr_int_status_en = 0;
+	memcpy(&regs, &dev->irq_en_reg, sizeof(regs));
+	spin_unlock_bh(&dev->lock);
+
+	return hif_read_write_sync(dev->ar, INT_STATUS_ENABLE_ADDRESS,
+				   &regs.int_status_en, sizeof(regs),
+				   HIF_WR_SYNC_BYTE_INC);
+}
+
+/* enable device interrupts */
+int ath6kldev_unmask_intrs(struct ath6kl_device *dev)
+{
+	int status = 0;
+
+	/*
+	 * Make sure interrupt are disabled before unmasking at the HIF
+	 * layer. The rationale here is that between device insertion
+	 * (where we clear the interrupts the first time) and when HTC
+	 * is finally ready to handle interrupts, other software can perform
+	 * target "soft" resets. The ATH6KL interrupt enables reset back to an
+	 * "enabled" state when this happens.
+	 */
+	ath6kldev_disable_intrs(dev);
+
+	/* unmask the host controller interrupts */
+	ath6kl_hif_irq_enable(dev->ar);
+	status = ath6kldev_enable_intrs(dev);
+
+	return status;
+}
+
+/* disable all device interrupts */
+int ath6kldev_mask_intrs(struct ath6kl_device *dev)
+{
+	/*
+	 * Mask the interrupt at the HIF layer to avoid any stray interrupt
+	 * taken while we zero out our shadow registers in
+	 * ath6kldev_disable_intrs().
+	 */
+	ath6kl_hif_irq_disable(dev->ar);
+
+	return ath6kldev_disable_intrs(dev);
+}
+
+int ath6kldev_setup(struct ath6kl_device *dev)
+{
+	int status = 0;
+
+	spin_lock_init(&dev->lock);
+
+	/*
+	 * NOTE: we actually get the block size of a mailbox other than 0,
+	 * for SDIO the block size on mailbox 0 is artificially set to 1.
+	 * So we use the block size that is set for the other 3 mailboxes.
+	 */
+	dev->htc_cnxt->block_sz = dev->ar->mbox_info.block_size;
+
+	/* must be a power of 2 */
+	if ((dev->htc_cnxt->block_sz & (dev->htc_cnxt->block_sz - 1)) != 0) {
+		WARN_ON(1);
+		goto fail_setup;
+	}
+
+	/* assemble mask, used for padding to a block */
+	dev->htc_cnxt->block_mask = dev->htc_cnxt->block_sz - 1;
+
+	ath6kl_dbg(ATH6KL_DBG_TRC, "block size: %d, mbox addr:0x%X\n",
+		   dev->htc_cnxt->block_sz, dev->ar->mbox_info.htc_addr);
+
+	ath6kl_dbg(ATH6KL_DBG_TRC,
+		   "hif interrupt processing is sync only\n");
+
+	status = ath6kldev_disable_intrs(dev);
+
+fail_setup:
+	return status;
+
+}
diff --git a/drivers/net/wireless/ath/ath6kl/htc_hif.h b/drivers/net/wireless/ath/ath6kl/htc_hif.h
new file mode 100644
index 000000000000..171ad63d89b0
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/htc_hif.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2007-2011 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 HTC_HIF_H
+#define HTC_HIF_H
+
+#include "htc.h"
+#include "hif.h"
+
+#define ATH6KL_MAILBOXES	4
+
+/* HTC runs over mailbox 0 */
+#define HTC_MAILBOX	0
+
+#define ATH6KL_TARGET_DEBUG_INTR_MASK     0x01
+
+#define OTHER_INTS_ENABLED		(INT_STATUS_ENABLE_ERROR_MASK |	\
+					INT_STATUS_ENABLE_CPU_MASK   |	\
+					INT_STATUS_ENABLE_COUNTER_MASK)
+
+#define ATH6KL_REG_IO_BUFFER_SIZE			32
+#define ATH6KL_MAX_REG_IO_BUFFERS			8
+#define ATH6KL_SCATTER_ENTRIES_PER_REQ            16
+#define ATH6KL_MAX_TRANSFER_SIZE_PER_SCATTER      (16 * 1024)
+#define ATH6KL_SCATTER_REQS                       4
+
+#ifndef A_CACHE_LINE_PAD
+#define A_CACHE_LINE_PAD                        128
+#endif
+#define ATH6KL_MIN_SCATTER_ENTRIES_PER_REQ        2
+#define ATH6KL_MIN_TRANSFER_SIZE_PER_SCATTER      (4 * 1024)
+
+struct ath6kl_irq_proc_registers {
+	u8 host_int_status;
+	u8 cpu_int_status;
+	u8 error_int_status;
+	u8 counter_int_status;
+	u8 mbox_frame;
+	u8 rx_lkahd_valid;
+	u8 host_int_status2;
+	u8 gmbox_rx_avail;
+	__le32 rx_lkahd[2];
+	__le32 rx_gmbox_lkahd_alias[2];
+} __packed;
+
+struct ath6kl_irq_enable_reg {
+	u8 int_status_en;
+	u8 cpu_int_status_en;
+	u8 err_int_status_en;
+	u8 cntr_int_status_en;
+} __packed;
+
+struct ath6kl_device {
+	spinlock_t lock;
+	u8 pad1[A_CACHE_LINE_PAD];
+	struct ath6kl_irq_proc_registers irq_proc_reg;
+	u8 pad2[A_CACHE_LINE_PAD];
+	struct ath6kl_irq_enable_reg irq_en_reg;
+	u8 pad3[A_CACHE_LINE_PAD];
+	struct htc_target *htc_cnxt;
+	struct ath6kl *ar;
+};
+
+int ath6kldev_setup(struct ath6kl_device *dev);
+int ath6kldev_unmask_intrs(struct ath6kl_device *dev);
+int ath6kldev_mask_intrs(struct ath6kl_device *dev);
+int ath6kldev_poll_mboxmsg_rx(struct ath6kl_device *dev,
+			      u32 *lk_ahd, int timeout);
+int ath6kldev_rx_control(struct ath6kl_device *dev, bool enable_rx);
+int ath6kldev_disable_intrs(struct ath6kl_device *dev);
+
+int ath6kldev_rw_comp_handler(void *context, int status);
+int ath6kldev_intr_bh_handler(struct ath6kl *ar);
+
+/* Scatter Function and Definitions */
+int ath6kldev_submit_scat_req(struct ath6kl_device *dev,
+			    struct hif_scatter_req *scat_req, bool read);
+
+#endif /*ATH6KL_H_ */
diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c
new file mode 100644
index 000000000000..9d10322eac41
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/init.c
@@ -0,0 +1,1303 @@
+
+/*
+ * Copyright (c) 2011 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.
+ */
+
+#include <linux/mmc/sdio_func.h>
+#include "core.h"
+#include "cfg80211.h"
+#include "target.h"
+#include "debug.h"
+#include "hif-ops.h"
+
+unsigned int debug_mask;
+
+module_param(debug_mask, uint, 0644);
+
+/*
+ * Include definitions here that can be used to tune the WLAN module
+ * behavior. Different customers can tune the behavior as per their needs,
+ * here.
+ */
+
+/*
+ * This configuration item enable/disable keepalive support.
+ * Keepalive support: In the absence of any data traffic to AP, null
+ * frames will be sent to the AP at periodic interval, to keep the association
+ * active. This configuration item defines the periodic interval.
+ * Use value of zero to disable keepalive support
+ * Default: 60 seconds
+ */
+#define WLAN_CONFIG_KEEP_ALIVE_INTERVAL 60
+
+/*
+ * This configuration item sets the value of disconnect timeout
+ * Firmware delays sending the disconnec event to the host for this
+ * timeout after is gets disconnected from the current AP.
+ * If the firmware successly roams within the disconnect timeout
+ * it sends a new connect event
+ */
+#define WLAN_CONFIG_DISCONNECT_TIMEOUT 10
+
+#define CONFIG_AR600x_DEBUG_UART_TX_PIN 8
+
+enum addr_type {
+	DATASET_PATCH_ADDR,
+	APP_LOAD_ADDR,
+	APP_START_OVERRIDE_ADDR,
+};
+
+#define ATH6KL_DATA_OFFSET    64
+struct sk_buff *ath6kl_buf_alloc(int size)
+{
+	struct sk_buff *skb;
+	u16 reserved;
+
+	/* Add chacheline space at front and back of buffer */
+	reserved = (2 * L1_CACHE_BYTES) + ATH6KL_DATA_OFFSET +
+		   sizeof(struct htc_packet);
+	skb = dev_alloc_skb(size + reserved);
+
+	if (skb)
+		skb_reserve(skb, reserved - L1_CACHE_BYTES);
+	return skb;
+}
+
+void ath6kl_init_profile_info(struct ath6kl *ar)
+{
+	ar->ssid_len = 0;
+	memset(ar->ssid, 0, sizeof(ar->ssid));
+
+	ar->dot11_auth_mode = OPEN_AUTH;
+	ar->auth_mode = NONE_AUTH;
+	ar->prwise_crypto = NONE_CRYPT;
+	ar->prwise_crypto_len = 0;
+	ar->grp_crypto = NONE_CRYPT;
+	ar->grp_crpto_len = 0;
+	memset(ar->wep_key_list, 0, sizeof(ar->wep_key_list));
+	memset(ar->req_bssid, 0, sizeof(ar->req_bssid));
+	memset(ar->bssid, 0, sizeof(ar->bssid));
+	ar->bss_ch = 0;
+	ar->nw_type = ar->next_mode = INFRA_NETWORK;
+}
+
+static u8 ath6kl_get_fw_iftype(struct ath6kl *ar)
+{
+	switch (ar->nw_type) {
+	case INFRA_NETWORK:
+		return HI_OPTION_FW_MODE_BSS_STA;
+	case ADHOC_NETWORK:
+		return HI_OPTION_FW_MODE_IBSS;
+	case AP_NETWORK:
+		return HI_OPTION_FW_MODE_AP;
+	default:
+		ath6kl_err("Unsupported interface type :%d\n", ar->nw_type);
+		return 0xff;
+	}
+}
+
+static inline u32 ath6kl_get_hi_item_addr(struct ath6kl *ar,
+					  u32 item_offset)
+{
+	u32 addr = 0;
+
+	if (ar->target_type == TARGET_TYPE_AR6003)
+		addr = ATH6KL_HI_START_ADDR + item_offset;
+
+	return addr;
+}
+
+static int ath6kl_set_host_app_area(struct ath6kl *ar)
+{
+	u32 address, data;
+	struct host_app_area host_app_area;
+
+	/* Fetch the address of the host_app_area_s
+	 * instance in the host interest area */
+	address = ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_app_host_interest));
+	address = TARG_VTOP(address);
+
+	if (ath6kl_read_reg_diag(ar, &address, &data))
+		return -EIO;
+
+	address = TARG_VTOP(data);
+	host_app_area.wmi_protocol_ver = WMI_PROTOCOL_VERSION;
+	if (ath6kl_access_datadiag(ar, address,
+				(u8 *)&host_app_area,
+				sizeof(struct host_app_area), false))
+		return -EIO;
+
+	return 0;
+}
+
+static inline void set_ac2_ep_map(struct ath6kl *ar,
+				  u8 ac,
+				  enum htc_endpoint_id ep)
+{
+	ar->ac2ep_map[ac] = ep;
+	ar->ep2ac_map[ep] = ac;
+}
+
+/* connect to a service */
+static int ath6kl_connectservice(struct ath6kl *ar,
+				 struct htc_service_connect_req  *con_req,
+				 char *desc)
+{
+	int status;
+	struct htc_service_connect_resp response;
+
+	memset(&response, 0, sizeof(response));
+
+	status = ath6kl_htc_conn_service(ar->htc_target, con_req, &response);
+	if (status) {
+		ath6kl_err("failed to connect to %s service status:%d\n",
+			   desc, status);
+		return status;
+	}
+
+	switch (con_req->svc_id) {
+	case WMI_CONTROL_SVC:
+		if (test_bit(WMI_ENABLED, &ar->flag))
+			ath6kl_wmi_set_control_ep(ar->wmi, response.endpoint);
+		ar->ctrl_ep = response.endpoint;
+		break;
+	case WMI_DATA_BE_SVC:
+		set_ac2_ep_map(ar, WMM_AC_BE, response.endpoint);
+		break;
+	case WMI_DATA_BK_SVC:
+		set_ac2_ep_map(ar, WMM_AC_BK, response.endpoint);
+		break;
+	case WMI_DATA_VI_SVC:
+		set_ac2_ep_map(ar, WMM_AC_VI, response.endpoint);
+		break;
+	case WMI_DATA_VO_SVC:
+		set_ac2_ep_map(ar, WMM_AC_VO, response.endpoint);
+		break;
+	default:
+		ath6kl_err("service id is not mapped %d\n", con_req->svc_id);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ath6kl_init_service_ep(struct ath6kl *ar)
+{
+	struct htc_service_connect_req connect;
+
+	memset(&connect, 0, sizeof(connect));
+
+	/* these fields are the same for all service endpoints */
+	connect.ep_cb.rx = ath6kl_rx;
+	connect.ep_cb.rx_refill = ath6kl_rx_refill;
+	connect.ep_cb.tx_full = ath6kl_tx_queue_full;
+
+	/*
+	 * Set the max queue depth so that our ath6kl_tx_queue_full handler
+	 * gets called.
+	*/
+	connect.max_txq_depth = MAX_DEFAULT_SEND_QUEUE_DEPTH;
+	connect.ep_cb.rx_refill_thresh = ATH6KL_MAX_RX_BUFFERS / 4;
+	if (!connect.ep_cb.rx_refill_thresh)
+		connect.ep_cb.rx_refill_thresh++;
+
+	/* connect to control service */
+	connect.svc_id = WMI_CONTROL_SVC;
+	if (ath6kl_connectservice(ar, &connect, "WMI CONTROL"))
+		return -EIO;
+
+	connect.flags |= HTC_FLGS_TX_BNDL_PAD_EN;
+
+	/*
+	 * Limit the HTC message size on the send path, although e can
+	 * receive A-MSDU frames of 4K, we will only send ethernet-sized
+	 * (802.3) frames on the send path.
+	 */
+	connect.max_rxmsg_sz = WMI_MAX_TX_DATA_FRAME_LENGTH;
+
+	/*
+	 * To reduce the amount of committed memory for larger A_MSDU
+	 * frames, use the recv-alloc threshold mechanism for larger
+	 * packets.
+	 */
+	connect.ep_cb.rx_alloc_thresh = ATH6KL_BUFFER_SIZE;
+	connect.ep_cb.rx_allocthresh = ath6kl_alloc_amsdu_rxbuf;
+
+	/*
+	 * For the remaining data services set the connection flag to
+	 * reduce dribbling, if configured to do so.
+	 */
+	connect.conn_flags |= HTC_CONN_FLGS_REDUCE_CRED_DRIB;
+	connect.conn_flags &= ~HTC_CONN_FLGS_THRESH_MASK;
+	connect.conn_flags |= HTC_CONN_FLGS_THRESH_LVL_HALF;
+
+	connect.svc_id = WMI_DATA_BE_SVC;
+
+	if (ath6kl_connectservice(ar, &connect, "WMI DATA BE"))
+		return -EIO;
+
+	/* connect to back-ground map this to WMI LOW_PRI */
+	connect.svc_id = WMI_DATA_BK_SVC;
+	if (ath6kl_connectservice(ar, &connect, "WMI DATA BK"))
+		return -EIO;
+
+	/* connect to Video service, map this to to HI PRI */
+	connect.svc_id = WMI_DATA_VI_SVC;
+	if (ath6kl_connectservice(ar, &connect, "WMI DATA VI"))
+		return -EIO;
+
+	/*
+	 * Connect to VO service, this is currently not mapped to a WMI
+	 * priority stream due to historical reasons. WMI originally
+	 * defined 3 priorities over 3 mailboxes We can change this when
+	 * WMI is reworked so that priorities are not dependent on
+	 * mailboxes.
+	 */
+	connect.svc_id = WMI_DATA_VO_SVC;
+	if (ath6kl_connectservice(ar, &connect, "WMI DATA VO"))
+		return -EIO;
+
+	return 0;
+}
+
+static void ath6kl_init_control_info(struct ath6kl *ar)
+{
+	u8 ctr;
+
+	clear_bit(WMI_ENABLED, &ar->flag);
+	ath6kl_init_profile_info(ar);
+	ar->def_txkey_index = 0;
+	memset(ar->wep_key_list, 0, sizeof(ar->wep_key_list));
+	ar->ch_hint = 0;
+	ar->listen_intvl_t = A_DEFAULT_LISTEN_INTERVAL;
+	ar->listen_intvl_b = 0;
+	ar->tx_pwr = 0;
+	clear_bit(SKIP_SCAN, &ar->flag);
+	set_bit(WMM_ENABLED, &ar->flag);
+	ar->intra_bss = 1;
+	memset(&ar->sc_params, 0, sizeof(ar->sc_params));
+	ar->sc_params.short_scan_ratio = WMI_SHORTSCANRATIO_DEFAULT;
+	ar->sc_params.scan_ctrl_flags = DEFAULT_SCAN_CTRL_FLAGS;
+
+	memset((u8 *)ar->sta_list, 0,
+	       AP_MAX_NUM_STA * sizeof(struct ath6kl_sta));
+
+	spin_lock_init(&ar->mcastpsq_lock);
+
+	/* Init the PS queues */
+	for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) {
+		spin_lock_init(&ar->sta_list[ctr].psq_lock);
+		skb_queue_head_init(&ar->sta_list[ctr].psq);
+	}
+
+	skb_queue_head_init(&ar->mcastpsq);
+
+	memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3);
+}
+
+/*
+ * Set HTC/Mbox operational parameters, this can only be called when the
+ * target is in the BMI phase.
+ */
+static int ath6kl_set_htc_params(struct ath6kl *ar, u32 mbox_isr_yield_val,
+				 u8 htc_ctrl_buf)
+{
+	int status;
+	u32 blk_size;
+
+	blk_size = ar->mbox_info.block_size;
+
+	if (htc_ctrl_buf)
+		blk_size |=  ((u32)htc_ctrl_buf) << 16;
+
+	/* set the host interest area for the block size */
+	status = ath6kl_bmi_write(ar,
+			ath6kl_get_hi_item_addr(ar,
+			HI_ITEM(hi_mbox_io_block_sz)),
+			(u8 *)&blk_size,
+			4);
+	if (status) {
+		ath6kl_err("bmi_write_memory for IO block size failed\n");
+		goto out;
+	}
+
+	ath6kl_dbg(ATH6KL_DBG_TRC, "block size set: %d (target addr:0x%X)\n",
+		   blk_size,
+		   ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_mbox_io_block_sz)));
+
+	if (mbox_isr_yield_val) {
+		/* set the host interest area for the mbox ISR yield limit */
+		status = ath6kl_bmi_write(ar,
+				ath6kl_get_hi_item_addr(ar,
+				HI_ITEM(hi_mbox_isr_yield_limit)),
+				(u8 *)&mbox_isr_yield_val,
+				4);
+		if (status) {
+			ath6kl_err("bmi_write_memory for yield limit failed\n");
+			goto out;
+		}
+	}
+
+out:
+	return status;
+}
+
+#define REG_DUMP_COUNT_AR6003   60
+#define REGISTER_DUMP_LEN_MAX   60
+
+static void ath6kl_dump_target_assert_info(struct ath6kl *ar)
+{
+	u32 address;
+	u32 regdump_loc = 0;
+	int status;
+	u32 regdump_val[REGISTER_DUMP_LEN_MAX];
+	u32 i;
+
+	if (ar->target_type != TARGET_TYPE_AR6003)
+		return;
+
+	/* the reg dump pointer is copied to the host interest area */
+	address = ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_failure_state));
+	address = TARG_VTOP(address);
+
+	/* read RAM location through diagnostic window */
+	status = ath6kl_read_reg_diag(ar, &address, &regdump_loc);
+
+	if (status || !regdump_loc) {
+		ath6kl_err("failed to get ptr to register dump area\n");
+		return;
+	}
+
+	ath6kl_dbg(ATH6KL_DBG_TRC, "location of register dump data: 0x%X\n",
+		regdump_loc);
+
+	regdump_loc = TARG_VTOP(regdump_loc);
+
+	/* fetch register dump data */
+	status = ath6kl_access_datadiag(ar,
+					regdump_loc,
+					(u8 *)&regdump_val[0],
+					REG_DUMP_COUNT_AR6003 * (sizeof(u32)),
+					true);
+
+	if (status) {
+		ath6kl_err("failed to get register dump\n");
+		return;
+	}
+	ath6kl_dbg(ATH6KL_DBG_TRC, "Register Dump:\n");
+
+	for (i = 0; i < REG_DUMP_COUNT_AR6003; i++)
+		ath6kl_dbg(ATH6KL_DBG_TRC, " %d :  0x%8.8X\n",
+			   i, regdump_val[i]);
+
+}
+
+void ath6kl_target_failure(struct ath6kl *ar)
+{
+	ath6kl_err("target asserted\n");
+
+	/* try dumping target assertion information (if any) */
+	ath6kl_dump_target_assert_info(ar);
+
+}
+
+static int ath6kl_target_config_wlan_params(struct ath6kl *ar)
+{
+	int status = 0;
+
+	/*
+	 * Configure the device for rx dot11 header rules. "0,0" are the
+	 * default values. Required if checksum offload is needed. Set
+	 * RxMetaVersion to 2.
+	 */
+	if (ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi,
+					       ar->rx_meta_ver, 0, 0)) {
+		ath6kl_err("unable to set the rx frame format\n");
+		status = -EIO;
+	}
+
+	if (ar->conf_flags & ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN)
+		if ((ath6kl_wmi_pmparams_cmd(ar->wmi, 0, 1, 0, 0, 1,
+		     IGNORE_POWER_SAVE_FAIL_EVENT_DURING_SCAN)) != 0) {
+			ath6kl_err("unable to set power save fail event policy\n");
+			status = -EIO;
+		}
+
+	if (!(ar->conf_flags & ATH6KL_CONF_IGNORE_ERP_BARKER))
+		if ((ath6kl_wmi_set_lpreamble_cmd(ar->wmi, 0,
+		     WMI_DONOT_IGNORE_BARKER_IN_ERP)) != 0) {
+			ath6kl_err("unable to set barker preamble policy\n");
+			status = -EIO;
+		}
+
+	if (ath6kl_wmi_set_keepalive_cmd(ar->wmi,
+			WLAN_CONFIG_KEEP_ALIVE_INTERVAL)) {
+		ath6kl_err("unable to set keep alive interval\n");
+		status = -EIO;
+	}
+
+	if (ath6kl_wmi_disctimeout_cmd(ar->wmi,
+			WLAN_CONFIG_DISCONNECT_TIMEOUT)) {
+		ath6kl_err("unable to set disconnect timeout\n");
+		status = -EIO;
+	}
+
+	if (!(ar->conf_flags & ATH6KL_CONF_ENABLE_TX_BURST))
+		if (ath6kl_wmi_set_wmm_txop(ar->wmi, WMI_TXOP_DISABLED)) {
+			ath6kl_err("unable to set txop bursting\n");
+			status = -EIO;
+		}
+
+	return status;
+}
+
+int ath6kl_configure_target(struct ath6kl *ar)
+{
+	u32 param, ram_reserved_size;
+	u8 fw_iftype;
+
+	fw_iftype = ath6kl_get_fw_iftype(ar);
+	if (fw_iftype == 0xff)
+		return -EINVAL;
+
+	/* Tell target which HTC version it is used*/
+	param = HTC_PROTOCOL_VERSION;
+	if (ath6kl_bmi_write(ar,
+			     ath6kl_get_hi_item_addr(ar,
+			     HI_ITEM(hi_app_host_interest)),
+			     (u8 *)&param, 4) != 0) {
+		ath6kl_err("bmi_write_memory for htc version failed\n");
+		return -EIO;
+	}
+
+	/* set the firmware mode to STA/IBSS/AP */
+	param = 0;
+
+	if (ath6kl_bmi_read(ar,
+			    ath6kl_get_hi_item_addr(ar,
+			    HI_ITEM(hi_option_flag)),
+			    (u8 *)&param, 4) != 0) {
+		ath6kl_err("bmi_read_memory for setting fwmode failed\n");
+		return -EIO;
+	}
+
+	param |= (1 << HI_OPTION_NUM_DEV_SHIFT);
+	param |= (fw_iftype << HI_OPTION_FW_MODE_SHIFT);
+	param |= (0 << HI_OPTION_MAC_ADDR_METHOD_SHIFT);
+	param |= (0 << HI_OPTION_FW_BRIDGE_SHIFT);
+
+	if (ath6kl_bmi_write(ar,
+			     ath6kl_get_hi_item_addr(ar,
+			     HI_ITEM(hi_option_flag)),
+			     (u8 *)&param,
+			     4) != 0) {
+		ath6kl_err("bmi_write_memory for setting fwmode failed\n");
+		return -EIO;
+	}
+
+	ath6kl_dbg(ATH6KL_DBG_TRC, "firmware mode set\n");
+
+	/*
+	 * Hardcode the address use for the extended board data
+	 * Ideally this should be pre-allocate by the OS at boot time
+	 * But since it is a new feature and board data is loaded
+	 * at init time, we have to workaround this from host.
+	 * It is difficult to patch the firmware boot code,
+	 * but possible in theory.
+	 */
+
+	if (ar->target_type == TARGET_TYPE_AR6003) {
+		if (ar->version.target_ver == AR6003_REV2_VERSION) {
+			param = AR6003_REV2_BOARD_EXT_DATA_ADDRESS;
+			ram_reserved_size =  AR6003_REV2_RAM_RESERVE_SIZE;
+		} else {
+			param = AR6003_REV3_BOARD_EXT_DATA_ADDRESS;
+			ram_reserved_size =  AR6003_REV3_RAM_RESERVE_SIZE;
+		}
+
+		if (ath6kl_bmi_write(ar,
+				     ath6kl_get_hi_item_addr(ar,
+				     HI_ITEM(hi_board_ext_data)),
+				     (u8 *)&param, 4) != 0) {
+			ath6kl_err("bmi_write_memory for hi_board_ext_data failed\n");
+			return -EIO;
+		}
+		if (ath6kl_bmi_write(ar,
+				     ath6kl_get_hi_item_addr(ar,
+				     HI_ITEM(hi_end_ram_reserve_sz)),
+				     (u8 *)&ram_reserved_size, 4) != 0) {
+			ath6kl_err("bmi_write_memory for hi_end_ram_reserve_sz failed\n");
+			return -EIO;
+		}
+	}
+
+	/* set the block size for the target */
+	if (ath6kl_set_htc_params(ar, MBOX_YIELD_LIMIT, 0))
+		/* use default number of control buffers */
+		return -EIO;
+
+	return 0;
+}
+
+struct ath6kl *ath6kl_core_alloc(struct device *sdev)
+{
+	struct net_device *dev;
+	struct ath6kl *ar;
+	struct wireless_dev *wdev;
+
+	wdev = ath6kl_cfg80211_init(sdev);
+	if (!wdev) {
+		ath6kl_err("ath6kl_cfg80211_init failed\n");
+		return NULL;
+	}
+
+	ar = wdev_priv(wdev);
+	ar->dev = sdev;
+	ar->wdev = wdev;
+	wdev->iftype = NL80211_IFTYPE_STATION;
+
+	dev = alloc_netdev(0, "wlan%d", ether_setup);
+	if (!dev) {
+		ath6kl_err("no memory for network device instance\n");
+		ath6kl_cfg80211_deinit(ar);
+		return NULL;
+	}
+
+	dev->ieee80211_ptr = wdev;
+	SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy));
+	wdev->netdev = dev;
+	ar->sme_state = SME_DISCONNECTED;
+	ar->auto_auth_stage = AUTH_IDLE;
+
+	init_netdev(dev);
+
+	ar->net_dev = dev;
+	set_bit(WLAN_ENABLED, &ar->flag);
+
+	ar->wlan_pwr_state = WLAN_POWER_STATE_ON;
+
+	spin_lock_init(&ar->lock);
+
+	ath6kl_init_control_info(ar);
+	init_waitqueue_head(&ar->event_wq);
+	sema_init(&ar->sem, 1);
+	clear_bit(DESTROY_IN_PROGRESS, &ar->flag);
+
+	INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue);
+
+	setup_timer(&ar->disconnect_timer, disconnect_timer_handler,
+		    (unsigned long) dev);
+
+	return ar;
+}
+
+int ath6kl_unavail_ev(struct ath6kl *ar)
+{
+	ath6kl_destroy(ar->net_dev, 1);
+
+	return 0;
+}
+
+/* firmware upload */
+static u32 ath6kl_get_load_address(u32 target_ver, enum addr_type type)
+{
+	WARN_ON(target_ver != AR6003_REV2_VERSION &&
+		target_ver != AR6003_REV3_VERSION);
+
+	switch (type) {
+	case DATASET_PATCH_ADDR:
+		return (target_ver == AR6003_REV2_VERSION) ?
+			AR6003_REV2_DATASET_PATCH_ADDRESS :
+			AR6003_REV3_DATASET_PATCH_ADDRESS;
+	case APP_LOAD_ADDR:
+		return (target_ver == AR6003_REV2_VERSION) ?
+			AR6003_REV2_APP_LOAD_ADDRESS :
+			0x1234;
+	case APP_START_OVERRIDE_ADDR:
+		return (target_ver == AR6003_REV2_VERSION) ?
+			AR6003_REV2_APP_START_OVERRIDE :
+			AR6003_REV3_APP_START_OVERRIDE;
+	default:
+		return 0;
+	}
+}
+
+static int ath6kl_get_fw(struct ath6kl *ar, const char *filename,
+			 u8 **fw, size_t *fw_len)
+{
+	const struct firmware *fw_entry;
+	int ret;
+
+	ret = request_firmware(&fw_entry, filename, ar->dev);
+	if (ret)
+		return ret;
+
+	*fw_len = fw_entry->size;
+	*fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL);
+
+	if (*fw == NULL)
+		ret = -ENOMEM;
+
+	release_firmware(fw_entry);
+
+	return ret;
+}
+
+static int ath6kl_fetch_board_file(struct ath6kl *ar)
+{
+	const char *filename;
+	int ret;
+
+	switch (ar->version.target_ver) {
+	case AR6003_REV2_VERSION:
+		filename = AR6003_REV2_BOARD_DATA_FILE;
+		break;
+	default:
+		filename = AR6003_REV3_BOARD_DATA_FILE;
+		break;
+	}
+
+	ret = ath6kl_get_fw(ar, filename, &ar->fw_board,
+			    &ar->fw_board_len);
+	if (ret == 0) {
+		/* managed to get proper board file */
+		return 0;
+	}
+
+	/* there was no proper board file, try to use default instead */
+	ath6kl_warn("Failed to get board file %s (%d), trying to find default board file.\n",
+		    filename, ret);
+
+	switch (ar->version.target_ver) {
+	case AR6003_REV2_VERSION:
+		filename = AR6003_REV2_DEFAULT_BOARD_DATA_FILE;
+		break;
+	default:
+		filename = AR6003_REV3_DEFAULT_BOARD_DATA_FILE;
+		break;
+	}
+
+	ret = ath6kl_get_fw(ar, filename, &ar->fw_board,
+			    &ar->fw_board_len);
+	if (ret) {
+		ath6kl_err("Failed to get default board file %s: %d\n",
+			   filename, ret);
+		return ret;
+	}
+
+	ath6kl_warn("WARNING! No proper board file was not found, instead using a default board file.\n");
+	ath6kl_warn("Most likely your hardware won't work as specified. Install correct board file!\n");
+
+	return 0;
+}
+
+
+static int ath6kl_upload_board_file(struct ath6kl *ar)
+{
+	u32 board_address, board_ext_address, param;
+	int ret;
+
+	if (ar->fw_board == NULL) {
+		ret = ath6kl_fetch_board_file(ar);
+		if (ret)
+			return ret;
+	}
+
+	/* Determine where in Target RAM to write Board Data */
+	ath6kl_bmi_read(ar,
+			ath6kl_get_hi_item_addr(ar,
+			HI_ITEM(hi_board_data)),
+			(u8 *) &board_address, 4);
+	ath6kl_dbg(ATH6KL_DBG_TRC, "board data download addr: 0x%x\n",
+		   board_address);
+
+	/* determine where in target ram to write extended board data */
+	ath6kl_bmi_read(ar,
+			ath6kl_get_hi_item_addr(ar,
+			HI_ITEM(hi_board_ext_data)),
+			(u8 *) &board_ext_address, 4);
+
+	ath6kl_dbg(ATH6KL_DBG_TRC, "board file download addr: 0x%x\n",
+		   board_ext_address);
+
+	if (board_ext_address == 0) {
+		ath6kl_err("Failed to get board file target address.\n");
+		return -EINVAL;
+	}
+
+	if (ar->fw_board_len == (AR6003_BOARD_DATA_SZ +
+				 AR6003_BOARD_EXT_DATA_SZ)) {
+		/* write extended board data */
+		ret = ath6kl_bmi_write(ar, board_ext_address,
+				       ar->fw_board + AR6003_BOARD_DATA_SZ,
+				       AR6003_BOARD_EXT_DATA_SZ);
+
+		if (ret) {
+			ath6kl_err("Failed to write extended board data: %d\n",
+				   ret);
+			return ret;
+		}
+
+		/* record that extended board data is initialized */
+		param = (AR6003_BOARD_EXT_DATA_SZ << 16) | 1;
+		ath6kl_bmi_write(ar,
+				 ath6kl_get_hi_item_addr(ar,
+				 HI_ITEM(hi_board_ext_data_config)),
+				 (unsigned char *) &param, 4);
+	}
+
+	if (ar->fw_board_len < AR6003_BOARD_DATA_SZ) {
+		ath6kl_err("Too small board file: %zu\n", ar->fw_board_len);
+		ret = -EINVAL;
+		return ret;
+	}
+
+	ret = ath6kl_bmi_write(ar, board_address, ar->fw_board,
+			       AR6003_BOARD_DATA_SZ);
+
+	if (ret) {
+		ath6kl_err("Board file bmi write failed: %d\n", ret);
+		return ret;
+	}
+
+	/* record the fact that Board Data IS initialized */
+	param = 1;
+	ath6kl_bmi_write(ar,
+			 ath6kl_get_hi_item_addr(ar,
+			 HI_ITEM(hi_board_data_initialized)),
+			 (u8 *)&param, 4);
+
+	return ret;
+}
+
+static int ath6kl_upload_otp(struct ath6kl *ar)
+{
+	const char *filename;
+	u32 address, param;
+	int ret;
+
+	switch (ar->version.target_ver) {
+	case AR6003_REV2_VERSION:
+		filename = AR6003_REV2_OTP_FILE;
+		break;
+	default:
+		filename = AR6003_REV3_OTP_FILE;
+		break;
+	}
+
+	if (ar->fw_otp == NULL) {
+		ret = ath6kl_get_fw(ar, filename, &ar->fw_otp,
+				    &ar->fw_otp_len);
+		if (ret) {
+			ath6kl_err("Failed to get OTP file %s: %d\n",
+				   filename, ret);
+			return ret;
+		}
+	}
+
+	address = ath6kl_get_load_address(ar->version.target_ver,
+					  APP_LOAD_ADDR);
+
+	ret = ath6kl_bmi_fast_download(ar, address, ar->fw_otp,
+				       ar->fw_otp_len);
+	if (ret) {
+		ath6kl_err("Failed to upload OTP file: %d\n", ret);
+		return ret;
+	}
+
+	/* execute the OTP code */
+	param = 0;
+	address = ath6kl_get_load_address(ar->version.target_ver,
+					  APP_START_OVERRIDE_ADDR);
+	ath6kl_bmi_execute(ar, address, &param);
+
+	return ret;
+}
+
+static int ath6kl_upload_firmware(struct ath6kl *ar)
+{
+	const char *filename;
+	u32 address;
+	int ret;
+
+	switch (ar->version.target_ver) {
+	case AR6003_REV2_VERSION:
+		filename = AR6003_REV2_FIRMWARE_FILE;
+		break;
+	default:
+		filename = AR6003_REV3_FIRMWARE_FILE;
+		break;
+	}
+
+	if (ar->fw == NULL) {
+		ret = ath6kl_get_fw(ar, filename, &ar->fw, &ar->fw_len);
+		if (ret) {
+			ath6kl_err("Failed to get firmware file %s: %d\n",
+				   filename, ret);
+			return ret;
+		}
+	}
+
+	address = ath6kl_get_load_address(ar->version.target_ver,
+					  APP_LOAD_ADDR);
+
+	ret = ath6kl_bmi_fast_download(ar, address, ar->fw, ar->fw_len);
+
+	if (ret) {
+		ath6kl_err("Failed to write firmware: %d\n", ret);
+		return ret;
+	}
+
+	/* Set starting address for firmware */
+	address = ath6kl_get_load_address(ar->version.target_ver,
+					  APP_START_OVERRIDE_ADDR);
+	ath6kl_bmi_set_app_start(ar, address);
+
+	return ret;
+}
+
+static int ath6kl_upload_patch(struct ath6kl *ar)
+{
+	const char *filename;
+	u32 address, param;
+	int ret;
+
+	switch (ar->version.target_ver) {
+	case AR6003_REV2_VERSION:
+		filename = AR6003_REV2_PATCH_FILE;
+		break;
+	default:
+		filename = AR6003_REV3_PATCH_FILE;
+		break;
+	}
+
+	if (ar->fw_patch == NULL) {
+		ret = ath6kl_get_fw(ar, filename, &ar->fw_patch,
+				    &ar->fw_patch_len);
+		if (ret) {
+			ath6kl_err("Failed to get patch file %s: %d\n",
+				   filename, ret);
+			return ret;
+		}
+	}
+
+	address = ath6kl_get_load_address(ar->version.target_ver,
+					  DATASET_PATCH_ADDR);
+
+	ret = ath6kl_bmi_write(ar, address, ar->fw_patch, ar->fw_patch_len);
+	if (ret) {
+		ath6kl_err("Failed to write patch file: %d\n", ret);
+		return ret;
+	}
+
+	param = address;
+	ath6kl_bmi_write(ar,
+			 ath6kl_get_hi_item_addr(ar,
+			 HI_ITEM(hi_dset_list_head)),
+			 (unsigned char *) &param, 4);
+
+	return 0;
+}
+
+static int ath6kl_init_upload(struct ath6kl *ar)
+{
+	u32 param, options, sleep, address;
+	int status = 0;
+
+	if (ar->target_type != TARGET_TYPE_AR6003)
+		return -EINVAL;
+
+	/* temporarily disable system sleep */
+	address = MBOX_BASE_ADDRESS + LOCAL_SCRATCH_ADDRESS;
+	status = ath6kl_bmi_reg_read(ar, address, &param);
+	if (status)
+		return status;
+
+	options = param;
+
+	param |= ATH6KL_OPTION_SLEEP_DISABLE;
+	status = ath6kl_bmi_reg_write(ar, address, param);
+	if (status)
+		return status;
+
+	address = RTC_BASE_ADDRESS + SYSTEM_SLEEP_ADDRESS;
+	status = ath6kl_bmi_reg_read(ar, address, &param);
+	if (status)
+		return status;
+
+	sleep = param;
+
+	param |= SM(SYSTEM_SLEEP_DISABLE, 1);
+	status = ath6kl_bmi_reg_write(ar, address, param);
+	if (status)
+		return status;
+
+	ath6kl_dbg(ATH6KL_DBG_TRC, "old options: %d, old sleep: %d\n",
+		   options, sleep);
+
+	/* program analog PLL register */
+	status = ath6kl_bmi_reg_write(ar, ATH6KL_ANALOG_PLL_REGISTER,
+				      0xF9104001);
+	if (status)
+		return status;
+
+	/* Run at 80/88MHz by default */
+	param = SM(CPU_CLOCK_STANDARD, 1);
+
+	address = RTC_BASE_ADDRESS + CPU_CLOCK_ADDRESS;
+	status = ath6kl_bmi_reg_write(ar, address, param);
+	if (status)
+		return status;
+
+	param = 0;
+	address = RTC_BASE_ADDRESS + LPO_CAL_ADDRESS;
+	param = SM(LPO_CAL_ENABLE, 1);
+	status = ath6kl_bmi_reg_write(ar, address, param);
+	if (status)
+		return status;
+
+	/* WAR to avoid SDIO CRC err */
+	if (ar->version.target_ver == AR6003_REV2_VERSION) {
+		ath6kl_err("temporary war to avoid sdio crc error\n");
+
+		param = 0x20;
+
+		address = GPIO_BASE_ADDRESS + GPIO_PIN10_ADDRESS;
+		status = ath6kl_bmi_reg_write(ar, address, param);
+		if (status)
+			return status;
+
+		address = GPIO_BASE_ADDRESS + GPIO_PIN11_ADDRESS;
+		status = ath6kl_bmi_reg_write(ar, address, param);
+		if (status)
+			return status;
+
+		address = GPIO_BASE_ADDRESS + GPIO_PIN12_ADDRESS;
+		status = ath6kl_bmi_reg_write(ar, address, param);
+		if (status)
+			return status;
+
+		address = GPIO_BASE_ADDRESS + GPIO_PIN13_ADDRESS;
+		status = ath6kl_bmi_reg_write(ar, address, param);
+		if (status)
+			return status;
+	}
+
+	/* write EEPROM data to Target RAM */
+	status = ath6kl_upload_board_file(ar);
+	if (status)
+		return status;
+
+	/* transfer One time Programmable data */
+	status = ath6kl_upload_otp(ar);
+	if (status)
+		return status;
+
+	/* Download Target firmware */
+	status = ath6kl_upload_firmware(ar);
+	if (status)
+		return status;
+
+	status = ath6kl_upload_patch(ar);
+	if (status)
+		return status;
+
+	/* Restore system sleep */
+	address = RTC_BASE_ADDRESS + SYSTEM_SLEEP_ADDRESS;
+	status = ath6kl_bmi_reg_write(ar, address, sleep);
+	if (status)
+		return status;
+
+	address = MBOX_BASE_ADDRESS + LOCAL_SCRATCH_ADDRESS;
+	param = options | 0x20;
+	status = ath6kl_bmi_reg_write(ar, address, param);
+	if (status)
+		return status;
+
+	/* Configure GPIO AR6003 UART */
+	param = CONFIG_AR600x_DEBUG_UART_TX_PIN;
+	status = ath6kl_bmi_write(ar,
+				  ath6kl_get_hi_item_addr(ar,
+				  HI_ITEM(hi_dbg_uart_txpin)),
+				  (u8 *)&param, 4);
+
+	return status;
+}
+
+static int ath6kl_init(struct net_device *dev)
+{
+	struct ath6kl *ar = ath6kl_priv(dev);
+	int status = 0;
+	s32 timeleft;
+
+	if (!ar)
+		return -EIO;
+
+	/* Do we need to finish the BMI phase */
+	if (ath6kl_bmi_done(ar)) {
+		status = -EIO;
+		goto ath6kl_init_done;
+	}
+
+	/* Indicate that WMI is enabled (although not ready yet) */
+	set_bit(WMI_ENABLED, &ar->flag);
+	ar->wmi = ath6kl_wmi_init(ar);
+	if (!ar->wmi) {
+		ath6kl_err("failed to initialize wmi\n");
+		status = -EIO;
+		goto ath6kl_init_done;
+	}
+
+	ath6kl_dbg(ATH6KL_DBG_TRC, "%s: got wmi @ 0x%p.\n", __func__, ar->wmi);
+
+	wlan_node_table_init(&ar->scan_table);
+
+	/*
+	 * The reason we have to wait for the target here is that the
+	 * driver layer has to init BMI in order to set the host block
+	 * size.
+	 */
+	if (ath6kl_htc_wait_target(ar->htc_target)) {
+		status = -EIO;
+		goto err_node_cleanup;
+	}
+
+	if (ath6kl_init_service_ep(ar)) {
+		status = -EIO;
+		goto err_cleanup_scatter;
+	}
+
+	/* setup access class priority mappings */
+	ar->ac_stream_pri_map[WMM_AC_BK] = 0; /* lowest  */
+	ar->ac_stream_pri_map[WMM_AC_BE] = 1;
+	ar->ac_stream_pri_map[WMM_AC_VI] = 2;
+	ar->ac_stream_pri_map[WMM_AC_VO] = 3; /* highest */
+
+	/* give our connected endpoints some buffers */
+	ath6kl_rx_refill(ar->htc_target, ar->ctrl_ep);
+	ath6kl_rx_refill(ar->htc_target, ar->ac2ep_map[WMM_AC_BE]);
+
+	/* allocate some buffers that handle larger AMSDU frames */
+	ath6kl_refill_amsdu_rxbufs(ar, ATH6KL_MAX_AMSDU_RX_BUFFERS);
+
+	/* setup credit distribution */
+	ath6k_setup_credit_dist(ar->htc_target, &ar->credit_state_info);
+
+	ath6kl_cookie_init(ar);
+
+	/* start HTC */
+	status = ath6kl_htc_start(ar->htc_target);
+
+	if (status) {
+		ath6kl_cookie_cleanup(ar);
+		goto err_rxbuf_cleanup;
+	}
+
+	/* Wait for Wmi event to be ready */
+	timeleft = wait_event_interruptible_timeout(ar->event_wq,
+						    test_bit(WMI_READY,
+							     &ar->flag),
+						    WMI_TIMEOUT);
+
+	if (ar->version.abi_ver != ATH6KL_ABI_VERSION) {
+		ath6kl_err("abi version mismatch: host(0x%x), target(0x%x)\n",
+			   ATH6KL_ABI_VERSION, ar->version.abi_ver);
+		status = -EIO;
+		goto err_htc_stop;
+	}
+
+	if (!timeleft || signal_pending(current)) {
+		ath6kl_err("wmi is not ready or wait was interrupted\n");
+		status = -EIO;
+		goto err_htc_stop;
+	}
+
+	ath6kl_dbg(ATH6KL_DBG_TRC, "%s: wmi is ready\n", __func__);
+
+	/* communicate the wmi protocol verision to the target */
+	if ((ath6kl_set_host_app_area(ar)) != 0)
+		ath6kl_err("unable to set the host app area\n");
+
+	ar->conf_flags = ATH6KL_CONF_IGNORE_ERP_BARKER |
+			 ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST;
+
+	status = ath6kl_target_config_wlan_params(ar);
+	if (!status)
+		goto ath6kl_init_done;
+
+err_htc_stop:
+	ath6kl_htc_stop(ar->htc_target);
+err_rxbuf_cleanup:
+	ath6kl_htc_flush_rx_buf(ar->htc_target);
+	ath6kl_cleanup_amsdu_rxbufs(ar);
+err_cleanup_scatter:
+	ath6kl_hif_cleanup_scatter(ar);
+err_node_cleanup:
+	wlan_node_table_cleanup(&ar->scan_table);
+	ath6kl_wmi_shutdown(ar->wmi);
+	clear_bit(WMI_ENABLED, &ar->flag);
+	ar->wmi = NULL;
+
+ath6kl_init_done:
+	return status;
+}
+
+int ath6kl_core_init(struct ath6kl *ar)
+{
+	int ret = 0;
+	struct ath6kl_bmi_target_info targ_info;
+
+	ar->ath6kl_wq = create_singlethread_workqueue("ath6kl");
+	if (!ar->ath6kl_wq)
+		return -ENOMEM;
+
+	ret = ath6kl_bmi_init(ar);
+	if (ret)
+		goto err_wq;
+
+	ret = ath6kl_bmi_get_target_info(ar, &targ_info);
+	if (ret)
+		goto err_bmi_cleanup;
+
+	ar->version.target_ver = le32_to_cpu(targ_info.version);
+	ar->target_type = le32_to_cpu(targ_info.type);
+	ar->wdev->wiphy->hw_version = le32_to_cpu(targ_info.version);
+
+	ret = ath6kl_configure_target(ar);
+	if (ret)
+		goto err_bmi_cleanup;
+
+	ar->htc_target = ath6kl_htc_create(ar);
+
+	if (!ar->htc_target) {
+		ret = -ENOMEM;
+		goto err_bmi_cleanup;
+	}
+
+	ar->aggr_cntxt = aggr_init(ar->net_dev);
+	if (!ar->aggr_cntxt) {
+		ath6kl_err("failed to initialize aggr\n");
+		ret = -ENOMEM;
+		goto err_htc_cleanup;
+	}
+
+	ret = ath6kl_init_upload(ar);
+	if (ret)
+		goto err_htc_cleanup;
+
+	ret = ath6kl_init(ar->net_dev);
+	if (ret)
+		goto err_htc_cleanup;
+
+	/* This runs the init function if registered */
+	ret = register_netdev(ar->net_dev);
+	if (ret) {
+		ath6kl_err("register_netdev failed\n");
+		ath6kl_destroy(ar->net_dev, 0);
+		return ret;
+	}
+
+	set_bit(NETDEV_REGISTERED, &ar->flag);
+
+	ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n",
+			__func__, ar->net_dev->name, ar->net_dev, ar);
+
+	return ret;
+
+err_htc_cleanup:
+	ath6kl_htc_cleanup(ar->htc_target);
+err_bmi_cleanup:
+	ath6kl_bmi_cleanup(ar);
+err_wq:
+	destroy_workqueue(ar->ath6kl_wq);
+	return ret;
+}
+
+void ath6kl_stop_txrx(struct ath6kl *ar)
+{
+	struct net_device *ndev = ar->net_dev;
+
+	if (!ndev)
+		return;
+
+	set_bit(DESTROY_IN_PROGRESS, &ar->flag);
+
+	if (down_interruptible(&ar->sem)) {
+		ath6kl_err("down_interruptible failed\n");
+		return;
+	}
+
+	if (ar->wlan_pwr_state != WLAN_POWER_STATE_CUT_PWR)
+		ath6kl_stop_endpoint(ndev, false, true);
+
+	clear_bit(WLAN_ENABLED, &ar->flag);
+}
+
+/*
+ * We need to differentiate between the surprise and planned removal of the
+ * device because of the following consideration:
+ *
+ * - In case of surprise removal, the hcd already frees up the pending
+ *   for the device and hence there is no need to unregister the function
+ *   driver inorder to get these requests. For planned removal, the function
+ *   driver has to explicitly unregister itself to have the hcd return all the
+ *   pending requests before the data structures for the devices are freed up.
+ *   Note that as per the current implementation, the function driver will
+ *   end up releasing all the devices since there is no API to selectively
+ *   release a particular device.
+ *
+ * - Certain commands issued to the target can be skipped for surprise
+ *   removal since they will anyway not go through.
+ */
+void ath6kl_destroy(struct net_device *dev, unsigned int unregister)
+{
+	struct ath6kl *ar;
+
+	if (!dev || !ath6kl_priv(dev)) {
+		ath6kl_err("failed to get device structure\n");
+		return;
+	}
+
+	ar = ath6kl_priv(dev);
+
+	destroy_workqueue(ar->ath6kl_wq);
+
+	if (ar->htc_target)
+		ath6kl_htc_cleanup(ar->htc_target);
+
+	aggr_module_destroy(ar->aggr_cntxt);
+
+	ath6kl_cookie_cleanup(ar);
+
+	ath6kl_cleanup_amsdu_rxbufs(ar);
+
+	ath6kl_bmi_cleanup(ar);
+
+	if (unregister && test_bit(NETDEV_REGISTERED, &ar->flag)) {
+		unregister_netdev(dev);
+		clear_bit(NETDEV_REGISTERED, &ar->flag);
+	}
+
+	free_netdev(dev);
+
+	wlan_node_table_cleanup(&ar->scan_table);
+
+	kfree(ar->fw_board);
+	kfree(ar->fw_otp);
+	kfree(ar->fw);
+	kfree(ar->fw_patch);
+
+	ath6kl_cfg80211_deinit(ar);
+}
diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c
new file mode 100644
index 000000000000..c336eae0cf48
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/main.c
@@ -0,0 +1,1337 @@
+/*
+ * Copyright (c) 2004-2011 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.
+ */
+
+#include "core.h"
+#include "hif-ops.h"
+#include "cfg80211.h"
+#include "target.h"
+#include "debug.h"
+
+struct ath6kl_sta *ath6kl_find_sta(struct ath6kl *ar, u8 *node_addr)
+{
+	struct ath6kl_sta *conn = NULL;
+	u8 i, max_conn;
+
+	max_conn = (ar->nw_type == AP_NETWORK) ? AP_MAX_NUM_STA : 0;
+
+	for (i = 0; i < max_conn; i++) {
+		if (memcmp(node_addr, ar->sta_list[i].mac, ETH_ALEN) == 0) {
+			conn = &ar->sta_list[i];
+			break;
+		}
+	}
+
+	return conn;
+}
+
+struct ath6kl_sta *ath6kl_find_sta_by_aid(struct ath6kl *ar, u8 aid)
+{
+	struct ath6kl_sta *conn = NULL;
+	u8 ctr;
+
+	for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) {
+		if (ar->sta_list[ctr].aid == aid) {
+			conn = &ar->sta_list[ctr];
+			break;
+		}
+	}
+	return conn;
+}
+
+static void ath6kl_add_new_sta(struct ath6kl *ar, u8 *mac, u16 aid, u8 *wpaie,
+			u8 ielen, u8 keymgmt, u8 ucipher, u8 auth)
+{
+	struct ath6kl_sta *sta;
+	u8 free_slot;
+
+	free_slot = aid - 1;
+
+	sta = &ar->sta_list[free_slot];
+	memcpy(sta->mac, mac, ETH_ALEN);
+	memcpy(sta->wpa_ie, wpaie, ielen);
+	sta->aid = aid;
+	sta->keymgmt = keymgmt;
+	sta->ucipher = ucipher;
+	sta->auth = auth;
+
+	ar->sta_list_index = ar->sta_list_index | (1 << free_slot);
+	ar->ap_stats.sta[free_slot].aid = cpu_to_le32(aid);
+}
+
+static void ath6kl_sta_cleanup(struct ath6kl *ar, u8 i)
+{
+	struct ath6kl_sta *sta = &ar->sta_list[i];
+
+	/* empty the queued pkts in the PS queue if any */
+	spin_lock_bh(&sta->psq_lock);
+	skb_queue_purge(&sta->psq);
+	spin_unlock_bh(&sta->psq_lock);
+
+	memset(&ar->ap_stats.sta[sta->aid - 1], 0,
+	       sizeof(struct wmi_per_sta_stat));
+	memset(sta->mac, 0, ETH_ALEN);
+	memset(sta->wpa_ie, 0, ATH6KL_MAX_IE);
+	sta->aid = 0;
+	sta->sta_flags = 0;
+
+	ar->sta_list_index = ar->sta_list_index & ~(1 << i);
+
+}
+
+static u8 ath6kl_remove_sta(struct ath6kl *ar, u8 *mac, u16 reason)
+{
+	u8 i, removed = 0;
+
+	if (is_zero_ether_addr(mac))
+		return removed;
+
+	if (is_broadcast_ether_addr(mac)) {
+		ath6kl_dbg(ATH6KL_DBG_TRC, "deleting all station\n");
+
+		for (i = 0; i < AP_MAX_NUM_STA; i++) {
+			if (!is_zero_ether_addr(ar->sta_list[i].mac)) {
+				ath6kl_sta_cleanup(ar, i);
+				removed = 1;
+			}
+		}
+	} else {
+		for (i = 0; i < AP_MAX_NUM_STA; i++) {
+			if (memcmp(ar->sta_list[i].mac, mac, ETH_ALEN) == 0) {
+				ath6kl_dbg(ATH6KL_DBG_TRC,
+					   "deleting station %pM aid=%d reason=%d\n",
+					   mac, ar->sta_list[i].aid, reason);
+				ath6kl_sta_cleanup(ar, i);
+				removed = 1;
+				break;
+			}
+		}
+	}
+
+	return removed;
+}
+
+enum htc_endpoint_id ath6kl_ac2_endpoint_id(void *devt, u8 ac)
+{
+	struct ath6kl *ar = devt;
+	return ar->ac2ep_map[ac];
+}
+
+struct ath6kl_cookie *ath6kl_alloc_cookie(struct ath6kl *ar)
+{
+	struct ath6kl_cookie *cookie;
+
+	cookie = ar->cookie_list;
+	if (cookie != NULL) {
+		ar->cookie_list = cookie->arc_list_next;
+		ar->cookie_count--;
+	}
+
+	return cookie;
+}
+
+void ath6kl_cookie_init(struct ath6kl *ar)
+{
+	u32 i;
+
+	ar->cookie_list = NULL;
+	ar->cookie_count = 0;
+
+	memset(ar->cookie_mem, 0, sizeof(ar->cookie_mem));
+
+	for (i = 0; i < MAX_COOKIE_NUM; i++)
+		ath6kl_free_cookie(ar, &ar->cookie_mem[i]);
+}
+
+void ath6kl_cookie_cleanup(struct ath6kl *ar)
+{
+	ar->cookie_list = NULL;
+	ar->cookie_count = 0;
+}
+
+void ath6kl_free_cookie(struct ath6kl *ar, struct ath6kl_cookie *cookie)
+{
+	/* Insert first */
+
+	if (!ar || !cookie)
+		return;
+
+	cookie->arc_list_next = ar->cookie_list;
+	ar->cookie_list = cookie;
+	ar->cookie_count++;
+}
+
+/* set the window address register (using 4-byte register access ). */
+static int ath6kl_set_addrwin_reg(struct ath6kl *ar, u32 reg_addr, u32 addr)
+{
+	int status;
+	u8 addr_val[4];
+	s32 i;
+
+	/*
+	 * Write bytes 1,2,3 of the register to set the upper address bytes,
+	 * the LSB is written last to initiate the access cycle
+	 */
+
+	for (i = 1; i <= 3; i++) {
+		/*
+		 * Fill the buffer with the address byte value we want to
+		 * hit 4 times.
+		 */
+		memset(addr_val, ((u8 *)&addr)[i], 4);
+
+		/*
+		 * Hit each byte of the register address with a 4-byte
+		 * write operation to the same address, this is a harmless
+		 * operation.
+		 */
+		status = hif_read_write_sync(ar, reg_addr + i, addr_val,
+					     4, HIF_WR_SYNC_BYTE_FIX);
+		if (status)
+			break;
+	}
+
+	if (status) {
+		ath6kl_err("failed to write initial bytes of 0x%x to window reg: 0x%X\n",
+			   addr, reg_addr);
+		return status;
+	}
+
+	/*
+	 * Write the address register again, this time write the whole
+	 * 4-byte value. The effect here is that the LSB write causes the
+	 * cycle to start, the extra 3 byte write to bytes 1,2,3 has no
+	 * effect since we are writing the same values again
+	 */
+	status = hif_read_write_sync(ar, reg_addr, (u8 *)(&addr),
+				     4, HIF_WR_SYNC_BYTE_INC);
+
+	if (status) {
+		ath6kl_err("failed to write 0x%x to window reg: 0x%X\n",
+			   addr, reg_addr);
+		return status;
+	}
+
+	return 0;
+}
+
+/*
+ * Read from the ATH6KL through its diagnostic window. No cooperation from
+ * the Target is required for this.
+ */
+int ath6kl_read_reg_diag(struct ath6kl *ar, u32 *address, u32 *data)
+{
+	int status;
+
+	/* set window register to start read cycle */
+	status = ath6kl_set_addrwin_reg(ar, WINDOW_READ_ADDR_ADDRESS,
+					*address);
+
+	if (status)
+		return status;
+
+	/* read the data */
+	status = hif_read_write_sync(ar, WINDOW_DATA_ADDRESS, (u8 *)data,
+				     sizeof(u32), HIF_RD_SYNC_BYTE_INC);
+	if (status) {
+		ath6kl_err("failed to read from window data addr\n");
+		return status;
+	}
+
+	return status;
+}
+
+
+/*
+ * Write to the ATH6KL through its diagnostic window. No cooperation from
+ * the Target is required for this.
+ */
+static int ath6kl_write_reg_diag(struct ath6kl *ar, u32 *address, u32 *data)
+{
+	int status;
+
+	/* set write data */
+	status = hif_read_write_sync(ar, WINDOW_DATA_ADDRESS, (u8 *)data,
+				     sizeof(u32), HIF_WR_SYNC_BYTE_INC);
+	if (status) {
+		ath6kl_err("failed to write 0x%x to window data addr\n", *data);
+		return status;
+	}
+
+	/* set window register, which starts the write cycle */
+	return ath6kl_set_addrwin_reg(ar, WINDOW_WRITE_ADDR_ADDRESS,
+				      *address);
+}
+
+int ath6kl_access_datadiag(struct ath6kl *ar, u32 address,
+			   u8 *data, u32 length, bool read)
+{
+	u32 count;
+	int status = 0;
+
+	for (count = 0; count < length; count += 4, address += 4) {
+		if (read) {
+			status = ath6kl_read_reg_diag(ar, &address,
+						      (u32 *) &data[count]);
+			if (status)
+				break;
+		} else {
+			status = ath6kl_write_reg_diag(ar, &address,
+						       (u32 *) &data[count]);
+			if (status)
+				break;
+		}
+	}
+
+	return status;
+}
+
+static void ath6kl_reset_device(struct ath6kl *ar, u32 target_type,
+				bool wait_fot_compltn, bool cold_reset)
+{
+	int status = 0;
+	u32 address;
+	u32 data;
+
+	if (target_type != TARGET_TYPE_AR6003)
+		return;
+
+	data = cold_reset ? RESET_CONTROL_COLD_RST : RESET_CONTROL_MBOX_RST;
+
+	address = RTC_BASE_ADDRESS;
+	status = ath6kl_write_reg_diag(ar, &address, &data);
+
+	if (status)
+		ath6kl_err("failed to reset target\n");
+}
+
+void ath6kl_stop_endpoint(struct net_device *dev, bool keep_profile,
+			  bool get_dbglogs)
+{
+	struct ath6kl *ar = ath6kl_priv(dev);
+	static u8 bcast_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+	bool discon_issued;
+
+	netif_stop_queue(dev);
+
+	/* disable the target and the interrupts associated with it */
+	if (test_bit(WMI_READY, &ar->flag)) {
+		discon_issued = (test_bit(CONNECTED, &ar->flag) ||
+				 test_bit(CONNECT_PEND, &ar->flag));
+		ath6kl_disconnect(ar);
+		if (!keep_profile)
+			ath6kl_init_profile_info(ar);
+
+		del_timer(&ar->disconnect_timer);
+
+		clear_bit(WMI_READY, &ar->flag);
+		ath6kl_wmi_shutdown(ar->wmi);
+		clear_bit(WMI_ENABLED, &ar->flag);
+		ar->wmi = NULL;
+
+		/*
+		 * After wmi_shudown all WMI events will be dropped. We
+		 * need to cleanup the buffers allocated in AP mode and
+		 * give disconnect notification to stack, which usually
+		 * happens in the disconnect_event. Simulate the disconnect
+		 * event by calling the function directly. Sometimes
+		 * disconnect_event will be received when the debug logs
+		 * are collected.
+		 */
+		if (discon_issued)
+			ath6kl_disconnect_event(ar, DISCONNECT_CMD,
+						(ar->nw_type & AP_NETWORK) ?
+						bcast_mac : ar->bssid,
+						0, NULL, 0);
+
+		ar->user_key_ctrl = 0;
+
+	} else {
+		ath6kl_dbg(ATH6KL_DBG_TRC,
+			   "%s: wmi is not ready 0x%p 0x%p\n",
+			   __func__, ar, ar->wmi);
+
+		/* Shut down WMI if we have started it */
+		if (test_bit(WMI_ENABLED, &ar->flag)) {
+			ath6kl_dbg(ATH6KL_DBG_TRC,
+				   "%s: shut down wmi\n", __func__);
+			ath6kl_wmi_shutdown(ar->wmi);
+			clear_bit(WMI_ENABLED, &ar->flag);
+			ar->wmi = NULL;
+		}
+	}
+
+	if (ar->htc_target) {
+		ath6kl_dbg(ATH6KL_DBG_TRC, "%s: shut down htc\n", __func__);
+		ath6kl_htc_stop(ar->htc_target);
+	}
+
+	/*
+	 * Try to reset the device if we can. The driver may have been
+	 * configure NOT to reset the target during a debug session.
+	 */
+	ath6kl_dbg(ATH6KL_DBG_TRC,
+		   "attempting to reset target on instance destroy\n");
+	ath6kl_reset_device(ar, ar->target_type, true, true);
+}
+
+static void ath6kl_install_static_wep_keys(struct ath6kl *ar)
+{
+	u8 index;
+	u8 keyusage;
+
+	for (index = WMI_MIN_KEY_INDEX; index <= WMI_MAX_KEY_INDEX; index++) {
+		if (ar->wep_key_list[index].key_len) {
+			keyusage = GROUP_USAGE;
+			if (index == ar->def_txkey_index)
+				keyusage |= TX_USAGE;
+
+			ath6kl_wmi_addkey_cmd(ar->wmi,
+					      index,
+					      WEP_CRYPT,
+					      keyusage,
+					      ar->wep_key_list[index].key_len,
+					      NULL,
+					      ar->wep_key_list[index].key,
+					      KEY_OP_INIT_VAL, NULL,
+					      NO_SYNC_WMIFLAG);
+		}
+	}
+}
+
+static void ath6kl_connect_ap_mode(struct ath6kl *ar, u16 channel, u8 *bssid,
+				   u16 listen_int, u16 beacon_int,
+				   u8 assoc_resp_len, u8 *assoc_info)
+{
+	struct net_device *dev = ar->net_dev;
+	struct station_info sinfo;
+	struct ath6kl_req_key *ik;
+	enum crypto_type keyType = NONE_CRYPT;
+
+	if (memcmp(dev->dev_addr, bssid, ETH_ALEN) == 0) {
+		ik = &ar->ap_mode_bkey;
+
+		switch (ar->auth_mode) {
+		case NONE_AUTH:
+			if (ar->prwise_crypto == WEP_CRYPT)
+				ath6kl_install_static_wep_keys(ar);
+			break;
+		case WPA_PSK_AUTH:
+		case WPA2_PSK_AUTH:
+		case (WPA_PSK_AUTH|WPA2_PSK_AUTH):
+			switch (ik->ik_type) {
+			case ATH6KL_CIPHER_TKIP:
+				keyType = TKIP_CRYPT;
+				break;
+			case ATH6KL_CIPHER_AES_CCM:
+				keyType = AES_CRYPT;
+				break;
+			default:
+				goto skip_key;
+			}
+			ath6kl_wmi_addkey_cmd(ar->wmi, ik->ik_keyix, keyType,
+					      GROUP_USAGE, ik->ik_keylen,
+					      (u8 *)&ik->ik_keyrsc,
+					      ik->ik_keydata,
+					      KEY_OP_INIT_VAL, ik->ik_macaddr,
+					      SYNC_BOTH_WMIFLAG);
+			break;
+		}
+skip_key:
+		set_bit(CONNECTED, &ar->flag);
+		return;
+	}
+
+	ath6kl_dbg(ATH6KL_DBG_TRC, "new station %pM aid=%d\n",
+		   bssid, channel);
+
+	ath6kl_add_new_sta(ar, bssid, channel, assoc_info, assoc_resp_len,
+			   listen_int & 0xFF, beacon_int,
+			   (listen_int >> 8) & 0xFF);
+
+	/* send event to application */
+	memset(&sinfo, 0, sizeof(sinfo));
+
+	/* TODO: sinfo.generation */
+	/* TODO: need to deliver (Re)AssocReq IEs somehow.. change in
+	 * cfg80211 needed, e.g., by adding those into sinfo
+	 */
+	cfg80211_new_sta(ar->net_dev, bssid, &sinfo, GFP_KERNEL);
+
+	netif_wake_queue(ar->net_dev);
+
+	return;
+}
+
+/* Functions for Tx credit handling */
+void ath6k_credit_init(struct htc_credit_state_info *cred_info,
+		       struct list_head *ep_list,
+		       int tot_credits)
+{
+	struct htc_endpoint_credit_dist *cur_ep_dist;
+	int count;
+
+	cred_info->cur_free_credits = tot_credits;
+	cred_info->total_avail_credits = tot_credits;
+
+	list_for_each_entry(cur_ep_dist, ep_list, list) {
+		if (cur_ep_dist->endpoint == ENDPOINT_0)
+			continue;
+
+		cur_ep_dist->cred_min = cur_ep_dist->cred_per_msg;
+
+		if (tot_credits > 4)
+			if ((cur_ep_dist->svc_id == WMI_DATA_BK_SVC) ||
+			    (cur_ep_dist->svc_id == WMI_DATA_BE_SVC)) {
+				ath6kl_deposit_credit_to_ep(cred_info,
+						cur_ep_dist,
+						cur_ep_dist->cred_min);
+				cur_ep_dist->dist_flags |= HTC_EP_ACTIVE;
+			}
+
+		if (cur_ep_dist->svc_id == WMI_CONTROL_SVC) {
+			ath6kl_deposit_credit_to_ep(cred_info, cur_ep_dist,
+						    cur_ep_dist->cred_min);
+			/*
+			 * Control service is always marked active, it
+			 * never goes inactive EVER.
+			 */
+			cur_ep_dist->dist_flags |= HTC_EP_ACTIVE;
+		} else if (cur_ep_dist->svc_id == WMI_DATA_BK_SVC)
+			/* this is the lowest priority data endpoint */
+			cred_info->lowestpri_ep_dist = cur_ep_dist->list;
+
+		/*
+		 * Streams have to be created (explicit | implicit) for all
+		 * kinds of traffic. BE endpoints are also inactive in the
+		 * beginning. When BE traffic starts it creates implicit
+		 * streams that redistributes credits.
+		 *
+		 * Note: all other endpoints have minimums set but are
+		 * initially given NO credits. credits will be distributed
+		 * as traffic activity demands
+		 */
+	}
+
+	WARN_ON(cred_info->cur_free_credits <= 0);
+
+	list_for_each_entry(cur_ep_dist, ep_list, list) {
+		if (cur_ep_dist->endpoint == ENDPOINT_0)
+			continue;
+
+		if (cur_ep_dist->svc_id == WMI_CONTROL_SVC)
+			cur_ep_dist->cred_norm = cur_ep_dist->cred_per_msg;
+		else {
+			/*
+			 * For the remaining data endpoints, we assume that
+			 * each cred_per_msg are the same. We use a simple
+			 * calculation here, we take the remaining credits
+			 * and determine how many max messages this can
+			 * cover and then set each endpoint's normal value
+			 * equal to 3/4 this amount.
+			 */
+			count = (cred_info->cur_free_credits /
+				 cur_ep_dist->cred_per_msg)
+				* cur_ep_dist->cred_per_msg;
+			count = (count * 3) >> 2;
+			count = max(count, cur_ep_dist->cred_per_msg);
+			cur_ep_dist->cred_norm = count;
+
+		}
+	}
+}
+
+/* initialize and setup credit distribution */
+int ath6k_setup_credit_dist(void *htc_handle,
+			    struct htc_credit_state_info *cred_info)
+{
+	u16 servicepriority[5];
+
+	memset(cred_info, 0, sizeof(struct htc_credit_state_info));
+
+	servicepriority[0] = WMI_CONTROL_SVC;  /* highest */
+	servicepriority[1] = WMI_DATA_VO_SVC;
+	servicepriority[2] = WMI_DATA_VI_SVC;
+	servicepriority[3] = WMI_DATA_BE_SVC;
+	servicepriority[4] = WMI_DATA_BK_SVC; /* lowest */
+
+	/* set priority list */
+	ath6kl_htc_set_credit_dist(htc_handle, cred_info, servicepriority, 5);
+
+	return 0;
+}
+
+/* reduce an ep's credits back to a set limit */
+static void ath6k_reduce_credits(struct htc_credit_state_info *cred_info,
+				 struct htc_endpoint_credit_dist  *ep_dist,
+				 int limit)
+{
+	int credits;
+
+	ep_dist->cred_assngd = limit;
+
+	if (ep_dist->credits <= limit)
+		return;
+
+	credits = ep_dist->credits - limit;
+	ep_dist->credits -= credits;
+	cred_info->cur_free_credits += credits;
+}
+
+static void ath6k_credit_update(struct htc_credit_state_info *cred_info,
+				struct list_head *epdist_list)
+{
+	struct htc_endpoint_credit_dist *cur_dist_list;
+
+	list_for_each_entry(cur_dist_list, epdist_list, list) {
+		if (cur_dist_list->endpoint == ENDPOINT_0)
+			continue;
+
+		if (cur_dist_list->cred_to_dist > 0) {
+			cur_dist_list->credits +=
+					cur_dist_list->cred_to_dist;
+			cur_dist_list->cred_to_dist = 0;
+			if (cur_dist_list->credits >
+			    cur_dist_list->cred_assngd)
+				ath6k_reduce_credits(cred_info,
+						cur_dist_list,
+						cur_dist_list->cred_assngd);
+
+			if (cur_dist_list->credits >
+			    cur_dist_list->cred_norm)
+				ath6k_reduce_credits(cred_info, cur_dist_list,
+						     cur_dist_list->cred_norm);
+
+			if (!(cur_dist_list->dist_flags & HTC_EP_ACTIVE)) {
+				if (cur_dist_list->txq_depth == 0)
+					ath6k_reduce_credits(cred_info,
+							     cur_dist_list, 0);
+			}
+		}
+	}
+}
+
+/*
+ * HTC has an endpoint that needs credits, ep_dist is the endpoint in
+ * question.
+ */
+void ath6k_seek_credits(struct htc_credit_state_info *cred_info,
+			struct htc_endpoint_credit_dist *ep_dist)
+{
+	struct htc_endpoint_credit_dist *curdist_list;
+	int credits = 0;
+	int need;
+
+	if (ep_dist->svc_id == WMI_CONTROL_SVC)
+		goto out;
+
+	if ((ep_dist->svc_id == WMI_DATA_VI_SVC) ||
+	    (ep_dist->svc_id == WMI_DATA_VO_SVC))
+		if ((ep_dist->cred_assngd >= ep_dist->cred_norm))
+			goto out;
+
+	/*
+	 * For all other services, we follow a simple algorithm of:
+	 *
+	 * 1. checking the free pool for credits
+	 * 2. checking lower priority endpoints for credits to take
+	 */
+
+	credits = min(cred_info->cur_free_credits, ep_dist->seek_cred);
+
+	if (credits >= ep_dist->seek_cred)
+		goto out;
+
+	/*
+	 * We don't have enough in the free pool, try taking away from
+	 * lower priority services The rule for taking away credits:
+	 *
+	 *   1. Only take from lower priority endpoints
+	 *   2. Only take what is allocated above the minimum (never
+	 *      starve an endpoint completely)
+	 *   3. Only take what you need.
+	 */
+
+	list_for_each_entry_reverse(curdist_list,
+				    &cred_info->lowestpri_ep_dist,
+				    list) {
+		if (curdist_list == ep_dist)
+			break;
+
+		need = ep_dist->seek_cred - cred_info->cur_free_credits;
+
+		if ((curdist_list->cred_assngd - need) >=
+		     curdist_list->cred_min) {
+			/*
+			 * The current one has been allocated more than
+			 * it's minimum and it has enough credits assigned
+			 * above it's minimum to fulfill our need try to
+			 * take away just enough to fulfill our need.
+			 */
+			ath6k_reduce_credits(cred_info, curdist_list,
+					curdist_list->cred_assngd - need);
+
+			if (cred_info->cur_free_credits >=
+			    ep_dist->seek_cred)
+				break;
+		}
+
+		if (curdist_list->endpoint == ENDPOINT_0)
+			break;
+	}
+
+	credits = min(cred_info->cur_free_credits, ep_dist->seek_cred);
+
+out:
+	/* did we find some credits? */
+	if (credits)
+		ath6kl_deposit_credit_to_ep(cred_info, ep_dist, credits);
+
+	ep_dist->seek_cred = 0;
+}
+
+/* redistribute credits based on activity change */
+static void ath6k_redistribute_credits(struct htc_credit_state_info *info,
+				       struct list_head *ep_dist_list)
+{
+	struct htc_endpoint_credit_dist *curdist_list;
+
+	list_for_each_entry(curdist_list, ep_dist_list, list) {
+		if (curdist_list->endpoint == ENDPOINT_0)
+			continue;
+
+		if ((curdist_list->svc_id == WMI_DATA_BK_SVC)  ||
+		    (curdist_list->svc_id == WMI_DATA_BE_SVC))
+			curdist_list->dist_flags |= HTC_EP_ACTIVE;
+
+		if ((curdist_list->svc_id != WMI_CONTROL_SVC) &&
+		    !(curdist_list->dist_flags & HTC_EP_ACTIVE)) {
+			if (curdist_list->txq_depth == 0)
+				ath6k_reduce_credits(info,
+						curdist_list, 0);
+			else
+				ath6k_reduce_credits(info,
+						curdist_list,
+						curdist_list->cred_min);
+		}
+	}
+}
+
+/*
+ *
+ * This function is invoked whenever endpoints require credit
+ * distributions. A lock is held while this function is invoked, this
+ * function shall NOT block. The ep_dist_list is a list of distribution
+ * structures in prioritized order as defined by the call to the
+ * htc_set_credit_dist() api.
+ */
+void ath6k_credit_distribute(struct htc_credit_state_info *cred_info,
+			     struct list_head *ep_dist_list,
+			     enum htc_credit_dist_reason reason)
+{
+	switch (reason) {
+	case HTC_CREDIT_DIST_SEND_COMPLETE:
+		ath6k_credit_update(cred_info, ep_dist_list);
+		break;
+	case HTC_CREDIT_DIST_ACTIVITY_CHANGE:
+		ath6k_redistribute_credits(cred_info, ep_dist_list);
+		break;
+	default:
+		break;
+	}
+
+	WARN_ON(cred_info->cur_free_credits > cred_info->total_avail_credits);
+	WARN_ON(cred_info->cur_free_credits < 0);
+}
+
+void disconnect_timer_handler(unsigned long ptr)
+{
+	struct net_device *dev = (struct net_device *)ptr;
+	struct ath6kl *ar = ath6kl_priv(dev);
+
+	ath6kl_init_profile_info(ar);
+	ath6kl_disconnect(ar);
+}
+
+void ath6kl_disconnect(struct ath6kl *ar)
+{
+	if (test_bit(CONNECTED, &ar->flag) ||
+	    test_bit(CONNECT_PEND, &ar->flag)) {
+		ath6kl_wmi_disconnect_cmd(ar->wmi);
+		/*
+		 * Disconnect command is issued, clear the connect pending
+		 * flag. The connected flag will be cleared in
+		 * disconnect event notification.
+		 */
+		clear_bit(CONNECT_PEND, &ar->flag);
+	}
+}
+
+/* WMI Event handlers */
+
+static const char *get_hw_id_string(u32 id)
+{
+	switch (id) {
+	case AR6003_REV1_VERSION:
+		return "1.0";
+	case AR6003_REV2_VERSION:
+		return "2.0";
+	case AR6003_REV3_VERSION:
+		return "2.1.1";
+	default:
+		return "unknown";
+	}
+}
+
+void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver)
+{
+	struct ath6kl *ar = devt;
+	struct net_device *dev = ar->net_dev;
+
+	memcpy(dev->dev_addr, datap, ETH_ALEN);
+	ath6kl_dbg(ATH6KL_DBG_TRC, "%s: mac addr = %pM\n",
+		   __func__, dev->dev_addr);
+
+	ar->version.wlan_ver = sw_ver;
+	ar->version.abi_ver = abi_ver;
+
+	snprintf(ar->wdev->wiphy->fw_version,
+		 sizeof(ar->wdev->wiphy->fw_version),
+		 "%u.%u.%u.%u",
+		 (ar->version.wlan_ver & 0xf0000000) >> 28,
+		 (ar->version.wlan_ver & 0x0f000000) >> 24,
+		 (ar->version.wlan_ver & 0x00ff0000) >> 16,
+		 (ar->version.wlan_ver & 0x0000ffff));
+
+	/* indicate to the waiting thread that the ready event was received */
+	set_bit(WMI_READY, &ar->flag);
+	wake_up(&ar->event_wq);
+
+	ath6kl_info("hw %s fw %s\n",
+		    get_hw_id_string(ar->wdev->wiphy->hw_version),
+		    ar->wdev->wiphy->fw_version);
+}
+
+void ath6kl_scan_complete_evt(struct ath6kl *ar, int status)
+{
+	ath6kl_cfg80211_scan_complete_event(ar, status);
+
+	if (!ar->usr_bss_filter)
+		ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0);
+
+	ath6kl_dbg(ATH6KL_DBG_WLAN_SCAN, "scan complete: %d\n", status);
+}
+
+void ath6kl_connect_event(struct ath6kl *ar, u16 channel, u8 *bssid,
+			  u16 listen_int, u16 beacon_int,
+			  enum network_type net_type, u8 beacon_ie_len,
+			  u8 assoc_req_len, u8 assoc_resp_len,
+			  u8 *assoc_info)
+{
+	unsigned long flags;
+
+	if (ar->nw_type == AP_NETWORK) {
+		ath6kl_connect_ap_mode(ar, channel, bssid, listen_int,
+				       beacon_int, assoc_resp_len,
+				       assoc_info);
+		return;
+	}
+
+	ath6kl_cfg80211_connect_event(ar, channel, bssid,
+				      listen_int, beacon_int,
+				      net_type, beacon_ie_len,
+				      assoc_req_len, assoc_resp_len,
+				      assoc_info);
+
+	memcpy(ar->bssid, bssid, sizeof(ar->bssid));
+	ar->bss_ch = channel;
+
+	if ((ar->nw_type == INFRA_NETWORK))
+		ath6kl_wmi_listeninterval_cmd(ar->wmi, ar->listen_intvl_t,
+					      ar->listen_intvl_b);
+
+	netif_wake_queue(ar->net_dev);
+
+	/* Update connect & link status atomically */
+	spin_lock_irqsave(&ar->lock, flags);
+	set_bit(CONNECTED, &ar->flag);
+	clear_bit(CONNECT_PEND, &ar->flag);
+	netif_carrier_on(ar->net_dev);
+	spin_unlock_irqrestore(&ar->lock, flags);
+
+	aggr_reset_state(ar->aggr_cntxt);
+	ar->reconnect_flag = 0;
+
+	if ((ar->nw_type == ADHOC_NETWORK) && ar->ibss_ps_enable) {
+		memset(ar->node_map, 0, sizeof(ar->node_map));
+		ar->node_num = 0;
+		ar->next_ep_id = ENDPOINT_2;
+	}
+
+	if (!ar->usr_bss_filter)
+		ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0);
+}
+
+void ath6kl_tkip_micerr_event(struct ath6kl *ar, u8 keyid, bool ismcast)
+{
+	struct ath6kl_sta *sta;
+	u8 tsc[6];
+	/*
+	 * For AP case, keyid will have aid of STA which sent pkt with
+	 * MIC error. Use this aid to get MAC & send it to hostapd.
+	 */
+	if (ar->nw_type == AP_NETWORK) {
+		sta = ath6kl_find_sta_by_aid(ar, (keyid >> 2));
+		if (!sta)
+			return;
+
+		ath6kl_dbg(ATH6KL_DBG_TRC,
+			   "ap tkip mic error received from aid=%d\n", keyid);
+
+		memset(tsc, 0, sizeof(tsc)); /* FIX: get correct TSC */
+		cfg80211_michael_mic_failure(ar->net_dev, sta->mac,
+					     NL80211_KEYTYPE_PAIRWISE, keyid,
+					     tsc, GFP_KERNEL);
+	} else
+		ath6kl_cfg80211_tkip_micerr_event(ar, keyid, ismcast);
+
+}
+
+static void ath6kl_update_target_stats(struct ath6kl *ar, u8 *ptr, u32 len)
+{
+	struct wmi_target_stats *tgt_stats =
+		(struct wmi_target_stats *) ptr;
+	struct target_stats *stats = &ar->target_stats;
+	struct tkip_ccmp_stats *ccmp_stats;
+	struct bss *conn_bss = NULL;
+	struct cserv_stats *c_stats;
+	u8 ac;
+
+	if (len < sizeof(*tgt_stats))
+		return;
+
+	/* update the RSSI of the connected bss */
+	if (test_bit(CONNECTED, &ar->flag)) {
+		conn_bss = ath6kl_wmi_find_node(ar->wmi, ar->bssid);
+		if (conn_bss) {
+			c_stats = &tgt_stats->cserv_stats;
+			conn_bss->ni_rssi =
+				a_sle16_to_cpu(c_stats->cs_ave_beacon_rssi);
+			conn_bss->ni_snr =
+				tgt_stats->cserv_stats.cs_ave_beacon_snr;
+			ath6kl_wmi_node_return(ar->wmi, conn_bss);
+		}
+	}
+
+	ath6kl_dbg(ATH6KL_DBG_TRC, "updating target stats\n");
+
+	stats->tx_pkt += le32_to_cpu(tgt_stats->stats.tx.pkt);
+	stats->tx_byte += le32_to_cpu(tgt_stats->stats.tx.byte);
+	stats->tx_ucast_pkt += le32_to_cpu(tgt_stats->stats.tx.ucast_pkt);
+	stats->tx_ucast_byte += le32_to_cpu(tgt_stats->stats.tx.ucast_byte);
+	stats->tx_mcast_pkt += le32_to_cpu(tgt_stats->stats.tx.mcast_pkt);
+	stats->tx_mcast_byte += le32_to_cpu(tgt_stats->stats.tx.mcast_byte);
+	stats->tx_bcast_pkt  += le32_to_cpu(tgt_stats->stats.tx.bcast_pkt);
+	stats->tx_bcast_byte += le32_to_cpu(tgt_stats->stats.tx.bcast_byte);
+	stats->tx_rts_success_cnt +=
+		le32_to_cpu(tgt_stats->stats.tx.rts_success_cnt);
+
+	for (ac = 0; ac < WMM_NUM_AC; ac++)
+		stats->tx_pkt_per_ac[ac] +=
+			le32_to_cpu(tgt_stats->stats.tx.pkt_per_ac[ac]);
+
+	stats->tx_err += le32_to_cpu(tgt_stats->stats.tx.err);
+	stats->tx_fail_cnt += le32_to_cpu(tgt_stats->stats.tx.fail_cnt);
+	stats->tx_retry_cnt += le32_to_cpu(tgt_stats->stats.tx.retry_cnt);
+	stats->tx_mult_retry_cnt +=
+		le32_to_cpu(tgt_stats->stats.tx.mult_retry_cnt);
+	stats->tx_rts_fail_cnt +=
+		le32_to_cpu(tgt_stats->stats.tx.rts_fail_cnt);
+	stats->tx_ucast_rate =
+	    ath6kl_wmi_get_rate(a_sle32_to_cpu(tgt_stats->stats.tx.ucast_rate));
+
+	stats->rx_pkt += le32_to_cpu(tgt_stats->stats.rx.pkt);
+	stats->rx_byte += le32_to_cpu(tgt_stats->stats.rx.byte);
+	stats->rx_ucast_pkt += le32_to_cpu(tgt_stats->stats.rx.ucast_pkt);
+	stats->rx_ucast_byte += le32_to_cpu(tgt_stats->stats.rx.ucast_byte);
+	stats->rx_mcast_pkt += le32_to_cpu(tgt_stats->stats.rx.mcast_pkt);
+	stats->rx_mcast_byte += le32_to_cpu(tgt_stats->stats.rx.mcast_byte);
+	stats->rx_bcast_pkt += le32_to_cpu(tgt_stats->stats.rx.bcast_pkt);
+	stats->rx_bcast_byte += le32_to_cpu(tgt_stats->stats.rx.bcast_byte);
+	stats->rx_frgment_pkt += le32_to_cpu(tgt_stats->stats.rx.frgment_pkt);
+	stats->rx_err += le32_to_cpu(tgt_stats->stats.rx.err);
+	stats->rx_crc_err += le32_to_cpu(tgt_stats->stats.rx.crc_err);
+	stats->rx_key_cache_miss +=
+		le32_to_cpu(tgt_stats->stats.rx.key_cache_miss);
+	stats->rx_decrypt_err += le32_to_cpu(tgt_stats->stats.rx.decrypt_err);
+	stats->rx_dupl_frame += le32_to_cpu(tgt_stats->stats.rx.dupl_frame);
+	stats->rx_ucast_rate =
+	    ath6kl_wmi_get_rate(a_sle32_to_cpu(tgt_stats->stats.rx.ucast_rate));
+
+	ccmp_stats = &tgt_stats->stats.tkip_ccmp_stats;
+
+	stats->tkip_local_mic_fail +=
+		le32_to_cpu(ccmp_stats->tkip_local_mic_fail);
+	stats->tkip_cnter_measures_invoked +=
+		le32_to_cpu(ccmp_stats->tkip_cnter_measures_invoked);
+	stats->tkip_fmt_err += le32_to_cpu(ccmp_stats->tkip_fmt_err);
+
+	stats->ccmp_fmt_err += le32_to_cpu(ccmp_stats->ccmp_fmt_err);
+	stats->ccmp_replays += le32_to_cpu(ccmp_stats->ccmp_replays);
+
+	stats->pwr_save_fail_cnt +=
+		le32_to_cpu(tgt_stats->pm_stats.pwr_save_failure_cnt);
+	stats->noise_floor_calib =
+		a_sle32_to_cpu(tgt_stats->noise_floor_calib);
+
+	stats->cs_bmiss_cnt +=
+		le32_to_cpu(tgt_stats->cserv_stats.cs_bmiss_cnt);
+	stats->cs_low_rssi_cnt +=
+		le32_to_cpu(tgt_stats->cserv_stats.cs_low_rssi_cnt);
+	stats->cs_connect_cnt +=
+		le16_to_cpu(tgt_stats->cserv_stats.cs_connect_cnt);
+	stats->cs_discon_cnt +=
+		le16_to_cpu(tgt_stats->cserv_stats.cs_discon_cnt);
+
+	stats->cs_ave_beacon_rssi =
+		a_sle16_to_cpu(tgt_stats->cserv_stats.cs_ave_beacon_rssi);
+
+	stats->cs_last_roam_msec =
+		tgt_stats->cserv_stats.cs_last_roam_msec;
+	stats->cs_snr = tgt_stats->cserv_stats.cs_snr;
+	stats->cs_rssi = a_sle16_to_cpu(tgt_stats->cserv_stats.cs_rssi);
+
+	stats->lq_val = le32_to_cpu(tgt_stats->lq_val);
+
+	stats->wow_pkt_dropped +=
+		le32_to_cpu(tgt_stats->wow_stats.wow_pkt_dropped);
+	stats->wow_host_pkt_wakeups +=
+		tgt_stats->wow_stats.wow_host_pkt_wakeups;
+	stats->wow_host_evt_wakeups +=
+		tgt_stats->wow_stats.wow_host_evt_wakeups;
+	stats->wow_evt_discarded +=
+		le16_to_cpu(tgt_stats->wow_stats.wow_evt_discarded);
+
+	if (test_bit(STATS_UPDATE_PEND, &ar->flag)) {
+		clear_bit(STATS_UPDATE_PEND, &ar->flag);
+		wake_up(&ar->event_wq);
+	}
+}
+
+static void ath6kl_add_le32(__le32 *var, __le32 val)
+{
+	*var = cpu_to_le32(le32_to_cpu(*var) + le32_to_cpu(val));
+}
+
+void ath6kl_tgt_stats_event(struct ath6kl *ar, u8 *ptr, u32 len)
+{
+	struct wmi_ap_mode_stat *p = (struct wmi_ap_mode_stat *) ptr;
+	struct wmi_ap_mode_stat *ap = &ar->ap_stats;
+	struct wmi_per_sta_stat *st_ap, *st_p;
+	u8 ac;
+
+	if (ar->nw_type == AP_NETWORK) {
+		if (len < sizeof(*p))
+			return;
+
+		for (ac = 0; ac < AP_MAX_NUM_STA; ac++) {
+			st_ap = &ap->sta[ac];
+			st_p = &p->sta[ac];
+
+			ath6kl_add_le32(&st_ap->tx_bytes, st_p->tx_bytes);
+			ath6kl_add_le32(&st_ap->tx_pkts, st_p->tx_pkts);
+			ath6kl_add_le32(&st_ap->tx_error, st_p->tx_error);
+			ath6kl_add_le32(&st_ap->tx_discard, st_p->tx_discard);
+			ath6kl_add_le32(&st_ap->rx_bytes, st_p->rx_bytes);
+			ath6kl_add_le32(&st_ap->rx_pkts, st_p->rx_pkts);
+			ath6kl_add_le32(&st_ap->rx_error, st_p->rx_error);
+			ath6kl_add_le32(&st_ap->rx_discard, st_p->rx_discard);
+		}
+
+	} else {
+		ath6kl_update_target_stats(ar, ptr, len);
+	}
+}
+
+void ath6kl_wakeup_event(void *dev)
+{
+	struct ath6kl *ar = (struct ath6kl *) dev;
+
+	wake_up(&ar->event_wq);
+}
+
+void ath6kl_txpwr_rx_evt(void *devt, u8 tx_pwr)
+{
+	struct ath6kl *ar = (struct ath6kl *) devt;
+
+	ar->tx_pwr = tx_pwr;
+	wake_up(&ar->event_wq);
+}
+
+void ath6kl_pspoll_event(struct ath6kl *ar, u8 aid)
+{
+	struct ath6kl_sta *conn;
+	struct sk_buff *skb;
+	bool psq_empty = false;
+
+	conn = ath6kl_find_sta_by_aid(ar, aid);
+
+	if (!conn)
+		return;
+	/*
+	 * Send out a packet queued on ps queue. When the ps queue
+	 * becomes empty update the PVB for this station.
+	 */
+	spin_lock_bh(&conn->psq_lock);
+	psq_empty  = skb_queue_empty(&conn->psq);
+	spin_unlock_bh(&conn->psq_lock);
+
+	if (psq_empty)
+		/* TODO: Send out a NULL data frame */
+		return;
+
+	spin_lock_bh(&conn->psq_lock);
+	skb = skb_dequeue(&conn->psq);
+	spin_unlock_bh(&conn->psq_lock);
+
+	conn->sta_flags |= STA_PS_POLLED;
+	ath6kl_data_tx(skb, ar->net_dev);
+	conn->sta_flags &= ~STA_PS_POLLED;
+
+	spin_lock_bh(&conn->psq_lock);
+	psq_empty  = skb_queue_empty(&conn->psq);
+	spin_unlock_bh(&conn->psq_lock);
+
+	if (psq_empty)
+		ath6kl_wmi_set_pvb_cmd(ar->wmi, conn->aid, 0);
+}
+
+void ath6kl_dtimexpiry_event(struct ath6kl *ar)
+{
+	bool mcastq_empty = false;
+	struct sk_buff *skb;
+
+	/*
+	 * If there are no associated STAs, ignore the DTIM expiry event.
+	 * There can be potential race conditions where the last associated
+	 * STA may disconnect & before the host could clear the 'Indicate
+	 * DTIM' request to the firmware, the firmware would have just
+	 * indicated a DTIM expiry event. The race is between 'clear DTIM
+	 * expiry cmd' going from the host to the firmware & the DTIM
+	 * expiry event happening from the firmware to the host.
+	 */
+	if (!ar->sta_list_index)
+		return;
+
+	spin_lock_bh(&ar->mcastpsq_lock);
+	mcastq_empty = skb_queue_empty(&ar->mcastpsq);
+	spin_unlock_bh(&ar->mcastpsq_lock);
+
+	if (mcastq_empty)
+		return;
+
+	/* set the STA flag to dtim_expired for the frame to go out */
+	set_bit(DTIM_EXPIRED, &ar->flag);
+
+	spin_lock_bh(&ar->mcastpsq_lock);
+	while ((skb = skb_dequeue(&ar->mcastpsq)) != NULL) {
+		spin_unlock_bh(&ar->mcastpsq_lock);
+
+		ath6kl_data_tx(skb, ar->net_dev);
+
+		spin_lock_bh(&ar->mcastpsq_lock);
+	}
+	spin_unlock_bh(&ar->mcastpsq_lock);
+
+	clear_bit(DTIM_EXPIRED, &ar->flag);
+
+	/* clear the LSB of the BitMapCtl field of the TIM IE */
+	ath6kl_wmi_set_pvb_cmd(ar->wmi, MCAST_AID, 0);
+}
+
+void ath6kl_disconnect_event(struct ath6kl *ar, u8 reason, u8 *bssid,
+			     u8 assoc_resp_len, u8 *assoc_info,
+			     u16 prot_reason_status)
+{
+	struct bss *wmi_ssid_node = NULL;
+	unsigned long flags;
+
+	if (ar->nw_type == AP_NETWORK) {
+		if (!ath6kl_remove_sta(ar, bssid, prot_reason_status))
+			return;
+
+		/* if no more associated STAs, empty the mcast PS q */
+		if (ar->sta_list_index == 0) {
+			spin_lock_bh(&ar->mcastpsq_lock);
+			skb_queue_purge(&ar->mcastpsq);
+			spin_unlock_bh(&ar->mcastpsq_lock);
+
+			/* clear the LSB of the TIM IE's BitMapCtl field */
+			if (test_bit(WMI_READY, &ar->flag))
+				ath6kl_wmi_set_pvb_cmd(ar->wmi, MCAST_AID, 0);
+		}
+
+		if (!is_broadcast_ether_addr(bssid)) {
+			/* send event to application */
+			cfg80211_del_sta(ar->net_dev, bssid, GFP_KERNEL);
+		}
+
+		clear_bit(CONNECTED, &ar->flag);
+		return;
+	}
+
+	ath6kl_cfg80211_disconnect_event(ar, reason, bssid,
+				       assoc_resp_len, assoc_info,
+				       prot_reason_status);
+
+	aggr_reset_state(ar->aggr_cntxt);
+
+	del_timer(&ar->disconnect_timer);
+
+	ath6kl_dbg(ATH6KL_DBG_WLAN_CONNECT,
+		   "disconnect reason is %d\n", reason);
+
+	/*
+	 * If the event is due to disconnect cmd from the host, only they
+	 * the target would stop trying to connect. Under any other
+	 * condition, target would keep trying to connect.
+	 */
+	if (reason == DISCONNECT_CMD) {
+		if (!ar->usr_bss_filter && test_bit(WMI_READY, &ar->flag))
+			ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0);
+	} else {
+		set_bit(CONNECT_PEND, &ar->flag);
+		if (((reason == ASSOC_FAILED) &&
+		    (prot_reason_status == 0x11)) ||
+		    ((reason == ASSOC_FAILED) && (prot_reason_status == 0x0)
+		     && (ar->reconnect_flag == 1))) {
+			set_bit(CONNECTED, &ar->flag);
+			return;
+		}
+	}
+
+	if ((reason == NO_NETWORK_AVAIL) && test_bit(WMI_READY, &ar->flag))  {
+		ath6kl_wmi_node_free(ar->wmi, bssid);
+
+		/*
+		 * In case any other same SSID nodes are present remove it,
+		 * since those nodes also not available now.
+		 */
+		do {
+			/*
+			 * Find the nodes based on SSID and remove it
+			 *
+			 * Note: This case will not work out for
+			 * Hidden-SSID
+			 */
+			wmi_ssid_node = ath6kl_wmi_find_ssid_node(ar->wmi,
+								  ar->ssid,
+								  ar->ssid_len,
+								  false,
+								  true);
+
+			if (wmi_ssid_node)
+				ath6kl_wmi_node_free(ar->wmi,
+						     wmi_ssid_node->ni_macaddr);
+
+		} while (wmi_ssid_node);
+	}
+
+	/* update connect & link status atomically */
+	spin_lock_irqsave(&ar->lock, flags);
+	clear_bit(CONNECTED, &ar->flag);
+	netif_carrier_off(ar->net_dev);
+	spin_unlock_irqrestore(&ar->lock, flags);
+
+	if ((reason != CSERV_DISCONNECT) || (ar->reconnect_flag != 1))
+		ar->reconnect_flag = 0;
+
+	if (reason != CSERV_DISCONNECT)
+		ar->user_key_ctrl = 0;
+
+	netif_stop_queue(ar->net_dev);
+	memset(ar->bssid, 0, sizeof(ar->bssid));
+	ar->bss_ch = 0;
+
+	ath6kl_tx_data_cleanup(ar);
+}
+
+static int ath6kl_open(struct net_device *dev)
+{
+	struct ath6kl *ar = ath6kl_priv(dev);
+	unsigned long flags;
+
+	spin_lock_irqsave(&ar->lock, flags);
+
+	set_bit(WLAN_ENABLED, &ar->flag);
+
+	if (test_bit(CONNECTED, &ar->flag)) {
+		netif_carrier_on(dev);
+		netif_wake_queue(dev);
+	} else
+		netif_carrier_off(dev);
+
+	spin_unlock_irqrestore(&ar->lock, flags);
+
+	return 0;
+}
+
+static int ath6kl_close(struct net_device *dev)
+{
+	struct ath6kl *ar = ath6kl_priv(dev);
+
+	netif_stop_queue(dev);
+
+	ath6kl_disconnect(ar);
+
+	if (test_bit(WMI_READY, &ar->flag)) {
+		if (ath6kl_wmi_scanparams_cmd(ar->wmi, 0xFFFF, 0, 0, 0, 0, 0, 0,
+					      0, 0, 0))
+			return -EIO;
+
+		clear_bit(WLAN_ENABLED, &ar->flag);
+	}
+
+	ath6kl_cfg80211_scan_complete_event(ar, -ECANCELED);
+
+	return 0;
+}
+
+static struct net_device_stats *ath6kl_get_stats(struct net_device *dev)
+{
+	struct ath6kl *ar = ath6kl_priv(dev);
+
+	return &ar->net_stats;
+}
+
+static struct net_device_ops ath6kl_netdev_ops = {
+	.ndo_open               = ath6kl_open,
+	.ndo_stop               = ath6kl_close,
+	.ndo_start_xmit         = ath6kl_data_tx,
+	.ndo_get_stats          = ath6kl_get_stats,
+};
+
+void init_netdev(struct net_device *dev)
+{
+	dev->netdev_ops = &ath6kl_netdev_ops;
+	dev->watchdog_timeo = ATH6KL_TX_TIMEOUT;
+
+	dev->needed_headroom = ETH_HLEN;
+	dev->needed_headroom += sizeof(struct ath6kl_llc_snap_hdr) +
+				sizeof(struct wmi_data_hdr) + HTC_HDR_LENGTH
+				+ WMI_MAX_TX_META_SZ;
+
+	return;
+}
diff --git a/drivers/net/wireless/ath/ath6kl/node.c b/drivers/net/wireless/ath/ath6kl/node.c
new file mode 100644
index 000000000000..131205c610b9
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/node.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2004-2011 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.
+ */
+
+#include "htc.h"
+#include "wmi.h"
+#include "debug.h"
+
+struct bss *wlan_node_alloc(int wh_size)
+{
+	struct bss *ni;
+
+	ni = kzalloc(sizeof(struct bss), GFP_ATOMIC);
+
+	if ((ni != NULL) && wh_size) {
+		ni->ni_buf = kmalloc(wh_size, GFP_ATOMIC);
+		if (ni->ni_buf == NULL) {
+			kfree(ni);
+			return NULL;
+		}
+	}
+
+	return ni;
+}
+
+void wlan_node_free(struct bss *ni)
+{
+	kfree(ni->ni_buf);
+	kfree(ni);
+}
+
+void wlan_setup_node(struct ath6kl_node_table *nt, struct bss *ni,
+		     const u8 *mac_addr)
+{
+	int hash;
+
+	memcpy(ni->ni_macaddr, mac_addr, ETH_ALEN);
+	hash = ATH6KL_NODE_HASH(mac_addr);
+	ni->ni_refcnt = 1;
+
+	ni->ni_tstamp = jiffies_to_msecs(jiffies);
+	ni->ni_actcnt = WLAN_NODE_INACT_CNT;
+
+	spin_lock_bh(&nt->nt_nodelock);
+
+	/* insert at the end of the node list */
+	ni->ni_list_next = NULL;
+	ni->ni_list_prev = nt->nt_node_last;
+	if (nt->nt_node_last != NULL)
+		nt->nt_node_last->ni_list_next = ni;
+
+	nt->nt_node_last = ni;
+	if (nt->nt_node_first == NULL)
+		nt->nt_node_first = ni;
+
+	/* insert into the hash list */
+	ni->ni_hash_next = nt->nt_hash[hash];
+	if (ni->ni_hash_next != NULL)
+		nt->nt_hash[hash]->ni_hash_prev = ni;
+
+	ni->ni_hash_prev = NULL;
+	nt->nt_hash[hash] = ni;
+
+	spin_unlock_bh(&nt->nt_nodelock);
+}
+
+struct bss *wlan_find_node(struct ath6kl_node_table *nt,
+			   const u8 *mac_addr)
+{
+	struct bss *ni, *found_ni = NULL;
+	int hash;
+
+	spin_lock_bh(&nt->nt_nodelock);
+
+	hash = ATH6KL_NODE_HASH(mac_addr);
+	for (ni = nt->nt_hash[hash]; ni; ni = ni->ni_hash_next) {
+		if (memcmp(ni->ni_macaddr, mac_addr, ETH_ALEN) == 0) {
+			ni->ni_refcnt++;
+			found_ni = ni;
+			break;
+		}
+	}
+
+	spin_unlock_bh(&nt->nt_nodelock);
+
+	return found_ni;
+}
+
+void wlan_node_reclaim(struct ath6kl_node_table *nt, struct bss *ni)
+{
+	int hash;
+
+	spin_lock_bh(&nt->nt_nodelock);
+
+	if (ni->ni_list_prev == NULL)
+		/* fix list head */
+		nt->nt_node_first = ni->ni_list_next;
+	else
+		ni->ni_list_prev->ni_list_next = ni->ni_list_next;
+
+	if (ni->ni_list_next == NULL)
+		/* fix list tail */
+		nt->nt_node_last = ni->ni_list_prev;
+	else
+		ni->ni_list_next->ni_list_prev = ni->ni_list_prev;
+
+	if (ni->ni_hash_prev == NULL) {
+		/* first in list so fix the list head */
+		hash = ATH6KL_NODE_HASH(ni->ni_macaddr);
+		nt->nt_hash[hash] = ni->ni_hash_next;
+	} else {
+		ni->ni_hash_prev->ni_hash_next = ni->ni_hash_next;
+	}
+
+	if (ni->ni_hash_next != NULL)
+		ni->ni_hash_next->ni_hash_prev = ni->ni_hash_prev;
+
+	wlan_node_free(ni);
+
+	spin_unlock_bh(&nt->nt_nodelock);
+}
+
+static void wlan_node_dec_free(struct bss *ni)
+{
+	if ((ni->ni_refcnt--) == 1)
+		wlan_node_free(ni);
+}
+
+void wlan_free_allnodes(struct ath6kl_node_table *nt)
+{
+	struct bss *ni;
+
+	while ((ni = nt->nt_node_first) != NULL)
+		wlan_node_reclaim(nt, ni);
+}
+
+void wlan_iterate_nodes(struct ath6kl_node_table *nt, void *arg)
+{
+	struct bss *ni;
+
+	spin_lock_bh(&nt->nt_nodelock);
+	for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) {
+			ni->ni_refcnt++;
+			ath6kl_cfg80211_scan_node(arg, ni);
+			wlan_node_dec_free(ni);
+	}
+	spin_unlock_bh(&nt->nt_nodelock);
+}
+
+void wlan_node_table_init(struct ath6kl_node_table *nt)
+{
+	ath6kl_dbg(ATH6KL_DBG_WLAN_NODE, "node table = 0x%lx\n",
+		   (unsigned long)nt);
+
+	memset(nt, 0, sizeof(struct ath6kl_node_table));
+
+	spin_lock_init(&nt->nt_nodelock);
+
+	nt->nt_node_age = WLAN_NODE_INACT_TIMEOUT_MSEC;
+}
+
+void wlan_refresh_inactive_nodes(struct ath6kl *ar)
+{
+	struct ath6kl_node_table *nt = &ar->scan_table;
+	struct bss *bss;
+	u32 now;
+
+	now = jiffies_to_msecs(jiffies);
+	bss = nt->nt_node_first;
+	while (bss != NULL) {
+		/* refresh all nodes except the current bss */
+		if (memcmp(ar->bssid, bss->ni_macaddr, ETH_ALEN) != 0) {
+			if (((now - bss->ni_tstamp) > nt->nt_node_age)
+			    || --bss->ni_actcnt == 0) {
+				wlan_node_reclaim(nt, bss);
+			}
+		}
+		bss = bss->ni_list_next;
+	}
+}
+
+void wlan_node_table_cleanup(struct ath6kl_node_table *nt)
+{
+	wlan_free_allnodes(nt);
+}
+
+struct bss *wlan_find_ssid_node(struct ath6kl_node_table *nt, u8 * ssid,
+				u32 ssid_len, bool is_wpa2, bool match_ssid)
+{
+	struct bss *ni, *found_ni = NULL;
+	u8 *ie_ssid;
+
+	spin_lock_bh(&nt->nt_nodelock);
+
+	for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) {
+
+		ie_ssid = ni->ni_cie.ie_ssid;
+
+		if ((ie_ssid[1] <= IEEE80211_MAX_SSID_LEN) &&
+		    (memcmp(ssid, &ie_ssid[2], ssid_len) == 0)) {
+
+				if (match_ssid ||
+				    (is_wpa2 && ni->ni_cie.ie_rsn != NULL) ||
+				    (!is_wpa2 && ni->ni_cie.ie_wpa != NULL)) {
+					ni->ni_refcnt++;
+					found_ni = ni;
+					break;
+				}
+		}
+	}
+
+	spin_unlock_bh(&nt->nt_nodelock);
+
+	return found_ni;
+}
+
+void wlan_node_return(struct ath6kl_node_table *nt, struct bss *ni)
+{
+	spin_lock_bh(&nt->nt_nodelock);
+	wlan_node_dec_free(ni);
+	spin_unlock_bh(&nt->nt_nodelock);
+}
diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c
new file mode 100644
index 000000000000..34171604cbe4
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/sdio.c
@@ -0,0 +1,912 @@
+/*
+ * Copyright (c) 2004-2011 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.
+ */
+
+#include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sd.h>
+#include "htc_hif.h"
+#include "hif-ops.h"
+#include "target.h"
+#include "debug.h"
+
+struct ath6kl_sdio {
+	struct sdio_func *func;
+
+	spinlock_t lock;
+
+	/* free list */
+	struct list_head bus_req_freeq;
+
+	/* available bus requests */
+	struct bus_request bus_req[BUS_REQUEST_MAX_NUM];
+
+	struct ath6kl *ar;
+	u8 *dma_buffer;
+
+	/* scatter request list head */
+	struct list_head scat_req;
+
+	spinlock_t scat_lock;
+	bool is_disabled;
+	atomic_t irq_handling;
+	const struct sdio_device_id *id;
+	struct work_struct wr_async_work;
+	struct list_head wr_asyncq;
+	spinlock_t wr_async_lock;
+};
+
+#define CMD53_ARG_READ          0
+#define CMD53_ARG_WRITE         1
+#define CMD53_ARG_BLOCK_BASIS   1
+#define CMD53_ARG_FIXED_ADDRESS 0
+#define CMD53_ARG_INCR_ADDRESS  1
+
+static inline struct ath6kl_sdio *ath6kl_sdio_priv(struct ath6kl *ar)
+{
+	return ar->hif_priv;
+}
+
+/*
+ * Macro to check if DMA buffer is WORD-aligned and DMA-able.
+ * Most host controllers assume the buffer is DMA'able and will
+ * bug-check otherwise (i.e. buffers on the stack). virt_addr_valid
+ * check fails on stack memory.
+ */
+static inline bool buf_needs_bounce(u8 *buf)
+{
+	return ((unsigned long) buf & 0x3) || !virt_addr_valid(buf);
+}
+
+static void ath6kl_sdio_set_mbox_info(struct ath6kl *ar)
+{
+	struct ath6kl_mbox_info *mbox_info = &ar->mbox_info;
+
+	/* EP1 has an extended range */
+	mbox_info->htc_addr = HIF_MBOX_BASE_ADDR;
+	mbox_info->htc_ext_addr = HIF_MBOX0_EXT_BASE_ADDR;
+	mbox_info->htc_ext_sz = HIF_MBOX0_EXT_WIDTH;
+	mbox_info->block_size = HIF_MBOX_BLOCK_SIZE;
+	mbox_info->gmbox_addr = HIF_GMBOX_BASE_ADDR;
+	mbox_info->gmbox_sz = HIF_GMBOX_WIDTH;
+}
+
+static inline void ath6kl_sdio_set_cmd53_arg(u32 *arg, u8 rw, u8 func,
+					     u8 mode, u8 opcode, u32 addr,
+					     u16 blksz)
+{
+	*arg = (((rw & 1) << 31) |
+		((func & 0x7) << 28) |
+		((mode & 1) << 27) |
+		((opcode & 1) << 26) |
+		((addr & 0x1FFFF) << 9) |
+		(blksz & 0x1FF));
+}
+
+static inline void ath6kl_sdio_set_cmd52_arg(u32 *arg, u8 write, u8 raw,
+					     unsigned int address,
+					     unsigned char val)
+{
+	const u8 func = 0;
+
+	*arg = ((write & 1) << 31) |
+	       ((func & 0x7) << 28) |
+	       ((raw & 1) << 27) |
+	       (1 << 26) |
+	       ((address & 0x1FFFF) << 9) |
+	       (1 << 8) |
+	       (val & 0xFF);
+}
+
+static int ath6kl_sdio_func0_cmd52_wr_byte(struct mmc_card *card,
+					   unsigned int address,
+					   unsigned char byte)
+{
+	struct mmc_command io_cmd;
+
+	memset(&io_cmd, 0, sizeof(io_cmd));
+	ath6kl_sdio_set_cmd52_arg(&io_cmd.arg, 1, 0, address, byte);
+	io_cmd.opcode = SD_IO_RW_DIRECT;
+	io_cmd.flags = MMC_RSP_R5 | MMC_CMD_AC;
+
+	return mmc_wait_for_cmd(card->host, &io_cmd, 0);
+}
+
+static int ath6kl_sdio_io(struct sdio_func *func, u32 request, u32 addr,
+			  u8 *buf, u32 len)
+{
+	int ret = 0;
+
+	if (request & HIF_WRITE) {
+		if (addr >= HIF_MBOX_BASE_ADDR &&
+		    addr <= HIF_MBOX_END_ADDR)
+			addr += (HIF_MBOX_WIDTH - len);
+
+		if (addr == HIF_MBOX0_EXT_BASE_ADDR)
+			addr += HIF_MBOX0_EXT_WIDTH - len;
+
+		if (request & HIF_FIXED_ADDRESS)
+			ret = sdio_writesb(func, addr, buf, len);
+		else
+			ret = sdio_memcpy_toio(func, addr, buf, len);
+	} else {
+		if (request & HIF_FIXED_ADDRESS)
+			ret = sdio_readsb(func, buf, addr, len);
+		else
+			ret = sdio_memcpy_fromio(func, buf, addr, len);
+	}
+
+	return ret;
+}
+
+static struct bus_request *ath6kl_sdio_alloc_busreq(struct ath6kl_sdio *ar_sdio)
+{
+	struct bus_request *bus_req;
+	unsigned long flag;
+
+	spin_lock_irqsave(&ar_sdio->lock, flag);
+
+	if (list_empty(&ar_sdio->bus_req_freeq)) {
+		spin_unlock_irqrestore(&ar_sdio->lock, flag);
+		return NULL;
+	}
+
+	bus_req = list_first_entry(&ar_sdio->bus_req_freeq,
+				   struct bus_request, list);
+	list_del(&bus_req->list);
+
+	spin_unlock_irqrestore(&ar_sdio->lock, flag);
+	ath6kl_dbg(ATH6KL_DBG_TRC, "%s: bus request 0x%p\n", __func__, bus_req);
+
+	return bus_req;
+}
+
+static void ath6kl_sdio_free_bus_req(struct ath6kl_sdio *ar_sdio,
+				     struct bus_request *bus_req)
+{
+	unsigned long flag;
+
+	ath6kl_dbg(ATH6KL_DBG_TRC, "%s: bus request 0x%p\n", __func__, bus_req);
+
+	spin_lock_irqsave(&ar_sdio->lock, flag);
+	list_add_tail(&bus_req->list, &ar_sdio->bus_req_freeq);
+	spin_unlock_irqrestore(&ar_sdio->lock, flag);
+}
+
+static void ath6kl_sdio_setup_scat_data(struct hif_scatter_req *scat_req,
+					struct mmc_data *data)
+{
+	struct scatterlist *sg;
+	int i;
+
+	data->blksz = HIF_MBOX_BLOCK_SIZE;
+	data->blocks = scat_req->len / HIF_MBOX_BLOCK_SIZE;
+
+	ath6kl_dbg(ATH6KL_DBG_SCATTER,
+		   "hif-scatter: (%s) addr: 0x%X, (block len: %d, block count: %d) , (tot:%d,sg:%d)\n",
+		   (scat_req->req & HIF_WRITE) ? "WR" : "RD", scat_req->addr,
+		   data->blksz, data->blocks, scat_req->len,
+		   scat_req->scat_entries);
+
+	data->flags = (scat_req->req & HIF_WRITE) ? MMC_DATA_WRITE :
+						    MMC_DATA_READ;
+
+	/* fill SG entries */
+	sg = scat_req->sgentries;
+	sg_init_table(sg, scat_req->scat_entries);
+
+	/* assemble SG list */
+	for (i = 0; i < scat_req->scat_entries; i++, sg++) {
+		if ((unsigned long)scat_req->scat_list[i].buf & 0x3)
+			/*
+			 * Some scatter engines can handle unaligned
+			 * buffers, print this as informational only.
+			 */
+			ath6kl_dbg(ATH6KL_DBG_SCATTER,
+				   "(%s) scatter buffer is unaligned 0x%p\n",
+				   scat_req->req & HIF_WRITE ? "WR" : "RD",
+				   scat_req->scat_list[i].buf);
+
+		ath6kl_dbg(ATH6KL_DBG_SCATTER, "%d: addr:0x%p, len:%d\n",
+			   i, scat_req->scat_list[i].buf,
+			   scat_req->scat_list[i].len);
+
+		sg_set_buf(sg, scat_req->scat_list[i].buf,
+			   scat_req->scat_list[i].len);
+	}
+
+	/* set scatter-gather table for request */
+	data->sg = scat_req->sgentries;
+	data->sg_len = scat_req->scat_entries;
+}
+
+static int ath6kl_sdio_scat_rw(struct ath6kl_sdio *ar_sdio,
+			       struct bus_request *req)
+{
+	struct mmc_request mmc_req;
+	struct mmc_command cmd;
+	struct mmc_data data;
+	struct hif_scatter_req *scat_req;
+	u8 opcode, rw;
+	int status, len;
+
+	scat_req = req->scat_req;
+
+	if (scat_req->virt_scat) {
+		len = scat_req->len;
+		if (scat_req->req & HIF_BLOCK_BASIS)
+			len = round_down(len, HIF_MBOX_BLOCK_SIZE);
+
+		status = ath6kl_sdio_io(ar_sdio->func, scat_req->req,
+					scat_req->addr, scat_req->virt_dma_buf,
+					len);
+		goto scat_complete;
+	}
+
+	memset(&mmc_req, 0, sizeof(struct mmc_request));
+	memset(&cmd, 0, sizeof(struct mmc_command));
+	memset(&data, 0, sizeof(struct mmc_data));
+
+	ath6kl_sdio_setup_scat_data(scat_req, &data);
+
+	opcode = (scat_req->req & HIF_FIXED_ADDRESS) ?
+		  CMD53_ARG_FIXED_ADDRESS : CMD53_ARG_INCR_ADDRESS;
+
+	rw = (scat_req->req & HIF_WRITE) ? CMD53_ARG_WRITE : CMD53_ARG_READ;
+
+	/* Fixup the address so that the last byte will fall on MBOX EOM */
+	if (scat_req->req & HIF_WRITE) {
+		if (scat_req->addr == HIF_MBOX_BASE_ADDR)
+			scat_req->addr += HIF_MBOX_WIDTH - scat_req->len;
+		else
+			/* Uses extended address range */
+			scat_req->addr += HIF_MBOX0_EXT_WIDTH - scat_req->len;
+	}
+
+	/* set command argument */
+	ath6kl_sdio_set_cmd53_arg(&cmd.arg, rw, ar_sdio->func->num,
+				  CMD53_ARG_BLOCK_BASIS, opcode, scat_req->addr,
+				  data.blocks);
+
+	cmd.opcode = SD_IO_RW_EXTENDED;
+	cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
+
+	mmc_req.cmd = &cmd;
+	mmc_req.data = &data;
+
+	mmc_set_data_timeout(&data, ar_sdio->func->card);
+	/* synchronous call to process request */
+	mmc_wait_for_req(ar_sdio->func->card->host, &mmc_req);
+
+	status = cmd.error ? cmd.error : data.error;
+
+scat_complete:
+	scat_req->status = status;
+
+	if (scat_req->status)
+		ath6kl_err("Scatter write request failed:%d\n",
+			   scat_req->status);
+
+	if (scat_req->req & HIF_ASYNCHRONOUS)
+		scat_req->complete(ar_sdio->ar->htc_target, scat_req);
+
+	return status;
+}
+
+static int ath6kl_sdio_alloc_prep_scat_req(struct ath6kl_sdio *ar_sdio,
+					   int n_scat_entry, int n_scat_req,
+					   bool virt_scat)
+{
+	struct hif_scatter_req *s_req;
+	struct bus_request *bus_req;
+	int i, scat_req_sz, scat_list_sz, sg_sz, buf_sz;
+	u8 *virt_buf;
+
+	scat_list_sz = (n_scat_entry - 1) * sizeof(struct hif_scatter_item);
+	scat_req_sz = sizeof(*s_req) + scat_list_sz;
+
+	if (!virt_scat)
+		sg_sz = sizeof(struct scatterlist) * n_scat_entry;
+	else
+		buf_sz =  2 * L1_CACHE_BYTES +
+			  ATH6KL_MAX_TRANSFER_SIZE_PER_SCATTER;
+
+	for (i = 0; i < n_scat_req; i++) {
+		/* allocate the scatter request */
+		s_req = kzalloc(scat_req_sz, GFP_KERNEL);
+		if (!s_req)
+			return -ENOMEM;
+
+		if (virt_scat) {
+			virt_buf = kzalloc(buf_sz, GFP_KERNEL);
+			if (!virt_buf) {
+				kfree(s_req);
+				return -ENOMEM;
+			}
+
+			s_req->virt_dma_buf =
+				(u8 *)L1_CACHE_ALIGN((unsigned long)virt_buf);
+		} else {
+			/* allocate sglist */
+			s_req->sgentries = kzalloc(sg_sz, GFP_KERNEL);
+
+			if (!s_req->sgentries) {
+				kfree(s_req);
+				return -ENOMEM;
+			}
+		}
+
+		/* allocate a bus request for this scatter request */
+		bus_req = ath6kl_sdio_alloc_busreq(ar_sdio);
+		if (!bus_req) {
+			kfree(s_req->sgentries);
+			kfree(s_req->virt_dma_buf);
+			kfree(s_req);
+			return -ENOMEM;
+		}
+
+		/* assign the scatter request to this bus request */
+		bus_req->scat_req = s_req;
+		s_req->busrequest = bus_req;
+
+		s_req->virt_scat = virt_scat;
+
+		/* add it to the scatter pool */
+		hif_scatter_req_add(ar_sdio->ar, s_req);
+	}
+
+	return 0;
+}
+
+static int ath6kl_sdio_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf,
+				       u32 len, u32 request)
+{
+	struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
+	u8  *tbuf = NULL;
+	int ret;
+	bool bounced = false;
+
+	if (request & HIF_BLOCK_BASIS)
+		len = round_down(len, HIF_MBOX_BLOCK_SIZE);
+
+	if (buf_needs_bounce(buf)) {
+		if (!ar_sdio->dma_buffer)
+			return -ENOMEM;
+		tbuf = ar_sdio->dma_buffer;
+		memcpy(tbuf, buf, len);
+		bounced = true;
+	} else
+		tbuf = buf;
+
+	sdio_claim_host(ar_sdio->func);
+	ret = ath6kl_sdio_io(ar_sdio->func, request, addr, tbuf, len);
+	if ((request & HIF_READ) && bounced)
+		memcpy(buf, tbuf, len);
+	sdio_release_host(ar_sdio->func);
+
+	return ret;
+}
+
+static void __ath6kl_sdio_write_async(struct ath6kl_sdio *ar_sdio,
+				      struct bus_request *req)
+{
+	if (req->scat_req)
+		ath6kl_sdio_scat_rw(ar_sdio, req);
+	else {
+		void *context;
+		int status;
+
+		status = ath6kl_sdio_read_write_sync(ar_sdio->ar, req->address,
+						     req->buffer, req->length,
+						     req->request);
+		context = req->packet;
+		ath6kl_sdio_free_bus_req(ar_sdio, req);
+		ath6kldev_rw_comp_handler(context, status);
+	}
+}
+
+static void ath6kl_sdio_write_async_work(struct work_struct *work)
+{
+	struct ath6kl_sdio *ar_sdio;
+	unsigned long flags;
+	struct bus_request *req, *tmp_req;
+
+	ar_sdio = container_of(work, struct ath6kl_sdio, wr_async_work);
+	sdio_claim_host(ar_sdio->func);
+
+	spin_lock_irqsave(&ar_sdio->wr_async_lock, flags);
+	list_for_each_entry_safe(req, tmp_req, &ar_sdio->wr_asyncq, list) {
+		list_del(&req->list);
+		spin_unlock_irqrestore(&ar_sdio->wr_async_lock, flags);
+		__ath6kl_sdio_write_async(ar_sdio, req);
+		spin_lock_irqsave(&ar_sdio->wr_async_lock, flags);
+	}
+	spin_unlock_irqrestore(&ar_sdio->wr_async_lock, flags);
+
+	sdio_release_host(ar_sdio->func);
+}
+
+static void ath6kl_sdio_irq_handler(struct sdio_func *func)
+{
+	int status;
+	struct ath6kl_sdio *ar_sdio;
+
+	ar_sdio = sdio_get_drvdata(func);
+	atomic_set(&ar_sdio->irq_handling, 1);
+
+	/*
+	 * Release the host during interrups so we can pick it back up when
+	 * we process commands.
+	 */
+	sdio_release_host(ar_sdio->func);
+
+	status = ath6kldev_intr_bh_handler(ar_sdio->ar);
+	sdio_claim_host(ar_sdio->func);
+	atomic_set(&ar_sdio->irq_handling, 0);
+	WARN_ON(status && status != -ECANCELED);
+}
+
+static int ath6kl_sdio_power_on(struct ath6kl_sdio *ar_sdio)
+{
+	struct sdio_func *func = ar_sdio->func;
+	int ret = 0;
+
+	if (!ar_sdio->is_disabled)
+		return 0;
+
+	sdio_claim_host(func);
+
+	ret = sdio_enable_func(func);
+	if (ret) {
+		ath6kl_err("Unable to enable sdio func: %d)\n", ret);
+		sdio_release_host(func);
+		return ret;
+	}
+
+	sdio_release_host(func);
+
+	/*
+	 * Wait for hardware to initialise. It should take a lot less than
+	 * 10 ms but let's be conservative here.
+	 */
+	msleep(10);
+
+	ar_sdio->is_disabled = false;
+
+	return ret;
+}
+
+static int ath6kl_sdio_power_off(struct ath6kl_sdio *ar_sdio)
+{
+	int ret;
+
+	if (ar_sdio->is_disabled)
+		return 0;
+
+	/* Disable the card */
+	sdio_claim_host(ar_sdio->func);
+	ret = sdio_disable_func(ar_sdio->func);
+	sdio_release_host(ar_sdio->func);
+
+	if (ret)
+		return ret;
+
+	ar_sdio->is_disabled = true;
+
+	return ret;
+}
+
+static int ath6kl_sdio_write_async(struct ath6kl *ar, u32 address, u8 *buffer,
+				   u32 length, u32 request,
+				   struct htc_packet *packet)
+{
+	struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
+	struct bus_request *bus_req;
+	unsigned long flags;
+
+	bus_req = ath6kl_sdio_alloc_busreq(ar_sdio);
+
+	if (!bus_req)
+		return -ENOMEM;
+
+	bus_req->address = address;
+	bus_req->buffer = buffer;
+	bus_req->length = length;
+	bus_req->request = request;
+	bus_req->packet = packet;
+
+	spin_lock_irqsave(&ar_sdio->wr_async_lock, flags);
+	list_add_tail(&bus_req->list, &ar_sdio->wr_asyncq);
+	spin_unlock_irqrestore(&ar_sdio->wr_async_lock, flags);
+	queue_work(ar->ath6kl_wq, &ar_sdio->wr_async_work);
+
+	return 0;
+}
+
+static void ath6kl_sdio_irq_enable(struct ath6kl *ar)
+{
+	struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
+	int ret;
+
+	sdio_claim_host(ar_sdio->func);
+
+	/* Register the isr */
+	ret =  sdio_claim_irq(ar_sdio->func, ath6kl_sdio_irq_handler);
+	if (ret)
+		ath6kl_err("Failed to claim sdio irq: %d\n", ret);
+
+	sdio_release_host(ar_sdio->func);
+}
+
+static void ath6kl_sdio_irq_disable(struct ath6kl *ar)
+{
+	struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
+	int ret;
+
+	sdio_claim_host(ar_sdio->func);
+
+	/* Mask our function IRQ */
+	while (atomic_read(&ar_sdio->irq_handling)) {
+		sdio_release_host(ar_sdio->func);
+		schedule_timeout(HZ / 10);
+		sdio_claim_host(ar_sdio->func);
+	}
+
+	ret = sdio_release_irq(ar_sdio->func);
+	if (ret)
+		ath6kl_err("Failed to release sdio irq: %d\n", ret);
+
+	sdio_release_host(ar_sdio->func);
+}
+
+static struct hif_scatter_req *ath6kl_sdio_scatter_req_get(struct ath6kl *ar)
+{
+	struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
+	struct hif_scatter_req *node = NULL;
+	unsigned long flag;
+
+	spin_lock_irqsave(&ar_sdio->scat_lock, flag);
+
+	if (!list_empty(&ar_sdio->scat_req)) {
+		node = list_first_entry(&ar_sdio->scat_req,
+					struct hif_scatter_req, list);
+		list_del(&node->list);
+	}
+
+	spin_unlock_irqrestore(&ar_sdio->scat_lock, flag);
+
+	return node;
+}
+
+static void ath6kl_sdio_scatter_req_add(struct ath6kl *ar,
+					struct hif_scatter_req *s_req)
+{
+	struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
+	unsigned long flag;
+
+	spin_lock_irqsave(&ar_sdio->scat_lock, flag);
+
+	list_add_tail(&s_req->list, &ar_sdio->scat_req);
+
+	spin_unlock_irqrestore(&ar_sdio->scat_lock, flag);
+
+}
+
+/* scatter gather read write request */
+static int ath6kl_sdio_async_rw_scatter(struct ath6kl *ar,
+					struct hif_scatter_req *scat_req)
+{
+	struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
+	u32 request = scat_req->req;
+	int status = 0;
+	unsigned long flags;
+
+	if (!scat_req->len)
+		return -EINVAL;
+
+	ath6kl_dbg(ATH6KL_DBG_SCATTER,
+		"hif-scatter: total len: %d scatter entries: %d\n",
+		scat_req->len, scat_req->scat_entries);
+
+	if (request & HIF_SYNCHRONOUS) {
+		sdio_claim_host(ar_sdio->func);
+		status = ath6kl_sdio_scat_rw(ar_sdio, scat_req->busrequest);
+		sdio_release_host(ar_sdio->func);
+	} else {
+		spin_lock_irqsave(&ar_sdio->wr_async_lock, flags);
+		list_add_tail(&scat_req->busrequest->list, &ar_sdio->wr_asyncq);
+		spin_unlock_irqrestore(&ar_sdio->wr_async_lock, flags);
+		queue_work(ar->ath6kl_wq, &ar_sdio->wr_async_work);
+	}
+
+	return status;
+}
+
+/* clean up scatter support */
+static void ath6kl_sdio_cleanup_scatter(struct ath6kl *ar)
+{
+	struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
+	struct hif_scatter_req *s_req, *tmp_req;
+	unsigned long flag;
+
+	/* empty the free list */
+	spin_lock_irqsave(&ar_sdio->scat_lock, flag);
+	list_for_each_entry_safe(s_req, tmp_req, &ar_sdio->scat_req, list) {
+		list_del(&s_req->list);
+		spin_unlock_irqrestore(&ar_sdio->scat_lock, flag);
+
+		if (s_req->busrequest)
+			ath6kl_sdio_free_bus_req(ar_sdio, s_req->busrequest);
+		kfree(s_req->virt_dma_buf);
+		kfree(s_req->sgentries);
+		kfree(s_req);
+
+		spin_lock_irqsave(&ar_sdio->scat_lock, flag);
+	}
+	spin_unlock_irqrestore(&ar_sdio->scat_lock, flag);
+}
+
+/* setup of HIF scatter resources */
+static int ath6kl_sdio_enable_scatter(struct ath6kl *ar)
+{
+	struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
+	struct htc_target *target = ar->htc_target;
+	int ret;
+	bool virt_scat = false;
+
+	/* check if host supports scatter and it meets our requirements */
+	if (ar_sdio->func->card->host->max_segs < MAX_SCATTER_ENTRIES_PER_REQ) {
+		ath6kl_err("host only supports scatter of :%d entries, need: %d\n",
+			   ar_sdio->func->card->host->max_segs,
+			   MAX_SCATTER_ENTRIES_PER_REQ);
+		virt_scat = true;
+	}
+
+	if (!virt_scat) {
+		ret = ath6kl_sdio_alloc_prep_scat_req(ar_sdio,
+				MAX_SCATTER_ENTRIES_PER_REQ,
+				MAX_SCATTER_REQUESTS, virt_scat);
+
+		if (!ret) {
+			ath6kl_dbg(ATH6KL_DBG_ANY,
+				   "hif-scatter enabled: max scatter req : %d entries: %d\n",
+				   MAX_SCATTER_REQUESTS,
+				   MAX_SCATTER_ENTRIES_PER_REQ);
+
+			target->max_scat_entries = MAX_SCATTER_ENTRIES_PER_REQ;
+			target->max_xfer_szper_scatreq =
+						MAX_SCATTER_REQ_TRANSFER_SIZE;
+		} else {
+			ath6kl_sdio_cleanup_scatter(ar);
+			ath6kl_warn("hif scatter resource setup failed, trying virtual scatter method\n");
+		}
+	}
+
+	if (virt_scat || ret) {
+		ret = ath6kl_sdio_alloc_prep_scat_req(ar_sdio,
+				ATH6KL_SCATTER_ENTRIES_PER_REQ,
+				ATH6KL_SCATTER_REQS, virt_scat);
+
+		if (ret) {
+			ath6kl_err("failed to alloc virtual scatter resources !\n");
+			ath6kl_sdio_cleanup_scatter(ar);
+			return ret;
+		}
+
+		ath6kl_dbg(ATH6KL_DBG_ANY,
+			   "Vitual scatter enabled, max_scat_req:%d, entries:%d\n",
+			   ATH6KL_SCATTER_REQS, ATH6KL_SCATTER_ENTRIES_PER_REQ);
+
+		target->max_scat_entries = ATH6KL_SCATTER_ENTRIES_PER_REQ;
+		target->max_xfer_szper_scatreq =
+					ATH6KL_MAX_TRANSFER_SIZE_PER_SCATTER;
+	}
+
+	return 0;
+}
+
+static const struct ath6kl_hif_ops ath6kl_sdio_ops = {
+	.read_write_sync = ath6kl_sdio_read_write_sync,
+	.write_async = ath6kl_sdio_write_async,
+	.irq_enable = ath6kl_sdio_irq_enable,
+	.irq_disable = ath6kl_sdio_irq_disable,
+	.scatter_req_get = ath6kl_sdio_scatter_req_get,
+	.scatter_req_add = ath6kl_sdio_scatter_req_add,
+	.enable_scatter = ath6kl_sdio_enable_scatter,
+	.scat_req_rw = ath6kl_sdio_async_rw_scatter,
+	.cleanup_scatter = ath6kl_sdio_cleanup_scatter,
+};
+
+static int ath6kl_sdio_probe(struct sdio_func *func,
+			     const struct sdio_device_id *id)
+{
+	int ret;
+	struct ath6kl_sdio *ar_sdio;
+	struct ath6kl *ar;
+	int count;
+
+	ath6kl_dbg(ATH6KL_DBG_TRC,
+		   "%s: func: 0x%X, vendor id: 0x%X, dev id: 0x%X, block size: 0x%X/0x%X\n",
+		   __func__, func->num, func->vendor,
+		   func->device, func->max_blksize, func->cur_blksize);
+
+	ar_sdio = kzalloc(sizeof(struct ath6kl_sdio), GFP_KERNEL);
+	if (!ar_sdio)
+		return -ENOMEM;
+
+	ar_sdio->dma_buffer = kzalloc(HIF_DMA_BUFFER_SIZE, GFP_KERNEL);
+	if (!ar_sdio->dma_buffer) {
+		ret = -ENOMEM;
+		goto err_hif;
+	}
+
+	ar_sdio->func = func;
+	sdio_set_drvdata(func, ar_sdio);
+
+	ar_sdio->id = id;
+	ar_sdio->is_disabled = true;
+
+	spin_lock_init(&ar_sdio->lock);
+	spin_lock_init(&ar_sdio->scat_lock);
+	spin_lock_init(&ar_sdio->wr_async_lock);
+
+	INIT_LIST_HEAD(&ar_sdio->scat_req);
+	INIT_LIST_HEAD(&ar_sdio->bus_req_freeq);
+	INIT_LIST_HEAD(&ar_sdio->wr_asyncq);
+
+	INIT_WORK(&ar_sdio->wr_async_work, ath6kl_sdio_write_async_work);
+
+	for (count = 0; count < BUS_REQUEST_MAX_NUM; count++)
+		ath6kl_sdio_free_bus_req(ar_sdio, &ar_sdio->bus_req[count]);
+
+	ar = ath6kl_core_alloc(&ar_sdio->func->dev);
+	if (!ar) {
+		ath6kl_err("Failed to alloc ath6kl core\n");
+		ret = -ENOMEM;
+		goto err_dma;
+	}
+
+	ar_sdio->ar = ar;
+	ar->hif_priv = ar_sdio;
+	ar->hif_ops = &ath6kl_sdio_ops;
+
+	ath6kl_sdio_set_mbox_info(ar);
+
+	sdio_claim_host(func);
+
+	if ((ar_sdio->id->device & MANUFACTURER_ID_ATH6KL_BASE_MASK) >=
+	    MANUFACTURER_ID_AR6003_BASE) {
+		/* enable 4-bit ASYNC interrupt on AR6003 or later */
+		ret = ath6kl_sdio_func0_cmd52_wr_byte(func->card,
+						CCCR_SDIO_IRQ_MODE_REG,
+						SDIO_IRQ_MODE_ASYNC_4BIT_IRQ);
+		if (ret) {
+			ath6kl_err("Failed to enable 4-bit async irq mode %d\n",
+				   ret);
+			sdio_release_host(func);
+			goto err_dma;
+		}
+
+		ath6kl_dbg(ATH6KL_DBG_TRC, "4-bit async irq mode enabled\n");
+	}
+
+	/* give us some time to enable, in ms */
+	func->enable_timeout = 100;
+
+	sdio_release_host(func);
+
+	ret = ath6kl_sdio_power_on(ar_sdio);
+	if (ret)
+		goto err_dma;
+
+	sdio_claim_host(func);
+
+	ret = sdio_set_block_size(func, HIF_MBOX_BLOCK_SIZE);
+	if (ret) {
+		ath6kl_err("Set sdio block size %d failed: %d)\n",
+			   HIF_MBOX_BLOCK_SIZE, ret);
+		sdio_release_host(func);
+		goto err_off;
+	}
+
+	sdio_release_host(func);
+
+	ret = ath6kl_core_init(ar);
+	if (ret) {
+		ath6kl_err("Failed to init ath6kl core\n");
+		goto err_off;
+	}
+
+	return ret;
+
+err_off:
+	ath6kl_sdio_power_off(ar_sdio);
+err_dma:
+	kfree(ar_sdio->dma_buffer);
+err_hif:
+	kfree(ar_sdio);
+
+	return ret;
+}
+
+static void ath6kl_sdio_remove(struct sdio_func *func)
+{
+	struct ath6kl_sdio *ar_sdio;
+
+	ar_sdio = sdio_get_drvdata(func);
+
+	ath6kl_stop_txrx(ar_sdio->ar);
+	cancel_work_sync(&ar_sdio->wr_async_work);
+
+	ath6kl_unavail_ev(ar_sdio->ar);
+
+	ath6kl_sdio_power_off(ar_sdio);
+
+	kfree(ar_sdio->dma_buffer);
+	kfree(ar_sdio);
+}
+
+static const struct sdio_device_id ath6kl_sdio_devices[] = {
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x0))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x1))},
+	{},
+};
+
+MODULE_DEVICE_TABLE(sdio, ath6kl_sdio_devices);
+
+static struct sdio_driver ath6kl_sdio_driver = {
+	.name = "ath6kl_sdio",
+	.id_table = ath6kl_sdio_devices,
+	.probe = ath6kl_sdio_probe,
+	.remove = ath6kl_sdio_remove,
+};
+
+static int __init ath6kl_sdio_init(void)
+{
+	int ret;
+
+	ret = sdio_register_driver(&ath6kl_sdio_driver);
+	if (ret)
+		ath6kl_err("sdio driver registration failed: %d\n", ret);
+
+	return ret;
+}
+
+static void __exit ath6kl_sdio_exit(void)
+{
+	sdio_unregister_driver(&ath6kl_sdio_driver);
+}
+
+module_init(ath6kl_sdio_init);
+module_exit(ath6kl_sdio_exit);
+
+MODULE_AUTHOR("Atheros Communications, Inc.");
+MODULE_DESCRIPTION("Driver support for Atheros AR600x SDIO devices");
+MODULE_LICENSE("Dual BSD/GPL");
+
+MODULE_FIRMWARE(AR6003_REV2_OTP_FILE);
+MODULE_FIRMWARE(AR6003_REV2_FIRMWARE_FILE);
+MODULE_FIRMWARE(AR6003_REV2_PATCH_FILE);
+MODULE_FIRMWARE(AR6003_REV2_BOARD_DATA_FILE);
+MODULE_FIRMWARE(AR6003_REV2_DEFAULT_BOARD_DATA_FILE);
+MODULE_FIRMWARE(AR6003_REV3_OTP_FILE);
+MODULE_FIRMWARE(AR6003_REV3_FIRMWARE_FILE);
+MODULE_FIRMWARE(AR6003_REV3_PATCH_FILE);
+MODULE_FIRMWARE(AR6003_REV3_BOARD_DATA_FILE);
+MODULE_FIRMWARE(AR6003_REV3_DEFAULT_BOARD_DATA_FILE);
diff --git a/drivers/net/wireless/ath/ath6kl/target.h b/drivers/net/wireless/ath/ath6kl/target.h
new file mode 100644
index 000000000000..519a013c9991
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/target.h
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 2004-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 TARGET_H
+#define TARGET_H
+
+#define AR6003_BOARD_DATA_SZ		1024
+#define AR6003_BOARD_EXT_DATA_SZ	768
+
+#define RESET_CONTROL_ADDRESS		0x00000000
+#define RESET_CONTROL_COLD_RST		0x00000100
+#define RESET_CONTROL_MBOX_RST		0x00000004
+
+#define CPU_CLOCK_STANDARD_S		0
+#define CPU_CLOCK_STANDARD		0x00000003
+#define CPU_CLOCK_ADDRESS		0x00000020
+
+#define CLOCK_CONTROL_ADDRESS		0x00000028
+#define CLOCK_CONTROL_LF_CLK32_S	2
+#define CLOCK_CONTROL_LF_CLK32		0x00000004
+
+#define SYSTEM_SLEEP_ADDRESS		0x000000c4
+#define SYSTEM_SLEEP_DISABLE_S		0
+#define SYSTEM_SLEEP_DISABLE		0x00000001
+
+#define LPO_CAL_ADDRESS			0x000000e0
+#define LPO_CAL_ENABLE_S		20
+#define LPO_CAL_ENABLE			0x00100000
+
+#define GPIO_PIN10_ADDRESS		0x00000050
+#define GPIO_PIN11_ADDRESS		0x00000054
+#define GPIO_PIN12_ADDRESS		0x00000058
+#define GPIO_PIN13_ADDRESS		0x0000005c
+
+#define HOST_INT_STATUS_ADDRESS		0x00000400
+#define HOST_INT_STATUS_ERROR_S		7
+#define HOST_INT_STATUS_ERROR		0x00000080
+
+#define HOST_INT_STATUS_CPU_S		6
+#define HOST_INT_STATUS_CPU		0x00000040
+
+#define HOST_INT_STATUS_COUNTER_S	4
+#define HOST_INT_STATUS_COUNTER		0x00000010
+
+#define CPU_INT_STATUS_ADDRESS		0x00000401
+
+#define ERROR_INT_STATUS_ADDRESS	0x00000402
+#define ERROR_INT_STATUS_WAKEUP_S	2
+#define ERROR_INT_STATUS_WAKEUP		0x00000004
+
+#define ERROR_INT_STATUS_RX_UNDERFLOW_S	1
+#define ERROR_INT_STATUS_RX_UNDERFLOW	0x00000002
+
+#define ERROR_INT_STATUS_TX_OVERFLOW_S	0
+#define ERROR_INT_STATUS_TX_OVERFLOW	0x00000001
+
+#define COUNTER_INT_STATUS_ADDRESS	0x00000403
+#define COUNTER_INT_STATUS_COUNTER_S	0
+#define COUNTER_INT_STATUS_COUNTER	0x000000ff
+
+#define RX_LOOKAHEAD_VALID_ADDRESS	0x00000405
+
+#define INT_STATUS_ENABLE_ADDRESS	0x00000418
+#define INT_STATUS_ENABLE_ERROR_S	7
+#define INT_STATUS_ENABLE_ERROR		0x00000080
+
+#define INT_STATUS_ENABLE_CPU_S		6
+#define INT_STATUS_ENABLE_CPU		0x00000040
+
+#define INT_STATUS_ENABLE_INT_S		5
+#define INT_STATUS_ENABLE_INT		0x00000020
+#define INT_STATUS_ENABLE_COUNTER_S	4
+#define INT_STATUS_ENABLE_COUNTER	0x00000010
+
+#define INT_STATUS_ENABLE_MBOX_DATA_S	0
+#define INT_STATUS_ENABLE_MBOX_DATA	0x0000000f
+
+#define CPU_INT_STATUS_ENABLE_ADDRESS	0x00000419
+#define CPU_INT_STATUS_ENABLE_BIT_S	0
+#define CPU_INT_STATUS_ENABLE_BIT	0x000000ff
+
+#define ERROR_STATUS_ENABLE_ADDRESS		0x0000041a
+#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_S	1
+#define ERROR_STATUS_ENABLE_RX_UNDERFLOW	0x00000002
+
+#define ERROR_STATUS_ENABLE_TX_OVERFLOW_S	0
+#define ERROR_STATUS_ENABLE_TX_OVERFLOW		0x00000001
+
+#define COUNTER_INT_STATUS_ENABLE_ADDRESS	0x0000041b
+#define COUNTER_INT_STATUS_ENABLE_BIT_S		0
+#define COUNTER_INT_STATUS_ENABLE_BIT		0x000000ff
+
+#define COUNT_ADDRESS			0x00000420
+
+#define COUNT_DEC_ADDRESS		0x00000440
+
+#define WINDOW_DATA_ADDRESS		0x00000474
+#define WINDOW_WRITE_ADDR_ADDRESS	0x00000478
+#define WINDOW_READ_ADDR_ADDRESS	0x0000047c
+#define CPU_DBG_SEL_ADDRESS		0x00000483
+#define CPU_DBG_ADDRESS			0x00000484
+
+#define LOCAL_SCRATCH_ADDRESS		0x000000c0
+#define ATH6KL_OPTION_SLEEP_DISABLE	0x08
+
+#define RTC_BASE_ADDRESS		0x00004000
+#define GPIO_BASE_ADDRESS		0x00014000
+#define MBOX_BASE_ADDRESS		0x00018000
+#define ANALOG_INTF_BASE_ADDRESS	0x0001c000
+
+/* real name of the register is unknown */
+#define ATH6KL_ANALOG_PLL_REGISTER	(ANALOG_INTF_BASE_ADDRESS + 0x284)
+
+#define SM(f, v)	(((v) << f##_S) & f)
+#define MS(f, v)	(((v) & f) >> f##_S)
+
+/*
+ * xxx_HOST_INTEREST_ADDRESS is the address in Target RAM of the
+ * host_interest structure.
+ *
+ * Host Interest is shared between Host and Target in order to coordinate
+ * between the two, and is intended to remain constant (with additions only
+ * at the end).
+ */
+#define ATH6KL_HI_START_ADDR           0x00540600
+
+/*
+ * These are items that the Host may need to access
+ * via BMI or via the Diagnostic Window. The position
+ * of items in this structure must remain constant.
+ * across firmware revisions!
+ *
+ * Types for each item must be fixed size across target and host platforms.
+ * The structure is used only to calculate offset for each register with
+ * HI_ITEM() macro, no values are stored to it.
+ *
+ * More items may be added at the end.
+ */
+struct host_interest {
+	/*
+	 * Pointer to application-defined area, if any.
+	 * Set by Target application during startup.
+	 */
+	u32 hi_app_host_interest;                      /* 0x00 */
+
+	/* Pointer to register dump area, valid after Target crash. */
+	u32 hi_failure_state;                          /* 0x04 */
+
+	/* Pointer to debug logging header */
+	u32 hi_dbglog_hdr;                             /* 0x08 */
+
+	u32 hi_unused1;                       /* 0x0c */
+
+	/*
+	 * General-purpose flag bits, similar to ATH6KL_OPTION_* flags.
+	 * Can be used by application rather than by OS.
+	 */
+	u32 hi_option_flag;                            /* 0x10 */
+
+	/*
+	 * Boolean that determines whether or not to
+	 * display messages on the serial port.
+	 */
+	u32 hi_serial_enable;                          /* 0x14 */
+
+	/* Start address of DataSet index, if any */
+	u32 hi_dset_list_head;                         /* 0x18 */
+
+	/* Override Target application start address */
+	u32 hi_app_start;                              /* 0x1c */
+
+	/* Clock and voltage tuning */
+	u32 hi_skip_clock_init;                        /* 0x20 */
+	u32 hi_core_clock_setting;                     /* 0x24 */
+	u32 hi_cpu_clock_setting;                      /* 0x28 */
+	u32 hi_system_sleep_setting;                   /* 0x2c */
+	u32 hi_xtal_control_setting;                   /* 0x30 */
+	u32 hi_pll_ctrl_setting_24ghz;                 /* 0x34 */
+	u32 hi_pll_ctrl_setting_5ghz;                  /* 0x38 */
+	u32 hi_ref_voltage_trim_setting;               /* 0x3c */
+	u32 hi_clock_info;                             /* 0x40 */
+
+	/*
+	 * Flash configuration overrides, used only
+	 * when firmware is not executing from flash.
+	 * (When using flash, modify the global variables
+	 * with equivalent names.)
+	 */
+	u32 hi_bank0_addr_value;                       /* 0x44 */
+	u32 hi_bank0_read_value;                       /* 0x48 */
+	u32 hi_bank0_write_value;                      /* 0x4c */
+	u32 hi_bank0_config_value;                     /* 0x50 */
+
+	/* Pointer to Board Data  */
+	u32 hi_board_data;                             /* 0x54 */
+	u32 hi_board_data_initialized;                 /* 0x58 */
+
+	u32 hi_dset_ram_index_tbl;                     /* 0x5c */
+
+	u32 hi_desired_baud_rate;                      /* 0x60 */
+	u32 hi_dbglog_config;                          /* 0x64 */
+	u32 hi_end_ram_reserve_sz;                     /* 0x68 */
+	u32 hi_mbox_io_block_sz;                       /* 0x6c */
+
+	u32 hi_num_bpatch_streams;                     /* 0x70 -- unused */
+	u32 hi_mbox_isr_yield_limit;                   /* 0x74 */
+
+	u32 hi_refclk_hz;                              /* 0x78 */
+	u32 hi_ext_clk_detected;                       /* 0x7c */
+	u32 hi_dbg_uart_txpin;                         /* 0x80 */
+	u32 hi_dbg_uart_rxpin;                         /* 0x84 */
+	u32 hi_hci_uart_baud;                          /* 0x88 */
+	u32 hi_hci_uart_pin_assignments;               /* 0x8C */
+	/*
+	 * NOTE: byte [0] = tx pin, [1] = rx pin, [2] = rts pin, [3] = cts
+	 * pin
+	 */
+	u32 hi_hci_uart_baud_scale_val;                /* 0x90 */
+	u32 hi_hci_uart_baud_step_val;                 /* 0x94 */
+
+	u32 hi_allocram_start;                         /* 0x98 */
+	u32 hi_allocram_sz;                            /* 0x9c */
+	u32 hi_hci_bridge_flags;                       /* 0xa0 */
+	u32 hi_hci_uart_support_pins;                  /* 0xa4 */
+	/*
+	 * NOTE: byte [0] = RESET pin (bit 7 is polarity),
+	 * bytes[1]..bytes[3] are for future use
+	 */
+	u32 hi_hci_uart_pwr_mgmt_params;               /* 0xa8 */
+	/*
+	 * 0xa8   - [1]: 0 = UART FC active low, 1 = UART FC active high
+	 *      [31:16]: wakeup timeout in ms
+	 */
+
+	/* Pointer to extended board data */
+	u32 hi_board_ext_data;                /* 0xac */
+	u32 hi_board_ext_data_config;         /* 0xb0 */
+
+	/*
+	 * Bit [0]  :   valid
+	 * Bit[31:16:   size
+	 */
+	/*
+	 * hi_reset_flag is used to do some stuff when target reset.
+	 * such as restore app_start after warm reset or
+	 * preserve host Interest area, or preserve ROM data, literals etc.
+	 */
+	u32 hi_reset_flag;                            /* 0xb4 */
+	/* indicate hi_reset_flag is valid */
+	u32 hi_reset_flag_valid;                      /* 0xb8 */
+	u32 hi_hci_uart_pwr_mgmt_params_ext;           /* 0xbc */
+	/*
+	 * 0xbc - [31:0]: idle timeout in ms
+	 */
+	/* ACS flags */
+	u32 hi_acs_flags;                              /* 0xc0 */
+	u32 hi_console_flags;                          /* 0xc4 */
+	u32 hi_nvram_state;                            /* 0xc8 */
+	u32 hi_option_flag2;                           /* 0xcc */
+
+	/* If non-zero, override values sent to Host in WMI_READY event. */
+	u32 hi_sw_version_override;                    /* 0xd0 */
+	u32 hi_abi_version_override;                   /* 0xd4 */
+
+	/*
+	 * Percentage of high priority RX traffic to total expected RX traffic -
+	 * applicable only to ar6004
+	 */
+	u32 hi_hp_rx_traffic_ratio;                    /* 0xd8 */
+
+	/* test applications flags */
+	u32 hi_test_apps_related    ;                  /* 0xdc */
+	/* location of test script */
+	u32 hi_ota_testscript;                         /* 0xe0 */
+	/* location of CAL data */
+	u32 hi_cal_data;                               /* 0xe4 */
+	/* Number of packet log buffers */
+	u32 hi_pktlog_num_buffers;                     /* 0xe8 */
+
+} __packed;
+
+#define HI_ITEM(item)  offsetof(struct host_interest, item)
+
+#define HI_OPTION_MAC_ADDR_METHOD_SHIFT	3
+
+#define HI_OPTION_FW_MODE_IBSS    0x0
+#define HI_OPTION_FW_MODE_BSS_STA 0x1
+#define HI_OPTION_FW_MODE_AP      0x2
+
+#define HI_OPTION_NUM_DEV_SHIFT   0x9
+
+#define HI_OPTION_FW_BRIDGE_SHIFT 0x04
+
+/* Fw Mode/SubMode Mask
+|------------------------------------------------------------------------------|
+|   SUB   |   SUB   |   SUB   |  SUB    |         |         |         |
+| MODE[3] | MODE[2] | MODE[1] | MODE[0] | MODE[3] | MODE[2] | MODE[1] | MODE[0|
+|   (2)   |   (2)   |   (2)   |   (2)   |   (2)   |   (2)   |   (2)   |   (2)
+|------------------------------------------------------------------------------|
+*/
+#define HI_OPTION_FW_MODE_SHIFT        0xC
+
+/* Convert a Target virtual address into a Target physical address */
+#define TARG_VTOP(vaddr)   (vaddr & 0x001fffff)
+
+#define AR6003_REV2_APP_START_OVERRIDE          0x944C00
+#define AR6003_REV2_APP_LOAD_ADDRESS            0x543180
+#define AR6003_REV2_BOARD_EXT_DATA_ADDRESS      0x57E500
+#define AR6003_REV2_DATASET_PATCH_ADDRESS       0x57e884
+#define AR6003_REV2_RAM_RESERVE_SIZE            6912
+
+#define AR6003_REV3_APP_START_OVERRIDE          0x945d00
+#define AR6003_REV3_APP_LOAD_ADDRESS            0x545000
+#define AR6003_REV3_BOARD_EXT_DATA_ADDRESS      0x542330
+#define AR6003_REV3_DATASET_PATCH_ADDRESS       0x57FF74
+#define AR6003_REV3_RAM_RESERVE_SIZE            512
+
+#endif
diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c
new file mode 100644
index 000000000000..167bdb9cf68d
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/txrx.c
@@ -0,0 +1,1457 @@
+/*
+ * Copyright (c) 2004-2011 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.
+ */
+
+#include "core.h"
+#include "debug.h"
+
+static u8 ath6kl_ibss_map_epid(struct sk_buff *skb, struct net_device *dev,
+			       u32 *map_no)
+{
+	struct ath6kl *ar = ath6kl_priv(dev);
+	struct ethhdr *eth_hdr;
+	u32 i, ep_map = -1;
+	u8 *datap;
+
+	*map_no = 0;
+	datap = skb->data;
+	eth_hdr = (struct ethhdr *) (datap + sizeof(struct wmi_data_hdr));
+
+	if (is_multicast_ether_addr(eth_hdr->h_dest))
+		return ENDPOINT_2;
+
+	for (i = 0; i < ar->node_num; i++) {
+		if (memcmp(eth_hdr->h_dest, ar->node_map[i].mac_addr,
+			   ETH_ALEN) == 0) {
+			*map_no = i + 1;
+			ar->node_map[i].tx_pend++;
+			return ar->node_map[i].ep_id;
+		}
+
+		if ((ep_map == -1) && !ar->node_map[i].tx_pend)
+			ep_map = i;
+	}
+
+	if (ep_map == -1) {
+		ep_map = ar->node_num;
+		ar->node_num++;
+		if (ar->node_num > MAX_NODE_NUM)
+			return ENDPOINT_UNUSED;
+	}
+
+	memcpy(ar->node_map[ep_map].mac_addr, eth_hdr->h_dest, ETH_ALEN);
+
+	for (i = ENDPOINT_2; i <= ENDPOINT_5; i++) {
+		if (!ar->tx_pending[i]) {
+			ar->node_map[ep_map].ep_id = i;
+			break;
+		}
+
+		/*
+		 * No free endpoint is available, start redistribution on
+		 * the inuse endpoints.
+		 */
+		if (i == ENDPOINT_5) {
+			ar->node_map[ep_map].ep_id = ar->next_ep_id;
+			ar->next_ep_id++;
+			if (ar->next_ep_id > ENDPOINT_5)
+				ar->next_ep_id = ENDPOINT_2;
+		}
+	}
+
+	*map_no = ep_map + 1;
+	ar->node_map[ep_map].tx_pend++;
+
+	return ar->node_map[ep_map].ep_id;
+}
+
+static bool ath6kl_powersave_ap(struct ath6kl *ar, struct sk_buff *skb,
+				bool *more_data)
+{
+	struct ethhdr *datap = (struct ethhdr *) skb->data;
+	struct ath6kl_sta *conn = NULL;
+	bool ps_queued = false, is_psq_empty = false;
+
+	if (is_multicast_ether_addr(datap->h_dest)) {
+		u8 ctr = 0;
+		bool q_mcast = false;
+
+		for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) {
+			if (ar->sta_list[ctr].sta_flags & STA_PS_SLEEP) {
+				q_mcast = true;
+				break;
+			}
+		}
+
+		if (q_mcast) {
+			/*
+			 * If this transmit is not because of a Dtim Expiry
+			 * q it.
+			 */
+			if (!test_bit(DTIM_EXPIRED, &ar->flag)) {
+				bool is_mcastq_empty = false;
+
+				spin_lock_bh(&ar->mcastpsq_lock);
+				is_mcastq_empty =
+					skb_queue_empty(&ar->mcastpsq);
+				skb_queue_tail(&ar->mcastpsq, skb);
+				spin_unlock_bh(&ar->mcastpsq_lock);
+
+				/*
+				 * If this is the first Mcast pkt getting
+				 * queued indicate to the target to set the
+				 * BitmapControl LSB of the TIM IE.
+				 */
+				if (is_mcastq_empty)
+					ath6kl_wmi_set_pvb_cmd(ar->wmi,
+							       MCAST_AID, 1);
+
+				ps_queued = true;
+			} else {
+				/*
+				 * This transmit is because of Dtim expiry.
+				 * Determine if MoreData bit has to be set.
+				 */
+				spin_lock_bh(&ar->mcastpsq_lock);
+				if (!skb_queue_empty(&ar->mcastpsq))
+					*more_data = true;
+				spin_unlock_bh(&ar->mcastpsq_lock);
+			}
+		}
+	} else {
+		conn = ath6kl_find_sta(ar, datap->h_dest);
+		if (!conn) {
+			dev_kfree_skb(skb);
+
+			/* Inform the caller that the skb is consumed */
+			return true;
+		}
+
+		if (conn->sta_flags & STA_PS_SLEEP) {
+			if (!(conn->sta_flags & STA_PS_POLLED)) {
+				/* Queue the frames if the STA is sleeping */
+				spin_lock_bh(&conn->psq_lock);
+				is_psq_empty = skb_queue_empty(&conn->psq);
+				skb_queue_tail(&conn->psq, skb);
+				spin_unlock_bh(&conn->psq_lock);
+
+				/*
+				 * If this is the first pkt getting queued
+				 * for this STA, update the PVB for this
+				 * STA.
+				 */
+				if (is_psq_empty)
+					ath6kl_wmi_set_pvb_cmd(ar->wmi,
+							       conn->aid, 1);
+
+				ps_queued = true;
+			} else {
+				/*
+				 * This tx is because of a PsPoll.
+				 * Determine if MoreData bit has to be set.
+				 */
+				spin_lock_bh(&conn->psq_lock);
+				if (!skb_queue_empty(&conn->psq))
+					*more_data = true;
+				spin_unlock_bh(&conn->psq_lock);
+			}
+		}
+	}
+
+	return ps_queued;
+}
+
+/* Tx functions */
+
+int ath6kl_control_tx(void *devt, struct sk_buff *skb,
+		      enum htc_endpoint_id eid)
+{
+	struct ath6kl *ar = devt;
+	int status = 0;
+	struct ath6kl_cookie *cookie = NULL;
+
+	spin_lock_bh(&ar->lock);
+
+	ath6kl_dbg(ATH6KL_DBG_WLAN_TX,
+		   "%s: skb=0x%p, len=0x%x eid =%d\n", __func__,
+		   skb, skb->len, eid);
+
+	if (test_bit(WMI_CTRL_EP_FULL, &ar->flag) && (eid == ar->ctrl_ep)) {
+		/*
+		 * Control endpoint is full, don't allocate resources, we
+		 * are just going to drop this packet.
+		 */
+		cookie = NULL;
+		ath6kl_err("wmi ctrl ep full, dropping pkt : 0x%p, len:%d\n",
+			   skb, skb->len);
+	} else
+		cookie = ath6kl_alloc_cookie(ar);
+
+	if (cookie == NULL) {
+		spin_unlock_bh(&ar->lock);
+		status = -ENOMEM;
+		goto fail_ctrl_tx;
+	}
+
+	ar->tx_pending[eid]++;
+
+	if (eid != ar->ctrl_ep)
+		ar->total_tx_data_pend++;
+
+	spin_unlock_bh(&ar->lock);
+
+	cookie->skb = skb;
+	cookie->map_no = 0;
+	set_htc_pkt_info(&cookie->htc_pkt, cookie, skb->data, skb->len,
+			 eid, ATH6KL_CONTROL_PKT_TAG);
+
+	/*
+	 * This interface is asynchronous, if there is an error, cleanup
+	 * will happen in the TX completion callback.
+	 */
+	ath6kl_htc_tx(ar->htc_target, &cookie->htc_pkt);
+
+	return 0;
+
+fail_ctrl_tx:
+	dev_kfree_skb(skb);
+	return status;
+}
+
+int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ath6kl *ar = ath6kl_priv(dev);
+	struct ath6kl_cookie *cookie = NULL;
+	enum htc_endpoint_id eid = ENDPOINT_UNUSED;
+	u32 map_no = 0;
+	u16 htc_tag = ATH6KL_DATA_PKT_TAG;
+	u8 ac = 99 ; /* initialize to unmapped ac */
+	bool chk_adhoc_ps_mapping = false, more_data = false;
+	struct wmi_tx_meta_v2 meta_v2;
+	int ret;
+
+	ath6kl_dbg(ATH6KL_DBG_WLAN_TX,
+		   "%s: skb=0x%p, data=0x%p, len=0x%x\n", __func__,
+		   skb, skb->data, skb->len);
+
+	/* If target is not associated */
+	if (!test_bit(CONNECTED, &ar->flag)) {
+		dev_kfree_skb(skb);
+		return 0;
+	}
+
+	if (!test_bit(WMI_READY, &ar->flag))
+		goto fail_tx;
+
+	/* AP mode Power saving processing */
+	if (ar->nw_type == AP_NETWORK) {
+		if (ath6kl_powersave_ap(ar, skb, &more_data))
+			return 0;
+	}
+
+	if (test_bit(WMI_ENABLED, &ar->flag)) {
+		memset(&meta_v2, 0, sizeof(meta_v2));
+
+		if (skb_headroom(skb) < dev->needed_headroom) {
+			WARN_ON(1);
+			goto fail_tx;
+		}
+
+		if (ath6kl_wmi_dix_2_dot3(ar->wmi, skb)) {
+			ath6kl_err("ath6kl_wmi_dix_2_dot3 failed\n");
+			goto fail_tx;
+		}
+
+		if (ath6kl_wmi_data_hdr_add(ar->wmi, skb, DATA_MSGTYPE,
+					    more_data, 0, 0, NULL)) {
+			ath6kl_err("wmi_data_hdr_add failed\n");
+			goto fail_tx;
+		}
+
+		if ((ar->nw_type == ADHOC_NETWORK) &&
+		     ar->ibss_ps_enable && test_bit(CONNECTED, &ar->flag))
+			chk_adhoc_ps_mapping = true;
+		else {
+			/* get the stream mapping */
+			ret = ath6kl_wmi_implicit_create_pstream(ar->wmi, skb,
+				    0, test_bit(WMM_ENABLED, &ar->flag), &ac);
+			if (ret)
+				goto fail_tx;
+		}
+	} else
+		goto fail_tx;
+
+	spin_lock_bh(&ar->lock);
+
+	if (chk_adhoc_ps_mapping)
+		eid = ath6kl_ibss_map_epid(skb, dev, &map_no);
+	else
+		eid = ar->ac2ep_map[ac];
+
+	if (eid == 0 || eid == ENDPOINT_UNUSED) {
+		ath6kl_err("eid %d is not mapped!\n", eid);
+		spin_unlock_bh(&ar->lock);
+		goto fail_tx;
+	}
+
+	/* allocate resource for this packet */
+	cookie = ath6kl_alloc_cookie(ar);
+
+	if (!cookie) {
+		spin_unlock_bh(&ar->lock);
+		goto fail_tx;
+	}
+
+	/* update counts while the lock is held */
+	ar->tx_pending[eid]++;
+	ar->total_tx_data_pend++;
+
+	spin_unlock_bh(&ar->lock);
+
+	cookie->skb = skb;
+	cookie->map_no = map_no;
+	set_htc_pkt_info(&cookie->htc_pkt, cookie, skb->data, skb->len,
+			 eid, htc_tag);
+
+	ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, skb->data, skb->len);
+
+	/*
+	 * HTC interface is asynchronous, if this fails, cleanup will
+	 * happen in the ath6kl_tx_complete callback.
+	 */
+	ath6kl_htc_tx(ar->htc_target, &cookie->htc_pkt);
+
+	return 0;
+
+fail_tx:
+	dev_kfree_skb(skb);
+
+	ar->net_stats.tx_dropped++;
+	ar->net_stats.tx_aborted_errors++;
+
+	return 0;
+}
+
+/* indicate tx activity or inactivity on a WMI stream */
+void ath6kl_indicate_tx_activity(void *devt, u8 traffic_class, bool active)
+{
+	struct ath6kl *ar = devt;
+	enum htc_endpoint_id eid;
+	int i;
+
+	eid = ar->ac2ep_map[traffic_class];
+
+	if (!test_bit(WMI_ENABLED, &ar->flag))
+		goto notify_htc;
+
+	spin_lock_bh(&ar->lock);
+
+	ar->ac_stream_active[traffic_class] = active;
+
+	if (active) {
+		/*
+		 * Keep track of the active stream with the highest
+		 * priority.
+		 */
+		if (ar->ac_stream_pri_map[traffic_class] >
+		    ar->hiac_stream_active_pri)
+			/* set the new highest active priority */
+			ar->hiac_stream_active_pri =
+					ar->ac_stream_pri_map[traffic_class];
+
+	} else {
+		/*
+		 * We may have to search for the next active stream
+		 * that is the highest priority.
+		 */
+		if (ar->hiac_stream_active_pri ==
+			ar->ac_stream_pri_map[traffic_class]) {
+			/*
+			 * The highest priority stream just went inactive
+			 * reset and search for the "next" highest "active"
+			 * priority stream.
+			 */
+			ar->hiac_stream_active_pri = 0;
+
+			for (i = 0; i < WMM_NUM_AC; i++) {
+				if (ar->ac_stream_active[i] &&
+				    (ar->ac_stream_pri_map[i] >
+				     ar->hiac_stream_active_pri))
+					/*
+					 * Set the new highest active
+					 * priority.
+					 */
+					ar->hiac_stream_active_pri =
+						ar->ac_stream_pri_map[i];
+			}
+		}
+	}
+
+	spin_unlock_bh(&ar->lock);
+
+notify_htc:
+	/* notify HTC, this may cause credit distribution changes */
+	ath6kl_htc_indicate_activity_change(ar->htc_target, eid, active);
+}
+
+enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
+					       struct htc_packet *packet)
+{
+	struct ath6kl *ar = target->dev->ar;
+	enum htc_endpoint_id endpoint = packet->endpoint;
+
+	if (endpoint == ar->ctrl_ep) {
+		/*
+		 * Under normal WMI if this is getting full, then something
+		 * is running rampant the host should not be exhausting the
+		 * WMI queue with too many commands the only exception to
+		 * this is during testing using endpointping.
+		 */
+		spin_lock_bh(&ar->lock);
+		set_bit(WMI_CTRL_EP_FULL, &ar->flag);
+		spin_unlock_bh(&ar->lock);
+		ath6kl_err("wmi ctrl ep is full\n");
+		return HTC_SEND_FULL_KEEP;
+	}
+
+	if (packet->info.tx.tag == ATH6KL_CONTROL_PKT_TAG)
+		return HTC_SEND_FULL_KEEP;
+
+	if (ar->nw_type == ADHOC_NETWORK)
+		/*
+		 * In adhoc mode, we cannot differentiate traffic
+		 * priorities so there is no need to continue, however we
+		 * should stop the network.
+		 */
+		goto stop_net_queues;
+
+	/*
+	 * The last MAX_HI_COOKIE_NUM "batch" of cookies are reserved for
+	 * the highest active stream.
+	 */
+	if (ar->ac_stream_pri_map[ar->ep2ac_map[endpoint]] <
+	    ar->hiac_stream_active_pri &&
+	    ar->cookie_count <= MAX_HI_COOKIE_NUM)
+		/*
+		 * Give preference to the highest priority stream by
+		 * dropping the packets which overflowed.
+		 */
+		return HTC_SEND_FULL_DROP;
+
+stop_net_queues:
+	spin_lock_bh(&ar->lock);
+	set_bit(NETQ_STOPPED, &ar->flag);
+	spin_unlock_bh(&ar->lock);
+	netif_stop_queue(ar->net_dev);
+
+	return HTC_SEND_FULL_KEEP;
+}
+
+/* TODO this needs to be looked at */
+static void ath6kl_tx_clear_node_map(struct ath6kl *ar,
+				     enum htc_endpoint_id eid, u32 map_no)
+{
+	u32 i;
+
+	if (ar->nw_type != ADHOC_NETWORK)
+		return;
+
+	if (!ar->ibss_ps_enable)
+		return;
+
+	if (eid == ar->ctrl_ep)
+		return;
+
+	if (map_no == 0)
+		return;
+
+	map_no--;
+	ar->node_map[map_no].tx_pend--;
+
+	if (ar->node_map[map_no].tx_pend)
+		return;
+
+	if (map_no != (ar->node_num - 1))
+		return;
+
+	for (i = ar->node_num; i > 0; i--) {
+		if (ar->node_map[i - 1].tx_pend)
+			break;
+
+		memset(&ar->node_map[i - 1], 0,
+		       sizeof(struct ath6kl_node_mapping));
+		ar->node_num--;
+	}
+}
+
+void ath6kl_tx_complete(void *context, struct list_head *packet_queue)
+{
+	struct ath6kl *ar = context;
+	struct sk_buff_head skb_queue;
+	struct htc_packet *packet;
+	struct sk_buff *skb;
+	struct ath6kl_cookie *ath6kl_cookie;
+	u32 map_no = 0;
+	int status;
+	enum htc_endpoint_id eid;
+	bool wake_event = false;
+	bool flushing = false;
+
+	skb_queue_head_init(&skb_queue);
+
+	/* lock the driver as we update internal state */
+	spin_lock_bh(&ar->lock);
+
+	/* reap completed packets */
+	while (!list_empty(packet_queue)) {
+
+		packet = list_first_entry(packet_queue, struct htc_packet,
+					  list);
+		list_del(&packet->list);
+
+		ath6kl_cookie = (struct ath6kl_cookie *)packet->pkt_cntxt;
+		if (!ath6kl_cookie)
+			goto fatal;
+
+		status = packet->status;
+		skb = ath6kl_cookie->skb;
+		eid = packet->endpoint;
+		map_no = ath6kl_cookie->map_no;
+
+		if (!skb || !skb->data)
+			goto fatal;
+
+		packet->buf = skb->data;
+
+		__skb_queue_tail(&skb_queue, skb);
+
+		if (!status && (packet->act_len != skb->len))
+			goto fatal;
+
+		ar->tx_pending[eid]--;
+
+		if (eid != ar->ctrl_ep)
+			ar->total_tx_data_pend--;
+
+		if (eid == ar->ctrl_ep) {
+			if (test_bit(WMI_CTRL_EP_FULL, &ar->flag))
+				clear_bit(WMI_CTRL_EP_FULL, &ar->flag);
+
+			if (ar->tx_pending[eid] == 0)
+				wake_event = true;
+		}
+
+		if (status) {
+			if (status == -ECANCELED)
+				/* a packet was flushed  */
+				flushing = true;
+
+			ar->net_stats.tx_errors++;
+
+			if (status != -ENOSPC)
+				ath6kl_err("tx error, status: 0x%x\n", status);
+			ath6kl_dbg(ATH6KL_DBG_WLAN_TX,
+				   "%s: skb=0x%p data=0x%p len=0x%x eid=%d %s\n",
+				   __func__, skb, packet->buf, packet->act_len,
+				   eid, "error!");
+		} else {
+			ath6kl_dbg(ATH6KL_DBG_WLAN_TX,
+				   "%s: skb=0x%p data=0x%p len=0x%x eid=%d %s\n",
+				   __func__, skb, packet->buf, packet->act_len,
+				   eid, "OK");
+
+			flushing = false;
+			ar->net_stats.tx_packets++;
+			ar->net_stats.tx_bytes += skb->len;
+		}
+
+		ath6kl_tx_clear_node_map(ar, eid, map_no);
+
+		ath6kl_free_cookie(ar, ath6kl_cookie);
+
+		if (test_bit(NETQ_STOPPED, &ar->flag))
+			clear_bit(NETQ_STOPPED, &ar->flag);
+	}
+
+	spin_unlock_bh(&ar->lock);
+
+	__skb_queue_purge(&skb_queue);
+
+	if (test_bit(CONNECTED, &ar->flag)) {
+		if (!flushing)
+			netif_wake_queue(ar->net_dev);
+	}
+
+	if (wake_event)
+		wake_up(&ar->event_wq);
+
+	return;
+
+fatal:
+	WARN_ON(1);
+	spin_unlock_bh(&ar->lock);
+	return;
+}
+
+void ath6kl_tx_data_cleanup(struct ath6kl *ar)
+{
+	int i;
+
+	/* flush all the data (non-control) streams */
+	for (i = 0; i < WMM_NUM_AC; i++)
+		ath6kl_htc_flush_txep(ar->htc_target, ar->ac2ep_map[i],
+				      ATH6KL_DATA_PKT_TAG);
+}
+
+/* Rx functions */
+
+static void ath6kl_deliver_frames_to_nw_stack(struct net_device *dev,
+					      struct sk_buff *skb)
+{
+	if (!skb)
+		return;
+
+	skb->dev = dev;
+
+	if (!(skb->dev->flags & IFF_UP)) {
+		dev_kfree_skb(skb);
+		return;
+	}
+
+	skb->protocol = eth_type_trans(skb, skb->dev);
+
+	netif_rx_ni(skb);
+}
+
+static void ath6kl_alloc_netbufs(struct sk_buff_head *q, u16 num)
+{
+	struct sk_buff *skb;
+
+	while (num) {
+		skb = ath6kl_buf_alloc(ATH6KL_BUFFER_SIZE);
+		if (!skb) {
+			ath6kl_err("netbuf allocation failed\n");
+			return;
+		}
+		skb_queue_tail(q, skb);
+		num--;
+	}
+}
+
+static struct sk_buff *aggr_get_free_skb(struct aggr_info *p_aggr)
+{
+	struct sk_buff *skb = NULL;
+
+	if (skb_queue_len(&p_aggr->free_q) < (AGGR_NUM_OF_FREE_NETBUFS >> 2))
+		ath6kl_alloc_netbufs(&p_aggr->free_q, AGGR_NUM_OF_FREE_NETBUFS);
+
+	skb = skb_dequeue(&p_aggr->free_q);
+
+	return skb;
+}
+
+void ath6kl_rx_refill(struct htc_target *target, enum htc_endpoint_id endpoint)
+{
+	struct ath6kl *ar = target->dev->ar;
+	struct sk_buff *skb;
+	int rx_buf;
+	int n_buf_refill;
+	struct htc_packet *packet;
+	struct list_head queue;
+
+	n_buf_refill = ATH6KL_MAX_RX_BUFFERS -
+			  ath6kl_htc_get_rxbuf_num(ar->htc_target, endpoint);
+
+	if (n_buf_refill <= 0)
+		return;
+
+	INIT_LIST_HEAD(&queue);
+
+	ath6kl_dbg(ATH6KL_DBG_WLAN_RX,
+		   "%s: providing htc with %d buffers at eid=%d\n",
+		   __func__, n_buf_refill, endpoint);
+
+	for (rx_buf = 0; rx_buf < n_buf_refill; rx_buf++) {
+		skb = ath6kl_buf_alloc(ATH6KL_BUFFER_SIZE);
+		if (!skb)
+			break;
+
+		packet = (struct htc_packet *) skb->head;
+		set_htc_rxpkt_info(packet, skb, skb->data,
+				ATH6KL_BUFFER_SIZE, endpoint);
+		list_add_tail(&packet->list, &queue);
+	}
+
+	if (!list_empty(&queue))
+		ath6kl_htc_add_rxbuf_multiple(ar->htc_target, &queue);
+}
+
+void ath6kl_refill_amsdu_rxbufs(struct ath6kl *ar, int count)
+{
+	struct htc_packet *packet;
+	struct sk_buff *skb;
+
+	while (count) {
+		skb = ath6kl_buf_alloc(ATH6KL_AMSDU_BUFFER_SIZE);
+		if (!skb)
+			return;
+
+		packet = (struct htc_packet *) skb->head;
+		set_htc_rxpkt_info(packet, skb, skb->data,
+				   ATH6KL_AMSDU_BUFFER_SIZE, 0);
+		spin_lock_bh(&ar->lock);
+		list_add_tail(&packet->list, &ar->amsdu_rx_buffer_queue);
+		spin_unlock_bh(&ar->lock);
+		count--;
+	}
+}
+
+/*
+ * Callback to allocate a receive buffer for a pending packet. We use a
+ * pre-allocated list of buffers of maximum AMSDU size (4K).
+ */
+struct htc_packet *ath6kl_alloc_amsdu_rxbuf(struct htc_target *target,
+					    enum htc_endpoint_id endpoint,
+					    int len)
+{
+	struct ath6kl *ar = target->dev->ar;
+	struct htc_packet *packet = NULL;
+	struct list_head *pkt_pos;
+	int refill_cnt = 0, depth = 0;
+
+	ath6kl_dbg(ATH6KL_DBG_WLAN_RX, "%s: eid=%d, len:%d\n",
+		   __func__, endpoint, len);
+
+	if ((len <= ATH6KL_BUFFER_SIZE) ||
+	    (len > ATH6KL_AMSDU_BUFFER_SIZE))
+		return NULL;
+
+	spin_lock_bh(&ar->lock);
+
+	if (list_empty(&ar->amsdu_rx_buffer_queue)) {
+		spin_unlock_bh(&ar->lock);
+		refill_cnt = ATH6KL_MAX_AMSDU_RX_BUFFERS;
+		goto refill_buf;
+	}
+
+	packet = list_first_entry(&ar->amsdu_rx_buffer_queue,
+				  struct htc_packet, list);
+	list_del(&packet->list);
+	list_for_each(pkt_pos, &ar->amsdu_rx_buffer_queue)
+		depth++;
+
+	refill_cnt = ATH6KL_MAX_AMSDU_RX_BUFFERS - depth;
+	spin_unlock_bh(&ar->lock);
+
+	/* set actual endpoint ID */
+	packet->endpoint = endpoint;
+
+refill_buf:
+	if (refill_cnt >= ATH6KL_AMSDU_REFILL_THRESHOLD)
+		ath6kl_refill_amsdu_rxbufs(ar, refill_cnt);
+
+	return packet;
+}
+
+static void aggr_slice_amsdu(struct aggr_info *p_aggr,
+			     struct rxtid *rxtid, struct sk_buff *skb)
+{
+	struct sk_buff *new_skb;
+	struct ethhdr *hdr;
+	u16 frame_8023_len, payload_8023_len, mac_hdr_len, amsdu_len;
+	u8 *framep;
+
+	mac_hdr_len = sizeof(struct ethhdr);
+	framep = skb->data + mac_hdr_len;
+	amsdu_len = skb->len - mac_hdr_len;
+
+	while (amsdu_len > mac_hdr_len) {
+		hdr = (struct ethhdr *) framep;
+		payload_8023_len = ntohs(hdr->h_proto);
+
+		if (payload_8023_len < MIN_MSDU_SUBFRAME_PAYLOAD_LEN ||
+		    payload_8023_len > MAX_MSDU_SUBFRAME_PAYLOAD_LEN) {
+			ath6kl_err("802.3 AMSDU frame bound check failed. len %d\n",
+				   payload_8023_len);
+			break;
+		}
+
+		frame_8023_len = payload_8023_len + mac_hdr_len;
+		new_skb = aggr_get_free_skb(p_aggr);
+		if (!new_skb) {
+			ath6kl_err("no buffer available\n");
+			break;
+		}
+
+		memcpy(new_skb->data, framep, frame_8023_len);
+		skb_put(new_skb, frame_8023_len);
+		if (ath6kl_wmi_dot3_2_dix(new_skb)) {
+			ath6kl_err("dot3_2_dix error\n");
+			dev_kfree_skb(new_skb);
+			break;
+		}
+
+		skb_queue_tail(&rxtid->q, new_skb);
+
+		/* Is this the last subframe within this aggregate ? */
+		if ((amsdu_len - frame_8023_len) == 0)
+			break;
+
+		/* Add the length of A-MSDU subframe padding bytes -
+		 * Round to nearest word.
+		 */
+		frame_8023_len = ALIGN(frame_8023_len + 3, 3);
+
+		framep += frame_8023_len;
+		amsdu_len -= frame_8023_len;
+	}
+
+	dev_kfree_skb(skb);
+}
+
+static void aggr_deque_frms(struct aggr_info *p_aggr, u8 tid,
+			    u16 seq_no, u8 order)
+{
+	struct sk_buff *skb;
+	struct rxtid *rxtid;
+	struct skb_hold_q *node;
+	u16 idx, idx_end, seq_end;
+	struct rxtid_stats *stats;
+
+	if (!p_aggr)
+		return;
+
+	rxtid = &p_aggr->rx_tid[tid];
+	stats = &p_aggr->stat[tid];
+
+	idx = AGGR_WIN_IDX(rxtid->seq_next, rxtid->hold_q_sz);
+
+	/*
+	 * idx_end is typically the last possible frame in the window,
+	 * but changes to 'the' seq_no, when BAR comes. If seq_no
+	 * is non-zero, we will go up to that and stop.
+	 * Note: last seq no in current window will occupy the same
+	 * index position as index that is just previous to start.
+	 * An imp point : if win_sz is 7, for seq_no space of 4095,
+	 * then, there would be holes when sequence wrap around occurs.
+	 * Target should judiciously choose the win_sz, based on
+	 * this condition. For 4095, (TID_WINDOW_SZ = 2 x win_sz
+	 * 2, 4, 8, 16 win_sz works fine).
+	 * We must deque from "idx" to "idx_end", including both.
+	 */
+	seq_end = seq_no ? seq_no : rxtid->seq_next;
+	idx_end = AGGR_WIN_IDX(seq_end, rxtid->hold_q_sz);
+
+	spin_lock_bh(&rxtid->lock);
+
+	do {
+		node = &rxtid->hold_q[idx];
+		if ((order == 1) && (!node->skb))
+			break;
+
+		if (node->skb) {
+			if (node->is_amsdu)
+				aggr_slice_amsdu(p_aggr, rxtid, node->skb);
+			else
+				skb_queue_tail(&rxtid->q, node->skb);
+			node->skb = NULL;
+		} else
+			stats->num_hole++;
+
+		rxtid->seq_next = ATH6KL_NEXT_SEQ_NO(rxtid->seq_next);
+		idx = AGGR_WIN_IDX(rxtid->seq_next, rxtid->hold_q_sz);
+	} while (idx != idx_end);
+
+	spin_unlock_bh(&rxtid->lock);
+
+	stats->num_delivered += skb_queue_len(&rxtid->q);
+
+	while ((skb = skb_dequeue(&rxtid->q)))
+		ath6kl_deliver_frames_to_nw_stack(p_aggr->dev, skb);
+}
+
+static bool aggr_process_recv_frm(struct aggr_info *agg_info, u8 tid,
+				  u16 seq_no,
+				  bool is_amsdu, struct sk_buff *frame)
+{
+	struct rxtid *rxtid;
+	struct rxtid_stats *stats;
+	struct sk_buff *skb;
+	struct skb_hold_q *node;
+	u16 idx, st, cur, end;
+	bool is_queued = false;
+	u16 extended_end;
+
+	rxtid = &agg_info->rx_tid[tid];
+	stats = &agg_info->stat[tid];
+
+	stats->num_into_aggr++;
+
+	if (!rxtid->aggr) {
+		if (is_amsdu) {
+			aggr_slice_amsdu(agg_info, rxtid, frame);
+			is_queued = true;
+			stats->num_amsdu++;
+			while ((skb = skb_dequeue(&rxtid->q)))
+				ath6kl_deliver_frames_to_nw_stack(agg_info->dev,
+								  skb);
+		}
+		return is_queued;
+	}
+
+	/* Check the incoming sequence no, if it's in the window */
+	st = rxtid->seq_next;
+	cur = seq_no;
+	end = (st + rxtid->hold_q_sz-1) & ATH6KL_MAX_SEQ_NO;
+
+	if (((st < end) && (cur < st || cur > end)) ||
+	    ((st > end) && (cur > end) && (cur < st))) {
+		extended_end = (end + rxtid->hold_q_sz - 1) &
+			ATH6KL_MAX_SEQ_NO;
+
+		if (((end < extended_end) &&
+		     (cur < end || cur > extended_end)) ||
+		    ((end > extended_end) && (cur > extended_end) &&
+		     (cur < end))) {
+			aggr_deque_frms(agg_info, tid, 0, 0);
+			if (cur >= rxtid->hold_q_sz - 1)
+				rxtid->seq_next = cur - (rxtid->hold_q_sz - 1);
+			else
+				rxtid->seq_next = ATH6KL_MAX_SEQ_NO -
+						  (rxtid->hold_q_sz - 2 - cur);
+		} else {
+			/*
+			 * Dequeue only those frames that are outside the
+			 * new shifted window.
+			 */
+			if (cur >= rxtid->hold_q_sz - 1)
+				st = cur - (rxtid->hold_q_sz - 1);
+			else
+				st = ATH6KL_MAX_SEQ_NO -
+					(rxtid->hold_q_sz - 2 - cur);
+
+			aggr_deque_frms(agg_info, tid, st, 0);
+		}
+
+		stats->num_oow++;
+	}
+
+	idx = AGGR_WIN_IDX(seq_no, rxtid->hold_q_sz);
+
+	node = &rxtid->hold_q[idx];
+
+	spin_lock_bh(&rxtid->lock);
+
+	/*
+	 * Is the cur frame duplicate or something beyond our window(hold_q
+	 * -> which is 2x, already)?
+	 *
+	 * 1. Duplicate is easy - drop incoming frame.
+	 * 2. Not falling in current sliding window.
+	 *  2a. is the frame_seq_no preceding current tid_seq_no?
+	 *      -> drop the frame. perhaps sender did not get our ACK.
+	 *         this is taken care of above.
+	 *  2b. is the frame_seq_no beyond window(st, TID_WINDOW_SZ);
+	 *      -> Taken care of it above, by moving window forward.
+	 */
+	dev_kfree_skb(node->skb);
+	stats->num_dups++;
+
+	node->skb = frame;
+	is_queued = true;
+	node->is_amsdu = is_amsdu;
+	node->seq_no = seq_no;
+
+	if (node->is_amsdu)
+		stats->num_amsdu++;
+	else
+		stats->num_mpdu++;
+
+	spin_unlock_bh(&rxtid->lock);
+
+	aggr_deque_frms(agg_info, tid, 0, 1);
+
+	if (agg_info->timer_scheduled)
+		rxtid->progress = true;
+	else
+		for (idx = 0 ; idx < rxtid->hold_q_sz; idx++) {
+			if (rxtid->hold_q[idx].skb) {
+				/*
+				 * There is a frame in the queue and no
+				 * timer so start a timer to ensure that
+				 * the frame doesn't remain stuck
+				 * forever.
+				 */
+				agg_info->timer_scheduled = true;
+				mod_timer(&agg_info->timer,
+					  (jiffies +
+					   HZ * (AGGR_RX_TIMEOUT) / 1000));
+				rxtid->progress = false;
+				rxtid->timer_mon = true;
+				break;
+			}
+		}
+
+	return is_queued;
+}
+
+void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
+{
+	struct ath6kl *ar = target->dev->ar;
+	struct sk_buff *skb = packet->pkt_cntxt;
+	struct wmi_rx_meta_v2 *meta;
+	struct wmi_data_hdr *dhdr;
+	int min_hdr_len;
+	u8 meta_type, dot11_hdr = 0;
+	int status = packet->status;
+	enum htc_endpoint_id ept = packet->endpoint;
+	bool is_amsdu, prev_ps, ps_state = false;
+	struct ath6kl_sta *conn = NULL;
+	struct sk_buff *skb1 = NULL;
+	struct ethhdr *datap = NULL;
+	u16 seq_no, offset;
+	u8 tid;
+
+	ath6kl_dbg(ATH6KL_DBG_WLAN_RX,
+		   "%s: ar=0x%p eid=%d, skb=0x%p, data=0x%p, len=0x%x status:%d",
+		   __func__, ar, ept, skb, packet->buf,
+		   packet->act_len, status);
+
+	if (status || !(skb->data + HTC_HDR_LENGTH)) {
+		ar->net_stats.rx_errors++;
+		dev_kfree_skb(skb);
+		return;
+	}
+
+	/*
+	 * Take lock to protect buffer counts and adaptive power throughput
+	 * state.
+	 */
+	spin_lock_bh(&ar->lock);
+
+	ar->net_stats.rx_packets++;
+	ar->net_stats.rx_bytes += packet->act_len;
+
+	skb_put(skb, packet->act_len + HTC_HDR_LENGTH);
+	skb_pull(skb, HTC_HDR_LENGTH);
+
+	ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, skb->data, skb->len);
+
+	spin_unlock_bh(&ar->lock);
+
+	skb->dev = ar->net_dev;
+
+	if (!test_bit(WMI_ENABLED, &ar->flag)) {
+		if (EPPING_ALIGNMENT_PAD > 0)
+			skb_pull(skb, EPPING_ALIGNMENT_PAD);
+		ath6kl_deliver_frames_to_nw_stack(ar->net_dev, skb);
+		return;
+	}
+
+	if (ept == ar->ctrl_ep) {
+		ath6kl_wmi_control_rx(ar->wmi, skb);
+		return;
+	}
+
+	min_hdr_len = sizeof(struct ethhdr);
+	min_hdr_len += sizeof(struct wmi_data_hdr) +
+		       sizeof(struct ath6kl_llc_snap_hdr);
+
+	dhdr = (struct wmi_data_hdr *) skb->data;
+
+	/*
+	 * In the case of AP mode we may receive NULL data frames
+	 * that do not have LLC hdr. They are 16 bytes in size.
+	 * Allow these frames in the AP mode.
+	 */
+	if (ar->nw_type != AP_NETWORK &&
+	    ((packet->act_len < min_hdr_len) ||
+	     (packet->act_len > WMI_MAX_AMSDU_RX_DATA_FRAME_LENGTH))) {
+		ath6kl_info("frame len is too short or too long\n");
+		ar->net_stats.rx_errors++;
+		ar->net_stats.rx_length_errors++;
+		dev_kfree_skb(skb);
+		return;
+	}
+
+	/* Get the Power save state of the STA */
+	if (ar->nw_type == AP_NETWORK) {
+		meta_type = wmi_data_hdr_get_meta(dhdr);
+
+		ps_state = !!((dhdr->info >> WMI_DATA_HDR_PS_SHIFT) &
+			      WMI_DATA_HDR_PS_MASK);
+
+		offset = sizeof(struct wmi_data_hdr);
+
+		switch (meta_type) {
+		case 0:
+			break;
+		case WMI_META_VERSION_1:
+			offset += sizeof(struct wmi_rx_meta_v1);
+			break;
+		case WMI_META_VERSION_2:
+			offset += sizeof(struct wmi_rx_meta_v2);
+			break;
+		default:
+			break;
+		}
+
+		datap = (struct ethhdr *) (skb->data + offset);
+		conn = ath6kl_find_sta(ar, datap->h_source);
+
+		if (!conn) {
+			dev_kfree_skb(skb);
+			return;
+		}
+
+		/*
+		 * If there is a change in PS state of the STA,
+		 * take appropriate steps:
+		 *
+		 * 1. If Sleep-->Awake, flush the psq for the STA
+		 *    Clear the PVB for the STA.
+		 * 2. If Awake-->Sleep, Starting queueing frames
+		 *    the STA.
+		 */
+		prev_ps = !!(conn->sta_flags & STA_PS_SLEEP);
+
+		if (ps_state)
+			conn->sta_flags |= STA_PS_SLEEP;
+		else
+			conn->sta_flags &= ~STA_PS_SLEEP;
+
+		if (prev_ps ^ !!(conn->sta_flags & STA_PS_SLEEP)) {
+			if (!(conn->sta_flags & STA_PS_SLEEP)) {
+				struct sk_buff *skbuff = NULL;
+
+				spin_lock_bh(&conn->psq_lock);
+				while ((skbuff = skb_dequeue(&conn->psq))
+				       != NULL) {
+					spin_unlock_bh(&conn->psq_lock);
+					ath6kl_data_tx(skbuff, ar->net_dev);
+					spin_lock_bh(&conn->psq_lock);
+				}
+				spin_unlock_bh(&conn->psq_lock);
+				/* Clear the PVB for this STA */
+				ath6kl_wmi_set_pvb_cmd(ar->wmi, conn->aid, 0);
+			}
+		}
+
+		/* drop NULL data frames here */
+		if ((packet->act_len < min_hdr_len) ||
+		    (packet->act_len >
+		     WMI_MAX_AMSDU_RX_DATA_FRAME_LENGTH)) {
+			dev_kfree_skb(skb);
+			return;
+		}
+	}
+
+	is_amsdu = wmi_data_hdr_is_amsdu(dhdr) ? true : false;
+	tid = wmi_data_hdr_get_up(dhdr);
+	seq_no = wmi_data_hdr_get_seqno(dhdr);
+	meta_type = wmi_data_hdr_get_meta(dhdr);
+	dot11_hdr = wmi_data_hdr_get_dot11(dhdr);
+
+	ath6kl_wmi_data_hdr_remove(ar->wmi, skb);
+
+	switch (meta_type) {
+	case WMI_META_VERSION_1:
+		skb_pull(skb, sizeof(struct wmi_rx_meta_v1));
+		break;
+	case WMI_META_VERSION_2:
+		meta = (struct wmi_rx_meta_v2 *) skb->data;
+		if (meta->csum_flags & 0x1) {
+			skb->ip_summed = CHECKSUM_COMPLETE;
+			skb->csum = (__force __wsum) meta->csum;
+		}
+		skb_pull(skb, sizeof(struct wmi_rx_meta_v2));
+		break;
+	default:
+		break;
+	}
+
+	if (dot11_hdr)
+		status = ath6kl_wmi_dot11_hdr_remove(ar->wmi, skb);
+	else if (!is_amsdu)
+		status = ath6kl_wmi_dot3_2_dix(skb);
+
+	if (status) {
+		/*
+		 * Drop frames that could not be processed (lack of
+		 * memory, etc.)
+		 */
+		dev_kfree_skb(skb);
+		return;
+	}
+
+	if (!(ar->net_dev->flags & IFF_UP)) {
+		dev_kfree_skb(skb);
+		return;
+	}
+
+	if (ar->nw_type == AP_NETWORK) {
+		datap = (struct ethhdr *) skb->data;
+		if (is_multicast_ether_addr(datap->h_dest))
+			/*
+			 * Bcast/Mcast frames should be sent to the
+			 * OS stack as well as on the air.
+			 */
+			skb1 = skb_copy(skb, GFP_ATOMIC);
+		else {
+			/*
+			 * Search for a connected STA with dstMac
+			 * as the Mac address. If found send the
+			 * frame to it on the air else send the
+			 * frame up the stack.
+			 */
+			struct ath6kl_sta *conn = NULL;
+			conn = ath6kl_find_sta(ar, datap->h_dest);
+
+			if (conn && ar->intra_bss) {
+				skb1 = skb;
+				skb = NULL;
+			} else if (conn && !ar->intra_bss) {
+				dev_kfree_skb(skb);
+				skb = NULL;
+			}
+		}
+		if (skb1)
+			ath6kl_data_tx(skb1, ar->net_dev);
+	}
+
+	if (!aggr_process_recv_frm(ar->aggr_cntxt, tid, seq_no,
+				   is_amsdu, skb))
+		ath6kl_deliver_frames_to_nw_stack(ar->net_dev, skb);
+}
+
+static void aggr_timeout(unsigned long arg)
+{
+	u8 i, j;
+	struct aggr_info *p_aggr = (struct aggr_info *) arg;
+	struct rxtid *rxtid;
+	struct rxtid_stats *stats;
+
+	for (i = 0; i < NUM_OF_TIDS; i++) {
+		rxtid = &p_aggr->rx_tid[i];
+		stats = &p_aggr->stat[i];
+
+		if (!rxtid->aggr || !rxtid->timer_mon || rxtid->progress)
+			continue;
+
+		/*
+		 * FIXME: these timeouts happen quite fruently, something
+		 * line once within 60 seconds. Investigate why.
+		 */
+		stats->num_timeouts++;
+		ath6kl_dbg(ATH6KL_DBG_AGGR,
+			   "aggr timeout (st %d end %d)\n",
+			   rxtid->seq_next,
+			   ((rxtid->seq_next + rxtid->hold_q_sz-1) &
+			    ATH6KL_MAX_SEQ_NO));
+		aggr_deque_frms(p_aggr, i, 0, 0);
+	}
+
+	p_aggr->timer_scheduled = false;
+
+	for (i = 0; i < NUM_OF_TIDS; i++) {
+		rxtid = &p_aggr->rx_tid[i];
+
+		if (rxtid->aggr && rxtid->hold_q) {
+			for (j = 0; j < rxtid->hold_q_sz; j++) {
+				if (rxtid->hold_q[j].skb) {
+					p_aggr->timer_scheduled = true;
+					rxtid->timer_mon = true;
+					rxtid->progress = false;
+					break;
+				}
+			}
+
+			if (j >= rxtid->hold_q_sz)
+				rxtid->timer_mon = false;
+		}
+	}
+
+	if (p_aggr->timer_scheduled)
+		mod_timer(&p_aggr->timer,
+			  jiffies + msecs_to_jiffies(AGGR_RX_TIMEOUT));
+}
+
+static void aggr_delete_tid_state(struct aggr_info *p_aggr, u8 tid)
+{
+	struct rxtid *rxtid;
+	struct rxtid_stats *stats;
+
+	if (!p_aggr || tid >= NUM_OF_TIDS)
+		return;
+
+	rxtid = &p_aggr->rx_tid[tid];
+	stats = &p_aggr->stat[tid];
+
+	if (rxtid->aggr)
+		aggr_deque_frms(p_aggr, tid, 0, 0);
+
+	rxtid->aggr = false;
+	rxtid->progress = false;
+	rxtid->timer_mon = false;
+	rxtid->win_sz = 0;
+	rxtid->seq_next = 0;
+	rxtid->hold_q_sz = 0;
+
+	kfree(rxtid->hold_q);
+	rxtid->hold_q = NULL;
+
+	memset(stats, 0, sizeof(struct rxtid_stats));
+}
+
+void aggr_recv_addba_req_evt(struct ath6kl *ar, u8 tid, u16 seq_no, u8 win_sz)
+{
+	struct aggr_info *p_aggr = ar->aggr_cntxt;
+	struct rxtid *rxtid;
+	struct rxtid_stats *stats;
+	u16 hold_q_size;
+
+	if (!p_aggr)
+		return;
+
+	rxtid = &p_aggr->rx_tid[tid];
+	stats = &p_aggr->stat[tid];
+
+	if (win_sz < AGGR_WIN_SZ_MIN || win_sz > AGGR_WIN_SZ_MAX)
+		ath6kl_dbg(ATH6KL_DBG_WLAN_RX, "%s: win_sz %d, tid %d\n",
+			   __func__, win_sz, tid);
+
+	if (rxtid->aggr)
+		aggr_delete_tid_state(p_aggr, tid);
+
+	rxtid->seq_next = seq_no;
+	hold_q_size = TID_WINDOW_SZ(win_sz) * sizeof(struct skb_hold_q);
+	rxtid->hold_q = kzalloc(hold_q_size, GFP_KERNEL);
+	if (!rxtid->hold_q)
+		return;
+
+	rxtid->win_sz = win_sz;
+	rxtid->hold_q_sz = TID_WINDOW_SZ(win_sz);
+	if (!skb_queue_empty(&rxtid->q))
+		return;
+
+	rxtid->aggr = true;
+}
+
+struct aggr_info *aggr_init(struct net_device *dev)
+{
+	struct aggr_info *p_aggr = NULL;
+	struct rxtid *rxtid;
+	u8 i;
+
+	p_aggr = kzalloc(sizeof(struct aggr_info), GFP_KERNEL);
+	if (!p_aggr) {
+		ath6kl_err("failed to alloc memory for aggr_node\n");
+		return NULL;
+	}
+
+	p_aggr->aggr_sz = AGGR_SZ_DEFAULT;
+	p_aggr->dev = dev;
+	init_timer(&p_aggr->timer);
+	p_aggr->timer.function = aggr_timeout;
+	p_aggr->timer.data = (unsigned long) p_aggr;
+
+	p_aggr->timer_scheduled = false;
+	skb_queue_head_init(&p_aggr->free_q);
+
+	ath6kl_alloc_netbufs(&p_aggr->free_q, AGGR_NUM_OF_FREE_NETBUFS);
+
+	for (i = 0; i < NUM_OF_TIDS; i++) {
+		rxtid = &p_aggr->rx_tid[i];
+		rxtid->aggr = false;
+		rxtid->progress = false;
+		rxtid->timer_mon = false;
+		skb_queue_head_init(&rxtid->q);
+		spin_lock_init(&rxtid->lock);
+	}
+
+	return p_aggr;
+}
+
+void aggr_recv_delba_req_evt(struct ath6kl *ar, u8 tid)
+{
+	struct aggr_info *p_aggr = ar->aggr_cntxt;
+	struct rxtid *rxtid;
+
+	if (!p_aggr)
+		return;
+
+	rxtid = &p_aggr->rx_tid[tid];
+
+	if (rxtid->aggr)
+		aggr_delete_tid_state(p_aggr, tid);
+}
+
+void aggr_reset_state(struct aggr_info *aggr_info)
+{
+	u8 tid;
+
+	for (tid = 0; tid < NUM_OF_TIDS; tid++)
+		aggr_delete_tid_state(aggr_info, tid);
+}
+
+/* clean up our amsdu buffer list */
+void ath6kl_cleanup_amsdu_rxbufs(struct ath6kl *ar)
+{
+	struct htc_packet *packet, *tmp_pkt;
+
+	spin_lock_bh(&ar->lock);
+	if (list_empty(&ar->amsdu_rx_buffer_queue)) {
+		spin_unlock_bh(&ar->lock);
+		return;
+	}
+
+	list_for_each_entry_safe(packet, tmp_pkt, &ar->amsdu_rx_buffer_queue,
+				 list) {
+		list_del(&packet->list);
+		spin_unlock_bh(&ar->lock);
+		dev_kfree_skb(packet->pkt_cntxt);
+		spin_lock_bh(&ar->lock);
+	}
+
+	spin_unlock_bh(&ar->lock);
+}
+
+void aggr_module_destroy(struct aggr_info *aggr_info)
+{
+	struct rxtid *rxtid;
+	u8 i, k;
+
+	if (!aggr_info)
+		return;
+
+	if (aggr_info->timer_scheduled) {
+		del_timer(&aggr_info->timer);
+		aggr_info->timer_scheduled = false;
+	}
+
+	for (i = 0; i < NUM_OF_TIDS; i++) {
+		rxtid = &aggr_info->rx_tid[i];
+		if (rxtid->hold_q) {
+			for (k = 0; k < rxtid->hold_q_sz; k++)
+				dev_kfree_skb(rxtid->hold_q[k].skb);
+			kfree(rxtid->hold_q);
+		}
+
+		skb_queue_purge(&rxtid->q);
+	}
+
+	skb_queue_purge(&aggr_info->free_q);
+	kfree(aggr_info);
+}
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
new file mode 100644
index 000000000000..f5aa33dd4c42
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -0,0 +1,2743 @@
+/*
+ * Copyright (c) 2004-2011 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.
+ */
+
+#include <linux/ip.h>
+#include "core.h"
+#include "debug.h"
+
+static int ath6kl_wmi_sync_point(struct wmi *wmi);
+
+static const s32 wmi_rate_tbl[][2] = {
+	/* {W/O SGI, with SGI} */
+	{1000, 1000},
+	{2000, 2000},
+	{5500, 5500},
+	{11000, 11000},
+	{6000, 6000},
+	{9000, 9000},
+	{12000, 12000},
+	{18000, 18000},
+	{24000, 24000},
+	{36000, 36000},
+	{48000, 48000},
+	{54000, 54000},
+	{6500, 7200},
+	{13000, 14400},
+	{19500, 21700},
+	{26000, 28900},
+	{39000, 43300},
+	{52000, 57800},
+	{58500, 65000},
+	{65000, 72200},
+	{13500, 15000},
+	{27000, 30000},
+	{40500, 45000},
+	{54000, 60000},
+	{81000, 90000},
+	{108000, 120000},
+	{121500, 135000},
+	{135000, 150000},
+	{0, 0}
+};
+
+/* 802.1d to AC mapping. Refer pg 57 of WMM-test-plan-v1.2 */
+static const u8 up_to_ac[] = {
+	WMM_AC_BE,
+	WMM_AC_BK,
+	WMM_AC_BK,
+	WMM_AC_BE,
+	WMM_AC_VI,
+	WMM_AC_VI,
+	WMM_AC_VO,
+	WMM_AC_VO,
+};
+
+void ath6kl_wmi_set_control_ep(struct wmi *wmi, enum htc_endpoint_id ep_id)
+{
+	if (WARN_ON(ep_id == ENDPOINT_UNUSED || ep_id >= ENDPOINT_MAX))
+		return;
+
+	wmi->ep_id = ep_id;
+}
+
+enum htc_endpoint_id ath6kl_wmi_get_control_ep(struct wmi *wmi)
+{
+	return wmi->ep_id;
+}
+
+/*  Performs DIX to 802.3 encapsulation for transmit packets.
+ *  Assumes the entire DIX header is contigous and that there is
+ *  enough room in the buffer for a 802.3 mac header and LLC+SNAP headers.
+ */
+int ath6kl_wmi_dix_2_dot3(struct wmi *wmi, struct sk_buff *skb)
+{
+	struct ath6kl_llc_snap_hdr *llc_hdr;
+	struct ethhdr *eth_hdr;
+	size_t new_len;
+	__be16 type;
+	u8 *datap;
+	u16 size;
+
+	if (WARN_ON(skb == NULL))
+		return -EINVAL;
+
+	size = sizeof(struct ath6kl_llc_snap_hdr) + sizeof(struct wmi_data_hdr);
+	if (skb_headroom(skb) < size)
+		return -ENOMEM;
+
+	eth_hdr = (struct ethhdr *) skb->data;
+	type = eth_hdr->h_proto;
+
+	if (!is_ethertype(be16_to_cpu(type))) {
+		ath6kl_dbg(ATH6KL_DBG_WMI,
+			"%s: pkt is already in 802.3 format\n", __func__);
+		return 0;
+	}
+
+	new_len = skb->len - sizeof(*eth_hdr) + sizeof(*llc_hdr);
+
+	skb_push(skb, sizeof(struct ath6kl_llc_snap_hdr));
+	datap = skb->data;
+
+	eth_hdr->h_proto = cpu_to_be16(new_len);
+
+	memcpy(datap, eth_hdr, sizeof(*eth_hdr));
+
+	llc_hdr = (struct ath6kl_llc_snap_hdr *)(datap + sizeof(*eth_hdr));
+	llc_hdr->dsap = 0xAA;
+	llc_hdr->ssap = 0xAA;
+	llc_hdr->cntl = 0x03;
+	llc_hdr->org_code[0] = 0x0;
+	llc_hdr->org_code[1] = 0x0;
+	llc_hdr->org_code[2] = 0x0;
+	llc_hdr->eth_type = type;
+
+	return 0;
+}
+
+static int ath6kl_wmi_meta_add(struct wmi *wmi, struct sk_buff *skb,
+			       u8 *version, void *tx_meta_info)
+{
+	struct wmi_tx_meta_v1 *v1;
+	struct wmi_tx_meta_v2 *v2;
+
+	if (WARN_ON(skb == NULL || version == NULL))
+		return -EINVAL;
+
+	switch (*version) {
+	case WMI_META_VERSION_1:
+		skb_push(skb, WMI_MAX_TX_META_SZ);
+		v1 = (struct wmi_tx_meta_v1 *) skb->data;
+		v1->pkt_id = 0;
+		v1->rate_plcy_id = 0;
+		*version = WMI_META_VERSION_1;
+		break;
+	case WMI_META_VERSION_2:
+		skb_push(skb, WMI_MAX_TX_META_SZ);
+		v2 = (struct wmi_tx_meta_v2 *) skb->data;
+		memcpy(v2, (struct wmi_tx_meta_v2 *) tx_meta_info,
+		       sizeof(struct wmi_tx_meta_v2));
+		break;
+	}
+
+	return 0;
+}
+
+int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb,
+			    u8 msg_type, bool more_data,
+			    enum wmi_data_hdr_data_type data_type,
+			    u8 meta_ver, void *tx_meta_info)
+{
+	struct wmi_data_hdr *data_hdr;
+	int ret;
+
+	if (WARN_ON(skb == NULL))
+		return -EINVAL;
+
+	ret = ath6kl_wmi_meta_add(wmi, skb, &meta_ver, tx_meta_info);
+	if (ret)
+		return ret;
+
+	skb_push(skb, sizeof(struct wmi_data_hdr));
+
+	data_hdr = (struct wmi_data_hdr *)skb->data;
+	memset(data_hdr, 0, sizeof(struct wmi_data_hdr));
+
+	data_hdr->info = msg_type << WMI_DATA_HDR_MSG_TYPE_SHIFT;
+	data_hdr->info |= data_type << WMI_DATA_HDR_DATA_TYPE_SHIFT;
+
+	if (more_data)
+		data_hdr->info |=
+		    WMI_DATA_HDR_MORE_MASK << WMI_DATA_HDR_MORE_SHIFT;
+
+	data_hdr->info2 = cpu_to_le16(meta_ver << WMI_DATA_HDR_META_SHIFT);
+	data_hdr->info3 = 0;
+
+	return 0;
+}
+
+static u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri)
+{
+	struct iphdr *ip_hdr = (struct iphdr *) pkt;
+	u8 ip_pri;
+
+	/*
+	 * Determine IPTOS priority
+	 *
+	 * IP-TOS - 8bits
+	 *          : DSCP(6-bits) ECN(2-bits)
+	 *          : DSCP - P2 P1 P0 X X X
+	 * where (P2 P1 P0) form 802.1D
+	 */
+	ip_pri = ip_hdr->tos >> 5;
+	ip_pri &= 0x7;
+
+	if ((layer2_pri & 0x7) > ip_pri)
+		return (u8) layer2_pri & 0x7;
+	else
+		return ip_pri;
+}
+
+int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, struct sk_buff *skb,
+				       u32 layer2_priority, bool wmm_enabled,
+				       u8 *ac)
+{
+	struct wmi_data_hdr *data_hdr;
+	struct ath6kl_llc_snap_hdr *llc_hdr;
+	struct wmi_create_pstream_cmd cmd;
+	u32 meta_size, hdr_size;
+	u16 ip_type = IP_ETHERTYPE;
+	u8 stream_exist, usr_pri;
+	u8 traffic_class = WMM_AC_BE;
+	u8 *datap;
+
+	if (WARN_ON(skb == NULL))
+		return -EINVAL;
+
+	datap = skb->data;
+	data_hdr = (struct wmi_data_hdr *) datap;
+
+	meta_size = ((le16_to_cpu(data_hdr->info2) >> WMI_DATA_HDR_META_SHIFT) &
+		     WMI_DATA_HDR_META_MASK) ? WMI_MAX_TX_META_SZ : 0;
+
+	if (!wmm_enabled) {
+		/* If WMM is disabled all traffic goes as BE traffic */
+		usr_pri = 0;
+	} else {
+		hdr_size = sizeof(struct ethhdr);
+
+		llc_hdr = (struct ath6kl_llc_snap_hdr *)(datap +
+							 sizeof(struct
+								wmi_data_hdr) +
+							 meta_size + hdr_size);
+
+		if (llc_hdr->eth_type == htons(ip_type)) {
+			/*
+			 * Extract the endpoint info from the TOS field
+			 * in the IP header.
+			 */
+			usr_pri =
+			   ath6kl_wmi_determine_user_priority(((u8 *) llc_hdr) +
+					sizeof(struct ath6kl_llc_snap_hdr),
+					layer2_priority);
+		} else
+			usr_pri = layer2_priority & 0x7;
+	}
+
+	/* workaround for WMM S5 */
+	if ((wmi->traffic_class == WMM_AC_VI) &&
+	    ((usr_pri == 5) || (usr_pri == 4)))
+		usr_pri = 1;
+
+	/* Convert user priority to traffic class */
+	traffic_class = up_to_ac[usr_pri & 0x7];
+
+	wmi_data_hdr_set_up(data_hdr, usr_pri);
+
+	spin_lock_bh(&wmi->lock);
+	stream_exist = wmi->fat_pipe_exist;
+	spin_unlock_bh(&wmi->lock);
+
+	if (!(stream_exist & (1 << traffic_class))) {
+		memset(&cmd, 0, sizeof(cmd));
+		cmd.traffic_class = traffic_class;
+		cmd.user_pri = usr_pri;
+		cmd.inactivity_int =
+			cpu_to_le32(WMI_IMPLICIT_PSTREAM_INACTIVITY_INT);
+		/* Implicit streams are created with TSID 0xFF */
+		cmd.tsid = WMI_IMPLICIT_PSTREAM;
+		ath6kl_wmi_create_pstream_cmd(wmi, &cmd);
+	}
+
+	*ac = traffic_class;
+
+	return 0;
+}
+
+int ath6kl_wmi_dot11_hdr_remove(struct wmi *wmi, struct sk_buff *skb)
+{
+	struct ieee80211_hdr_3addr *pwh, wh;
+	struct ath6kl_llc_snap_hdr *llc_hdr;
+	struct ethhdr eth_hdr;
+	u32 hdr_size;
+	u8 *datap;
+	__le16 sub_type;
+
+	if (WARN_ON(skb == NULL))
+		return -EINVAL;
+
+	datap = skb->data;
+	pwh = (struct ieee80211_hdr_3addr *) datap;
+
+	sub_type = pwh->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE);
+
+	memcpy((u8 *) &wh, datap, sizeof(struct ieee80211_hdr_3addr));
+
+	/* Strip off the 802.11 header */
+	if (sub_type == cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
+		hdr_size = roundup(sizeof(struct ieee80211_qos_hdr),
+				   sizeof(u32));
+		skb_pull(skb, hdr_size);
+	} else if (sub_type == cpu_to_le16(IEEE80211_STYPE_DATA))
+		skb_pull(skb, sizeof(struct ieee80211_hdr_3addr));
+
+	datap = skb->data;
+	llc_hdr = (struct ath6kl_llc_snap_hdr *)(datap);
+
+	memset(&eth_hdr, 0, sizeof(eth_hdr));
+	eth_hdr.h_proto = llc_hdr->eth_type;
+
+	switch ((le16_to_cpu(wh.frame_control)) &
+		(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
+	case 0:
+		memcpy(eth_hdr.h_dest, wh.addr1, ETH_ALEN);
+		memcpy(eth_hdr.h_source, wh.addr2, ETH_ALEN);
+		break;
+	case IEEE80211_FCTL_TODS:
+		memcpy(eth_hdr.h_dest, wh.addr3, ETH_ALEN);
+		memcpy(eth_hdr.h_source, wh.addr2, ETH_ALEN);
+		break;
+	case IEEE80211_FCTL_FROMDS:
+		memcpy(eth_hdr.h_dest, wh.addr1, ETH_ALEN);
+		memcpy(eth_hdr.h_source, wh.addr3, ETH_ALEN);
+		break;
+	case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
+		break;
+	}
+
+	skb_pull(skb, sizeof(struct ath6kl_llc_snap_hdr));
+	skb_push(skb, sizeof(eth_hdr));
+
+	datap = skb->data;
+
+	memcpy(datap, &eth_hdr, sizeof(eth_hdr));
+
+	return 0;
+}
+
+/*
+ * Performs 802.3 to DIX encapsulation for received packets.
+ * Assumes the entire 802.3 header is contigous.
+ */
+int ath6kl_wmi_dot3_2_dix(struct sk_buff *skb)
+{
+	struct ath6kl_llc_snap_hdr *llc_hdr;
+	struct ethhdr eth_hdr;
+	u8 *datap;
+
+	if (WARN_ON(skb == NULL))
+		return -EINVAL;
+
+	datap = skb->data;
+
+	memcpy(&eth_hdr, datap, sizeof(eth_hdr));
+
+	llc_hdr = (struct ath6kl_llc_snap_hdr *) (datap + sizeof(eth_hdr));
+	eth_hdr.h_proto = llc_hdr->eth_type;
+
+	skb_pull(skb, sizeof(struct ath6kl_llc_snap_hdr));
+	datap = skb->data;
+
+	memcpy(datap, &eth_hdr, sizeof(eth_hdr));
+
+	return 0;
+}
+
+int ath6kl_wmi_data_hdr_remove(struct wmi *wmi, struct sk_buff *skb)
+{
+	if (WARN_ON(skb == NULL))
+		return -EINVAL;
+
+	skb_pull(skb, sizeof(struct wmi_data_hdr));
+
+	return 0;
+}
+
+static void ath6kl_wmi_convert_bssinfo_hdr2_to_hdr(struct sk_buff *skb,
+						   u8 *datap)
+{
+	struct wmi_bss_info_hdr2 bih2;
+	struct wmi_bss_info_hdr *bih;
+
+	memcpy(&bih2, datap, sizeof(struct wmi_bss_info_hdr2));
+
+	skb_push(skb, 4);
+	bih = (struct wmi_bss_info_hdr *) skb->data;
+
+	bih->ch = bih2.ch;
+	bih->frame_type = bih2.frame_type;
+	bih->snr = bih2.snr;
+	bih->rssi = a_cpu_to_sle16(bih2.snr - 95);
+	bih->ie_mask = cpu_to_le32(le16_to_cpu(bih2.ie_mask));
+	memcpy(bih->bssid, bih2.bssid, ETH_ALEN);
+}
+
+static int ath6kl_wmi_tx_complete_event_rx(u8 *datap, int len)
+{
+	struct tx_complete_msg_v1 *msg_v1;
+	struct wmi_tx_complete_event *evt;
+	int index;
+	u16 size;
+
+	evt = (struct wmi_tx_complete_event *) datap;
+
+	ath6kl_dbg(ATH6KL_DBG_WMI, "comp: %d %d %d\n",
+		   evt->num_msg, evt->msg_len, evt->msg_type);
+
+	if (!AR_DBG_LVL_CHECK(ATH6KL_DBG_WMI))
+		return 0;
+
+	for (index = 0; index < evt->num_msg; index++) {
+		size = sizeof(struct wmi_tx_complete_event) +
+		    (index * sizeof(struct tx_complete_msg_v1));
+		msg_v1 = (struct tx_complete_msg_v1 *)(datap + size);
+
+		ath6kl_dbg(ATH6KL_DBG_WMI, "msg: %d %d %d %d\n",
+			   msg_v1->status, msg_v1->pkt_id,
+			   msg_v1->rate_idx, msg_v1->ack_failures);
+	}
+
+	return 0;
+}
+
+static inline struct sk_buff *ath6kl_wmi_get_new_buf(u32 size)
+{
+	struct sk_buff *skb;
+
+	skb = ath6kl_buf_alloc(size);
+	if (!skb)
+		return NULL;
+
+	skb_put(skb, size);
+	if (size)
+		memset(skb->data, 0, size);
+
+	return skb;
+}
+
+/* Send a "simple" wmi command -- one with no arguments */
+static int ath6kl_wmi_simple_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id)
+{
+	struct sk_buff *skb;
+	int ret;
+
+	skb = ath6kl_wmi_get_new_buf(0);
+	if (!skb)
+		return -ENOMEM;
+
+	ret = ath6kl_wmi_cmd_send(wmi, skb, cmd_id, NO_SYNC_WMIFLAG);
+
+	return ret;
+}
+
+static int ath6kl_wmi_ready_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+	struct wmi_ready_event_2 *ev = (struct wmi_ready_event_2 *) datap;
+
+	if (len < sizeof(struct wmi_ready_event_2))
+		return -EINVAL;
+
+	wmi->ready = true;
+	ath6kl_ready_event(wmi->parent_dev, ev->mac_addr,
+			   le32_to_cpu(ev->sw_version),
+			   le32_to_cpu(ev->abi_version));
+
+	return 0;
+}
+
+static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+	struct wmi_connect_event *ev;
+	u8 *pie, *peie;
+
+	if (len < sizeof(struct wmi_connect_event))
+		return -EINVAL;
+
+	ev = (struct wmi_connect_event *) datap;
+
+	ath6kl_dbg(ATH6KL_DBG_WMI, "%s: freq %d bssid %pM\n",
+		   __func__, ev->ch, ev->bssid);
+
+	/* Start of assoc rsp IEs */
+	pie = ev->assoc_info + ev->beacon_ie_len +
+	      ev->assoc_req_len + (sizeof(u16) * 3); /* capinfo, status, aid */
+
+	/* End of assoc rsp IEs */
+	peie = ev->assoc_info + ev->beacon_ie_len + ev->assoc_req_len +
+	    ev->assoc_resp_len;
+
+	while (pie < peie) {
+		switch (*pie) {
+		case WLAN_EID_VENDOR_SPECIFIC:
+			if (pie[1] > 3 && pie[2] == 0x00 && pie[3] == 0x50 &&
+			    pie[4] == 0xf2 && pie[5] == WMM_OUI_TYPE) {
+				/* WMM OUT (00:50:F2) */
+				if (pie[1] > 5
+				    && pie[6] == WMM_PARAM_OUI_SUBTYPE)
+					wmi->is_wmm_enabled = true;
+			}
+			break;
+		}
+
+		if (wmi->is_wmm_enabled)
+			break;
+
+		pie += pie[1] + 2;
+	}
+
+	ath6kl_connect_event(wmi->parent_dev, le16_to_cpu(ev->ch), ev->bssid,
+			     le16_to_cpu(ev->listen_intvl),
+			     le16_to_cpu(ev->beacon_intvl),
+			     le32_to_cpu(ev->nw_type),
+			     ev->beacon_ie_len, ev->assoc_req_len,
+			     ev->assoc_resp_len, ev->assoc_info);
+
+	return 0;
+}
+
+static int ath6kl_wmi_disconnect_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+	struct wmi_disconnect_event *ev;
+	wmi->traffic_class = 100;
+
+	if (len < sizeof(struct wmi_disconnect_event))
+		return -EINVAL;
+
+	ev = (struct wmi_disconnect_event *) datap;
+
+	wmi->is_wmm_enabled = false;
+	wmi->pair_crypto_type = NONE_CRYPT;
+	wmi->grp_crypto_type = NONE_CRYPT;
+
+	ath6kl_disconnect_event(wmi->parent_dev, ev->disconn_reason,
+				ev->bssid, ev->assoc_resp_len, ev->assoc_info,
+				le16_to_cpu(ev->proto_reason_status));
+
+	return 0;
+}
+
+static int ath6kl_wmi_peer_node_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+	struct wmi_peer_node_event *ev;
+
+	if (len < sizeof(struct wmi_peer_node_event))
+		return -EINVAL;
+
+	ev = (struct wmi_peer_node_event *) datap;
+
+	if (ev->event_code == PEER_NODE_JOIN_EVENT)
+		ath6kl_dbg(ATH6KL_DBG_WMI, "joined node with mac addr: %pM\n",
+			   ev->peer_mac_addr);
+	else if (ev->event_code == PEER_NODE_LEAVE_EVENT)
+		ath6kl_dbg(ATH6KL_DBG_WMI, "left node with mac addr: %pM\n",
+			   ev->peer_mac_addr);
+
+	return 0;
+}
+
+static int ath6kl_wmi_tkip_micerr_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+	struct wmi_tkip_micerr_event *ev;
+
+	if (len < sizeof(struct wmi_tkip_micerr_event))
+		return -EINVAL;
+
+	ev = (struct wmi_tkip_micerr_event *) datap;
+
+	ath6kl_tkip_micerr_event(wmi->parent_dev, ev->key_id, ev->is_mcast);
+
+	return 0;
+}
+
+static int ath6kl_wlan_parse_beacon(u8 *buf, int frame_len,
+				    struct ath6kl_common_ie *cie)
+{
+	u8 *frm, *efrm;
+	u8 elemid_ssid = false;
+
+	frm = buf;
+	efrm = (u8 *) (frm + frame_len);
+
+	/*
+	 * beacon/probe response frame format
+	 *  [8] time stamp
+	 *  [2] beacon interval
+	 *  [2] capability information
+	 *  [tlv] ssid
+	 *  [tlv] supported rates
+	 *  [tlv] country information
+	 *  [tlv] parameter set (FH/DS)
+	 *  [tlv] erp information
+	 *  [tlv] extended supported rates
+	 *  [tlv] WMM
+	 *  [tlv] WPA or RSN
+	 *  [tlv] Atheros Advanced Capabilities
+	 */
+	if ((efrm - frm) < 12)
+		return -EINVAL;
+
+	memset(cie, 0, sizeof(*cie));
+
+	cie->ie_tstamp = frm;
+	frm += 8;
+	cie->ie_beaconInt = *(u16 *) frm;
+	frm += 2;
+	cie->ie_capInfo = *(u16 *) frm;
+	frm += 2;
+	cie->ie_chan = 0;
+
+	while (frm < efrm) {
+		switch (*frm) {
+		case WLAN_EID_SSID:
+			if (!elemid_ssid) {
+				cie->ie_ssid = frm;
+				elemid_ssid = true;
+			}
+			break;
+		case WLAN_EID_SUPP_RATES:
+			cie->ie_rates = frm;
+			break;
+		case WLAN_EID_COUNTRY:
+			cie->ie_country = frm;
+			break;
+		case WLAN_EID_FH_PARAMS:
+			break;
+		case WLAN_EID_DS_PARAMS:
+			cie->ie_chan = frm[2];
+			break;
+		case WLAN_EID_TIM:
+			cie->ie_tim = frm;
+			break;
+		case WLAN_EID_IBSS_PARAMS:
+			break;
+		case WLAN_EID_EXT_SUPP_RATES:
+			cie->ie_xrates = frm;
+			break;
+		case WLAN_EID_ERP_INFO:
+			if (frm[1] != 1)
+				return -EINVAL;
+
+			cie->ie_erp = frm[2];
+			break;
+		case WLAN_EID_RSN:
+			cie->ie_rsn = frm;
+			break;
+		case WLAN_EID_HT_CAPABILITY:
+			cie->ie_htcap = frm;
+			break;
+		case WLAN_EID_HT_INFORMATION:
+			cie->ie_htop = frm;
+			break;
+		case WLAN_EID_VENDOR_SPECIFIC:
+			if (frm[1] > 3 && frm[2] == 0x00 && frm[3] == 0x50 &&
+			    frm[4] == 0xf2) {
+				/* OUT Type (00:50:F2) */
+
+				if (frm[5] == WPA_OUI_TYPE) {
+					/* WPA OUT */
+					cie->ie_wpa = frm;
+				} else if (frm[5] == WMM_OUI_TYPE) {
+					/* WMM OUT */
+					cie->ie_wmm = frm;
+				} else if (frm[5] == WSC_OUT_TYPE) {
+					/* WSC OUT */
+					cie->ie_wsc = frm;
+				}
+
+			} else if (frm[1] > 3 && frm[2] == 0x00
+				   && frm[3] == 0x03 && frm[4] == 0x7f
+				   && frm[5] == ATH_OUI_TYPE) {
+				/* Atheros OUI (00:03:7f) */
+				cie->ie_ath = frm;
+			}
+			break;
+		default:
+			break;
+		}
+		frm += frm[1] + 2;
+	}
+
+	if ((cie->ie_rates == NULL)
+	    || (cie->ie_rates[1] > ATH6KL_RATE_MAXSIZE))
+		return -EINVAL;
+
+	if ((cie->ie_ssid == NULL)
+	    || (cie->ie_ssid[1] > IEEE80211_MAX_SSID_LEN))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+	struct bss *bss = NULL;
+	struct wmi_bss_info_hdr *bih;
+	u8 cached_ssid_len = 0;
+	u8 cached_ssid[IEEE80211_MAX_SSID_LEN] = { 0 };
+	u8 beacon_ssid_len = 0;
+	u8 *buf, *ie_ssid;
+	u8 *ni_buf;
+	int buf_len;
+
+	int ret;
+
+	if (len <= sizeof(struct wmi_bss_info_hdr))
+		return -EINVAL;
+
+	bih = (struct wmi_bss_info_hdr *) datap;
+	bss = wlan_find_node(&wmi->parent_dev->scan_table, bih->bssid);
+
+	if (a_sle16_to_cpu(bih->rssi) > 0) {
+		if (bss == NULL)
+			return 0;
+		else
+			bih->rssi = a_cpu_to_sle16(bss->ni_rssi);
+	}
+
+	buf = datap + sizeof(struct wmi_bss_info_hdr);
+	len -= sizeof(struct wmi_bss_info_hdr);
+
+	ath6kl_dbg(ATH6KL_DBG_WMI,
+		   "bss info evt - ch %u, rssi %02x, bssid \"%pM\"\n",
+		   bih->ch, a_sle16_to_cpu(bih->rssi), bih->bssid);
+
+	if (bss != NULL) {
+		/*
+		 * Free up the node. We are about to allocate a new node.
+		 * In case of hidden AP, beacon will not have ssid,
+		 * but a directed probe response will have it,
+		 * so cache the probe-resp-ssid if already present.
+		 */
+		if (wmi->is_probe_ssid && (bih->frame_type == BEACON_FTYPE)) {
+			ie_ssid = bss->ni_cie.ie_ssid;
+			if (ie_ssid && (ie_ssid[1] <= IEEE80211_MAX_SSID_LEN) &&
+			    (ie_ssid[2] != 0)) {
+				cached_ssid_len = ie_ssid[1];
+				memcpy(cached_ssid, ie_ssid + 2,
+				       cached_ssid_len);
+			}
+		}
+
+		/*
+		 * Use the current average rssi of associated AP base on
+		 * assumption
+		 *   1. Most os with GUI will update RSSI by
+		 *      ath6kl_wmi_get_stats_cmd() periodically.
+		 *   2. ath6kl_wmi_get_stats_cmd(..) will be called when calling
+		 *      ath6kl_wmi_startscan_cmd(...)
+		 * The average value of RSSI give end-user better feeling for
+		 * instance value of scan result. It also sync up RSSI info
+		 * in GUI between scan result and RSSI signal icon.
+		 */
+		if (memcmp(wmi->parent_dev->bssid, bih->bssid, ETH_ALEN) == 0) {
+			bih->rssi = a_cpu_to_sle16(bss->ni_rssi);
+			bih->snr = bss->ni_snr;
+		}
+
+		wlan_node_reclaim(&wmi->parent_dev->scan_table, bss);
+	}
+
+	/*
+	 * beacon/probe response frame format
+	 *  [8] time stamp
+	 *  [2] beacon interval
+	 *  [2] capability information
+	 *  [tlv] ssid
+	 */
+	beacon_ssid_len = buf[SSID_IE_LEN_INDEX];
+
+	/*
+	 * If ssid is cached for this hidden AP, then change
+	 * buffer len accordingly.
+	 */
+	if (wmi->is_probe_ssid && (bih->frame_type == BEACON_FTYPE) &&
+	    (cached_ssid_len != 0) &&
+	    (beacon_ssid_len == 0 || (cached_ssid_len > beacon_ssid_len &&
+				      buf[SSID_IE_LEN_INDEX + 1] == 0))) {
+
+		len += (cached_ssid_len - beacon_ssid_len);
+	}
+
+	bss = wlan_node_alloc(len);
+	if (!bss)
+		return -ENOMEM;
+
+	bss->ni_snr = bih->snr;
+	bss->ni_rssi = a_sle16_to_cpu(bih->rssi);
+
+	if (WARN_ON(!bss->ni_buf))
+		return -EINVAL;
+
+	/*
+	 * In case of hidden AP, beacon will not have ssid,
+	 * but a directed probe response will have it,
+	 * so place the cached-ssid(probe-resp) in the bss info.
+	 */
+	if (wmi->is_probe_ssid && (bih->frame_type == BEACON_FTYPE) &&
+	    (cached_ssid_len != 0) &&
+	    (beacon_ssid_len == 0 || (beacon_ssid_len &&
+				      buf[SSID_IE_LEN_INDEX + 1] == 0))) {
+		ni_buf = bss->ni_buf;
+		buf_len = len;
+
+		/*
+		 * Copy the first 14 bytes:
+		 * time-stamp(8), beacon-interval(2),
+		 * cap-info(2), ssid-id(1), ssid-len(1).
+		 */
+		memcpy(ni_buf, buf, SSID_IE_LEN_INDEX + 1);
+
+		ni_buf[SSID_IE_LEN_INDEX] = cached_ssid_len;
+		ni_buf += (SSID_IE_LEN_INDEX + 1);
+
+		buf += (SSID_IE_LEN_INDEX + 1);
+		buf_len -= (SSID_IE_LEN_INDEX + 1);
+
+		memcpy(ni_buf, cached_ssid, cached_ssid_len);
+		ni_buf += cached_ssid_len;
+
+		buf += beacon_ssid_len;
+		buf_len -= beacon_ssid_len;
+
+		if (cached_ssid_len > beacon_ssid_len)
+			buf_len -= (cached_ssid_len - beacon_ssid_len);
+
+		memcpy(ni_buf, buf, buf_len);
+	} else
+		memcpy(bss->ni_buf, buf, len);
+
+	bss->ni_framelen = len;
+
+	ret = ath6kl_wlan_parse_beacon(bss->ni_buf, len, &bss->ni_cie);
+	if (ret) {
+		wlan_node_free(bss);
+		return -EINVAL;
+	}
+
+	/*
+	 * Update the frequency in ie_chan, overwriting of channel number
+	 * which is done in ath6kl_wlan_parse_beacon
+	 */
+	bss->ni_cie.ie_chan = le16_to_cpu(bih->ch);
+	wlan_setup_node(&wmi->parent_dev->scan_table, bss, bih->bssid);
+
+	return 0;
+}
+
+static int ath6kl_wmi_opt_frame_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+	struct bss *bss;
+	struct wmi_opt_rx_info_hdr *bih;
+	u8 *buf;
+
+	if (len <= sizeof(struct wmi_opt_rx_info_hdr))
+		return -EINVAL;
+
+	bih = (struct wmi_opt_rx_info_hdr *) datap;
+	buf = datap + sizeof(struct wmi_opt_rx_info_hdr);
+	len -= sizeof(struct wmi_opt_rx_info_hdr);
+
+	ath6kl_dbg(ATH6KL_DBG_WMI, "opt frame event %2.2x:%2.2x\n",
+		   bih->bssid[4], bih->bssid[5]);
+
+	bss = wlan_find_node(&wmi->parent_dev->scan_table, bih->bssid);
+	if (bss != NULL) {
+		/* Free up the node. We are about to allocate a new node. */
+		wlan_node_reclaim(&wmi->parent_dev->scan_table, bss);
+	}
+
+	bss = wlan_node_alloc(len);
+	if (!bss)
+		return -ENOMEM;
+
+	bss->ni_snr = bih->snr;
+	bss->ni_cie.ie_chan = le16_to_cpu(bih->ch);
+
+	if (WARN_ON(!bss->ni_buf))
+		return -EINVAL;
+
+	memcpy(bss->ni_buf, buf, len);
+	wlan_setup_node(&wmi->parent_dev->scan_table, bss, bih->bssid);
+
+	return 0;
+}
+
+/* Inactivity timeout of a fatpipe(pstream) at the target */
+static int ath6kl_wmi_pstream_timeout_event_rx(struct wmi *wmi, u8 *datap,
+					       int len)
+{
+	struct wmi_pstream_timeout_event *ev;
+
+	if (len < sizeof(struct wmi_pstream_timeout_event))
+		return -EINVAL;
+
+	ev = (struct wmi_pstream_timeout_event *) datap;
+
+	/*
+	 * When the pstream (fat pipe == AC) timesout, it means there were
+	 * no thinStreams within this pstream & it got implicitly created
+	 * due to data flow on this AC. We start the inactivity timer only
+	 * for implicitly created pstream. Just reset the host state.
+	 */
+	spin_lock_bh(&wmi->lock);
+	wmi->stream_exist_for_ac[ev->traffic_class] = 0;
+	wmi->fat_pipe_exist &= ~(1 << ev->traffic_class);
+	spin_unlock_bh(&wmi->lock);
+
+	/* Indicate inactivity to driver layer for this fatpipe (pstream) */
+	ath6kl_indicate_tx_activity(wmi->parent_dev, ev->traffic_class, false);
+
+	return 0;
+}
+
+static int ath6kl_wmi_bitrate_reply_rx(struct wmi *wmi, u8 *datap, int len)
+{
+	struct wmi_bit_rate_reply *reply;
+	s32 rate;
+	u32 sgi, index;
+
+	if (len < sizeof(struct wmi_bit_rate_reply))
+		return -EINVAL;
+
+	reply = (struct wmi_bit_rate_reply *) datap;
+
+	ath6kl_dbg(ATH6KL_DBG_WMI, "rateindex %d\n", reply->rate_index);
+
+	if (reply->rate_index == (s8) RATE_AUTO) {
+		rate = RATE_AUTO;
+	} else {
+		index = reply->rate_index & 0x7f;
+		sgi = (reply->rate_index & 0x80) ? 1 : 0;
+		rate = wmi_rate_tbl[index][sgi];
+	}
+
+	ath6kl_wakeup_event(wmi->parent_dev);
+
+	return 0;
+}
+
+static int ath6kl_wmi_ratemask_reply_rx(struct wmi *wmi, u8 *datap, int len)
+{
+	if (len < sizeof(struct wmi_fix_rates_reply))
+		return -EINVAL;
+
+	ath6kl_wakeup_event(wmi->parent_dev);
+
+	return 0;
+}
+
+static int ath6kl_wmi_ch_list_reply_rx(struct wmi *wmi, u8 *datap, int len)
+{
+	if (len < sizeof(struct wmi_channel_list_reply))
+		return -EINVAL;
+
+	ath6kl_wakeup_event(wmi->parent_dev);
+
+	return 0;
+}
+
+static int ath6kl_wmi_tx_pwr_reply_rx(struct wmi *wmi, u8 *datap, int len)
+{
+	struct wmi_tx_pwr_reply *reply;
+
+	if (len < sizeof(struct wmi_tx_pwr_reply))
+		return -EINVAL;
+
+	reply = (struct wmi_tx_pwr_reply *) datap;
+	ath6kl_txpwr_rx_evt(wmi->parent_dev, reply->dbM);
+
+	return 0;
+}
+
+static int ath6kl_wmi_keepalive_reply_rx(struct wmi *wmi, u8 *datap, int len)
+{
+	if (len < sizeof(struct wmi_get_keepalive_cmd))
+		return -EINVAL;
+
+	ath6kl_wakeup_event(wmi->parent_dev);
+
+	return 0;
+}
+
+static int ath6kl_wmi_scan_complete_rx(struct wmi *wmi, u8 *datap, int len)
+{
+	struct wmi_scan_complete_event *ev;
+
+	ev = (struct wmi_scan_complete_event *) datap;
+
+	if (a_sle32_to_cpu(ev->status) == 0)
+		wlan_refresh_inactive_nodes(wmi->parent_dev);
+
+	ath6kl_scan_complete_evt(wmi->parent_dev, a_sle32_to_cpu(ev->status));
+	wmi->is_probe_ssid = false;
+
+	return 0;
+}
+
+/*
+ * Target is reporting a programming error.  This is for
+ * developer aid only.  Target only checks a few common violations
+ * and it is responsibility of host to do all error checking.
+ * Behavior of target after wmi error event is undefined.
+ * A reset is recommended.
+ */
+static int ath6kl_wmi_error_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+	const char *type = "unknown error";
+	struct wmi_cmd_error_event *ev;
+	ev = (struct wmi_cmd_error_event *) datap;
+
+	switch (ev->err_code) {
+	case INVALID_PARAM:
+		type = "invalid parameter";
+		break;
+	case ILLEGAL_STATE:
+		type = "invalid state";
+		break;
+	case INTERNAL_ERROR:
+		type = "internal error";
+		break;
+	}
+
+	ath6kl_dbg(ATH6KL_DBG_WMI, "programming error, cmd=%d %s\n",
+		   ev->cmd_id, type);
+
+	return 0;
+}
+
+static int ath6kl_wmi_stats_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+	ath6kl_tgt_stats_event(wmi->parent_dev, datap, len);
+
+	return 0;
+}
+
+static u8 ath6kl_wmi_get_upper_threshold(s16 rssi,
+					 struct sq_threshold_params *sq_thresh,
+					 u32 size)
+{
+	u32 index;
+	u8 threshold = (u8) sq_thresh->upper_threshold[size - 1];
+
+	/* The list is already in sorted order. Get the next lower value */
+	for (index = 0; index < size; index++) {
+		if (rssi < sq_thresh->upper_threshold[index]) {
+			threshold = (u8) sq_thresh->upper_threshold[index];
+			break;
+		}
+	}
+
+	return threshold;
+}
+
+static u8 ath6kl_wmi_get_lower_threshold(s16 rssi,
+					 struct sq_threshold_params *sq_thresh,
+					 u32 size)
+{
+	u32 index;
+	u8 threshold = (u8) sq_thresh->lower_threshold[size - 1];
+
+	/* The list is already in sorted order. Get the next lower value */
+	for (index = 0; index < size; index++) {
+		if (rssi > sq_thresh->lower_threshold[index]) {
+			threshold = (u8) sq_thresh->lower_threshold[index];
+			break;
+		}
+	}
+
+	return threshold;
+}
+
+static int ath6kl_wmi_send_rssi_threshold_params(struct wmi *wmi,
+			struct wmi_rssi_threshold_params_cmd *rssi_cmd)
+{
+	struct sk_buff *skb;
+	struct wmi_rssi_threshold_params_cmd *cmd;
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_rssi_threshold_params_cmd *) skb->data;
+	memcpy(cmd, rssi_cmd, sizeof(struct wmi_rssi_threshold_params_cmd));
+
+	return ath6kl_wmi_cmd_send(wmi, skb, WMI_RSSI_THRESHOLD_PARAMS_CMDID,
+				   NO_SYNC_WMIFLAG);
+}
+
+static int ath6kl_wmi_rssi_threshold_event_rx(struct wmi *wmi, u8 *datap,
+					      int len)
+{
+	struct wmi_rssi_threshold_event *reply;
+	struct wmi_rssi_threshold_params_cmd cmd;
+	struct sq_threshold_params *sq_thresh;
+	enum wmi_rssi_threshold_val new_threshold;
+	u8 upper_rssi_threshold, lower_rssi_threshold;
+	s16 rssi;
+	int ret;
+
+	if (len < sizeof(struct wmi_rssi_threshold_event))
+		return -EINVAL;
+
+	reply = (struct wmi_rssi_threshold_event *) datap;
+	new_threshold = (enum wmi_rssi_threshold_val) reply->range;
+	rssi = a_sle16_to_cpu(reply->rssi);
+
+	sq_thresh = &wmi->sq_threshld[SIGNAL_QUALITY_METRICS_RSSI];
+
+	/*
+	 * Identify the threshold breached and communicate that to the app.
+	 * After that install a new set of thresholds based on the signal
+	 * quality reported by the target
+	 */
+	if (new_threshold) {
+		/* Upper threshold breached */
+		if (rssi < sq_thresh->upper_threshold[0]) {
+			ath6kl_dbg(ATH6KL_DBG_WMI,
+				"spurious upper rssi threshold event: %d\n",
+				rssi);
+		} else if ((rssi < sq_thresh->upper_threshold[1]) &&
+			   (rssi >= sq_thresh->upper_threshold[0])) {
+			new_threshold = WMI_RSSI_THRESHOLD1_ABOVE;
+		} else if ((rssi < sq_thresh->upper_threshold[2]) &&
+			   (rssi >= sq_thresh->upper_threshold[1])) {
+			new_threshold = WMI_RSSI_THRESHOLD2_ABOVE;
+		} else if ((rssi < sq_thresh->upper_threshold[3]) &&
+			   (rssi >= sq_thresh->upper_threshold[2])) {
+			new_threshold = WMI_RSSI_THRESHOLD3_ABOVE;
+		} else if ((rssi < sq_thresh->upper_threshold[4]) &&
+			   (rssi >= sq_thresh->upper_threshold[3])) {
+			new_threshold = WMI_RSSI_THRESHOLD4_ABOVE;
+		} else if ((rssi < sq_thresh->upper_threshold[5]) &&
+			   (rssi >= sq_thresh->upper_threshold[4])) {
+			new_threshold = WMI_RSSI_THRESHOLD5_ABOVE;
+		} else if (rssi >= sq_thresh->upper_threshold[5]) {
+			new_threshold = WMI_RSSI_THRESHOLD6_ABOVE;
+		}
+	} else {
+		/* Lower threshold breached */
+		if (rssi > sq_thresh->lower_threshold[0]) {
+			ath6kl_dbg(ATH6KL_DBG_WMI,
+				"spurious lower rssi threshold event: %d %d\n",
+				rssi, sq_thresh->lower_threshold[0]);
+		} else if ((rssi > sq_thresh->lower_threshold[1]) &&
+			   (rssi <= sq_thresh->lower_threshold[0])) {
+			new_threshold = WMI_RSSI_THRESHOLD6_BELOW;
+		} else if ((rssi > sq_thresh->lower_threshold[2]) &&
+			   (rssi <= sq_thresh->lower_threshold[1])) {
+			new_threshold = WMI_RSSI_THRESHOLD5_BELOW;
+		} else if ((rssi > sq_thresh->lower_threshold[3]) &&
+			   (rssi <= sq_thresh->lower_threshold[2])) {
+			new_threshold = WMI_RSSI_THRESHOLD4_BELOW;
+		} else if ((rssi > sq_thresh->lower_threshold[4]) &&
+			   (rssi <= sq_thresh->lower_threshold[3])) {
+			new_threshold = WMI_RSSI_THRESHOLD3_BELOW;
+		} else if ((rssi > sq_thresh->lower_threshold[5]) &&
+			   (rssi <= sq_thresh->lower_threshold[4])) {
+			new_threshold = WMI_RSSI_THRESHOLD2_BELOW;
+		} else if (rssi <= sq_thresh->lower_threshold[5]) {
+			new_threshold = WMI_RSSI_THRESHOLD1_BELOW;
+		}
+	}
+
+	/* Calculate and install the next set of thresholds */
+	lower_rssi_threshold = ath6kl_wmi_get_lower_threshold(rssi, sq_thresh,
+				       sq_thresh->lower_threshold_valid_count);
+	upper_rssi_threshold = ath6kl_wmi_get_upper_threshold(rssi, sq_thresh,
+				       sq_thresh->upper_threshold_valid_count);
+
+	/* Issue a wmi command to install the thresholds */
+	cmd.thresh_above1_val = a_cpu_to_sle16(upper_rssi_threshold);
+	cmd.thresh_below1_val = a_cpu_to_sle16(lower_rssi_threshold);
+	cmd.weight = sq_thresh->weight;
+	cmd.poll_time = cpu_to_le32(sq_thresh->polling_interval);
+
+	ret = ath6kl_wmi_send_rssi_threshold_params(wmi, &cmd);
+	if (ret) {
+		ath6kl_err("unable to configure rssi thresholds\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int ath6kl_wmi_cac_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+	struct wmi_cac_event *reply;
+	struct ieee80211_tspec_ie *ts;
+	u16 active_tsids, tsinfo;
+	u8 tsid, index;
+	u8 ts_id;
+
+	if (len < sizeof(struct wmi_cac_event))
+		return -EINVAL;
+
+	reply = (struct wmi_cac_event *) datap;
+
+	if ((reply->cac_indication == CAC_INDICATION_ADMISSION_RESP) &&
+	    (reply->status_code != IEEE80211_TSPEC_STATUS_ADMISS_ACCEPTED)) {
+
+		ts = (struct ieee80211_tspec_ie *) &(reply->tspec_suggestion);
+		tsinfo = le16_to_cpu(ts->tsinfo);
+		tsid = (tsinfo >> IEEE80211_WMM_IE_TSPEC_TID_SHIFT) &
+			IEEE80211_WMM_IE_TSPEC_TID_MASK;
+
+		ath6kl_wmi_delete_pstream_cmd(wmi, reply->ac, tsid);
+	} else if (reply->cac_indication == CAC_INDICATION_NO_RESP) {
+		/*
+		 * Following assumes that there is only one outstanding
+		 * ADDTS request when this event is received
+		 */
+		spin_lock_bh(&wmi->lock);
+		active_tsids = wmi->stream_exist_for_ac[reply->ac];
+		spin_unlock_bh(&wmi->lock);
+
+		for (index = 0; index < sizeof(active_tsids) * 8; index++) {
+			if ((active_tsids >> index) & 1)
+				break;
+		}
+		if (index < (sizeof(active_tsids) * 8))
+			ath6kl_wmi_delete_pstream_cmd(wmi, reply->ac, index);
+	}
+
+	/*
+	 * Clear active tsids and Add missing handling
+	 * for delete qos stream from AP
+	 */
+	else if (reply->cac_indication == CAC_INDICATION_DELETE) {
+
+		ts = (struct ieee80211_tspec_ie *) &(reply->tspec_suggestion);
+		tsinfo = le16_to_cpu(ts->tsinfo);
+		ts_id = ((tsinfo >> IEEE80211_WMM_IE_TSPEC_TID_SHIFT) &
+			 IEEE80211_WMM_IE_TSPEC_TID_MASK);
+
+		spin_lock_bh(&wmi->lock);
+		wmi->stream_exist_for_ac[reply->ac] &= ~(1 << ts_id);
+		active_tsids = wmi->stream_exist_for_ac[reply->ac];
+		spin_unlock_bh(&wmi->lock);
+
+		/* Indicate stream inactivity to driver layer only if all tsids
+		 * within this AC are deleted.
+		 */
+		if (!active_tsids) {
+			ath6kl_indicate_tx_activity(wmi->parent_dev, reply->ac,
+						    false);
+			wmi->fat_pipe_exist &= ~(1 << reply->ac);
+		}
+	}
+
+	return 0;
+}
+
+static int ath6kl_wmi_send_snr_threshold_params(struct wmi *wmi,
+			struct wmi_snr_threshold_params_cmd *snr_cmd)
+{
+	struct sk_buff *skb;
+	struct wmi_snr_threshold_params_cmd *cmd;
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_snr_threshold_params_cmd *) skb->data;
+	memcpy(cmd, snr_cmd, sizeof(struct wmi_snr_threshold_params_cmd));
+
+	return ath6kl_wmi_cmd_send(wmi, skb, WMI_SNR_THRESHOLD_PARAMS_CMDID,
+				   NO_SYNC_WMIFLAG);
+}
+
+static int ath6kl_wmi_snr_threshold_event_rx(struct wmi *wmi, u8 *datap,
+					     int len)
+{
+	struct wmi_snr_threshold_event *reply;
+	struct sq_threshold_params *sq_thresh;
+	struct wmi_snr_threshold_params_cmd cmd;
+	enum wmi_snr_threshold_val new_threshold;
+	u8 upper_snr_threshold, lower_snr_threshold;
+	s16 snr;
+	int ret;
+
+	if (len < sizeof(struct wmi_snr_threshold_event))
+		return -EINVAL;
+
+	reply = (struct wmi_snr_threshold_event *) datap;
+
+	new_threshold = (enum wmi_snr_threshold_val) reply->range;
+	snr = reply->snr;
+
+	sq_thresh = &wmi->sq_threshld[SIGNAL_QUALITY_METRICS_SNR];
+
+	/*
+	 * Identify the threshold breached and communicate that to the app.
+	 * After that install a new set of thresholds based on the signal
+	 * quality reported by the target.
+	 */
+	if (new_threshold) {
+		/* Upper threshold breached */
+		if (snr < sq_thresh->upper_threshold[0]) {
+			ath6kl_dbg(ATH6KL_DBG_WMI,
+				"spurious upper snr threshold event: %d\n",
+				snr);
+		} else if ((snr < sq_thresh->upper_threshold[1]) &&
+			   (snr >= sq_thresh->upper_threshold[0])) {
+			new_threshold = WMI_SNR_THRESHOLD1_ABOVE;
+		} else if ((snr < sq_thresh->upper_threshold[2]) &&
+			   (snr >= sq_thresh->upper_threshold[1])) {
+			new_threshold = WMI_SNR_THRESHOLD2_ABOVE;
+		} else if ((snr < sq_thresh->upper_threshold[3]) &&
+			   (snr >= sq_thresh->upper_threshold[2])) {
+			new_threshold = WMI_SNR_THRESHOLD3_ABOVE;
+		} else if (snr >= sq_thresh->upper_threshold[3]) {
+			new_threshold = WMI_SNR_THRESHOLD4_ABOVE;
+		}
+	} else {
+		/* Lower threshold breached */
+		if (snr > sq_thresh->lower_threshold[0]) {
+			ath6kl_dbg(ATH6KL_DBG_WMI,
+				"spurious lower snr threshold event: %d\n",
+				sq_thresh->lower_threshold[0]);
+		} else if ((snr > sq_thresh->lower_threshold[1]) &&
+			   (snr <= sq_thresh->lower_threshold[0])) {
+			new_threshold = WMI_SNR_THRESHOLD4_BELOW;
+		} else if ((snr > sq_thresh->lower_threshold[2]) &&
+			   (snr <= sq_thresh->lower_threshold[1])) {
+			new_threshold = WMI_SNR_THRESHOLD3_BELOW;
+		} else if ((snr > sq_thresh->lower_threshold[3]) &&
+			   (snr <= sq_thresh->lower_threshold[2])) {
+			new_threshold = WMI_SNR_THRESHOLD2_BELOW;
+		} else if (snr <= sq_thresh->lower_threshold[3]) {
+			new_threshold = WMI_SNR_THRESHOLD1_BELOW;
+		}
+	}
+
+	/* Calculate and install the next set of thresholds */
+	lower_snr_threshold = ath6kl_wmi_get_lower_threshold(snr, sq_thresh,
+				       sq_thresh->lower_threshold_valid_count);
+	upper_snr_threshold = ath6kl_wmi_get_upper_threshold(snr, sq_thresh,
+				       sq_thresh->upper_threshold_valid_count);
+
+	/* Issue a wmi command to install the thresholds */
+	cmd.thresh_above1_val = upper_snr_threshold;
+	cmd.thresh_below1_val = lower_snr_threshold;
+	cmd.weight = sq_thresh->weight;
+	cmd.poll_time = cpu_to_le32(sq_thresh->polling_interval);
+
+	ath6kl_dbg(ATH6KL_DBG_WMI,
+		   "snr: %d, threshold: %d, lower: %d, upper: %d\n",
+		   snr, new_threshold,
+		   lower_snr_threshold, upper_snr_threshold);
+
+	ret = ath6kl_wmi_send_snr_threshold_params(wmi, &cmd);
+	if (ret) {
+		ath6kl_err("unable to configure snr threshold\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int ath6kl_wmi_aplist_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+	u16 ap_info_entry_size;
+	struct wmi_aplist_event *ev = (struct wmi_aplist_event *) datap;
+	struct wmi_ap_info_v1 *ap_info_v1;
+	u8 index;
+
+	if (len < sizeof(struct wmi_aplist_event) ||
+	    ev->ap_list_ver != APLIST_VER1)
+		return -EINVAL;
+
+	ap_info_entry_size = sizeof(struct wmi_ap_info_v1);
+	ap_info_v1 = (struct wmi_ap_info_v1 *) ev->ap_list;
+
+	ath6kl_dbg(ATH6KL_DBG_WMI,
+		   "number of APs in aplist event: %d\n", ev->num_ap);
+
+	if (len < (int) (sizeof(struct wmi_aplist_event) +
+			 (ev->num_ap - 1) * ap_info_entry_size))
+		return -EINVAL;
+
+	/* AP list version 1 contents */
+	for (index = 0; index < ev->num_ap; index++) {
+		ath6kl_dbg(ATH6KL_DBG_WMI, "AP#%d BSSID %pM Channel %d\n",
+			   index, ap_info_v1->bssid, ap_info_v1->channel);
+		ap_info_v1++;
+	}
+
+	return 0;
+}
+
+int ath6kl_wmi_cmd_send(struct wmi *wmi, struct sk_buff *skb,
+			enum wmi_cmd_id cmd_id, enum wmi_sync_flag sync_flag)
+{
+	struct wmi_cmd_hdr *cmd_hdr;
+	enum htc_endpoint_id ep_id = wmi->ep_id;
+	int ret;
+
+	if (WARN_ON(skb == NULL))
+		return -EINVAL;
+
+	if (sync_flag >= END_WMIFLAG) {
+		dev_kfree_skb(skb);
+		return -EINVAL;
+	}
+
+	if ((sync_flag == SYNC_BEFORE_WMIFLAG) ||
+	    (sync_flag == SYNC_BOTH_WMIFLAG)) {
+		/*
+		 * Make sure all data currently queued is transmitted before
+		 * the cmd execution.  Establish a new sync point.
+		 */
+		ath6kl_wmi_sync_point(wmi);
+	}
+
+	skb_push(skb, sizeof(struct wmi_cmd_hdr));
+
+	cmd_hdr = (struct wmi_cmd_hdr *) skb->data;
+	cmd_hdr->cmd_id = cpu_to_le16(cmd_id);
+	cmd_hdr->info1 = 0;	/* added for virtual interface */
+
+	/* Only for OPT_TX_CMD, use BE endpoint. */
+	if (cmd_id == WMI_OPT_TX_FRAME_CMDID) {
+		ret = ath6kl_wmi_data_hdr_add(wmi, skb, OPT_MSGTYPE,
+					      false, false, 0, NULL);
+		if (ret) {
+			dev_kfree_skb(skb);
+			return ret;
+		}
+		ep_id = ath6kl_ac2_endpoint_id(wmi->parent_dev, WMM_AC_BE);
+	}
+
+	ath6kl_control_tx(wmi->parent_dev, skb, ep_id);
+
+	if ((sync_flag == SYNC_AFTER_WMIFLAG) ||
+	    (sync_flag == SYNC_BOTH_WMIFLAG)) {
+		/*
+		 * Make sure all new data queued waits for the command to
+		 * execute. Establish a new sync point.
+		 */
+		ath6kl_wmi_sync_point(wmi);
+	}
+
+	return 0;
+}
+
+int ath6kl_wmi_connect_cmd(struct wmi *wmi, enum network_type nw_type,
+			   enum dot11_auth_mode dot11_auth_mode,
+			   enum auth_mode auth_mode,
+			   enum crypto_type pairwise_crypto,
+			   u8 pairwise_crypto_len,
+			   enum crypto_type group_crypto,
+			   u8 group_crypto_len, int ssid_len, u8 *ssid,
+			   u8 *bssid, u16 channel, u32 ctrl_flags)
+{
+	struct sk_buff *skb;
+	struct wmi_connect_cmd *cc;
+	int ret;
+
+	wmi->traffic_class = 100;
+
+	if ((pairwise_crypto == NONE_CRYPT) && (group_crypto != NONE_CRYPT))
+		return -EINVAL;
+
+	if ((pairwise_crypto != NONE_CRYPT) && (group_crypto == NONE_CRYPT))
+		return -EINVAL;
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_connect_cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cc = (struct wmi_connect_cmd *) skb->data;
+
+	if (ssid_len)
+		memcpy(cc->ssid, ssid, ssid_len);
+
+	cc->ssid_len = ssid_len;
+	cc->nw_type = nw_type;
+	cc->dot11_auth_mode = dot11_auth_mode;
+	cc->auth_mode = auth_mode;
+	cc->prwise_crypto_type = pairwise_crypto;
+	cc->prwise_crypto_len = pairwise_crypto_len;
+	cc->grp_crypto_type = group_crypto;
+	cc->grp_crypto_len = group_crypto_len;
+	cc->ch = cpu_to_le16(channel);
+	cc->ctrl_flags = cpu_to_le32(ctrl_flags);
+
+	if (bssid != NULL)
+		memcpy(cc->bssid, bssid, ETH_ALEN);
+
+	wmi->pair_crypto_type = pairwise_crypto;
+	wmi->grp_crypto_type = group_crypto;
+
+	ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_CONNECT_CMDID, NO_SYNC_WMIFLAG);
+
+	return ret;
+}
+
+int ath6kl_wmi_reconnect_cmd(struct wmi *wmi, u8 *bssid, u16 channel)
+{
+	struct sk_buff *skb;
+	struct wmi_reconnect_cmd *cc;
+	int ret;
+
+	wmi->traffic_class = 100;
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_reconnect_cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cc = (struct wmi_reconnect_cmd *) skb->data;
+	cc->channel = cpu_to_le16(channel);
+
+	if (bssid != NULL)
+		memcpy(cc->bssid, bssid, ETH_ALEN);
+
+	ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_RECONNECT_CMDID,
+				  NO_SYNC_WMIFLAG);
+
+	return ret;
+}
+
+int ath6kl_wmi_disconnect_cmd(struct wmi *wmi)
+{
+	int ret;
+
+	wmi->traffic_class = 100;
+
+	/* Disconnect command does not need to do a SYNC before. */
+	ret = ath6kl_wmi_simple_cmd(wmi, WMI_DISCONNECT_CMDID);
+
+	return ret;
+}
+
+int ath6kl_wmi_startscan_cmd(struct wmi *wmi, enum wmi_scan_type scan_type,
+			     u32 force_fgscan, u32 is_legacy,
+			     u32 home_dwell_time, u32 force_scan_interval,
+			     s8 num_chan, u16 *ch_list)
+{
+	struct sk_buff *skb;
+	struct wmi_start_scan_cmd *sc;
+	s8 size;
+	int ret;
+
+	size = sizeof(struct wmi_start_scan_cmd);
+
+	if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN))
+		return -EINVAL;
+
+	if (num_chan > WMI_MAX_CHANNELS)
+		return -EINVAL;
+
+	if (num_chan)
+		size += sizeof(u16) * (num_chan - 1);
+
+	skb = ath6kl_wmi_get_new_buf(size);
+	if (!skb)
+		return -ENOMEM;
+
+	sc = (struct wmi_start_scan_cmd *) skb->data;
+	sc->scan_type = scan_type;
+	sc->force_fg_scan = cpu_to_le32(force_fgscan);
+	sc->is_legacy = cpu_to_le32(is_legacy);
+	sc->home_dwell_time = cpu_to_le32(home_dwell_time);
+	sc->force_scan_intvl = cpu_to_le32(force_scan_interval);
+	sc->num_ch = num_chan;
+
+	if (num_chan)
+		memcpy(sc->ch_list, ch_list, num_chan * sizeof(u16));
+
+	ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_START_SCAN_CMDID,
+				  NO_SYNC_WMIFLAG);
+
+	return ret;
+}
+
+int ath6kl_wmi_scanparams_cmd(struct wmi *wmi, u16 fg_start_sec,
+			      u16 fg_end_sec, u16 bg_sec,
+			      u16 minact_chdw_msec, u16 maxact_chdw_msec,
+			      u16 pas_chdw_msec, u8 short_scan_ratio,
+			      u8 scan_ctrl_flag, u32 max_dfsch_act_time,
+			      u16 maxact_scan_per_ssid)
+{
+	struct sk_buff *skb;
+	struct wmi_scan_params_cmd *sc;
+	int ret;
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(*sc));
+	if (!skb)
+		return -ENOMEM;
+
+	sc = (struct wmi_scan_params_cmd *) skb->data;
+	sc->fg_start_period = cpu_to_le16(fg_start_sec);
+	sc->fg_end_period = cpu_to_le16(fg_end_sec);
+	sc->bg_period = cpu_to_le16(bg_sec);
+	sc->minact_chdwell_time = cpu_to_le16(minact_chdw_msec);
+	sc->maxact_chdwell_time = cpu_to_le16(maxact_chdw_msec);
+	sc->pas_chdwell_time = cpu_to_le16(pas_chdw_msec);
+	sc->short_scan_ratio = short_scan_ratio;
+	sc->scan_ctrl_flags = scan_ctrl_flag;
+	sc->max_dfsch_act_time = cpu_to_le32(max_dfsch_act_time);
+	sc->maxact_scan_per_ssid = cpu_to_le16(maxact_scan_per_ssid);
+
+	ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_SCAN_PARAMS_CMDID,
+				  NO_SYNC_WMIFLAG);
+	return ret;
+}
+
+int ath6kl_wmi_bssfilter_cmd(struct wmi *wmi, u8 filter, u32 ie_mask)
+{
+	struct sk_buff *skb;
+	struct wmi_bss_filter_cmd *cmd;
+	int ret;
+
+	if (filter >= LAST_BSS_FILTER)
+		return -EINVAL;
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_bss_filter_cmd *) skb->data;
+	cmd->bss_filter = filter;
+	cmd->ie_mask = cpu_to_le32(ie_mask);
+
+	ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_BSS_FILTER_CMDID,
+				  NO_SYNC_WMIFLAG);
+	return ret;
+}
+
+int ath6kl_wmi_probedssid_cmd(struct wmi *wmi, u8 index, u8 flag,
+			      u8 ssid_len, u8 *ssid)
+{
+	struct sk_buff *skb;
+	struct wmi_probed_ssid_cmd *cmd;
+	int ret;
+
+	if (index > MAX_PROBED_SSID_INDEX)
+		return -EINVAL;
+
+	if (ssid_len > sizeof(cmd->ssid))
+		return -EINVAL;
+
+	if ((flag & (DISABLE_SSID_FLAG | ANY_SSID_FLAG)) && (ssid_len > 0))
+		return -EINVAL;
+
+	if ((flag & SPECIFIC_SSID_FLAG) && !ssid_len)
+		return -EINVAL;
+
+	if (flag & SPECIFIC_SSID_FLAG)
+		wmi->is_probe_ssid = true;
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_probed_ssid_cmd *) skb->data;
+	cmd->entry_index = index;
+	cmd->flag = flag;
+	cmd->ssid_len = ssid_len;
+	memcpy(cmd->ssid, ssid, ssid_len);
+
+	ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_PROBED_SSID_CMDID,
+				  NO_SYNC_WMIFLAG);
+	return ret;
+}
+
+int ath6kl_wmi_listeninterval_cmd(struct wmi *wmi, u16 listen_interval,
+				  u16 listen_beacons)
+{
+	struct sk_buff *skb;
+	struct wmi_listen_int_cmd *cmd;
+	int ret;
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_listen_int_cmd *) skb->data;
+	cmd->listen_intvl = cpu_to_le16(listen_interval);
+	cmd->num_beacons = cpu_to_le16(listen_beacons);
+
+	ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_LISTEN_INT_CMDID,
+				  NO_SYNC_WMIFLAG);
+	return ret;
+}
+
+int ath6kl_wmi_powermode_cmd(struct wmi *wmi, u8 pwr_mode)
+{
+	struct sk_buff *skb;
+	struct wmi_power_mode_cmd *cmd;
+	int ret;
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_power_mode_cmd *) skb->data;
+	cmd->pwr_mode = pwr_mode;
+	wmi->pwr_mode = pwr_mode;
+
+	ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_POWER_MODE_CMDID,
+				  NO_SYNC_WMIFLAG);
+	return ret;
+}
+
+int ath6kl_wmi_pmparams_cmd(struct wmi *wmi, u16 idle_period,
+			    u16 ps_poll_num, u16 dtim_policy,
+			    u16 tx_wakeup_policy, u16 num_tx_to_wakeup,
+			    u16 ps_fail_event_policy)
+{
+	struct sk_buff *skb;
+	struct wmi_power_params_cmd *pm;
+	int ret;
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(*pm));
+	if (!skb)
+		return -ENOMEM;
+
+	pm = (struct wmi_power_params_cmd *)skb->data;
+	pm->idle_period = cpu_to_le16(idle_period);
+	pm->pspoll_number = cpu_to_le16(ps_poll_num);
+	pm->dtim_policy = cpu_to_le16(dtim_policy);
+	pm->tx_wakeup_policy = cpu_to_le16(tx_wakeup_policy);
+	pm->num_tx_to_wakeup = cpu_to_le16(num_tx_to_wakeup);
+	pm->ps_fail_event_policy = cpu_to_le16(ps_fail_event_policy);
+
+	ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_POWER_PARAMS_CMDID,
+				  NO_SYNC_WMIFLAG);
+	return ret;
+}
+
+int ath6kl_wmi_disctimeout_cmd(struct wmi *wmi, u8 timeout)
+{
+	struct sk_buff *skb;
+	struct wmi_disc_timeout_cmd *cmd;
+	int ret;
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_disc_timeout_cmd *) skb->data;
+	cmd->discon_timeout = timeout;
+
+	ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_DISC_TIMEOUT_CMDID,
+				  NO_SYNC_WMIFLAG);
+	return ret;
+}
+
+int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 key_index,
+			  enum crypto_type key_type,
+			  u8 key_usage, u8 key_len,
+			  u8 *key_rsc, u8 *key_material,
+			  u8 key_op_ctrl, u8 *mac_addr,
+			  enum wmi_sync_flag sync_flag)
+{
+	struct sk_buff *skb;
+	struct wmi_add_cipher_key_cmd *cmd;
+	int ret;
+
+	if ((key_index > WMI_MAX_KEY_INDEX) || (key_len > WMI_MAX_KEY_LEN) ||
+	    (key_material == NULL))
+		return -EINVAL;
+
+	if ((WEP_CRYPT != key_type) && (NULL == key_rsc))
+		return -EINVAL;
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_add_cipher_key_cmd *) skb->data;
+	cmd->key_index = key_index;
+	cmd->key_type = key_type;
+	cmd->key_usage = key_usage;
+	cmd->key_len = key_len;
+	memcpy(cmd->key, key_material, key_len);
+
+	if (key_rsc != NULL)
+		memcpy(cmd->key_rsc, key_rsc, sizeof(cmd->key_rsc));
+
+	cmd->key_op_ctrl = key_op_ctrl;
+
+	if (mac_addr)
+		memcpy(cmd->key_mac_addr, mac_addr, ETH_ALEN);
+
+	ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_ADD_CIPHER_KEY_CMDID,
+				  sync_flag);
+
+	return ret;
+}
+
+int ath6kl_wmi_add_krk_cmd(struct wmi *wmi, u8 *krk)
+{
+	struct sk_buff *skb;
+	struct wmi_add_krk_cmd *cmd;
+	int ret;
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_add_krk_cmd *) skb->data;
+	memcpy(cmd->krk, krk, WMI_KRK_LEN);
+
+	ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_ADD_KRK_CMDID, NO_SYNC_WMIFLAG);
+
+	return ret;
+}
+
+int ath6kl_wmi_deletekey_cmd(struct wmi *wmi, u8 key_index)
+{
+	struct sk_buff *skb;
+	struct wmi_delete_cipher_key_cmd *cmd;
+	int ret;
+
+	if (key_index > WMI_MAX_KEY_INDEX)
+		return -EINVAL;
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_delete_cipher_key_cmd *) skb->data;
+	cmd->key_index = key_index;
+
+	ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_DELETE_CIPHER_KEY_CMDID,
+				  NO_SYNC_WMIFLAG);
+
+	return ret;
+}
+
+int ath6kl_wmi_setpmkid_cmd(struct wmi *wmi, const u8 *bssid,
+			    const u8 *pmkid, bool set)
+{
+	struct sk_buff *skb;
+	struct wmi_setpmkid_cmd *cmd;
+	int ret;
+
+	if (bssid == NULL)
+		return -EINVAL;
+
+	if (set && pmkid == NULL)
+		return -EINVAL;
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_setpmkid_cmd *) skb->data;
+	memcpy(cmd->bssid, bssid, ETH_ALEN);
+	if (set) {
+		memcpy(cmd->pmkid, pmkid, sizeof(cmd->pmkid));
+		cmd->enable = PMKID_ENABLE;
+	} else {
+		memset(cmd->pmkid, 0, sizeof(cmd->pmkid));
+		cmd->enable = PMKID_DISABLE;
+	}
+
+	ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_PMKID_CMDID,
+				  NO_SYNC_WMIFLAG);
+
+	return ret;
+}
+
+static int ath6kl_wmi_data_sync_send(struct wmi *wmi, struct sk_buff *skb,
+			      enum htc_endpoint_id ep_id)
+{
+	struct wmi_data_hdr *data_hdr;
+	int ret;
+
+	if (WARN_ON(skb == NULL || ep_id == wmi->ep_id))
+		return -EINVAL;
+
+	skb_push(skb, sizeof(struct wmi_data_hdr));
+
+	data_hdr = (struct wmi_data_hdr *) skb->data;
+	data_hdr->info = SYNC_MSGTYPE << WMI_DATA_HDR_MSG_TYPE_SHIFT;
+	data_hdr->info3 = 0;
+
+	ret = ath6kl_control_tx(wmi->parent_dev, skb, ep_id);
+
+	return ret;
+}
+
+static int ath6kl_wmi_sync_point(struct wmi *wmi)
+{
+	struct sk_buff *skb;
+	struct wmi_sync_cmd *cmd;
+	struct wmi_data_sync_bufs data_sync_bufs[WMM_NUM_AC];
+	enum htc_endpoint_id ep_id;
+	u8 index, num_pri_streams = 0;
+	int ret = 0;
+
+	memset(data_sync_bufs, 0, sizeof(data_sync_bufs));
+
+	spin_lock_bh(&wmi->lock);
+
+	for (index = 0; index < WMM_NUM_AC; index++) {
+		if (wmi->fat_pipe_exist & (1 << index)) {
+			num_pri_streams++;
+			data_sync_bufs[num_pri_streams - 1].traffic_class =
+			    index;
+		}
+	}
+
+	spin_unlock_bh(&wmi->lock);
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+	if (!skb) {
+		ret = -ENOMEM;
+		goto free_skb;
+	}
+
+	cmd = (struct wmi_sync_cmd *) skb->data;
+
+	/*
+	 * In the SYNC cmd sent on the control Ep, send a bitmap
+	 * of the data eps on which the Data Sync will be sent
+	 */
+	cmd->data_sync_map = wmi->fat_pipe_exist;
+
+	for (index = 0; index < num_pri_streams; index++) {
+		data_sync_bufs[index].skb = ath6kl_buf_alloc(0);
+		if (data_sync_bufs[index].skb == NULL) {
+			ret = -ENOMEM;
+			break;
+		}
+	}
+
+	/*
+	 * If buffer allocation for any of the dataSync fails,
+	 * then do not send the Synchronize cmd on the control ep
+	 */
+	if (ret)
+		goto free_skb;
+
+	/*
+	 * Send sync cmd followed by sync data messages on all
+	 * endpoints being used
+	 */
+	ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SYNCHRONIZE_CMDID,
+				  NO_SYNC_WMIFLAG);
+
+	if (ret)
+		goto free_skb;
+
+	/* cmd buffer sent, we no longer own it */
+	skb = NULL;
+
+	for (index = 0; index < num_pri_streams; index++) {
+
+		if (WARN_ON(!data_sync_bufs[index].skb))
+			break;
+
+		ep_id = ath6kl_ac2_endpoint_id(wmi->parent_dev,
+					       data_sync_bufs[index].
+					       traffic_class);
+		ret =
+		    ath6kl_wmi_data_sync_send(wmi, data_sync_bufs[index].skb,
+					      ep_id);
+
+		if (ret)
+			break;
+
+		data_sync_bufs[index].skb = NULL;
+	}
+
+free_skb:
+	/* free up any resources left over (possibly due to an error) */
+	if (skb)
+		dev_kfree_skb(skb);
+
+	for (index = 0; index < num_pri_streams; index++) {
+		if (data_sync_bufs[index].skb != NULL) {
+			dev_kfree_skb((struct sk_buff *)data_sync_bufs[index].
+				      skb);
+		}
+	}
+
+	return ret;
+}
+
+int ath6kl_wmi_create_pstream_cmd(struct wmi *wmi,
+				  struct wmi_create_pstream_cmd *params)
+{
+	struct sk_buff *skb;
+	struct wmi_create_pstream_cmd *cmd;
+	u8 fatpipe_exist_for_ac = 0;
+	s32 min_phy = 0;
+	s32 nominal_phy = 0;
+	int ret;
+
+	if (!((params->user_pri < 8) &&
+	      (params->user_pri <= 0x7) &&
+	      (up_to_ac[params->user_pri & 0x7] == params->traffic_class) &&
+	      (params->traffic_direc == UPLINK_TRAFFIC ||
+	       params->traffic_direc == DNLINK_TRAFFIC ||
+	       params->traffic_direc == BIDIR_TRAFFIC) &&
+	      (params->traffic_type == TRAFFIC_TYPE_APERIODIC ||
+	       params->traffic_type == TRAFFIC_TYPE_PERIODIC) &&
+	      (params->voice_psc_cap == DISABLE_FOR_THIS_AC ||
+	       params->voice_psc_cap == ENABLE_FOR_THIS_AC ||
+	       params->voice_psc_cap == ENABLE_FOR_ALL_AC) &&
+	      (params->tsid == WMI_IMPLICIT_PSTREAM ||
+	       params->tsid <= WMI_MAX_THINSTREAM))) {
+		return -EINVAL;
+	}
+
+	/*
+	 * Check nominal PHY rate is >= minimalPHY,
+	 * so that DUT can allow TSRS IE
+	 */
+
+	/* Get the physical rate (units of bps) */
+	min_phy = ((le32_to_cpu(params->min_phy_rate) / 1000) / 1000);
+
+	/* Check minimal phy < nominal phy rate */
+	if (params->nominal_phy >= min_phy) {
+		/* unit of 500 kbps */
+		nominal_phy = (params->nominal_phy * 1000) / 500;
+		ath6kl_dbg(ATH6KL_DBG_WMI,
+			   "TSRS IE enabled::MinPhy %x->NominalPhy ===> %x\n",
+			   min_phy, nominal_phy);
+
+		params->nominal_phy = nominal_phy;
+	} else {
+		params->nominal_phy = 0;
+	}
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	ath6kl_dbg(ATH6KL_DBG_WMI,
+		   "sending create_pstream_cmd: ac=%d  tsid:%d\n",
+		   params->traffic_class, params->tsid);
+
+	cmd = (struct wmi_create_pstream_cmd *) skb->data;
+	memcpy(cmd, params, sizeof(*cmd));
+
+	/* This is an implicitly created Fat pipe */
+	if ((u32) params->tsid == (u32) WMI_IMPLICIT_PSTREAM) {
+		spin_lock_bh(&wmi->lock);
+		fatpipe_exist_for_ac = (wmi->fat_pipe_exist &
+					(1 << params->traffic_class));
+		wmi->fat_pipe_exist |= (1 << params->traffic_class);
+		spin_unlock_bh(&wmi->lock);
+	} else {
+		/* explicitly created thin stream within a fat pipe */
+		spin_lock_bh(&wmi->lock);
+		fatpipe_exist_for_ac = (wmi->fat_pipe_exist &
+					(1 << params->traffic_class));
+		wmi->stream_exist_for_ac[params->traffic_class] |=
+		    (1 << params->tsid);
+		/*
+		 * If a thinstream becomes active, the fat pipe automatically
+		 * becomes active
+		 */
+		wmi->fat_pipe_exist |= (1 << params->traffic_class);
+		spin_unlock_bh(&wmi->lock);
+	}
+
+	/*
+	 * Indicate activty change to driver layer only if this is the
+	 * first TSID to get created in this AC explicitly or an implicit
+	 * fat pipe is getting created.
+	 */
+	if (!fatpipe_exist_for_ac)
+		ath6kl_indicate_tx_activity(wmi->parent_dev,
+					    params->traffic_class, true);
+
+	ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_CREATE_PSTREAM_CMDID,
+				  NO_SYNC_WMIFLAG);
+	return ret;
+}
+
+int ath6kl_wmi_delete_pstream_cmd(struct wmi *wmi, u8 traffic_class, u8 tsid)
+{
+	struct sk_buff *skb;
+	struct wmi_delete_pstream_cmd *cmd;
+	u16 active_tsids = 0;
+	int ret;
+
+	if (traffic_class > 3) {
+		ath6kl_err("invalid traffic class: %d\n", traffic_class);
+		return -EINVAL;
+	}
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_delete_pstream_cmd *) skb->data;
+	cmd->traffic_class = traffic_class;
+	cmd->tsid = tsid;
+
+	spin_lock_bh(&wmi->lock);
+	active_tsids = wmi->stream_exist_for_ac[traffic_class];
+	spin_unlock_bh(&wmi->lock);
+
+	if (!(active_tsids & (1 << tsid))) {
+		dev_kfree_skb(skb);
+		ath6kl_dbg(ATH6KL_DBG_WMI,
+			   "TSID %d doesn't exist for traffic class: %d\n",
+			   tsid, traffic_class);
+		return -ENODATA;
+	}
+
+	ath6kl_dbg(ATH6KL_DBG_WMI,
+		   "sending delete_pstream_cmd: traffic class: %d tsid=%d\n",
+		   traffic_class, tsid);
+
+	ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_DELETE_PSTREAM_CMDID,
+				  SYNC_BEFORE_WMIFLAG);
+
+	spin_lock_bh(&wmi->lock);
+	wmi->stream_exist_for_ac[traffic_class] &= ~(1 << tsid);
+	active_tsids = wmi->stream_exist_for_ac[traffic_class];
+	spin_unlock_bh(&wmi->lock);
+
+	/*
+	 * Indicate stream inactivity to driver layer only if all tsids
+	 * within this AC are deleted.
+	 */
+	if (!active_tsids) {
+		ath6kl_indicate_tx_activity(wmi->parent_dev,
+					    traffic_class, false);
+		wmi->fat_pipe_exist &= ~(1 << traffic_class);
+	}
+
+	return ret;
+}
+
+int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd)
+{
+	struct sk_buff *skb;
+	struct wmi_set_ip_cmd *cmd;
+	int ret;
+
+	/* Multicast address are not valid */
+	if ((*((u8 *) &ip_cmd->ips[0]) >= 0xE0) ||
+	    (*((u8 *) &ip_cmd->ips[1]) >= 0xE0))
+		return -EINVAL;
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_ip_cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_set_ip_cmd *) skb->data;
+	memcpy(cmd, ip_cmd, sizeof(struct wmi_set_ip_cmd));
+
+	ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_IP_CMDID, NO_SYNC_WMIFLAG);
+	return ret;
+}
+
+static int ath6kl_wmi_get_wow_list_event_rx(struct wmi *wmi, u8 * datap,
+					    int len)
+{
+	if (len < sizeof(struct wmi_get_wow_list_reply))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int ath6kl_wmi_cmd_send_xtnd(struct wmi *wmi, struct sk_buff *skb,
+				    enum wmix_command_id cmd_id,
+				    enum wmi_sync_flag sync_flag)
+{
+	struct wmix_cmd_hdr *cmd_hdr;
+	int ret;
+
+	skb_push(skb, sizeof(struct wmix_cmd_hdr));
+
+	cmd_hdr = (struct wmix_cmd_hdr *) skb->data;
+	cmd_hdr->cmd_id = cpu_to_le32(cmd_id);
+
+	ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_EXTENSION_CMDID, sync_flag);
+
+	return ret;
+}
+
+int ath6kl_wmi_get_challenge_resp_cmd(struct wmi *wmi, u32 cookie, u32 source)
+{
+	struct sk_buff *skb;
+	struct wmix_hb_challenge_resp_cmd *cmd;
+	int ret;
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmix_hb_challenge_resp_cmd *) skb->data;
+	cmd->cookie = cpu_to_le32(cookie);
+	cmd->source = cpu_to_le32(source);
+
+	ret = ath6kl_wmi_cmd_send_xtnd(wmi, skb, WMIX_HB_CHALLENGE_RESP_CMDID,
+				       NO_SYNC_WMIFLAG);
+	return ret;
+}
+
+int ath6kl_wmi_get_stats_cmd(struct wmi *wmi)
+{
+	return ath6kl_wmi_simple_cmd(wmi, WMI_GET_STATISTICS_CMDID);
+}
+
+int ath6kl_wmi_set_tx_pwr_cmd(struct wmi *wmi, u8 dbM)
+{
+	struct sk_buff *skb;
+	struct wmi_set_tx_pwr_cmd *cmd;
+	int ret;
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_tx_pwr_cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_set_tx_pwr_cmd *) skb->data;
+	cmd->dbM = dbM;
+
+	ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_TX_PWR_CMDID,
+				  NO_SYNC_WMIFLAG);
+
+	return ret;
+}
+
+int ath6kl_wmi_get_tx_pwr_cmd(struct wmi *wmi)
+{
+	return ath6kl_wmi_simple_cmd(wmi, WMI_GET_TX_PWR_CMDID);
+}
+
+int ath6kl_wmi_set_lpreamble_cmd(struct wmi *wmi, u8 status, u8 preamble_policy)
+{
+	struct sk_buff *skb;
+	struct wmi_set_lpreamble_cmd *cmd;
+	int ret;
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_lpreamble_cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_set_lpreamble_cmd *) skb->data;
+	cmd->status = status;
+	cmd->preamble_policy = preamble_policy;
+
+	ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_LPREAMBLE_CMDID,
+				  NO_SYNC_WMIFLAG);
+	return ret;
+}
+
+int ath6kl_wmi_set_rts_cmd(struct wmi *wmi, u16 threshold)
+{
+	struct sk_buff *skb;
+	struct wmi_set_rts_cmd *cmd;
+	int ret;
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_rts_cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_set_rts_cmd *) skb->data;
+	cmd->threshold = cpu_to_le16(threshold);
+
+	ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_RTS_CMDID, NO_SYNC_WMIFLAG);
+	return ret;
+}
+
+int ath6kl_wmi_set_wmm_txop(struct wmi *wmi, enum wmi_txop_cfg cfg)
+{
+	struct sk_buff *skb;
+	struct wmi_set_wmm_txop_cmd *cmd;
+	int ret;
+
+	if (!((cfg == WMI_TXOP_DISABLED) || (cfg == WMI_TXOP_ENABLED)))
+		return -EINVAL;
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_wmm_txop_cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_set_wmm_txop_cmd *) skb->data;
+	cmd->txop_enable = cfg;
+
+	ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_WMM_TXOP_CMDID,
+				  NO_SYNC_WMIFLAG);
+	return ret;
+}
+
+int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 keep_alive_intvl)
+{
+	struct sk_buff *skb;
+	struct wmi_set_keepalive_cmd *cmd;
+	int ret;
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_set_keepalive_cmd *) skb->data;
+	cmd->keep_alive_intvl = keep_alive_intvl;
+	wmi->keep_alive_intvl = keep_alive_intvl;
+
+	ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_KEEPALIVE_CMDID,
+				  NO_SYNC_WMIFLAG);
+	return ret;
+}
+
+s32 ath6kl_wmi_get_rate(s8 rate_index)
+{
+	if (rate_index == RATE_AUTO)
+		return 0;
+
+	return wmi_rate_tbl[(u32) rate_index][0];
+}
+
+void ath6kl_wmi_node_return(struct wmi *wmi, struct bss *bss)
+{
+	if (bss)
+		wlan_node_return(&wmi->parent_dev->scan_table, bss);
+}
+
+struct bss *ath6kl_wmi_find_ssid_node(struct wmi *wmi, u8 * ssid,
+				      u32 ssid_len, bool is_wpa2,
+				      bool match_ssid)
+{
+	struct bss *node = NULL;
+
+	node = wlan_find_ssid_node(&wmi->parent_dev->scan_table, ssid,
+				  ssid_len, is_wpa2, match_ssid);
+	return node;
+}
+
+struct bss *ath6kl_wmi_find_node(struct wmi *wmi, const u8 * mac_addr)
+{
+	struct bss *ni = NULL;
+
+	ni = wlan_find_node(&wmi->parent_dev->scan_table, mac_addr);
+
+	return ni;
+}
+
+void ath6kl_wmi_node_free(struct wmi *wmi, const u8 * mac_addr)
+{
+	struct bss *ni = NULL;
+
+	ni = wlan_find_node(&wmi->parent_dev->scan_table, mac_addr);
+	if (ni != NULL)
+		wlan_node_reclaim(&wmi->parent_dev->scan_table, ni);
+
+	return;
+}
+
+static int ath6kl_wmi_get_pmkid_list_event_rx(struct wmi *wmi, u8 *datap,
+					      u32 len)
+{
+	struct wmi_pmkid_list_reply *reply;
+	u32 expected_len;
+
+	if (len < sizeof(struct wmi_pmkid_list_reply))
+		return -EINVAL;
+
+	reply = (struct wmi_pmkid_list_reply *)datap;
+	expected_len = sizeof(reply->num_pmkid) +
+		le32_to_cpu(reply->num_pmkid) * WMI_PMKID_LEN;
+
+	if (len < expected_len)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int ath6kl_wmi_addba_req_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+	struct wmi_addba_req_event *cmd = (struct wmi_addba_req_event *) datap;
+
+	aggr_recv_addba_req_evt(wmi->parent_dev, cmd->tid,
+				le16_to_cpu(cmd->st_seq_no), cmd->win_sz);
+
+	return 0;
+}
+
+static int ath6kl_wmi_delba_req_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+	struct wmi_delba_event *cmd = (struct wmi_delba_event *) datap;
+
+	aggr_recv_delba_req_evt(wmi->parent_dev, cmd->tid);
+
+	return 0;
+}
+
+/*  AP mode functions */
+static int ath6kl_wmi_pspoll_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+	struct wmi_pspoll_event *ev;
+
+	if (len < sizeof(struct wmi_pspoll_event))
+		return -EINVAL;
+
+	ev = (struct wmi_pspoll_event *) datap;
+
+	ath6kl_pspoll_event(wmi->parent_dev, le16_to_cpu(ev->aid));
+
+	return 0;
+}
+
+static int ath6kl_wmi_dtimexpiry_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+	ath6kl_dtimexpiry_event(wmi->parent_dev);
+
+	return 0;
+}
+
+int ath6kl_wmi_set_pvb_cmd(struct wmi *wmi, u16 aid, bool flag)
+{
+	struct sk_buff *skb;
+	struct wmi_ap_set_pvb_cmd *cmd;
+	int ret;
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_ap_set_pvb_cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_ap_set_pvb_cmd *) skb->data;
+	cmd->aid = cpu_to_le16(aid);
+	cmd->flag = cpu_to_le32(flag);
+
+	ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_AP_SET_PVB_CMDID,
+				  NO_SYNC_WMIFLAG);
+
+	return 0;
+}
+
+int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 rx_meta_ver,
+				       bool rx_dot11_hdr, bool defrag_on_host)
+{
+	struct sk_buff *skb;
+	struct wmi_rx_frame_format_cmd *cmd;
+	int ret;
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_rx_frame_format_cmd *) skb->data;
+	cmd->dot11_hdr = rx_dot11_hdr ? 1 : 0;
+	cmd->defrag_on_host = defrag_on_host ? 1 : 0;
+	cmd->meta_ver = rx_meta_ver;
+
+	/* Delete the local aggr state, on host */
+	ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_RX_FRAME_FORMAT_CMDID,
+				  NO_SYNC_WMIFLAG);
+
+	return ret;
+}
+
+static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb)
+{
+	struct wmix_cmd_hdr *cmd;
+	u32 len;
+	u16 id;
+	u8 *datap;
+	int ret = 0;
+
+	if (skb->len < sizeof(struct wmix_cmd_hdr)) {
+		ath6kl_err("bad packet 1\n");
+		wmi->stat.cmd_len_err++;
+		return -EINVAL;
+	}
+
+	cmd = (struct wmix_cmd_hdr *) skb->data;
+	id = le32_to_cpu(cmd->cmd_id);
+
+	skb_pull(skb, sizeof(struct wmix_cmd_hdr));
+
+	datap = skb->data;
+	len = skb->len;
+
+	switch (id) {
+	case WMIX_HB_CHALLENGE_RESP_EVENTID:
+		break;
+	case WMIX_DBGLOG_EVENTID:
+		break;
+	default:
+		ath6kl_err("unknown cmd id 0x%x\n", id);
+		wmi->stat.cmd_id_err++;
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/* Control Path */
+int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
+{
+	struct wmi_cmd_hdr *cmd;
+	u32 len;
+	u16 id;
+	u8 *datap;
+	int ret = 0;
+
+	if (WARN_ON(skb == NULL))
+		return -EINVAL;
+
+	if (skb->len < sizeof(struct wmi_cmd_hdr)) {
+		ath6kl_err("bad packet 1\n");
+		dev_kfree_skb(skb);
+		wmi->stat.cmd_len_err++;
+		return -EINVAL;
+	}
+
+	cmd = (struct wmi_cmd_hdr *) skb->data;
+	id = le16_to_cpu(cmd->cmd_id);
+
+	skb_pull(skb, sizeof(struct wmi_cmd_hdr));
+
+	datap = skb->data;
+	len = skb->len;
+
+	ath6kl_dbg(ATH6KL_DBG_WMI, "%s: wmi id: %d\n", __func__, id);
+	ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "msg payload ", datap, len);
+
+	switch (id) {
+	case WMI_GET_BITRATE_CMDID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_BITRATE_CMDID\n");
+		ret = ath6kl_wmi_bitrate_reply_rx(wmi, datap, len);
+		break;
+	case WMI_GET_CHANNEL_LIST_CMDID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_CHANNEL_LIST_CMDID\n");
+		ret = ath6kl_wmi_ch_list_reply_rx(wmi, datap, len);
+		break;
+	case WMI_GET_TX_PWR_CMDID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_TX_PWR_CMDID\n");
+		ret = ath6kl_wmi_tx_pwr_reply_rx(wmi, datap, len);
+		break;
+	case WMI_READY_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_READY_EVENTID\n");
+		ret = ath6kl_wmi_ready_event_rx(wmi, datap, len);
+		break;
+	case WMI_CONNECT_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CONNECT_EVENTID\n");
+		ret = ath6kl_wmi_connect_event_rx(wmi, datap, len);
+		break;
+	case WMI_DISCONNECT_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DISCONNECT_EVENTID\n");
+		ret = ath6kl_wmi_disconnect_event_rx(wmi, datap, len);
+		break;
+	case WMI_PEER_NODE_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PEER_NODE_EVENTID\n");
+		ret = ath6kl_wmi_peer_node_event_rx(wmi, datap, len);
+		break;
+	case WMI_TKIP_MICERR_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TKIP_MICERR_EVENTID\n");
+		ret = ath6kl_wmi_tkip_micerr_event_rx(wmi, datap, len);
+		break;
+	case WMI_BSSINFO_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_BSSINFO_EVENTID\n");
+		ath6kl_wmi_convert_bssinfo_hdr2_to_hdr(skb, datap);
+		ret = ath6kl_wmi_bssinfo_event_rx(wmi, skb->data, skb->len);
+		break;
+	case WMI_REGDOMAIN_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REGDOMAIN_EVENTID\n");
+		break;
+	case WMI_PSTREAM_TIMEOUT_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSTREAM_TIMEOUT_EVENTID\n");
+		ret = ath6kl_wmi_pstream_timeout_event_rx(wmi, datap, len);
+		break;
+	case WMI_NEIGHBOR_REPORT_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_NEIGHBOR_REPORT_EVENTID\n");
+		break;
+	case WMI_SCAN_COMPLETE_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SCAN_COMPLETE_EVENTID\n");
+		ret = ath6kl_wmi_scan_complete_rx(wmi, datap, len);
+		break;
+	case WMI_CMDERROR_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CMDERROR_EVENTID\n");
+		ret = ath6kl_wmi_error_event_rx(wmi, datap, len);
+		break;
+	case WMI_REPORT_STATISTICS_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_STATISTICS_EVENTID\n");
+		ret = ath6kl_wmi_stats_event_rx(wmi, datap, len);
+		break;
+	case WMI_RSSI_THRESHOLD_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RSSI_THRESHOLD_EVENTID\n");
+		ret = ath6kl_wmi_rssi_threshold_event_rx(wmi, datap, len);
+		break;
+	case WMI_ERROR_REPORT_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ERROR_REPORT_EVENTID\n");
+		break;
+	case WMI_OPT_RX_FRAME_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_OPT_RX_FRAME_EVENTID\n");
+		ret = ath6kl_wmi_opt_frame_event_rx(wmi, datap, len);
+		break;
+	case WMI_REPORT_ROAM_TBL_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_ROAM_TBL_EVENTID\n");
+		break;
+	case WMI_EXTENSION_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_EXTENSION_EVENTID\n");
+		ret = ath6kl_wmi_control_rx_xtnd(wmi, skb);
+		break;
+	case WMI_CAC_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CAC_EVENTID\n");
+		ret = ath6kl_wmi_cac_event_rx(wmi, datap, len);
+		break;
+	case WMI_CHANNEL_CHANGE_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CHANNEL_CHANGE_EVENTID\n");
+		break;
+	case WMI_REPORT_ROAM_DATA_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_ROAM_DATA_EVENTID\n");
+		break;
+	case WMI_GET_FIXRATES_CMDID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_FIXRATES_CMDID\n");
+		ret = ath6kl_wmi_ratemask_reply_rx(wmi, datap, len);
+		break;
+	case WMI_TX_RETRY_ERR_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_RETRY_ERR_EVENTID\n");
+		break;
+	case WMI_SNR_THRESHOLD_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SNR_THRESHOLD_EVENTID\n");
+		ret = ath6kl_wmi_snr_threshold_event_rx(wmi, datap, len);
+		break;
+	case WMI_LQ_THRESHOLD_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_LQ_THRESHOLD_EVENTID\n");
+		break;
+	case WMI_APLIST_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_APLIST_EVENTID\n");
+		ret = ath6kl_wmi_aplist_event_rx(wmi, datap, len);
+		break;
+	case WMI_GET_KEEPALIVE_CMDID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_KEEPALIVE_CMDID\n");
+		ret = ath6kl_wmi_keepalive_reply_rx(wmi, datap, len);
+		break;
+	case WMI_GET_WOW_LIST_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_WOW_LIST_EVENTID\n");
+		ret = ath6kl_wmi_get_wow_list_event_rx(wmi, datap, len);
+		break;
+	case WMI_GET_PMKID_LIST_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_PMKID_LIST_EVENTID\n");
+		ret = ath6kl_wmi_get_pmkid_list_event_rx(wmi, datap, len);
+		break;
+	case WMI_PSPOLL_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSPOLL_EVENTID\n");
+		ret = ath6kl_wmi_pspoll_event_rx(wmi, datap, len);
+		break;
+	case WMI_DTIMEXPIRY_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DTIMEXPIRY_EVENTID\n");
+		ret = ath6kl_wmi_dtimexpiry_event_rx(wmi, datap, len);
+		break;
+	case WMI_SET_PARAMS_REPLY_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SET_PARAMS_REPLY_EVENTID\n");
+		break;
+	case WMI_ADDBA_REQ_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_REQ_EVENTID\n");
+		ret = ath6kl_wmi_addba_req_event_rx(wmi, datap, len);
+		break;
+	case WMI_ADDBA_RESP_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_RESP_EVENTID\n");
+		break;
+	case WMI_DELBA_REQ_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DELBA_REQ_EVENTID\n");
+		ret = ath6kl_wmi_delba_req_event_rx(wmi, datap, len);
+		break;
+	case WMI_REPORT_BTCOEX_CONFIG_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI,
+			   "WMI_REPORT_BTCOEX_CONFIG_EVENTID\n");
+		break;
+	case WMI_REPORT_BTCOEX_STATS_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI,
+			   "WMI_REPORT_BTCOEX_STATS_EVENTID\n");
+		break;
+	case WMI_TX_COMPLETE_EVENTID:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_COMPLETE_EVENTID\n");
+		ret = ath6kl_wmi_tx_complete_event_rx(datap, len);
+		break;
+	default:
+		ath6kl_dbg(ATH6KL_DBG_WMI, "unknown cmd id 0x%x\n", id);
+		wmi->stat.cmd_id_err++;
+		ret = -EINVAL;
+		break;
+	}
+
+	dev_kfree_skb(skb);
+
+	return ret;
+}
+
+static void ath6kl_wmi_qos_state_init(struct wmi *wmi)
+{
+	if (!wmi)
+		return;
+
+	spin_lock_bh(&wmi->lock);
+
+	wmi->fat_pipe_exist = 0;
+	memset(wmi->stream_exist_for_ac, 0, sizeof(wmi->stream_exist_for_ac));
+
+	spin_unlock_bh(&wmi->lock);
+}
+
+void *ath6kl_wmi_init(struct ath6kl *dev)
+{
+	struct wmi *wmi;
+
+	wmi = kzalloc(sizeof(struct wmi), GFP_KERNEL);
+	if (!wmi)
+		return NULL;
+
+	spin_lock_init(&wmi->lock);
+
+	wmi->parent_dev = dev;
+
+	ath6kl_wmi_qos_state_init(wmi);
+
+	wmi->pwr_mode = REC_POWER;
+	wmi->phy_mode = WMI_11G_MODE;
+
+	wmi->pair_crypto_type = NONE_CRYPT;
+	wmi->grp_crypto_type = NONE_CRYPT;
+
+	wmi->ht_allowed[A_BAND_24GHZ] = 1;
+	wmi->ht_allowed[A_BAND_5GHZ] = 1;
+
+	return wmi;
+}
+
+void ath6kl_wmi_shutdown(struct wmi *wmi)
+{
+	if (!wmi)
+		return;
+
+	kfree(wmi);
+}
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h
new file mode 100644
index 000000000000..fe3ddce64087
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/wmi.h
@@ -0,0 +1,2018 @@
+/*
+ * Copyright (c) 2010-2011 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.
+ */
+
+/*
+ * This file contains the definitions of the WMI protocol specified in the
+ * Wireless Module Interface (WMI).  It includes definitions of all the
+ * commands and events. Commands are messages from the host to the WM.
+ * Events and Replies are messages from the WM to the host.
+ */
+
+#ifndef WMI_H
+#define WMI_H
+
+#include <linux/ieee80211.h>
+
+#include "htc.h"
+
+#define HTC_PROTOCOL_VERSION		0x0002
+#define WMI_PROTOCOL_VERSION		0x0002
+#define WMI_CONTROL_MSG_MAX_LEN		256
+#define is_ethertype(type_or_len)	((type_or_len) >= 0x0600)
+
+#define IP_ETHERTYPE		0x0800
+
+#define WMI_IMPLICIT_PSTREAM	0xFF
+#define WMI_MAX_THINSTREAM	15
+
+#define SSID_IE_LEN_INDEX	13
+
+/* Host side link management data structures */
+#define SIG_QUALITY_THRESH_LVLS		6
+#define SIG_QUALITY_UPPER_THRESH_LVLS	SIG_QUALITY_THRESH_LVLS
+#define SIG_QUALITY_LOWER_THRESH_LVLS	SIG_QUALITY_THRESH_LVLS
+
+#define A_BAND_24GHZ           0
+#define A_BAND_5GHZ            1
+#define A_NUM_BANDS            2
+
+/* in ms */
+#define WMI_IMPLICIT_PSTREAM_INACTIVITY_INT 5000
+
+/*
+ * There are no signed versions of __le16 and __le32, so for a temporary
+ * solution come up with our own version. The idea is from fs/ntfs/types.h.
+ *
+ * Use a_ prefix so that it doesn't conflict if we get proper support to
+ * linux/types.h.
+ */
+typedef __s16 __bitwise a_sle16;
+typedef __s32 __bitwise a_sle32;
+
+static inline a_sle32 a_cpu_to_sle32(s32 val)
+{
+	return (__force a_sle32) cpu_to_le32(val);
+}
+
+static inline s32 a_sle32_to_cpu(a_sle32 val)
+{
+	return le32_to_cpu((__force __le32) val);
+}
+
+static inline a_sle16 a_cpu_to_sle16(s16 val)
+{
+	return (__force a_sle16) cpu_to_le16(val);
+}
+
+static inline s16 a_sle16_to_cpu(a_sle16 val)
+{
+	return le16_to_cpu((__force __le16) val);
+}
+
+struct sq_threshold_params {
+	s16 upper_threshold[SIG_QUALITY_UPPER_THRESH_LVLS];
+	s16 lower_threshold[SIG_QUALITY_LOWER_THRESH_LVLS];
+	u32 upper_threshold_valid_count;
+	u32 lower_threshold_valid_count;
+	u32 polling_interval;
+	u8 weight;
+	u8 last_rssi;
+	u8 last_rssi_poll_event;
+};
+
+struct wmi_stats {
+	u32 cmd_len_err;
+	u32 cmd_id_err;
+};
+
+struct wmi_data_sync_bufs {
+	u8 traffic_class;
+	struct sk_buff *skb;
+};
+
+/* WMM stream classes */
+#define WMM_NUM_AC  4
+#define WMM_AC_BE   0		/* best effort */
+#define WMM_AC_BK   1		/* background */
+#define WMM_AC_VI   2		/* video */
+#define WMM_AC_VO   3		/* voice */
+
+struct wmi {
+	bool ready;
+	u16 stream_exist_for_ac[WMM_NUM_AC];
+	u8 fat_pipe_exist;
+	struct ath6kl *parent_dev;
+	struct wmi_stats stat;
+	u8 pwr_mode;
+	u8 phy_mode;
+	u8 keep_alive_intvl;
+	spinlock_t lock;
+	enum htc_endpoint_id ep_id;
+	struct sq_threshold_params
+	    sq_threshld[SIGNAL_QUALITY_METRICS_NUM_MAX];
+	enum crypto_type pair_crypto_type;
+	enum crypto_type grp_crypto_type;
+	bool is_wmm_enabled;
+	u8 ht_allowed[A_NUM_BANDS];
+	u8 traffic_class;
+	bool is_probe_ssid;
+};
+
+struct host_app_area {
+	u32 wmi_protocol_ver;
+};
+
+enum wmi_msg_type {
+	DATA_MSGTYPE = 0x0,
+	CNTL_MSGTYPE,
+	SYNC_MSGTYPE,
+	OPT_MSGTYPE,
+};
+
+/*
+ * Macros for operating on WMI_DATA_HDR (info) field
+ */
+
+#define WMI_DATA_HDR_MSG_TYPE_MASK  0x03
+#define WMI_DATA_HDR_MSG_TYPE_SHIFT 0
+#define WMI_DATA_HDR_UP_MASK        0x07
+#define WMI_DATA_HDR_UP_SHIFT       2
+
+/* In AP mode, the same bit (b5) is used to indicate Power save state in
+ * the Rx dir and More data bit state in the tx direction.
+ */
+#define WMI_DATA_HDR_PS_MASK        0x1
+#define WMI_DATA_HDR_PS_SHIFT       5
+
+#define WMI_DATA_HDR_MORE_MASK      0x1
+#define WMI_DATA_HDR_MORE_SHIFT     5
+
+enum wmi_data_hdr_data_type {
+	WMI_DATA_HDR_DATA_TYPE_802_3 = 0,
+	WMI_DATA_HDR_DATA_TYPE_802_11,
+
+	/* used to be used for the PAL */
+	WMI_DATA_HDR_DATA_TYPE_ACL,
+};
+
+#define WMI_DATA_HDR_DATA_TYPE_MASK     0x3
+#define WMI_DATA_HDR_DATA_TYPE_SHIFT    6
+
+/* Macros for operating on WMI_DATA_HDR (info2) field */
+#define WMI_DATA_HDR_SEQNO_MASK     0xFFF
+#define WMI_DATA_HDR_SEQNO_SHIFT    0
+
+#define WMI_DATA_HDR_AMSDU_MASK     0x1
+#define WMI_DATA_HDR_AMSDU_SHIFT    12
+
+#define WMI_DATA_HDR_META_MASK      0x7
+#define WMI_DATA_HDR_META_SHIFT     13
+
+struct wmi_data_hdr {
+	s8 rssi;
+
+	/*
+	 * usage of 'info' field(8-bit):
+	 *
+	 *  b1:b0       - WMI_MSG_TYPE
+	 *  b4:b3:b2    - UP(tid)
+	 *  b5          - Used in AP mode.
+	 *  More-data in tx dir, PS in rx.
+	 *  b7:b6       - Dot3 header(0),
+	 *                Dot11 Header(1),
+	 *                ACL data(2)
+	 */
+	u8 info;
+
+	/*
+	 * usage of 'info2' field(16-bit):
+	 *
+	 * b11:b0       - seq_no
+	 * b12          - A-MSDU?
+	 * b15:b13      - META_DATA_VERSION 0 - 7
+	 */
+	__le16 info2;
+	__le16 info3;
+} __packed;
+
+static inline u8 wmi_data_hdr_get_up(struct wmi_data_hdr *dhdr)
+{
+	return (dhdr->info >> WMI_DATA_HDR_UP_SHIFT) & WMI_DATA_HDR_UP_MASK;
+}
+
+static inline void wmi_data_hdr_set_up(struct wmi_data_hdr *dhdr,
+				       u8 usr_pri)
+{
+	dhdr->info &= ~(WMI_DATA_HDR_UP_MASK << WMI_DATA_HDR_UP_SHIFT);
+	dhdr->info |= usr_pri << WMI_DATA_HDR_UP_SHIFT;
+}
+
+static inline u8 wmi_data_hdr_get_dot11(struct wmi_data_hdr *dhdr)
+{
+	u8 data_type;
+
+	data_type = (dhdr->info >> WMI_DATA_HDR_DATA_TYPE_SHIFT) &
+				   WMI_DATA_HDR_DATA_TYPE_MASK;
+	return (data_type == WMI_DATA_HDR_DATA_TYPE_802_11);
+}
+
+static inline u16 wmi_data_hdr_get_seqno(struct wmi_data_hdr *dhdr)
+{
+	return (le16_to_cpu(dhdr->info2) >> WMI_DATA_HDR_SEQNO_SHIFT) &
+				WMI_DATA_HDR_SEQNO_MASK;
+}
+
+static inline u8 wmi_data_hdr_is_amsdu(struct wmi_data_hdr *dhdr)
+{
+	return (le16_to_cpu(dhdr->info2) >> WMI_DATA_HDR_AMSDU_SHIFT) &
+			       WMI_DATA_HDR_AMSDU_MASK;
+}
+
+static inline u8 wmi_data_hdr_get_meta(struct wmi_data_hdr *dhdr)
+{
+	return (le16_to_cpu(dhdr->info2) >> WMI_DATA_HDR_META_SHIFT) &
+			       WMI_DATA_HDR_META_MASK;
+}
+
+/* Tx meta version definitions */
+#define WMI_MAX_TX_META_SZ	12
+#define WMI_META_VERSION_1	0x01
+#define WMI_META_VERSION_2	0x02
+
+struct wmi_tx_meta_v1 {
+	/* packet ID to identify the tx request */
+	u8 pkt_id;
+
+	/* rate policy to be used for the tx of this frame */
+	u8 rate_plcy_id;
+} __packed;
+
+struct wmi_tx_meta_v2 {
+	/*
+	 * Offset from start of the WMI header for csum calculation to
+	 * begin.
+	 */
+	u8 csum_start;
+
+	/* offset from start of WMI header where final csum goes */
+	u8 csum_dest;
+
+	/* no of bytes over which csum is calculated */
+	u8 csum_flags;
+} __packed;
+
+struct wmi_rx_meta_v1 {
+	u8 status;
+
+	/* rate index mapped to rate at which this packet was received. */
+	u8 rix;
+
+	/* rssi of packet */
+	u8 rssi;
+
+	/* rf channel during packet reception */
+	u8 channel;
+
+	__le16 flags;
+} __packed;
+
+struct wmi_rx_meta_v2 {
+	__le16 csum;
+
+	/* bit 0 set -partial csum valid bit 1 set -test mode */
+	u8 csum_flags;
+} __packed;
+
+/* Control Path */
+struct wmi_cmd_hdr {
+	__le16 cmd_id;
+
+	/* info1 - 16 bits
+	 * b03:b00 - id
+	 * b15:b04 - unused */
+	__le16 info1;
+
+	/* for alignment */
+	__le16 reserved;
+} __packed;
+
+/* List of WMI commands */
+enum wmi_cmd_id {
+	WMI_CONNECT_CMDID = 0x0001,
+	WMI_RECONNECT_CMDID,
+	WMI_DISCONNECT_CMDID,
+	WMI_SYNCHRONIZE_CMDID,
+	WMI_CREATE_PSTREAM_CMDID,
+	WMI_DELETE_PSTREAM_CMDID,
+	WMI_START_SCAN_CMDID,
+	WMI_SET_SCAN_PARAMS_CMDID,
+	WMI_SET_BSS_FILTER_CMDID,
+	WMI_SET_PROBED_SSID_CMDID,	/* 10 */
+	WMI_SET_LISTEN_INT_CMDID,
+	WMI_SET_BMISS_TIME_CMDID,
+	WMI_SET_DISC_TIMEOUT_CMDID,
+	WMI_GET_CHANNEL_LIST_CMDID,
+	WMI_SET_BEACON_INT_CMDID,
+	WMI_GET_STATISTICS_CMDID,
+	WMI_SET_CHANNEL_PARAMS_CMDID,
+	WMI_SET_POWER_MODE_CMDID,
+	WMI_SET_IBSS_PM_CAPS_CMDID,
+	WMI_SET_POWER_PARAMS_CMDID,	/* 20 */
+	WMI_SET_POWERSAVE_TIMERS_POLICY_CMDID,
+	WMI_ADD_CIPHER_KEY_CMDID,
+	WMI_DELETE_CIPHER_KEY_CMDID,
+	WMI_ADD_KRK_CMDID,
+	WMI_DELETE_KRK_CMDID,
+	WMI_SET_PMKID_CMDID,
+	WMI_SET_TX_PWR_CMDID,
+	WMI_GET_TX_PWR_CMDID,
+	WMI_SET_ASSOC_INFO_CMDID,
+	WMI_ADD_BAD_AP_CMDID,		/* 30 */
+	WMI_DELETE_BAD_AP_CMDID,
+	WMI_SET_TKIP_COUNTERMEASURES_CMDID,
+	WMI_RSSI_THRESHOLD_PARAMS_CMDID,
+	WMI_TARGET_ERROR_REPORT_BITMASK_CMDID,
+	WMI_SET_ACCESS_PARAMS_CMDID,
+	WMI_SET_RETRY_LIMITS_CMDID,
+	WMI_SET_OPT_MODE_CMDID,
+	WMI_OPT_TX_FRAME_CMDID,
+	WMI_SET_VOICE_PKT_SIZE_CMDID,
+	WMI_SET_MAX_SP_LEN_CMDID,	/* 40 */
+	WMI_SET_ROAM_CTRL_CMDID,
+	WMI_GET_ROAM_TBL_CMDID,
+	WMI_GET_ROAM_DATA_CMDID,
+	WMI_ENABLE_RM_CMDID,
+	WMI_SET_MAX_OFFHOME_DURATION_CMDID,
+	WMI_EXTENSION_CMDID,	/* Non-wireless extensions */
+	WMI_SNR_THRESHOLD_PARAMS_CMDID,
+	WMI_LQ_THRESHOLD_PARAMS_CMDID,
+	WMI_SET_LPREAMBLE_CMDID,
+	WMI_SET_RTS_CMDID,		/* 50 */
+	WMI_CLR_RSSI_SNR_CMDID,
+	WMI_SET_FIXRATES_CMDID,
+	WMI_GET_FIXRATES_CMDID,
+	WMI_SET_AUTH_MODE_CMDID,
+	WMI_SET_REASSOC_MODE_CMDID,
+	WMI_SET_WMM_CMDID,
+	WMI_SET_WMM_TXOP_CMDID,
+	WMI_TEST_CMDID,
+
+	/* COEX AR6002 only */
+	WMI_SET_BT_STATUS_CMDID,
+	WMI_SET_BT_PARAMS_CMDID,	/* 60 */
+
+	WMI_SET_KEEPALIVE_CMDID,
+	WMI_GET_KEEPALIVE_CMDID,
+	WMI_SET_APPIE_CMDID,
+	WMI_GET_APPIE_CMDID,
+	WMI_SET_WSC_STATUS_CMDID,
+
+	/* Wake on Wireless */
+	WMI_SET_HOST_SLEEP_MODE_CMDID,
+	WMI_SET_WOW_MODE_CMDID,
+	WMI_GET_WOW_LIST_CMDID,
+	WMI_ADD_WOW_PATTERN_CMDID,
+	WMI_DEL_WOW_PATTERN_CMDID,	/* 70 */
+
+	WMI_SET_FRAMERATES_CMDID,
+	WMI_SET_AP_PS_CMDID,
+	WMI_SET_QOS_SUPP_CMDID,
+
+	/* WMI_THIN_RESERVED_... mark the start and end
+	 * values for WMI_THIN_RESERVED command IDs. These
+	 * command IDs can be found in wmi_thin.h */
+	WMI_THIN_RESERVED_START = 0x8000,
+	WMI_THIN_RESERVED_END = 0x8fff,
+
+	/* Developer commands starts at 0xF000 */
+	WMI_SET_BITRATE_CMDID = 0xF000,
+	WMI_GET_BITRATE_CMDID,
+	WMI_SET_WHALPARAM_CMDID,
+	WMI_SET_MAC_ADDRESS_CMDID,
+	WMI_SET_AKMP_PARAMS_CMDID,
+	WMI_SET_PMKID_LIST_CMDID,
+	WMI_GET_PMKID_LIST_CMDID,
+	WMI_ABORT_SCAN_CMDID,
+	WMI_SET_TARGET_EVENT_REPORT_CMDID,
+
+	/* Unused */
+	WMI_UNUSED1,
+	WMI_UNUSED2,
+
+	/* AP mode commands */
+	WMI_AP_HIDDEN_SSID_CMDID,
+	WMI_AP_SET_NUM_STA_CMDID,
+	WMI_AP_ACL_POLICY_CMDID,
+	WMI_AP_ACL_MAC_LIST_CMDID,
+	WMI_AP_CONFIG_COMMIT_CMDID,
+	WMI_AP_SET_MLME_CMDID,
+	WMI_AP_SET_PVB_CMDID,
+	WMI_AP_CONN_INACT_CMDID,
+	WMI_AP_PROT_SCAN_TIME_CMDID,
+	WMI_AP_SET_COUNTRY_CMDID,
+	WMI_AP_SET_DTIM_CMDID,
+	WMI_AP_MODE_STAT_CMDID,
+
+	WMI_SET_IP_CMDID,
+	WMI_SET_PARAMS_CMDID,
+	WMI_SET_MCAST_FILTER_CMDID,
+	WMI_DEL_MCAST_FILTER_CMDID,
+
+	WMI_ALLOW_AGGR_CMDID,
+	WMI_ADDBA_REQ_CMDID,
+	WMI_DELBA_REQ_CMDID,
+	WMI_SET_HT_CAP_CMDID,
+	WMI_SET_HT_OP_CMDID,
+	WMI_SET_TX_SELECT_RATES_CMDID,
+	WMI_SET_TX_SGI_PARAM_CMDID,
+	WMI_SET_RATE_POLICY_CMDID,
+
+	WMI_HCI_CMD_CMDID,
+	WMI_RX_FRAME_FORMAT_CMDID,
+	WMI_SET_THIN_MODE_CMDID,
+	WMI_SET_BT_WLAN_CONN_PRECEDENCE_CMDID,
+
+	WMI_AP_SET_11BG_RATESET_CMDID,
+	WMI_SET_PMK_CMDID,
+	WMI_MCAST_FILTER_CMDID,
+
+	/* COEX CMDID AR6003 */
+	WMI_SET_BTCOEX_FE_ANT_CMDID,
+	WMI_SET_BTCOEX_COLOCATED_BT_DEV_CMDID,
+	WMI_SET_BTCOEX_SCO_CONFIG_CMDID,
+	WMI_SET_BTCOEX_A2DP_CONFIG_CMDID,
+	WMI_SET_BTCOEX_ACLCOEX_CONFIG_CMDID,
+	WMI_SET_BTCOEX_BTINQUIRY_PAGE_CONFIG_CMDID,
+	WMI_SET_BTCOEX_DEBUG_CMDID,
+	WMI_SET_BTCOEX_BT_OPERATING_STATUS_CMDID,
+	WMI_GET_BTCOEX_STATS_CMDID,
+	WMI_GET_BTCOEX_CONFIG_CMDID,
+
+	WMI_SET_DFS_ENABLE_CMDID,	/* F034 */
+	WMI_SET_DFS_MINRSSITHRESH_CMDID,
+	WMI_SET_DFS_MAXPULSEDUR_CMDID,
+	WMI_DFS_RADAR_DETECTED_CMDID,
+
+	/* P2P commands */
+	WMI_P2P_SET_CONFIG_CMDID,	/* F038 */
+	WMI_WPS_SET_CONFIG_CMDID,
+	WMI_SET_REQ_DEV_ATTR_CMDID,
+	WMI_P2P_FIND_CMDID,
+	WMI_P2P_STOP_FIND_CMDID,
+	WMI_P2P_GO_NEG_START_CMDID,
+	WMI_P2P_LISTEN_CMDID,
+
+	WMI_CONFIG_TX_MAC_RULES_CMDID,	/* F040 */
+	WMI_SET_PROMISCUOUS_MODE_CMDID,
+	WMI_RX_FRAME_FILTER_CMDID,
+	WMI_SET_CHANNEL_CMDID,
+
+	/* WAC commands */
+	WMI_ENABLE_WAC_CMDID,
+	WMI_WAC_SCAN_REPLY_CMDID,
+	WMI_WAC_CTRL_REQ_CMDID,
+	WMI_SET_DIV_PARAMS_CMDID,
+
+	WMI_GET_PMK_CMDID,
+	WMI_SET_PASSPHRASE_CMDID,
+	WMI_SEND_ASSOC_RES_CMDID,
+	WMI_SET_ASSOC_REQ_RELAY_CMDID,
+	WMI_GET_RFKILL_MODE_CMDID,
+
+	/* ACS command, consists of sub-commands */
+	WMI_ACS_CTRL_CMDID,
+
+	/* Ultra low power store / recall commands */
+	WMI_STORERECALL_CONFIGURE_CMDID,
+	WMI_STORERECALL_RECALL_CMDID,
+	WMI_STORERECALL_HOST_READY_CMDID,
+	WMI_FORCE_TARGET_ASSERT_CMDID,
+	WMI_SET_EXCESS_TX_RETRY_THRES_CMDID,
+};
+
+/* WMI_CONNECT_CMDID  */
+enum network_type {
+	INFRA_NETWORK = 0x01,
+	ADHOC_NETWORK = 0x02,
+	ADHOC_CREATOR = 0x04,
+	AP_NETWORK = 0x10,
+};
+
+enum dot11_auth_mode {
+	OPEN_AUTH = 0x01,
+	SHARED_AUTH = 0x02,
+
+	/* different from IEEE_AUTH_MODE definitions */
+	LEAP_AUTH = 0x04,
+};
+
+enum {
+	AUTH_IDLE,
+	AUTH_OPEN_IN_PROGRESS,
+};
+
+enum auth_mode {
+	NONE_AUTH = 0x01,
+	WPA_AUTH = 0x02,
+	WPA2_AUTH = 0x04,
+	WPA_PSK_AUTH = 0x08,
+	WPA2_PSK_AUTH = 0x10,
+	WPA_AUTH_CCKM = 0x20,
+	WPA2_AUTH_CCKM = 0x40,
+};
+
+#define WMI_MIN_CRYPTO_TYPE NONE_CRYPT
+#define WMI_MAX_CRYPTO_TYPE (AES_CRYPT + 1)
+
+#define WMI_MIN_KEY_INDEX   0
+#define WMI_MAX_KEY_INDEX   3
+
+#define WMI_MAX_KEY_LEN     32
+
+/*
+ * NB: these values are ordered carefully; there are lots of
+ * of implications in any reordering.  In particular beware
+ * that 4 is not used to avoid conflicting with IEEE80211_F_PRIVACY.
+ */
+#define ATH6KL_CIPHER_WEP            0
+#define ATH6KL_CIPHER_TKIP           1
+#define ATH6KL_CIPHER_AES_OCB        2
+#define ATH6KL_CIPHER_AES_CCM        3
+#define ATH6KL_CIPHER_CKIP           5
+#define ATH6KL_CIPHER_CCKM_KRK       6
+#define ATH6KL_CIPHER_NONE           7 /* pseudo value */
+
+/*
+ * 802.11 rate set.
+ */
+#define ATH6KL_RATE_MAXSIZE  15	/* max rates we'll handle */
+
+#define ATH_OUI_TYPE            0x01
+#define WPA_OUI_TYPE            0x01
+#define WMM_PARAM_OUI_SUBTYPE   0x01
+#define WMM_OUI_TYPE            0x02
+#define WSC_OUT_TYPE            0x04
+
+enum wmi_connect_ctrl_flags_bits {
+	CONNECT_ASSOC_POLICY_USER = 0x0001,
+	CONNECT_SEND_REASSOC = 0x0002,
+	CONNECT_IGNORE_WPAx_GROUP_CIPHER = 0x0004,
+	CONNECT_PROFILE_MATCH_DONE = 0x0008,
+	CONNECT_IGNORE_AAC_BEACON = 0x0010,
+	CONNECT_CSA_FOLLOW_BSS = 0x0020,
+	CONNECT_DO_WPA_OFFLOAD = 0x0040,
+	CONNECT_DO_NOT_DEAUTH = 0x0080,
+};
+
+struct wmi_connect_cmd {
+	u8 nw_type;
+	u8 dot11_auth_mode;
+	u8 auth_mode;
+	u8 prwise_crypto_type;
+	u8 prwise_crypto_len;
+	u8 grp_crypto_type;
+	u8 grp_crypto_len;
+	u8 ssid_len;
+	u8 ssid[IEEE80211_MAX_SSID_LEN];
+	__le16 ch;
+	u8 bssid[ETH_ALEN];
+	__le32 ctrl_flags;
+} __packed;
+
+/* WMI_RECONNECT_CMDID */
+struct wmi_reconnect_cmd {
+	/* channel hint */
+	__le16 channel;
+
+	/* mandatory if set */
+	u8 bssid[ETH_ALEN];
+} __packed;
+
+/* WMI_ADD_CIPHER_KEY_CMDID */
+enum key_usage {
+	PAIRWISE_USAGE = 0x00,
+	GROUP_USAGE = 0x01,
+
+	/* default Tx Key - static WEP only */
+	TX_USAGE = 0x02,
+};
+
+/*
+ * Bit Flag
+ * Bit 0 - Initialise TSC - default is Initialize
+ */
+#define KEY_OP_INIT_TSC     0x01
+#define KEY_OP_INIT_RSC     0x02
+
+/* default initialise the TSC & RSC */
+#define KEY_OP_INIT_VAL     0x03
+#define KEY_OP_VALID_MASK   0x03
+
+struct wmi_add_cipher_key_cmd {
+	u8 key_index;
+	u8 key_type;
+
+	/* enum key_usage */
+	u8 key_usage;
+
+	u8 key_len;
+
+	/* key replay sequence counter */
+	u8 key_rsc[8];
+
+	u8 key[WLAN_MAX_KEY_LEN];
+
+	/* additional key control info */
+	u8 key_op_ctrl;
+
+	u8 key_mac_addr[ETH_ALEN];
+} __packed;
+
+/* WMI_DELETE_CIPHER_KEY_CMDID */
+struct wmi_delete_cipher_key_cmd {
+	u8 key_index;
+} __packed;
+
+#define WMI_KRK_LEN     16
+
+/* WMI_ADD_KRK_CMDID */
+struct wmi_add_krk_cmd {
+	u8 krk[WMI_KRK_LEN];
+} __packed;
+
+/* WMI_SETPMKID_CMDID */
+
+#define WMI_PMKID_LEN 16
+
+enum pmkid_enable_flg {
+	PMKID_DISABLE = 0,
+	PMKID_ENABLE = 1,
+};
+
+struct wmi_setpmkid_cmd {
+	u8 bssid[ETH_ALEN];
+
+	/* enum pmkid_enable_flg */
+	u8 enable;
+
+	u8 pmkid[WMI_PMKID_LEN];
+} __packed;
+
+/* WMI_START_SCAN_CMD */
+enum wmi_scan_type {
+	WMI_LONG_SCAN = 0,
+	WMI_SHORT_SCAN = 1,
+};
+
+struct wmi_start_scan_cmd {
+	__le32 force_fg_scan;
+
+	/* for legacy cisco AP compatibility */
+	__le32 is_legacy;
+
+	/* max duration in the home channel(msec) */
+	__le32 home_dwell_time;
+
+	/* time interval between scans (msec) */
+	__le32 force_scan_intvl;
+
+	/* enum wmi_scan_type */
+	u8 scan_type;
+
+	/* how many channels follow */
+	u8 num_ch;
+
+	/* channels in Mhz */
+	__le16 ch_list[1];
+} __packed;
+
+/* WMI_SET_SCAN_PARAMS_CMDID */
+#define WMI_SHORTSCANRATIO_DEFAULT      3
+
+/*
+ *  Warning: scan control flag value of 0xFF is used to disable
+ *  all flags in WMI_SCAN_PARAMS_CMD. Do not add any more
+ *  flags here
+ */
+enum wmi_scan_ctrl_flags_bits {
+
+	/* set if can scan in the connect cmd */
+	CONNECT_SCAN_CTRL_FLAGS = 0x01,
+
+	/* set if scan for the SSID it is already connected to */
+	SCAN_CONNECTED_CTRL_FLAGS = 0x02,
+
+	/* set if enable active scan */
+	ACTIVE_SCAN_CTRL_FLAGS = 0x04,
+
+	/* set if enable roam scan when bmiss and lowrssi */
+	ROAM_SCAN_CTRL_FLAGS = 0x08,
+
+	/* set if follows customer BSSINFO reporting rule */
+	REPORT_BSSINFO_CTRL_FLAGS = 0x10,
+
+	/* if disabled, target doesn't scan after a disconnect event  */
+	ENABLE_AUTO_CTRL_FLAGS = 0x20,
+
+	/*
+	 * Scan complete event with canceled status will be generated when
+	 * a scan is prempted before it gets completed.
+	 */
+	ENABLE_SCAN_ABORT_EVENT = 0x40
+};
+
+#define DEFAULT_SCAN_CTRL_FLAGS			\
+	(CONNECT_SCAN_CTRL_FLAGS |		\
+	 SCAN_CONNECTED_CTRL_FLAGS |		\
+	 ACTIVE_SCAN_CTRL_FLAGS |		\
+	 ROAM_SCAN_CTRL_FLAGS |			\
+	 ENABLE_AUTO_CTRL_FLAGS)
+
+struct wmi_scan_params_cmd {
+	  /* sec */
+	__le16 fg_start_period;
+
+	/* sec */
+	__le16 fg_end_period;
+
+	/* sec */
+	__le16 bg_period;
+
+	/* msec */
+	__le16 maxact_chdwell_time;
+
+	/* msec */
+	__le16 pas_chdwell_time;
+
+	  /* how many shorts scan for one long */
+	u8 short_scan_ratio;
+
+	u8 scan_ctrl_flags;
+
+	/* msec */
+	__le16 minact_chdwell_time;
+
+	/* max active scans per ssid */
+	__le16 maxact_scan_per_ssid;
+
+	/* msecs */
+	__le32 max_dfsch_act_time;
+} __packed;
+
+/* WMI_SET_BSS_FILTER_CMDID */
+enum wmi_bss_filter {
+	/* no beacons forwarded */
+	NONE_BSS_FILTER = 0x0,
+
+	/* all beacons forwarded */
+	ALL_BSS_FILTER,
+
+	/* only beacons matching profile */
+	PROFILE_FILTER,
+
+	/* all but beacons matching profile */
+	ALL_BUT_PROFILE_FILTER,
+
+	/* only beacons matching current BSS */
+	CURRENT_BSS_FILTER,
+
+	/* all but beacons matching BSS */
+	ALL_BUT_BSS_FILTER,
+
+	/* beacons matching probed ssid */
+	PROBED_SSID_FILTER,
+
+	/* marker only */
+	LAST_BSS_FILTER,
+};
+
+struct wmi_bss_filter_cmd {
+	/* see, enum wmi_bss_filter */
+	u8 bss_filter;
+
+	/* for alignment */
+	u8 reserved1;
+
+	/* for alignment */
+	__le16 reserved2;
+
+	__le32 ie_mask;
+} __packed;
+
+/* WMI_SET_PROBED_SSID_CMDID */
+#define MAX_PROBED_SSID_INDEX   9
+
+enum wmi_ssid_flag {
+	/* disables entry */
+	DISABLE_SSID_FLAG = 0,
+
+	/* probes specified ssid */
+	SPECIFIC_SSID_FLAG = 0x01,
+
+	/* probes for any ssid */
+	ANY_SSID_FLAG = 0x02,
+};
+
+struct wmi_probed_ssid_cmd {
+	/* 0 to MAX_PROBED_SSID_INDEX */
+	u8 entry_index;
+
+	/* see, enum wmi_ssid_flg */
+	u8 flag;
+
+	u8 ssid_len;
+	u8 ssid[IEEE80211_MAX_SSID_LEN];
+} __packed;
+
+/*
+ * WMI_SET_LISTEN_INT_CMDID
+ * The Listen interval is between 15 and 3000 TUs
+ */
+struct wmi_listen_int_cmd {
+	__le16 listen_intvl;
+	__le16 num_beacons;
+} __packed;
+
+/* WMI_SET_POWER_MODE_CMDID */
+enum wmi_power_mode {
+	REC_POWER = 0x01,
+	MAX_PERF_POWER,
+};
+
+struct wmi_power_mode_cmd {
+	/* see, enum wmi_power_mode */
+	u8 pwr_mode;
+} __packed;
+
+/*
+ * Policy to determnine whether power save failure event should be sent to
+ * host during scanning
+ */
+enum power_save_fail_event_policy {
+	SEND_POWER_SAVE_FAIL_EVENT_ALWAYS = 1,
+	IGNORE_POWER_SAVE_FAIL_EVENT_DURING_SCAN = 2,
+};
+
+struct wmi_power_params_cmd {
+	/* msec */
+	__le16 idle_period;
+
+	__le16 pspoll_number;
+	__le16 dtim_policy;
+	__le16 tx_wakeup_policy;
+	__le16 num_tx_to_wakeup;
+	__le16 ps_fail_event_policy;
+} __packed;
+
+/* WMI_SET_DISC_TIMEOUT_CMDID */
+struct wmi_disc_timeout_cmd {
+	/* seconds */
+	u8 discon_timeout;
+} __packed;
+
+enum dir_type {
+	UPLINK_TRAFFIC = 0,
+	DNLINK_TRAFFIC = 1,
+	BIDIR_TRAFFIC = 2,
+};
+
+enum voiceps_cap_type {
+	DISABLE_FOR_THIS_AC = 0,
+	ENABLE_FOR_THIS_AC = 1,
+	ENABLE_FOR_ALL_AC = 2,
+};
+
+enum traffic_type {
+	TRAFFIC_TYPE_APERIODIC = 0,
+	TRAFFIC_TYPE_PERIODIC = 1,
+};
+
+/* WMI_SYNCHRONIZE_CMDID */
+struct wmi_sync_cmd {
+	u8 data_sync_map;
+} __packed;
+
+/* WMI_CREATE_PSTREAM_CMDID */
+struct wmi_create_pstream_cmd {
+	/* msec */
+	__le32 min_service_int;
+
+	/* msec */
+	__le32 max_service_int;
+
+	/* msec */
+	__le32 inactivity_int;
+
+	/* msec */
+	__le32 suspension_int;
+
+	__le32 service_start_time;
+
+	/* in bps */
+	__le32 min_data_rate;
+
+	/* in bps */
+	__le32 mean_data_rate;
+
+	/* in bps */
+	__le32 peak_data_rate;
+
+	__le32 max_burst_size;
+	__le32 delay_bound;
+
+	/* in bps */
+	__le32 min_phy_rate;
+
+	__le32 sba;
+	__le32 medium_time;
+
+	/* in octects */
+	__le16 nominal_msdu;
+
+	/* in octects */
+	__le16 max_msdu;
+
+	u8 traffic_class;
+
+	/* see, enum dir_type */
+	u8 traffic_direc;
+
+	u8 rx_queue_num;
+
+	/* see, enum traffic_type */
+	u8 traffic_type;
+
+	/* see, enum voiceps_cap_type */
+	u8 voice_psc_cap;
+	u8 tsid;
+
+	/* 802.1D user priority */
+	u8 user_pri;
+
+	/* nominal phy rate */
+	u8 nominal_phy;
+} __packed;
+
+/* WMI_DELETE_PSTREAM_CMDID */
+struct wmi_delete_pstream_cmd {
+	u8 tx_queue_num;
+	u8 rx_queue_num;
+	u8 traffic_direc;
+	u8 traffic_class;
+	u8 tsid;
+} __packed;
+
+/* WMI_SET_CHANNEL_PARAMS_CMDID */
+enum wmi_phy_mode {
+	WMI_11A_MODE = 0x1,
+	WMI_11G_MODE = 0x2,
+	WMI_11AG_MODE = 0x3,
+	WMI_11B_MODE = 0x4,
+	WMI_11GONLY_MODE = 0x5,
+};
+
+#define WMI_MAX_CHANNELS        32
+
+/*
+ *  WMI_RSSI_THRESHOLD_PARAMS_CMDID
+ *  Setting the polltime to 0 would disable polling. Threshold values are
+ *  in the ascending order, and should agree to:
+ *  (lowThreshold_lowerVal < lowThreshold_upperVal < highThreshold_lowerVal
+ *   < highThreshold_upperVal)
+ */
+
+struct wmi_rssi_threshold_params_cmd {
+	/* polling time as a factor of LI */
+	__le32 poll_time;
+
+	/* lowest of upper */
+	a_sle16 thresh_above1_val;
+
+	a_sle16 thresh_above2_val;
+	a_sle16 thresh_above3_val;
+	a_sle16 thresh_above4_val;
+	a_sle16 thresh_above5_val;
+
+	/* highest of upper */
+	a_sle16 thresh_above6_val;
+
+	/* lowest of bellow */
+	a_sle16 thresh_below1_val;
+
+	a_sle16 thresh_below2_val;
+	a_sle16 thresh_below3_val;
+	a_sle16 thresh_below4_val;
+	a_sle16 thresh_below5_val;
+
+	/* highest of bellow */
+	a_sle16 thresh_below6_val;
+
+	/* "alpha" */
+	u8 weight;
+
+	u8 reserved[3];
+} __packed;
+
+/*
+ *  WMI_SNR_THRESHOLD_PARAMS_CMDID
+ *  Setting the polltime to 0 would disable polling.
+ */
+
+struct wmi_snr_threshold_params_cmd {
+	/* polling time as a factor of LI */
+	__le32 poll_time;
+
+	/* "alpha" */
+	u8 weight;
+
+	/* lowest of uppper */
+	u8 thresh_above1_val;
+
+	u8 thresh_above2_val;
+	u8 thresh_above3_val;
+
+	/* highest of upper */
+	u8 thresh_above4_val;
+
+	/* lowest of bellow */
+	u8 thresh_below1_val;
+
+	u8 thresh_below2_val;
+	u8 thresh_below3_val;
+
+	/* highest of bellow */
+	u8 thresh_below4_val;
+
+	u8 reserved[3];
+} __packed;
+
+enum wmi_preamble_policy {
+	WMI_IGNORE_BARKER_IN_ERP = 0,
+	WMI_DONOT_IGNORE_BARKER_IN_ERP
+};
+
+struct wmi_set_lpreamble_cmd {
+	u8 status;
+	u8 preamble_policy;
+} __packed;
+
+struct wmi_set_rts_cmd {
+	__le16 threshold;
+} __packed;
+
+/* WMI_SET_TX_PWR_CMDID */
+struct wmi_set_tx_pwr_cmd {
+	/* in dbM units */
+	u8 dbM;
+} __packed;
+
+struct wmi_tx_pwr_reply {
+	/* in dbM units */
+	u8 dbM;
+} __packed;
+
+struct wmi_report_sleep_state_event {
+	__le32 sleep_state;
+};
+
+enum wmi_report_sleep_status {
+	WMI_REPORT_SLEEP_STATUS_IS_DEEP_SLEEP = 0,
+	WMI_REPORT_SLEEP_STATUS_IS_AWAKE
+};
+enum target_event_report_config {
+	/* default */
+	DISCONN_EVT_IN_RECONN = 0,
+
+	NO_DISCONN_EVT_IN_RECONN
+};
+
+/* Command Replies */
+
+/* WMI_GET_CHANNEL_LIST_CMDID reply */
+struct wmi_channel_list_reply {
+	u8 reserved;
+
+	/* number of channels in reply */
+	u8 num_ch;
+
+	/* channel in Mhz */
+	__le16 ch_list[1];
+} __packed;
+
+/* List of Events (target to host) */
+enum wmi_event_id {
+	WMI_READY_EVENTID = 0x1001,
+	WMI_CONNECT_EVENTID,
+	WMI_DISCONNECT_EVENTID,
+	WMI_BSSINFO_EVENTID,
+	WMI_CMDERROR_EVENTID,
+	WMI_REGDOMAIN_EVENTID,
+	WMI_PSTREAM_TIMEOUT_EVENTID,
+	WMI_NEIGHBOR_REPORT_EVENTID,
+	WMI_TKIP_MICERR_EVENTID,
+	WMI_SCAN_COMPLETE_EVENTID,	/* 0x100a */
+	WMI_REPORT_STATISTICS_EVENTID,
+	WMI_RSSI_THRESHOLD_EVENTID,
+	WMI_ERROR_REPORT_EVENTID,
+	WMI_OPT_RX_FRAME_EVENTID,
+	WMI_REPORT_ROAM_TBL_EVENTID,
+	WMI_EXTENSION_EVENTID,
+	WMI_CAC_EVENTID,
+	WMI_SNR_THRESHOLD_EVENTID,
+	WMI_LQ_THRESHOLD_EVENTID,
+	WMI_TX_RETRY_ERR_EVENTID,	/* 0x1014 */
+	WMI_REPORT_ROAM_DATA_EVENTID,
+	WMI_TEST_EVENTID,
+	WMI_APLIST_EVENTID,
+	WMI_GET_WOW_LIST_EVENTID,
+	WMI_GET_PMKID_LIST_EVENTID,
+	WMI_CHANNEL_CHANGE_EVENTID,
+	WMI_PEER_NODE_EVENTID,
+	WMI_PSPOLL_EVENTID,
+	WMI_DTIMEXPIRY_EVENTID,
+	WMI_WLAN_VERSION_EVENTID,
+	WMI_SET_PARAMS_REPLY_EVENTID,
+	WMI_ADDBA_REQ_EVENTID,		/*0x1020 */
+	WMI_ADDBA_RESP_EVENTID,
+	WMI_DELBA_REQ_EVENTID,
+	WMI_TX_COMPLETE_EVENTID,
+	WMI_HCI_EVENT_EVENTID,
+	WMI_ACL_DATA_EVENTID,
+	WMI_REPORT_SLEEP_STATE_EVENTID,
+	WMI_REPORT_BTCOEX_STATS_EVENTID,
+	WMI_REPORT_BTCOEX_CONFIG_EVENTID,
+	WMI_GET_PMK_EVENTID,
+
+	/* DFS Events */
+	WMI_DFS_HOST_ATTACH_EVENTID,
+	WMI_DFS_HOST_INIT_EVENTID,
+	WMI_DFS_RESET_DELAYLINES_EVENTID,
+	WMI_DFS_RESET_RADARQ_EVENTID,
+	WMI_DFS_RESET_AR_EVENTID,
+	WMI_DFS_RESET_ARQ_EVENTID,
+	WMI_DFS_SET_DUR_MULTIPLIER_EVENTID,
+	WMI_DFS_SET_BANGRADAR_EVENTID,
+	WMI_DFS_SET_DEBUGLEVEL_EVENTID,
+	WMI_DFS_PHYERR_EVENTID,
+
+	/* CCX Evants */
+	WMI_CCX_RM_STATUS_EVENTID,
+
+	/* P2P Events */
+	WMI_P2P_GO_NEG_RESULT_EVENTID,
+
+	WMI_WAC_SCAN_DONE_EVENTID,
+	WMI_WAC_REPORT_BSS_EVENTID,
+	WMI_WAC_START_WPS_EVENTID,
+	WMI_WAC_CTRL_REQ_REPLY_EVENTID,
+
+	/* RFKILL Events */
+	WMI_RFKILL_STATE_CHANGE_EVENTID,
+	WMI_RFKILL_GET_MODE_CMD_EVENTID,
+	WMI_THIN_RESERVED_START_EVENTID = 0x8000,
+
+	/*
+	 * Events in this range are reserved for thinmode
+	 * See wmi_thin.h for actual definitions
+	 */
+	WMI_THIN_RESERVED_END_EVENTID = 0x8fff,
+
+	WMI_SET_CHANNEL_EVENTID,
+	WMI_ASSOC_REQ_EVENTID,
+
+	/* Generic ACS event */
+	WMI_ACS_EVENTID,
+	WMI_REPORT_WMM_PARAMS_EVENTID
+};
+
+struct wmi_ready_event_2 {
+	__le32 sw_version;
+	__le32 abi_version;
+	u8 mac_addr[ETH_ALEN];
+	u8 phy_cap;
+} __packed;
+
+/* Connect Event */
+struct wmi_connect_event {
+	__le16 ch;
+	u8 bssid[ETH_ALEN];
+	__le16 listen_intvl;
+	__le16 beacon_intvl;
+	__le32 nw_type;
+	u8 beacon_ie_len;
+	u8 assoc_req_len;
+	u8 assoc_resp_len;
+	u8 assoc_info[1];
+} __packed;
+
+/* Disconnect Event */
+enum wmi_disconnect_reason {
+	NO_NETWORK_AVAIL = 0x01,
+
+	/* bmiss */
+	LOST_LINK = 0x02,
+
+	DISCONNECT_CMD = 0x03,
+	BSS_DISCONNECTED = 0x04,
+	AUTH_FAILED = 0x05,
+	ASSOC_FAILED = 0x06,
+	NO_RESOURCES_AVAIL = 0x07,
+	CSERV_DISCONNECT = 0x08,
+	INVALID_PROFILE = 0x0a,
+	DOT11H_CHANNEL_SWITCH = 0x0b,
+	PROFILE_MISMATCH = 0x0c,
+	CONNECTION_EVICTED = 0x0d,
+	IBSS_MERGE = 0xe,
+};
+
+struct wmi_disconnect_event {
+	/* reason code, see 802.11 spec. */
+	__le16 proto_reason_status;
+
+	/* set if known */
+	u8 bssid[ETH_ALEN];
+
+	/* see WMI_DISCONNECT_REASON */
+	u8 disconn_reason;
+
+	u8 assoc_resp_len;
+	u8 assoc_info[1];
+} __packed;
+
+/*
+ * BSS Info Event.
+ * Mechanism used to inform host of the presence and characteristic of
+ * wireless networks present.  Consists of bss info header followed by
+ * the beacon or probe-response frame body.  The 802.11 header is no included.
+ */
+enum wmi_bi_ftype {
+	BEACON_FTYPE = 0x1,
+	PROBERESP_FTYPE,
+	ACTION_MGMT_FTYPE,
+	PROBEREQ_FTYPE,
+};
+
+struct wmi_bss_info_hdr {
+	__le16 ch;
+
+	/* see, enum wmi_bi_ftype */
+	u8 frame_type;
+
+	u8 snr;
+	a_sle16 rssi;
+	u8 bssid[ETH_ALEN];
+	__le32 ie_mask;
+} __packed;
+
+/*
+ * BSS INFO HDR version 2.0
+ * With 6 bytes HTC header and 6 bytes of WMI header
+ * WMI_BSS_INFO_HDR cannot be accommodated in the removed 802.11 management
+ * header space.
+ * - Reduce the ie_mask to 2 bytes as only two bit flags are used
+ * - Remove rssi and compute it on the host. rssi = snr - 95
+ */
+struct wmi_bss_info_hdr2 {
+	__le16 ch;
+
+	/* see, enum wmi_bi_ftype */
+	u8 frame_type;
+
+	u8 snr;
+	u8 bssid[ETH_ALEN];
+	__le16 ie_mask;
+} __packed;
+
+/* Command Error Event */
+enum wmi_error_code {
+	INVALID_PARAM = 0x01,
+	ILLEGAL_STATE = 0x02,
+	INTERNAL_ERROR = 0x03,
+};
+
+struct wmi_cmd_error_event {
+	__le16 cmd_id;
+	u8 err_code;
+} __packed;
+
+struct wmi_pstream_timeout_event {
+	u8 tx_queue_num;
+	u8 rx_queue_num;
+	u8 traffic_direc;
+	u8 traffic_class;
+} __packed;
+
+/*
+ * The WMI_NEIGHBOR_REPORT Event is generated by the target to inform
+ * the host of BSS's it has found that matches the current profile.
+ * It can be used by the host to cache PMKs and/to initiate pre-authentication
+ * if the BSS supports it.  The first bssid is always the current associated
+ * BSS.
+ * The bssid and bssFlags information repeats according to the number
+ * or APs reported.
+ */
+enum wmi_bss_flags {
+	WMI_DEFAULT_BSS_FLAGS = 0x00,
+	WMI_PREAUTH_CAPABLE_BSS = 0x01,
+	WMI_PMKID_VALID_BSS = 0x02,
+};
+
+/* TKIP MIC Error Event */
+struct wmi_tkip_micerr_event {
+	u8 key_id;
+	u8 is_mcast;
+} __packed;
+
+/* WMI_SCAN_COMPLETE_EVENTID */
+struct wmi_scan_complete_event {
+	a_sle32 status;
+} __packed;
+
+#define MAX_OPT_DATA_LEN 1400
+
+/*
+ * Special frame receive Event.
+ * Mechanism used to inform host of the receiption of the special frames.
+ * Consists of special frame info header followed by special frame body.
+ * The 802.11 header is not included.
+ */
+struct wmi_opt_rx_info_hdr {
+	__le16 ch;
+	u8 frame_type;
+	s8 snr;
+	u8 src_addr[ETH_ALEN];
+	u8 bssid[ETH_ALEN];
+} __packed;
+
+/* Reporting statistic */
+struct tx_stats {
+	__le32 pkt;
+	__le32 byte;
+	__le32 ucast_pkt;
+	__le32 ucast_byte;
+	__le32 mcast_pkt;
+	__le32 mcast_byte;
+	__le32 bcast_pkt;
+	__le32 bcast_byte;
+	__le32 rts_success_cnt;
+	__le32 pkt_per_ac[4];
+	__le32 err_per_ac[4];
+
+	__le32 err;
+	__le32 fail_cnt;
+	__le32 retry_cnt;
+	__le32 mult_retry_cnt;
+	__le32 rts_fail_cnt;
+	a_sle32 ucast_rate;
+} __packed;
+
+struct rx_stats {
+	__le32 pkt;
+	__le32 byte;
+	__le32 ucast_pkt;
+	__le32 ucast_byte;
+	__le32 mcast_pkt;
+	__le32 mcast_byte;
+	__le32 bcast_pkt;
+	__le32 bcast_byte;
+	__le32 frgment_pkt;
+
+	__le32 err;
+	__le32 crc_err;
+	__le32 key_cache_miss;
+	__le32 decrypt_err;
+	__le32 dupl_frame;
+	a_sle32 ucast_rate;
+} __packed;
+
+struct tkip_ccmp_stats {
+	__le32 tkip_local_mic_fail;
+	__le32 tkip_cnter_measures_invoked;
+	__le32 tkip_replays;
+	__le32 tkip_fmt_err;
+	__le32 ccmp_fmt_err;
+	__le32 ccmp_replays;
+} __packed;
+
+struct pm_stats {
+	__le32 pwr_save_failure_cnt;
+	__le16 stop_tx_failure_cnt;
+	__le16 atim_tx_failure_cnt;
+	__le16 atim_rx_failure_cnt;
+	__le16 bcn_rx_failure_cnt;
+} __packed;
+
+struct cserv_stats {
+	__le32 cs_bmiss_cnt;
+	__le32 cs_low_rssi_cnt;
+	__le16 cs_connect_cnt;
+	__le16 cs_discon_cnt;
+	a_sle16 cs_ave_beacon_rssi;
+	__le16 cs_roam_count;
+	a_sle16 cs_rssi;
+	u8 cs_snr;
+	u8 cs_ave_beacon_snr;
+	u8 cs_last_roam_msec;
+} __packed;
+
+struct wlan_net_stats {
+	struct tx_stats tx;
+	struct rx_stats rx;
+	struct tkip_ccmp_stats tkip_ccmp_stats;
+} __packed;
+
+struct arp_stats {
+	__le32 arp_received;
+	__le32 arp_matched;
+	__le32 arp_replied;
+} __packed;
+
+struct wlan_wow_stats {
+	__le32 wow_pkt_dropped;
+	__le16 wow_evt_discarded;
+	u8 wow_host_pkt_wakeups;
+	u8 wow_host_evt_wakeups;
+} __packed;
+
+struct wmi_target_stats {
+	__le32 lq_val;
+	a_sle32 noise_floor_calib;
+	struct pm_stats pm_stats;
+	struct wlan_net_stats stats;
+	struct wlan_wow_stats wow_stats;
+	struct arp_stats arp_stats;
+	struct cserv_stats cserv_stats;
+} __packed;
+
+/*
+ * WMI_RSSI_THRESHOLD_EVENTID.
+ * Indicate the RSSI events to host. Events are indicated when we breach a
+ * thresold value.
+ */
+enum wmi_rssi_threshold_val {
+	WMI_RSSI_THRESHOLD1_ABOVE = 0,
+	WMI_RSSI_THRESHOLD2_ABOVE,
+	WMI_RSSI_THRESHOLD3_ABOVE,
+	WMI_RSSI_THRESHOLD4_ABOVE,
+	WMI_RSSI_THRESHOLD5_ABOVE,
+	WMI_RSSI_THRESHOLD6_ABOVE,
+	WMI_RSSI_THRESHOLD1_BELOW,
+	WMI_RSSI_THRESHOLD2_BELOW,
+	WMI_RSSI_THRESHOLD3_BELOW,
+	WMI_RSSI_THRESHOLD4_BELOW,
+	WMI_RSSI_THRESHOLD5_BELOW,
+	WMI_RSSI_THRESHOLD6_BELOW
+};
+
+struct wmi_rssi_threshold_event {
+	a_sle16 rssi;
+	u8 range;
+} __packed;
+
+enum wmi_snr_threshold_val {
+	WMI_SNR_THRESHOLD1_ABOVE = 1,
+	WMI_SNR_THRESHOLD1_BELOW,
+	WMI_SNR_THRESHOLD2_ABOVE,
+	WMI_SNR_THRESHOLD2_BELOW,
+	WMI_SNR_THRESHOLD3_ABOVE,
+	WMI_SNR_THRESHOLD3_BELOW,
+	WMI_SNR_THRESHOLD4_ABOVE,
+	WMI_SNR_THRESHOLD4_BELOW
+};
+
+struct wmi_snr_threshold_event {
+	/* see, enum wmi_snr_threshold_val */
+	u8 range;
+
+	u8 snr;
+} __packed;
+
+/* WMI_REPORT_ROAM_TBL_EVENTID */
+#define MAX_ROAM_TBL_CAND   5
+
+struct wmi_bss_roam_info {
+	a_sle32 roam_util;
+	u8 bssid[ETH_ALEN];
+	s8 rssi;
+	s8 rssidt;
+	s8 last_rssi;
+	s8 util;
+	s8 bias;
+
+	/* for alignment */
+	u8 reserved;
+} __packed;
+
+/* WMI_CAC_EVENTID */
+enum cac_indication {
+	CAC_INDICATION_ADMISSION = 0x00,
+	CAC_INDICATION_ADMISSION_RESP = 0x01,
+	CAC_INDICATION_DELETE = 0x02,
+	CAC_INDICATION_NO_RESP = 0x03,
+};
+
+#define WMM_TSPEC_IE_LEN   63
+
+struct wmi_cac_event {
+	u8 ac;
+	u8 cac_indication;
+	u8 status_code;
+	u8 tspec_suggestion[WMM_TSPEC_IE_LEN];
+} __packed;
+
+/* WMI_APLIST_EVENTID */
+
+enum aplist_ver {
+	APLIST_VER1 = 1,
+};
+
+struct wmi_ap_info_v1 {
+	u8 bssid[ETH_ALEN];
+	__le16 channel;
+} __packed;
+
+union wmi_ap_info {
+	struct wmi_ap_info_v1 ap_info_v1;
+} __packed;
+
+struct wmi_aplist_event {
+	u8 ap_list_ver;
+	u8 num_ap;
+	union wmi_ap_info ap_list[1];
+} __packed;
+
+/* Developer Commands */
+
+/*
+ * WMI_SET_BITRATE_CMDID
+ *
+ * Get bit rate cmd uses same definition as set bit rate cmd
+ */
+enum wmi_bit_rate {
+	RATE_AUTO = -1,
+	RATE_1Mb = 0,
+	RATE_2Mb = 1,
+	RATE_5_5Mb = 2,
+	RATE_11Mb = 3,
+	RATE_6Mb = 4,
+	RATE_9Mb = 5,
+	RATE_12Mb = 6,
+	RATE_18Mb = 7,
+	RATE_24Mb = 8,
+	RATE_36Mb = 9,
+	RATE_48Mb = 10,
+	RATE_54Mb = 11,
+	RATE_MCS_0_20 = 12,
+	RATE_MCS_1_20 = 13,
+	RATE_MCS_2_20 = 14,
+	RATE_MCS_3_20 = 15,
+	RATE_MCS_4_20 = 16,
+	RATE_MCS_5_20 = 17,
+	RATE_MCS_6_20 = 18,
+	RATE_MCS_7_20 = 19,
+	RATE_MCS_0_40 = 20,
+	RATE_MCS_1_40 = 21,
+	RATE_MCS_2_40 = 22,
+	RATE_MCS_3_40 = 23,
+	RATE_MCS_4_40 = 24,
+	RATE_MCS_5_40 = 25,
+	RATE_MCS_6_40 = 26,
+	RATE_MCS_7_40 = 27,
+};
+
+struct wmi_bit_rate_reply {
+	/* see, enum wmi_bit_rate */
+	s8 rate_index;
+} __packed;
+
+/*
+ * WMI_SET_FIXRATES_CMDID
+ *
+ * Get fix rates cmd uses same definition as set fix rates cmd
+ */
+struct wmi_fix_rates_reply {
+	/* see wmi_bit_rate */
+	__le32 fix_rate_mask;
+} __packed;
+
+enum roam_data_type {
+	/* get the roam time data */
+	ROAM_DATA_TIME = 1,
+};
+
+struct wmi_target_roam_time {
+	__le32 disassoc_time;
+	__le32 no_txrx_time;
+	__le32 assoc_time;
+	__le32 allow_txrx_time;
+	u8 disassoc_bssid[ETH_ALEN];
+	s8 disassoc_bss_rssi;
+	u8 assoc_bssid[ETH_ALEN];
+	s8 assoc_bss_rssi;
+} __packed;
+
+enum wmi_txop_cfg {
+	WMI_TXOP_DISABLED = 0,
+	WMI_TXOP_ENABLED
+};
+
+struct wmi_set_wmm_txop_cmd {
+	u8 txop_enable;
+} __packed;
+
+struct wmi_set_keepalive_cmd {
+	u8 keep_alive_intvl;
+} __packed;
+
+struct wmi_get_keepalive_cmd {
+	__le32 configured;
+	u8 keep_alive_intvl;
+} __packed;
+
+/* Notify the WSC registration status to the target */
+#define WSC_REG_ACTIVE     1
+#define WSC_REG_INACTIVE   0
+
+#define WOW_MAX_FILTER_LISTS	 1
+#define WOW_MAX_FILTERS_PER_LIST 4
+#define WOW_PATTERN_SIZE	 64
+#define WOW_MASK_SIZE		 64
+
+#define MAC_MAX_FILTERS_PER_LIST 4
+
+struct wow_filter {
+	u8 wow_valid_filter;
+	u8 wow_filter_id;
+	u8 wow_filter_size;
+	u8 wow_filter_offset;
+	u8 wow_filter_mask[WOW_MASK_SIZE];
+	u8 wow_filter_pattern[WOW_PATTERN_SIZE];
+} __packed;
+
+#define MAX_IP_ADDRS  2
+
+struct wmi_set_ip_cmd {
+	/* IP in network byte order */
+	__le32 ips[MAX_IP_ADDRS];
+} __packed;
+
+/* WMI_GET_WOW_LIST_CMD reply  */
+struct wmi_get_wow_list_reply {
+	/* number of patterns in reply */
+	u8 num_filters;
+
+	/* this is filter # x of total num_filters */
+	u8 this_filter_num;
+
+	u8 wow_mode;
+	u8 host_mode;
+	struct wow_filter wow_filters[1];
+} __packed;
+
+/* WMI_SET_AKMP_PARAMS_CMD */
+
+struct wmi_pmkid {
+	u8 pmkid[WMI_PMKID_LEN];
+} __packed;
+
+/* WMI_GET_PMKID_LIST_CMD  Reply */
+struct wmi_pmkid_list_reply {
+	__le32 num_pmkid;
+	u8 bssid_list[ETH_ALEN][1];
+	struct wmi_pmkid pmkid_list[1];
+} __packed;
+
+/* WMI_ADDBA_REQ_EVENTID */
+struct wmi_addba_req_event {
+	u8 tid;
+	u8 win_sz;
+	__le16 st_seq_no;
+
+	/* f/w response for ADDBA Req; OK (0) or failure (!=0) */
+	u8 status;
+} __packed;
+
+/* WMI_ADDBA_RESP_EVENTID */
+struct wmi_addba_resp_event {
+	u8 tid;
+
+	/* OK (0), failure (!=0) */
+	u8 status;
+
+	/* three values: not supported(0), 3839, 8k */
+	__le16 amsdu_sz;
+} __packed;
+
+/* WMI_DELBA_EVENTID
+ * f/w received a DELBA for peer and processed it.
+ * Host is notified of this
+ */
+struct wmi_delba_event {
+	u8 tid;
+	u8 is_peer_initiator;
+	__le16 reason_code;
+} __packed;
+
+#define PEER_NODE_JOIN_EVENT		0x00
+#define PEER_NODE_LEAVE_EVENT		0x01
+#define PEER_FIRST_NODE_JOIN_EVENT	0x10
+#define PEER_LAST_NODE_LEAVE_EVENT	0x11
+
+struct wmi_peer_node_event {
+	u8 event_code;
+	u8 peer_mac_addr[ETH_ALEN];
+} __packed;
+
+/* Transmit complete event data structure(s) */
+
+/* version 1 of tx complete msg */
+struct tx_complete_msg_v1 {
+#define TX_COMPLETE_STATUS_SUCCESS 0
+#define TX_COMPLETE_STATUS_RETRIES 1
+#define TX_COMPLETE_STATUS_NOLINK  2
+#define TX_COMPLETE_STATUS_TIMEOUT 3
+#define TX_COMPLETE_STATUS_OTHER   4
+
+	u8 status;
+
+	/* packet ID to identify parent packet */
+	u8 pkt_id;
+
+	/* rate index on successful transmission */
+	u8 rate_idx;
+
+	/* number of ACK failures in tx attempt */
+	u8 ack_failures;
+} __packed;
+
+struct wmi_tx_complete_event {
+	/* no of tx comp msgs following this struct */
+	u8 num_msg;
+
+	/* length in bytes for each individual msg following this struct */
+	u8 msg_len;
+
+	/* version of tx complete msg data following this struct */
+	u8 msg_type;
+
+	/* individual messages follow this header */
+	u8 reserved;
+} __packed;
+
+/*
+ * ------- AP Mode definitions --------------
+ */
+
+/*
+ * !!! Warning !!!
+ * -Changing the following values needs compilation of both driver and firmware
+ */
+#define AP_MAX_NUM_STA          8
+
+/* Spl. AID used to set DTIM flag in the beacons */
+#define MCAST_AID               0xFF
+
+#define DEF_AP_COUNTRY_CODE     "US "
+
+/* Used with WMI_AP_SET_NUM_STA_CMDID */
+
+struct wmi_ap_set_pvb_cmd {
+	__le32 flag;
+	__le16 aid;
+} __packed;
+
+struct wmi_rx_frame_format_cmd {
+	/* version of meta data for rx packets <0 = default> (0-7 = valid) */
+	u8 meta_ver;
+
+	/*
+	 * 1 == leave .11 header intact,
+	 * 0 == replace .11 header with .3 <default>
+	 */
+	u8 dot11_hdr;
+
+	/*
+	 * 1 == defragmentation is performed by host,
+	 * 0 == performed by target <default>
+	 */
+	u8 defrag_on_host;
+
+	/* for alignment */
+	u8 reserved[1];
+} __packed;
+
+/* AP mode events */
+
+/* WMI_PS_POLL_EVENT */
+struct wmi_pspoll_event {
+	__le16 aid;
+} __packed;
+
+struct wmi_per_sta_stat {
+	__le32 tx_bytes;
+	__le32 tx_pkts;
+	__le32 tx_error;
+	__le32 tx_discard;
+	__le32 rx_bytes;
+	__le32 rx_pkts;
+	__le32 rx_error;
+	__le32 rx_discard;
+	__le32 aid;
+} __packed;
+
+struct wmi_ap_mode_stat {
+	__le32 action;
+	struct wmi_per_sta_stat sta[AP_MAX_NUM_STA + 1];
+} __packed;
+
+/* End of AP mode definitions */
+
+/* Extended WMI (WMIX)
+ *
+ * Extended WMIX commands are encapsulated in a WMI message with
+ * cmd=WMI_EXTENSION_CMD.
+ *
+ * Extended WMI commands are those that are needed during wireless
+ * operation, but which are not really wireless commands.  This allows,
+ * for instance, platform-specific commands.  Extended WMI commands are
+ * embedded in a WMI command message with WMI_COMMAND_ID=WMI_EXTENSION_CMDID.
+ * Extended WMI events are similarly embedded in a WMI event message with
+ * WMI_EVENT_ID=WMI_EXTENSION_EVENTID.
+ */
+struct wmix_cmd_hdr {
+	__le32 cmd_id;
+} __packed;
+
+enum wmix_command_id {
+	WMIX_DSETOPEN_REPLY_CMDID = 0x2001,
+	WMIX_DSETDATA_REPLY_CMDID,
+	WMIX_GPIO_OUTPUT_SET_CMDID,
+	WMIX_GPIO_INPUT_GET_CMDID,
+	WMIX_GPIO_REGISTER_SET_CMDID,
+	WMIX_GPIO_REGISTER_GET_CMDID,
+	WMIX_GPIO_INTR_ACK_CMDID,
+	WMIX_HB_CHALLENGE_RESP_CMDID,
+	WMIX_DBGLOG_CFG_MODULE_CMDID,
+	WMIX_PROF_CFG_CMDID,	/* 0x200a */
+	WMIX_PROF_ADDR_SET_CMDID,
+	WMIX_PROF_START_CMDID,
+	WMIX_PROF_STOP_CMDID,
+	WMIX_PROF_COUNT_GET_CMDID,
+};
+
+enum wmix_event_id {
+	WMIX_DSETOPENREQ_EVENTID = 0x3001,
+	WMIX_DSETCLOSE_EVENTID,
+	WMIX_DSETDATAREQ_EVENTID,
+	WMIX_GPIO_INTR_EVENTID,
+	WMIX_GPIO_DATA_EVENTID,
+	WMIX_GPIO_ACK_EVENTID,
+	WMIX_HB_CHALLENGE_RESP_EVENTID,
+	WMIX_DBGLOG_EVENTID,
+	WMIX_PROF_COUNT_EVENTID,
+};
+
+/*
+ * ------Error Detection support-------
+ */
+
+/*
+ * WMIX_HB_CHALLENGE_RESP_CMDID
+ * Heartbeat Challenge Response command
+ */
+struct wmix_hb_challenge_resp_cmd {
+	__le32 cookie;
+	__le32 source;
+} __packed;
+
+/* End of Extended WMI (WMIX) */
+
+enum wmi_sync_flag {
+	NO_SYNC_WMIFLAG = 0,
+
+	/* transmit all queued data before cmd */
+	SYNC_BEFORE_WMIFLAG,
+
+	/* any new data waits until cmd execs */
+	SYNC_AFTER_WMIFLAG,
+
+	SYNC_BOTH_WMIFLAG,
+
+	/* end marker */
+	END_WMIFLAG
+};
+
+enum htc_endpoint_id ath6kl_wmi_get_control_ep(struct wmi *wmi);
+void ath6kl_wmi_set_control_ep(struct wmi *wmi, enum htc_endpoint_id ep_id);
+int ath6kl_wmi_dix_2_dot3(struct wmi *wmi, struct sk_buff *skb);
+int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb,
+			    u8 msg_type, bool more_data,
+			    enum wmi_data_hdr_data_type data_type,
+			    u8 meta_ver, void *tx_meta_info);
+
+int ath6kl_wmi_dot11_hdr_remove(struct wmi *wmi, struct sk_buff *skb);
+int ath6kl_wmi_dot3_2_dix(struct sk_buff *skb);
+int ath6kl_wmi_data_hdr_remove(struct wmi *wmi, struct sk_buff *skb);
+int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, struct sk_buff *skb,
+				       u32 layer2_priority, bool wmm_enabled,
+				       u8 *ac);
+
+int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb);
+struct bss *ath6kl_wmi_find_node(struct wmi *wmi, const u8 *mac_addr);
+void ath6kl_wmi_node_free(struct wmi *wmi, const u8 *mac_addr);
+
+int ath6kl_wmi_cmd_send(struct wmi *wmi, struct sk_buff *skb,
+			enum wmi_cmd_id cmd_id, enum wmi_sync_flag sync_flag);
+
+int ath6kl_wmi_connect_cmd(struct wmi *wmi, enum network_type nw_type,
+			   enum dot11_auth_mode dot11_auth_mode,
+			   enum auth_mode auth_mode,
+			   enum crypto_type pairwise_crypto,
+			   u8 pairwise_crypto_len,
+			   enum crypto_type group_crypto,
+			   u8 group_crypto_len, int ssid_len, u8 *ssid,
+			   u8 *bssid, u16 channel, u32 ctrl_flags);
+
+int ath6kl_wmi_reconnect_cmd(struct wmi *wmi, u8 *bssid, u16 channel);
+int ath6kl_wmi_disconnect_cmd(struct wmi *wmi);
+int ath6kl_wmi_startscan_cmd(struct wmi *wmi, enum wmi_scan_type scan_type,
+			     u32 force_fgscan, u32 is_legacy,
+			     u32 home_dwell_time, u32 force_scan_interval,
+			     s8 num_chan, u16 *ch_list);
+int ath6kl_wmi_scanparams_cmd(struct wmi *wmi, u16 fg_start_sec,
+			      u16 fg_end_sec, u16 bg_sec,
+			      u16 minact_chdw_msec, u16 maxact_chdw_msec,
+			      u16 pas_chdw_msec, u8 short_scan_ratio,
+			      u8 scan_ctrl_flag, u32 max_dfsch_act_time,
+			      u16 maxact_scan_per_ssid);
+int ath6kl_wmi_bssfilter_cmd(struct wmi *wmi, u8 filter, u32 ie_mask);
+int ath6kl_wmi_probedssid_cmd(struct wmi *wmi, u8 index, u8 flag,
+			      u8 ssid_len, u8 *ssid);
+int ath6kl_wmi_listeninterval_cmd(struct wmi *wmi, u16 listen_interval,
+				  u16 listen_beacons);
+int ath6kl_wmi_powermode_cmd(struct wmi *wmi, u8 pwr_mode);
+int ath6kl_wmi_pmparams_cmd(struct wmi *wmi, u16 idle_period,
+			    u16 ps_poll_num, u16 dtim_policy,
+			    u16 tx_wakup_policy, u16 num_tx_to_wakeup,
+			    u16 ps_fail_event_policy);
+int ath6kl_wmi_disctimeout_cmd(struct wmi *wmi, u8 timeout);
+int ath6kl_wmi_create_pstream_cmd(struct wmi *wmi,
+				  struct wmi_create_pstream_cmd *pstream);
+int ath6kl_wmi_delete_pstream_cmd(struct wmi *wmi, u8 traffic_class, u8 tsid);
+
+int ath6kl_wmi_set_rts_cmd(struct wmi *wmi, u16 threshold);
+int ath6kl_wmi_set_lpreamble_cmd(struct wmi *wmi, u8 status,
+				 u8 preamble_policy);
+
+int ath6kl_wmi_get_challenge_resp_cmd(struct wmi *wmi, u32 cookie, u32 source);
+
+int ath6kl_wmi_get_stats_cmd(struct wmi *wmi);
+int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 key_index,
+			  enum crypto_type key_type,
+			  u8 key_usage, u8 key_len,
+			  u8 *key_rsc, u8 *key_material,
+			  u8 key_op_ctrl, u8 *mac_addr,
+			  enum wmi_sync_flag sync_flag);
+int ath6kl_wmi_add_krk_cmd(struct wmi *wmi, u8 *krk);
+int ath6kl_wmi_deletekey_cmd(struct wmi *wmi, u8 key_index);
+int ath6kl_wmi_setpmkid_cmd(struct wmi *wmi, const u8 *bssid,
+			    const u8 *pmkid, bool set);
+int ath6kl_wmi_set_tx_pwr_cmd(struct wmi *wmi, u8 dbM);
+int ath6kl_wmi_get_tx_pwr_cmd(struct wmi *wmi);
+
+int ath6kl_wmi_set_wmm_txop(struct wmi *wmi, enum wmi_txop_cfg cfg);
+int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 keep_alive_intvl);
+
+s32 ath6kl_wmi_get_rate(s8 rate_index);
+
+int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd);
+
+struct bss *ath6kl_wmi_find_ssid_node(struct wmi *wmi, u8 *ssid,
+				      u32 ssid_len, bool is_wpa2,
+				      bool match_ssid);
+
+void ath6kl_wmi_node_return(struct wmi *wmi, struct bss *bss);
+
+/* AP mode */
+int ath6kl_wmi_set_pvb_cmd(struct wmi *wmi, u16 aid, bool flag);
+
+int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 rx_meta_version,
+				       bool rx_dot11_hdr, bool defrag_on_host);
+
+void *ath6kl_wmi_init(struct ath6kl *devt);
+void ath6kl_wmi_shutdown(struct wmi *wmi);
+
+#endif /* WMI_H */
diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c
index 0b36fcf8a280..85a54cd2b083 100644
--- a/drivers/net/wireless/ath/ath9k/ahb.c
+++ b/drivers/net/wireless/ath/ath9k/ahb.c
@@ -133,7 +133,7 @@ static int ath_ahb_probe(struct platform_device *pdev)
 		goto err_free_hw;
 	}
 
-	ret = ath9k_init_device(id->driver_data, sc, 0x0, &ath_ahb_bus_ops);
+	ret = ath9k_init_device(id->driver_data, sc, &ath_ahb_bus_ops);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to initialize device\n");
 		goto err_irq;
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
index 2339728a7306..a0aadaddd071 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
@@ -835,108 +835,108 @@ static const u32 ar9300_2p2_baseband_core[][2] = {
 
 static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][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},
+	{0x0000a2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+	{0x0000a2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+	{0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
 	{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
-	{0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
-	{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
-	{0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
-	{0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004},
-	{0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200},
-	{0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202},
-	{0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400},
-	{0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402},
-	{0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404},
-	{0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603},
-	{0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02},
-	{0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04},
-	{0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20},
-	{0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20},
-	{0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22},
-	{0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24},
-	{0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640},
-	{0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660},
-	{0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861},
-	{0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81},
-	{0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83},
-	{0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84},
-	{0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3},
-	{0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5},
-	{0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9},
-	{0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb},
-	{0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
-	{0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
-	{0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
-	{0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
-	{0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
-	{0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
-	{0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
-	{0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000},
-	{0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002},
-	{0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004},
-	{0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200},
-	{0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202},
-	{0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400},
-	{0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402},
-	{0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404},
-	{0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603},
-	{0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02},
-	{0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04},
-	{0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20},
-	{0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20},
-	{0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22},
-	{0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24},
-	{0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640},
-	{0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660},
-	{0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861},
-	{0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81},
-	{0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83},
-	{0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84},
-	{0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3},
-	{0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5},
-	{0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9},
-	{0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb},
-	{0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
-	{0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
-	{0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
-	{0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
-	{0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
-	{0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
-	{0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{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, 0x21002220, 0x21002220, 0x16000402, 0x16000402},
+	{0x0000a51c, 0x27002223, 0x27002223, 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, 0x52022470, 0x52022470, 0x3f001861, 0x3f001861},
+	{0x0000a548, 0x55022490, 0x55022490, 0x43001a81, 0x43001a81},
+	{0x0000a54c, 0x59022492, 0x59022492, 0x47001a83, 0x47001a83},
+	{0x0000a550, 0x5d022692, 0x5d022692, 0x4a001c84, 0x4a001c84},
+	{0x0000a554, 0x61022892, 0x61022892, 0x4e001ce3, 0x4e001ce3},
+	{0x0000a558, 0x65024890, 0x65024890, 0x52001ce5, 0x52001ce5},
+	{0x0000a55c, 0x69024892, 0x69024892, 0x56001ce9, 0x56001ce9},
+	{0x0000a560, 0x6e024c92, 0x6e024c92, 0x5a001ceb, 0x5a001ceb},
+	{0x0000a564, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+	{0x0000a568, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+	{0x0000a56c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+	{0x0000a570, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+	{0x0000a574, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+	{0x0000a578, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+	{0x0000a57c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+	{0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+	{0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
+	{0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
+	{0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
+	{0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202},
+	{0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400},
+	{0x0000a598, 0x21802220, 0x21802220, 0x16800402, 0x16800402},
+	{0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404},
+	{0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603},
+	{0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02},
+	{0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04},
+	{0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20},
+	{0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20},
+	{0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22},
+	{0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24},
+	{0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640},
+	{0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660},
+	{0x0000a5c4, 0x52822470, 0x52822470, 0x3f801861, 0x3f801861},
+	{0x0000a5c8, 0x55822490, 0x55822490, 0x43801a81, 0x43801a81},
+	{0x0000a5cc, 0x59822492, 0x59822492, 0x47801a83, 0x47801a83},
+	{0x0000a5d0, 0x5d822692, 0x5d822692, 0x4a801c84, 0x4a801c84},
+	{0x0000a5d4, 0x61822892, 0x61822892, 0x4e801ce3, 0x4e801ce3},
+	{0x0000a5d8, 0x65824890, 0x65824890, 0x52801ce5, 0x52801ce5},
+	{0x0000a5dc, 0x69824892, 0x69824892, 0x56801ce9, 0x56801ce9},
+	{0x0000a5e0, 0x6e824c92, 0x6e824c92, 0x5a801ceb, 0x5a801ceb},
+	{0x0000a5e4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+	{0x0000a5e8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+	{0x0000a5ec, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f0, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+	{0x0000a5fc, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
 	{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, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
-	{0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
-	{0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+	{0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a614, 0x02004000, 0x02004000, 0x01404000, 0x01404000},
+	{0x0000a618, 0x02004801, 0x02004801, 0x01404501, 0x01404501},
+	{0x0000a61c, 0x02808a02, 0x02808a02, 0x02008501, 0x02008501},
+	{0x0000a620, 0x0380ce03, 0x0380ce03, 0x0280ca03, 0x0280ca03},
+	{0x0000a624, 0x04411104, 0x04411104, 0x03010c04, 0x03010c04},
+	{0x0000a628, 0x04411104, 0x04411104, 0x04014c04, 0x04014c04},
+	{0x0000a62c, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+	{0x0000a630, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+	{0x0000a634, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+	{0x0000a638, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+	{0x0000a63c, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+	{0x0000b2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+	{0x0000b2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+	{0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
 	{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
-	{0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
-	{0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
-	{0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+	{0x0000c2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+	{0x0000c2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+	{0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
 	{0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
-	{0x00016044, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
-	{0x00016048, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
-	{0x00016068, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
-	{0x00016444, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
-	{0x00016448, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
-	{0x00016468, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
-	{0x00016844, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
-	{0x00016848, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
-	{0x00016868, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
+	{0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+	{0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
+	{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+	{0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+	{0x00016448, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
+	{0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+	{0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+	{0x00016848, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
+	{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
 };
 
 static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = {
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
index c34bef1bf2b0..cb8bcc4e6091 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
@@ -3418,6 +3418,133 @@ static bool ath9k_hw_ar9300_fill_eeprom(struct ath_hw *ah)
 	return true;
 }
 
+#if defined(CONFIG_ATH9K_DEBUGFS) || defined(CONFIG_ATH9K_HTC_DEBUGFS)
+static u32 ar9003_dump_modal_eeprom(char *buf, u32 len, u32 size,
+				    struct ar9300_modal_eep_header *modal_hdr)
+{
+	PR_EEP("Chain0 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[0]));
+	PR_EEP("Chain1 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[1]));
+	PR_EEP("Chain2 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[2]));
+	PR_EEP("Ant. Common Control", le32_to_cpu(modal_hdr->antCtrlCommon));
+	PR_EEP("Ant. Common Control2", le32_to_cpu(modal_hdr->antCtrlCommon2));
+	PR_EEP("Ant. Gain", modal_hdr->antennaGain);
+	PR_EEP("Switch Settle", modal_hdr->switchSettling);
+	PR_EEP("Chain0 xatten1DB", modal_hdr->xatten1DB[0]);
+	PR_EEP("Chain1 xatten1DB", modal_hdr->xatten1DB[1]);
+	PR_EEP("Chain2 xatten1DB", modal_hdr->xatten1DB[2]);
+	PR_EEP("Chain0 xatten1Margin", modal_hdr->xatten1Margin[0]);
+	PR_EEP("Chain1 xatten1Margin", modal_hdr->xatten1Margin[1]);
+	PR_EEP("Chain2 xatten1Margin", modal_hdr->xatten1Margin[2]);
+	PR_EEP("Temp Slope", modal_hdr->tempSlope);
+	PR_EEP("Volt Slope", modal_hdr->voltSlope);
+	PR_EEP("spur Channels0", modal_hdr->spurChans[0]);
+	PR_EEP("spur Channels1", modal_hdr->spurChans[1]);
+	PR_EEP("spur Channels2", modal_hdr->spurChans[2]);
+	PR_EEP("spur Channels3", modal_hdr->spurChans[3]);
+	PR_EEP("spur Channels4", modal_hdr->spurChans[4]);
+	PR_EEP("Chain0 NF Threshold", modal_hdr->noiseFloorThreshCh[0]);
+	PR_EEP("Chain1 NF Threshold", modal_hdr->noiseFloorThreshCh[1]);
+	PR_EEP("Chain2 NF Threshold", modal_hdr->noiseFloorThreshCh[2]);
+	PR_EEP("xPA Bias Level", modal_hdr->xpaBiasLvl);
+	PR_EEP("txFrameToDataStart", modal_hdr->txFrameToDataStart);
+	PR_EEP("txFrameToPaOn", modal_hdr->txFrameToPaOn);
+	PR_EEP("txFrameToXpaOn", modal_hdr->txFrameToXpaOn);
+	PR_EEP("txClip", modal_hdr->txClip);
+	PR_EEP("ADC Desired size", modal_hdr->adcDesiredSize);
+	PR_EEP("Chain0 ob", modal_hdr->ob[0]);
+	PR_EEP("Chain1 ob", modal_hdr->ob[1]);
+	PR_EEP("Chain2 ob", modal_hdr->ob[2]);
+
+	PR_EEP("Chain0 db_stage2", modal_hdr->db_stage2[0]);
+	PR_EEP("Chain1 db_stage2", modal_hdr->db_stage2[1]);
+	PR_EEP("Chain2 db_stage2", modal_hdr->db_stage2[2]);
+	PR_EEP("Chain0 db_stage3", modal_hdr->db_stage3[0]);
+	PR_EEP("Chain1 db_stage3", modal_hdr->db_stage3[1]);
+	PR_EEP("Chain2 db_stage3", modal_hdr->db_stage3[2]);
+	PR_EEP("Chain0 db_stage4", modal_hdr->db_stage4[0]);
+	PR_EEP("Chain1 db_stage4", modal_hdr->db_stage4[1]);
+	PR_EEP("Chain2 db_stage4", modal_hdr->db_stage4[2]);
+
+	return len;
+}
+
+static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
+				       u8 *buf, u32 len, u32 size)
+{
+	struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+	struct ar9300_base_eep_hdr *pBase;
+
+	if (!dump_base_hdr) {
+		len += snprintf(buf + len, size - len,
+				"%20s :\n", "2GHz modal Header");
+		len += ar9003_dump_modal_eeprom(buf, len, size,
+						&eep->modalHeader2G);
+		len += snprintf(buf + len, size - len,
+				"%20s :\n", "5GHz modal Header");
+		len += ar9003_dump_modal_eeprom(buf, len, size,
+						&eep->modalHeader5G);
+		goto out;
+	}
+
+	pBase = &eep->baseEepHeader;
+
+	PR_EEP("EEPROM Version", ah->eeprom.ar9300_eep.eepromVersion);
+	PR_EEP("RegDomain1", le16_to_cpu(pBase->regDmn[0]));
+	PR_EEP("RegDomain2", le16_to_cpu(pBase->regDmn[1]));
+	PR_EEP("TX Mask", (pBase->txrxMask >> 4));
+	PR_EEP("RX Mask", (pBase->txrxMask & 0x0f));
+	PR_EEP("Allow 5GHz", !!(pBase->opCapFlags.opFlags &
+				AR5416_OPFLAGS_11A));
+	PR_EEP("Allow 2GHz", !!(pBase->opCapFlags.opFlags &
+				AR5416_OPFLAGS_11G));
+	PR_EEP("Disable 2GHz HT20", !!(pBase->opCapFlags.opFlags &
+					AR5416_OPFLAGS_N_2G_HT20));
+	PR_EEP("Disable 2GHz HT40", !!(pBase->opCapFlags.opFlags &
+					AR5416_OPFLAGS_N_2G_HT40));
+	PR_EEP("Disable 5Ghz HT20", !!(pBase->opCapFlags.opFlags &
+					AR5416_OPFLAGS_N_5G_HT20));
+	PR_EEP("Disable 5Ghz HT40", !!(pBase->opCapFlags.opFlags &
+					AR5416_OPFLAGS_N_5G_HT40));
+	PR_EEP("Big Endian", !!(pBase->opCapFlags.eepMisc & 0x01));
+	PR_EEP("RF Silent", pBase->rfSilent);
+	PR_EEP("BT option", pBase->blueToothOptions);
+	PR_EEP("Device Cap", pBase->deviceCap);
+	PR_EEP("Device Type", pBase->deviceType);
+	PR_EEP("Power Table Offset", pBase->pwrTableOffset);
+	PR_EEP("Tuning Caps1", pBase->params_for_tuning_caps[0]);
+	PR_EEP("Tuning Caps2", pBase->params_for_tuning_caps[1]);
+	PR_EEP("Enable Tx Temp Comp", !!(pBase->featureEnable & BIT(0)));
+	PR_EEP("Enable Tx Volt Comp", !!(pBase->featureEnable & BIT(1)));
+	PR_EEP("Enable fast clock", !!(pBase->featureEnable & BIT(2)));
+	PR_EEP("Enable doubling", !!(pBase->featureEnable & BIT(3)));
+	PR_EEP("Internal regulator", !!(pBase->featureEnable & BIT(4)));
+	PR_EEP("Enable Paprd", !!(pBase->featureEnable & BIT(5)));
+	PR_EEP("Driver Strength", !!(pBase->miscConfiguration & BIT(0)));
+	PR_EEP("Chain mask Reduce", (pBase->miscConfiguration >> 0x3) & 0x1);
+	PR_EEP("Write enable Gpio", pBase->eepromWriteEnableGpio);
+	PR_EEP("WLAN Disable Gpio", pBase->wlanDisableGpio);
+	PR_EEP("WLAN LED Gpio", pBase->wlanLedGpio);
+	PR_EEP("Rx Band Select Gpio", pBase->rxBandSelectGpio);
+	PR_EEP("Tx Gain", pBase->txrxgain >> 4);
+	PR_EEP("Rx Gain", pBase->txrxgain & 0xf);
+	PR_EEP("SW Reg", le32_to_cpu(pBase->swreg));
+
+	len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress",
+			ah->eeprom.ar9300_eep.macAddr);
+out:
+	if (len > size)
+		len = size;
+
+	return len;
+}
+#else
+static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
+				       u8 *buf, u32 len, u32 size)
+{
+	return 0;
+}
+#endif
+
 /* XXX: review hardware docs */
 static int ath9k_hw_ar9300_get_eeprom_ver(struct ath_hw *ah)
 {
@@ -4061,7 +4188,7 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray)
         /* Write the power for duplicated frames - HT40 */
 
         /* dup40_cck (LSB), dup40_ofdm, ext20_cck, ext20_ofdm (MSB) */
-	REG_WRITE(ah, 0xa3e0,
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE(8),
 		  POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 24) |
 		  POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 16) |
 		  POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24],  8) |
@@ -4922,25 +5049,7 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
 			"TPC[%02d] 0x%08x\n", i, targetPowerValT2[i]);
 	}
 
-	/*
-	 * This is the TX power we send back to driver core,
-	 * and it can use to pass to userspace to display our
-	 * currently configured TX power setting.
-	 *
-	 * Since power is rate dependent, use one of the indices
-	 * from the AR9300_Rates enum to select an entry from
-	 * targetPowerValT2[] to report. Currently returns the
-	 * power for HT40 MCS 0, HT20 MCS 0, or OFDM 6 Mbps
-	 * as CCK power is less interesting (?).
-	 */
-	i = ALL_TARGET_LEGACY_6_24; /* legacy */
-	if (IS_CHAN_HT40(chan))
-		i = ALL_TARGET_HT40_0_8_16; /* ht40 */
-	else if (IS_CHAN_HT20(chan))
-		i = ALL_TARGET_HT20_0_8_16; /* ht20 */
-
-	ah->txpower_limit = targetPowerValT2[i];
-	regulatory->max_power_level = targetPowerValT2[i];
+	ah->txpower_limit = regulatory->max_power_level;
 
 	/* Write target power array to registers */
 	ar9003_hw_tx_power_regwrite(ah, targetPowerValT2);
@@ -5015,6 +5124,7 @@ const struct eeprom_ops eep_ar9300_ops = {
 	.check_eeprom = ath9k_hw_ar9300_check_eeprom,
 	.get_eeprom = ath9k_hw_ar9300_get_eeprom,
 	.fill_eeprom = ath9k_hw_ar9300_fill_eeprom,
+	.dump_eeprom = ath9k_hw_ar9003_dump_eeprom,
 	.get_eeprom_ver = ath9k_hw_ar9300_get_eeprom_ver,
 	.get_eeprom_rev = ath9k_hw_ar9300_get_eeprom_rev,
 	.set_board_values = ath9k_hw_ar9300_set_board_values,
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
index 8ff0b88a29b9..1aadc4757e67 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
@@ -531,17 +531,18 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs,
 
 	/* TODO: byte swap on big endian for ar9300_10 */
 
-	if ((rxsp->status11 & AR_RxDone) == 0)
-		return -EINPROGRESS;
+	if (!rxs) {
+		if ((rxsp->status11 & AR_RxDone) == 0)
+			return -EINPROGRESS;
 
-	if (MS(rxsp->ds_info, AR_DescId) != 0x168c)
-		return -EINVAL;
+		if (MS(rxsp->ds_info, AR_DescId) != 0x168c)
+			return -EINVAL;
 
-	if ((rxsp->ds_info & (AR_TxRxDesc | AR_CtrlStat)) != 0)
-		return -EINPROGRESS;
+		if ((rxsp->ds_info & (AR_TxRxDesc | AR_CtrlStat)) != 0)
+			return -EINPROGRESS;
 
-	if (!rxs)
 		return 0;
+	}
 
 	rxs->rs_status = 0;
 	rxs->rs_flags =  0;
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index 1baca8e4715d..a0aaa6855486 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -370,7 +370,7 @@ static void ar9003_hw_spur_ofdm_work(struct ath_hw *ah,
 			else
 				spur_subchannel_sd = 0;
 
-			spur_freq_sd = ((freq_offset + 10) << 9) / 11;
+			spur_freq_sd = (freq_offset << 9) / 11;
 
 		} else {
 			if (REG_READ_FIELD(ah, AR_PHY_GEN_CTRL,
@@ -379,7 +379,7 @@ static void ar9003_hw_spur_ofdm_work(struct ath_hw *ah,
 			else
 				spur_subchannel_sd = 1;
 
-			spur_freq_sd = ((freq_offset - 10) << 9) / 11;
+			spur_freq_sd = (freq_offset << 9) / 11;
 
 		}
 
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 46393f90f16c..c03949eb37c8 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -217,7 +217,6 @@ struct ath_buf_state {
 	u8 bf_type;
 	u8 bfs_paprd;
 	unsigned long bfs_paprd_timestamp;
-	enum ath9k_internal_frame_type bfs_ftype;
 };
 
 struct ath_buf {
@@ -273,8 +272,6 @@ struct ath_node {
 struct ath_tx_control {
 	struct ath_txq *txq;
 	struct ath_node *an;
-	int if_id;
-	enum ath9k_internal_frame_type frame_type;
 	u8 paprd;
 };
 
@@ -570,7 +567,6 @@ struct ath_ant_comb {
 #define PS_WAIT_FOR_PSPOLL_DATA   BIT(2)
 #define PS_WAIT_FOR_TX_ACK        BIT(3)
 #define PS_BEACON_SYNC            BIT(4)
-#define PS_TSFOOR_SYNC            BIT(5)
 
 struct ath_rate_table;
 
@@ -669,7 +665,7 @@ extern bool is_ath9k_unloaded;
 
 irqreturn_t ath_isr(int irq, void *dev);
 void ath9k_init_crypto(struct ath_softc *sc);
-int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
+int ath9k_init_device(u16 devid, struct ath_softc *sc,
 		    const struct ath_bus_ops *bus_ops);
 void ath9k_deinit_device(struct ath_softc *sc);
 void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw);
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 0d13ff74a68b..086c9c816bf7 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -522,6 +522,7 @@ static void ath_beacon_config_ap(struct ath_softc *sc,
 	ath9k_beacon_init(sc, nexttbtt, intval);
 	sc->beacon.bmisscnt = 0;
 	ath9k_hw_set_interrupts(ah, ah->imask);
+	ath9k_hw_enable_interrupts(ah);
 }
 
 /*
@@ -648,12 +649,8 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
 	ath9k_hw_set_sta_beacon_timers(ah, &bs);
 	ah->imask |= ATH9K_INT_BMISS;
 
-	/*
-	 * If the beacon config is called beacause of TSFOOR,
-	 * Interrupts will be enabled back at the end of ath9k_tasklet
-	 */
-	if (!(sc->ps_flags & PS_TSFOOR_SYNC))
-		ath9k_hw_set_interrupts(ah, ah->imask);
+	ath9k_hw_set_interrupts(ah, ah->imask);
+	ath9k_hw_enable_interrupts(ah);
 }
 
 static void ath_beacon_config_adhoc(struct ath_softc *sc,
@@ -687,12 +684,9 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
 	ath9k_hw_disable_interrupts(ah);
 	ath9k_beacon_init(sc, nexttbtt, intval);
 	sc->beacon.bmisscnt = 0;
-	/*
-	 * If the beacon config is called beacause of TSFOOR,
-	 * Interrupts will be enabled back at the end of ath9k_tasklet
-	 */
-	if (!(sc->ps_flags & PS_TSFOOR_SYNC))
-		ath9k_hw_set_interrupts(ah, ah->imask);
+
+	ath9k_hw_set_interrupts(ah, ah->imask);
+	ath9k_hw_enable_interrupts(ah);
 }
 
 static bool ath9k_allow_beacon_config(struct ath_softc *sc,
diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c
index a1250c586e40..ac2da3cce788 100644
--- a/drivers/net/wireless/ath/ath9k/calib.c
+++ b/drivers/net/wireless/ath/ath9k/calib.c
@@ -63,6 +63,19 @@ static s16 ath9k_hw_get_default_nf(struct ath_hw *ah,
 	return ath9k_hw_get_nf_limits(ah, chan)->nominal;
 }
 
+s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+	s8 noise = ATH_DEFAULT_NOISE_FLOOR;
+
+	if (chan && chan->noisefloor) {
+		s8 delta = chan->noisefloor -
+			   ath9k_hw_get_default_nf(ah, chan);
+		if (delta > 0)
+			noise += delta;
+	}
+	return noise;
+}
+EXPORT_SYMBOL(ath9k_hw_getchan_noise);
 
 static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah,
 					      struct ath9k_hw_cal_data *cal,
@@ -378,6 +391,7 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)
 
 	if (!caldata) {
 		chan->noisefloor = nf;
+		ah->noise = ath9k_hw_getchan_noise(ah, chan);
 		return false;
 	}
 
@@ -385,6 +399,7 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)
 	caldata->nfcal_pending = false;
 	ath9k_hw_update_nfcal_hist_buffer(ah, caldata, nfarray);
 	chan->noisefloor = h[0].privNF;
+	ah->noise = ath9k_hw_getchan_noise(ah, chan);
 	return true;
 }
 
diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h
index 1bef41d1b1ff..05b9dbf81850 100644
--- a/drivers/net/wireless/ath/ath9k/calib.h
+++ b/drivers/net/wireless/ath/ath9k/calib.h
@@ -108,6 +108,7 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
 void ath9k_hw_bstuck_nfcal(struct ath_hw *ah);
 void ath9k_hw_reset_calibration(struct ath_hw *ah,
 				struct ath9k_cal_list *currCal);
+s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan);
 
 
 #endif /* CALIB_H */
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index d1eb89611ff7..9bec3b89fb68 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -1163,6 +1163,62 @@ static const struct file_operations fops_regdump = {
 	.llseek = default_llseek,/* read accesses f_pos */
 };
 
+static ssize_t read_file_base_eeprom(struct file *file, char __user *user_buf,
+				     size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	struct ath_hw *ah = sc->sc_ah;
+	u32 len = 0, size = 1500;
+	ssize_t retval = 0;
+	char *buf;
+
+	buf = kzalloc(size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	len = ah->eep_ops->dump_eeprom(ah, true, buf, len, size);
+
+	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+	kfree(buf);
+
+	return retval;
+}
+
+static const struct file_operations fops_base_eeprom = {
+	.read = read_file_base_eeprom,
+	.open = ath9k_debugfs_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+static ssize_t read_file_modal_eeprom(struct file *file, char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	struct ath_hw *ah = sc->sc_ah;
+	u32 len = 0, size = 6000;
+	char *buf;
+	size_t retval;
+
+	buf = kzalloc(size, GFP_KERNEL);
+	if (buf == NULL)
+		return -ENOMEM;
+
+	len = ah->eep_ops->dump_eeprom(ah, false, buf, len, size);
+
+	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+	kfree(buf);
+
+	return retval;
+}
+
+static const struct file_operations fops_modal_eeprom = {
+	.read = read_file_modal_eeprom,
+	.open = ath9k_debugfs_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
 int ath9k_init_debug(struct ath_hw *ah)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
@@ -1206,6 +1262,10 @@ int ath9k_init_debug(struct ath_hw *ah)
 			    &ah->config.cwm_ignore_extcca);
 	debugfs_create_file("regdump", S_IRUSR, sc->debug.debugfs_phy, sc,
 			    &fops_regdump);
+	debugfs_create_file("base_eeprom", S_IRUSR, sc->debug.debugfs_phy, sc,
+			    &fops_base_eeprom);
+	debugfs_create_file("modal_eeprom", S_IRUSR, sc->debug.debugfs_phy, sc,
+			    &fops_modal_eeprom);
 
 	debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR,
 			   sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask);
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h
index de99c0da52e4..a3c7d0c247a3 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/eeprom.h
@@ -649,6 +649,8 @@ struct eeprom_ops {
 	int (*check_eeprom)(struct ath_hw *hw);
 	u32 (*get_eeprom)(struct ath_hw *hw, enum eeprom_param param);
 	bool (*fill_eeprom)(struct ath_hw *hw);
+	u32 (*dump_eeprom)(struct ath_hw *hw, bool dump_base_hdr, u8 *buf,
+			   u32 len, u32 size);
 	int (*get_eeprom_ver)(struct ath_hw *hw);
 	int (*get_eeprom_rev)(struct ath_hw *hw);
 	void (*set_board_values)(struct ath_hw *hw, struct ath9k_channel *chan);
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
index 47cc95086e6e..ea658e794cbd 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
@@ -72,6 +72,117 @@ static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah)
 		return __ath9k_hw_4k_fill_eeprom(ah);
 }
 
+#if defined(CONFIG_ATH9K_DEBUGFS) || defined(CONFIG_ATH9K_HTC_DEBUGFS)
+static u32 ath9k_dump_4k_modal_eeprom(char *buf, u32 len, u32 size,
+				      struct modal_eep_4k_header *modal_hdr)
+{
+	PR_EEP("Chain0 Ant. Control", modal_hdr->antCtrlChain[0]);
+	PR_EEP("Ant. Common Control", modal_hdr->antCtrlCommon);
+	PR_EEP("Chain0 Ant. Gain", modal_hdr->antennaGainCh[0]);
+	PR_EEP("Switch Settle", modal_hdr->switchSettling);
+	PR_EEP("Chain0 TxRxAtten", modal_hdr->txRxAttenCh[0]);
+	PR_EEP("Chain0 RxTxMargin", modal_hdr->rxTxMarginCh[0]);
+	PR_EEP("ADC Desired size", modal_hdr->adcDesiredSize);
+	PR_EEP("PGA Desired size", modal_hdr->pgaDesiredSize);
+	PR_EEP("Chain0 xlna Gain", modal_hdr->xlnaGainCh[0]);
+	PR_EEP("txEndToXpaOff", modal_hdr->txEndToXpaOff);
+	PR_EEP("txEndToRxOn", modal_hdr->txEndToRxOn);
+	PR_EEP("txFrameToXpaOn", modal_hdr->txFrameToXpaOn);
+	PR_EEP("CCA Threshold)", modal_hdr->thresh62);
+	PR_EEP("Chain0 NF Threshold", modal_hdr->noiseFloorThreshCh[0]);
+	PR_EEP("xpdGain", modal_hdr->xpdGain);
+	PR_EEP("External PD", modal_hdr->xpd);
+	PR_EEP("Chain0 I Coefficient", modal_hdr->iqCalICh[0]);
+	PR_EEP("Chain0 Q Coefficient", modal_hdr->iqCalQCh[0]);
+	PR_EEP("pdGainOverlap", modal_hdr->pdGainOverlap);
+	PR_EEP("O/D Bias Version", modal_hdr->version);
+	PR_EEP("CCK OutputBias", modal_hdr->ob_0);
+	PR_EEP("BPSK OutputBias", modal_hdr->ob_1);
+	PR_EEP("QPSK OutputBias", modal_hdr->ob_2);
+	PR_EEP("16QAM OutputBias", modal_hdr->ob_3);
+	PR_EEP("64QAM OutputBias", modal_hdr->ob_4);
+	PR_EEP("CCK Driver1_Bias", modal_hdr->db1_0);
+	PR_EEP("BPSK Driver1_Bias", modal_hdr->db1_1);
+	PR_EEP("QPSK Driver1_Bias", modal_hdr->db1_2);
+	PR_EEP("16QAM Driver1_Bias", modal_hdr->db1_3);
+	PR_EEP("64QAM Driver1_Bias", modal_hdr->db1_4);
+	PR_EEP("CCK Driver2_Bias", modal_hdr->db2_0);
+	PR_EEP("BPSK Driver2_Bias", modal_hdr->db2_1);
+	PR_EEP("QPSK Driver2_Bias", modal_hdr->db2_2);
+	PR_EEP("16QAM Driver2_Bias", modal_hdr->db2_3);
+	PR_EEP("64QAM Driver2_Bias", modal_hdr->db2_4);
+	PR_EEP("xPA Bias Level", modal_hdr->xpaBiasLvl);
+	PR_EEP("txFrameToDataStart", modal_hdr->txFrameToDataStart);
+	PR_EEP("txFrameToPaOn", modal_hdr->txFrameToPaOn);
+	PR_EEP("HT40 Power Inc.", modal_hdr->ht40PowerIncForPdadc);
+	PR_EEP("Chain0 bswAtten", modal_hdr->bswAtten[0]);
+	PR_EEP("Chain0 bswMargin", modal_hdr->bswMargin[0]);
+	PR_EEP("HT40 Switch Settle", modal_hdr->swSettleHt40);
+	PR_EEP("Chain0 xatten2Db", modal_hdr->xatten2Db[0]);
+	PR_EEP("Chain0 xatten2Margin", modal_hdr->xatten2Margin[0]);
+	PR_EEP("Ant. Diversity ctl1", modal_hdr->antdiv_ctl1);
+	PR_EEP("Ant. Diversity ctl2", modal_hdr->antdiv_ctl2);
+	PR_EEP("TX Diversity", modal_hdr->tx_diversity);
+
+	return len;
+}
+
+static u32 ath9k_hw_4k_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
+				       u8 *buf, u32 len, u32 size)
+{
+	struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
+	struct base_eep_header_4k *pBase = &eep->baseEepHeader;
+
+	if (!dump_base_hdr) {
+		len += snprintf(buf + len, size - len,
+				"%20s :\n", "2GHz modal Header");
+		len += ath9k_dump_4k_modal_eeprom(buf, len, size,
+						  &eep->modalHeader);
+		goto out;
+	}
+
+	PR_EEP("Major Version", pBase->version >> 12);
+	PR_EEP("Minor Version", pBase->version & 0xFFF);
+	PR_EEP("Checksum", pBase->checksum);
+	PR_EEP("Length", pBase->length);
+	PR_EEP("RegDomain1", pBase->regDmn[0]);
+	PR_EEP("RegDomain2", pBase->regDmn[1]);
+	PR_EEP("TX Mask", pBase->txMask);
+	PR_EEP("RX Mask", pBase->rxMask);
+	PR_EEP("Allow 5GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11A));
+	PR_EEP("Allow 2GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11G));
+	PR_EEP("Disable 2GHz HT20", !!(pBase->opCapFlags &
+					AR5416_OPFLAGS_N_2G_HT20));
+	PR_EEP("Disable 2GHz HT40", !!(pBase->opCapFlags &
+					AR5416_OPFLAGS_N_2G_HT40));
+	PR_EEP("Disable 5Ghz HT20", !!(pBase->opCapFlags &
+					AR5416_OPFLAGS_N_5G_HT20));
+	PR_EEP("Disable 5Ghz HT40", !!(pBase->opCapFlags &
+					AR5416_OPFLAGS_N_5G_HT40));
+	PR_EEP("Big Endian", !!(pBase->eepMisc & 0x01));
+	PR_EEP("Cal Bin Major Ver", (pBase->binBuildNumber >> 24) & 0xFF);
+	PR_EEP("Cal Bin Minor Ver", (pBase->binBuildNumber >> 16) & 0xFF);
+	PR_EEP("Cal Bin Build", (pBase->binBuildNumber >> 8) & 0xFF);
+	PR_EEP("TX Gain type", pBase->txGainType);
+
+	len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress",
+			pBase->macAddr);
+
+out:
+	if (len > size)
+		len = size;
+
+	return len;
+}
+#else
+static u32 ath9k_hw_4k_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
+				       u8 *buf, u32 len, u32 size)
+{
+	return 0;
+}
+#endif
+
+
 #undef SIZE_EEPROM_4K
 
 static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
@@ -238,18 +349,14 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah,
 	case EEP_ANT_DIV_CTL1:
 		return pModal->antdiv_ctl1;
 	case EEP_TXGAIN_TYPE:
-		if (ver_minor >= AR5416_EEP_MINOR_VER_19)
-			return pBase->txGainType;
-		else
-			return AR5416_EEP_TXGAIN_ORIGINAL;
+		return pBase->txGainType;
 	default:
 		return 0;
 	}
 }
 
 static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
-				  struct ath9k_channel *chan,
-				  int16_t *pTxPowerIndexOffset)
+				  struct ath9k_channel *chan)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
 	struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k;
@@ -356,8 +463,6 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
 			REGWRITE_BUFFER_FLUSH(ah);
 		}
 	}
-
-	*pTxPowerIndexOffset = 0;
 }
 
 static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
@@ -580,7 +685,6 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
 	struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k;
 	struct modal_eep_4k_header *pModal = &pEepData->modalHeader;
 	int16_t ratesArray[Ar5416RateSize];
-	int16_t txPowerIndexOffset = 0;
 	u8 ht40PowerIncForPdadc = 2;
 	int i;
 
@@ -597,11 +701,10 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
 					     twiceMaxRegulatoryPower,
 					     powerLimit);
 
-	ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset);
+	ath9k_hw_set_4k_power_cal_table(ah, chan);
 
 	regulatory->max_power_level = 0;
 	for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
-		ratesArray[i] =	(int16_t)(txPowerIndexOffset + ratesArray[i]);
 		if (ratesArray[i] > MAX_RATE_POWER)
 			ratesArray[i] = MAX_RATE_POWER;
 
@@ -612,15 +715,6 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
 	if (test)
 	    return;
 
-	/* Update regulatory */
-	i = rate6mb;
-	if (IS_CHAN_HT40(chan))
-		i = rateHt40_0;
-	else if (IS_CHAN_HT20(chan))
-		i = rateHt20_0;
-
-	regulatory->max_power_level = ratesArray[i];
-
 	if (AR_SREV_9280_20_OR_LATER(ah)) {
 		for (i = 0; i < Ar5416RateSize; i++)
 			ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2;
@@ -1063,6 +1157,7 @@ const struct eeprom_ops eep_4k_ops = {
 	.check_eeprom		= ath9k_hw_4k_check_eeprom,
 	.get_eeprom		= ath9k_hw_4k_get_eeprom,
 	.fill_eeprom		= ath9k_hw_4k_fill_eeprom,
+	.dump_eeprom		= ath9k_hw_4k_dump_eeprom,
 	.get_eeprom_ver		= ath9k_hw_4k_get_eeprom_ver,
 	.get_eeprom_rev		= ath9k_hw_4k_get_eeprom_rev,
 	.set_board_values	= ath9k_hw_4k_set_board_values,
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
index d6f6b192f450..21f180db2381 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
@@ -76,6 +76,111 @@ static bool ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah)
 		return __ath9k_hw_ar9287_fill_eeprom(ah);
 }
 
+#if defined(CONFIG_ATH9K_DEBUGFS) || defined(CONFIG_ATH9K_HTC_DEBUGFS)
+static u32 ar9287_dump_modal_eeprom(char *buf, u32 len, u32 size,
+				    struct modal_eep_ar9287_header *modal_hdr)
+{
+	PR_EEP("Chain0 Ant. Control", modal_hdr->antCtrlChain[0]);
+	PR_EEP("Chain1 Ant. Control", modal_hdr->antCtrlChain[1]);
+	PR_EEP("Ant. Common Control", modal_hdr->antCtrlCommon);
+	PR_EEP("Chain0 Ant. Gain", modal_hdr->antennaGainCh[0]);
+	PR_EEP("Chain1 Ant. Gain", modal_hdr->antennaGainCh[1]);
+	PR_EEP("Switch Settle", modal_hdr->switchSettling);
+	PR_EEP("Chain0 TxRxAtten", modal_hdr->txRxAttenCh[0]);
+	PR_EEP("Chain1 TxRxAtten", modal_hdr->txRxAttenCh[1]);
+	PR_EEP("Chain0 RxTxMargin", modal_hdr->rxTxMarginCh[0]);
+	PR_EEP("Chain1 RxTxMargin", modal_hdr->rxTxMarginCh[1]);
+	PR_EEP("ADC Desired size", modal_hdr->adcDesiredSize);
+	PR_EEP("txEndToXpaOff", modal_hdr->txEndToXpaOff);
+	PR_EEP("txEndToRxOn", modal_hdr->txEndToRxOn);
+	PR_EEP("txFrameToXpaOn", modal_hdr->txFrameToXpaOn);
+	PR_EEP("CCA Threshold)", modal_hdr->thresh62);
+	PR_EEP("Chain0 NF Threshold", modal_hdr->noiseFloorThreshCh[0]);
+	PR_EEP("Chain1 NF Threshold", modal_hdr->noiseFloorThreshCh[1]);
+	PR_EEP("xpdGain", modal_hdr->xpdGain);
+	PR_EEP("External PD", modal_hdr->xpd);
+	PR_EEP("Chain0 I Coefficient", modal_hdr->iqCalICh[0]);
+	PR_EEP("Chain1 I Coefficient", modal_hdr->iqCalICh[1]);
+	PR_EEP("Chain0 Q Coefficient", modal_hdr->iqCalQCh[0]);
+	PR_EEP("Chain1 Q Coefficient", modal_hdr->iqCalQCh[1]);
+	PR_EEP("pdGainOverlap", modal_hdr->pdGainOverlap);
+	PR_EEP("xPA Bias Level", modal_hdr->xpaBiasLvl);
+	PR_EEP("txFrameToDataStart", modal_hdr->txFrameToDataStart);
+	PR_EEP("txFrameToPaOn", modal_hdr->txFrameToPaOn);
+	PR_EEP("HT40 Power Inc.", modal_hdr->ht40PowerIncForPdadc);
+	PR_EEP("Chain0 bswAtten", modal_hdr->bswAtten[0]);
+	PR_EEP("Chain1 bswAtten", modal_hdr->bswAtten[1]);
+	PR_EEP("Chain0 bswMargin", modal_hdr->bswMargin[0]);
+	PR_EEP("Chain1 bswMargin", modal_hdr->bswMargin[1]);
+	PR_EEP("HT40 Switch Settle", modal_hdr->swSettleHt40);
+	PR_EEP("AR92x7 Version", modal_hdr->version);
+	PR_EEP("DriverBias1", modal_hdr->db1);
+	PR_EEP("DriverBias2", modal_hdr->db1);
+	PR_EEP("CCK OutputBias", modal_hdr->ob_cck);
+	PR_EEP("PSK OutputBias", modal_hdr->ob_psk);
+	PR_EEP("QAM OutputBias", modal_hdr->ob_qam);
+	PR_EEP("PAL_OFF OutputBias", modal_hdr->ob_pal_off);
+
+	return len;
+}
+
+static u32 ath9k_hw_ar9287_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
+				       u8 *buf, u32 len, u32 size)
+{
+	struct ar9287_eeprom *eep = &ah->eeprom.map9287;
+	struct base_eep_ar9287_header *pBase = &eep->baseEepHeader;
+
+	if (!dump_base_hdr) {
+		len += snprintf(buf + len, size - len,
+				"%20s :\n", "2GHz modal Header");
+		len += ar9287_dump_modal_eeprom(buf, len, size,
+						&eep->modalHeader);
+		goto out;
+	}
+
+	PR_EEP("Major Version", pBase->version >> 12);
+	PR_EEP("Minor Version", pBase->version & 0xFFF);
+	PR_EEP("Checksum", pBase->checksum);
+	PR_EEP("Length", pBase->length);
+	PR_EEP("RegDomain1", pBase->regDmn[0]);
+	PR_EEP("RegDomain2", pBase->regDmn[1]);
+	PR_EEP("TX Mask", pBase->txMask);
+	PR_EEP("RX Mask", pBase->rxMask);
+	PR_EEP("Allow 5GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11A));
+	PR_EEP("Allow 2GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11G));
+	PR_EEP("Disable 2GHz HT20", !!(pBase->opCapFlags &
+					AR5416_OPFLAGS_N_2G_HT20));
+	PR_EEP("Disable 2GHz HT40", !!(pBase->opCapFlags &
+					AR5416_OPFLAGS_N_2G_HT40));
+	PR_EEP("Disable 5Ghz HT20", !!(pBase->opCapFlags &
+					AR5416_OPFLAGS_N_5G_HT20));
+	PR_EEP("Disable 5Ghz HT40", !!(pBase->opCapFlags &
+					AR5416_OPFLAGS_N_5G_HT40));
+	PR_EEP("Big Endian", !!(pBase->eepMisc & 0x01));
+	PR_EEP("Cal Bin Major Ver", (pBase->binBuildNumber >> 24) & 0xFF);
+	PR_EEP("Cal Bin Minor Ver", (pBase->binBuildNumber >> 16) & 0xFF);
+	PR_EEP("Cal Bin Build", (pBase->binBuildNumber >> 8) & 0xFF);
+	PR_EEP("Power Table Offset", pBase->pwrTableOffset);
+	PR_EEP("OpenLoop Power Ctrl", pBase->openLoopPwrCntl);
+
+	len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress",
+			pBase->macAddr);
+
+out:
+	if (len > size)
+		len = size;
+
+	return len;
+}
+#else
+static u32 ath9k_hw_ar9287_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
+				       u8 *buf, u32 len, u32 size)
+{
+	return 0;
+}
+#endif
+
+
 static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah)
 {
 	u32 sum = 0, el, integer;
@@ -307,8 +412,7 @@ static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah,
 }
 
 static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah,
-						struct ath9k_channel *chan,
-						int16_t *pTxPowerIndexOffset)
+						struct ath9k_channel *chan)
 {
 	struct cal_data_per_freq_ar9287 *pRawDataset;
 	struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop;
@@ -444,8 +548,6 @@ static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah,
 			REGWRITE_BUFFER_FLUSH(ah);
 		}
 	}
-
-	*pTxPowerIndexOffset = 0;
 }
 
 static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah,
@@ -720,7 +822,6 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah,
 	struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
 	struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader;
 	int16_t ratesArray[Ar5416RateSize];
-	int16_t txPowerIndexOffset = 0;
 	u8 ht40PowerIncForPdadc = 2;
 	int i;
 
@@ -736,11 +837,10 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah,
 						 twiceMaxRegulatoryPower,
 						 powerLimit);
 
-	ath9k_hw_set_ar9287_power_cal_table(ah, chan, &txPowerIndexOffset);
+	ath9k_hw_set_ar9287_power_cal_table(ah, chan);
 
 	regulatory->max_power_level = 0;
 	for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
-		ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
 		if (ratesArray[i] > MAX_RATE_POWER)
 			ratesArray[i] = MAX_RATE_POWER;
 
@@ -751,13 +851,6 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah,
 	if (test)
 		return;
 
-	if (IS_CHAN_2GHZ(chan))
-		i = rate1l;
-	else
-		i = rate6mb;
-
-	regulatory->max_power_level = ratesArray[i];
-
 	if (AR_SREV_9280_20_OR_LATER(ah)) {
 		for (i = 0; i < Ar5416RateSize; i++)
 			ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2;
@@ -1003,6 +1096,7 @@ const struct eeprom_ops eep_ar9287_ops = {
 	.check_eeprom		= ath9k_hw_ar9287_check_eeprom,
 	.get_eeprom		= ath9k_hw_ar9287_get_eeprom,
 	.fill_eeprom		= ath9k_hw_ar9287_fill_eeprom,
+	.dump_eeprom		= ath9k_hw_ar9287_dump_eeprom,
 	.get_eeprom_ver		= ath9k_hw_ar9287_get_eeprom_ver,
 	.get_eeprom_rev		= ath9k_hw_ar9287_get_eeprom_rev,
 	.set_board_values	= ath9k_hw_ar9287_set_board_values,
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c
index b9540a992616..e7e84be8beed 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
@@ -133,6 +133,136 @@ static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah)
 
 #undef SIZE_EEPROM_DEF
 
+#if defined(CONFIG_ATH9K_DEBUGFS) || defined(CONFIG_ATH9K_HTC_DEBUGFS)
+static u32 ath9k_def_dump_modal_eeprom(char *buf, u32 len, u32 size,
+				       struct modal_eep_header *modal_hdr)
+{
+	PR_EEP("Chain0 Ant. Control", modal_hdr->antCtrlChain[0]);
+	PR_EEP("Chain1 Ant. Control", modal_hdr->antCtrlChain[1]);
+	PR_EEP("Chain2 Ant. Control", modal_hdr->antCtrlChain[2]);
+	PR_EEP("Ant. Common Control", modal_hdr->antCtrlCommon);
+	PR_EEP("Chain0 Ant. Gain", modal_hdr->antennaGainCh[0]);
+	PR_EEP("Chain1 Ant. Gain", modal_hdr->antennaGainCh[1]);
+	PR_EEP("Chain2 Ant. Gain", modal_hdr->antennaGainCh[2]);
+	PR_EEP("Switch Settle", modal_hdr->switchSettling);
+	PR_EEP("Chain0 TxRxAtten", modal_hdr->txRxAttenCh[0]);
+	PR_EEP("Chain1 TxRxAtten", modal_hdr->txRxAttenCh[1]);
+	PR_EEP("Chain2 TxRxAtten", modal_hdr->txRxAttenCh[2]);
+	PR_EEP("Chain0 RxTxMargin", modal_hdr->rxTxMarginCh[0]);
+	PR_EEP("Chain1 RxTxMargin", modal_hdr->rxTxMarginCh[1]);
+	PR_EEP("Chain2 RxTxMargin", modal_hdr->rxTxMarginCh[2]);
+	PR_EEP("ADC Desired size", modal_hdr->adcDesiredSize);
+	PR_EEP("PGA Desired size", modal_hdr->pgaDesiredSize);
+	PR_EEP("Chain0 xlna Gain", modal_hdr->xlnaGainCh[0]);
+	PR_EEP("Chain1 xlna Gain", modal_hdr->xlnaGainCh[1]);
+	PR_EEP("Chain2 xlna Gain", modal_hdr->xlnaGainCh[2]);
+	PR_EEP("txEndToXpaOff", modal_hdr->txEndToXpaOff);
+	PR_EEP("txEndToRxOn", modal_hdr->txEndToRxOn);
+	PR_EEP("txFrameToXpaOn", modal_hdr->txFrameToXpaOn);
+	PR_EEP("CCA Threshold)", modal_hdr->thresh62);
+	PR_EEP("Chain0 NF Threshold", modal_hdr->noiseFloorThreshCh[0]);
+	PR_EEP("Chain1 NF Threshold", modal_hdr->noiseFloorThreshCh[1]);
+	PR_EEP("Chain2 NF Threshold", modal_hdr->noiseFloorThreshCh[2]);
+	PR_EEP("xpdGain", modal_hdr->xpdGain);
+	PR_EEP("External PD", modal_hdr->xpd);
+	PR_EEP("Chain0 I Coefficient", modal_hdr->iqCalICh[0]);
+	PR_EEP("Chain1 I Coefficient", modal_hdr->iqCalICh[1]);
+	PR_EEP("Chain2 I Coefficient", modal_hdr->iqCalICh[2]);
+	PR_EEP("Chain0 Q Coefficient", modal_hdr->iqCalQCh[0]);
+	PR_EEP("Chain1 Q Coefficient", modal_hdr->iqCalQCh[1]);
+	PR_EEP("Chain2 Q Coefficient", modal_hdr->iqCalQCh[2]);
+	PR_EEP("pdGainOverlap", modal_hdr->pdGainOverlap);
+	PR_EEP("Chain0 OutputBias", modal_hdr->ob);
+	PR_EEP("Chain0 DriverBias", modal_hdr->db);
+	PR_EEP("xPA Bias Level", modal_hdr->xpaBiasLvl);
+	PR_EEP("2chain pwr decrease", modal_hdr->pwrDecreaseFor2Chain);
+	PR_EEP("3chain pwr decrease", modal_hdr->pwrDecreaseFor3Chain);
+	PR_EEP("txFrameToDataStart", modal_hdr->txFrameToDataStart);
+	PR_EEP("txFrameToPaOn", modal_hdr->txFrameToPaOn);
+	PR_EEP("HT40 Power Inc.", modal_hdr->ht40PowerIncForPdadc);
+	PR_EEP("Chain0 bswAtten", modal_hdr->bswAtten[0]);
+	PR_EEP("Chain1 bswAtten", modal_hdr->bswAtten[1]);
+	PR_EEP("Chain2 bswAtten", modal_hdr->bswAtten[2]);
+	PR_EEP("Chain0 bswMargin", modal_hdr->bswMargin[0]);
+	PR_EEP("Chain1 bswMargin", modal_hdr->bswMargin[1]);
+	PR_EEP("Chain2 bswMargin", modal_hdr->bswMargin[2]);
+	PR_EEP("HT40 Switch Settle", modal_hdr->swSettleHt40);
+	PR_EEP("Chain0 xatten2Db", modal_hdr->xatten2Db[0]);
+	PR_EEP("Chain1 xatten2Db", modal_hdr->xatten2Db[1]);
+	PR_EEP("Chain2 xatten2Db", modal_hdr->xatten2Db[2]);
+	PR_EEP("Chain0 xatten2Margin", modal_hdr->xatten2Margin[0]);
+	PR_EEP("Chain1 xatten2Margin", modal_hdr->xatten2Margin[1]);
+	PR_EEP("Chain2 xatten2Margin", modal_hdr->xatten2Margin[2]);
+	PR_EEP("Chain1 OutputBias", modal_hdr->ob_ch1);
+	PR_EEP("Chain1 DriverBias", modal_hdr->db_ch1);
+	PR_EEP("LNA Control", modal_hdr->lna_ctl);
+	PR_EEP("XPA Bias Freq0", modal_hdr->xpaBiasLvlFreq[0]);
+	PR_EEP("XPA Bias Freq1", modal_hdr->xpaBiasLvlFreq[1]);
+	PR_EEP("XPA Bias Freq2", modal_hdr->xpaBiasLvlFreq[2]);
+
+	return len;
+}
+
+static u32 ath9k_hw_def_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
+				    u8 *buf, u32 len, u32 size)
+{
+	struct ar5416_eeprom_def *eep = &ah->eeprom.def;
+	struct base_eep_header *pBase = &eep->baseEepHeader;
+
+	if (!dump_base_hdr) {
+		len += snprintf(buf + len, size - len,
+				"%20s :\n", "2GHz modal Header");
+		len += ath9k_def_dump_modal_eeprom(buf, len, size,
+						   &eep->modalHeader[0]);
+		len += snprintf(buf + len, size - len,
+				"%20s :\n", "5GHz modal Header");
+		len += ath9k_def_dump_modal_eeprom(buf, len, size,
+						   &eep->modalHeader[1]);
+		goto out;
+	}
+
+	PR_EEP("Major Version", pBase->version >> 12);
+	PR_EEP("Minor Version", pBase->version & 0xFFF);
+	PR_EEP("Checksum", pBase->checksum);
+	PR_EEP("Length", pBase->length);
+	PR_EEP("RegDomain1", pBase->regDmn[0]);
+	PR_EEP("RegDomain2", pBase->regDmn[1]);
+	PR_EEP("TX Mask", pBase->txMask);
+	PR_EEP("RX Mask", pBase->rxMask);
+	PR_EEP("Allow 5GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11A));
+	PR_EEP("Allow 2GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11G));
+	PR_EEP("Disable 2GHz HT20", !!(pBase->opCapFlags &
+					AR5416_OPFLAGS_N_2G_HT20));
+	PR_EEP("Disable 2GHz HT40", !!(pBase->opCapFlags &
+					AR5416_OPFLAGS_N_2G_HT40));
+	PR_EEP("Disable 5Ghz HT20", !!(pBase->opCapFlags &
+					AR5416_OPFLAGS_N_5G_HT20));
+	PR_EEP("Disable 5Ghz HT40", !!(pBase->opCapFlags &
+					AR5416_OPFLAGS_N_5G_HT40));
+	PR_EEP("Big Endian", !!(pBase->eepMisc & 0x01));
+	PR_EEP("Cal Bin Major Ver", (pBase->binBuildNumber >> 24) & 0xFF);
+	PR_EEP("Cal Bin Minor Ver", (pBase->binBuildNumber >> 16) & 0xFF);
+	PR_EEP("Cal Bin Build", (pBase->binBuildNumber >> 8) & 0xFF);
+	PR_EEP("OpenLoop Power Ctrl", pBase->openLoopPwrCntl);
+
+	len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress",
+			pBase->macAddr);
+
+out:
+	if (len > size)
+		len = size;
+
+	return len;
+}
+#else
+static u32 ath9k_hw_def_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
+				    u8 *buf, u32 len, u32 size)
+{
+	return 0;
+}
+#endif
+
+
 static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
 {
 	struct ar5416_eeprom_def *eep =
@@ -693,8 +823,7 @@ static void ath9k_adjust_pdadc_values(struct ath_hw *ah,
 }
 
 static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
-				  struct ath9k_channel *chan,
-				  int16_t *pTxPowerIndexOffset)
+				  struct ath9k_channel *chan)
 {
 #define SM_PD_GAIN(x) SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##x)
 #define SM_PDGAIN_B(x, y) \
@@ -855,7 +984,6 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
 		}
 	}
 
-	*pTxPowerIndexOffset = 0;
 #undef SM_PD_GAIN
 #undef SM_PDGAIN_B
 }
@@ -1143,7 +1271,6 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
 	struct modal_eep_header *pModal =
 		&(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]);
 	int16_t ratesArray[Ar5416RateSize];
-	int16_t txPowerIndexOffset = 0;
 	u8 ht40PowerIncForPdadc = 2;
 	int i, cck_ofdm_delta = 0;
 
@@ -1160,28 +1287,16 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
 					       twiceMaxRegulatoryPower,
 					       powerLimit);
 
-	ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset);
+	ath9k_hw_set_def_power_cal_table(ah, chan);
 
 	regulatory->max_power_level = 0;
 	for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
-		ratesArray[i] =	(int16_t)(txPowerIndexOffset + ratesArray[i]);
 		if (ratesArray[i] > MAX_RATE_POWER)
 			ratesArray[i] = MAX_RATE_POWER;
 		if (ratesArray[i] > regulatory->max_power_level)
 			regulatory->max_power_level = ratesArray[i];
 	}
 
-	if (!test) {
-		i = rate6mb;
-
-		if (IS_CHAN_HT40(chan))
-			i = rateHt40_0;
-		else if (IS_CHAN_HT20(chan))
-			i = rateHt20_0;
-
-		regulatory->max_power_level = ratesArray[i];
-	}
-
 	switch(ar5416_get_ntxchains(ah->txchainmask)) {
 	case 1:
 		break;
@@ -1336,6 +1451,7 @@ const struct eeprom_ops eep_def_ops = {
 	.check_eeprom		= ath9k_hw_def_check_eeprom,
 	.get_eeprom		= ath9k_hw_def_get_eeprom,
 	.fill_eeprom		= ath9k_hw_def_fill_eeprom,
+	.dump_eeprom		= ath9k_hw_def_dump_eeprom,
 	.get_eeprom_ver		= ath9k_hw_def_get_eeprom_ver,
 	.get_eeprom_rev		= ath9k_hw_def_get_eeprom_rev,
 	.set_board_values	= ath9k_hw_def_set_board_values,
diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c
index bc713fc28191..5113dd80c99f 100644
--- a/drivers/net/wireless/ath/ath9k/gpio.c
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
@@ -149,6 +149,7 @@ static void ath9k_gen_timer_start(struct ath_hw *ah,
 		ath9k_hw_disable_interrupts(ah);
 		ah->imask |= ATH9K_INT_GENTIMER;
 		ath9k_hw_set_interrupts(ah, ah->imask);
+		ath9k_hw_enable_interrupts(ah);
 	}
 }
 
@@ -163,6 +164,7 @@ static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
 		ath9k_hw_disable_interrupts(ah);
 		ah->imask &= ~ATH9K_INT_GENTIMER;
 		ath9k_hw_set_interrupts(ah, ah->imask);
+		ath9k_hw_enable_interrupts(ah);
 	}
 }
 
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index 5bc022087e65..da5596766d82 100644
--- a/drivers/net/wireless/ath/ath9k/htc.h
+++ b/drivers/net/wireless/ath/ath9k/htc.h
@@ -521,8 +521,6 @@ void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb,
 
 int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv,
 				u8 enable_coex);
-void ath9k_htc_station_work(struct work_struct *work);
-void ath9k_htc_aggr_work(struct work_struct *work);
 void ath9k_htc_ani_work(struct work_struct *work);
 void ath9k_htc_start_ani(struct ath9k_htc_priv *priv);
 void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv);
@@ -542,7 +540,6 @@ int ath9k_htc_tx_get_slot(struct ath9k_htc_priv *priv);
 void ath9k_htc_tx_clear_slot(struct ath9k_htc_priv *priv, int slot);
 void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv);
 void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event);
-void ath9k_htc_tx_failed(struct ath9k_htc_priv *priv);
 void ath9k_tx_failed_tasklet(unsigned long data);
 void ath9k_htc_tx_cleanup_timer(unsigned long data);
 
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index 3bea7ea86f0a..19aa5b724887 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -666,7 +666,6 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
 		return -ENOMEM;
 
 	ah->hw_version.devid = devid;
-	ah->hw_version.subsysid = 0; /* FIXME */
 	ah->hw_version.usbdev = drv_info;
 	ah->ah_flags |= AH_USE_EEPROM;
 	ah->reg_ops.read = ath9k_regread;
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 8dcefe74f4c3..db44e5b0c98b 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -1486,6 +1486,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 		memset(caldata, 0, sizeof(*caldata));
 		ath9k_init_nfcal_hist_buffer(ah, chan);
 	}
+	ah->noise = ath9k_hw_getchan_noise(ah, chan);
 
 	if (bChannelChange &&
 	    (ah->chip_fullsleep != true) &&
@@ -2439,15 +2440,18 @@ void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test)
 	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
 	struct ath9k_channel *chan = ah->curchan;
 	struct ieee80211_channel *channel = chan->chan;
+	int reg_pwr = min_t(int, MAX_RATE_POWER, regulatory->power_limit);
+	int chan_pwr = channel->max_power * 2;
+
+	if (test)
+		reg_pwr = chan_pwr = MAX_RATE_POWER;
 
 	regulatory->power_limit = min(limit, (u32) MAX_RATE_POWER);
 
 	ah->eep_ops->set_txpower(ah, chan,
 				 ath9k_regd_get_ctl(regulatory, chan),
 				 channel->max_antenna_gain * 2,
-				 channel->max_power * 2,
-				 min((u32) MAX_RATE_POWER,
-				 (u32) regulatory->power_limit), test);
+				 chan_pwr, reg_pwr, test);
 }
 EXPORT_SYMBOL(ath9k_hw_set_txpowerlimit);
 
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index c79889036ec4..4fbcced2828c 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -93,6 +93,12 @@
 			(_ah)->reg_ops.write_flush((_ah));	\
 	} while (0)
 
+#define PR_EEP(_s, _val)						\
+	do {								\
+		len += snprintf(buf + len, size - len, "%20s : %10d\n",	\
+				_s, (_val));				\
+	} while (0)
+
 #define SM(_v, _f)  (((_v) << _f##_S) & _f)
 #define MS(_v, _f)  (((_v) & _f) >> _f##_S)
 #define REG_RMW_FIELD(_a, _r, _f, _v) \
@@ -438,7 +444,6 @@ struct ath9k_hw_version {
 	u16 phyRev;
 	u16 analog5GhzRev;
 	u16 analog2GhzRev;
-	u16 subsysid;
 	enum ath_usb_dev usbdev;
 };
 
@@ -690,6 +695,7 @@ struct ath_hw {
 	enum nl80211_iftype opmode;
 	enum ath9k_power_mode power_mode;
 
+	s8 noise;
 	struct ath9k_hw_cal_data *caldata;
 	struct ath9k_pacal_info pacal_info;
 	struct ar5416Stats stats;
@@ -703,6 +709,7 @@ struct ath_hw {
 	u32 txdesc_interrupt_mask;
 	u32 txeol_interrupt_mask;
 	u32 txurn_interrupt_mask;
+	atomic_t intr_ref_cnt;
 	bool chip_fullsleep;
 	u32 atim_window;
 
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index aa0ff7e2c922..db38a58e752d 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -548,7 +548,7 @@ static void ath9k_init_misc(struct ath_softc *sc)
 		sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT;
 }
 
-static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
+static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
 			    const struct ath_bus_ops *bus_ops)
 {
 	struct ath9k_platform_data *pdata = sc->dev->platform_data;
@@ -563,10 +563,10 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
 
 	ah->hw = sc->hw;
 	ah->hw_version.devid = devid;
-	ah->hw_version.subsysid = subsysid;
 	ah->reg_ops.read = ath9k_ioread32;
 	ah->reg_ops.write = ath9k_iowrite32;
 	ah->reg_ops.rmw = ath9k_reg_rmw;
+	atomic_set(&ah->intr_ref_cnt, -1);
 	sc->sc_ah = ah;
 
 	if (!pdata) {
@@ -743,7 +743,7 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
 	SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
 }
 
-int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
+int ath9k_init_device(u16 devid, struct ath_softc *sc,
 		    const struct ath_bus_ops *bus_ops)
 {
 	struct ieee80211_hw *hw = sc->hw;
@@ -753,7 +753,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
 	struct ath_regulatory *reg;
 
 	/* Bring up device */
-	error = ath9k_init_softc(devid, sc, subsysid, bus_ops);
+	error = ath9k_init_softc(devid, sc, bus_ops);
 	if (error != 0)
 		goto error_init;
 
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index b6b523a897e5..0f90e1521ffe 100644
--- a/drivers/net/wireless/ath/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -800,6 +800,11 @@ void ath9k_hw_disable_interrupts(struct ath_hw *ah)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
 
+	if (!(ah->imask & ATH9K_INT_GLOBAL))
+		atomic_set(&ah->intr_ref_cnt, -1);
+	else
+		atomic_dec(&ah->intr_ref_cnt);
+
 	ath_dbg(common, ATH_DBG_INTERRUPT, "disable IER\n");
 	REG_WRITE(ah, AR_IER, AR_IER_DISABLE);
 	(void) REG_READ(ah, AR_IER);
@@ -821,6 +826,13 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah)
 	if (!(ah->imask & ATH9K_INT_GLOBAL))
 		return;
 
+	if (!atomic_inc_and_test(&ah->intr_ref_cnt)) {
+		ath_dbg(common, ATH_DBG_INTERRUPT,
+			"Do not enable IER ref count %d\n",
+			atomic_read(&ah->intr_ref_cnt));
+		return;
+	}
+
 	if (AR_SREV_9340(ah))
 		sync_default &= ~AR_INTR_SYNC_HOST1_FATAL;
 
@@ -852,7 +864,6 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
 
 	ath_dbg(common, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints);
 
-	/* TODO: global int Ref count */
 	mask = ints & ATH9K_INT_COMMON;
 	mask2 = 0;
 
@@ -929,9 +940,6 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
 			REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER);
 	}
 
-	if (ints & ATH9K_INT_GLOBAL)
-		ath9k_hw_enable_interrupts(ah);
-
 	return;
 }
 EXPORT_SYMBOL(ath9k_hw_set_interrupts);
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 9098aaad97a9..1e7fe8c0e119 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -163,7 +163,7 @@ static void ath_update_survey_nf(struct ath_softc *sc, int channel)
 
 	if (chan->noisefloor) {
 		survey->filled |= SURVEY_INFO_NOISE_DBM;
-		survey->noise = chan->noisefloor;
+		survey->noise = ath9k_hw_getchan_noise(ah, chan);
 	}
 }
 
@@ -294,6 +294,7 @@ static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 	ath9k_cmn_update_txpow(ah, sc->curtxpow,
 			       sc->config.txpowlimit, &sc->curtxpow);
 	ath9k_hw_set_interrupts(ah, ah->imask);
+	ath9k_hw_enable_interrupts(ah);
 
 	if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) {
 		if (sc->sc_flags & SC_OP_BEACONS)
@@ -706,8 +707,7 @@ void ath9k_tasklet(unsigned long data)
 		 */
 		ath_dbg(common, ATH_DBG_PS,
 			"TSFOOR - Sync with next Beacon\n");
-		sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC |
-				PS_TSFOOR_SYNC;
+		sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC;
 	}
 
 	if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
@@ -886,6 +886,7 @@ static void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
 
 	ath9k_ps_wakeup(sc);
 	spin_lock_bh(&sc->sc_pcu_lock);
+	atomic_set(&ah->intr_ref_cnt, -1);
 
 	ath9k_hw_configpcipowersave(ah, 0, 0);
 
@@ -910,6 +911,7 @@ static void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
 
 	/* Re-Enable  interrupts */
 	ath9k_hw_set_interrupts(ah, ah->imask);
+	ath9k_hw_enable_interrupts(ah);
 
 	/* Enable LED */
 	ath9k_hw_cfg_output(ah, ah->led_pin,
@@ -1016,6 +1018,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
 		ath_set_beacon(sc);	/* restart beacons */
 
 	ath9k_hw_set_interrupts(ah, ah->imask);
+	ath9k_hw_enable_interrupts(ah);
 
 	if (retry_tx) {
 		int i;
@@ -1130,6 +1133,7 @@ static int ath9k_start(struct ieee80211_hw *hw)
 	/* Disable BMISS interrupt when we're not associated */
 	ah->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
 	ath9k_hw_set_interrupts(ah, ah->imask);
+	ath9k_hw_enable_interrupts(ah);
 
 	ieee80211_wake_queues(hw);
 
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c
index be4ea1329813..5685cf11cfe3 100644
--- a/drivers/net/wireless/ath/ath9k/pci.c
+++ b/drivers/net/wireless/ath/ath9k/pci.c
@@ -156,7 +156,6 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	struct ath_softc *sc;
 	struct ieee80211_hw *hw;
 	u8 csz;
-	u16 subsysid;
 	u32 val;
 	int ret = 0;
 	char hw_name[64];
@@ -250,8 +249,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
 	sc->irq = pdev->irq;
 
-	pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsysid);
-	ret = ath9k_init_device(id->device, sc, subsysid, &ath_pci_bus_ops);
+	ret = ath9k_init_device(id->device, sc, &ath_pci_bus_ops);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to initialize device\n");
 		goto err_init;
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index c04a6c3cac7f..9e3649a3d5ca 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -1484,7 +1484,7 @@ static ssize_t read_file_rcstat(struct file *file, char __user *user_buf,
 	if (rc->rate_table == NULL)
 		return 0;
 
-	max = 80 + rc->rate_table->rate_cnt * 1024 + 1;
+	max = 80 + rc->rate_table_size * 1024 + 1;
 	buf = kmalloc(max, GFP_KERNEL);
 	if (buf == NULL)
 		return -ENOMEM;
@@ -1494,7 +1494,7 @@ static ssize_t read_file_rcstat(struct file *file, char __user *user_buf,
 		       "HT", "MCS", "Rate",
 		       "Success", "Retries", "XRetries", "PER");
 
-	for (i = 0; i < rc->rate_table->rate_cnt; i++) {
+	for (i = 0; i < rc->rate_table_size; i++) {
 		u32 ratekbps = rc->rate_table->info[i].ratekbps;
 		struct ath_rc_stats *stats = &rc->rcstats[i];
 		char mcs[5];
diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h
index c3d850207bee..b7a4bcd3eec7 100644
--- a/drivers/net/wireless/ath/ath9k/rc.h
+++ b/drivers/net/wireless/ath/ath9k/rc.h
@@ -221,12 +221,6 @@ struct ath_rate_priv {
 	struct ath_rc_stats rcstats[RATE_TABLE_SIZE];
 };
 
-enum ath9k_internal_frame_type {
-	ATH9K_IFT_NOT_INTERNAL,
-	ATH9K_IFT_PAUSE,
-	ATH9K_IFT_UNPAUSE
-};
-
 #ifdef CONFIG_ATH9K_RATE_CONTROL
 int ath_rate_control_register(void);
 void ath_rate_control_unregister(void);
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 9a4850154fb2..74094022b654 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -601,7 +601,6 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
 		ath_dbg(common, ATH_DBG_PS,
 			"Reconfigure Beacon timers based on timestamp from the AP\n");
 		ath_set_beacon(sc);
-		sc->ps_flags &= ~PS_TSFOOR_SYNC;
 	}
 
 	if (ath_beacon_dtim_pending_cab(skb)) {
@@ -995,6 +994,8 @@ static int ath9k_rx_skb_preprocess(struct ath_common *common,
 				   struct ieee80211_rx_status *rx_status,
 				   bool *decrypt_error)
 {
+	struct ath_hw *ah = common->ah;
+
 	memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
 
 	/*
@@ -1015,7 +1016,7 @@ static int ath9k_rx_skb_preprocess(struct ath_common *common,
 
 	rx_status->band = hw->conf.channel->band;
 	rx_status->freq = hw->conf.channel->center_freq;
-	rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + rx_stats->rs_rssi;
+	rx_status->signal = ah->noise + rx_stats->rs_rssi;
 	rx_status->antenna = rx_stats->rs_antenna;
 	rx_status->flag |= RX_FLAG_MACTIME_MPDU;
 
@@ -1783,11 +1784,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 	struct ieee80211_rx_status *rxs;
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_common *common = ath9k_hw_common(ah);
-	/*
-	 * The hw can technically differ from common->hw when using ath9k
-	 * virtual wiphy so to account for that we iterate over the active
-	 * wiphys and find the appropriate wiphy and therefore hw.
-	 */
 	struct ieee80211_hw *hw = sc->hw;
 	struct ieee80211_hdr *hdr;
 	int retval;
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index cc595712f518..e1d1e903229b 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -551,7 +551,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
 		if (clear_filter)
 			tid->ac->clear_ps_filter = true;
 		list_splice(&bf_pending, &tid->buf_q);
-		ath_tx_queue_tid(txq, tid);
+		if (!an->sleeping)
+			ath_tx_queue_tid(txq, tid);
 		spin_unlock_bh(&txq->axq_lock);
 	}
 
@@ -1413,7 +1414,8 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
 		 */
 		TX_STAT_INC(txctl->txq->axq_qnum, a_queued_sw);
 		list_add_tail(&bf->list, &tid->buf_q);
-		ath_tx_queue_tid(txctl->txq, tid);
+		if (!txctl->an || !txctl->an->sleeping)
+			ath_tx_queue_tid(txctl->txq, tid);
 		return;
 	}
 
@@ -1777,7 +1779,6 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
 		INIT_LIST_HEAD(&bf_head);
 		list_add_tail(&bf->list, &bf_head);
 
-		bf->bf_state.bfs_ftype = txctl->frame_type;
 		bf->bf_state.bfs_paprd = txctl->paprd;
 
 		if (bf->bf_state.bfs_paprd)
@@ -1876,7 +1877,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
 /*****************/
 
 static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
-			    int tx_flags, int ftype, struct ath_txq *txq)
+			    int tx_flags, struct ath_txq *txq)
 {
 	struct ieee80211_hw *hw = sc->hw;
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
@@ -1961,8 +1962,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
 			complete(&sc->paprd_complete);
 	} else {
 		ath_debug_stat_tx(sc, bf, ts, txq);
-		ath_tx_complete(sc, skb, tx_flags,
-				bf->bf_state.bfs_ftype, txq);
+		ath_tx_complete(sc, skb, tx_flags, txq);
 	}
 	/* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't
 	 * accidentally reference it later.
diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h
index 172f63f671cf..03a8268ccf21 100644
--- a/drivers/net/wireless/ath/regd.h
+++ b/drivers/net/wireless/ath/regd.h
@@ -101,7 +101,7 @@ enum CountryCode {
 	CTRY_GERMANY = 276,
 	CTRY_GREECE = 300,
 	CTRY_GREENLAND = 304,
-	CTRY_GRENEDA = 308,
+	CTRY_GRENADA = 308,
 	CTRY_GUAM = 316,
 	CTRY_GUATEMALA = 320,
 	CTRY_HAITI = 332,
diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h
index 24b53839fc3a..bdd2b4d61f2f 100644
--- a/drivers/net/wireless/ath/regd_common.h
+++ b/drivers/net/wireless/ath/regd_common.h
@@ -332,7 +332,7 @@ static struct country_code_to_enum_rd allCountries[] = {
 	{CTRY_GERMANY, ETSI1_WORLD, "DE"},
 	{CTRY_GREECE, ETSI1_WORLD, "GR"},
 	{CTRY_GREENLAND, ETSI1_WORLD, "GL"},
-	{CTRY_GRENEDA, FCC3_FCCA, "GD"},
+	{CTRY_GRENADA, FCC3_FCCA, "GD"},
 	{CTRY_GUAM, FCC1_FCCA, "GU"},
 	{CTRY_GUATEMALA, FCC1_FCCA, "GT"},
 	{CTRY_HAITI, ETSI1_WORLD, "HT"},
diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig
index 3cab843afb05..b81a2a1c2618 100644
--- a/drivers/net/wireless/b43/Kconfig
+++ b/drivers/net/wireless/b43/Kconfig
@@ -114,13 +114,13 @@ config B43_PHY_N
 	  affect other devices support and may provide support for basic needs.
 
 config B43_PHY_LP
-	bool "Support for low-power (LP-PHY) devices (EXPERIMENTAL)"
-	depends on B43 && EXPERIMENTAL
+	bool "Support for low-power (LP-PHY) devices"
+	depends on B43
 	default y
 	---help---
 	  Support for the LP-PHY.
 	  The LP-PHY is a low-power PHY built into some notebooks
-	  and embedded devices. It supports 802.11a/g
+	  and embedded devices. It supports 802.11a/b/g
 	  (802.11a support is optional, and currently disabled).
 
 config B43_PHY_HT
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 26f1ab840cc7..d2661aaff50f 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -37,7 +37,6 @@
 #include <linux/if_arp.h>
 #include <linux/etherdevice.h>
 #include <linux/firmware.h>
-#include <linux/wireless.h>
 #include <linux/workqueue.h>
 #include <linux/skbuff.h>
 #include <linux/io.h>
@@ -115,6 +114,7 @@ MODULE_PARM_DESC(pio, "Use PIO accesses by default: 0=DMA, 1=PIO");
 
 #ifdef CONFIG_B43_BCMA
 static const struct bcma_device_id b43_bcma_tbl[] = {
+	BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x11, BCMA_ANY_CLASS),
 	BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x17, BCMA_ANY_CLASS),
 	BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x18, BCMA_ANY_CLASS),
 	BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x1D, BCMA_ANY_CLASS),
diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h
index a610a352102a..ad4e743e4765 100644
--- a/drivers/net/wireless/b43legacy/b43legacy.h
+++ b/drivers/net/wireless/b43legacy/b43legacy.h
@@ -14,7 +14,6 @@
 #include <linux/ssb/ssb.h>
 #include <linux/ssb/ssb_driver_chipcommon.h>
 
-#include <linux/wireless.h>
 #include <net/mac80211.h>
 
 #include "debugfs.h"
diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c
index 5010c477abdf..c5535adf6991 100644
--- a/drivers/net/wireless/b43legacy/dma.c
+++ b/drivers/net/wireless/b43legacy/dma.c
@@ -42,10 +42,9 @@
 
 /* 32bit DMA ops. */
 static
-struct b43legacy_dmadesc_generic *op32_idx2desc(
-					struct b43legacy_dmaring *ring,
-					int slot,
-					struct b43legacy_dmadesc_meta **meta)
+struct b43legacy_dmadesc32 *op32_idx2desc(struct b43legacy_dmaring *ring,
+					  int slot,
+					  struct b43legacy_dmadesc_meta **meta)
 {
 	struct b43legacy_dmadesc32 *desc;
 
@@ -53,11 +52,11 @@ struct b43legacy_dmadesc_generic *op32_idx2desc(
 	desc = ring->descbase;
 	desc = &(desc[slot]);
 
-	return (struct b43legacy_dmadesc_generic *)desc;
+	return (struct b43legacy_dmadesc32 *)desc;
 }
 
 static void op32_fill_descriptor(struct b43legacy_dmaring *ring,
-				 struct b43legacy_dmadesc_generic *desc,
+				 struct b43legacy_dmadesc32 *desc,
 				 dma_addr_t dmaaddr, u16 bufsize,
 				 int start, int end, int irq)
 {
@@ -67,7 +66,7 @@ static void op32_fill_descriptor(struct b43legacy_dmaring *ring,
 	u32 addr;
 	u32 addrext;
 
-	slot = (int)(&(desc->dma32) - descbase);
+	slot = (int)(desc - descbase);
 	B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
 
 	addr = (u32)(dmaaddr & ~SSB_DMA_TRANSLATION_MASK);
@@ -87,8 +86,8 @@ static void op32_fill_descriptor(struct b43legacy_dmaring *ring,
 	ctl |= (addrext << B43legacy_DMA32_DCTL_ADDREXT_SHIFT)
 	       & B43legacy_DMA32_DCTL_ADDREXT_MASK;
 
-	desc->dma32.control = cpu_to_le32(ctl);
-	desc->dma32.address = cpu_to_le32(addr);
+	desc->control = cpu_to_le32(ctl);
+	desc->address = cpu_to_le32(addr);
 }
 
 static void op32_poke_tx(struct b43legacy_dmaring *ring, int slot)
@@ -128,121 +127,6 @@ static void op32_set_current_rxslot(struct b43legacy_dmaring *ring,
 			    (u32)(slot * sizeof(struct b43legacy_dmadesc32)));
 }
 
-static const struct b43legacy_dma_ops dma32_ops = {
-	.idx2desc		= op32_idx2desc,
-	.fill_descriptor	= op32_fill_descriptor,
-	.poke_tx		= op32_poke_tx,
-	.tx_suspend		= op32_tx_suspend,
-	.tx_resume		= op32_tx_resume,
-	.get_current_rxslot	= op32_get_current_rxslot,
-	.set_current_rxslot	= op32_set_current_rxslot,
-};
-
-/* 64bit DMA ops. */
-static
-struct b43legacy_dmadesc_generic *op64_idx2desc(
-					struct b43legacy_dmaring *ring,
-					int slot,
-					struct b43legacy_dmadesc_meta
-					**meta)
-{
-	struct b43legacy_dmadesc64 *desc;
-
-	*meta = &(ring->meta[slot]);
-	desc = ring->descbase;
-	desc = &(desc[slot]);
-
-	return (struct b43legacy_dmadesc_generic *)desc;
-}
-
-static void op64_fill_descriptor(struct b43legacy_dmaring *ring,
-				 struct b43legacy_dmadesc_generic *desc,
-				 dma_addr_t dmaaddr, u16 bufsize,
-				 int start, int end, int irq)
-{
-	struct b43legacy_dmadesc64 *descbase = ring->descbase;
-	int slot;
-	u32 ctl0 = 0;
-	u32 ctl1 = 0;
-	u32 addrlo;
-	u32 addrhi;
-	u32 addrext;
-
-	slot = (int)(&(desc->dma64) - descbase);
-	B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
-
-	addrlo = (u32)(dmaaddr & 0xFFFFFFFF);
-	addrhi = (((u64)dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK);
-	addrext = (((u64)dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK)
-		  >> SSB_DMA_TRANSLATION_SHIFT;
-	addrhi |= ring->dev->dma.translation;
-	if (slot == ring->nr_slots - 1)
-		ctl0 |= B43legacy_DMA64_DCTL0_DTABLEEND;
-	if (start)
-		ctl0 |= B43legacy_DMA64_DCTL0_FRAMESTART;
-	if (end)
-		ctl0 |= B43legacy_DMA64_DCTL0_FRAMEEND;
-	if (irq)
-		ctl0 |= B43legacy_DMA64_DCTL0_IRQ;
-	ctl1 |= (bufsize - ring->frameoffset)
-		& B43legacy_DMA64_DCTL1_BYTECNT;
-	ctl1 |= (addrext << B43legacy_DMA64_DCTL1_ADDREXT_SHIFT)
-		& B43legacy_DMA64_DCTL1_ADDREXT_MASK;
-
-	desc->dma64.control0 = cpu_to_le32(ctl0);
-	desc->dma64.control1 = cpu_to_le32(ctl1);
-	desc->dma64.address_low = cpu_to_le32(addrlo);
-	desc->dma64.address_high = cpu_to_le32(addrhi);
-}
-
-static void op64_poke_tx(struct b43legacy_dmaring *ring, int slot)
-{
-	b43legacy_dma_write(ring, B43legacy_DMA64_TXINDEX,
-			    (u32)(slot * sizeof(struct b43legacy_dmadesc64)));
-}
-
-static void op64_tx_suspend(struct b43legacy_dmaring *ring)
-{
-	b43legacy_dma_write(ring, B43legacy_DMA64_TXCTL,
-			    b43legacy_dma_read(ring, B43legacy_DMA64_TXCTL)
-			    | B43legacy_DMA64_TXSUSPEND);
-}
-
-static void op64_tx_resume(struct b43legacy_dmaring *ring)
-{
-	b43legacy_dma_write(ring, B43legacy_DMA64_TXCTL,
-			    b43legacy_dma_read(ring, B43legacy_DMA64_TXCTL)
-			    & ~B43legacy_DMA64_TXSUSPEND);
-}
-
-static int op64_get_current_rxslot(struct b43legacy_dmaring *ring)
-{
-	u32 val;
-
-	val = b43legacy_dma_read(ring, B43legacy_DMA64_RXSTATUS);
-	val &= B43legacy_DMA64_RXSTATDPTR;
-
-	return (val / sizeof(struct b43legacy_dmadesc64));
-}
-
-static void op64_set_current_rxslot(struct b43legacy_dmaring *ring,
-				    int slot)
-{
-	b43legacy_dma_write(ring, B43legacy_DMA64_RXINDEX,
-			    (u32)(slot * sizeof(struct b43legacy_dmadesc64)));
-}
-
-static const struct b43legacy_dma_ops dma64_ops = {
-	.idx2desc		= op64_idx2desc,
-	.fill_descriptor	= op64_fill_descriptor,
-	.poke_tx		= op64_poke_tx,
-	.tx_suspend		= op64_tx_suspend,
-	.tx_resume		= op64_tx_resume,
-	.get_current_rxslot	= op64_get_current_rxslot,
-	.set_current_rxslot	= op64_set_current_rxslot,
-};
-
-
 static inline int free_slots(struct b43legacy_dmaring *ring)
 {
 	return (ring->nr_slots - ring->used_slots);
@@ -358,14 +242,6 @@ return 0;
 static u16 b43legacy_dmacontroller_base(enum b43legacy_dmatype type,
 					int controller_idx)
 {
-	static const u16 map64[] = {
-		B43legacy_MMIO_DMA64_BASE0,
-		B43legacy_MMIO_DMA64_BASE1,
-		B43legacy_MMIO_DMA64_BASE2,
-		B43legacy_MMIO_DMA64_BASE3,
-		B43legacy_MMIO_DMA64_BASE4,
-		B43legacy_MMIO_DMA64_BASE5,
-	};
 	static const u16 map32[] = {
 		B43legacy_MMIO_DMA32_BASE0,
 		B43legacy_MMIO_DMA32_BASE1,
@@ -375,11 +251,6 @@ static u16 b43legacy_dmacontroller_base(enum b43legacy_dmatype type,
 		B43legacy_MMIO_DMA32_BASE5,
 	};
 
-	if (type == B43legacy_DMA_64BIT) {
-		B43legacy_WARN_ON(!(controller_idx >= 0 &&
-				  controller_idx < ARRAY_SIZE(map64)));
-		return map64[controller_idx];
-	}
 	B43legacy_WARN_ON(!(controller_idx >= 0 &&
 			  controller_idx < ARRAY_SIZE(map32)));
 	return map32[controller_idx];
@@ -491,25 +362,15 @@ static int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev,
 
 	might_sleep();
 
-	offset = (type == B43legacy_DMA_64BIT) ?
-		 B43legacy_DMA64_RXCTL : B43legacy_DMA32_RXCTL;
+	offset = B43legacy_DMA32_RXCTL;
 	b43legacy_write32(dev, mmio_base + offset, 0);
 	for (i = 0; i < 10; i++) {
-		offset = (type == B43legacy_DMA_64BIT) ?
-			 B43legacy_DMA64_RXSTATUS : B43legacy_DMA32_RXSTATUS;
+		offset = B43legacy_DMA32_RXSTATUS;
 		value = b43legacy_read32(dev, mmio_base + offset);
-		if (type == B43legacy_DMA_64BIT) {
-			value &= B43legacy_DMA64_RXSTAT;
-			if (value == B43legacy_DMA64_RXSTAT_DISABLED) {
-				i = -1;
-				break;
-			}
-		} else {
-			value &= B43legacy_DMA32_RXSTATE;
-			if (value == B43legacy_DMA32_RXSTAT_DISABLED) {
-				i = -1;
-				break;
-			}
+		value &= B43legacy_DMA32_RXSTATE;
+		if (value == B43legacy_DMA32_RXSTAT_DISABLED) {
+			i = -1;
+			break;
 		}
 		msleep(1);
 	}
@@ -533,43 +394,24 @@ static int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev,
 	might_sleep();
 
 	for (i = 0; i < 10; i++) {
-		offset = (type == B43legacy_DMA_64BIT) ?
-			 B43legacy_DMA64_TXSTATUS : B43legacy_DMA32_TXSTATUS;
+		offset = B43legacy_DMA32_TXSTATUS;
 		value = b43legacy_read32(dev, mmio_base + offset);
-		if (type == B43legacy_DMA_64BIT) {
-			value &= B43legacy_DMA64_TXSTAT;
-			if (value == B43legacy_DMA64_TXSTAT_DISABLED ||
-			    value == B43legacy_DMA64_TXSTAT_IDLEWAIT ||
-			    value == B43legacy_DMA64_TXSTAT_STOPPED)
-				break;
-		} else {
-			value &= B43legacy_DMA32_TXSTATE;
-			if (value == B43legacy_DMA32_TXSTAT_DISABLED ||
-			    value == B43legacy_DMA32_TXSTAT_IDLEWAIT ||
-			    value == B43legacy_DMA32_TXSTAT_STOPPED)
-				break;
-		}
+		value &= B43legacy_DMA32_TXSTATE;
+		if (value == B43legacy_DMA32_TXSTAT_DISABLED ||
+		    value == B43legacy_DMA32_TXSTAT_IDLEWAIT ||
+		    value == B43legacy_DMA32_TXSTAT_STOPPED)
+			break;
 		msleep(1);
 	}
-	offset = (type == B43legacy_DMA_64BIT) ? B43legacy_DMA64_TXCTL :
-						 B43legacy_DMA32_TXCTL;
+	offset = B43legacy_DMA32_TXCTL;
 	b43legacy_write32(dev, mmio_base + offset, 0);
 	for (i = 0; i < 10; i++) {
-		offset = (type == B43legacy_DMA_64BIT) ?
-			 B43legacy_DMA64_TXSTATUS : B43legacy_DMA32_TXSTATUS;
+		offset = B43legacy_DMA32_TXSTATUS;
 		value = b43legacy_read32(dev, mmio_base + offset);
-		if (type == B43legacy_DMA_64BIT) {
-			value &= B43legacy_DMA64_TXSTAT;
-			if (value == B43legacy_DMA64_TXSTAT_DISABLED) {
-				i = -1;
-				break;
-			}
-		} else {
-			value &= B43legacy_DMA32_TXSTATE;
-			if (value == B43legacy_DMA32_TXSTAT_DISABLED) {
-				i = -1;
-				break;
-			}
+		value &= B43legacy_DMA32_TXSTATE;
+		if (value == B43legacy_DMA32_TXSTAT_DISABLED) {
+			i = -1;
+			break;
 		}
 		msleep(1);
 	}
@@ -601,9 +443,6 @@ static bool b43legacy_dma_mapping_error(struct b43legacy_dmaring *ring,
 		if ((u64)addr + buffersize > (1ULL << 32))
 			goto address_error;
 		break;
-	case B43legacy_DMA_64BIT:
-		/* Currently we can't have addresses beyond 64 bits in the kernel. */
-		break;
 	}
 
 	/* The address is OK. */
@@ -617,7 +456,7 @@ address_error:
 }
 
 static int setup_rx_descbuffer(struct b43legacy_dmaring *ring,
-			       struct b43legacy_dmadesc_generic *desc,
+			       struct b43legacy_dmadesc32 *desc,
 			       struct b43legacy_dmadesc_meta *meta,
 			       gfp_t gfp_flags)
 {
@@ -653,8 +492,7 @@ static int setup_rx_descbuffer(struct b43legacy_dmaring *ring,
 
 	meta->skb = skb;
 	meta->dmaaddr = dmaaddr;
-	ring->ops->fill_descriptor(ring, desc, dmaaddr,
-				   ring->rx_buffersize, 0, 0, 0);
+	op32_fill_descriptor(ring, desc, dmaaddr, ring->rx_buffersize, 0, 0, 0);
 
 	rxhdr = (struct b43legacy_rxhdr_fw3 *)(skb->data);
 	rxhdr->frame_len = 0;
@@ -671,11 +509,11 @@ static int alloc_initial_descbuffers(struct b43legacy_dmaring *ring)
 {
 	int i;
 	int err = -ENOMEM;
-	struct b43legacy_dmadesc_generic *desc;
+	struct b43legacy_dmadesc32 *desc;
 	struct b43legacy_dmadesc_meta *meta;
 
 	for (i = 0; i < ring->nr_slots; i++) {
-		desc = ring->ops->idx2desc(ring, i, &meta);
+		desc = op32_idx2desc(ring, i, &meta);
 
 		err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL);
 		if (err) {
@@ -692,7 +530,7 @@ out:
 
 err_unwind:
 	for (i--; i >= 0; i--) {
-		desc = ring->ops->idx2desc(ring, i, &meta);
+		desc = op32_idx2desc(ring, i, &meta);
 
 		unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0);
 		dev_kfree_skb(meta->skb);
@@ -710,83 +548,35 @@ static int dmacontroller_setup(struct b43legacy_dmaring *ring)
 	u32 value;
 	u32 addrext;
 	u32 trans = ring->dev->dma.translation;
+	u32 ringbase = (u32)(ring->dmabase);
 
 	if (ring->tx) {
-		if (ring->type == B43legacy_DMA_64BIT) {
-			u64 ringbase = (u64)(ring->dmabase);
-
-			addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
-				  >> SSB_DMA_TRANSLATION_SHIFT;
-			value = B43legacy_DMA64_TXENABLE;
-			value |= (addrext << B43legacy_DMA64_TXADDREXT_SHIFT)
-				& B43legacy_DMA64_TXADDREXT_MASK;
-			b43legacy_dma_write(ring, B43legacy_DMA64_TXCTL,
-					    value);
-			b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGLO,
-					    (ringbase & 0xFFFFFFFF));
-			b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGHI,
-					    ((ringbase >> 32)
-					    & ~SSB_DMA_TRANSLATION_MASK)
-					    | trans);
-		} else {
-			u32 ringbase = (u32)(ring->dmabase);
-
-			addrext = (ringbase & SSB_DMA_TRANSLATION_MASK)
-				  >> SSB_DMA_TRANSLATION_SHIFT;
-			value = B43legacy_DMA32_TXENABLE;
-			value |= (addrext << B43legacy_DMA32_TXADDREXT_SHIFT)
-				& B43legacy_DMA32_TXADDREXT_MASK;
-			b43legacy_dma_write(ring, B43legacy_DMA32_TXCTL,
-					    value);
-			b43legacy_dma_write(ring, B43legacy_DMA32_TXRING,
-					    (ringbase &
-					    ~SSB_DMA_TRANSLATION_MASK)
-					    | trans);
-		}
+		addrext = (ringbase & SSB_DMA_TRANSLATION_MASK)
+			  >> SSB_DMA_TRANSLATION_SHIFT;
+		value = B43legacy_DMA32_TXENABLE;
+		value |= (addrext << B43legacy_DMA32_TXADDREXT_SHIFT)
+			& B43legacy_DMA32_TXADDREXT_MASK;
+		b43legacy_dma_write(ring, B43legacy_DMA32_TXCTL, value);
+		b43legacy_dma_write(ring, B43legacy_DMA32_TXRING,
+				    (ringbase & ~SSB_DMA_TRANSLATION_MASK)
+				    | trans);
 	} else {
 		err = alloc_initial_descbuffers(ring);
 		if (err)
 			goto out;
-		if (ring->type == B43legacy_DMA_64BIT) {
-			u64 ringbase = (u64)(ring->dmabase);
-
-			addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
-				  >> SSB_DMA_TRANSLATION_SHIFT;
-			value = (ring->frameoffset <<
-				 B43legacy_DMA64_RXFROFF_SHIFT);
-			value |= B43legacy_DMA64_RXENABLE;
-			value |= (addrext << B43legacy_DMA64_RXADDREXT_SHIFT)
-				& B43legacy_DMA64_RXADDREXT_MASK;
-			b43legacy_dma_write(ring, B43legacy_DMA64_RXCTL,
-					    value);
-			b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGLO,
-					    (ringbase & 0xFFFFFFFF));
-			b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGHI,
-					    ((ringbase >> 32) &
-					    ~SSB_DMA_TRANSLATION_MASK) |
-					    trans);
-			b43legacy_dma_write(ring, B43legacy_DMA64_RXINDEX,
-					    200);
-		} else {
-			u32 ringbase = (u32)(ring->dmabase);
-
-			addrext = (ringbase & SSB_DMA_TRANSLATION_MASK)
-				  >> SSB_DMA_TRANSLATION_SHIFT;
-			value = (ring->frameoffset <<
-				 B43legacy_DMA32_RXFROFF_SHIFT);
-			value |= B43legacy_DMA32_RXENABLE;
-			value |= (addrext <<
-				 B43legacy_DMA32_RXADDREXT_SHIFT)
-				 & B43legacy_DMA32_RXADDREXT_MASK;
-			b43legacy_dma_write(ring, B43legacy_DMA32_RXCTL,
-					    value);
-			b43legacy_dma_write(ring, B43legacy_DMA32_RXRING,
-					    (ringbase &
-					    ~SSB_DMA_TRANSLATION_MASK)
-					    | trans);
-			b43legacy_dma_write(ring, B43legacy_DMA32_RXINDEX,
-					    200);
-		}
+
+		addrext = (ringbase & SSB_DMA_TRANSLATION_MASK)
+			  >> SSB_DMA_TRANSLATION_SHIFT;
+		value = (ring->frameoffset <<
+			 B43legacy_DMA32_RXFROFF_SHIFT);
+		value |= B43legacy_DMA32_RXENABLE;
+		value |= (addrext << B43legacy_DMA32_RXADDREXT_SHIFT)
+			 & B43legacy_DMA32_RXADDREXT_MASK;
+		b43legacy_dma_write(ring, B43legacy_DMA32_RXCTL, value);
+		b43legacy_dma_write(ring, B43legacy_DMA32_RXRING,
+				    (ringbase & ~SSB_DMA_TRANSLATION_MASK)
+				    | trans);
+		b43legacy_dma_write(ring, B43legacy_DMA32_RXINDEX, 200);
 	}
 
 out:
@@ -799,19 +589,11 @@ static void dmacontroller_cleanup(struct b43legacy_dmaring *ring)
 	if (ring->tx) {
 		b43legacy_dmacontroller_tx_reset(ring->dev, ring->mmio_base,
 						 ring->type);
-		if (ring->type == B43legacy_DMA_64BIT) {
-			b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGLO, 0);
-			b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGHI, 0);
-		} else
-			b43legacy_dma_write(ring, B43legacy_DMA32_TXRING, 0);
+		b43legacy_dma_write(ring, B43legacy_DMA32_TXRING, 0);
 	} else {
 		b43legacy_dmacontroller_rx_reset(ring->dev, ring->mmio_base,
 						 ring->type);
-		if (ring->type == B43legacy_DMA_64BIT) {
-			b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGLO, 0);
-			b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGHI, 0);
-		} else
-			b43legacy_dma_write(ring, B43legacy_DMA32_RXRING, 0);
+		b43legacy_dma_write(ring, B43legacy_DMA32_RXRING, 0);
 	}
 }
 
@@ -823,7 +605,7 @@ static void free_all_descbuffers(struct b43legacy_dmaring *ring)
 	if (!ring->used_slots)
 		return;
 	for (i = 0; i < ring->nr_slots; i++) {
-		ring->ops->idx2desc(ring, i, &meta);
+		op32_idx2desc(ring, i, &meta);
 
 		if (!meta->skb) {
 			B43legacy_WARN_ON(!ring->tx);
@@ -844,9 +626,6 @@ static u64 supported_dma_mask(struct b43legacy_wldev *dev)
 	u32 tmp;
 	u16 mmio_base;
 
-	tmp = b43legacy_read32(dev, SSB_TMSHIGH);
-	if (tmp & SSB_TMSHIGH_DMA64)
-		return DMA_BIT_MASK(64);
 	mmio_base = b43legacy_dmacontroller_base(0, 0);
 	b43legacy_write32(dev,
 			mmio_base + B43legacy_DMA32_TXCTL,
@@ -865,8 +644,6 @@ static enum b43legacy_dmatype dma_mask_to_engine_type(u64 dmamask)
 		return B43legacy_DMA_30BIT;
 	if (dmamask == DMA_BIT_MASK(32))
 		return B43legacy_DMA_32BIT;
-	if (dmamask == DMA_BIT_MASK(64))
-		return B43legacy_DMA_64BIT;
 	B43legacy_WARN_ON(1);
 	return B43legacy_DMA_30BIT;
 }
@@ -937,10 +714,6 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
 	ring->nr_slots = nr_slots;
 	ring->mmio_base = b43legacy_dmacontroller_base(type, controller_index);
 	ring->index = controller_index;
-	if (type == B43legacy_DMA_64BIT)
-		ring->ops = &dma64_ops;
-	else
-		ring->ops = &dma32_ops;
 	if (for_tx) {
 		ring->tx = 1;
 		ring->current_slot = -1;
@@ -1247,12 +1020,11 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring,
 			    struct sk_buff **in_skb)
 {
 	struct sk_buff *skb = *in_skb;
-	const struct b43legacy_dma_ops *ops = ring->ops;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	u8 *header;
 	int slot, old_top_slot, old_used_slots;
 	int err;
-	struct b43legacy_dmadesc_generic *desc;
+	struct b43legacy_dmadesc32 *desc;
 	struct b43legacy_dmadesc_meta *meta;
 	struct b43legacy_dmadesc_meta *meta_hdr;
 	struct sk_buff *bounce_skb;
@@ -1265,7 +1037,7 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring,
 
 	/* Get a slot for the header. */
 	slot = request_slot(ring);
-	desc = ops->idx2desc(ring, slot, &meta_hdr);
+	desc = op32_idx2desc(ring, slot, &meta_hdr);
 	memset(meta_hdr, 0, sizeof(*meta_hdr));
 
 	header = &(ring->txhdr_cache[slot * sizeof(
@@ -1287,12 +1059,12 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring,
 		ring->used_slots = old_used_slots;
 		return -EIO;
 	}
-	ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr,
+	op32_fill_descriptor(ring, desc, meta_hdr->dmaaddr,
 			     sizeof(struct b43legacy_txhdr_fw3), 1, 0, 0);
 
 	/* Get a slot for the payload. */
 	slot = request_slot(ring);
-	desc = ops->idx2desc(ring, slot, &meta);
+	desc = op32_idx2desc(ring, slot, &meta);
 	memset(meta, 0, sizeof(*meta));
 
 	meta->skb = skb;
@@ -1328,12 +1100,12 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring,
 		}
 	}
 
-	ops->fill_descriptor(ring, desc, meta->dmaaddr,
+	op32_fill_descriptor(ring, desc, meta->dmaaddr,
 			     skb->len, 0, 1, 1);
 
 	wmb();	/* previous stuff MUST be done */
 	/* Now transfer the whole frame. */
-	ops->poke_tx(ring, next_slot(ring, slot));
+	op32_poke_tx(ring, next_slot(ring, slot));
 	return 0;
 
 out_free_bounce:
@@ -1429,7 +1201,6 @@ out_unlock:
 void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
 				 const struct b43legacy_txstatus *status)
 {
-	const struct b43legacy_dma_ops *ops;
 	struct b43legacy_dmaring *ring;
 	struct b43legacy_dmadesc_meta *meta;
 	int retry_limit;
@@ -1442,10 +1213,9 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
 	spin_lock(&ring->lock);
 
 	B43legacy_WARN_ON(!ring->tx);
-	ops = ring->ops;
 	while (1) {
 		B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
-		ops->idx2desc(ring, slot, &meta);
+		op32_idx2desc(ring, slot, &meta);
 
 		if (meta->skb)
 			unmap_descbuffer(ring, meta->dmaaddr,
@@ -1528,8 +1298,7 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
 static void dma_rx(struct b43legacy_dmaring *ring,
 		   int *slot)
 {
-	const struct b43legacy_dma_ops *ops = ring->ops;
-	struct b43legacy_dmadesc_generic *desc;
+	struct b43legacy_dmadesc32 *desc;
 	struct b43legacy_dmadesc_meta *meta;
 	struct b43legacy_rxhdr_fw3 *rxhdr;
 	struct sk_buff *skb;
@@ -1537,7 +1306,7 @@ static void dma_rx(struct b43legacy_dmaring *ring,
 	int err;
 	dma_addr_t dmaaddr;
 
-	desc = ops->idx2desc(ring, *slot, &meta);
+	desc = op32_idx2desc(ring, *slot, &meta);
 
 	sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize);
 	skb = meta->skb;
@@ -1589,7 +1358,7 @@ static void dma_rx(struct b43legacy_dmaring *ring,
 		s32 tmp = len;
 
 		while (1) {
-			desc = ops->idx2desc(ring, *slot, &meta);
+			desc = op32_idx2desc(ring, *slot, &meta);
 			/* recycle the descriptor buffer. */
 			sync_descbuffer_for_device(ring, meta->dmaaddr,
 						   ring->rx_buffersize);
@@ -1626,13 +1395,12 @@ drop:
 
 void b43legacy_dma_rx(struct b43legacy_dmaring *ring)
 {
-	const struct b43legacy_dma_ops *ops = ring->ops;
 	int slot;
 	int current_slot;
 	int used_slots = 0;
 
 	B43legacy_WARN_ON(ring->tx);
-	current_slot = ops->get_current_rxslot(ring);
+	current_slot = op32_get_current_rxslot(ring);
 	B43legacy_WARN_ON(!(current_slot >= 0 && current_slot <
 			   ring->nr_slots));
 
@@ -1641,7 +1409,7 @@ void b43legacy_dma_rx(struct b43legacy_dmaring *ring)
 		dma_rx(ring, &slot);
 		update_max_used_slots(ring, ++used_slots);
 	}
-	ops->set_current_rxslot(ring, slot);
+	op32_set_current_rxslot(ring, slot);
 	ring->current_slot = slot;
 }
 
@@ -1651,7 +1419,7 @@ static void b43legacy_dma_tx_suspend_ring(struct b43legacy_dmaring *ring)
 
 	spin_lock_irqsave(&ring->lock, flags);
 	B43legacy_WARN_ON(!ring->tx);
-	ring->ops->tx_suspend(ring);
+	op32_tx_suspend(ring);
 	spin_unlock_irqrestore(&ring->lock, flags);
 }
 
@@ -1661,7 +1429,7 @@ static void b43legacy_dma_tx_resume_ring(struct b43legacy_dmaring *ring)
 
 	spin_lock_irqsave(&ring->lock, flags);
 	B43legacy_WARN_ON(!ring->tx);
-	ring->ops->tx_resume(ring);
+	op32_tx_resume(ring);
 	spin_unlock_irqrestore(&ring->lock, flags);
 }
 
diff --git a/drivers/net/wireless/b43legacy/dma.h b/drivers/net/wireless/b43legacy/dma.h
index 686941c242fc..504a58767e95 100644
--- a/drivers/net/wireless/b43legacy/dma.h
+++ b/drivers/net/wireless/b43legacy/dma.h
@@ -82,90 +82,6 @@ struct b43legacy_dmadesc32 {
 #define B43legacy_DMA32_DCTL_FRAMESTART		0x80000000
 
 
-
-/*** 64-bit DMA Engine. ***/
-
-/* 64-bit DMA controller registers. */
-#define B43legacy_DMA64_TXCTL				0x00
-#define		B43legacy_DMA64_TXENABLE		0x00000001
-#define		B43legacy_DMA64_TXSUSPEND		0x00000002
-#define		B43legacy_DMA64_TXLOOPBACK		0x00000004
-#define		B43legacy_DMA64_TXFLUSH			0x00000010
-#define		B43legacy_DMA64_TXADDREXT_MASK		0x00030000
-#define		B43legacy_DMA64_TXADDREXT_SHIFT		16
-#define B43legacy_DMA64_TXINDEX				0x04
-#define B43legacy_DMA64_TXRINGLO			0x08
-#define B43legacy_DMA64_TXRINGHI			0x0C
-#define B43legacy_DMA64_TXSTATUS			0x10
-#define		B43legacy_DMA64_TXSTATDPTR		0x00001FFF
-#define		B43legacy_DMA64_TXSTAT			0xF0000000
-#define			B43legacy_DMA64_TXSTAT_DISABLED	0x00000000
-#define			B43legacy_DMA64_TXSTAT_ACTIVE	0x10000000
-#define			B43legacy_DMA64_TXSTAT_IDLEWAIT	0x20000000
-#define			B43legacy_DMA64_TXSTAT_STOPPED	0x30000000
-#define			B43legacy_DMA64_TXSTAT_SUSP	0x40000000
-#define B43legacy_DMA64_TXERROR				0x14
-#define		B43legacy_DMA64_TXERRDPTR		0x0001FFFF
-#define		B43legacy_DMA64_TXERR			0xF0000000
-#define			B43legacy_DMA64_TXERR_NOERR	0x00000000
-#define			B43legacy_DMA64_TXERR_PROT	0x10000000
-#define			B43legacy_DMA64_TXERR_UNDERRUN	0x20000000
-#define			B43legacy_DMA64_TXERR_TRANSFER	0x30000000
-#define			B43legacy_DMA64_TXERR_DESCREAD	0x40000000
-#define			B43legacy_DMA64_TXERR_CORE	0x50000000
-#define B43legacy_DMA64_RXCTL				0x20
-#define		B43legacy_DMA64_RXENABLE		0x00000001
-#define		B43legacy_DMA64_RXFROFF_MASK		0x000000FE
-#define		B43legacy_DMA64_RXFROFF_SHIFT		1
-#define		B43legacy_DMA64_RXDIRECTFIFO		0x00000100
-#define		B43legacy_DMA64_RXADDREXT_MASK		0x00030000
-#define		B43legacy_DMA64_RXADDREXT_SHIFT		16
-#define B43legacy_DMA64_RXINDEX				0x24
-#define B43legacy_DMA64_RXRINGLO			0x28
-#define B43legacy_DMA64_RXRINGHI			0x2C
-#define B43legacy_DMA64_RXSTATUS			0x30
-#define		B43legacy_DMA64_RXSTATDPTR		0x00001FFF
-#define		B43legacy_DMA64_RXSTAT			0xF0000000
-#define			B43legacy_DMA64_RXSTAT_DISABLED	0x00000000
-#define			B43legacy_DMA64_RXSTAT_ACTIVE	0x10000000
-#define			B43legacy_DMA64_RXSTAT_IDLEWAIT	0x20000000
-#define			B43legacy_DMA64_RXSTAT_STOPPED	0x30000000
-#define			B43legacy_DMA64_RXSTAT_SUSP	0x40000000
-#define B43legacy_DMA64_RXERROR				0x34
-#define		B43legacy_DMA64_RXERRDPTR		0x0001FFFF
-#define		B43legacy_DMA64_RXERR			0xF0000000
-#define			B43legacy_DMA64_RXERR_NOERR	0x00000000
-#define			B43legacy_DMA64_RXERR_PROT	0x10000000
-#define			B43legacy_DMA64_RXERR_UNDERRUN	0x20000000
-#define			B43legacy_DMA64_RXERR_TRANSFER	0x30000000
-#define			B43legacy_DMA64_RXERR_DESCREAD	0x40000000
-#define			B43legacy_DMA64_RXERR_CORE	0x50000000
-
-/* 64-bit DMA descriptor. */
-struct b43legacy_dmadesc64 {
-	__le32 control0;
-	__le32 control1;
-	__le32 address_low;
-	__le32 address_high;
-} __packed;
-#define B43legacy_DMA64_DCTL0_DTABLEEND		0x10000000
-#define B43legacy_DMA64_DCTL0_IRQ		0x20000000
-#define B43legacy_DMA64_DCTL0_FRAMEEND		0x40000000
-#define B43legacy_DMA64_DCTL0_FRAMESTART	0x80000000
-#define B43legacy_DMA64_DCTL1_BYTECNT		0x00001FFF
-#define B43legacy_DMA64_DCTL1_ADDREXT_MASK	0x00030000
-#define B43legacy_DMA64_DCTL1_ADDREXT_SHIFT	16
-
-
-
-struct b43legacy_dmadesc_generic {
-	union {
-		struct b43legacy_dmadesc32 dma32;
-		struct b43legacy_dmadesc64 dma64;
-	} __packed;
-} __packed;
-
-
 /* Misc DMA constants */
 #define B43legacy_DMA_RINGMEMSIZE	PAGE_SIZE
 #define B43legacy_DMA0_RX_FRAMEOFFSET	30
@@ -197,35 +113,12 @@ struct b43legacy_dmadesc_meta {
 	bool is_last_fragment;
 };
 
-struct b43legacy_dmaring;
-
-/* Lowlevel DMA operations that differ between 32bit and 64bit DMA. */
-struct b43legacy_dma_ops {
-	struct b43legacy_dmadesc_generic * (*idx2desc)
-					   (struct b43legacy_dmaring *ring,
-					   int slot,
-					   struct b43legacy_dmadesc_meta
-					   **meta);
-	void (*fill_descriptor)(struct b43legacy_dmaring *ring,
-				struct b43legacy_dmadesc_generic *desc,
-				dma_addr_t dmaaddr, u16 bufsize,
-				int start, int end, int irq);
-	void (*poke_tx)(struct b43legacy_dmaring *ring, int slot);
-	void (*tx_suspend)(struct b43legacy_dmaring *ring);
-	void (*tx_resume)(struct b43legacy_dmaring *ring);
-	int (*get_current_rxslot)(struct b43legacy_dmaring *ring);
-	void (*set_current_rxslot)(struct b43legacy_dmaring *ring, int slot);
-};
-
 enum b43legacy_dmatype {
 	B43legacy_DMA_30BIT = 30,
 	B43legacy_DMA_32BIT = 32,
-	B43legacy_DMA_64BIT = 64,
 };
 
 struct b43legacy_dmaring {
-	/* Lowlevel DMA ops. */
-	const struct b43legacy_dma_ops *ops;
 	/* Kernel virtual base address of the ring memory. */
 	void *descbase;
 	/* Meta data about all descriptors. */
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 04c03b212a5e..aae8dfcb852e 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -35,7 +35,6 @@
 #include <linux/if_arp.h>
 #include <linux/etherdevice.h>
 #include <linux/firmware.h>
-#include <linux/wireless.h>
 #include <linux/workqueue.h>
 #include <linux/sched.h>
 #include <linux/skbuff.h>
@@ -3785,7 +3784,8 @@ static int b43legacy_wireless_init(struct ssb_device *dev)
 	INIT_WORK(&wl->beacon_update_trigger, b43legacy_beacon_update_trigger_work);
 
 	ssb_set_devtypedata(dev, wl);
-	b43legacyinfo(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id);
+	b43legacyinfo(wl, "Broadcom %04X WLAN found (core revision %u)\n",
+		      dev->bus->chip_id, dev->id.revision);
 	err = 0;
 out:
 	return err;
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
index 553f66b67c16..f303df43ed3f 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -32,6 +32,7 @@
 
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <net/cfg80211-wext.h>
 #include "ipw2200.h"
 
 
diff --git a/drivers/net/wireless/iwlegacy/iwl-3945-led.c b/drivers/net/wireless/iwlegacy/iwl-3945-led.c
index abd923558d48..7a7f0f38c8ab 100644
--- a/drivers/net/wireless/iwlegacy/iwl-3945-led.c
+++ b/drivers/net/wireless/iwlegacy/iwl-3945-led.c
@@ -32,7 +32,6 @@
 #include <linux/delay.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
-#include <linux/wireless.h>
 #include <net/mac80211.h>
 #include <linux/etherdevice.h>
 #include <asm/unaligned.h>
diff --git a/drivers/net/wireless/iwlegacy/iwl-3945-rs.c b/drivers/net/wireless/iwlegacy/iwl-3945-rs.c
index 977bd2477c6a..0cc5177d738d 100644
--- a/drivers/net/wireless/iwlegacy/iwl-3945-rs.c
+++ b/drivers/net/wireless/iwlegacy/iwl-3945-rs.c
@@ -28,7 +28,6 @@
 #include <linux/init.h>
 #include <linux/skbuff.h>
 #include <linux/slab.h>
-#include <linux/wireless.h>
 #include <net/mac80211.h>
 
 #include <linux/netdevice.h>
diff --git a/drivers/net/wireless/iwlegacy/iwl-3945.c b/drivers/net/wireless/iwlegacy/iwl-3945.c
index 73fe3cdf796b..f7c0a7438476 100644
--- a/drivers/net/wireless/iwlegacy/iwl-3945.c
+++ b/drivers/net/wireless/iwlegacy/iwl-3945.c
@@ -34,7 +34,6 @@
 #include <linux/sched.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
-#include <linux/wireless.h>
 #include <linux/firmware.h>
 #include <linux/etherdevice.h>
 #include <asm/unaligned.h>
diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-led.c b/drivers/net/wireless/iwlegacy/iwl-4965-led.c
index 26d324e30692..6862fdcaee62 100644
--- a/drivers/net/wireless/iwlegacy/iwl-4965-led.c
+++ b/drivers/net/wireless/iwlegacy/iwl-4965-led.c
@@ -32,7 +32,6 @@
 #include <linux/delay.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
-#include <linux/wireless.h>
 #include <net/mac80211.h>
 #include <linux/etherdevice.h>
 #include <asm/unaligned.h>
diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-rs.c b/drivers/net/wireless/iwlegacy/iwl-4965-rs.c
index 9b65153bdd01..57ebe214e68c 100644
--- a/drivers/net/wireless/iwlegacy/iwl-4965-rs.c
+++ b/drivers/net/wireless/iwlegacy/iwl-4965-rs.c
@@ -27,7 +27,6 @@
 #include <linux/init.h>
 #include <linux/skbuff.h>
 #include <linux/slab.h>
-#include <linux/wireless.h>
 #include <net/mac80211.h>
 
 #include <linux/netdevice.h>
diff --git a/drivers/net/wireless/iwlegacy/iwl-4965.c b/drivers/net/wireless/iwlegacy/iwl-4965.c
index ecdc6e557428..86f4fce193e4 100644
--- a/drivers/net/wireless/iwlegacy/iwl-4965.c
+++ b/drivers/net/wireless/iwlegacy/iwl-4965.c
@@ -33,7 +33,6 @@
 #include <linux/sched.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
-#include <linux/wireless.h>
 #include <net/mac80211.h>
 #include <linux/etherdevice.h>
 #include <asm/unaligned.h>
diff --git a/drivers/net/wireless/iwlegacy/iwl-led.c b/drivers/net/wireless/iwlegacy/iwl-led.c
index bda0d61b2c0d..dc568a474c5d 100644
--- a/drivers/net/wireless/iwlegacy/iwl-led.c
+++ b/drivers/net/wireless/iwlegacy/iwl-led.c
@@ -33,7 +33,6 @@
 #include <linux/delay.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
-#include <linux/wireless.h>
 #include <net/mac80211.h>
 #include <linux/etherdevice.h>
 #include <asm/unaligned.h>
diff --git a/drivers/net/wireless/iwlegacy/iwl3945-base.c b/drivers/net/wireless/iwlegacy/iwl3945-base.c
index 795826a014ed..015739d204f2 100644
--- a/drivers/net/wireless/iwlegacy/iwl3945-base.c
+++ b/drivers/net/wireless/iwlegacy/iwl3945-base.c
@@ -40,7 +40,6 @@
 #include <linux/sched.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
-#include <linux/wireless.h>
 #include <linux/firmware.h>
 #include <linux/etherdevice.h>
 #include <linux/if_arp.h>
diff --git a/drivers/net/wireless/iwlegacy/iwl4965-base.c b/drivers/net/wireless/iwlegacy/iwl4965-base.c
index 14334668034e..6bc5575c8dff 100644
--- a/drivers/net/wireless/iwlegacy/iwl4965-base.c
+++ b/drivers/net/wireless/iwlegacy/iwl4965-base.c
@@ -40,7 +40,6 @@
 #include <linux/sched.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
-#include <linux/wireless.h>
 #include <linux/firmware.h>
 #include <linux/etherdevice.h>
 #include <linux/if_arp.h>
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index ad3bdba6beed..1d7572f9887f 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -111,20 +111,3 @@ config IWLWIFI_DEVICE_SVTOOL
 	  NL80211_TESTMODE. svtool is a software validation tool that runs in
 	  the user space and interacts with the device in the kernel space
 	  through the generic netlink message via NL80211_TESTMODE channel.
-
-config IWL_P2P
-	bool "iwlwifi experimental P2P support"
-	depends on IWLAGN
-	help
-	  This option enables experimental P2P support for some devices
-	  based on microcode support. Since P2P support is still under
-	  development, this option may even enable it for some devices
-	  now that turn out to not support it in the future due to
-	  microcode restrictions.
-
-	  To determine if your microcode supports the experimental P2P
-	  offered by this option, check if the driver advertises AP
-	  support when it is loaded.
-
-	  Say Y only if you want to experiment with P2P.
-
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index 01b49eb8c8ec..ccdbed567171 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -30,7 +30,6 @@
 #include <linux/delay.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
-#include <linux/wireless.h>
 #include <net/mac80211.h>
 #include <linux/etherdevice.h>
 #include <asm/unaligned.h>
@@ -46,8 +45,12 @@
 #include "iwl-agn-hw.h"
 
 /* Highest firmware API version supported */
-#define IWL1000_UCODE_API_MAX 5
-#define IWL100_UCODE_API_MAX 5
+#define IWL1000_UCODE_API_MAX 6
+#define IWL100_UCODE_API_MAX 6
+
+/* Oldest version we won't warn about */
+#define IWL1000_UCODE_API_OK 5
+#define IWL100_UCODE_API_OK 5
 
 /* Lowest firmware API version supported */
 #define IWL1000_UCODE_API_MIN 1
@@ -135,8 +138,7 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv)
 	priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE;
 	priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE;
 
-	priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
-					BIT(IEEE80211_BAND_5GHZ);
+	priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ);
 
 	priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
 	if (priv->cfg->rx_with_siso_diversity)
@@ -201,12 +203,13 @@ static struct iwl_base_params iwl1000_base_params = {
 static struct iwl_ht_params iwl1000_ht_params = {
 	.ht_greenfield_support = true,
 	.use_rts_for_aggregation = true, /* use rts/cts protection */
-	.smps_mode = IEEE80211_SMPS_STATIC,
+	.smps_mode = IEEE80211_SMPS_DYNAMIC,
 };
 
 #define IWL_DEVICE_1000						\
 	.fw_name_pre = IWL1000_FW_PRE,				\
 	.ucode_api_max = IWL1000_UCODE_API_MAX,			\
+	.ucode_api_ok = IWL1000_UCODE_API_OK,			\
 	.ucode_api_min = IWL1000_UCODE_API_MIN,			\
 	.eeprom_ver = EEPROM_1000_EEPROM_VERSION,		\
 	.eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,	\
@@ -228,6 +231,7 @@ struct iwl_cfg iwl1000_bg_cfg = {
 #define IWL_DEVICE_100						\
 	.fw_name_pre = IWL100_FW_PRE,				\
 	.ucode_api_max = IWL100_UCODE_API_MAX,			\
+	.ucode_api_ok = IWL100_UCODE_API_OK,			\
 	.ucode_api_min = IWL100_UCODE_API_MIN,			\
 	.eeprom_ver = EEPROM_1000_EEPROM_VERSION,		\
 	.eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,	\
diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c
index 0e13f0bb2e17..54d931d614fb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-2000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-2000.c
@@ -30,7 +30,6 @@
 #include <linux/delay.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
-#include <linux/wireless.h>
 #include <net/mac80211.h>
 #include <linux/etherdevice.h>
 #include <asm/unaligned.h>
@@ -47,10 +46,16 @@
 #include "iwl-6000-hw.h"
 
 /* Highest firmware API version supported */
-#define IWL2030_UCODE_API_MAX 5
-#define IWL2000_UCODE_API_MAX 5
-#define IWL105_UCODE_API_MAX 5
-#define IWL135_UCODE_API_MAX 5
+#define IWL2030_UCODE_API_MAX 6
+#define IWL2000_UCODE_API_MAX 6
+#define IWL105_UCODE_API_MAX 6
+#define IWL135_UCODE_API_MAX 6
+
+/* Oldest version we won't warn about */
+#define IWL2030_UCODE_API_OK 5
+#define IWL2000_UCODE_API_OK 5
+#define IWL105_UCODE_API_OK 5
+#define IWL135_UCODE_API_OK 5
 
 /* Lowest firmware API version supported */
 #define IWL2030_UCODE_API_MIN 5
@@ -130,8 +135,7 @@ static int iwl2000_hw_set_hw_params(struct iwl_priv *priv)
 	priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE;
 	priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE;
 
-	priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
-					BIT(IEEE80211_BAND_5GHZ);
+	priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ);
 
 	priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
 	if (priv->cfg->rx_with_siso_diversity)
@@ -217,6 +221,7 @@ static struct iwl_base_params iwl2000_base_params = {
 	.wd_timeout = IWL_DEF_WD_TIMEOUT,
 	.max_event_log_size = 512,
 	.shadow_reg_enable = true,
+	.hd_v2 = true,
 };
 
 
@@ -236,6 +241,7 @@ static struct iwl_base_params iwl2030_base_params = {
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
 	.max_event_log_size = 512,
 	.shadow_reg_enable = true,
+	.hd_v2 = true,
 };
 
 static struct iwl_ht_params iwl2000_ht_params = {
@@ -256,6 +262,7 @@ static struct iwl_bt_params iwl2030_bt_params = {
 #define IWL_DEVICE_2000						\
 	.fw_name_pre = IWL2000_FW_PRE,				\
 	.ucode_api_max = IWL2000_UCODE_API_MAX,			\
+	.ucode_api_ok = IWL2000_UCODE_API_OK,			\
 	.ucode_api_min = IWL2000_UCODE_API_MIN,			\
 	.eeprom_ver = EEPROM_2000_EEPROM_VERSION,		\
 	.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,	\
@@ -280,6 +287,7 @@ struct iwl_cfg iwl2000_2bg_cfg = {
 #define IWL_DEVICE_2030						\
 	.fw_name_pre = IWL2030_FW_PRE,				\
 	.ucode_api_max = IWL2030_UCODE_API_MAX,			\
+	.ucode_api_ok = IWL2030_UCODE_API_OK,			\
 	.ucode_api_min = IWL2030_UCODE_API_MIN,			\
 	.eeprom_ver = EEPROM_2000_EEPROM_VERSION,		\
 	.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,	\
@@ -306,6 +314,7 @@ struct iwl_cfg iwl2030_2bg_cfg = {
 #define IWL_DEVICE_105						\
 	.fw_name_pre = IWL105_FW_PRE,				\
 	.ucode_api_max = IWL105_UCODE_API_MAX,			\
+	.ucode_api_ok = IWL105_UCODE_API_OK,			\
 	.ucode_api_min = IWL105_UCODE_API_MIN,			\
 	.eeprom_ver = EEPROM_2000_EEPROM_VERSION,		\
 	.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,	\
@@ -332,6 +341,7 @@ struct iwl_cfg iwl105_bgn_cfg = {
 #define IWL_DEVICE_135						\
 	.fw_name_pre = IWL135_FW_PRE,				\
 	.ucode_api_max = IWL135_UCODE_API_MAX,			\
+	.ucode_api_ok = IWL135_UCODE_API_OK,			\
 	.ucode_api_min = IWL135_UCODE_API_MIN,			\
 	.eeprom_ver = EEPROM_2000_EEPROM_VERSION,		\
 	.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,	\
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index c95cefd529dc..a9adee5634d8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -31,7 +31,6 @@
 #include <linux/sched.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
-#include <linux/wireless.h>
 #include <net/mac80211.h>
 #include <linux/etherdevice.h>
 #include <asm/unaligned.h>
@@ -84,12 +83,12 @@ static void iwl5000_nic_config(struct iwl_priv *priv)
 }
 
 static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
-	.min_nrg_cck = 95,
+	.min_nrg_cck = 100,
 	.max_nrg_cck = 0, /* not used, set to 0 */
 	.auto_corr_min_ofdm = 90,
 	.auto_corr_min_ofdm_mrc = 170,
-	.auto_corr_min_ofdm_x1 = 120,
-	.auto_corr_min_ofdm_mrc_x1 = 240,
+	.auto_corr_min_ofdm_x1 = 105,
+	.auto_corr_min_ofdm_mrc_x1 = 220,
 
 	.auto_corr_max_ofdm = 120,
 	.auto_corr_max_ofdm_mrc = 210,
@@ -98,10 +97,10 @@ static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
 
 	.auto_corr_min_cck = 125,
 	.auto_corr_max_cck = 200,
-	.auto_corr_min_cck_mrc = 170,
+	.auto_corr_min_cck_mrc = 200,
 	.auto_corr_max_cck_mrc = 400,
-	.nrg_th_cck = 95,
-	.nrg_th_ofdm = 95,
+	.nrg_th_cck = 100,
+	.nrg_th_ofdm = 100,
 
 	.barker_corr_th_min = 190,
 	.barker_corr_th_min_mrc = 390,
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index 973d1972e8cc..339de88d9ae2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -30,7 +30,6 @@
 #include <linux/delay.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
-#include <linux/wireless.h>
 #include <net/mac80211.h>
 #include <linux/etherdevice.h>
 #include <asm/unaligned.h>
@@ -50,7 +49,10 @@
 /* Highest firmware API version supported */
 #define IWL6000_UCODE_API_MAX 4
 #define IWL6050_UCODE_API_MAX 5
-#define IWL6000G2_UCODE_API_MAX 5
+#define IWL6000G2_UCODE_API_MAX 6
+
+/* Oldest version we won't warn about */
+#define IWL6000G2_UCODE_API_OK 5
 
 /* Lowest firmware API version supported */
 #define IWL6000_UCODE_API_MIN 4
@@ -111,7 +113,7 @@ static void iwl6000_nic_config(struct iwl_priv *priv)
 }
 
 static struct iwl_sensitivity_ranges iwl6000_sensitivity = {
-	.min_nrg_cck = 97,
+	.min_nrg_cck = 110,
 	.max_nrg_cck = 0, /* not used, set to 0 */
 	.auto_corr_min_ofdm = 80,
 	.auto_corr_min_ofdm_mrc = 128,
@@ -127,11 +129,11 @@ static struct iwl_sensitivity_ranges iwl6000_sensitivity = {
 	.auto_corr_max_cck = 175,
 	.auto_corr_min_cck_mrc = 160,
 	.auto_corr_max_cck_mrc = 310,
-	.nrg_th_cck = 97,
-	.nrg_th_ofdm = 100,
+	.nrg_th_cck = 110,
+	.nrg_th_ofdm = 110,
 
 	.barker_corr_th_min = 190,
-	.barker_corr_th_min_mrc = 390,
+	.barker_corr_th_min_mrc = 336,
 	.nrg_th_cca = 62,
 };
 
@@ -365,8 +367,9 @@ static struct iwl_bt_params iwl6000_bt_params = {
 };
 
 #define IWL_DEVICE_6005						\
-	.fw_name_pre = IWL6005_FW_PRE,			\
+	.fw_name_pre = IWL6005_FW_PRE,				\
 	.ucode_api_max = IWL6000G2_UCODE_API_MAX,		\
+	.ucode_api_ok = IWL6000G2_UCODE_API_OK,			\
 	.ucode_api_min = IWL6000G2_UCODE_API_MIN,		\
 	.eeprom_ver = EEPROM_6005_EEPROM_VERSION,		\
 	.eeprom_calib_ver = EEPROM_6005_TX_POWER_VERSION,	\
@@ -393,8 +396,9 @@ struct iwl_cfg iwl6005_2bg_cfg = {
 };
 
 #define IWL_DEVICE_6030						\
-	.fw_name_pre = IWL6030_FW_PRE,			\
+	.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,		\
 	.eeprom_ver = EEPROM_6030_EEPROM_VERSION,		\
 	.eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION,	\
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
index 72d6297602b8..1789e3af8101 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
@@ -505,28 +505,53 @@ static int iwl_enhance_sensitivity_write(struct iwl_priv *priv)
 
 	iwl_prepare_legacy_sensitivity_tbl(priv, data, &cmd.enhance_table[0]);
 
-	cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX] =
-		HD_INA_NON_SQUARE_DET_OFDM_DATA;
-	cmd.enhance_table[HD_INA_NON_SQUARE_DET_CCK_INDEX] =
-		HD_INA_NON_SQUARE_DET_CCK_DATA;
-	cmd.enhance_table[HD_CORR_11_INSTEAD_OF_CORR_9_EN_INDEX] =
-		HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA;
-	cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
-		HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA;
-	cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
-		HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA;
-	cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_INDEX] =
-		HD_OFDM_NON_SQUARE_DET_SLOPE_DATA;
-	cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_INDEX] =
-		HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA;
-	cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
-		HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA;
-	cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
-		HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA;
-	cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_INDEX] =
-		HD_CCK_NON_SQUARE_DET_SLOPE_DATA;
-	cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_INDEX] =
-		HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA;
+	if (priv->cfg->base_params->hd_v2) {
+		cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX] =
+			HD_INA_NON_SQUARE_DET_OFDM_DATA_V2;
+		cmd.enhance_table[HD_INA_NON_SQUARE_DET_CCK_INDEX] =
+			HD_INA_NON_SQUARE_DET_CCK_DATA_V2;
+		cmd.enhance_table[HD_CORR_11_INSTEAD_OF_CORR_9_EN_INDEX] =
+			HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V2;
+		cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
+			HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V2;
+		cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
+			HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2;
+		cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_INDEX] =
+			HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V2;
+		cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_INDEX] =
+			HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V2;
+		cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
+			HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V2;
+		cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
+			HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2;
+		cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_INDEX] =
+			HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V2;
+		cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_INDEX] =
+			HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V2;
+	} else {
+		cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX] =
+			HD_INA_NON_SQUARE_DET_OFDM_DATA_V1;
+		cmd.enhance_table[HD_INA_NON_SQUARE_DET_CCK_INDEX] =
+			HD_INA_NON_SQUARE_DET_CCK_DATA_V1;
+		cmd.enhance_table[HD_CORR_11_INSTEAD_OF_CORR_9_EN_INDEX] =
+			HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V1;
+		cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
+			HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V1;
+		cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
+			HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1;
+		cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_INDEX] =
+			HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V1;
+		cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_INDEX] =
+			HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V1;
+		cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
+			HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V1;
+		cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
+			HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1;
+		cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_INDEX] =
+			HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V1;
+		cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_INDEX] =
+			HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V1;
+	}
 
 	/* Update uCode's "work" table, and copy it to DSP */
 	cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE;
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h
index 0e5b842529c4..47c43042ba4f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h
@@ -92,8 +92,8 @@
 
 #define IWLAGN_CMD_FIFO_NUM		7
 #define IWLAGN_NUM_QUEUES		20
-#define IWLAGN_NUM_AMPDU_QUEUES		10
-#define IWLAGN_FIRST_AMPDU_QUEUE	10
+#define IWLAGN_NUM_AMPDU_QUEUES		9
+#define IWLAGN_FIRST_AMPDU_QUEUE	11
 
 /* Fixed (non-configurable) rx data from phy */
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
index 3bee0f119bcd..4edb6cfc5488 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
@@ -753,18 +753,6 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
 	return added;
 }
 
-static int iwl_fill_offch_tx(struct iwl_priv *priv, void *data, size_t maxlen)
-{
-	struct sk_buff *skb = priv->offchan_tx_skb;
-
-	if (skb->len < maxlen)
-		maxlen = skb->len;
-
-	memcpy(data, skb->data, maxlen);
-
-	return maxlen;
-}
-
 int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
 	struct iwl_host_cmd cmd = {
@@ -807,7 +795,7 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
 	scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
 	scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
 
-	if (priv->scan_type != IWL_SCAN_OFFCH_TX &&
+	if (priv->scan_type != IWL_SCAN_ROC &&
 	    iwl_is_any_associated(priv)) {
 		u16 interval = 0;
 		u32 extra;
@@ -816,7 +804,7 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
 
 		IWL_DEBUG_INFO(priv, "Scanning while associated...\n");
 		switch (priv->scan_type) {
-		case IWL_SCAN_OFFCH_TX:
+		case IWL_SCAN_ROC:
 			WARN_ON(1);
 			break;
 		case IWL_SCAN_RADIO_RESET:
@@ -838,10 +826,11 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
 		scan->suspend_time = cpu_to_le32(scan_suspend_time);
 		IWL_DEBUG_SCAN(priv, "suspend_time 0x%X beacon interval %d\n",
 			       scan_suspend_time, interval);
-	} else if (priv->scan_type == IWL_SCAN_OFFCH_TX) {
+	} else if (priv->scan_type == IWL_SCAN_ROC) {
 		scan->suspend_time = 0;
-		scan->max_out_time =
-			cpu_to_le32(1024 * priv->offchan_tx_timeout);
+		scan->max_out_time = 0;
+		scan->quiet_time = 0;
+		scan->quiet_plcp_th = 0;
 	}
 
 	switch (priv->scan_type) {
@@ -869,8 +858,8 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
 		} else
 			IWL_DEBUG_SCAN(priv, "Start passive scan.\n");
 		break;
-	case IWL_SCAN_OFFCH_TX:
-		IWL_DEBUG_SCAN(priv, "Start offchannel TX scan.\n");
+	case IWL_SCAN_ROC:
+		IWL_DEBUG_SCAN(priv, "Start ROC scan.\n");
 		break;
 	}
 
@@ -988,19 +977,13 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
 					IWL_MAX_SCAN_SIZE - sizeof(*scan));
 		break;
 	case IWL_SCAN_RADIO_RESET:
+	case IWL_SCAN_ROC:
 		/* use bcast addr, will not be transmitted but must be valid */
 		cmd_len = iwl_fill_probe_req(priv,
 					(struct ieee80211_mgmt *)scan->data,
 					iwl_bcast_addr, NULL, 0,
 					IWL_MAX_SCAN_SIZE - sizeof(*scan));
 		break;
-	case IWL_SCAN_OFFCH_TX:
-		cmd_len = iwl_fill_offch_tx(priv, scan->data,
-					    IWL_MAX_SCAN_SIZE
-					     - sizeof(*scan)
-					     - sizeof(struct iwl_scan_channel));
-		scan->scan_flags |= IWL_SCAN_FLAGS_ACTION_FRAME_TX;
-		break;
 	default:
 		BUG();
 	}
@@ -1021,18 +1004,18 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
 				is_active, n_probes,
 				(void *)&scan->data[cmd_len]);
 		break;
-	case IWL_SCAN_OFFCH_TX: {
+	case IWL_SCAN_ROC: {
 		struct iwl_scan_channel *scan_ch;
 
 		scan->channel_count = 1;
 
 		scan_ch = (void *)&scan->data[cmd_len];
-		scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
+		scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
 		scan_ch->channel =
-			cpu_to_le16(priv->offchan_tx_chan->hw_value);
+			cpu_to_le16(priv->hw_roc_channel->hw_value);
 		scan_ch->active_dwell =
-			cpu_to_le16(priv->offchan_tx_timeout);
-		scan_ch->passive_dwell = 0;
+		scan_ch->passive_dwell =
+			cpu_to_le16(priv->hw_roc_duration);
 
 		/* Set txpower levels to defaults */
 		scan_ch->dsp_atten = 110;
@@ -1041,7 +1024,7 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
 		 * power level:
 		 * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3;
 		 */
-		if (priv->offchan_tx_chan->band == IEEE80211_BAND_5GHZ)
+		if (priv->hw_roc_channel->band == IEEE80211_BAND_5GHZ)
 			scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
 		else
 			scan_ch->tx_gain = ((1 << 5) | (5 << 3));
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index 3789ff4bf53b..1fa438e20f0a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -27,7 +27,6 @@
 #include <linux/init.h>
 #include <linux/skbuff.h>
 #include <linux/slab.h>
-#include <linux/wireless.h>
 #include <net/mac80211.h>
 
 #include <linux/netdevice.h>
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
index d42ef1763a71..d562e9359d97 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
@@ -337,10 +337,10 @@ int iwlagn_set_pan_params(struct iwl_priv *priv)
 	cmd.slots[0].type = 0; /* BSS */
 	cmd.slots[1].type = 1; /* PAN */
 
-	if (priv->hw_roc_channel) {
+	if (priv->hw_roc_setup) {
 		/* both contexts must be used for this to happen */
-		slot1 = priv->hw_roc_duration;
-		slot0 = IWL_MIN_SLOT_TIME;
+		slot1 = IWL_MIN_SLOT_TIME;
+		slot0 = 3000;
 	} else if (ctx_bss->vif && ctx_pan->vif) {
 		int bcnint = ctx_pan->beacon_int;
 		int dtim = ctx_pan->vif->bss_conf.dtim_period ?: 1;
@@ -437,23 +437,6 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
 	/* always get timestamp with Rx frame */
 	ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK;
 
-	if (ctx->ctxid == IWL_RXON_CTX_PAN && priv->hw_roc_channel) {
-		struct ieee80211_channel *chan = priv->hw_roc_channel;
-
-		iwl_set_rxon_channel(priv, chan, ctx);
-		iwl_set_flags_for_band(priv, ctx, chan->band, NULL);
-		ctx->staging.filter_flags |=
-			RXON_FILTER_ASSOC_MSK |
-			RXON_FILTER_PROMISC_MSK |
-			RXON_FILTER_CTL2HOST_MSK;
-		ctx->staging.dev_type = RXON_DEV_TYPE_P2P;
-		new_assoc = true;
-
-		if (memcmp(&ctx->staging, &ctx->active,
-			   sizeof(ctx->staging)) == 0)
-			return 0;
-	}
-
 	/*
 	 * force CTS-to-self frames protection if RTS-CTS is not preferred
 	 * one aggregation protection method
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index 53bb59ee719d..9bc26da62768 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -128,11 +128,10 @@ static void iwlagn_tx_cmd_protection(struct iwl_priv *priv,
  * handle build REPLY_TX command notification.
  */
 static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv,
-					struct sk_buff *skb,
-					struct iwl_tx_cmd *tx_cmd,
-					struct ieee80211_tx_info *info,
-					struct ieee80211_hdr *hdr,
-					u8 std_id)
+				      struct sk_buff *skb,
+				      struct iwl_tx_cmd *tx_cmd,
+				      struct ieee80211_tx_info *info,
+				      struct ieee80211_hdr *hdr, u8 sta_id)
 {
 	__le16 fc = hdr->frame_control;
 	__le32 tx_flags = tx_cmd->tx_flags;
@@ -157,7 +156,7 @@ static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv,
 		tx_flags |= TX_CMD_FLG_IGNORE_BT;
 
 
-	tx_cmd->sta_id = std_id;
+	tx_cmd->sta_id = sta_id;
 	if (ieee80211_has_morefrags(fc))
 		tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
 
@@ -189,9 +188,9 @@ static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv,
 #define RTS_DFAULT_RETRY_LIMIT		60
 
 static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv,
-			      struct iwl_tx_cmd *tx_cmd,
-			      struct ieee80211_tx_info *info,
-			      __le16 fc)
+				     struct iwl_tx_cmd *tx_cmd,
+				     struct ieee80211_tx_info *info,
+				     __le16 fc)
 {
 	u32 rate_flags;
 	int rate_idx;
@@ -334,14 +333,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 	unsigned long flags;
 	bool is_agg = false;
 
-	/*
-	 * If the frame needs to go out off-channel, then
-	 * we'll have put the PAN context to that channel,
-	 * so make the frame go out there.
-	 */
-	if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
-		ctx = &priv->contexts[IWL_RXON_CTX_PAN];
-	else if (info->control.vif)
+	if (info->control.vif)
 		ctx = iwl_rxon_ctx_from_vif(info->control.vif);
 
 	spin_lock_irqsave(&priv->lock, flags);
@@ -407,7 +399,9 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 		 */
 		hdr->frame_control |=
 			cpu_to_le16(IEEE80211_FCTL_MOREDATA);
-	} else
+	} else if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
+		txq_id = IWL_AUX_QUEUE;
+	else
 		txq_id = ctx->ac_to_queue[skb_get_queue_mapping(skb)];
 
 	/* irqs already disabled/saved above when locking priv->lock */
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index b0ae4de7f083..33894dde1ae3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -35,7 +35,6 @@
 #include <linux/sched.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
-#include <linux/wireless.h>
 #include <linux/firmware.h>
 #include <linux/etherdevice.h>
 #include <linux/if_arp.h>
@@ -614,6 +613,87 @@ static int iwl_alloc_fw_desc(struct iwl_priv *priv, struct fw_desc *desc,
 	return 0;
 }
 
+static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
+{
+	static const u8 iwlagn_bss_ac_to_fifo[] = {
+		IWL_TX_FIFO_VO,
+		IWL_TX_FIFO_VI,
+		IWL_TX_FIFO_BE,
+		IWL_TX_FIFO_BK,
+	};
+	static const u8 iwlagn_bss_ac_to_queue[] = {
+		0, 1, 2, 3,
+	};
+	static const u8 iwlagn_pan_ac_to_fifo[] = {
+		IWL_TX_FIFO_VO_IPAN,
+		IWL_TX_FIFO_VI_IPAN,
+		IWL_TX_FIFO_BE_IPAN,
+		IWL_TX_FIFO_BK_IPAN,
+	};
+	static const u8 iwlagn_pan_ac_to_queue[] = {
+		7, 6, 5, 4,
+	};
+	int i;
+
+	/*
+	 * The default context is always valid,
+	 * the PAN context depends on uCode.
+	 */
+	priv->valid_contexts = BIT(IWL_RXON_CTX_BSS);
+	if (ucode_flags & IWL_UCODE_TLV_FLAGS_PAN)
+		priv->valid_contexts |= BIT(IWL_RXON_CTX_PAN);
+
+	for (i = 0; i < NUM_IWL_RXON_CTX; i++)
+		priv->contexts[i].ctxid = i;
+
+	priv->contexts[IWL_RXON_CTX_BSS].always_active = true;
+	priv->contexts[IWL_RXON_CTX_BSS].is_active = true;
+	priv->contexts[IWL_RXON_CTX_BSS].rxon_cmd = REPLY_RXON;
+	priv->contexts[IWL_RXON_CTX_BSS].rxon_timing_cmd = REPLY_RXON_TIMING;
+	priv->contexts[IWL_RXON_CTX_BSS].rxon_assoc_cmd = REPLY_RXON_ASSOC;
+	priv->contexts[IWL_RXON_CTX_BSS].qos_cmd = REPLY_QOS_PARAM;
+	priv->contexts[IWL_RXON_CTX_BSS].ap_sta_id = IWL_AP_ID;
+	priv->contexts[IWL_RXON_CTX_BSS].wep_key_cmd = REPLY_WEPKEY;
+	priv->contexts[IWL_RXON_CTX_BSS].ac_to_fifo = iwlagn_bss_ac_to_fifo;
+	priv->contexts[IWL_RXON_CTX_BSS].ac_to_queue = iwlagn_bss_ac_to_queue;
+	priv->contexts[IWL_RXON_CTX_BSS].exclusive_interface_modes =
+		BIT(NL80211_IFTYPE_ADHOC);
+	priv->contexts[IWL_RXON_CTX_BSS].interface_modes =
+		BIT(NL80211_IFTYPE_STATION);
+	priv->contexts[IWL_RXON_CTX_BSS].ap_devtype = RXON_DEV_TYPE_AP;
+	priv->contexts[IWL_RXON_CTX_BSS].ibss_devtype = RXON_DEV_TYPE_IBSS;
+	priv->contexts[IWL_RXON_CTX_BSS].station_devtype = RXON_DEV_TYPE_ESS;
+	priv->contexts[IWL_RXON_CTX_BSS].unused_devtype = RXON_DEV_TYPE_ESS;
+
+	priv->contexts[IWL_RXON_CTX_PAN].rxon_cmd = REPLY_WIPAN_RXON;
+	priv->contexts[IWL_RXON_CTX_PAN].rxon_timing_cmd =
+		REPLY_WIPAN_RXON_TIMING;
+	priv->contexts[IWL_RXON_CTX_PAN].rxon_assoc_cmd =
+		REPLY_WIPAN_RXON_ASSOC;
+	priv->contexts[IWL_RXON_CTX_PAN].qos_cmd = REPLY_WIPAN_QOS_PARAM;
+	priv->contexts[IWL_RXON_CTX_PAN].ap_sta_id = IWL_AP_ID_PAN;
+	priv->contexts[IWL_RXON_CTX_PAN].wep_key_cmd = REPLY_WIPAN_WEPKEY;
+	priv->contexts[IWL_RXON_CTX_PAN].bcast_sta_id = IWLAGN_PAN_BCAST_ID;
+	priv->contexts[IWL_RXON_CTX_PAN].station_flags = STA_FLG_PAN_STATION;
+	priv->contexts[IWL_RXON_CTX_PAN].ac_to_fifo = iwlagn_pan_ac_to_fifo;
+	priv->contexts[IWL_RXON_CTX_PAN].ac_to_queue = iwlagn_pan_ac_to_queue;
+	priv->contexts[IWL_RXON_CTX_PAN].mcast_queue = IWL_IPAN_MCAST_QUEUE;
+	priv->contexts[IWL_RXON_CTX_PAN].interface_modes =
+		BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP);
+
+	if (ucode_flags & IWL_UCODE_TLV_FLAGS_P2P)
+		priv->contexts[IWL_RXON_CTX_PAN].interface_modes |=
+			BIT(NL80211_IFTYPE_P2P_CLIENT) |
+			BIT(NL80211_IFTYPE_P2P_GO);
+
+	priv->contexts[IWL_RXON_CTX_PAN].ap_devtype = RXON_DEV_TYPE_CP;
+	priv->contexts[IWL_RXON_CTX_PAN].station_devtype = RXON_DEV_TYPE_2STA;
+	priv->contexts[IWL_RXON_CTX_PAN].unused_devtype = RXON_DEV_TYPE_P2P;
+
+	BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
+}
+
+
 struct iwlagn_ucode_capabilities {
 	u32 max_probe_length;
 	u32 standard_phy_calibration_size;
@@ -952,6 +1032,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
 	int err;
 	struct iwlagn_firmware_pieces pieces;
 	const unsigned int api_max = priv->cfg->ucode_api_max;
+	unsigned int api_ok = priv->cfg->ucode_api_ok;
 	const unsigned int api_min = priv->cfg->ucode_api_min;
 	u32 api_ver;
 	char buildstr[25];
@@ -962,10 +1043,13 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
 			IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE,
 	};
 
+	if (!api_ok)
+		api_ok = api_max;
+
 	memset(&pieces, 0, sizeof(pieces));
 
 	if (!ucode_raw) {
-		if (priv->fw_index <= priv->cfg->ucode_api_max)
+		if (priv->fw_index <= api_ok)
 			IWL_ERR(priv,
 				"request for firmware file '%s' failed.\n",
 				priv->firmware_name);
@@ -1011,12 +1095,18 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
 			goto try_again;
 		}
 
-		if (api_ver != api_max)
-			IWL_ERR(priv,
-				"Firmware has old API version. Expected v%u, "
-				"got v%u. New firmware can be obtained "
-				"from http://www.intellinuxwireless.org.\n",
-				api_max, api_ver);
+		if (api_ver < api_ok) {
+			if (api_ok != api_max)
+				IWL_ERR(priv, "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, "
+					"expected v%u, got v%u.\n",
+					api_max, api_ver);
+			IWL_ERR(priv, "New firmware can be obtained from "
+				      "http://www.intellinuxwireless.org/.\n");
+		}
 	}
 
 	if (build)
@@ -1143,17 +1233,23 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
 	priv->new_scan_threshold_behaviour =
 		!!(ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWSCAN);
 
-	if ((priv->cfg->sku & EEPROM_SKU_CAP_IPAN_ENABLE) &&
-	    (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN)) {
-		priv->valid_contexts |= BIT(IWL_RXON_CTX_PAN);
-		priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN;
-	} else
-		priv->sta_key_max_num = STA_KEY_MAX_NUM;
+	if (!(priv->cfg->sku & EEPROM_SKU_CAP_IPAN_ENABLE))
+		ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_PAN;
 
-	if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS))
+	/*
+	 * 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->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM;
-	else
+	} else {
+		priv->sta_key_max_num = STA_KEY_MAX_NUM;
 		priv->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM;
+	}
 
 	/*
 	 * figure out the offset of chain noise reset and gain commands
@@ -1169,6 +1265,9 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
 	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...
 	 *
@@ -1765,6 +1864,13 @@ static void __iwl_down(struct iwl_priv *priv)
 
 	iwl_scan_cancel_timeout(priv, 200);
 
+	/*
+	 * If active, scanning won't cancel it, so say it expired.
+	 * No race since we hold the mutex here and a new one
+	 * can't come in at this time.
+	 */
+	ieee80211_remain_on_channel_expired(priv->hw);
+
 	exit_pending = test_and_set_bit(STATUS_EXIT_PENDING, &priv->status);
 
 	/* Stop TX queues watchdog. We need to have STATUS_EXIT_PENDING bit set
@@ -1955,94 +2061,6 @@ static void iwl_bg_restart(struct work_struct *data)
 	}
 }
 
-static int iwl_mac_offchannel_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
-				 struct ieee80211_channel *chan,
-				 enum nl80211_channel_type channel_type,
-				 unsigned int wait)
-{
-	struct iwl_priv *priv = hw->priv;
-	int ret;
-
-	/* Not supported if we don't have PAN */
-	if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN))) {
-		ret = -EOPNOTSUPP;
-		goto free;
-	}
-
-	/* Not supported on pre-P2P firmware */
-	if (!(priv->contexts[IWL_RXON_CTX_PAN].interface_modes &
-					BIT(NL80211_IFTYPE_P2P_CLIENT))) {
-		ret = -EOPNOTSUPP;
-		goto free;
-	}
-
-	mutex_lock(&priv->mutex);
-
-	if (!priv->contexts[IWL_RXON_CTX_PAN].is_active) {
-		/*
-		 * If the PAN context is free, use the normal
-		 * way of doing remain-on-channel offload + TX.
-		 */
-		ret = 1;
-		goto out;
-	}
-
-	/* TODO: queue up if scanning? */
-	if (test_bit(STATUS_SCANNING, &priv->status) ||
-	    priv->offchan_tx_skb) {
-		ret = -EBUSY;
-		goto out;
-	}
-
-	/*
-	 * max_scan_ie_len doesn't include the blank SSID or the header,
-	 * so need to add that again here.
-	 */
-	if (skb->len > hw->wiphy->max_scan_ie_len + 24 + 2) {
-		ret = -ENOBUFS;
-		goto out;
-	}
-
-	priv->offchan_tx_skb = skb;
-	priv->offchan_tx_timeout = wait;
-	priv->offchan_tx_chan = chan;
-
-	ret = iwl_scan_initiate(priv, priv->contexts[IWL_RXON_CTX_PAN].vif,
-				IWL_SCAN_OFFCH_TX, chan->band);
-	if (ret)
-		priv->offchan_tx_skb = NULL;
- out:
-	mutex_unlock(&priv->mutex);
- free:
-	if (ret < 0)
-		kfree_skb(skb);
-
-	return ret;
-}
-
-static int iwl_mac_offchannel_tx_cancel_wait(struct ieee80211_hw *hw)
-{
-	struct iwl_priv *priv = hw->priv;
-	int ret;
-
-	mutex_lock(&priv->mutex);
-
-	if (!priv->offchan_tx_skb) {
-		ret = -EINVAL;
-		goto unlock;
-	}
-
-	priv->offchan_tx_skb = NULL;
-
-	ret = iwl_scan_cancel_timeout(priv, 200);
-	if (ret)
-		ret = -EIO;
-unlock:
-	mutex_unlock(&priv->mutex);
-
-	return ret;
-}
-
 /*****************************************************************************
  *
  * mac80211 entry point functions
@@ -3198,35 +3216,34 @@ done:
 	IWL_DEBUG_MAC80211(priv, "leave\n");
 }
 
-static void iwlagn_disable_roc(struct iwl_priv *priv)
+void iwlagn_disable_roc(struct iwl_priv *priv)
 {
 	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
-	struct ieee80211_channel *chan = ACCESS_ONCE(priv->hw->conf.channel);
 
 	lockdep_assert_held(&priv->mutex);
 
-	if (!ctx->is_active)
+	if (!priv->hw_roc_setup)
 		return;
 
-	ctx->staging.dev_type = RXON_DEV_TYPE_2STA;
+	ctx->staging.dev_type = RXON_DEV_TYPE_P2P;
 	ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-	iwl_set_rxon_channel(priv, chan, ctx);
-	iwl_set_flags_for_band(priv, ctx, chan->band, NULL);
 
 	priv->hw_roc_channel = NULL;
 
+	memset(ctx->staging.node_addr, 0, ETH_ALEN);
+
 	iwlagn_commit_rxon(priv, ctx);
 
 	ctx->is_active = false;
+	priv->hw_roc_setup = false;
 }
 
-static void iwlagn_bg_roc_done(struct work_struct *work)
+static void iwlagn_disable_roc_work(struct work_struct *work)
 {
 	struct iwl_priv *priv = container_of(work, struct iwl_priv,
-					     hw_roc_work.work);
+					     hw_roc_disable_work.work);
 
 	mutex_lock(&priv->mutex);
-	ieee80211_remain_on_channel_expired(priv->hw);
 	iwlagn_disable_roc(priv);
 	mutex_unlock(&priv->mutex);
 }
@@ -3237,33 +3254,63 @@ static int iwl_mac_remain_on_channel(struct ieee80211_hw *hw,
 				     int duration)
 {
 	struct iwl_priv *priv = hw->priv;
+	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
 	int err = 0;
 
 	if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
 		return -EOPNOTSUPP;
 
-	if (!(priv->contexts[IWL_RXON_CTX_PAN].interface_modes &
-					BIT(NL80211_IFTYPE_P2P_CLIENT)))
+	if (!(ctx->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)))
 		return -EOPNOTSUPP;
 
 	mutex_lock(&priv->mutex);
 
-	if (priv->contexts[IWL_RXON_CTX_PAN].is_active ||
-	    test_bit(STATUS_SCAN_HW, &priv->status)) {
+	/*
+	 * TODO: Remove this hack! Firmware needs to be updated
+	 * to allow longer off-channel periods in scanning for
+	 * this use case, based on a flag (and we'll need an API
+	 * flag in the firmware when it has that).
+	 */
+	if (iwl_is_associated(priv, IWL_RXON_CTX_BSS) && duration > 80)
+		duration = 80;
+
+	if (test_bit(STATUS_SCAN_HW, &priv->status)) {
 		err = -EBUSY;
 		goto out;
 	}
 
-	priv->contexts[IWL_RXON_CTX_PAN].is_active = true;
 	priv->hw_roc_channel = channel;
 	priv->hw_roc_chantype = channel_type;
-	priv->hw_roc_duration = DIV_ROUND_UP(duration * 1000, 1024);
-	iwlagn_commit_rxon(priv, &priv->contexts[IWL_RXON_CTX_PAN]);
-	queue_delayed_work(priv->workqueue, &priv->hw_roc_work,
-			   msecs_to_jiffies(duration + 20));
+	priv->hw_roc_duration = duration;
+	cancel_delayed_work(&priv->hw_roc_disable_work);
+
+	if (!ctx->is_active) {
+		ctx->is_active = true;
+		ctx->staging.dev_type = RXON_DEV_TYPE_P2P;
+		memcpy(ctx->staging.node_addr,
+		       priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr,
+		       ETH_ALEN);
+		memcpy(ctx->staging.bssid_addr,
+		       priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr,
+		       ETH_ALEN);
+		err = iwlagn_commit_rxon(priv, ctx);
+		if (err)
+			goto out;
+		ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK |
+					     RXON_FILTER_PROMISC_MSK |
+					     RXON_FILTER_CTL2HOST_MSK;
+
+		err = iwlagn_commit_rxon(priv, ctx);
+		if (err) {
+			iwlagn_disable_roc(priv);
+			goto out;
+		}
+		priv->hw_roc_setup = true;
+	}
 
-	msleep(IWL_MIN_SLOT_TIME); /* TU is almost ms */
-	ieee80211_ready_on_channel(priv->hw);
+	err = iwl_scan_initiate(priv, ctx->vif, IWL_SCAN_ROC, channel->band);
+	if (err)
+		iwlagn_disable_roc(priv);
 
  out:
 	mutex_unlock(&priv->mutex);
@@ -3278,9 +3325,8 @@ static int iwl_mac_cancel_remain_on_channel(struct ieee80211_hw *hw)
 	if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
 		return -EOPNOTSUPP;
 
-	cancel_delayed_work_sync(&priv->hw_roc_work);
-
 	mutex_lock(&priv->mutex);
+	iwl_scan_cancel_timeout(priv, priv->hw_roc_duration);
 	iwlagn_disable_roc(priv);
 	mutex_unlock(&priv->mutex);
 
@@ -3305,7 +3351,8 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
 	INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush);
 	INIT_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency);
 	INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config);
-	INIT_DELAYED_WORK(&priv->hw_roc_work, iwlagn_bg_roc_done);
+	INIT_DELAYED_WORK(&priv->hw_roc_disable_work,
+			  iwlagn_disable_roc_work);
 
 	iwl_setup_scan_deferred_work(priv);
 
@@ -3337,6 +3384,7 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
 
 	cancel_work_sync(&priv->bt_full_concurrency);
 	cancel_work_sync(&priv->bt_runtime_config);
+	cancel_delayed_work_sync(&priv->hw_roc_disable_work);
 
 	del_timer_sync(&priv->statistics_periodic);
 	del_timer_sync(&priv->ucode_trace);
@@ -3489,8 +3537,6 @@ struct ieee80211_ops iwlagn_hw_ops = {
 	.tx_last_beacon = iwl_mac_tx_last_beacon,
 	.remain_on_channel = iwl_mac_remain_on_channel,
 	.cancel_remain_on_channel = iwl_mac_cancel_remain_on_channel,
-	.offchannel_tx = iwl_mac_offchannel_tx,
-	.offchannel_tx_cancel_wait = iwl_mac_offchannel_tx_cancel_wait,
 	.rssi_callback = iwl_mac_rssi_callback,
 	CFG80211_TESTMODE_CMD(iwl_testmode_cmd)
 	CFG80211_TESTMODE_DUMP(iwl_testmode_dump)
@@ -3519,28 +3565,6 @@ static int iwl_set_hw_params(struct iwl_priv *priv)
 	return priv->cfg->lib->set_hw_params(priv);
 }
 
-static const u8 iwlagn_bss_ac_to_fifo[] = {
-	IWL_TX_FIFO_VO,
-	IWL_TX_FIFO_VI,
-	IWL_TX_FIFO_BE,
-	IWL_TX_FIFO_BK,
-};
-
-static const u8 iwlagn_bss_ac_to_queue[] = {
-	0, 1, 2, 3,
-};
-
-static const u8 iwlagn_pan_ac_to_fifo[] = {
-	IWL_TX_FIFO_VO_IPAN,
-	IWL_TX_FIFO_VI_IPAN,
-	IWL_TX_FIFO_BE_IPAN,
-	IWL_TX_FIFO_BK_IPAN,
-};
-
-static const u8 iwlagn_pan_ac_to_queue[] = {
-	7, 6, 5, 4,
-};
-
 /* This function both allocates and initializes hw and priv. */
 static struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg)
 {
@@ -3563,65 +3587,6 @@ out:
 	return hw;
 }
 
-static void iwl_init_context(struct iwl_priv *priv)
-{
-	int i;
-
-	/*
-	 * The default context is always valid,
-	 * more may be discovered when firmware
-	 * is loaded.
-	 */
-	priv->valid_contexts = BIT(IWL_RXON_CTX_BSS);
-
-	for (i = 0; i < NUM_IWL_RXON_CTX; i++)
-		priv->contexts[i].ctxid = i;
-
-	priv->contexts[IWL_RXON_CTX_BSS].always_active = true;
-	priv->contexts[IWL_RXON_CTX_BSS].is_active = true;
-	priv->contexts[IWL_RXON_CTX_BSS].rxon_cmd = REPLY_RXON;
-	priv->contexts[IWL_RXON_CTX_BSS].rxon_timing_cmd = REPLY_RXON_TIMING;
-	priv->contexts[IWL_RXON_CTX_BSS].rxon_assoc_cmd = REPLY_RXON_ASSOC;
-	priv->contexts[IWL_RXON_CTX_BSS].qos_cmd = REPLY_QOS_PARAM;
-	priv->contexts[IWL_RXON_CTX_BSS].ap_sta_id = IWL_AP_ID;
-	priv->contexts[IWL_RXON_CTX_BSS].wep_key_cmd = REPLY_WEPKEY;
-	priv->contexts[IWL_RXON_CTX_BSS].ac_to_fifo = iwlagn_bss_ac_to_fifo;
-	priv->contexts[IWL_RXON_CTX_BSS].ac_to_queue = iwlagn_bss_ac_to_queue;
-	priv->contexts[IWL_RXON_CTX_BSS].exclusive_interface_modes =
-		BIT(NL80211_IFTYPE_ADHOC);
-	priv->contexts[IWL_RXON_CTX_BSS].interface_modes =
-		BIT(NL80211_IFTYPE_STATION);
-	priv->contexts[IWL_RXON_CTX_BSS].ap_devtype = RXON_DEV_TYPE_AP;
-	priv->contexts[IWL_RXON_CTX_BSS].ibss_devtype = RXON_DEV_TYPE_IBSS;
-	priv->contexts[IWL_RXON_CTX_BSS].station_devtype = RXON_DEV_TYPE_ESS;
-	priv->contexts[IWL_RXON_CTX_BSS].unused_devtype = RXON_DEV_TYPE_ESS;
-
-	priv->contexts[IWL_RXON_CTX_PAN].rxon_cmd = REPLY_WIPAN_RXON;
-	priv->contexts[IWL_RXON_CTX_PAN].rxon_timing_cmd =
-		REPLY_WIPAN_RXON_TIMING;
-	priv->contexts[IWL_RXON_CTX_PAN].rxon_assoc_cmd =
-		REPLY_WIPAN_RXON_ASSOC;
-	priv->contexts[IWL_RXON_CTX_PAN].qos_cmd = REPLY_WIPAN_QOS_PARAM;
-	priv->contexts[IWL_RXON_CTX_PAN].ap_sta_id = IWL_AP_ID_PAN;
-	priv->contexts[IWL_RXON_CTX_PAN].wep_key_cmd = REPLY_WIPAN_WEPKEY;
-	priv->contexts[IWL_RXON_CTX_PAN].bcast_sta_id = IWLAGN_PAN_BCAST_ID;
-	priv->contexts[IWL_RXON_CTX_PAN].station_flags = STA_FLG_PAN_STATION;
-	priv->contexts[IWL_RXON_CTX_PAN].ac_to_fifo = iwlagn_pan_ac_to_fifo;
-	priv->contexts[IWL_RXON_CTX_PAN].ac_to_queue = iwlagn_pan_ac_to_queue;
-	priv->contexts[IWL_RXON_CTX_PAN].mcast_queue = IWL_IPAN_MCAST_QUEUE;
-	priv->contexts[IWL_RXON_CTX_PAN].interface_modes =
-		BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP);
-#ifdef CONFIG_IWL_P2P
-	priv->contexts[IWL_RXON_CTX_PAN].interface_modes |=
-		BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
-#endif
-	priv->contexts[IWL_RXON_CTX_PAN].ap_devtype = RXON_DEV_TYPE_CP;
-	priv->contexts[IWL_RXON_CTX_PAN].station_devtype = RXON_DEV_TYPE_2STA;
-	priv->contexts[IWL_RXON_CTX_PAN].unused_devtype = RXON_DEV_TYPE_P2P;
-
-	BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
-}
-
 int iwl_probe(struct iwl_bus *bus, struct iwl_cfg *cfg)
 {
 	int err = 0;
@@ -3724,9 +3689,6 @@ int iwl_probe(struct iwl_bus *bus, struct iwl_cfg *cfg)
 		priv->hw->wiphy->n_addresses++;
 	}
 
-	/* initialize all valid contexts */
-	iwl_init_context(priv);
-
 	/************************
 	 * 5. Setup HW constants
 	 ************************/
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h
index d941c4c98e4b..df2960ae92aa 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.h
@@ -209,6 +209,7 @@ u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx, u8 valid);
 /* scan */
 int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif);
 void iwlagn_post_scan(struct iwl_priv *priv);
+void iwlagn_disable_roc(struct iwl_priv *priv);
 
 /* station mgmt */
 int iwlagn_manage_ibss_station(struct iwl_priv *priv,
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index e9e9d1d1778d..0016c61b3000 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -3067,17 +3067,29 @@ struct iwl_missed_beacon_notif {
 /* number of additional entries for enhanced tbl */
 #define ENHANCE_HD_TABLE_ENTRIES  (ENHANCE_HD_TABLE_SIZE - HD_TABLE_SIZE)
 
-#define HD_INA_NON_SQUARE_DET_OFDM_DATA			cpu_to_le16(0)
-#define HD_INA_NON_SQUARE_DET_CCK_DATA			cpu_to_le16(0)
-#define HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA		cpu_to_le16(0)
-#define HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA		cpu_to_le16(668)
-#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA	cpu_to_le16(4)
-#define HD_OFDM_NON_SQUARE_DET_SLOPE_DATA		cpu_to_le16(486)
-#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA		cpu_to_le16(37)
-#define HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA		cpu_to_le16(853)
-#define HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA	cpu_to_le16(4)
-#define HD_CCK_NON_SQUARE_DET_SLOPE_DATA		cpu_to_le16(476)
-#define HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA		cpu_to_le16(99)
+#define HD_INA_NON_SQUARE_DET_OFDM_DATA_V1		cpu_to_le16(0)
+#define HD_INA_NON_SQUARE_DET_CCK_DATA_V1		cpu_to_le16(0)
+#define HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V1		cpu_to_le16(0)
+#define HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V1	cpu_to_le16(668)
+#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1	cpu_to_le16(4)
+#define HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V1		cpu_to_le16(486)
+#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V1	cpu_to_le16(37)
+#define HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V1		cpu_to_le16(853)
+#define HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1	cpu_to_le16(4)
+#define HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V1		cpu_to_le16(476)
+#define HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V1		cpu_to_le16(99)
+
+#define HD_INA_NON_SQUARE_DET_OFDM_DATA_V2		cpu_to_le16(1)
+#define HD_INA_NON_SQUARE_DET_CCK_DATA_V2		cpu_to_le16(1)
+#define HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V2		cpu_to_le16(1)
+#define HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V2	cpu_to_le16(600)
+#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2	cpu_to_le16(40)
+#define HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V2		cpu_to_le16(486)
+#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V2	cpu_to_le16(45)
+#define HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V2		cpu_to_le16(853)
+#define HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2	cpu_to_le16(60)
+#define HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V2		cpu_to_le16(476)
+#define HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V2		cpu_to_le16(99)
 
 
 /* Control field in struct iwl_sensitivity_cmd */
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index cf376f62b2f6..e269987cd64c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -40,6 +40,7 @@
 #include "iwl-io.h"
 #include "iwl-power.h"
 #include "iwl-sta.h"
+#include "iwl-agn.h"
 #include "iwl-helpers.h"
 #include "iwl-agn.h"
 #include "iwl-trans.h"
@@ -1273,8 +1274,12 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 	IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n",
 			   viftype, vif->addr);
 
+	cancel_delayed_work_sync(&priv->hw_roc_disable_work);
+
 	mutex_lock(&priv->mutex);
 
+	iwlagn_disable_roc(priv);
+
 	if (!iwl_is_ready_rf(priv)) {
 		IWL_WARN(priv, "Try to add interface when device not ready\n");
 		err = -EINVAL;
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 02817a438550..42bcb469d32c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -136,6 +136,7 @@ struct iwl_mod_params {
  * @max_event_log_size: size of event log buffer size for ucode event logging
  * @shadow_reg_enable: HW shadhow register bit
  * @no_idle_support: do not support idle mode
+ * @hd_v2: v2 of enhanced sensitivity value, used for 2000 series and up
  */
 struct iwl_base_params {
 	int eeprom_size;
@@ -158,6 +159,7 @@ struct iwl_base_params {
 	u32 max_event_log_size;
 	const bool shadow_reg_enable;
 	const bool no_idle_support;
+	const bool hd_v2;
 };
 /*
  * @advanced_bt_coexist: support advanced bt coexist
@@ -194,6 +196,8 @@ struct iwl_ht_params {
  *	(.ucode) will be added to filename before loading from disk. The
  *	filename is constructed as fw_name_pre<api>.ucode.
  * @ucode_api_max: Highest version of uCode API supported by driver.
+ * @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.
  * @valid_tx_ant: valid transmit antenna
  * @valid_rx_ant: valid receive antenna
@@ -237,6 +241,7 @@ struct iwl_cfg {
 	const char *name;
 	const char *fw_name_pre;
 	const unsigned int ucode_api_max;
+	const unsigned int ucode_api_ok;
 	const unsigned int ucode_api_min;
 	u8   valid_tx_ant;
 	u8   valid_rx_ant;
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 6c9790cac8d0..dd34c7c502fa 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -230,12 +230,23 @@ struct iwl_channel_info {
 #define IWL_TX_FIFO_BE_IPAN	4
 #define IWL_TX_FIFO_VI_IPAN	IWL_TX_FIFO_VI
 #define IWL_TX_FIFO_VO_IPAN	5
+/* re-uses the VO FIFO, uCode will properly flush/schedule */
+#define IWL_TX_FIFO_AUX		5
 #define IWL_TX_FIFO_UNUSED	-1
 
-/* Minimum number of queues. MAX_NUM is defined in hw specific files.
- * Set the minimum to accommodate the 4 standard TX queues, 1 command
- * queue, 2 (unused) HCCA queues, and 4 HT queues (one for each AC) */
-#define IWL_MIN_NUM_QUEUES	10
+/* AUX (TX during scan dwell) queue */
+#define IWL_AUX_QUEUE		10
+
+/*
+ * Minimum number of queues. MAX_NUM is defined in hw specific files.
+ * Set the minimum to accommodate
+ *  - 4 standard TX queues
+ *  - the command queue
+ *  - 4 PAN TX queues
+ *  - the PAN multicast queue, and
+ *  - the AUX (TX during scan dwell) queue.
+ */
+#define IWL_MIN_NUM_QUEUES	11
 
 /*
  * Command queue depends on iPAN support.
@@ -564,11 +575,13 @@ enum iwl_ucode_tlv_type {
  * @IWL_UCODE_TLV_FLAGS_NEWSCAN: new uCode scan behaviour on hidden SSID,
  *	treats good CRC threshold as a boolean
  * @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w).
+ * @IWL_UCODE_TLV_FLAGS_P2P: This uCode image supports P2P.
  */
 enum iwl_ucode_tlv_flag {
 	IWL_UCODE_TLV_FLAGS_PAN		= BIT(0),
 	IWL_UCODE_TLV_FLAGS_NEWSCAN	= BIT(1),
 	IWL_UCODE_TLV_FLAGS_MFP		= BIT(2),
+	IWL_UCODE_TLV_FLAGS_P2P		= BIT(3),
 };
 
 struct iwl_ucode_tlv {
@@ -1168,7 +1181,7 @@ struct iwl_rxon_context {
 enum iwl_scan_type {
 	IWL_SCAN_NORMAL,
 	IWL_SCAN_RADIO_RESET,
-	IWL_SCAN_OFFCH_TX,
+	IWL_SCAN_ROC,
 };
 
 enum iwlagn_ucode_type {
@@ -1438,15 +1451,11 @@ struct iwl_priv {
 
 	/* remain-on-channel offload support */
 	struct ieee80211_channel *hw_roc_channel;
-	struct delayed_work hw_roc_work;
+	struct delayed_work hw_roc_disable_work;
 	enum nl80211_channel_type hw_roc_chantype;
 	int hw_roc_duration;
 	bool hw_roc_setup;
 
-	struct sk_buff *offchan_tx_skb;
-	int offchan_tx_timeout;
-	struct ieee80211_channel *offchan_tx_chan;
-
 	/* bt coex */
 	u8 bt_enable_flag;
 	u8 bt_status;
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c
index a67ae56d5464..1a5252d8ca73 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-led.c
@@ -31,7 +31,6 @@
 #include <linux/delay.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
-#include <linux/wireless.h>
 #include <net/mac80211.h>
 #include <linux/etherdevice.h>
 #include <asm/unaligned.h>
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index dd6937e97055..28e59319f581 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -103,6 +103,12 @@ static void iwl_complete_scan(struct iwl_priv *priv, bool aborted)
 		ieee80211_scan_completed(priv->hw, aborted);
 	}
 
+	if (priv->scan_type == IWL_SCAN_ROC) {
+		ieee80211_remain_on_channel_expired(priv->hw);
+		priv->hw_roc_channel = NULL;
+		schedule_delayed_work(&priv->hw_roc_disable_work, 10 * HZ);
+	}
+
 	priv->scan_type = IWL_SCAN_NORMAL;
 	priv->scan_vif = NULL;
 	priv->scan_request = NULL;
@@ -211,6 +217,9 @@ static void iwl_rx_scan_start_notif(struct iwl_priv *priv,
 		       le32_to_cpu(notif->tsf_high),
 		       le32_to_cpu(notif->tsf_low),
 		       notif->status, notif->beacon_timer);
+
+	if (priv->scan_type == IWL_SCAN_ROC)
+		ieee80211_ready_on_channel(priv->hw);
 }
 
 /* Service SCAN_RESULTS_NOTIFICATION (0x83) */
@@ -370,7 +379,7 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv,
 
 	IWL_DEBUG_SCAN(priv, "Starting %sscan...\n",
 			scan_type == IWL_SCAN_NORMAL ? "" :
-			scan_type == IWL_SCAN_OFFCH_TX ? "offchan TX " :
+			scan_type == IWL_SCAN_ROC ? "remain-on-channel " :
 			"internal short ");
 
 	set_bit(STATUS_SCANNING, &priv->status);
@@ -565,10 +574,10 @@ static void iwl_bg_scan_completed(struct work_struct *work)
 		goto out_settings;
 	}
 
-	if (priv->scan_type == IWL_SCAN_OFFCH_TX && priv->offchan_tx_skb) {
-		ieee80211_tx_status_irqsafe(priv->hw,
-					    priv->offchan_tx_skb);
-		priv->offchan_tx_skb = NULL;
+	if (priv->scan_type == IWL_SCAN_ROC) {
+		ieee80211_remain_on_channel_expired(priv->hw);
+		priv->hw_roc_channel = NULL;
+		schedule_delayed_work(&priv->hw_roc_disable_work, 10 * HZ);
 	}
 
 	if (priv->scan_type != IWL_SCAN_NORMAL && !aborted) {
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.c b/drivers/net/wireless/iwlwifi/iwl-trans.c
index 41f0de914008..3001bfb46e25 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.c
@@ -750,6 +750,7 @@ static const struct queue_to_fifo_ac iwlagn_default_queue_to_tx_fifo[] = {
 	{ IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
 	{ IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
 	{ IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
+	{ IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
 };
 
 static const struct queue_to_fifo_ac iwlagn_ipan_queue_to_tx_fifo[] = {
@@ -763,6 +764,7 @@ static const struct queue_to_fifo_ac iwlagn_ipan_queue_to_tx_fifo[] = {
 	{ IWL_TX_FIFO_VO_IPAN, IEEE80211_AC_VO, },
 	{ IWL_TX_FIFO_BE_IPAN, 2, },
 	{ IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, },
+	{ IWL_TX_FIFO_AUX, IWL_AC_UNSET, },
 };
 static void iwl_trans_tx_start(struct iwl_priv *priv)
 {
@@ -848,10 +850,12 @@ static void iwl_trans_tx_start(struct iwl_priv *priv)
 	/* reset to 0 to enable all the queue first */
 	priv->txq_ctx_active_msk = 0;
 
-	BUILD_BUG_ON(ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo) != 10);
-	BUILD_BUG_ON(ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo) != 10);
+	BUILD_BUG_ON(ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo) !=
+						IWLAGN_FIRST_AMPDU_QUEUE);
+	BUILD_BUG_ON(ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo) !=
+						IWLAGN_FIRST_AMPDU_QUEUE);
 
-	for (i = 0; i < 10; i++) {
+	for (i = 0; i < IWLAGN_FIRST_AMPDU_QUEUE; i++) {
 		int fifo = queue_to_fifo[i].fifo;
 		int ac = queue_to_fifo[i].ac;
 
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index b456a53b64b1..85b3169c40d7 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -19,6 +19,7 @@
 #include "decl.h"
 #include "cfg.h"
 #include "cmd.h"
+#include "mesh.h"
 
 
 #define CHAN2G(_channel, _freq, _flags) {        \
@@ -442,13 +443,16 @@ static int lbs_cfg_set_channel(struct wiphy *wiphy,
 	struct lbs_private *priv = wiphy_priv(wiphy);
 	int ret = -ENOTSUPP;
 
-	lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d",
-			   channel->center_freq, channel_type);
+	lbs_deb_enter_args(LBS_DEB_CFG80211, "iface %s freq %d, type %d",
+			   netdev_name(netdev), channel->center_freq, channel_type);
 
 	if (channel_type != NL80211_CHAN_NO_HT)
 		goto out;
 
-	ret = lbs_set_channel(priv, channel->hw_value);
+	if (netdev == priv->mesh_dev)
+		ret = lbs_mesh_set_channel(priv, channel->hw_value);
+	else
+		ret = lbs_set_channel(priv, channel->hw_value);
 
  out:
 	lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
@@ -708,7 +712,7 @@ static void lbs_scan_worker(struct work_struct *work)
 
 	if (priv->scan_channel < priv->scan_req->n_channels) {
 		cancel_delayed_work(&priv->scan_work);
-		if (!priv->stopping)
+		if (netif_running(priv->dev))
 			queue_delayed_work(priv->work_thread, &priv->scan_work,
 				msecs_to_jiffies(300));
 	}
@@ -1292,6 +1296,9 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
 	int ret = 0;
 	u8 preamble = RADIO_PREAMBLE_SHORT;
 
+	if (dev == priv->mesh_dev)
+		return -EOPNOTSUPP;
+
 	lbs_deb_enter(LBS_DEB_CFG80211);
 
 	if (!sme->bssid) {
@@ -1402,28 +1409,23 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
 	return ret;
 }
 
-static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev,
-	u16 reason_code)
+int lbs_disconnect(struct lbs_private *priv, u16 reason)
 {
-	struct lbs_private *priv = wiphy_priv(wiphy);
 	struct cmd_ds_802_11_deauthenticate cmd;
-
-	lbs_deb_enter_args(LBS_DEB_CFG80211, "reason_code %d", reason_code);
-
-	/* store for lbs_cfg_ret_disconnect() */
-	priv->disassoc_reason = reason_code;
+	int ret;
 
 	memset(&cmd, 0, sizeof(cmd));
 	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
 	/* Mildly ugly to use a locally store my own BSSID ... */
 	memcpy(cmd.macaddr, &priv->assoc_bss, ETH_ALEN);
-	cmd.reasoncode = cpu_to_le16(reason_code);
+	cmd.reasoncode = cpu_to_le16(reason);
 
-	if (lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd))
-		return -EFAULT;
+	ret = lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd);
+	if (ret)
+		return ret;
 
 	cfg80211_disconnected(priv->dev,
-			priv->disassoc_reason,
+			reason,
 			NULL, 0,
 			GFP_KERNEL);
 	priv->connect_status = LBS_DISCONNECTED;
@@ -1431,6 +1433,21 @@ static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev,
 	return 0;
 }
 
+static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev,
+	u16 reason_code)
+{
+	struct lbs_private *priv = wiphy_priv(wiphy);
+
+	if (dev == priv->mesh_dev)
+		return -EOPNOTSUPP;
+
+	lbs_deb_enter_args(LBS_DEB_CFG80211, "reason_code %d", reason_code);
+
+	/* store for lbs_cfg_ret_disconnect() */
+	priv->disassoc_reason = reason_code;
+
+	return lbs_disconnect(priv, reason_code);
+}
 
 static int lbs_cfg_set_default_key(struct wiphy *wiphy,
 				   struct net_device *netdev,
@@ -1439,6 +1456,9 @@ static int lbs_cfg_set_default_key(struct wiphy *wiphy,
 {
 	struct lbs_private *priv = wiphy_priv(wiphy);
 
+	if (netdev == priv->mesh_dev)
+		return -EOPNOTSUPP;
+
 	lbs_deb_enter(LBS_DEB_CFG80211);
 
 	if (key_index != priv->wep_tx_key) {
@@ -1460,6 +1480,9 @@ static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev,
 	u16 key_type;
 	int ret = 0;
 
+	if (netdev == priv->mesh_dev)
+		return -EOPNOTSUPP;
+
 	lbs_deb_enter(LBS_DEB_CFG80211);
 
 	lbs_deb_assoc("add_key: cipher 0x%x, mac_addr %pM\n",
@@ -1603,6 +1626,9 @@ static int lbs_get_survey(struct wiphy *wiphy, struct net_device *dev,
 	s8 signal, noise;
 	int ret;
 
+	if (dev == priv->mesh_dev)
+		return -EOPNOTSUPP;
+
 	if (idx != 0)
 		ret = -ENOENT;
 
@@ -1636,6 +1662,9 @@ static int lbs_change_intf(struct wiphy *wiphy, struct net_device *dev,
 	struct lbs_private *priv = wiphy_priv(wiphy);
 	int ret = 0;
 
+	if (dev == priv->mesh_dev)
+		return -EOPNOTSUPP;
+
 	lbs_deb_enter(LBS_DEB_CFG80211);
 
 	switch (type) {
@@ -1959,6 +1988,9 @@ static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev,
 	struct cfg80211_bss *bss;
 	DECLARE_SSID_BUF(ssid_buf);
 
+	if (dev == priv->mesh_dev)
+		return -EOPNOTSUPP;
+
 	lbs_deb_enter(LBS_DEB_CFG80211);
 
 	if (!params->channel) {
@@ -1995,6 +2027,9 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
 	struct cmd_ds_802_11_ad_hoc_stop cmd;
 	int ret = 0;
 
+	if (dev == priv->mesh_dev)
+		return -EOPNOTSUPP;
+
 	lbs_deb_enter(LBS_DEB_CFG80211);
 
 	memset(&cmd, 0, sizeof(cmd));
@@ -2117,6 +2152,8 @@ int lbs_cfg_register(struct lbs_private *priv)
 			BIT(NL80211_IFTYPE_ADHOC);
 	if (lbs_rtap_supported(priv))
 		wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
+	if (lbs_mesh_activated(priv))
+		wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MESH_POINT);
 
 	wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &lbs_band_2ghz;
 
diff --git a/drivers/net/wireless/libertas/cfg.h b/drivers/net/wireless/libertas/cfg.h
index 4f46bb744bee..a02ee151710e 100644
--- a/drivers/net/wireless/libertas/cfg.h
+++ b/drivers/net/wireless/libertas/cfg.h
@@ -17,5 +17,6 @@ void lbs_send_disconnect_notification(struct lbs_private *priv);
 void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event);
 
 void lbs_scan_deinit(struct lbs_private *priv);
+int lbs_disconnect(struct lbs_private *priv, u16 reason);
 
 #endif
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index dbd24a4607ec..e08ab1de3d9d 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -1088,7 +1088,7 @@ void __lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
 	if (!cmd->callback || cmd->callback == lbs_cmd_async_callback)
 		__lbs_cleanup_and_insert_cmd(priv, cmd);
 	priv->cur_cmd = NULL;
-	wake_up_interruptible(&priv->waitq);
+	wake_up(&priv->waitq);
 }
 
 void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
@@ -1627,7 +1627,7 @@ struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
 		lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
 
 		/* Wake up main thread to execute next command */
-		wake_up_interruptible(&priv->waitq);
+		wake_up(&priv->waitq);
 		cmdnode = ERR_PTR(-ENOBUFS);
 		goto done;
 	}
@@ -1647,7 +1647,7 @@ struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
 
 	cmdnode->cmdwaitqwoken = 0;
 	lbs_queue_cmd(priv, cmdnode);
-	wake_up_interruptible(&priv->waitq);
+	wake_up(&priv->waitq);
 
  done:
 	lbs_deb_leave_args(LBS_DEB_HOST, "ret %p", cmdnode);
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index da0b05bb89fe..9304e6fc421f 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -43,10 +43,14 @@ int lbs_start_card(struct lbs_private *priv);
 void lbs_stop_card(struct lbs_private *priv);
 void lbs_host_to_card_done(struct lbs_private *priv);
 
+int lbs_start_iface(struct lbs_private *priv);
+int lbs_stop_iface(struct lbs_private *priv);
+
 int lbs_rtap_supported(struct lbs_private *priv);
 
 int lbs_set_mac_address(struct net_device *dev, void *addr);
 void lbs_set_multicast_list(struct net_device *dev);
+void lbs_update_mcast(struct lbs_private *priv);
 
 int lbs_suspend(struct lbs_private *priv);
 int lbs_resume(struct lbs_private *priv);
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index adb3490e3cf5..814838916b82 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -6,7 +6,6 @@
 #ifndef _LBS_DEV_H_
 #define _LBS_DEV_H_
 
-#include "mesh.h"
 #include "defs.h"
 #include "host.h"
 
@@ -22,6 +21,17 @@ struct sleep_params {
 	uint16_t sp_reserved;
 };
 
+/* Mesh statistics */
+struct lbs_mesh_stats {
+	u32	fwd_bcast_cnt;		/* Fwd: Broadcast counter */
+	u32	fwd_unicast_cnt;	/* Fwd: Unicast counter */
+	u32	fwd_drop_ttl;		/* Fwd: TTL zero */
+	u32	fwd_drop_rbt;		/* Fwd: Recently Broadcasted */
+	u32	fwd_drop_noroute; 	/* Fwd: No route to Destination */
+	u32	fwd_drop_nobuf;		/* Fwd: Run out of internal buffers */
+	u32	drop_blind;		/* Rx:  Dropped by blinding table */
+	u32	tx_failed_cnt;		/* Tx:  Failed transmissions */
+};
 
 /* Private structure for the MV device */
 struct lbs_private {
@@ -36,7 +46,6 @@ struct lbs_private {
 	/* CFG80211 */
 	struct wireless_dev *wdev;
 	bool wiphy_registered;
-	bool stopping;
 	struct cfg80211_scan_request *scan_req;
 	u8 assoc_bss[ETH_ALEN];
 	u8 disassoc_reason;
@@ -86,11 +95,14 @@ struct lbs_private {
 
 	/* Hardware access */
 	void *card;
+	bool iface_running;
 	u8 fw_ready;
 	u8 surpriseremoved;
 	u8 setup_fw_on_resume;
 	int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb);
 	void (*reset_card) (struct lbs_private *priv);
+	int (*power_save) (struct lbs_private *priv);
+	int (*power_restore) (struct lbs_private *priv);
 	int (*enter_deep_sleep) (struct lbs_private *priv);
 	int (*exit_deep_sleep) (struct lbs_private *priv);
 	int (*reset_deep_sleep_wakeup) (struct lbs_private *priv);
@@ -172,4 +184,16 @@ struct lbs_private {
 
 extern struct cmd_confirm_sleep confirm_sleep;
 
+/* Check if there is an interface active. */
+static inline int lbs_iface_active(struct lbs_private *priv)
+{
+	int r;
+
+	r = netif_running(priv->dev);
+	if (priv->mesh_dev);
+		r |= netif_running(priv->dev);
+
+	return r;
+}
+
 #endif
diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c
index 4dfb3bfd2cf3..885ddc1c4fed 100644
--- a/drivers/net/wireless/libertas/ethtool.c
+++ b/drivers/net/wireless/libertas/ethtool.c
@@ -5,6 +5,7 @@
 
 #include "decl.h"
 #include "cmd.h"
+#include "mesh.h"
 
 
 static void lbs_ethtool_get_drvinfo(struct net_device *dev,
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index 387786e1b394..c962e21762dc 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -39,6 +39,7 @@
 #include <linux/mmc/sdio_ids.h>
 #include <linux/mmc/sdio.h>
 #include <linux/mmc/host.h>
+#include <linux/pm_runtime.h>
 
 #include "host.h"
 #include "decl.h"
@@ -47,6 +48,8 @@
 #include "cmd.h"
 #include "if_sdio.h"
 
+static void if_sdio_interrupt(struct sdio_func *func);
+
 /* The if_sdio_remove() callback function is called when
  * user removes this module from kernel space or ejects
  * the card from the slot. The driver handles these 2 cases
@@ -757,6 +760,136 @@ out:
 	return ret;
 }
 
+/********************************************************************/
+/* Power management                                                 */
+/********************************************************************/
+
+static int if_sdio_power_on(struct if_sdio_card *card)
+{
+	struct sdio_func *func = card->func;
+	struct lbs_private *priv = card->priv;
+	struct mmc_host *host = func->card->host;
+	int ret;
+
+	sdio_claim_host(func);
+
+	ret = sdio_enable_func(func);
+	if (ret)
+		goto release;
+
+	/* For 1-bit transfers to the 8686 model, we need to enable the
+	 * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0
+	 * bit to allow access to non-vendor registers. */
+	if ((card->model == MODEL_8686) &&
+	    (host->caps & MMC_CAP_SDIO_IRQ) &&
+	    (host->ios.bus_width == MMC_BUS_WIDTH_1)) {
+		u8 reg;
+
+		func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
+		reg = sdio_f0_readb(func, SDIO_CCCR_IF, &ret);
+		if (ret)
+			goto disable;
+
+		reg |= SDIO_BUS_ECSI;
+		sdio_f0_writeb(func, reg, SDIO_CCCR_IF, &ret);
+		if (ret)
+			goto disable;
+	}
+
+	card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret);
+	if (ret)
+		goto disable;
+
+	card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 1, &ret) << 8;
+	if (ret)
+		goto disable;
+
+	card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 2, &ret) << 16;
+	if (ret)
+		goto disable;
+
+	sdio_release_host(func);
+	ret = if_sdio_prog_firmware(card);
+	sdio_claim_host(func);
+	if (ret)
+		goto disable;
+
+	/*
+	 * Get rx_unit if the chip is SD8688 or newer.
+	 * SD8385 & SD8686 do not have rx_unit.
+	 */
+	if ((card->model != MODEL_8385)
+			&& (card->model != MODEL_8686))
+		card->rx_unit = if_sdio_read_rx_unit(card);
+	else
+		card->rx_unit = 0;
+
+	/*
+	 * Set up the interrupt handler late.
+	 *
+	 * If we set it up earlier, the (buggy) hardware generates a spurious
+	 * interrupt, even before the interrupt has been enabled, with
+	 * CCCR_INTx = 0.
+	 *
+	 * We register the interrupt handler late so that we can handle any
+	 * spurious interrupts, and also to avoid generation of that known
+	 * spurious interrupt in the first place.
+	 */
+	ret = sdio_claim_irq(func, if_sdio_interrupt);
+	if (ret)
+		goto disable;
+
+	/*
+	 * Enable interrupts now that everything is set up
+	 */
+	sdio_writeb(func, 0x0f, IF_SDIO_H_INT_MASK, &ret);
+	if (ret)
+		goto release_irq;
+
+	sdio_release_host(func);
+
+	/*
+	 * FUNC_INIT is required for SD8688 WLAN/BT multiple functions
+	 */
+	if (card->model == MODEL_8688) {
+		struct cmd_header cmd;
+
+		memset(&cmd, 0, sizeof(cmd));
+
+		lbs_deb_sdio("send function INIT command\n");
+		if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd),
+				lbs_cmd_copyback, (unsigned long) &cmd))
+			netdev_alert(priv->dev, "CMD_FUNC_INIT cmd failed\n");
+	}
+
+	priv->fw_ready = 1;
+
+	return 0;
+
+release_irq:
+	sdio_release_irq(func);
+disable:
+	sdio_disable_func(func);
+release:
+	sdio_release_host(func);
+	return ret;
+}
+
+static int if_sdio_power_off(struct if_sdio_card *card)
+{
+	struct sdio_func *func = card->func;
+	struct lbs_private *priv = card->priv;
+
+	priv->fw_ready = 0;
+
+	sdio_claim_host(func);
+	sdio_release_irq(func);
+	sdio_disable_func(func);
+	sdio_release_host(func);
+	return 0;
+}
+
+
 /*******************************************************************/
 /* Libertas callbacks                                              */
 /*******************************************************************/
@@ -923,6 +1056,32 @@ static void if_sdio_reset_card(struct lbs_private *priv)
 	schedule_work(&card_reset_work);
 }
 
+static int if_sdio_power_save(struct lbs_private *priv)
+{
+	struct if_sdio_card *card = priv->card;
+	int ret;
+
+	flush_workqueue(card->workqueue);
+
+	ret = if_sdio_power_off(card);
+
+	/* Let runtime PM know the card is powered off */
+	pm_runtime_put_sync(&card->func->dev);
+
+	return ret;
+}
+
+static int if_sdio_power_restore(struct lbs_private *priv)
+{
+	struct if_sdio_card *card = priv->card;
+
+	/* Make sure the card will not be powered off by runtime PM */
+	pm_runtime_get_sync(&card->func->dev);
+
+	return if_sdio_power_on(card);
+}
+
+
 /*******************************************************************/
 /* SDIO callbacks                                                  */
 /*******************************************************************/
@@ -976,7 +1135,6 @@ static int if_sdio_probe(struct sdio_func *func,
 	int ret, i;
 	unsigned int model;
 	struct if_sdio_packet *packet;
-	struct mmc_host *host = func->card->host;
 
 	lbs_deb_enter(LBS_DEB_SDIO);
 
@@ -1033,45 +1191,6 @@ static int if_sdio_probe(struct sdio_func *func,
 		goto free;
 	}
 
-	sdio_claim_host(func);
-
-	ret = sdio_enable_func(func);
-	if (ret)
-		goto release;
-
-	/* For 1-bit transfers to the 8686 model, we need to enable the
-	 * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0
-	 * bit to allow access to non-vendor registers. */
-	if ((card->model == MODEL_8686) &&
-	    (host->caps & MMC_CAP_SDIO_IRQ) &&
-	    (host->ios.bus_width == MMC_BUS_WIDTH_1)) {
-		u8 reg;
-
-		func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
-		reg = sdio_f0_readb(func, SDIO_CCCR_IF, &ret);
-		if (ret)
-			goto release_int;
-
-		reg |= SDIO_BUS_ECSI;
-		sdio_f0_writeb(func, reg, SDIO_CCCR_IF, &ret);
-		if (ret)
-			goto release_int;
-	}
-
-	card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret);
-	if (ret)
-		goto release_int;
-
-	card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 1, &ret) << 8;
-	if (ret)
-		goto release_int;
-
-	card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 2, &ret) << 16;
-	if (ret)
-		goto release_int;
-
-	sdio_release_host(func);
-
 	sdio_set_drvdata(func, card);
 
 	lbs_deb_sdio("class = 0x%X, vendor = 0x%X, "
@@ -1079,14 +1198,11 @@ static int if_sdio_probe(struct sdio_func *func,
 			func->class, func->vendor, func->device,
 			model, (unsigned)card->ioport);
 
-	ret = if_sdio_prog_firmware(card);
-	if (ret)
-		goto reclaim;
 
 	priv = lbs_add_card(card, &func->dev);
 	if (!priv) {
 		ret = -ENOMEM;
-		goto reclaim;
+		goto free;
 	}
 
 	card->priv = priv;
@@ -1097,62 +1213,21 @@ static int if_sdio_probe(struct sdio_func *func,
 	priv->exit_deep_sleep = if_sdio_exit_deep_sleep;
 	priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup;
 	priv->reset_card = if_sdio_reset_card;
+	priv->power_save = if_sdio_power_save;
+	priv->power_restore = if_sdio_power_restore;
 
-	sdio_claim_host(func);
-
-	/*
-	 * Get rx_unit if the chip is SD8688 or newer.
-	 * SD8385 & SD8686 do not have rx_unit.
-	 */
-	if ((card->model != MODEL_8385)
-			&& (card->model != MODEL_8686))
-		card->rx_unit = if_sdio_read_rx_unit(card);
-	else
-		card->rx_unit = 0;
-
-	/*
-	 * Set up the interrupt handler late.
-	 *
-	 * If we set it up earlier, the (buggy) hardware generates a spurious
-	 * interrupt, even before the interrupt has been enabled, with
-	 * CCCR_INTx = 0.
-	 *
-	 * We register the interrupt handler late so that we can handle any
-	 * spurious interrupts, and also to avoid generation of that known
-	 * spurious interrupt in the first place.
-	 */
-	ret = sdio_claim_irq(func, if_sdio_interrupt);
-	if (ret)
-		goto disable;
-
-	/*
-	 * Enable interrupts now that everything is set up
-	 */
-	sdio_writeb(func, 0x0f, IF_SDIO_H_INT_MASK, &ret);
-	sdio_release_host(func);
+	ret = if_sdio_power_on(card);
 	if (ret)
-		goto reclaim;
-
-	priv->fw_ready = 1;
-
-	/*
-	 * FUNC_INIT is required for SD8688 WLAN/BT multiple functions
-	 */
-	if (card->model == MODEL_8688) {
-		struct cmd_header cmd;
-
-		memset(&cmd, 0, sizeof(cmd));
-
-		lbs_deb_sdio("send function INIT command\n");
-		if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd),
-				lbs_cmd_copyback, (unsigned long) &cmd))
-			netdev_alert(priv->dev, "CMD_FUNC_INIT cmd failed\n");
-	}
+		goto err_activate_card;
 
 	ret = lbs_start_card(priv);
+	if_sdio_power_off(card);
 	if (ret)
 		goto err_activate_card;
 
+	/* Tell PM core that we don't need the card to be powered now */
+	pm_runtime_put_noidle(&func->dev);
+
 out:
 	lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
 
@@ -1161,14 +1236,6 @@ out:
 err_activate_card:
 	flush_workqueue(card->workqueue);
 	lbs_remove_card(priv);
-reclaim:
-	sdio_claim_host(func);
-release_int:
-	sdio_release_irq(func);
-disable:
-	sdio_disable_func(func);
-release:
-	sdio_release_host(func);
 free:
 	destroy_workqueue(card->workqueue);
 	while (card->packets) {
@@ -1195,6 +1262,9 @@ static void if_sdio_remove(struct sdio_func *func)
 
 	card = sdio_get_drvdata(func);
 
+	/* Undo decrement done above in if_sdio_probe */
+	pm_runtime_get_noresume(&func->dev);
+
 	if (user_rmmod && (card->model == MODEL_8688)) {
 		/*
 		 * FUNC_SHUTDOWN is required for SD8688 WLAN/BT
@@ -1219,11 +1289,6 @@ static void if_sdio_remove(struct sdio_func *func)
 	flush_workqueue(card->workqueue);
 	destroy_workqueue(card->workqueue);
 
-	sdio_claim_host(func);
-	sdio_release_irq(func);
-	sdio_disable_func(func);
-	sdio_release_host(func);
-
 	while (card->packets) {
 		packet = card->packets;
 		card->packets = card->packets->next;
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
index e0286cfbc91d..622ae6de0d8b 100644
--- a/drivers/net/wireless/libertas/if_spi.c
+++ b/drivers/net/wireless/libertas/if_spi.c
@@ -531,10 +531,6 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card,
 		goto out;
 	err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG,
 				IF_SPI_CIC_CMD_DOWNLOAD_OVER);
-		goto out;
-
-	lbs_deb_spi("waiting for helper to boot...\n");
-
 out:
 	if (err)
 		pr_err("failed to load helper firmware (err=%d)\n", err);
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index b5acc393a65a..0c846f5a646a 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -324,7 +324,7 @@ static int if_usb_probe(struct usb_interface *intf,
 	}
 	kparam_unblock_sysfs_write(fw_name);
 
-	if (!(priv = lbs_add_card(cardp, &udev->dev)))
+	if (!(priv = lbs_add_card(cardp, &intf->dev)))
 		goto err_prog_firmware;
 
 	cardp->priv = priv;
@@ -956,7 +956,7 @@ static int if_usb_prog_firmware(struct if_usb_card *cardp,
 	priv->dnld_sent = DNLD_RES_RECEIVED;
 	spin_unlock_irqrestore(&priv->driver_lock, flags);
 
-	wake_up_interruptible(&priv->waitq);
+	wake_up(&priv->waitq);
 
 	return ret;
 }
@@ -1112,6 +1112,15 @@ static int if_usb_suspend(struct usb_interface *intf, pm_message_t message)
 	if (priv->psstate != PS_STATE_FULL_POWER)
 		return -1;
 
+#ifdef CONFIG_OLPC
+	if (machine_is_olpc()) {
+		if (priv->wol_criteria == EHS_REMOVE_WAKEUP)
+			olpc_ec_wakeup_clear(EC_SCI_SRC_WLAN);
+		else
+			olpc_ec_wakeup_set(EC_SCI_SRC_WLAN);
+	}
+#endif
+
 	ret = lbs_suspend(priv);
 	if (ret)
 		goto out;
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 2fdeb81ce5b2..d1c1d52931f1 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -23,6 +23,7 @@
 #include "cfg.h"
 #include "debugfs.h"
 #include "cmd.h"
+#include "mesh.h"
 
 #define DRIVER_RELEASE_VERSION "323.p0"
 const char lbs_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION
@@ -98,6 +99,37 @@ u8 lbs_data_rate_to_fw_index(u32 rate)
 	return 0;
 }
 
+int lbs_start_iface(struct lbs_private *priv)
+{
+	struct cmd_ds_802_11_mac_address cmd;
+	int ret;
+
+	if (priv->power_restore) {
+		ret = priv->power_restore(priv);
+		if (ret)
+			return ret;
+	}
+
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	cmd.action = cpu_to_le16(CMD_ACT_SET);
+	memcpy(cmd.macadd, priv->current_addr, ETH_ALEN);
+
+	ret = lbs_cmd_with_response(priv, CMD_802_11_MAC_ADDRESS, &cmd);
+	if (ret) {
+		lbs_deb_net("set MAC address failed\n");
+		goto err;
+	}
+
+	lbs_update_channel(priv);
+
+	priv->iface_running = true;
+	return 0;
+
+err:
+	if (priv->power_save)
+		priv->power_save(priv);
+	return ret;
+}
 
 /**
  *  lbs_dev_open - open the ethX interface
@@ -111,23 +143,64 @@ static int lbs_dev_open(struct net_device *dev)
 	int ret = 0;
 
 	lbs_deb_enter(LBS_DEB_NET);
+	if (!priv->iface_running) {
+		ret = lbs_start_iface(priv);
+		if (ret)
+			goto out;
+	}
 
 	spin_lock_irq(&priv->driver_lock);
-	priv->stopping = false;
 
-	if (priv->connect_status == LBS_CONNECTED)
-		netif_carrier_on(dev);
-	else
-		netif_carrier_off(dev);
+	netif_carrier_off(dev);
 
 	if (!priv->tx_pending_len)
 		netif_wake_queue(dev);
 
 	spin_unlock_irq(&priv->driver_lock);
+
+out:
 	lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
 	return ret;
 }
 
+static bool lbs_command_queue_empty(struct lbs_private *priv)
+{
+	unsigned long flags;
+	bool ret;
+	spin_lock_irqsave(&priv->driver_lock, flags);
+	ret = priv->cur_cmd == NULL && list_empty(&priv->cmdpendingq);
+	spin_unlock_irqrestore(&priv->driver_lock, flags);
+	return ret;
+}
+
+int lbs_stop_iface(struct lbs_private *priv)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	lbs_deb_enter(LBS_DEB_MAIN);
+
+	spin_lock_irqsave(&priv->driver_lock, flags);
+	priv->iface_running = false;
+	kfree_skb(priv->currenttxskb);
+	priv->currenttxskb = NULL;
+	priv->tx_pending_len = 0;
+	spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+	cancel_work_sync(&priv->mcast_work);
+
+	/* Disable command processing, and wait for all commands to complete */
+	lbs_deb_main("waiting for commands to complete\n");
+	wait_event(priv->waitq, lbs_command_queue_empty(priv));
+	lbs_deb_main("all commands completed\n");
+
+	if (priv->power_save)
+		ret = priv->power_save(priv);
+
+	lbs_deb_leave(LBS_DEB_MAIN);
+	return ret;
+}
+
 /**
  *  lbs_eth_stop - close the ethX interface
  *
@@ -140,18 +213,25 @@ static int lbs_eth_stop(struct net_device *dev)
 
 	lbs_deb_enter(LBS_DEB_NET);
 
+	if (priv->connect_status == LBS_CONNECTED)
+		lbs_disconnect(priv, WLAN_REASON_DEAUTH_LEAVING);
+
 	spin_lock_irq(&priv->driver_lock);
-	priv->stopping = true;
 	netif_stop_queue(dev);
 	spin_unlock_irq(&priv->driver_lock);
 
-	schedule_work(&priv->mcast_work);
+	lbs_update_mcast(priv);
 	cancel_delayed_work_sync(&priv->scan_work);
 	if (priv->scan_req) {
 		cfg80211_scan_done(priv->scan_req, false);
 		priv->scan_req = NULL;
 	}
 
+	netif_carrier_off(priv->dev);
+
+	if (!lbs_iface_active(priv))
+		lbs_stop_iface(priv);
+
 	lbs_deb_leave(LBS_DEB_NET);
 	return 0;
 }
@@ -169,7 +249,7 @@ void lbs_host_to_card_done(struct lbs_private *priv)
 	/* Wake main thread if commands are pending */
 	if (!priv->cur_cmd || priv->tx_pending_len > 0) {
 		if (!priv->wakeup_dev_required)
-			wake_up_interruptible(&priv->waitq);
+			wake_up(&priv->waitq);
 	}
 
 	spin_unlock_irqrestore(&priv->driver_lock, flags);
@@ -182,29 +262,24 @@ int lbs_set_mac_address(struct net_device *dev, void *addr)
 	int ret = 0;
 	struct lbs_private *priv = dev->ml_priv;
 	struct sockaddr *phwaddr = addr;
-	struct cmd_ds_802_11_mac_address cmd;
 
 	lbs_deb_enter(LBS_DEB_NET);
 
+	/*
+	 * Can only set MAC address when all interfaces are down, to be written
+	 * to the hardware when one of them is brought up.
+	 */
+	if (lbs_iface_active(priv))
+		return -EBUSY;
+
 	/* In case it was called from the mesh device */
 	dev = priv->dev;
 
-	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-	cmd.action = cpu_to_le16(CMD_ACT_SET);
-	memcpy(cmd.macadd, phwaddr->sa_data, ETH_ALEN);
-
-	ret = lbs_cmd_with_response(priv, CMD_802_11_MAC_ADDRESS, &cmd);
-	if (ret) {
-		lbs_deb_net("set MAC address failed\n");
-		goto done;
-	}
-
 	memcpy(priv->current_addr, phwaddr->sa_data, ETH_ALEN);
 	memcpy(dev->dev_addr, phwaddr->sa_data, ETH_ALEN);
 	if (priv->mesh_dev)
 		memcpy(priv->mesh_dev->dev_addr, phwaddr->sa_data, ETH_ALEN);
 
-done:
 	lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
 	return ret;
 }
@@ -258,18 +333,18 @@ static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd,
 	return i;
 }
 
-static void lbs_set_mcast_worker(struct work_struct *work)
+void lbs_update_mcast(struct lbs_private *priv)
 {
-	struct lbs_private *priv = container_of(work, struct lbs_private, mcast_work);
 	struct cmd_ds_mac_multicast_adr mcast_cmd;
-	int dev_flags;
+	int dev_flags = 0;
 	int nr_addrs;
 	int old_mac_control = priv->mac_control;
 
 	lbs_deb_enter(LBS_DEB_NET);
 
-	dev_flags = priv->dev->flags;
-	if (priv->mesh_dev)
+	if (netif_running(priv->dev))
+		dev_flags |= priv->dev->flags;
+	if (priv->mesh_dev && netif_running(priv->mesh_dev))
 		dev_flags |= priv->mesh_dev->flags;
 
 	if (dev_flags & IFF_PROMISC) {
@@ -315,6 +390,12 @@ static void lbs_set_mcast_worker(struct work_struct *work)
 	lbs_deb_leave(LBS_DEB_NET);
 }
 
+static void lbs_set_mcast_worker(struct work_struct *work)
+{
+	struct lbs_private *priv = container_of(work, struct lbs_private, mcast_work);
+	lbs_update_mcast(priv);
+}
+
 void lbs_set_multicast_list(struct net_device *dev)
 {
 	struct lbs_private *priv = dev->ml_priv;
@@ -647,7 +728,7 @@ static void lbs_cmd_timeout_handler(unsigned long data)
 	if (priv->dnld_sent == DNLD_CMD_SENT)
 		priv->dnld_sent = DNLD_RES_RECEIVED;
 
-	wake_up_interruptible(&priv->waitq);
+	wake_up(&priv->waitq);
 out:
 	spin_unlock_irqrestore(&priv->driver_lock, flags);
 	lbs_deb_leave(LBS_DEB_CMD);
@@ -889,10 +970,6 @@ void lbs_remove_card(struct lbs_private *priv)
 	lbs_remove_mesh(priv);
 	lbs_scan_deinit(priv);
 
-	dev = priv->dev;
-
-	cancel_work_sync(&priv->mcast_work);
-
 	/* worker thread destruction blocks on the in-flight command which
 	 * should have been cleared already in lbs_stop_card().
 	 */
@@ -950,17 +1027,18 @@ int lbs_start_card(struct lbs_private *priv)
 	if (ret)
 		goto done;
 
+	if (!lbs_disablemesh)
+		lbs_init_mesh(priv);
+	else
+		pr_info("%s: mesh disabled\n", dev->name);
+
 	if (lbs_cfg_register(priv)) {
 		pr_err("cannot register device\n");
 		goto done;
 	}
 
-	lbs_update_channel(priv);
-
-	if (!lbs_disablemesh)
-		lbs_init_mesh(priv);
-	else
-		pr_info("%s: mesh disabled\n", dev->name);
+	if (lbs_mesh_activated(priv))
+		lbs_start_mesh(priv);
 
 	lbs_debugfs_init_one(priv, dev);
 
@@ -978,8 +1056,6 @@ EXPORT_SYMBOL_GPL(lbs_start_card);
 void lbs_stop_card(struct lbs_private *priv)
 {
 	struct net_device *dev;
-	struct cmd_ctrl_node *cmdnode;
-	unsigned long flags;
 
 	lbs_deb_enter(LBS_DEB_MAIN);
 
@@ -992,30 +1068,6 @@ void lbs_stop_card(struct lbs_private *priv)
 
 	lbs_debugfs_remove_one(priv);
 	lbs_deinit_mesh(priv);
-
-	/* Delete the timeout of the currently processing command */
-	del_timer_sync(&priv->command_timer);
-	del_timer_sync(&priv->auto_deepsleep_timer);
-
-	/* Flush pending command nodes */
-	spin_lock_irqsave(&priv->driver_lock, flags);
-	lbs_deb_main("clearing pending commands\n");
-	list_for_each_entry(cmdnode, &priv->cmdpendingq, list) {
-		cmdnode->result = -ENOENT;
-		cmdnode->cmdwaitqwoken = 1;
-		wake_up(&cmdnode->cmdwait_q);
-	}
-
-	/* Flush the command the card is currently processing */
-	if (priv->cur_cmd) {
-		lbs_deb_main("clearing current command\n");
-		priv->cur_cmd->result = -ENOENT;
-		priv->cur_cmd->cmdwaitqwoken = 1;
-		wake_up(&priv->cur_cmd->cmdwait_q);
-	}
-	lbs_deb_main("done clearing commands\n");
-	spin_unlock_irqrestore(&priv->driver_lock, flags);
-
 	unregister_netdev(dev);
 
 out:
@@ -1036,7 +1088,7 @@ void lbs_queue_event(struct lbs_private *priv, u32 event)
 
 	kfifo_in(&priv->event_fifo, (unsigned char *) &event, sizeof(u32));
 
-	wake_up_interruptible(&priv->waitq);
+	wake_up(&priv->waitq);
 
 	spin_unlock_irqrestore(&priv->driver_lock, flags);
 	lbs_deb_leave(LBS_DEB_THREAD);
@@ -1054,7 +1106,7 @@ void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx)
 	BUG_ON(resp_idx > 1);
 	priv->resp_idx = resp_idx;
 
-	wake_up_interruptible(&priv->waitq);
+	wake_up(&priv->waitq);
 
 	lbs_deb_leave(LBS_DEB_THREAD);
 }
diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c
index 8e3104d990fb..e87c031b298f 100644
--- a/drivers/net/wireless/libertas/mesh.c
+++ b/drivers/net/wireless/libertas/mesh.c
@@ -129,6 +129,19 @@ static int lbs_mesh_config(struct lbs_private *priv, uint16_t action,
 	return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
 }
 
+int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel)
+{
+	return lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, channel);
+}
+
+static uint16_t lbs_mesh_get_channel(struct lbs_private *priv)
+{
+	struct wireless_dev *mesh_wdev = priv->mesh_dev->ieee80211_ptr;
+	if (mesh_wdev->channel)
+		return mesh_wdev->channel->hw_value;
+	else
+		return 1;
+}
 
 /***************************************************************************
  * Mesh sysfs support
@@ -812,7 +825,6 @@ static void lbs_persist_config_remove(struct net_device *dev)
  */
 int lbs_init_mesh(struct lbs_private *priv)
 {
-	struct net_device *dev = priv->dev;
 	int ret = 0;
 
 	lbs_deb_enter(LBS_DEB_MESH);
@@ -837,11 +849,9 @@ int lbs_init_mesh(struct lbs_private *priv)
 		   useful */
 
 		priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
-		if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
-				    priv->channel)) {
+		if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1)) {
 			priv->mesh_tlv = TLV_TYPE_MESH_ID;
-			if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
-					    priv->channel))
+			if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1))
 				priv->mesh_tlv = 0;
 		}
 	} else
@@ -851,23 +861,16 @@ int lbs_init_mesh(struct lbs_private *priv)
 		 * 0x100+37; Do not invoke command with old TLV.
 		 */
 		priv->mesh_tlv = TLV_TYPE_MESH_ID;
-		if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
-				    priv->channel))
+		if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1))
 			priv->mesh_tlv = 0;
 	}
 
 	/* Stop meshing until interface is brought up */
-	lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, priv->channel);
+	lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, 1);
 
 	if (priv->mesh_tlv) {
 		sprintf(priv->mesh_ssid, "mesh");
 		priv->mesh_ssid_len = 4;
-
-		lbs_add_mesh(priv);
-
-		if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
-			netdev_err(dev, "cannot register lbs_mesh attribute\n");
-
 		ret = 1;
 	}
 
@@ -875,6 +878,13 @@ int lbs_init_mesh(struct lbs_private *priv)
 	return ret;
 }
 
+void lbs_start_mesh(struct lbs_private *priv)
+{
+	lbs_add_mesh(priv);
+
+	if (device_create_file(&priv->dev->dev, &dev_attr_lbs_mesh))
+		netdev_err(priv->dev, "cannot register lbs_mesh attribute\n");
+}
 
 int lbs_deinit_mesh(struct lbs_private *priv)
 {
@@ -904,7 +914,8 @@ static int lbs_mesh_stop(struct net_device *dev)
 	struct lbs_private *priv = dev->ml_priv;
 
 	lbs_deb_enter(LBS_DEB_MESH);
-	lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, priv->channel);
+	lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP,
+		lbs_mesh_get_channel(priv));
 
 	spin_lock_irq(&priv->driver_lock);
 
@@ -913,7 +924,9 @@ static int lbs_mesh_stop(struct net_device *dev)
 
 	spin_unlock_irq(&priv->driver_lock);
 
-	schedule_work(&priv->mcast_work);
+	lbs_update_mcast(priv);
+	if (!lbs_iface_active(priv))
+		lbs_stop_iface(priv);
 
 	lbs_deb_leave(LBS_DEB_MESH);
 	return 0;
@@ -931,6 +944,11 @@ static int lbs_mesh_dev_open(struct net_device *dev)
 	int ret = 0;
 
 	lbs_deb_enter(LBS_DEB_NET);
+	if (!priv->iface_running) {
+		ret = lbs_start_iface(priv);
+		if (ret)
+			goto out;
+	}
 
 	spin_lock_irq(&priv->driver_lock);
 
@@ -947,7 +965,8 @@ static int lbs_mesh_dev_open(struct net_device *dev)
 
 	spin_unlock_irq(&priv->driver_lock);
 
-	ret = lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, priv->channel);
+	ret = lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
+		lbs_mesh_get_channel(priv));
 
 out:
 	lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
@@ -971,18 +990,32 @@ static const struct net_device_ops mesh_netdev_ops = {
 static int lbs_add_mesh(struct lbs_private *priv)
 {
 	struct net_device *mesh_dev = NULL;
+	struct wireless_dev *mesh_wdev;
 	int ret = 0;
 
 	lbs_deb_enter(LBS_DEB_MESH);
 
 	/* Allocate a virtual mesh device */
+	mesh_wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
+	if (!mesh_wdev) {
+		lbs_deb_mesh("init mshX wireless device failed\n");
+		ret = -ENOMEM;
+		goto done;
+	}
+
 	mesh_dev = alloc_netdev(0, "msh%d", ether_setup);
 	if (!mesh_dev) {
 		lbs_deb_mesh("init mshX device failed\n");
 		ret = -ENOMEM;
-		goto done;
+		goto err_free_wdev;
 	}
+
+	mesh_wdev->iftype = NL80211_IFTYPE_MESH_POINT;
+	mesh_wdev->wiphy = priv->wdev->wiphy;
+	mesh_wdev->netdev = mesh_dev;
+
 	mesh_dev->ml_priv = priv;
+	mesh_dev->ieee80211_ptr = mesh_wdev;
 	priv->mesh_dev = mesh_dev;
 
 	mesh_dev->netdev_ops = &mesh_netdev_ops;
@@ -996,7 +1029,7 @@ static int lbs_add_mesh(struct lbs_private *priv)
 	ret = register_netdev(mesh_dev);
 	if (ret) {
 		pr_err("cannot register mshX virtual interface\n");
-		goto err_free;
+		goto err_free_netdev;
 	}
 
 	ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
@@ -1012,9 +1045,12 @@ static int lbs_add_mesh(struct lbs_private *priv)
 err_unregister:
 	unregister_netdev(mesh_dev);
 
-err_free:
+err_free_netdev:
 	free_netdev(mesh_dev);
 
+err_free_wdev:
+	kfree(mesh_wdev);
+
 done:
 	lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
 	return ret;
@@ -1035,6 +1071,7 @@ void lbs_remove_mesh(struct lbs_private *priv)
 	lbs_persist_config_remove(mesh_dev);
 	unregister_netdev(mesh_dev);
 	priv->mesh_dev = NULL;
+	kfree(mesh_dev->ieee80211_ptr);
 	free_netdev(mesh_dev);
 	lbs_deb_leave(LBS_DEB_MESH);
 }
diff --git a/drivers/net/wireless/libertas/mesh.h b/drivers/net/wireless/libertas/mesh.h
index 50144913f2ab..6603f341c874 100644
--- a/drivers/net/wireless/libertas/mesh.h
+++ b/drivers/net/wireless/libertas/mesh.h
@@ -9,30 +9,25 @@
 #include <net/lib80211.h>
 
 #include "host.h"
+#include "dev.h"
 
 #ifdef CONFIG_LIBERTAS_MESH
 
-/* Mesh statistics */
-struct lbs_mesh_stats {
-	u32	fwd_bcast_cnt;		/* Fwd: Broadcast counter */
-	u32	fwd_unicast_cnt;	/* Fwd: Unicast counter */
-	u32	fwd_drop_ttl;		/* Fwd: TTL zero */
-	u32	fwd_drop_rbt;		/* Fwd: Recently Broadcasted */
-	u32	fwd_drop_noroute; 	/* Fwd: No route to Destination */
-	u32	fwd_drop_nobuf;		/* Fwd: Run out of internal buffers */
-	u32	drop_blind;		/* Rx:  Dropped by blinding table */
-	u32	tx_failed_cnt;		/* Tx:  Failed transmissions */
-};
-
-
 struct net_device;
-struct lbs_private;
 
 int lbs_init_mesh(struct lbs_private *priv);
+void lbs_start_mesh(struct lbs_private *priv);
 int lbs_deinit_mesh(struct lbs_private *priv);
 
 void lbs_remove_mesh(struct lbs_private *priv);
 
+static inline bool lbs_mesh_activated(struct lbs_private *priv)
+{
+	/* Mesh SSID is only programmed after successful init */
+	return priv->mesh_ssid_len != 0;
+}
+
+int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel);
 
 /* Sending / Receiving */
 
@@ -67,11 +62,13 @@ void lbs_mesh_ethtool_get_strings(struct net_device *dev,
 
 #define lbs_init_mesh(priv)
 #define lbs_deinit_mesh(priv)
+#define lbs_start_mesh(priv)
 #define lbs_add_mesh(priv)
 #define lbs_remove_mesh(priv)
 #define lbs_mesh_set_dev(priv, dev, rxpd) (dev)
 #define lbs_mesh_set_txpd(priv, dev, txpd)
-#define lbs_mesh_config(priv, enable, chan)
+#define lbs_mesh_set_channel(priv, channel) (0)
+#define lbs_mesh_activated(priv) (false)
 
 #endif
 
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
index bfb8898ae518..62e10eeadd7e 100644
--- a/drivers/net/wireless/libertas/rx.c
+++ b/drivers/net/wireless/libertas/rx.c
@@ -15,6 +15,7 @@
 #include "radiotap.h"
 #include "decl.h"
 #include "dev.h"
+#include "mesh.h"
 
 struct eth803hdr {
 	u8 dest_addr[6];
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c
index a6e85134cfe1..8f127520d786 100644
--- a/drivers/net/wireless/libertas/tx.c
+++ b/drivers/net/wireless/libertas/tx.c
@@ -12,6 +12,7 @@
 #include "decl.h"
 #include "defs.h"
 #include "dev.h"
+#include "mesh.h"
 
 /**
  * convert_radiotap_rate_to_mv - converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 031cd89b1768..34b79fc91e39 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -612,6 +612,12 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
 	rx_status.freq = data->channel->center_freq;
 	rx_status.band = data->channel->band;
 	rx_status.rate_idx = info->control.rates[0].idx;
+	if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS)
+		rx_status.flag |= RX_FLAG_HT;
+	if (info->control.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+		rx_status.flag |= RX_FLAG_40MHZ;
+	if (info->control.rates[0].flags & IEEE80211_TX_RC_SHORT_GI)
+		rx_status.flag |= RX_FLAG_SHORT_GI;
 	/* TODO: simulate real signal strength (and optional packet loss) */
 	rx_status.signal = data->power_level - 50;
 
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index 352d2c5da1fc..6fd53e4e3fe6 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -547,7 +547,7 @@ mwifiex_dump_station_info(struct mwifiex_private *priv,
 	sinfo->tx_bytes = priv->stats.tx_bytes;
 	sinfo->rx_packets = priv->stats.rx_packets;
 	sinfo->tx_packets = priv->stats.tx_packets;
-	sinfo->signal = priv->w_stats.qual.level;
+	sinfo->signal = priv->qual_level;
 	sinfo->txrate.legacy = rate.rate;
 
 	return ret;
@@ -793,139 +793,6 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv)
 }
 
 /*
- * This function informs the CFG802.11 subsystem of a new BSS connection.
- *
- * The following information are sent to the CFG802.11 subsystem
- * to register the new BSS connection. If we do not register the new BSS,
- * a kernel panic will result.
- *      - MAC address
- *      - Capabilities
- *      - Beacon period
- *      - RSSI value
- *      - Channel
- *      - Supported rates IE
- *      - Extended capabilities IE
- *      - DS parameter set IE
- *      - HT Capability IE
- *      - Vendor Specific IE (221)
- *      - WPA IE
- *      - RSN IE
- */
-static int mwifiex_inform_bss_from_scan_result(struct mwifiex_private *priv,
-					       struct mwifiex_802_11_ssid *ssid)
-{
-	struct mwifiex_bssdescriptor *scan_table;
-	int i, j;
-	struct ieee80211_channel *chan;
-	u8 *ie, *ie_buf;
-	u32 ie_len;
-	u8 *beacon;
-	int beacon_size;
-	u8 element_id, element_len;
-
-#define MAX_IE_BUF	2048
-	ie_buf = kzalloc(MAX_IE_BUF, GFP_KERNEL);
-	if (!ie_buf) {
-		dev_err(priv->adapter->dev, "%s: failed to alloc ie_buf\n",
-						__func__);
-		return -ENOMEM;
-	}
-
-	scan_table = priv->adapter->scan_table;
-	for (i = 0; i < priv->adapter->num_in_scan_table; i++) {
-		if (ssid) {
-			/* Inform specific BSS only */
-			if (memcmp(ssid->ssid, scan_table[i].ssid.ssid,
-					   ssid->ssid_len))
-				continue;
-		}
-		memset(ie_buf, 0, MAX_IE_BUF);
-		ie_buf[0] = WLAN_EID_SSID;
-		ie_buf[1] = scan_table[i].ssid.ssid_len;
-		memcpy(&ie_buf[sizeof(struct ieee_types_header)],
-		       scan_table[i].ssid.ssid, ie_buf[1]);
-
-		ie = ie_buf + ie_buf[1] + sizeof(struct ieee_types_header);
-		ie_len = ie_buf[1] + sizeof(struct ieee_types_header);
-
-		ie[0] = WLAN_EID_SUPP_RATES;
-
-		for (j = 0; j < sizeof(scan_table[i].supported_rates); j++) {
-			if (!scan_table[i].supported_rates[j])
-				break;
-			else
-				ie[j + sizeof(struct ieee_types_header)] =
-					scan_table[i].supported_rates[j];
-		}
-
-		ie[1] = j;
-		ie_len += ie[1] + sizeof(struct ieee_types_header);
-
-		beacon = scan_table[i].beacon_buf;
-		beacon_size = scan_table[i].beacon_buf_size;
-
-		/* Skip time stamp, beacon interval and capability */
-
-		if (beacon) {
-			beacon += sizeof(scan_table[i].beacon_period)
-				+ sizeof(scan_table[i].time_stamp) +
-				+sizeof(scan_table[i].cap_info_bitmap);
-
-			beacon_size -= sizeof(scan_table[i].beacon_period)
-				+ sizeof(scan_table[i].time_stamp)
-				+ sizeof(scan_table[i].cap_info_bitmap);
-		}
-
-		while (beacon_size >= sizeof(struct ieee_types_header)) {
-			ie = ie_buf + ie_len;
-			element_id = *beacon;
-			element_len = *(beacon + 1);
-			if (beacon_size < (int) element_len +
-			    sizeof(struct ieee_types_header)) {
-				dev_err(priv->adapter->dev, "%s: in processing"
-					" IE, bytes left < IE length\n",
-					__func__);
-				break;
-			}
-			switch (element_id) {
-			case WLAN_EID_EXT_CAPABILITY:
-			case WLAN_EID_DS_PARAMS:
-			case WLAN_EID_HT_CAPABILITY:
-			case WLAN_EID_VENDOR_SPECIFIC:
-			case WLAN_EID_RSN:
-			case WLAN_EID_BSS_AC_ACCESS_DELAY:
-				ie[0] = element_id;
-				ie[1] = element_len;
-				memcpy(&ie[sizeof(struct ieee_types_header)],
-				       (u8 *) beacon
-				       + sizeof(struct ieee_types_header),
-				       element_len);
-				ie_len += ie[1] +
-					sizeof(struct ieee_types_header);
-				break;
-			default:
-				break;
-			}
-			beacon += element_len +
-					sizeof(struct ieee_types_header);
-			beacon_size -= element_len +
-					sizeof(struct ieee_types_header);
-		}
-		chan = ieee80211_get_channel(priv->wdev->wiphy,
-						scan_table[i].freq);
-		cfg80211_inform_bss(priv->wdev->wiphy, chan,
-					scan_table[i].mac_address,
-					0, scan_table[i].cap_info_bitmap,
-					scan_table[i].beacon_period,
-					ie_buf, ie_len,
-					scan_table[i].rssi, GFP_KERNEL);
-	}
-
-	kfree(ie_buf);
-	return 0;
-}
-
-/*
  * This function connects with a BSS.
  *
  * This function handles both Infra and Ad-Hoc modes. It also performs
@@ -937,8 +804,7 @@ static int mwifiex_inform_bss_from_scan_result(struct mwifiex_private *priv,
  * For Infra mode, the function returns failure if the specified SSID
  * is not found in scan table. However, for Ad-Hoc mode, it can create
  * the IBSS if it does not exist. On successful completion in either case,
- * the function notifies the CFG802.11 subsystem of the new BSS connection,
- * otherwise the kernel will panic.
+ * the function notifies the CFG802.11 subsystem of the new BSS connection.
  */
 static int
 mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid,
@@ -946,11 +812,11 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid,
 		       struct cfg80211_connect_params *sme, bool privacy)
 {
 	struct mwifiex_802_11_ssid req_ssid;
-	struct mwifiex_ssid_bssid ssid_bssid;
 	int ret, auth_type = 0;
+	struct cfg80211_bss *bss = NULL;
+	u8 is_scanning_required = 0;
 
 	memset(&req_ssid, 0, sizeof(struct mwifiex_802_11_ssid));
-	memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid));
 
 	req_ssid.ssid_len = ssid_len;
 	if (ssid_len > IEEE80211_MAX_SSID_LEN) {
@@ -1028,30 +894,48 @@ done:
 		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
+	 * then request scan and cfg80211_get_bss() again for final output.
+	 */
+	while (1) {
+		if (is_scanning_required) {
+			/* Do specific SSID scanning */
+			if (mwifiex_request_scan(priv, &req_ssid)) {
+				dev_err(priv->adapter->dev, "scan error\n");
+				return -EFAULT;
+			}
+		}
 
-	memcpy(&ssid_bssid.ssid, &req_ssid, sizeof(struct mwifiex_802_11_ssid));
-
-	if (mode != NL80211_IFTYPE_ADHOC) {
-		if (mwifiex_find_best_bss(priv, &ssid_bssid))
-			return -EFAULT;
-		/* Inform the BSS information to kernel, otherwise
-		 * kernel will give a panic after successful assoc */
-		if (mwifiex_inform_bss_from_scan_result(priv, &req_ssid))
-			return -EFAULT;
+		/* Find the BSS we want using available scan results */
+		if (mode == NL80211_IFTYPE_ADHOC)
+			bss = cfg80211_get_bss(priv->wdev->wiphy, channel,
+					       bssid, ssid, ssid_len,
+					       WLAN_CAPABILITY_IBSS,
+					       WLAN_CAPABILITY_IBSS);
+		else
+			bss = cfg80211_get_bss(priv->wdev->wiphy, channel,
+					       bssid, ssid, ssid_len,
+					       WLAN_CAPABILITY_ESS,
+					       WLAN_CAPABILITY_ESS);
+
+		if (!bss) {
+			if (is_scanning_required) {
+				dev_warn(priv->adapter->dev, "assoc: requested "
+					 "bss not found in scan results\n");
+				break;
+			}
+			is_scanning_required = 1;
+		} else {
+			dev_dbg(priv->adapter->dev, "info: trying to associate to %s and bssid %pM\n",
+					(char *) req_ssid.ssid, bss->bssid);
+			memcpy(&priv->cfg_bssid, bss->bssid, ETH_ALEN);
+			break;
+		}
 	}
 
-	dev_dbg(priv->adapter->dev, "info: trying to associate to %s and bssid %pM\n",
-	       (char *) req_ssid.ssid, ssid_bssid.bssid);
-
-	memcpy(&priv->cfg_bssid, ssid_bssid.bssid, 6);
-
-	/* Connect to BSS by ESSID */
-	memset(&ssid_bssid.bssid, 0, ETH_ALEN);
-
-	if (!netif_queue_stopped(priv->netdev))
-		netif_stop_queue(priv->netdev);
-
-	if (mwifiex_bss_start(priv, &ssid_bssid))
+	if (mwifiex_bss_start(priv, bss, &req_ssid))
 		return -EFAULT;
 
 	if (mode == NL80211_IFTYPE_ADHOC) {
@@ -1416,13 +1300,8 @@ mwifiex_cfg80211_results(struct work_struct *work)
 					MWIFIEX_SCAN_TYPE_ACTIVE;
 			scan_req->chan_list[i].scan_time = 0;
 		}
-		if (mwifiex_set_user_scan_ioctl(priv, scan_req)) {
+		if (mwifiex_set_user_scan_ioctl(priv, scan_req))
 			ret = -EFAULT;
-			goto done;
-		}
-		if (mwifiex_inform_bss_from_scan_result(priv, NULL))
-			ret = -EFAULT;
-done:
 		priv->scan_result_status = ret;
 		dev_dbg(priv->adapter->dev, "info: %s: sending scan results\n",
 							__func__);
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index 4fee0993b186..f23ec72ed4fe 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -821,6 +821,14 @@ struct host_cmd_ds_txpwr_cfg {
 	__le32 mode;
 } __packed;
 
+struct mwifiex_bcn_param {
+	u8 bssid[ETH_ALEN];
+	u8 rssi;
+	__le32 timestamp[2];
+	__le16 beacon_period;
+	__le16 cap_info_bitmap;
+} __packed;
+
 #define MWIFIEX_USER_SCAN_CHAN_MAX             50
 
 #define MWIFIEX_MAX_SSID_LIST_LENGTH         10
@@ -862,13 +870,6 @@ struct mwifiex_user_scan_ssid {
 
 struct mwifiex_user_scan_cfg {
 	/*
-	 *  Flag set to keep the previous scan table intact
-	 *
-	 *  If set, the scan results will accumulate, replacing any previous
-	 *   matched entries for a BSS with the new scan data
-	 */
-	u8 keep_previous_scan;
-	/*
 	 *  BSS mode to be sent in the firmware command
 	 */
 	u8 bss_mode;
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index 3f1559e61320..26e685a31bc0 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -152,19 +152,6 @@ static int mwifiex_init_priv(struct mwifiex_private *priv)
 static int mwifiex_allocate_adapter(struct mwifiex_adapter *adapter)
 {
 	int ret;
-	u32 buf_size;
-	struct mwifiex_bssdescriptor *temp_scan_table;
-
-	/* Allocate buffer to store the BSSID list */
-	buf_size = sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP;
-	temp_scan_table = kzalloc(buf_size, GFP_KERNEL);
-	if (!temp_scan_table) {
-		dev_err(adapter->dev, "%s: failed to alloc temp_scan_table\n",
-		       __func__);
-		return -ENOMEM;
-	}
-
-	adapter->scan_table = temp_scan_table;
 
 	/* Allocate command buffer */
 	ret = mwifiex_alloc_cmd_buffer(adapter);
@@ -222,14 +209,8 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
 	adapter->active_scan_time = MWIFIEX_ACTIVE_SCAN_CHAN_TIME;
 	adapter->passive_scan_time = MWIFIEX_PASSIVE_SCAN_CHAN_TIME;
 
-	adapter->num_in_scan_table = 0;
-	memset(adapter->scan_table, 0,
-	       (sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP));
 	adapter->scan_probes = 1;
 
-	memset(adapter->bcn_buf, 0, sizeof(adapter->bcn_buf));
-	adapter->bcn_buf_end = adapter->bcn_buf;
-
 	adapter->multiple_dtim = 1;
 
 	adapter->local_listen_interval = 0;	/* default value in firmware
@@ -326,8 +307,6 @@ mwifiex_free_adapter(struct mwifiex_adapter *adapter)
 	del_timer(&adapter->cmd_timer);
 
 	dev_dbg(adapter->dev, "info: free scan table\n");
-	kfree(adapter->scan_table);
-	adapter->scan_table = NULL;
 
 	adapter->if_ops.cleanup_if(adapter);
 
diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h
index f6bcc868562f..e0b68e7c8ca2 100644
--- a/drivers/net/wireless/mwifiex/ioctl.h
+++ b/drivers/net/wireless/mwifiex/ioctl.h
@@ -134,7 +134,6 @@ struct mwifiex_ver_ext {
 struct mwifiex_bss_info {
 	u32 bss_mode;
 	struct mwifiex_802_11_ssid ssid;
-	u32 scan_table_idx;
 	u32 bss_chan;
 	u32 region_code;
 	u32 media_connected;
@@ -307,10 +306,12 @@ struct mwifiex_ds_read_eeprom {
 	u8 value[MAX_EEPROM_DATA];
 };
 
+#define IEEE_MAX_IE_SIZE		256
+
 struct mwifiex_ds_misc_gen_ie {
 	u32 type;
 	u32 len;
-	u8 ie_data[IW_CUSTOM_MAX];
+	u8 ie_data[IEEE_MAX_IE_SIZE];
 };
 
 struct mwifiex_ds_misc_cmd {
diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c
index 644e2e405cb5..5cdad92277fa 100644
--- a/drivers/net/wireless/mwifiex/join.c
+++ b/drivers/net/wireless/mwifiex/join.c
@@ -224,32 +224,6 @@ mwifiex_setup_rates_from_bssdesc(struct mwifiex_private *priv,
 }
 
 /*
- * This function updates the scan entry TSF timestamps to reflect
- * a new association.
- */
-static void
-mwifiex_update_tsf_timestamps(struct mwifiex_private *priv,
-			      struct mwifiex_bssdescriptor *new_bss_desc)
-{
-	struct mwifiex_adapter *adapter = priv->adapter;
-	u32 table_idx;
-	long long new_tsf_base;
-	signed long long tsf_delta;
-
-	memcpy(&new_tsf_base, new_bss_desc->time_stamp, sizeof(new_tsf_base));
-
-	tsf_delta = new_tsf_base - new_bss_desc->network_tsf;
-
-	dev_dbg(adapter->dev, "info: TSF: update TSF timestamps, "
-		"0x%016llx -> 0x%016llx\n",
-	       new_bss_desc->network_tsf, new_tsf_base);
-
-	for (table_idx = 0; table_idx < adapter->num_in_scan_table;
-	     table_idx++)
-		adapter->scan_table[table_idx].network_tsf += tsf_delta;
-}
-
-/*
  * This function appends a WAPI IE.
  *
  * This function is called from the network join command preparation routine.
@@ -639,12 +613,6 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
 
 	priv->curr_bss_params.band = (u8) bss_desc->bss_band;
 
-	/*
-	 * Adjust the timestamps in the scan table to be relative to the newly
-	 * associated AP's TSF
-	 */
-	mwifiex_update_tsf_timestamps(priv, bss_desc);
-
 	if (bss_desc->wmm_ie.vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC)
 		priv->curr_bss_params.wmm_enabled = true;
 	else
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
index 0415e3d1c317..48b4d95219fb 100644
--- a/drivers/net/wireless/mwifiex/main.c
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -849,6 +849,7 @@ mwifiex_add_card(void *card, struct semaphore *sem,
 {
 	int i;
 	struct mwifiex_adapter *adapter;
+	char fmt[64];
 
 	if (down_interruptible(sem))
 		goto exit_sem_err;
@@ -897,6 +898,9 @@ mwifiex_add_card(void *card, struct semaphore *sem,
 
 	up(sem);
 
+	mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1);
+	dev_notice(adapter->dev, "driver_version = %s\n", fmt);
+
 	return 0;
 
 err_add_intf:
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 2215c3c97354..e6b6c0cfb63e 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -54,6 +54,8 @@ struct mwifiex_drv_mode {
 };
 
 
+#define MWIFIEX_MAX_AP				64
+
 #define MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT	(5 * HZ)
 
 #define MWIFIEX_TIMER_10S			10000
@@ -227,27 +229,10 @@ struct ieee_types_header {
 	u8 len;
 } __packed;
 
-struct ieee_obss_scan_param {
-	u16 obss_scan_passive_dwell;
-	u16 obss_scan_active_dwell;
-	u16 bss_chan_width_trigger_scan_int;
-	u16 obss_scan_passive_total;
-	u16 obss_scan_active_total;
-	u16 bss_width_chan_trans_delay;
-	u16 obss_scan_active_threshold;
-} __packed;
-
-struct ieee_types_obss_scan_param {
-	struct ieee_types_header ieee_hdr;
-	struct ieee_obss_scan_param obss_scan;
-} __packed;
-
 #define MWIFIEX_SUPPORTED_RATES                 14
 
 #define MWIFIEX_SUPPORTED_RATES_EXT             32
 
-#define IEEE_MAX_IE_SIZE			256
-
 struct ieee_types_vendor_specific {
 	struct ieee_types_vendor_header vend_hdr;
 	u8 data[IEEE_MAX_IE_SIZE - sizeof(struct ieee_types_vendor_header)];
@@ -291,8 +276,6 @@ struct mwifiex_bssdescriptor {
 	u16 bss_co_2040_offset;
 	u8 *bcn_ext_cap;
 	u16 ext_cap_offset;
-	struct ieee_types_obss_scan_param *bcn_obss_scan;
-	u16 overlap_bss_offset;
 	struct ieee_types_vendor_specific *bcn_wpa_ie;
 	u16 wpa_offset;
 	struct ieee_types_generic *bcn_rsn_ie;
@@ -301,8 +284,6 @@ struct mwifiex_bssdescriptor {
 	u16 wapi_offset;
 	u8 *beacon_buf;
 	u32 beacon_buf_size;
-	u32 beacon_buf_size_max;
-
 };
 
 struct mwifiex_current_bss_params {
@@ -468,7 +449,7 @@ struct mwifiex_private {
 	struct dentry *dfs_dev_dir;
 #endif
 	u8 nick_name[16];
-	struct iw_statistics w_stats;
+	u8 qual_level, qual_noise;
 	u16 current_key_index;
 	struct semaphore async_sem;
 	u8 scan_pending_on_block;
@@ -624,15 +605,11 @@ struct mwifiex_adapter {
 	u32 scan_processing;
 	u16 region_code;
 	struct mwifiex_802_11d_domain_reg domain_reg;
-	struct mwifiex_bssdescriptor *scan_table;
-	u32 num_in_scan_table;
 	u16 scan_probes;
 	u32 scan_mode;
 	u16 specific_scan_time;
 	u16 active_scan_time;
 	u16 passive_scan_time;
-	u8 bcn_buf[MAX_SCAN_BEACON_BUFFER];
-	u8 *bcn_buf_end;
 	u8 fw_bands;
 	u8 adhoc_start_band;
 	u8 config_bands;
@@ -765,13 +742,6 @@ void mwifiex_queue_scan_cmd(struct mwifiex_private *priv,
 			    struct cmd_ctrl_node *cmd_node);
 int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
 			    struct host_cmd_ds_command *resp);
-s32 mwifiex_find_ssid_in_list(struct mwifiex_private *priv,
-				struct mwifiex_802_11_ssid *ssid, u8 *bssid,
-				u32 mode);
-s32 mwifiex_find_bssid_in_list(struct mwifiex_private *priv, u8 *bssid,
-				 u32 mode);
-int mwifiex_find_best_network(struct mwifiex_private *priv,
-			      struct mwifiex_ssid_bssid *req_ssid_bssid);
 s32 mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1,
 		       struct mwifiex_802_11_ssid *ssid2);
 int mwifiex_associate(struct mwifiex_private *priv,
@@ -782,7 +752,6 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
 int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
 				 struct host_cmd_ds_command *resp);
 void mwifiex_reset_connect_state(struct mwifiex_private *priv);
-void mwifiex_2040_coex_event(struct mwifiex_private *priv);
 u8 mwifiex_band_to_radio_type(u8 band);
 int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac);
 int mwifiex_adhoc_start(struct mwifiex_private *priv,
@@ -922,8 +891,8 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
 int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist,
 			    struct net_device *dev);
 int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter);
-int mwifiex_bss_start(struct mwifiex_private *priv,
-		      struct mwifiex_ssid_bssid *ssid_bssid);
+int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
+		      struct mwifiex_802_11_ssid *req_ssid);
 int mwifiex_set_hs_params(struct mwifiex_private *priv,
 			      u16 action, int cmd_type,
 			      struct mwifiex_ds_hs_cfg *hscfg);
@@ -934,8 +903,6 @@ int mwifiex_get_signal_info(struct mwifiex_private *priv,
 			    struct mwifiex_ds_get_signal *signal);
 int mwifiex_drv_get_data_rate(struct mwifiex_private *priv,
 			      struct mwifiex_rate_cfg *rate);
-int mwifiex_find_best_bss(struct mwifiex_private *priv,
-			  struct mwifiex_ssid_bssid *ssid_bssid);
 int mwifiex_request_scan(struct mwifiex_private *priv,
 			 struct mwifiex_802_11_ssid *req_ssid);
 int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv,
@@ -984,12 +951,20 @@ int mwifiex_main_process(struct mwifiex_adapter *);
 
 int mwifiex_bss_set_channel(struct mwifiex_private *,
 			    struct mwifiex_chan_freq_power *cfp);
-int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *,
-			       struct mwifiex_ssid_bssid *);
 int mwifiex_set_radio_band_cfg(struct mwifiex_private *,
 			 struct mwifiex_ds_band_cfg *);
 int mwifiex_get_bss_info(struct mwifiex_private *,
 			 struct mwifiex_bss_info *);
+int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
+			      u8 *bssid, s32 rssi, u8 *ie_buf,
+			      size_t ie_len, u16 beacon_period,
+			      u16 cap_info_bitmap,
+			      struct mwifiex_bssdescriptor *bss_desc);
+int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
+				struct mwifiex_bssdescriptor *bss_entry,
+				u8 *ie_buf, u32 ie_len);
+int mwifiex_check_network_compatibility(struct mwifiex_private *priv,
+					struct mwifiex_bssdescriptor *bss_desc);
 
 #ifdef CONFIG_DEBUG_FS
 void mwifiex_debugfs_init(void);
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
index 6f88c8ab5de5..b28241c6e737 100644
--- a/drivers/net/wireless/mwifiex/scan.c
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -172,36 +172,6 @@ mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1,
 }
 
 /*
- * Sends IOCTL request to get the best BSS.
- *
- * This function allocates the IOCTL request buffer, fills it
- * with requisite parameters and calls the IOCTL handler.
- */
-int mwifiex_find_best_bss(struct mwifiex_private *priv,
-			  struct mwifiex_ssid_bssid *ssid_bssid)
-{
-	struct mwifiex_ssid_bssid tmp_ssid_bssid;
-	u8 *mac;
-
-	if (!ssid_bssid)
-		return -1;
-
-	memcpy(&tmp_ssid_bssid, ssid_bssid,
-	       sizeof(struct mwifiex_ssid_bssid));
-
-	if (!mwifiex_bss_ioctl_find_bss(priv, &tmp_ssid_bssid)) {
-		memcpy(ssid_bssid, &tmp_ssid_bssid,
-		       sizeof(struct mwifiex_ssid_bssid));
-		mac = (u8 *) &ssid_bssid->bssid;
-		dev_dbg(priv->adapter->dev, "cmd: found network: ssid=%s,"
-				" %pM\n", ssid_bssid->ssid.ssid, mac);
-		return 0;
-	}
-
-	return -1;
-}
-
-/*
  * Sends IOCTL request to start a scan with user configurations.
  *
  * This function allocates the IOCTL request buffer, fills it
@@ -286,8 +256,7 @@ mwifiex_is_network_compatible_for_static_wep(struct mwifiex_private *priv,
  */
 static bool
 mwifiex_is_network_compatible_for_wpa(struct mwifiex_private *priv,
-				      struct mwifiex_bssdescriptor *bss_desc,
-				      int index)
+				      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
@@ -298,9 +267,9 @@ mwifiex_is_network_compatible_for_wpa(struct mwifiex_private *priv,
 	    * LinkSys WRT54G && bss_desc->privacy
 	    */
 	 ) {
-		dev_dbg(priv->adapter->dev, "info: %s: WPA: index=%d"
+		dev_dbg(priv->adapter->dev, "info: %s: WPA:"
 			" wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s "
-			"EncMode=%#x privacy=%#x\n", __func__, index,
+			"EncMode=%#x privacy=%#x\n", __func__,
 			(bss_desc->bcn_wpa_ie) ?
 			(*(bss_desc->bcn_wpa_ie)).
 			vend_hdr.element_id : 0,
@@ -324,8 +293,7 @@ mwifiex_is_network_compatible_for_wpa(struct mwifiex_private *priv,
  */
 static bool
 mwifiex_is_network_compatible_for_wpa2(struct mwifiex_private *priv,
-				       struct mwifiex_bssdescriptor *bss_desc,
-				       int index)
+				       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
@@ -336,9 +304,9 @@ mwifiex_is_network_compatible_for_wpa2(struct mwifiex_private *priv,
 	    * LinkSys WRT54G && bss_desc->privacy
 	    */
 	 ) {
-		dev_dbg(priv->adapter->dev, "info: %s: WPA2: index=%d"
+		dev_dbg(priv->adapter->dev, "info: %s: WPA2: "
 			" wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s "
-			"EncMode=%#x privacy=%#x\n", __func__, index,
+			"EncMode=%#x privacy=%#x\n", __func__,
 			(bss_desc->bcn_wpa_ie) ?
 			(*(bss_desc->bcn_wpa_ie)).
 			vend_hdr.element_id : 0,
@@ -383,8 +351,7 @@ mwifiex_is_network_compatible_for_adhoc_aes(struct mwifiex_private *priv,
  */
 static bool
 mwifiex_is_network_compatible_for_dynamic_wep(struct mwifiex_private *priv,
-				       struct mwifiex_bssdescriptor *bss_desc,
-				       int index)
+				       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
@@ -395,9 +362,9 @@ mwifiex_is_network_compatible_for_dynamic_wep(struct mwifiex_private *priv,
 	    && priv->sec_info.encryption_mode
 	    && bss_desc->privacy) {
 		dev_dbg(priv->adapter->dev, "info: %s: dynamic "
-			"WEP: index=%d wpa_ie=%#x wpa2_ie=%#x "
+			"WEP: wpa_ie=%#x wpa2_ie=%#x "
 			"EncMode=%#x privacy=%#x\n",
-			__func__, index,
+			__func__,
 			(bss_desc->bcn_wpa_ie) ?
 			(*(bss_desc->bcn_wpa_ie)).
 			vend_hdr.element_id : 0,
@@ -430,42 +397,41 @@ mwifiex_is_network_compatible_for_dynamic_wep(struct mwifiex_private *priv,
  * Compatibility is not matched while roaming, except for mode.
  */
 static s32
-mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode)
+mwifiex_is_network_compatible(struct mwifiex_private *priv,
+			      struct mwifiex_bssdescriptor *bss_desc, u32 mode)
 {
 	struct mwifiex_adapter *adapter = priv->adapter;
-	struct mwifiex_bssdescriptor *bss_desc;
 
-	bss_desc = &adapter->scan_table[index];
 	bss_desc->disable_11n = false;
 
 	/* Don't check for compatibility if roaming */
 	if (priv->media_connected && (priv->bss_mode == NL80211_IFTYPE_STATION)
 	    && (bss_desc->bss_mode == NL80211_IFTYPE_STATION))
-		return index;
+		return 0;
 
 	if (priv->wps.session_enable) {
 		dev_dbg(adapter->dev,
 			"info: return success directly in WPS period\n");
-		return index;
+		return 0;
 	}
 
 	if (mwifiex_is_network_compatible_for_wapi(priv, bss_desc)) {
 		dev_dbg(adapter->dev, "info: return success for WAPI AP\n");
-		return index;
+		return 0;
 	}
 
 	if (bss_desc->bss_mode == mode) {
 		if (mwifiex_is_network_compatible_for_no_sec(priv, bss_desc)) {
 			/* No security */
-			return index;
+			return 0;
 		} else if (mwifiex_is_network_compatible_for_static_wep(priv,
 								bss_desc)) {
 			/* Static WEP enabled */
 			dev_dbg(adapter->dev, "info: Disable 11n in WEP mode.\n");
 			bss_desc->disable_11n = true;
-			return index;
-		} else if (mwifiex_is_network_compatible_for_wpa(priv, bss_desc,
-								 index)) {
+			return 0;
+		} else if (mwifiex_is_network_compatible_for_wpa(priv,
+								 bss_desc)) {
 			/* WPA enabled */
 			if (((priv->adapter->config_bands & BAND_GN
 			      || priv->adapter->config_bands & BAND_AN)
@@ -483,9 +449,9 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode)
 					return -1;
 				}
 			}
-			return index;
+			return 0;
 		} else if (mwifiex_is_network_compatible_for_wpa2(priv,
-							bss_desc, index)) {
+							bss_desc)) {
 			/* WPA2 enabled */
 			if (((priv->adapter->config_bands & BAND_GN
 			      || priv->adapter->config_bands & BAND_AN)
@@ -503,22 +469,22 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode)
 					return -1;
 				}
 			}
-			return index;
+			return 0;
 		} else if (mwifiex_is_network_compatible_for_adhoc_aes(priv,
 								bss_desc)) {
 			/* Ad-hoc AES enabled */
-			return index;
+			return 0;
 		} else if (mwifiex_is_network_compatible_for_dynamic_wep(priv,
-							bss_desc, index)) {
+							bss_desc)) {
 			/* Dynamic WEP enabled */
-			return index;
+			return 0;
 		}
 
 		/* Security doesn't match */
-		dev_dbg(adapter->dev, "info: %s: failed: index=%d "
+		dev_dbg(adapter->dev, "info: %s: failed: "
 		       "wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode"
 		       "=%#x privacy=%#x\n",
-		       __func__, index,
+		       __func__,
 		       (bss_desc->bcn_wpa_ie) ?
 		       (*(bss_desc->bcn_wpa_ie)).vend_hdr.
 		       element_id : 0,
@@ -538,52 +504,6 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode)
 }
 
 /*
- * This function finds the best SSID in the scan list.
- *
- * It searches the scan table for the best SSID that also matches the current
- * adapter network preference (mode, security etc.).
- */
-static s32
-mwifiex_find_best_network_in_list(struct mwifiex_private *priv)
-{
-	struct mwifiex_adapter *adapter = priv->adapter;
-	u32 mode = priv->bss_mode;
-	s32 best_net = -1;
-	s32 best_rssi = 0;
-	u32 i;
-
-	dev_dbg(adapter->dev, "info: num of BSSIDs = %d\n",
-				adapter->num_in_scan_table);
-
-	for (i = 0; i < adapter->num_in_scan_table; i++) {
-		switch (mode) {
-		case NL80211_IFTYPE_STATION:
-		case NL80211_IFTYPE_ADHOC:
-			if (mwifiex_is_network_compatible(priv, i, mode) >= 0) {
-				if (SCAN_RSSI(adapter->scan_table[i].rssi) >
-				    best_rssi) {
-					best_rssi = SCAN_RSSI(adapter->
-							  scan_table[i].rssi);
-					best_net = i;
-				}
-			}
-			break;
-		case NL80211_IFTYPE_UNSPECIFIED:
-		default:
-			if (SCAN_RSSI(adapter->scan_table[i].rssi) >
-			    best_rssi) {
-				best_rssi = SCAN_RSSI(adapter->scan_table[i].
-						      rssi);
-				best_net = i;
-			}
-			break;
-		}
-	}
-
-	return best_net;
-}
-
-/*
  * This function creates a channel list for the driver to scan, based
  * on region/band information.
  *
@@ -1161,34 +1081,13 @@ mwifiex_ret_802_11_scan_get_tlv_ptrs(struct mwifiex_adapter *adapter,
 }
 
 /*
- * This function interprets a BSS scan response returned from the firmware.
- *
- * The various fixed fields and IEs are parsed and passed back for a BSS
- * probe response or beacon from scan command. Information is recorded as
- * needed in the scan table for that entry.
- *
- * The following IE types are recognized and parsed -
- *      - SSID
- *      - Supported rates
- *      - FH parameters set
- *      - DS parameters set
- *      - CF parameters set
- *      - IBSS parameters set
- *      - ERP information
- *      - Extended supported rates
- *      - Vendor specific (221)
- *      - RSN IE
- *      - WAPI IE
- *      - HT capability
- *      - HT operation
- *      - BSS Coexistence 20/40
- *      - Extended capability
- *      - Overlapping BSS scan parameters
+ * This function parses provided beacon buffer and updates
+ * respective fields in bss descriptor structure.
  */
-static int
-mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter,
-				   struct mwifiex_bssdescriptor *bss_entry,
-				   u8 **beacon_info, u32 *bytes_left)
+int
+mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
+				struct mwifiex_bssdescriptor *bss_entry,
+				u8 *ie_buf, u32 ie_len)
 {
 	int ret = 0;
 	u8 element_id;
@@ -1196,135 +1095,43 @@ mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter,
 	struct ieee_types_ds_param_set *ds_param_set;
 	struct ieee_types_cf_param_set *cf_param_set;
 	struct ieee_types_ibss_param_set *ibss_param_set;
-	__le16 beacon_interval;
-	__le16 capabilities;
 	u8 *current_ptr;
 	u8 *rate;
 	u8 element_len;
 	u16 total_ie_len;
 	u8 bytes_to_copy;
 	u8 rate_size;
-	u16 beacon_size;
 	u8 found_data_rate_ie;
-	u32 bytes_left_for_current_beacon;
+	u32 bytes_left;
 	struct ieee_types_vendor_specific *vendor_ie;
 	const u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 };
 	const u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 };
 
 	found_data_rate_ie = false;
 	rate_size = 0;
-	beacon_size = 0;
-
-	if (*bytes_left >= sizeof(beacon_size)) {
-		/* Extract & convert beacon size from the command buffer */
-		memcpy(&beacon_size, *beacon_info, sizeof(beacon_size));
-		*bytes_left -= sizeof(beacon_size);
-		*beacon_info += sizeof(beacon_size);
-	}
-
-	if (!beacon_size || beacon_size > *bytes_left) {
-		*beacon_info += *bytes_left;
-		*bytes_left = 0;
-		return -1;
-	}
-
-	/* Initialize the current working beacon pointer for this BSS
-	   iteration */
-	current_ptr = *beacon_info;
-
-	/* Advance the return beacon pointer past the current beacon */
-	*beacon_info += beacon_size;
-	*bytes_left -= beacon_size;
-
-	bytes_left_for_current_beacon = beacon_size;
-
-	memcpy(bss_entry->mac_address, current_ptr, ETH_ALEN);
-	dev_dbg(adapter->dev, "info: InterpretIE: AP MAC Addr: %pM\n",
-						bss_entry->mac_address);
-
-	current_ptr += ETH_ALEN;
-	bytes_left_for_current_beacon -= ETH_ALEN;
-
-	if (bytes_left_for_current_beacon < 12) {
-		dev_err(adapter->dev, "InterpretIE: not enough bytes left\n");
-		return -1;
-	}
-
-	/*
-	 * Next 4 fields are RSSI, time stamp, beacon interval,
-	 *   and capability information
-	 */
-
-	/* RSSI is 1 byte long */
-	bss_entry->rssi = (s32) (*current_ptr);
-	dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%02X\n", *current_ptr);
-	current_ptr += 1;
-	bytes_left_for_current_beacon -= 1;
-
-	/*
-	 *  The RSSI is not part of the beacon/probe response.  After we have
-	 *    advanced current_ptr past the RSSI field, save the remaining
-	 *    data for use at the application layer
-	 */
-	bss_entry->beacon_buf = current_ptr;
-	bss_entry->beacon_buf_size = bytes_left_for_current_beacon;
-
-	/* Time stamp is 8 bytes long */
-	memcpy(bss_entry->time_stamp, current_ptr, 8);
-	current_ptr += 8;
-	bytes_left_for_current_beacon -= 8;
-
-	/* Beacon interval is 2 bytes long */
-	memcpy(&beacon_interval, current_ptr, 2);
-	bss_entry->beacon_period = le16_to_cpu(beacon_interval);
-	current_ptr += 2;
-	bytes_left_for_current_beacon -= 2;
-
-	/* Capability information is 2 bytes long */
-	memcpy(&capabilities, current_ptr, 2);
-	dev_dbg(adapter->dev, "info: InterpretIE: capabilities=0x%X\n",
-	       capabilities);
-	bss_entry->cap_info_bitmap = le16_to_cpu(capabilities);
-	current_ptr += 2;
-	bytes_left_for_current_beacon -= 2;
-
-	/* Rest of the current buffer are IE's */
-	dev_dbg(adapter->dev, "info: InterpretIE: IELength for this AP = %d\n",
-	       bytes_left_for_current_beacon);
-
-	if (bss_entry->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) {
-		dev_dbg(adapter->dev, "info: InterpretIE: AP WEP enabled\n");
-		bss_entry->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP;
-	} else {
-		bss_entry->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL;
-	}
-
-	if (bss_entry->cap_info_bitmap & WLAN_CAPABILITY_IBSS)
-		bss_entry->bss_mode = NL80211_IFTYPE_ADHOC;
-	else
-		bss_entry->bss_mode = NL80211_IFTYPE_STATION;
-
+	current_ptr = ie_buf;
+	bytes_left = ie_len;
+	bss_entry->beacon_buf = ie_buf;
+	bss_entry->beacon_buf_size = ie_len;
 
 	/* Process variable IE */
-	while (bytes_left_for_current_beacon >= 2) {
+	while (bytes_left >= 2) {
 		element_id = *current_ptr;
 		element_len = *(current_ptr + 1);
 		total_ie_len = element_len + sizeof(struct ieee_types_header);
 
-		if (bytes_left_for_current_beacon < total_ie_len) {
+		if (bytes_left < total_ie_len) {
 			dev_err(adapter->dev, "err: InterpretIE: in processing"
 				" IE, bytes left < IE length\n");
-			bytes_left_for_current_beacon = 0;
-			ret = -1;
-			continue;
+			return -1;
 		}
 		switch (element_id) {
 		case WLAN_EID_SSID:
 			bss_entry->ssid.ssid_len = element_len;
 			memcpy(bss_entry->ssid.ssid, (current_ptr + 2),
 			       element_len);
-			dev_dbg(adapter->dev, "info: InterpretIE: ssid: %-32s\n",
-			       bss_entry->ssid.ssid);
+			dev_dbg(adapter->dev, "info: InterpretIE: ssid: "
+					      "%-32s\n", bss_entry->ssid.ssid);
 			break;
 
 		case WLAN_EID_SUPP_RATES:
@@ -1471,13 +1278,6 @@ mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter,
 					sizeof(struct ieee_types_header) -
 					bss_entry->beacon_buf);
 			break;
-		case WLAN_EID_OVERLAP_BSS_SCAN_PARAM:
-			bss_entry->bcn_obss_scan =
-				(struct ieee_types_obss_scan_param *)
-				current_ptr;
-			bss_entry->overlap_bss_offset = (u16) (current_ptr -
-							bss_entry->beacon_buf);
-			break;
 		default:
 			break;
 		}
@@ -1485,577 +1285,13 @@ mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter,
 		current_ptr += element_len + 2;
 
 		/* Need to account for IE ID and IE Len */
-		bytes_left_for_current_beacon -= (element_len + 2);
+		bytes_left -= (element_len + 2);
 
-	}	/* while (bytes_left_for_current_beacon > 2) */
+	}	/* while (bytes_left > 2) */
 	return ret;
 }
 
 /*
- * This function adjusts the pointers used in beacon buffers to reflect
- * shifts.
- *
- * The memory allocated for beacon buffers is of fixed sizes where all the
- * saved beacons must be stored. New beacons are added in the free portion
- * of this memory, space permitting; while duplicate beacon buffers are
- * placed at the same start location. However, since duplicate beacon
- * buffers may not match the size of the old one, all the following buffers
- * in the memory must be shifted to either make space, or to fill up freed
- * up space.
- *
- * This function is used to update the beacon buffer pointers that are past
- * an existing beacon buffer that is updated with a new one of different
- * size. The pointers are shifted by a fixed amount, either forward or
- * backward.
- *
- * the following pointers in every affected beacon buffers are changed, if
- * present -
- *      - WPA IE pointer
- *      - RSN IE pointer
- *      - WAPI IE pointer
- *      - HT capability IE pointer
- *      - HT information IE pointer
- *      - BSS coexistence 20/40 IE pointer
- *      - Extended capability IE pointer
- *      - Overlapping BSS scan parameter IE pointer
- */
-static void
-mwifiex_adjust_beacon_buffer_ptrs(struct mwifiex_private *priv, u8 advance,
-				  u8 *bcn_store, u32 rem_bcn_size,
-				  u32 num_of_ent)
-{
-	struct mwifiex_adapter *adapter = priv->adapter;
-	u32 adj_idx;
-	for (adj_idx = 0; adj_idx < num_of_ent; adj_idx++) {
-		if (adapter->scan_table[adj_idx].beacon_buf > bcn_store) {
-
-			if (advance)
-				adapter->scan_table[adj_idx].beacon_buf +=
-					rem_bcn_size;
-			else
-				adapter->scan_table[adj_idx].beacon_buf -=
-					rem_bcn_size;
-
-			if (adapter->scan_table[adj_idx].bcn_wpa_ie)
-				adapter->scan_table[adj_idx].bcn_wpa_ie =
-				(struct ieee_types_vendor_specific *)
-				(adapter->scan_table[adj_idx].beacon_buf +
-				 adapter->scan_table[adj_idx].wpa_offset);
-			if (adapter->scan_table[adj_idx].bcn_rsn_ie)
-				adapter->scan_table[adj_idx].bcn_rsn_ie =
-				(struct ieee_types_generic *)
-				(adapter->scan_table[adj_idx].beacon_buf +
-				 adapter->scan_table[adj_idx].rsn_offset);
-			if (adapter->scan_table[adj_idx].bcn_wapi_ie)
-				adapter->scan_table[adj_idx].bcn_wapi_ie =
-				(struct ieee_types_generic *)
-				(adapter->scan_table[adj_idx].beacon_buf +
-				 adapter->scan_table[adj_idx].wapi_offset);
-			if (adapter->scan_table[adj_idx].bcn_ht_cap)
-				adapter->scan_table[adj_idx].bcn_ht_cap =
-				(struct ieee80211_ht_cap *)
-				(adapter->scan_table[adj_idx].beacon_buf +
-				 adapter->scan_table[adj_idx].ht_cap_offset);
-
-			if (adapter->scan_table[adj_idx].bcn_ht_info)
-				adapter->scan_table[adj_idx].bcn_ht_info =
-				(struct ieee80211_ht_info *)
-				(adapter->scan_table[adj_idx].beacon_buf +
-				 adapter->scan_table[adj_idx].ht_info_offset);
-			if (adapter->scan_table[adj_idx].bcn_bss_co_2040)
-				adapter->scan_table[adj_idx].bcn_bss_co_2040 =
-				(u8 *)
-				(adapter->scan_table[adj_idx].beacon_buf +
-			       adapter->scan_table[adj_idx].bss_co_2040_offset);
-			if (adapter->scan_table[adj_idx].bcn_ext_cap)
-				adapter->scan_table[adj_idx].bcn_ext_cap =
-				(u8 *)
-				(adapter->scan_table[adj_idx].beacon_buf +
-				 adapter->scan_table[adj_idx].ext_cap_offset);
-			if (adapter->scan_table[adj_idx].bcn_obss_scan)
-				adapter->scan_table[adj_idx].bcn_obss_scan =
-				(struct ieee_types_obss_scan_param *)
-				(adapter->scan_table[adj_idx].beacon_buf +
-			       adapter->scan_table[adj_idx].overlap_bss_offset);
-		}
-	}
-}
-
-/*
- * This function updates the pointers used in beacon buffer for given bss
- * descriptor to reflect shifts
- *
- * Following pointers are updated
- *      - WPA IE pointer
- *      - RSN IE pointer
- *      - WAPI IE pointer
- *      - HT capability IE pointer
- *      - HT information IE pointer
- *      - BSS coexistence 20/40 IE pointer
- *      - Extended capability IE pointer
- *      - Overlapping BSS scan parameter IE pointer
- */
-static void
-mwifiex_update_beacon_buffer_ptrs(struct mwifiex_bssdescriptor *beacon)
-{
-	if (beacon->bcn_wpa_ie)
-		beacon->bcn_wpa_ie = (struct ieee_types_vendor_specific *)
-			(beacon->beacon_buf + beacon->wpa_offset);
-	if (beacon->bcn_rsn_ie)
-		beacon->bcn_rsn_ie = (struct ieee_types_generic *)
-			(beacon->beacon_buf + beacon->rsn_offset);
-	if (beacon->bcn_wapi_ie)
-		beacon->bcn_wapi_ie = (struct ieee_types_generic *)
-			(beacon->beacon_buf + beacon->wapi_offset);
-	if (beacon->bcn_ht_cap)
-		beacon->bcn_ht_cap = (struct ieee80211_ht_cap *)
-			(beacon->beacon_buf + beacon->ht_cap_offset);
-	if (beacon->bcn_ht_info)
-		beacon->bcn_ht_info = (struct ieee80211_ht_info *)
-			(beacon->beacon_buf + beacon->ht_info_offset);
-	if (beacon->bcn_bss_co_2040)
-		beacon->bcn_bss_co_2040 = (u8 *) (beacon->beacon_buf +
-			beacon->bss_co_2040_offset);
-	if (beacon->bcn_ext_cap)
-		beacon->bcn_ext_cap = (u8 *) (beacon->beacon_buf +
-			beacon->ext_cap_offset);
-	if (beacon->bcn_obss_scan)
-		beacon->bcn_obss_scan = (struct ieee_types_obss_scan_param *)
-			(beacon->beacon_buf + beacon->overlap_bss_offset);
-}
-
-/*
- * This function stores a beacon or probe response for a BSS returned
- * in the scan.
- *
- * This stores a new scan response or an update for a previous scan response.
- * New entries need to verify that they do not exceed the total amount of
- * memory allocated for the table.
- *
- * Replacement entries need to take into consideration the amount of space
- * currently allocated for the beacon/probe response and adjust the entry
- * as needed.
- *
- * A small amount of extra pad (SCAN_BEACON_ENTRY_PAD) is generally reserved
- * for an entry in case it is a beacon since a probe response for the
- * network will by larger per the standard.  This helps to reduce the
- * amount of memory copying to fit a new probe response into an entry
- * already occupied by a network's previously stored beacon.
- */
-static void
-mwifiex_ret_802_11_scan_store_beacon(struct mwifiex_private *priv,
-				     u32 beacon_idx, u32 num_of_ent,
-				     struct mwifiex_bssdescriptor *new_beacon)
-{
-	struct mwifiex_adapter *adapter = priv->adapter;
-	u8 *bcn_store;
-	u32 new_bcn_size;
-	u32 old_bcn_size;
-	u32 bcn_space;
-
-	if (adapter->scan_table[beacon_idx].beacon_buf) {
-
-		new_bcn_size = new_beacon->beacon_buf_size;
-		old_bcn_size = adapter->scan_table[beacon_idx].beacon_buf_size;
-		bcn_space = adapter->scan_table[beacon_idx].beacon_buf_size_max;
-		bcn_store = adapter->scan_table[beacon_idx].beacon_buf;
-
-		/* Set the max to be the same as current entry unless changed
-		   below */
-		new_beacon->beacon_buf_size_max = bcn_space;
-		if (new_bcn_size == old_bcn_size) {
-			/*
-			 * Beacon is the same size as the previous entry.
-			 *   Replace the previous contents with the scan result
-			 */
-			memcpy(bcn_store, new_beacon->beacon_buf,
-			       new_beacon->beacon_buf_size);
-
-		} else if (new_bcn_size <= bcn_space) {
-			/*
-			 * New beacon size will fit in the amount of space
-			 *   we have previously allocated for it
-			 */
-
-			/* Copy the new beacon buffer entry over the old one */
-			memcpy(bcn_store, new_beacon->beacon_buf, new_bcn_size);
-
-			/*
-			 *  If the old beacon size was less than the maximum
-			 *  we had alloted for the entry, and the new entry
-			 *  is even smaller, reset the max size to the old
-			 *  beacon entry and compress the storage space
-			 *  (leaving a new pad space of (old_bcn_size -
-			 *  new_bcn_size).
-			 */
-			if (old_bcn_size < bcn_space
-			    && new_bcn_size <= old_bcn_size) {
-				/*
-				 * Old Beacon size is smaller than the alloted
-				 * storage size. Shrink the alloted storage
-				 * space.
-				 */
-				dev_dbg(adapter->dev, "info: AppControl:"
-					" smaller duplicate beacon "
-				       "(%d), old = %d, new = %d, space = %d,"
-				       "left = %d\n",
-				       beacon_idx, old_bcn_size, new_bcn_size,
-				       bcn_space,
-				       (int)(sizeof(adapter->bcn_buf) -
-					(adapter->bcn_buf_end -
-					 adapter->bcn_buf)));
-
-				/*
-				 *  memmove (since the memory overlaps) the
-				 *  data after the beacon we just stored to the
-				 *  end of the current beacon.  This cleans up
-				 *  any unused space the old larger beacon was
-				 *  using in the buffer
-				 */
-				memmove(bcn_store + old_bcn_size,
-					bcn_store + bcn_space,
-					adapter->bcn_buf_end - (bcn_store +
-								   bcn_space));
-
-				/*
-				 * Decrement the end pointer by the difference
-				 * between the old larger size and the new
-				 * smaller size since we are using less space
-				 * due to the new beacon being smaller
-				 */
-				adapter->bcn_buf_end -=
-					(bcn_space - old_bcn_size);
-
-				/* Set the maximum storage size to the old
-				   beacon size */
-				new_beacon->beacon_buf_size_max = old_bcn_size;
-
-				/* Adjust beacon buffer pointers that are past
-				   the current */
-				mwifiex_adjust_beacon_buffer_ptrs(priv, 0,
-					bcn_store, (bcn_space - old_bcn_size),
-					num_of_ent);
-			}
-		} else if (adapter->bcn_buf_end + (new_bcn_size - bcn_space)
-			   < (adapter->bcn_buf + sizeof(adapter->bcn_buf))) {
-			/*
-			 * Beacon is larger than space previously allocated
-			 * (bcn_space) and there is enough space left in the
-			 * beaconBuffer to store the additional data
-			 */
-			dev_dbg(adapter->dev, "info: AppControl:"
-				" larger duplicate beacon (%d), "
-			       "old = %d, new = %d, space = %d, left = %d\n",
-			       beacon_idx, old_bcn_size, new_bcn_size,
-			       bcn_space,
-			       (int)(sizeof(adapter->bcn_buf) -
-				(adapter->bcn_buf_end -
-				 adapter->bcn_buf)));
-
-			/*
-			 * memmove (since the memory overlaps) the data
-			 *  after the beacon we just stored to the end of
-			 *  the current beacon.  This moves the data for
-			 *  the beacons after this further in memory to
-			 *  make space for the new larger beacon we are
-			 *  about to copy in.
-			 */
-			memmove(bcn_store + new_bcn_size,
-				bcn_store + bcn_space,
-				adapter->bcn_buf_end - (bcn_store + bcn_space));
-
-			/* Copy the new beacon buffer entry over the old one */
-			memcpy(bcn_store, new_beacon->beacon_buf, new_bcn_size);
-
-			/* Move the beacon end pointer by the amount of new
-			   beacon data we are adding */
-			adapter->bcn_buf_end += (new_bcn_size - bcn_space);
-
-			/*
-			 * This entry is bigger than the alloted max space
-			 *  previously reserved.  Increase the max space to
-			 *  be equal to the new beacon size
-			 */
-			new_beacon->beacon_buf_size_max = new_bcn_size;
-
-			/* Adjust beacon buffer pointers that are past the
-			   current */
-			mwifiex_adjust_beacon_buffer_ptrs(priv, 1, bcn_store,
-						(new_bcn_size - bcn_space),
-						num_of_ent);
-		} else {
-			/*
-			 * Beacon is larger than the previously allocated space,
-			 * but there is not enough free space to store the
-			 * additional data.
-			 */
-			dev_err(adapter->dev, "AppControl: larger duplicate "
-				" beacon (%d), old = %d new = %d, space = %d,"
-				" left = %d\n", beacon_idx, old_bcn_size,
-				new_bcn_size, bcn_space,
-				(int)(sizeof(adapter->bcn_buf) -
-				(adapter->bcn_buf_end - adapter->bcn_buf)));
-
-			/* Storage failure, keep old beacon intact */
-			new_beacon->beacon_buf_size = old_bcn_size;
-			if (new_beacon->bcn_wpa_ie)
-				new_beacon->wpa_offset =
-					adapter->scan_table[beacon_idx].
-					wpa_offset;
-			if (new_beacon->bcn_rsn_ie)
-				new_beacon->rsn_offset =
-					adapter->scan_table[beacon_idx].
-					rsn_offset;
-			if (new_beacon->bcn_wapi_ie)
-				new_beacon->wapi_offset =
-					adapter->scan_table[beacon_idx].
-					wapi_offset;
-			if (new_beacon->bcn_ht_cap)
-				new_beacon->ht_cap_offset =
-					adapter->scan_table[beacon_idx].
-					ht_cap_offset;
-			if (new_beacon->bcn_ht_info)
-				new_beacon->ht_info_offset =
-					adapter->scan_table[beacon_idx].
-					ht_info_offset;
-			if (new_beacon->bcn_bss_co_2040)
-				new_beacon->bss_co_2040_offset =
-					adapter->scan_table[beacon_idx].
-					bss_co_2040_offset;
-			if (new_beacon->bcn_ext_cap)
-				new_beacon->ext_cap_offset =
-					adapter->scan_table[beacon_idx].
-					ext_cap_offset;
-			if (new_beacon->bcn_obss_scan)
-				new_beacon->overlap_bss_offset =
-					adapter->scan_table[beacon_idx].
-					overlap_bss_offset;
-		}
-		/* Point the new entry to its permanent storage space */
-		new_beacon->beacon_buf = bcn_store;
-		mwifiex_update_beacon_buffer_ptrs(new_beacon);
-	} else {
-		/*
-		 * No existing beacon data exists for this entry, check to see
-		 *   if we can fit it in the remaining space
-		 */
-		if (adapter->bcn_buf_end + new_beacon->beacon_buf_size +
-		    SCAN_BEACON_ENTRY_PAD < (adapter->bcn_buf +
-					     sizeof(adapter->bcn_buf))) {
-
-			/*
-			 * Copy the beacon buffer data from the local entry to
-			 * the adapter dev struct buffer space used to store
-			 * the raw beacon data for each entry in the scan table
-			 */
-			memcpy(adapter->bcn_buf_end, new_beacon->beacon_buf,
-			       new_beacon->beacon_buf_size);
-
-			/* Update the beacon ptr to point to the table save
-			   area */
-			new_beacon->beacon_buf = adapter->bcn_buf_end;
-			new_beacon->beacon_buf_size_max =
-				(new_beacon->beacon_buf_size +
-				 SCAN_BEACON_ENTRY_PAD);
-
-			mwifiex_update_beacon_buffer_ptrs(new_beacon);
-
-			/* Increment the end pointer by the size reserved */
-			adapter->bcn_buf_end += new_beacon->beacon_buf_size_max;
-
-			dev_dbg(adapter->dev, "info: AppControl: beacon[%02d]"
-				" sz=%03d, used = %04d, left = %04d\n",
-			       beacon_idx,
-			       new_beacon->beacon_buf_size,
-			       (int)(adapter->bcn_buf_end - adapter->bcn_buf),
-			       (int)(sizeof(adapter->bcn_buf) -
-				(adapter->bcn_buf_end -
-				 adapter->bcn_buf)));
-		} else {
-			/* No space for new beacon */
-			dev_dbg(adapter->dev, "info: AppControl: no space for"
-				" beacon (%d): %pM sz=%03d, left=%03d\n",
-			       beacon_idx, new_beacon->mac_address,
-			       new_beacon->beacon_buf_size,
-			       (int)(sizeof(adapter->bcn_buf) -
-				(adapter->bcn_buf_end -
-				 adapter->bcn_buf)));
-
-			/* Storage failure; clear storage records for this
-			   bcn */
-			new_beacon->beacon_buf = NULL;
-			new_beacon->beacon_buf_size = 0;
-			new_beacon->beacon_buf_size_max = 0;
-			new_beacon->bcn_wpa_ie = NULL;
-			new_beacon->wpa_offset = 0;
-			new_beacon->bcn_rsn_ie = NULL;
-			new_beacon->rsn_offset = 0;
-			new_beacon->bcn_wapi_ie = NULL;
-			new_beacon->wapi_offset = 0;
-			new_beacon->bcn_ht_cap = NULL;
-			new_beacon->ht_cap_offset = 0;
-			new_beacon->bcn_ht_info = NULL;
-			new_beacon->ht_info_offset = 0;
-			new_beacon->bcn_bss_co_2040 = NULL;
-			new_beacon->bss_co_2040_offset = 0;
-			new_beacon->bcn_ext_cap = NULL;
-			new_beacon->ext_cap_offset = 0;
-			new_beacon->bcn_obss_scan = NULL;
-			new_beacon->overlap_bss_offset = 0;
-		}
-	}
-}
-
-/*
- * This function restores a beacon buffer of the current BSS descriptor.
- */
-static void mwifiex_restore_curr_bcn(struct mwifiex_private *priv)
-{
-	struct mwifiex_adapter *adapter = priv->adapter;
-	struct mwifiex_bssdescriptor *curr_bss =
-		&priv->curr_bss_params.bss_descriptor;
-	unsigned long flags;
-
-	if (priv->curr_bcn_buf &&
-	    ((adapter->bcn_buf_end + priv->curr_bcn_size) <
-	     (adapter->bcn_buf + sizeof(adapter->bcn_buf)))) {
-		spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags);
-
-		/* restore the current beacon buffer */
-		memcpy(adapter->bcn_buf_end, priv->curr_bcn_buf,
-		       priv->curr_bcn_size);
-		curr_bss->beacon_buf = adapter->bcn_buf_end;
-		curr_bss->beacon_buf_size = priv->curr_bcn_size;
-		adapter->bcn_buf_end += priv->curr_bcn_size;
-
-		/* adjust the pointers in the current BSS descriptor */
-		if (curr_bss->bcn_wpa_ie)
-			curr_bss->bcn_wpa_ie =
-				(struct ieee_types_vendor_specific *)
-				(curr_bss->beacon_buf +
-				 curr_bss->wpa_offset);
-
-		if (curr_bss->bcn_rsn_ie)
-			curr_bss->bcn_rsn_ie = (struct ieee_types_generic *)
-				(curr_bss->beacon_buf +
-				 curr_bss->rsn_offset);
-
-		if (curr_bss->bcn_ht_cap)
-			curr_bss->bcn_ht_cap = (struct ieee80211_ht_cap *)
-				(curr_bss->beacon_buf +
-				 curr_bss->ht_cap_offset);
-
-		if (curr_bss->bcn_ht_info)
-			curr_bss->bcn_ht_info = (struct ieee80211_ht_info *)
-				(curr_bss->beacon_buf +
-				 curr_bss->ht_info_offset);
-
-		if (curr_bss->bcn_bss_co_2040)
-			curr_bss->bcn_bss_co_2040 =
-				(u8 *) (curr_bss->beacon_buf +
-				 curr_bss->bss_co_2040_offset);
-
-		if (curr_bss->bcn_ext_cap)
-			curr_bss->bcn_ext_cap = (u8 *) (curr_bss->beacon_buf +
-				 curr_bss->ext_cap_offset);
-
-		if (curr_bss->bcn_obss_scan)
-			curr_bss->bcn_obss_scan =
-				(struct ieee_types_obss_scan_param *)
-				(curr_bss->beacon_buf +
-				 curr_bss->overlap_bss_offset);
-
-		spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags);
-
-		dev_dbg(adapter->dev, "info: current beacon restored %d\n",
-		       priv->curr_bcn_size);
-	} else {
-		dev_warn(adapter->dev,
-			"curr_bcn_buf not saved or bcn_buf has no space\n");
-	}
-}
-
-/*
- * This function post processes the scan table after a new scan command has
- * completed.
- *
- * It inspects each entry of the scan table and tries to find an entry that
- * matches with our current associated/joined network from the scan. If
- * one is found, the stored copy of the BSS descriptor of our current network
- * is updated.
- *
- * It also debug dumps the current scan table contents after processing is over.
- */
-static void
-mwifiex_process_scan_results(struct mwifiex_private *priv)
-{
-	struct mwifiex_adapter *adapter = priv->adapter;
-	s32 j;
-	u32 i;
-	unsigned long flags;
-
-	if (priv->media_connected) {
-
-		j = mwifiex_find_ssid_in_list(priv, &priv->curr_bss_params.
-					      bss_descriptor.ssid,
-					      priv->curr_bss_params.
-					      bss_descriptor.mac_address,
-					      priv->bss_mode);
-
-		if (j >= 0) {
-			spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags);
-			priv->curr_bss_params.bss_descriptor.bcn_wpa_ie = NULL;
-			priv->curr_bss_params.bss_descriptor.wpa_offset = 0;
-			priv->curr_bss_params.bss_descriptor.bcn_rsn_ie = NULL;
-			priv->curr_bss_params.bss_descriptor.rsn_offset = 0;
-			priv->curr_bss_params.bss_descriptor.bcn_wapi_ie = NULL;
-			priv->curr_bss_params.bss_descriptor.wapi_offset = 0;
-			priv->curr_bss_params.bss_descriptor.bcn_ht_cap = NULL;
-			priv->curr_bss_params.bss_descriptor.ht_cap_offset =
-				0;
-			priv->curr_bss_params.bss_descriptor.bcn_ht_info = NULL;
-			priv->curr_bss_params.bss_descriptor.ht_info_offset =
-				0;
-			priv->curr_bss_params.bss_descriptor.bcn_bss_co_2040 =
-				NULL;
-			priv->curr_bss_params.bss_descriptor.
-				bss_co_2040_offset = 0;
-			priv->curr_bss_params.bss_descriptor.bcn_ext_cap = NULL;
-			priv->curr_bss_params.bss_descriptor.ext_cap_offset = 0;
-			priv->curr_bss_params.bss_descriptor.
-				bcn_obss_scan = NULL;
-			priv->curr_bss_params.bss_descriptor.
-				overlap_bss_offset = 0;
-			priv->curr_bss_params.bss_descriptor.beacon_buf = NULL;
-			priv->curr_bss_params.bss_descriptor.beacon_buf_size =
-				0;
-			priv->curr_bss_params.bss_descriptor.
-				beacon_buf_size_max = 0;
-
-			dev_dbg(adapter->dev, "info: Found current ssid/bssid"
-				" in list @ index #%d\n", j);
-			/* Make a copy of current BSSID descriptor */
-			memcpy(&priv->curr_bss_params.bss_descriptor,
-			       &adapter->scan_table[j],
-			       sizeof(priv->curr_bss_params.bss_descriptor));
-
-			mwifiex_save_curr_bcn(priv);
-			spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags);
-
-		} else {
-			mwifiex_restore_curr_bcn(priv);
-		}
-	}
-
-	for (i = 0; i < adapter->num_in_scan_table; i++)
-		dev_dbg(adapter->dev, "info: scan:(%02d) %pM "
-		       "RSSI[%03d], SSID[%s]\n",
-		       i, adapter->scan_table[i].mac_address,
-		       (s32) adapter->scan_table[i].rssi,
-		       adapter->scan_table[i].ssid.ssid);
-}
-
-/*
  * This function converts radio type scan parameter to a band configuration
  * to be used in join command.
  */
@@ -2072,175 +1308,6 @@ mwifiex_radio_type_to_band(u8 radio_type)
 }
 
 /*
- * This function deletes a specific indexed entry from the scan table.
- *
- * This also compacts the remaining entries and adjusts any buffering
- * of beacon/probe response data if needed.
- */
-static void
-mwifiex_scan_delete_table_entry(struct mwifiex_private *priv, s32 table_idx)
-{
-	struct mwifiex_adapter *adapter = priv->adapter;
-	u32 del_idx;
-	u32 beacon_buf_adj;
-	u8 *beacon_buf;
-
-	/*
-	 * Shift the saved beacon buffer data for the scan table back over the
-	 *   entry being removed.  Update the end of buffer pointer.  Save the
-	 *   deleted buffer allocation size for pointer adjustments for entries
-	 *   compacted after the deleted index.
-	 */
-	beacon_buf_adj = adapter->scan_table[table_idx].beacon_buf_size_max;
-
-	dev_dbg(adapter->dev, "info: Scan: Delete Entry %d, beacon buffer "
-		"removal = %d bytes\n", table_idx, beacon_buf_adj);
-
-	/* Check if the table entry had storage allocated for its beacon */
-	if (beacon_buf_adj) {
-		beacon_buf = adapter->scan_table[table_idx].beacon_buf;
-
-		/*
-		 * Remove the entry's buffer space, decrement the table end
-		 * pointer by the amount we are removing
-		 */
-		adapter->bcn_buf_end -= beacon_buf_adj;
-
-		dev_dbg(adapter->dev, "info: scan: delete entry %d,"
-			" compact data: %p <- %p (sz = %d)\n",
-		       table_idx, beacon_buf,
-		       beacon_buf + beacon_buf_adj,
-		       (int)(adapter->bcn_buf_end - beacon_buf));
-
-		/*
-		 * Compact data storage.  Copy all data after the deleted
-		 * entry's end address (beacon_buf + beacon_buf_adj) back
-		 * to the original start address (beacon_buf).
-		 *
-		 * Scan table entries affected by the move will have their
-		 * entry pointer adjusted below.
-		 *
-		 * Use memmove since the dest/src memory regions overlap.
-		 */
-		memmove(beacon_buf, beacon_buf + beacon_buf_adj,
-			adapter->bcn_buf_end - beacon_buf);
-	}
-
-	dev_dbg(adapter->dev,
-		"info: Scan: Delete Entry %d, num_in_scan_table = %d\n",
-	       table_idx, adapter->num_in_scan_table);
-
-	/* Shift all of the entries after the table_idx back by one, compacting
-	   the table and removing the requested entry */
-	for (del_idx = table_idx; (del_idx + 1) < adapter->num_in_scan_table;
-	     del_idx++) {
-		/* Copy the next entry over this one */
-		memcpy(adapter->scan_table + del_idx,
-		       adapter->scan_table + del_idx + 1,
-		       sizeof(struct mwifiex_bssdescriptor));
-
-		/*
-		 * Adjust this entry's pointer to its beacon buffer based on
-		 * the removed/compacted entry from the deleted index.  Don't
-		 * decrement if the buffer pointer is NULL (no data stored for
-		 * this entry).
-		 */
-		if (adapter->scan_table[del_idx].beacon_buf) {
-			adapter->scan_table[del_idx].beacon_buf -=
-				beacon_buf_adj;
-			if (adapter->scan_table[del_idx].bcn_wpa_ie)
-				adapter->scan_table[del_idx].bcn_wpa_ie =
-					(struct ieee_types_vendor_specific *)
-					(adapter->scan_table[del_idx].
-					 beacon_buf +
-					 adapter->scan_table[del_idx].
-					 wpa_offset);
-			if (adapter->scan_table[del_idx].bcn_rsn_ie)
-				adapter->scan_table[del_idx].bcn_rsn_ie =
-					(struct ieee_types_generic *)
-					(adapter->scan_table[del_idx].
-					 beacon_buf +
-					 adapter->scan_table[del_idx].
-					 rsn_offset);
-			if (adapter->scan_table[del_idx].bcn_wapi_ie)
-				adapter->scan_table[del_idx].bcn_wapi_ie =
-					(struct ieee_types_generic *)
-					(adapter->scan_table[del_idx].beacon_buf
-					 + adapter->scan_table[del_idx].
-					 wapi_offset);
-			if (adapter->scan_table[del_idx].bcn_ht_cap)
-				adapter->scan_table[del_idx].bcn_ht_cap =
-					(struct ieee80211_ht_cap *)
-					(adapter->scan_table[del_idx].beacon_buf
-					 + adapter->scan_table[del_idx].
-					  ht_cap_offset);
-
-			if (adapter->scan_table[del_idx].bcn_ht_info)
-				adapter->scan_table[del_idx].bcn_ht_info =
-					(struct ieee80211_ht_info *)
-					(adapter->scan_table[del_idx].beacon_buf
-					 + adapter->scan_table[del_idx].
-					  ht_info_offset);
-			if (adapter->scan_table[del_idx].bcn_bss_co_2040)
-				adapter->scan_table[del_idx].bcn_bss_co_2040 =
-					(u8 *)
-					(adapter->scan_table[del_idx].beacon_buf
-					 + adapter->scan_table[del_idx].
-					   bss_co_2040_offset);
-			if (adapter->scan_table[del_idx].bcn_ext_cap)
-				adapter->scan_table[del_idx].bcn_ext_cap =
-					(u8 *)
-					(adapter->scan_table[del_idx].beacon_buf
-					 + adapter->scan_table[del_idx].
-					     ext_cap_offset);
-			if (adapter->scan_table[del_idx].bcn_obss_scan)
-				adapter->scan_table[del_idx].
-					bcn_obss_scan =
-					(struct ieee_types_obss_scan_param *)
-					(adapter->scan_table[del_idx].beacon_buf
-					 + adapter->scan_table[del_idx].
-					     overlap_bss_offset);
-		}
-	}
-
-	/* The last entry is invalid now that it has been deleted or moved
-	   back */
-	memset(adapter->scan_table + adapter->num_in_scan_table - 1,
-	       0x00, sizeof(struct mwifiex_bssdescriptor));
-
-	adapter->num_in_scan_table--;
-}
-
-/*
- * This function deletes all occurrences of a given SSID from the scan table.
- *
- * This iterates through the scan table and deletes all entries that match
- * the given SSID. It also compacts the remaining scan table entries.
- */
-static int
-mwifiex_scan_delete_ssid_table_entry(struct mwifiex_private *priv,
-				     struct mwifiex_802_11_ssid *del_ssid)
-{
-	s32 table_idx = -1;
-
-	dev_dbg(priv->adapter->dev, "info: scan: delete ssid entry: %-32s\n",
-			del_ssid->ssid);
-
-	/* If the requested SSID is found in the table, delete it.  Then keep
-	   searching the table for multiple entires for the SSID until no
-	   more are found */
-	while ((table_idx = mwifiex_find_ssid_in_list(priv, del_ssid, NULL,
-					NL80211_IFTYPE_UNSPECIFIED)) >= 0) {
-		dev_dbg(priv->adapter->dev,
-			"info: Scan: Delete SSID Entry: Found Idx = %d\n",
-		       table_idx);
-		mwifiex_scan_delete_table_entry(priv, table_idx);
-	}
-
-	return table_idx == -1 ? -1 : 0;
-}
-
-/*
  * This is an internal function used to start a scan based on an input
  * configuration.
  *
@@ -2258,7 +1325,6 @@ int mwifiex_scan_networks(struct mwifiex_private *priv,
 	struct mwifiex_ie_types_chan_list_param_set *chan_list_out;
 	u32 buf_size;
 	struct mwifiex_chan_scan_param_set *scan_chan_list;
-	u8 keep_previous_scan;
 	u8 filtered_scan;
 	u8 scan_current_chan_only;
 	u8 max_chan_per_scan;
@@ -2295,24 +1361,11 @@ int mwifiex_scan_networks(struct mwifiex_private *priv,
 		return -ENOMEM;
 	}
 
-	keep_previous_scan = false;
-
 	mwifiex_scan_setup_scan_config(priv, user_scan_in,
 				       &scan_cfg_out->config, &chan_list_out,
 				       scan_chan_list, &max_chan_per_scan,
 				       &filtered_scan, &scan_current_chan_only);
 
-	if (user_scan_in)
-		keep_previous_scan = user_scan_in->keep_previous_scan;
-
-
-	if (!keep_previous_scan) {
-		memset(adapter->scan_table, 0x00,
-		       sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP);
-		adapter->num_in_scan_table = 0;
-		adapter->bcn_buf_end = adapter->bcn_buf;
-	}
-
 	ret = mwifiex_scan_channel_list(priv, max_chan_per_scan, filtered_scan,
 					&scan_cfg_out->config, chan_list_out,
 					scan_chan_list);
@@ -2379,6 +1432,107 @@ int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd,
 }
 
 /*
+ * This function checks compatibility of requested network with current
+ * driver settings.
+ */
+int mwifiex_check_network_compatibility(struct mwifiex_private *priv,
+					struct mwifiex_bssdescriptor *bss_desc)
+{
+	int ret = -1;
+
+	if (!bss_desc)
+		return -1;
+
+	if ((mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv,
+			(u8) bss_desc->bss_band, (u16) bss_desc->channel))) {
+		switch (priv->bss_mode) {
+		case NL80211_IFTYPE_STATION:
+		case NL80211_IFTYPE_ADHOC:
+			ret = mwifiex_is_network_compatible(priv, bss_desc,
+							    priv->bss_mode);
+			if (ret)
+				dev_err(priv->adapter->dev, "cannot find ssid "
+					"%s\n", bss_desc->ssid.ssid);
+				break;
+		default:
+				ret = 0;
+		}
+	}
+
+	return ret;
+}
+
+static int
+mwifiex_update_curr_bss_params(struct mwifiex_private *priv,
+			u8 *bssid, s32 rssi, const u8 *ie_buf,
+			size_t ie_len, u16 beacon_period, u16 cap_info_bitmap)
+{
+	struct mwifiex_bssdescriptor *bss_desc = NULL;
+	int ret;
+	unsigned long flags;
+	u8 *beacon_ie;
+
+	/* Allocate and fill new bss descriptor */
+	bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor),
+			GFP_KERNEL);
+	if (!bss_desc) {
+		dev_err(priv->adapter->dev, " failed to alloc bss_desc\n");
+		return -ENOMEM;
+	}
+	beacon_ie = kzalloc(ie_len, GFP_KERNEL);
+	if (!bss_desc) {
+		dev_err(priv->adapter->dev, " failed to alloc bss_desc\n");
+		return -ENOMEM;
+	}
+	memcpy(beacon_ie, ie_buf, ie_len);
+
+	ret = mwifiex_fill_new_bss_desc(priv, bssid, rssi, beacon_ie,
+					ie_len, beacon_period,
+					cap_info_bitmap, bss_desc);
+	if (ret)
+		goto done;
+
+	ret = mwifiex_check_network_compatibility(priv, bss_desc);
+	if (ret)
+		goto done;
+
+	/* Update current bss descriptor parameters */
+	spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags);
+	priv->curr_bss_params.bss_descriptor.bcn_wpa_ie = NULL;
+	priv->curr_bss_params.bss_descriptor.wpa_offset = 0;
+	priv->curr_bss_params.bss_descriptor.bcn_rsn_ie = NULL;
+	priv->curr_bss_params.bss_descriptor.rsn_offset = 0;
+	priv->curr_bss_params.bss_descriptor.bcn_wapi_ie = NULL;
+	priv->curr_bss_params.bss_descriptor.wapi_offset = 0;
+	priv->curr_bss_params.bss_descriptor.bcn_ht_cap = NULL;
+	priv->curr_bss_params.bss_descriptor.ht_cap_offset =
+		0;
+	priv->curr_bss_params.bss_descriptor.bcn_ht_info = NULL;
+	priv->curr_bss_params.bss_descriptor.ht_info_offset =
+		0;
+	priv->curr_bss_params.bss_descriptor.bcn_bss_co_2040 =
+		NULL;
+	priv->curr_bss_params.bss_descriptor.
+		bss_co_2040_offset = 0;
+	priv->curr_bss_params.bss_descriptor.bcn_ext_cap = NULL;
+	priv->curr_bss_params.bss_descriptor.ext_cap_offset = 0;
+	priv->curr_bss_params.bss_descriptor.beacon_buf = NULL;
+	priv->curr_bss_params.bss_descriptor.beacon_buf_size =
+		0;
+
+	/* Make a copy of current BSSID descriptor */
+	memcpy(&priv->curr_bss_params.bss_descriptor, bss_desc,
+		sizeof(priv->curr_bss_params.bss_descriptor));
+	mwifiex_save_curr_bcn(priv);
+	spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags);
+
+done:
+	kfree(bss_desc);
+	kfree(beacon_ie);
+	return 0;
+}
+
+/*
  * This function handles the command response of scan.
  *
  * The response buffer for the scan command has the following
@@ -2404,21 +1558,16 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
 	struct mwifiex_adapter *adapter = priv->adapter;
 	struct cmd_ctrl_node *cmd_node;
 	struct host_cmd_ds_802_11_scan_rsp *scan_rsp;
-	struct mwifiex_bssdescriptor *bss_new_entry = NULL;
 	struct mwifiex_ie_types_data *tlv_data;
 	struct mwifiex_ie_types_tsf_timestamp *tsf_tlv;
 	u8 *bss_info;
 	u32 scan_resp_size;
 	u32 bytes_left;
-	u32 num_in_table;
-	u32 bss_idx;
 	u32 idx;
 	u32 tlv_buf_size;
-	long long tsf_val;
 	struct mwifiex_chan_freq_power *cfp;
 	struct mwifiex_ie_types_chan_band_list_param_set *chan_band_tlv;
 	struct chan_band_param_set *chan_band;
-	u8 band;
 	u8 is_bgscan_resp;
 	unsigned long flags;
 
@@ -2430,7 +1579,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
 		scan_rsp = &resp->params.scan_resp;
 
 
-	if (scan_rsp->number_of_sets > IW_MAX_AP) {
+	if (scan_rsp->number_of_sets > MWIFIEX_MAX_AP) {
 		dev_err(adapter->dev, "SCAN_RESP: too many AP returned (%d)\n",
 		       scan_rsp->number_of_sets);
 		ret = -1;
@@ -2447,7 +1596,6 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
 		"info: SCAN_RESP: returned %d APs before parsing\n",
 	       scan_rsp->number_of_sets);
 
-	num_in_table = adapter->num_in_scan_table;
 	bss_info = scan_rsp->bss_desc_and_tlv_buffer;
 
 	/*
@@ -2479,125 +1627,147 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
 					     (struct mwifiex_ie_types_data **)
 					     &chan_band_tlv);
 
-	/*
-	 *  Process each scan response returned (scan_rsp->number_of_sets).
-	 *  Save the information in the bss_new_entry and then insert into the
-	 *  driver scan table either as an update to an existing entry
-	 *  or as an addition at the end of the table
-	 */
-	bss_new_entry = kzalloc(sizeof(struct mwifiex_bssdescriptor),
-				GFP_KERNEL);
-	if (!bss_new_entry) {
-		dev_err(adapter->dev, " failed to alloc bss_new_entry\n");
-		return -ENOMEM;
-	}
-
 	for (idx = 0; idx < scan_rsp->number_of_sets && bytes_left; idx++) {
-		/* Zero out the bss_new_entry we are about to store info in */
-		memset(bss_new_entry, 0x00,
-		       sizeof(struct mwifiex_bssdescriptor));
-
-		if (mwifiex_interpret_bss_desc_with_ie(adapter, bss_new_entry,
-							&bss_info,
-							&bytes_left)) {
-			/* Error parsing/interpreting scan response, skipped */
-			dev_err(adapter->dev, "SCAN_RESP: "
-			       "mwifiex_interpret_bss_desc_with_ie "
-			       "returned ERROR\n");
-			continue;
+		u8 bssid[ETH_ALEN];
+		s32 rssi;
+		const u8 *ie_buf;
+		size_t ie_len;
+		int channel = -1;
+		u64 network_tsf = 0;
+		u16 beacon_size = 0;
+		u32 curr_bcn_bytes;
+		u32 freq;
+		u16 beacon_period;
+		u16 cap_info_bitmap;
+		u8 *current_ptr;
+		struct mwifiex_bcn_param *bcn_param;
+
+		if (bytes_left >= sizeof(beacon_size)) {
+			/* Extract & convert beacon size from command buffer */
+			memcpy(&beacon_size, bss_info, sizeof(beacon_size));
+			bytes_left -= sizeof(beacon_size);
+			bss_info += sizeof(beacon_size);
 		}
 
-		/* Process the data fields and IEs returned for this BSS */
-		dev_dbg(adapter->dev, "info: SCAN_RESP: BSSID = %pM\n",
-		       bss_new_entry->mac_address);
+		if (!beacon_size || beacon_size > bytes_left) {
+			bss_info += bytes_left;
+			bytes_left = 0;
+			return -1;
+		}
 
-		/* Search the scan table for the same bssid */
-		for (bss_idx = 0; bss_idx < num_in_table; bss_idx++) {
-			if (memcmp(bss_new_entry->mac_address,
-				adapter->scan_table[bss_idx].mac_address,
-				sizeof(bss_new_entry->mac_address))) {
-				continue;
+		/* Initialize the current working beacon pointer for this BSS
+		 * iteration */
+		current_ptr = bss_info;
+
+		/* Advance the return beacon pointer past the current beacon */
+		bss_info += beacon_size;
+		bytes_left -= beacon_size;
+
+		curr_bcn_bytes = beacon_size;
+
+		/*
+		 * First 5 fields are bssid, RSSI, time stamp, beacon interval,
+		 *   and capability information
+		 */
+		if (curr_bcn_bytes < sizeof(struct mwifiex_bcn_param)) {
+			dev_err(adapter->dev, "InterpretIE: not enough bytes left\n");
+			continue;
+		}
+		bcn_param = (struct mwifiex_bcn_param *)current_ptr;
+		current_ptr += sizeof(*bcn_param);
+		curr_bcn_bytes -= sizeof(*bcn_param);
+
+		memcpy(bssid, bcn_param->bssid, ETH_ALEN);
+
+		rssi = (s32) (bcn_param->rssi);
+		dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%02X\n",
+					rssi);
+
+		beacon_period = le16_to_cpu(bcn_param->beacon_period);
+
+		cap_info_bitmap = le16_to_cpu(bcn_param->cap_info_bitmap);
+		dev_dbg(adapter->dev, "info: InterpretIE: capabilities=0x%X\n",
+				cap_info_bitmap);
+
+		/* Rest of the current buffer are IE's */
+		ie_buf = current_ptr;
+		ie_len = curr_bcn_bytes;
+		dev_dbg(adapter->dev, "info: InterpretIE: IELength for this AP"
+				      " = %d\n", curr_bcn_bytes);
+
+		while (curr_bcn_bytes >= sizeof(struct ieee_types_header)) {
+			u8 element_id, element_len;
+
+			element_id = *current_ptr;
+			element_len = *(current_ptr + 1);
+			if (curr_bcn_bytes < element_len +
+					sizeof(struct ieee_types_header)) {
+				dev_err(priv->adapter->dev, "%s: in processing"
+					" IE, bytes left < IE length\n",
+					__func__);
+				goto done;
 			}
-			/*
-			 * If the SSID matches as well, it is a
-			 * duplicate of this entry.  Keep the bss_idx
-			 * set to this entry so we replace the old
-			 * contents in the table
-			 */
-			if ((bss_new_entry->ssid.ssid_len
-				== adapter->scan_table[bss_idx]. ssid.ssid_len)
-					&& (!memcmp(bss_new_entry->ssid.ssid,
-					adapter->scan_table[bss_idx].ssid.ssid,
-					bss_new_entry->ssid.ssid_len))) {
-				dev_dbg(adapter->dev, "info: SCAN_RESP:"
-					" duplicate of index: %d\n", bss_idx);
+			if (element_id == WLAN_EID_DS_PARAMS) {
+				channel = *(u8 *) (current_ptr +
+					sizeof(struct ieee_types_header));
 				break;
 			}
-		}
-		/*
-		 * If the bss_idx is equal to the number of entries in
-		 * the table, the new entry was not a duplicate; append
-		 * it to the scan table
-		 */
-		if (bss_idx == num_in_table) {
-			/* Range check the bss_idx, keep it limited to
-			   the last entry */
-			if (bss_idx == IW_MAX_AP)
-				bss_idx--;
-			else
-				num_in_table++;
+
+			current_ptr += element_len +
+					sizeof(struct ieee_types_header);
+			curr_bcn_bytes -= element_len +
+					sizeof(struct ieee_types_header);
 		}
 
 		/*
-		 * Save the beacon/probe response returned for later application
-		 * retrieval.  Duplicate beacon/probe responses are updated if
-		 * possible
-		 */
-		mwifiex_ret_802_11_scan_store_beacon(priv, bss_idx,
-						num_in_table, bss_new_entry);
-		/*
 		 * If the TSF TLV was appended to the scan results, save this
 		 * entry's TSF value in the networkTSF field.The networkTSF is
 		 * the firmware's TSF value at the time the beacon or probe
 		 * response was received.
 		 */
-		if (tsf_tlv) {
-			memcpy(&tsf_val, &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE]
-					, sizeof(tsf_val));
-			memcpy(&bss_new_entry->network_tsf, &tsf_val,
-					sizeof(bss_new_entry->network_tsf));
-		}
-		band = BAND_G;
-		if (chan_band_tlv) {
-			chan_band = &chan_band_tlv->chan_band_param[idx];
-			band = mwifiex_radio_type_to_band(chan_band->radio_type
-					& (BIT(0) | BIT(1)));
-		}
-
-		/* Save the band designation for this entry for use in join */
-		bss_new_entry->bss_band = band;
-		cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv,
-					(u8) bss_new_entry->bss_band,
-					(u16)bss_new_entry->channel);
+		if (tsf_tlv)
+			memcpy(&network_tsf,
+					&tsf_tlv->tsf_data[idx * TSF_DATA_SIZE],
+					sizeof(network_tsf));
+
+		if (channel != -1) {
+			struct ieee80211_channel *chan;
+			u8 band;
+
+			band = BAND_G;
+			if (chan_band_tlv) {
+				chan_band =
+					&chan_band_tlv->chan_band_param[idx];
+				band = mwifiex_radio_type_to_band(
+						chan_band->radio_type
+						& (BIT(0) | BIT(1)));
+			}
 
-		if (cfp)
-			bss_new_entry->freq = cfp->freq;
-		else
-			bss_new_entry->freq = 0;
+			cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(
+						priv, (u8)band, (u16)channel);
 
-		/* Copy the locally created bss_new_entry to the scan table */
-		memcpy(&adapter->scan_table[bss_idx], bss_new_entry,
-		       sizeof(adapter->scan_table[bss_idx]));
+			freq = cfp ? cfp->freq : 0;
 
-	}
+			chan = ieee80211_get_channel(priv->wdev->wiphy, freq);
 
-	dev_dbg(adapter->dev,
-		"info: SCAN_RESP: Scanned %2d APs, %d valid, %d total\n",
-	       scan_rsp->number_of_sets,
-	       num_in_table - adapter->num_in_scan_table, num_in_table);
+			if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) {
+				cfg80211_inform_bss(priv->wdev->wiphy, chan,
+					bssid, network_tsf, cap_info_bitmap,
+					beacon_period, ie_buf, ie_len, rssi,
+					GFP_KERNEL);
 
-	/* Update the total number of BSSIDs in the scan table */
-	adapter->num_in_scan_table = num_in_table;
+				if (priv->media_connected && !memcmp(bssid,
+					priv->curr_bss_params.bss_descriptor
+						     .mac_address, ETH_ALEN))
+					mwifiex_update_curr_bss_params(priv,
+							bssid, rssi, ie_buf,
+							ie_len, beacon_period,
+							cap_info_bitmap);
+			}
+		} else {
+			dev_dbg(adapter->dev, "missing BSS channel IE\n");
+		}
+	}
 
 	spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
 	if (list_empty(&adapter->scan_pending_q)) {
@@ -2605,12 +1775,6 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
 		spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
 		adapter->scan_processing = false;
 		spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
-		/*
-		 * Process the resulting scan table:
-		 *   - Remove any bad ssids
-		 *   - Update our current BSS information from scan data
-		 */
-		mwifiex_process_scan_results(priv);
 
 		/* Need to indicate IOCTL complete */
 		if (adapter->curr_cmd->wait_q_enabled) {
@@ -2636,7 +1800,6 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
 	}
 
 done:
-	kfree((u8 *) bss_new_entry);
 	return ret;
 }
 
@@ -2663,141 +1826,6 @@ int mwifiex_cmd_802_11_bg_scan_query(struct host_cmd_ds_command *cmd)
 }
 
 /*
- * This function finds a SSID in the scan table.
- *
- * A BSSID may optionally be provided to qualify the SSID.
- * For non-Auto mode, further check is made to make sure the
- * BSS found in the scan table is compatible with the current
- * settings of the driver.
- */
-s32
-mwifiex_find_ssid_in_list(struct mwifiex_private *priv,
-			  struct mwifiex_802_11_ssid *ssid, u8 *bssid,
-			  u32 mode)
-{
-	struct mwifiex_adapter *adapter = priv->adapter;
-	s32 net = -1, j;
-	u8 best_rssi = 0;
-	u32 i;
-
-	dev_dbg(adapter->dev, "info: num of entries in table = %d\n",
-	       adapter->num_in_scan_table);
-
-	/*
-	 * Loop through the table until the maximum is reached or until a match
-	 *   is found based on the bssid field comparison
-	 */
-	for (i = 0;
-	     i < adapter->num_in_scan_table && (!bssid || (bssid && net < 0));
-	     i++) {
-		if (!mwifiex_ssid_cmp(&adapter->scan_table[i].ssid, ssid) &&
-		    (!bssid
-		     || !memcmp(adapter->scan_table[i].mac_address, bssid,
-				ETH_ALEN))
-		    &&
-		    (mwifiex_get_cfp_by_band_and_channel_from_cfg80211
-		     (priv, (u8) adapter->scan_table[i].bss_band,
-		      (u16) adapter->scan_table[i].channel))) {
-			switch (mode) {
-			case NL80211_IFTYPE_STATION:
-			case NL80211_IFTYPE_ADHOC:
-				j = mwifiex_is_network_compatible(priv, i,
-								  mode);
-
-				if (j >= 0) {
-					if (SCAN_RSSI
-					    (adapter->scan_table[i].rssi) >
-					    best_rssi) {
-						best_rssi = SCAN_RSSI(adapter->
-								  scan_table
-								  [i].rssi);
-						net = i;
-					}
-				} else {
-					if (net == -1)
-						net = j;
-				}
-				break;
-			case NL80211_IFTYPE_UNSPECIFIED:
-			default:
-				/*
-				 * Do not check compatibility if the mode
-				 * requested is Auto/Unknown.  Allows generic
-				 * find to work without verifying against the
-				 * Adapter security settings
-				 */
-				if (SCAN_RSSI(adapter->scan_table[i].rssi) >
-				    best_rssi) {
-					best_rssi = SCAN_RSSI(adapter->
-							  scan_table[i].rssi);
-					net = i;
-				}
-				break;
-			}
-		}
-	}
-
-	return net;
-}
-
-/*
- * This function finds a specific compatible BSSID in the scan list.
- *
- * This function loops through the scan table looking for a compatible
- * match. If a BSSID matches, but the BSS is found to be not compatible
- * the function ignores it and continues to search through the rest of
- * the entries in case there is an AP with multiple SSIDs assigned to
- * the same BSSID.
- */
-s32
-mwifiex_find_bssid_in_list(struct mwifiex_private *priv, u8 *bssid,
-			   u32 mode)
-{
-	struct mwifiex_adapter *adapter = priv->adapter;
-	s32 net = -1;
-	u32 i;
-
-	if (!bssid)
-		return -1;
-
-	dev_dbg(adapter->dev, "info: FindBSSID: Num of BSSIDs = %d\n",
-	       adapter->num_in_scan_table);
-
-	/*
-	 * Look through the scan table for a compatible match. The ret return
-	 *   variable will be equal to the index in the scan table (greater
-	 *   than zero) if the network is compatible.  The loop will continue
-	 *   past a matched bssid that is not compatible in case there is an
-	 *   AP with multiple SSIDs assigned to the same BSSID
-	 */
-	for (i = 0; net < 0 && i < adapter->num_in_scan_table; i++) {
-		if (!memcmp
-		    (adapter->scan_table[i].mac_address, bssid, ETH_ALEN)
-			&& mwifiex_get_cfp_by_band_and_channel_from_cfg80211
-								(priv,
-							    (u8) adapter->
-							    scan_table[i].
-							    bss_band,
-							    (u16) adapter->
-							    scan_table[i].
-							    channel)) {
-			switch (mode) {
-			case NL80211_IFTYPE_STATION:
-			case NL80211_IFTYPE_ADHOC:
-				net = mwifiex_is_network_compatible(priv, i,
-								    mode);
-				break;
-			default:
-				net = i;
-				break;
-			}
-		}
-	}
-
-	return net;
-}
-
-/*
  * This function inserts scan command node to the scan pending queue.
  */
 void
@@ -2814,42 +1842,6 @@ mwifiex_queue_scan_cmd(struct mwifiex_private *priv,
 }
 
 /*
- * This function finds an AP with specific ssid in the scan list.
- */
-int mwifiex_find_best_network(struct mwifiex_private *priv,
-			      struct mwifiex_ssid_bssid *req_ssid_bssid)
-{
-	struct mwifiex_adapter *adapter = priv->adapter;
-	struct mwifiex_bssdescriptor *req_bss;
-	s32 i;
-
-	memset(req_ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid));
-
-	i = mwifiex_find_best_network_in_list(priv);
-
-	if (i >= 0) {
-		req_bss = &adapter->scan_table[i];
-		memcpy(&req_ssid_bssid->ssid, &req_bss->ssid,
-		       sizeof(struct mwifiex_802_11_ssid));
-		memcpy((u8 *) &req_ssid_bssid->bssid,
-		       (u8 *) &req_bss->mac_address, ETH_ALEN);
-
-		/* Make sure we are in the right mode */
-		if (priv->bss_mode == NL80211_IFTYPE_UNSPECIFIED)
-			priv->bss_mode = req_bss->bss_mode;
-	}
-
-	if (!req_ssid_bssid->ssid.ssid_len)
-		return -1;
-
-	dev_dbg(adapter->dev, "info: Best network found = [%s], "
-	       "[%pM]\n", req_ssid_bssid->ssid.ssid,
-	       req_ssid_bssid->bssid);
-
-	return 0;
-}
-
-/*
  * This function sends a scan command for all available channels to the
  * firmware, filtered on a specific SSID.
  */
@@ -2874,8 +1866,6 @@ static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv,
 		return ret;
 	}
 
-	mwifiex_scan_delete_ssid_table_entry(priv, req_ssid);
-
 	scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), GFP_KERNEL);
 	if (!scan_cfg) {
 		dev_err(adapter->dev, "failed to alloc scan_cfg\n");
@@ -2884,7 +1874,6 @@ static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv,
 
 	memcpy(scan_cfg->ssid_list[0].ssid, req_ssid->ssid,
 	       req_ssid->ssid_len);
-	scan_cfg->keep_previous_scan = true;
 
 	ret = mwifiex_scan_networks(priv, scan_cfg);
 
@@ -3010,6 +1999,39 @@ mwifiex_save_curr_bcn(struct mwifiex_private *priv)
 		curr_bss->beacon_buf_size);
 	dev_dbg(priv->adapter->dev, "info: current beacon saved %d\n",
 		priv->curr_bcn_size);
+
+	curr_bss->beacon_buf = priv->curr_bcn_buf;
+
+	/* adjust the pointers in the current BSS descriptor */
+	if (curr_bss->bcn_wpa_ie)
+		curr_bss->bcn_wpa_ie =
+			(struct ieee_types_vendor_specific *)
+			(curr_bss->beacon_buf +
+			 curr_bss->wpa_offset);
+
+	if (curr_bss->bcn_rsn_ie)
+		curr_bss->bcn_rsn_ie = (struct ieee_types_generic *)
+			(curr_bss->beacon_buf +
+			 curr_bss->rsn_offset);
+
+	if (curr_bss->bcn_ht_cap)
+		curr_bss->bcn_ht_cap = (struct ieee80211_ht_cap *)
+			(curr_bss->beacon_buf +
+			 curr_bss->ht_cap_offset);
+
+	if (curr_bss->bcn_ht_info)
+		curr_bss->bcn_ht_info = (struct ieee80211_ht_info *)
+			(curr_bss->beacon_buf +
+			 curr_bss->ht_info_offset);
+
+	if (curr_bss->bcn_bss_co_2040)
+		curr_bss->bcn_bss_co_2040 =
+			(u8 *) (curr_bss->beacon_buf +
+					curr_bss->bss_co_2040_offset);
+
+	if (curr_bss->bcn_ext_cap)
+		curr_bss->bcn_ext_cap = (u8 *) (curr_bss->beacon_buf +
+				curr_bss->ext_cap_offset);
 }
 
 /*
diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c
index fc265cab0907..f204810e8338 100644
--- a/drivers/net/wireless/mwifiex/sta_event.c
+++ b/drivers/net/wireless/mwifiex/sta_event.c
@@ -130,8 +130,8 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv)
 	if (netif_carrier_ok(priv->netdev))
 		netif_carrier_off(priv->netdev);
 	/* Reset wireless stats signal info */
-	priv->w_stats.qual.level = 0;
-	priv->w_stats.qual.noise = 0;
+	priv->qual_level = 0;
+	priv->qual_noise = 0;
 }
 
 /*
@@ -299,11 +299,6 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
 
 	case EVENT_BG_SCAN_REPORT:
 		dev_dbg(adapter->dev, "event: BGS_REPORT\n");
-		/* Clear the previous scan result */
-		memset(adapter->scan_table, 0x00,
-		       sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP);
-		adapter->num_in_scan_table = 0;
-		adapter->bcn_buf_end = adapter->bcn_buf;
 		ret = mwifiex_send_cmd_async(priv,
 					     HostCmd_CMD_802_11_BG_SCAN_QUERY,
 					     HostCmd_ACT_GEN_GET, 0, NULL);
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index c34ff8c4f4f8..3fca219bcfb6 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -142,90 +142,142 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
 }
 
 /*
+ * This function fills bss descriptor structure using provided
+ * information.
+ */
+int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
+			      u8 *bssid, s32 rssi, u8 *ie_buf,
+			      size_t ie_len, u16 beacon_period,
+			      u16 cap_info_bitmap,
+			      struct mwifiex_bssdescriptor *bss_desc)
+{
+	int ret;
+
+	memcpy(bss_desc->mac_address, bssid, ETH_ALEN);
+	bss_desc->rssi = rssi;
+	bss_desc->beacon_buf = ie_buf;
+	bss_desc->beacon_buf_size = ie_len;
+	bss_desc->beacon_period = beacon_period;
+	bss_desc->cap_info_bitmap = cap_info_bitmap;
+	if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) {
+		dev_dbg(priv->adapter->dev, "info: InterpretIE: AP WEP enabled\n");
+		bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP;
+	} else {
+		bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL;
+	}
+	if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_IBSS)
+		bss_desc->bss_mode = NL80211_IFTYPE_ADHOC;
+	else
+		bss_desc->bss_mode = NL80211_IFTYPE_STATION;
+
+	ret = mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc,
+					      ie_buf, ie_len);
+
+	return ret;
+}
+
+/*
  * In Ad-Hoc mode, the IBSS is created if not found in scan list.
  * In both Ad-Hoc and infra mode, an deauthentication is performed
  * first.
  */
-int mwifiex_bss_start(struct mwifiex_private *priv,
-		      struct mwifiex_ssid_bssid *ssid_bssid)
+int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
+		      struct mwifiex_802_11_ssid *req_ssid)
 {
 	int ret;
 	struct mwifiex_adapter *adapter = priv->adapter;
-	s32 i = -1;
+	struct mwifiex_bssdescriptor *bss_desc = NULL;
+	u8 *beacon_ie = NULL;
 
 	priv->scan_block = false;
-	if (!ssid_bssid)
-		return -1;
+
+	if (bss) {
+		/* Allocate and fill new bss descriptor */
+		bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor),
+				GFP_KERNEL);
+		if (!bss_desc) {
+			dev_err(priv->adapter->dev, " failed to alloc bss_desc\n");
+			return -ENOMEM;
+		}
+		beacon_ie = kzalloc(bss->len_beacon_ies, GFP_KERNEL);
+		if (!beacon_ie) {
+			dev_err(priv->adapter->dev, " failed to alloc bss_desc\n");
+			return -ENOMEM;
+		}
+		memcpy(beacon_ie, bss->information_elements,
+		       bss->len_beacon_ies);
+		ret = mwifiex_fill_new_bss_desc(priv, bss->bssid, bss->signal,
+						beacon_ie, bss->len_beacon_ies,
+						bss->beacon_interval,
+						bss->capability, bss_desc);
+		if (ret)
+			goto done;
+	}
 
 	if (priv->bss_mode == NL80211_IFTYPE_STATION) {
 		/* Infra mode */
 		ret = mwifiex_deauthenticate(priv, NULL);
 		if (ret)
-			return ret;
+			goto done;
 
-		/* Search for the requested SSID in the scan table */
-		if (ssid_bssid->ssid.ssid_len)
-			i = mwifiex_find_ssid_in_list(priv, &ssid_bssid->ssid,
-						NULL, NL80211_IFTYPE_STATION);
-		else
-			i = mwifiex_find_bssid_in_list(priv,
-						(u8 *) &ssid_bssid->bssid,
-						NL80211_IFTYPE_STATION);
-		if (i < 0)
-			return -1;
+		ret = mwifiex_check_network_compatibility(priv, bss_desc);
+		if (ret)
+			goto done;
+
+		dev_dbg(adapter->dev, "info: SSID found in scan list ... "
+				      "associating...\n");
 
-		dev_dbg(adapter->dev,
-			"info: SSID found in scan list ... associating...\n");
+		if (!netif_queue_stopped(priv->netdev))
+			netif_stop_queue(priv->netdev);
 
 		/* Clear any past association response stored for
 		 * application retrieval */
 		priv->assoc_rsp_size = 0;
-		ret = mwifiex_associate(priv, &adapter->scan_table[i]);
-		if (ret)
-			return ret;
+		ret = mwifiex_associate(priv, bss_desc);
+		if (bss)
+			cfg80211_put_bss(bss);
 	} else {
 		/* Adhoc mode */
 		/* If the requested SSID matches current SSID, return */
-		if (ssid_bssid->ssid.ssid_len &&
+		if (bss_desc && bss_desc->ssid.ssid_len &&
 		    (!mwifiex_ssid_cmp
 		     (&priv->curr_bss_params.bss_descriptor.ssid,
-		      &ssid_bssid->ssid)))
+		      &bss_desc->ssid))) {
+			kfree(bss_desc);
+			kfree(beacon_ie);
 			return 0;
+		}
 
 		/* Exit Adhoc mode first */
 		dev_dbg(adapter->dev, "info: Sending Adhoc Stop\n");
 		ret = mwifiex_deauthenticate(priv, NULL);
 		if (ret)
-			return ret;
+			goto done;
 
 		priv->adhoc_is_link_sensed = false;
 
-		/* Search for the requested network in the scan table */
-		if (ssid_bssid->ssid.ssid_len)
-			i = mwifiex_find_ssid_in_list(priv,
-						      &ssid_bssid->ssid, NULL,
-						      NL80211_IFTYPE_ADHOC);
-		else
-			i = mwifiex_find_bssid_in_list(priv,
-						       (u8 *)&ssid_bssid->bssid,
-						       NL80211_IFTYPE_ADHOC);
-
-		if (i >= 0) {
+		ret = mwifiex_check_network_compatibility(priv, bss_desc);
+
+		if (!netif_queue_stopped(priv->netdev))
+			netif_stop_queue(priv->netdev);
+
+		if (!ret) {
 			dev_dbg(adapter->dev, "info: network found in scan"
 							" list. Joining...\n");
-			ret = mwifiex_adhoc_join(priv, &adapter->scan_table[i]);
-			if (ret)
-				return ret;
+			ret = mwifiex_adhoc_join(priv, bss_desc);
+			if (bss)
+				cfg80211_put_bss(bss);
 		} else {
 			dev_dbg(adapter->dev, "info: Network not found in "
 				"the list, creating adhoc with ssid = %s\n",
-			       ssid_bssid->ssid.ssid);
-			ret = mwifiex_adhoc_start(priv, &ssid_bssid->ssid);
-			if (ret)
-				return ret;
+				req_ssid->ssid);
+			ret = mwifiex_adhoc_start(priv, req_ssid);
 		}
 	}
 
+done:
+	kfree(bss_desc);
+	kfree(beacon_ie);
 	return ret;
 }
 
@@ -376,7 +428,6 @@ int mwifiex_get_bss_info(struct mwifiex_private *priv,
 {
 	struct mwifiex_adapter *adapter = priv->adapter;
 	struct mwifiex_bssdescriptor *bss_desc;
-	s32 tbl_idx;
 
 	if (!info)
 		return -1;
@@ -394,17 +445,6 @@ int mwifiex_get_bss_info(struct mwifiex_private *priv,
 
 	info->region_code = adapter->region_code;
 
-	/* Scan table index if connected */
-	info->scan_table_idx = 0;
-	if (priv->media_connected) {
-		tbl_idx =
-			mwifiex_find_ssid_in_list(priv, &bss_desc->ssid,
-						  bss_desc->mac_address,
-						  priv->bss_mode);
-		if (tbl_idx >= 0)
-			info->scan_table_idx = tbl_idx;
-	}
-
 	info->media_connected = priv->media_connected;
 
 	info->max_power_level = priv->max_tx_power_level;
@@ -586,50 +626,6 @@ static int mwifiex_bss_ioctl_ibss_channel(struct mwifiex_private *priv,
 }
 
 /*
- * IOCTL request handler to find a particular BSS.
- *
- * The BSS can be searched with either a BSSID or a SSID. If none of
- * these are provided, just the best BSS (best RSSI) is returned.
- */
-int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *priv,
-			       struct mwifiex_ssid_bssid *ssid_bssid)
-{
-	struct mwifiex_adapter *adapter = priv->adapter;
-	struct mwifiex_bssdescriptor *bss_desc;
-	u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
-	u8 mac[ETH_ALEN];
-	int i = 0;
-
-	if (memcmp(ssid_bssid->bssid, zero_mac, sizeof(zero_mac))) {
-		i = mwifiex_find_bssid_in_list(priv,
-					       (u8 *) ssid_bssid->bssid,
-					       priv->bss_mode);
-		if (i < 0) {
-			memcpy(mac, ssid_bssid->bssid, sizeof(mac));
-			dev_err(adapter->dev, "cannot find bssid %pM\n", mac);
-			return -1;
-		}
-		bss_desc = &adapter->scan_table[i];
-		memcpy(&ssid_bssid->ssid, &bss_desc->ssid,
-				sizeof(struct mwifiex_802_11_ssid));
-	} else if (ssid_bssid->ssid.ssid_len) {
-		i = mwifiex_find_ssid_in_list(priv, &ssid_bssid->ssid, NULL,
-					      priv->bss_mode);
-		if (i < 0) {
-			dev_err(adapter->dev, "cannot find ssid %s\n",
-					ssid_bssid->ssid.ssid);
-			return -1;
-		}
-		bss_desc = &adapter->scan_table[i];
-		memcpy(ssid_bssid->bssid, bss_desc->mac_address, ETH_ALEN);
-	} else {
-		return mwifiex_find_best_network(priv, ssid_bssid);
-	}
-
-	return 0;
-}
-
-/*
  * IOCTL request handler to change Ad-Hoc channel.
  *
  * This function allocates the IOCTL request buffer, fills it
@@ -653,6 +649,8 @@ mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel)
 	struct mwifiex_bss_info bss_info;
 	struct mwifiex_ssid_bssid ssid_bssid;
 	u16 curr_chan = 0;
+	struct cfg80211_bss *bss = NULL;
+	struct ieee80211_channel *chan;
 
 	memset(&bss_info, 0, sizeof(bss_info));
 
@@ -688,12 +686,20 @@ mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel)
 		ret = -1;
 		goto done;
 	}
-	/* Start/Join Adhoc network */
-	memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid));
-	memcpy(&ssid_bssid.ssid, &bss_info.ssid,
-	       sizeof(struct mwifiex_802_11_ssid));
 
-	ret = mwifiex_bss_start(priv, &ssid_bssid);
+	chan = __ieee80211_get_channel(priv->wdev->wiphy,
+			ieee80211_channel_to_frequency(channel,
+						priv->curr_bss_params.band));
+
+	/* Find the BSS we want using available scan results */
+	bss = cfg80211_get_bss(priv->wdev->wiphy, chan, bss_info.bssid,
+			       bss_info.ssid.ssid, bss_info.ssid.ssid_len,
+			       WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
+	if (!bss)
+		wiphy_warn(priv->wdev->wiphy, "assoc: bss %pM not in scan results\n",
+			  bss_info.bssid);
+
+	ret = mwifiex_bss_start(priv, bss, &bss_info.ssid);
 done:
 	return ret;
 }
@@ -1280,9 +1286,9 @@ int mwifiex_get_signal_info(struct mwifiex_private *priv,
 
 	if (!status) {
 		if (signal->selector & BCN_RSSI_AVG_MASK)
-			priv->w_stats.qual.level = signal->bcn_rssi_avg;
+			priv->qual_level = signal->bcn_rssi_avg;
 		if (signal->selector & BCN_NF_AVG_MASK)
-			priv->w_stats.qual.noise = signal->bcn_nf_avg;
+			priv->qual_noise = signal->bcn_nf_avg;
 	}
 
 	return status;
@@ -1341,18 +1347,8 @@ int
 mwifiex_get_stats_info(struct mwifiex_private *priv,
 		       struct mwifiex_ds_get_stats *log)
 {
-	int ret;
-
-	ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_GET_LOG,
+	return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_GET_LOG,
 				    HostCmd_ACT_GEN_GET, 0, log);
-
-	if (!ret) {
-		priv->w_stats.discard.fragment = log->fcs_error;
-		priv->w_stats.discard.retries = log->retry;
-		priv->w_stats.discard.misc = log->ack_failure;
-	}
-
-	return ret;
 }
 
 /*
@@ -1594,7 +1590,7 @@ mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len)
 {
 	struct mwifiex_ds_misc_gen_ie gen_ie;
 
-	if (ie_len > IW_CUSTOM_MAX)
+	if (ie_len > IEEE_MAX_IE_SIZE)
 		return -EFAULT;
 
 	gen_ie.type = MWIFIEX_IE_TYPE_GEN_IE;
diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c
index bbb9beb206b1..33747e131a96 100644
--- a/drivers/net/wireless/orinoco/wext.c
+++ b/drivers/net/wireless/orinoco/wext.c
@@ -9,6 +9,7 @@
 #include <linux/ieee80211.h>
 #include <net/iw_handler.h>
 #include <net/cfg80211.h>
+#include <net/cfg80211-wext.h>
 
 #include "hermes.h"
 #include "hermes_rid.h"
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 6e0c61145b18..0c13840a7de5 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -36,13 +36,11 @@
 #include <linux/mii.h>
 #include <linux/usb.h>
 #include <linux/usb/cdc.h>
-#include <linux/wireless.h>
 #include <linux/ieee80211.h>
 #include <linux/if_arp.h>
 #include <linux/ctype.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
-#include <net/iw_handler.h>
 #include <net/cfg80211.h>
 #include <linux/usb/usbnet.h>
 #include <linux/usb/rndis_host.h>
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 76bcc3547976..daa32fc9398b 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -645,11 +645,6 @@ static void rt2400pci_start_queue(struct data_queue *queue)
 		rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
 		break;
 	case QID_BEACON:
-		/*
-		 * Allow the tbtt tasklet to be scheduled.
-		 */
-		tasklet_enable(&rt2x00dev->tbtt_tasklet);
-
 		rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
 		rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
 		rt2x00_set_field32(&reg, CSR14_TBCN, 1);
@@ -715,7 +710,7 @@ static void rt2400pci_stop_queue(struct data_queue *queue)
 		/*
 		 * Wait for possibly running tbtt tasklets.
 		 */
-		tasklet_disable(&rt2x00dev->tbtt_tasklet);
+		tasklet_kill(&rt2x00dev->tbtt_tasklet);
 		break;
 	default:
 		break;
@@ -982,12 +977,6 @@ static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
 	if (state == STATE_RADIO_IRQ_ON) {
 		rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
 		rt2x00pci_register_write(rt2x00dev, CSR7, reg);
-
-		/*
-		 * Enable tasklets.
-		 */
-		tasklet_enable(&rt2x00dev->txstatus_tasklet);
-		tasklet_enable(&rt2x00dev->rxdone_tasklet);
 	}
 
 	/*
@@ -1011,8 +1000,9 @@ static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
 		 * Ensure that all tasklets are finished before
 		 * disabling the interrupts.
 		 */
-		tasklet_disable(&rt2x00dev->txstatus_tasklet);
-		tasklet_disable(&rt2x00dev->rxdone_tasklet);
+		tasklet_kill(&rt2x00dev->txstatus_tasklet);
+		tasklet_kill(&rt2x00dev->rxdone_tasklet);
+		tasklet_kill(&rt2x00dev->tbtt_tasklet);
 	}
 }
 
@@ -1347,22 +1337,25 @@ static void rt2400pci_txstatus_tasklet(unsigned long data)
 	/*
 	 * Enable all TXDONE interrupts again.
 	 */
-	spin_lock_irq(&rt2x00dev->irqmask_lock);
+	if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) {
+		spin_lock_irq(&rt2x00dev->irqmask_lock);
 
-	rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
-	rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, 0);
-	rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, 0);
-	rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, 0);
-	rt2x00pci_register_write(rt2x00dev, CSR8, reg);
+		rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
+		rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, 0);
+		rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, 0);
+		rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, 0);
+		rt2x00pci_register_write(rt2x00dev, CSR8, reg);
 
-	spin_unlock_irq(&rt2x00dev->irqmask_lock);
+		spin_unlock_irq(&rt2x00dev->irqmask_lock);
+	}
 }
 
 static void rt2400pci_tbtt_tasklet(unsigned long data)
 {
 	struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
 	rt2x00lib_beacondone(rt2x00dev);
-	rt2400pci_enable_interrupt(rt2x00dev, CSR8_TBCN_EXPIRE);
+	if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+		rt2400pci_enable_interrupt(rt2x00dev, CSR8_TBCN_EXPIRE);
 }
 
 static void rt2400pci_rxdone_tasklet(unsigned long data)
@@ -1370,7 +1363,7 @@ static void rt2400pci_rxdone_tasklet(unsigned long data)
 	struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
 	if (rt2x00pci_rxdone(rt2x00dev))
 		tasklet_schedule(&rt2x00dev->rxdone_tasklet);
-	else
+	else if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
 		rt2400pci_enable_interrupt(rt2x00dev, CSR8_RXDONE);
 }
 
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index c288d951c034..b46c3b8866fa 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -735,11 +735,6 @@ static void rt2500pci_start_queue(struct data_queue *queue)
 		rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
 		break;
 	case QID_BEACON:
-		/*
-		 * Allow the tbtt tasklet to be scheduled.
-		 */
-		tasklet_enable(&rt2x00dev->tbtt_tasklet);
-
 		rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
 		rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
 		rt2x00_set_field32(&reg, CSR14_TBCN, 1);
@@ -805,7 +800,7 @@ static void rt2500pci_stop_queue(struct data_queue *queue)
 		/*
 		 * Wait for possibly running tbtt tasklets.
 		 */
-		tasklet_disable(&rt2x00dev->tbtt_tasklet);
+		tasklet_kill(&rt2x00dev->tbtt_tasklet);
 		break;
 	default:
 		break;
@@ -1137,12 +1132,6 @@ static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
 	if (state == STATE_RADIO_IRQ_ON) {
 		rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
 		rt2x00pci_register_write(rt2x00dev, CSR7, reg);
-
-		/*
-		 * Enable tasklets.
-		 */
-		tasklet_enable(&rt2x00dev->txstatus_tasklet);
-		tasklet_enable(&rt2x00dev->rxdone_tasklet);
 	}
 
 	/*
@@ -1165,8 +1154,9 @@ static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
 		/*
 		 * Ensure that all tasklets are finished.
 		 */
-		tasklet_disable(&rt2x00dev->txstatus_tasklet);
-		tasklet_disable(&rt2x00dev->rxdone_tasklet);
+		tasklet_kill(&rt2x00dev->txstatus_tasklet);
+		tasklet_kill(&rt2x00dev->rxdone_tasklet);
+		tasklet_kill(&rt2x00dev->tbtt_tasklet);
 	}
 }
 
@@ -1479,22 +1469,25 @@ static void rt2500pci_txstatus_tasklet(unsigned long data)
 	/*
 	 * Enable all TXDONE interrupts again.
 	 */
-	spin_lock_irq(&rt2x00dev->irqmask_lock);
+	if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) {
+		spin_lock_irq(&rt2x00dev->irqmask_lock);
 
-	rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
-	rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, 0);
-	rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, 0);
-	rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, 0);
-	rt2x00pci_register_write(rt2x00dev, CSR8, reg);
+		rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
+		rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, 0);
+		rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, 0);
+		rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, 0);
+		rt2x00pci_register_write(rt2x00dev, CSR8, reg);
 
-	spin_unlock_irq(&rt2x00dev->irqmask_lock);
+		spin_unlock_irq(&rt2x00dev->irqmask_lock);
+	}
 }
 
 static void rt2500pci_tbtt_tasklet(unsigned long data)
 {
 	struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
 	rt2x00lib_beacondone(rt2x00dev);
-	rt2500pci_enable_interrupt(rt2x00dev, CSR8_TBCN_EXPIRE);
+	if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+		rt2500pci_enable_interrupt(rt2x00dev, CSR8_TBCN_EXPIRE);
 }
 
 static void rt2500pci_rxdone_tasklet(unsigned long data)
@@ -1502,7 +1495,7 @@ static void rt2500pci_rxdone_tasklet(unsigned long data)
 	struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
 	if (rt2x00pci_rxdone(rt2x00dev))
 		tasklet_schedule(&rt2x00dev->rxdone_tasklet);
-	else
+	else if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
 		rt2500pci_enable_interrupt(rt2x00dev, CSR8_RXDONE);
 }
 
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index ebc17ad61dec..cabf249aa55b 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -200,13 +200,6 @@ static void rt2800pci_start_queue(struct data_queue *queue)
 		rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
 		break;
 	case QID_BEACON:
-		/*
-		 * Allow beacon tasklets to be scheduled for periodic
-		 * beacon updates.
-		 */
-		tasklet_enable(&rt2x00dev->tbtt_tasklet);
-		tasklet_enable(&rt2x00dev->pretbtt_tasklet);
-
 		rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
 		rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
 		rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
@@ -269,10 +262,13 @@ static void rt2800pci_stop_queue(struct data_queue *queue)
 		rt2x00pci_register_write(rt2x00dev, INT_TIMER_EN, reg);
 
 		/*
-		 * Wait for tbtt tasklets to finish.
+		 * Wait for current invocation to finish. The tasklet
+		 * won't be scheduled anymore afterwards since we disabled
+		 * the TBTT and PRE TBTT timer.
 		 */
-		tasklet_disable(&rt2x00dev->tbtt_tasklet);
-		tasklet_disable(&rt2x00dev->pretbtt_tasklet);
+		tasklet_kill(&rt2x00dev->tbtt_tasklet);
+		tasklet_kill(&rt2x00dev->pretbtt_tasklet);
+
 		break;
 	default:
 		break;
@@ -437,14 +433,6 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
 	if (state == STATE_RADIO_IRQ_ON) {
 		rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
 		rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
-
-		/*
-		 * Enable tasklets. The beacon related tasklets are
-		 * enabled when the beacon queue is started.
-		 */
-		tasklet_enable(&rt2x00dev->txstatus_tasklet);
-		tasklet_enable(&rt2x00dev->rxdone_tasklet);
-		tasklet_enable(&rt2x00dev->autowake_tasklet);
 	}
 
 	spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
@@ -472,12 +460,13 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
 
 	if (state == STATE_RADIO_IRQ_OFF) {
 		/*
-		 * Ensure that all tasklets are finished before
-		 * disabling the interrupts.
+		 * Wait for possibly running tasklets to finish.
 		 */
-		tasklet_disable(&rt2x00dev->txstatus_tasklet);
-		tasklet_disable(&rt2x00dev->rxdone_tasklet);
-		tasklet_disable(&rt2x00dev->autowake_tasklet);
+		tasklet_kill(&rt2x00dev->txstatus_tasklet);
+		tasklet_kill(&rt2x00dev->rxdone_tasklet);
+		tasklet_kill(&rt2x00dev->autowake_tasklet);
+		tasklet_kill(&rt2x00dev->tbtt_tasklet);
+		tasklet_kill(&rt2x00dev->pretbtt_tasklet);
 	}
 }
 
@@ -813,14 +802,16 @@ static void rt2800pci_pretbtt_tasklet(unsigned long data)
 {
 	struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
 	rt2x00lib_pretbtt(rt2x00dev);
-	rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_PRE_TBTT);
+	if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+		rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_PRE_TBTT);
 }
 
 static void rt2800pci_tbtt_tasklet(unsigned long data)
 {
 	struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
 	rt2x00lib_beacondone(rt2x00dev);
-	rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_TBTT);
+	if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+		rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_TBTT);
 }
 
 static void rt2800pci_rxdone_tasklet(unsigned long data)
@@ -828,7 +819,7 @@ static void rt2800pci_rxdone_tasklet(unsigned long data)
 	struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
 	if (rt2x00pci_rxdone(rt2x00dev))
 		tasklet_schedule(&rt2x00dev->rxdone_tasklet);
-	else
+	else if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
 		rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RX_DONE);
 }
 
@@ -836,7 +827,8 @@ static void rt2800pci_autowake_tasklet(unsigned long data)
 {
 	struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
 	rt2800pci_wakeup(rt2x00dev);
-	rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_AUTO_WAKEUP);
+	if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+		rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_AUTO_WAKEUP);
 }
 
 static void rt2800pci_txstatus_interrupt(struct rt2x00_dev *rt2x00dev)
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 0955c941317f..92ff6a72a2bb 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -946,7 +946,6 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
 		tasklet_init(&rt2x00dev->taskletname, \
 			     rt2x00dev->ops->lib->taskletname, \
 			     (unsigned long)rt2x00dev); \
-		tasklet_disable(&rt2x00dev->taskletname); \
 	}
 
 	RT2X00_TASKLET_INIT(txstatus_tasklet);
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 53110b83bf6e..058ef4b19d1d 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -1142,11 +1142,6 @@ static void rt61pci_start_queue(struct data_queue *queue)
 		rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
 		break;
 	case QID_BEACON:
-		/*
-		 * Allow the tbtt tasklet to be scheduled.
-		 */
-		tasklet_enable(&rt2x00dev->tbtt_tasklet);
-
 		rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
 		rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
 		rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
@@ -1230,7 +1225,7 @@ static void rt61pci_stop_queue(struct data_queue *queue)
 		/*
 		 * Wait for possibly running tbtt tasklets.
 		 */
-		tasklet_disable(&rt2x00dev->tbtt_tasklet);
+		tasklet_kill(&rt2x00dev->tbtt_tasklet);
 		break;
 	default:
 		break;
@@ -1731,13 +1726,6 @@ static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
 
 		rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, &reg);
 		rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg);
-
-		/*
-		 * Enable tasklets.
-		 */
-		tasklet_enable(&rt2x00dev->txstatus_tasklet);
-		tasklet_enable(&rt2x00dev->rxdone_tasklet);
-		tasklet_enable(&rt2x00dev->autowake_tasklet);
 	}
 
 	/*
@@ -1772,9 +1760,10 @@ static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
 		/*
 		 * Ensure that all tasklets are finished.
 		 */
-		tasklet_disable(&rt2x00dev->txstatus_tasklet);
-		tasklet_disable(&rt2x00dev->rxdone_tasklet);
-		tasklet_disable(&rt2x00dev->autowake_tasklet);
+		tasklet_kill(&rt2x00dev->txstatus_tasklet);
+		tasklet_kill(&rt2x00dev->rxdone_tasklet);
+		tasklet_kill(&rt2x00dev->autowake_tasklet);
+		tasklet_kill(&rt2x00dev->tbtt_tasklet);
 	}
 }
 
@@ -2300,22 +2289,24 @@ static void rt61pci_txstatus_tasklet(unsigned long data)
 {
 	struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
 	rt61pci_txdone(rt2x00dev);
-	rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_TXDONE);
+	if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+		rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_TXDONE);
 }
 
 static void rt61pci_tbtt_tasklet(unsigned long data)
 {
 	struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
 	rt2x00lib_beacondone(rt2x00dev);
-	rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_BEACON_DONE);
+	if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+		rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_BEACON_DONE);
 }
 
 static void rt61pci_rxdone_tasklet(unsigned long data)
 {
 	struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
 	if (rt2x00pci_rxdone(rt2x00dev))
-		rt2x00pci_rxdone(rt2x00dev);
-	else
+		tasklet_schedule(&rt2x00dev->rxdone_tasklet);
+	else if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
 		rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RXDONE);
 }
 
@@ -2325,7 +2316,8 @@ static void rt61pci_autowake_tasklet(unsigned long data)
 	rt61pci_wakeup(rt2x00dev);
 	rt2x00pci_register_write(rt2x00dev,
 				 M2H_CMD_DONE_CSR, 0xffffffff);
-	rt61pci_enable_mcu_interrupt(rt2x00dev, MCU_INT_MASK_CSR_TWAKEUP);
+	if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+		rt61pci_enable_mcu_interrupt(rt2x00dev, MCU_INT_MASK_CSR_TWAKEUP);
 }
 
 static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c
index 56f12358389d..9983fa18065a 100644
--- a/drivers/net/wireless/rtlwifi/pci.c
+++ b/drivers/net/wireless/rtlwifi/pci.c
@@ -218,7 +218,6 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw)
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor;
-	u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport;
 	u8 num4bytes = pcipriv->ndis_adapter.num4bytes;
 	/*Retrieve original configuration settings. */
 	u8 linkctrl_reg = pcipriv->ndis_adapter.linkctrl_reg;
@@ -254,9 +253,8 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw)
 	udelay(50);
 
 	/*4 Disable Pci Bridge ASPM */
-	rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS,
-				     pcicfg_addrport + (num4bytes << 2));
-	rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, pcibridge_linkctrlreg);
+	pci_write_config_byte(rtlpci->pdev, (num4bytes << 2),
+			      pcibridge_linkctrlreg);
 
 	udelay(50);
 }
@@ -277,7 +275,6 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw)
 	u8 pcibridge_devnum = pcipriv->ndis_adapter.pcibridge_devnum;
 	u8 pcibridge_funcnum = pcipriv->ndis_adapter.pcibridge_funcnum;
 	u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor;
-	u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport;
 	u8 num4bytes = pcipriv->ndis_adapter.num4bytes;
 	u16 aspmlevel;
 	u8 u_pcibridge_aspmsetting;
@@ -293,8 +290,6 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw)
 	}
 
 	/*4 Enable Pci Bridge ASPM */
-	rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS,
-				     pcicfg_addrport + (num4bytes << 2));
 
 	u_pcibridge_aspmsetting =
 	    pcipriv->ndis_adapter.pcibridge_linkctrlreg |
@@ -303,7 +298,8 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw)
 	if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL)
 		u_pcibridge_aspmsetting &= ~BIT(0);
 
-	rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, u_pcibridge_aspmsetting);
+	pci_write_config_byte(rtlpci->pdev, (num4bytes << 2),
+			      u_pcibridge_aspmsetting);
 
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
 		 ("PlatformEnableASPM():PciBridge busnumber[%x], "
@@ -335,25 +331,18 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw)
 
 static bool rtl_pci_get_amd_l1_patch(struct ieee80211_hw *hw)
 {
-	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
-	u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport;
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 
 	bool status = false;
 	u8 offset_e0;
 	unsigned offset_e4;
 
-	rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS,
-			pcicfg_addrport + 0xE0);
-	rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, 0xA0);
+	pci_write_config_byte(rtlpci->pdev, 0xe0, 0xa0);
 
-	rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS,
-			pcicfg_addrport + 0xE0);
-	rtl_pci_raw_read_port_uchar(PCI_CONF_DATA, &offset_e0);
+	pci_read_config_byte(rtlpci->pdev, 0xe0, &offset_e0);
 
 	if (offset_e0 == 0xA0) {
-		rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS,
-					     pcicfg_addrport + 0xE4);
-		rtl_pci_raw_read_port_ulong(PCI_CONF_DATA, &offset_e4);
+		pci_read_config_dword(rtlpci->pdev, 0xe4, &offset_e4);
 		if (offset_e4 & BIT(23))
 			status = true;
 	}
@@ -364,17 +353,15 @@ static bool rtl_pci_get_amd_l1_patch(struct ieee80211_hw *hw)
 static void rtl_pci_get_linkcontrol_field(struct ieee80211_hw *hw)
 {
 	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+	struct rtl_pci *rtlpci = rtl_pcidev(pcipriv);
 	u8 capabilityoffset = pcipriv->ndis_adapter.pcibridge_pciehdr_offset;
-	u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport;
 	u8 linkctrl_reg;
 	u8 num4bbytes;
 
 	num4bbytes = (capabilityoffset + 0x10) / 4;
 
 	/*Read  Link Control Register */
-	rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS,
-				     pcicfg_addrport + (num4bbytes << 2));
-	rtl_pci_raw_read_port_uchar(PCI_CONF_DATA, &linkctrl_reg);
+	pci_read_config_byte(rtlpci->pdev, (num4bbytes << 2), &linkctrl_reg);
 
 	pcipriv->ndis_adapter.pcibridge_linkctrlreg = linkctrl_reg;
 }
@@ -1718,10 +1705,6 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
 		    PCI_SLOT(bridge_pdev->devfn);
 		pcipriv->ndis_adapter.pcibridge_funcnum =
 		    PCI_FUNC(bridge_pdev->devfn);
-		pcipriv->ndis_adapter.pcicfg_addrport =
-		    (pcipriv->ndis_adapter.pcibridge_busnum << 16) |
-		    (pcipriv->ndis_adapter.pcibridge_devnum << 11) |
-		    (pcipriv->ndis_adapter.pcibridge_funcnum << 8) | (1 << 31);
 		pcipriv->ndis_adapter.pcibridge_pciehdr_offset =
 		    pci_pcie_cap(bridge_pdev);
 		pcipriv->ndis_adapter.num4bytes =
diff --git a/drivers/net/wireless/rtlwifi/pci.h b/drivers/net/wireless/rtlwifi/pci.h
index c53c62046747..a24e505b202b 100644
--- a/drivers/net/wireless/rtlwifi/pci.h
+++ b/drivers/net/wireless/rtlwifi/pci.h
@@ -212,7 +212,6 @@ struct mp_adapter {
 	u16 pcibridge_vendorid;
 	u16 pcibridge_deviceid;
 
-	u32 pcicfg_addrport;
 	u8 num4bytes;
 
 	u8 pcibridge_pciehdr_offset;
@@ -273,29 +272,4 @@ static inline void pci_write32_async(struct rtl_priv *rtlpriv,
 	writel(val, (u8 __iomem *) rtlpriv->io.pci_mem_start + addr);
 }
 
-static inline void rtl_pci_raw_write_port_ulong(u32 port, u32 val)
-{
-	outl(val, port);
-}
-
-static inline void rtl_pci_raw_write_port_uchar(u32 port, u8 val)
-{
-	outb(val, port);
-}
-
-static inline void rtl_pci_raw_read_port_uchar(u32 port, u8 *pval)
-{
-	*pval = inb(port);
-}
-
-static inline void rtl_pci_raw_read_port_ushort(u32 port, u16 *pval)
-{
-	*pval = inw(port);
-}
-
-static inline void rtl_pci_raw_read_port_ulong(u32 port, u32 *pval)
-{
-	*pval = inl(port);
-}
-
 #endif
diff --git a/drivers/net/wireless/wl1251/cmd.h b/drivers/net/wireless/wl1251/cmd.h
index 79ca5273c9e9..ee4f2b391822 100644
--- a/drivers/net/wireless/wl1251/cmd.h
+++ b/drivers/net/wireless/wl1251/cmd.h
@@ -269,7 +269,7 @@ struct cmd_join {
 	u8 bss_type;
 	u8 channel;
 	u8 ssid_len;
-	u8 ssid[IW_ESSID_MAX_SIZE];
+	u8 ssid[IEEE80211_MAX_SSID_LEN];
 	u8 ctrl; /* JOIN_CMD_CTRL_* */
 	u8 tx_mgt_frame_rate; /* OBSOLETE */
 	u8 tx_mgt_frame_mod;  /* OBSOLETE */
diff --git a/drivers/net/wireless/wl1251/wl12xx_80211.h b/drivers/net/wireless/wl1251/wl12xx_80211.h
index 1417b1445c3d..04ed51495772 100644
--- a/drivers/net/wireless/wl1251/wl12xx_80211.h
+++ b/drivers/net/wireless/wl1251/wl12xx_80211.h
@@ -76,7 +76,7 @@ struct wl12xx_ie_header {
 
 struct wl12xx_ie_ssid {
 	struct wl12xx_ie_header header;
-	char ssid[IW_ESSID_MAX_SIZE];
+	char ssid[IEEE80211_MAX_SSID_LEN];
 } __packed;
 
 struct wl12xx_ie_rates {
diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h
index 1f7037292c15..bba077ecd945 100644
--- a/drivers/net/wireless/wl12xx/cmd.h
+++ b/drivers/net/wireless/wl12xx/cmd.h
@@ -239,7 +239,7 @@ struct wl1271_cmd_join {
 	u8 bss_type;
 	u8 channel;
 	u8 ssid_len;
-	u8 ssid[IW_ESSID_MAX_SIZE];
+	u8 ssid[IEEE80211_MAX_SSID_LEN];
 	u8 ctrl; /* JOIN_CMD_CTRL_* */
 	u8 reserved[3];
 } __packed;
@@ -528,7 +528,7 @@ struct wl1271_cmd_bss_start {
 	/* wl1271_ssid_type */
 	u8 ssid_type;
 	u8 ssid_len;
-	u8 ssid[IW_ESSID_MAX_SIZE];
+	u8 ssid[IEEE80211_MAX_SSID_LEN];
 	u8 padding_1[2];
 
 	/* Basic rate set */
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index e58c22d21e39..3418299e17c8 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -1997,7 +1997,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
 	wl1271_power_off(wl);
 
 	memset(wl->bssid, 0, ETH_ALEN);
-	memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
+	memset(wl->ssid, 0, IEEE80211_MAX_SSID_LEN + 1);
 	wl->ssid_len = 0;
 	wl->bss_type = MAX_BSS_TYPE;
 	wl->set_bss_type = MAX_BSS_TYPE;
diff --git a/drivers/net/wireless/wl12xx/scan.h b/drivers/net/wireless/wl12xx/scan.h
index d882e4da71b7..0b2a2987439d 100644
--- a/drivers/net/wireless/wl12xx/scan.h
+++ b/drivers/net/wireless/wl12xx/scan.h
@@ -77,7 +77,7 @@ struct basic_scan_params {
 	u8 ssid_len;
 	/* in order to align */
 	u8 padding1[2];
-	u8 ssid[IW_ESSID_MAX_SIZE];
+	u8 ssid[IEEE80211_MAX_SSID_LEN];
 	/* Band to scan */
 	u8 band;
 	u8 use_ssid_list;
@@ -167,7 +167,7 @@ struct wl1271_cmd_sched_scan_config {
 	u8 filter_type;
 
 	u8 ssid_len;     /* For SCAN_SSID_FILTER_SPECIFIC */
-	u8 ssid[IW_ESSID_MAX_SIZE];
+	u8 ssid[IEEE80211_MAX_SSID_LEN];
 
 	u8 n_probe_reqs; /* Number of probes requests per channel */
 
@@ -194,7 +194,7 @@ enum {
 struct wl1271_ssid {
 	u8 type;
 	u8 len;
-	u8 ssid[IW_ESSID_MAX_SIZE];
+	u8 ssid[IEEE80211_MAX_SSID_LEN];
 	/* u8 padding[2]; */
 } __packed;
 
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 1a8751eb8140..0bc29356ebe4 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -309,7 +309,7 @@ struct wl1271_scan {
 	unsigned long scanned_ch[BITS_TO_LONGS(WL1271_MAX_CHANNELS)];
 	bool failed;
 	u8 state;
-	u8 ssid[IW_ESSID_MAX_SIZE+1];
+	u8 ssid[IEEE80211_MAX_SSID_LEN+1];
 	size_t ssid_len;
 };
 
@@ -415,7 +415,7 @@ struct wl1271 {
 	u8 mac_addr[ETH_ALEN];
 	u8 bss_type;
 	u8 set_bss_type;
-	u8 ssid[IW_ESSID_MAX_SIZE + 1];
+	u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
 	u8 ssid_len;
 	int channel;
 
diff --git a/drivers/net/wireless/wl12xx/wl12xx_80211.h b/drivers/net/wireless/wl12xx/wl12xx_80211.h
index 18fe542360f2..f334ea081722 100644
--- a/drivers/net/wireless/wl12xx/wl12xx_80211.h
+++ b/drivers/net/wireless/wl12xx/wl12xx_80211.h
@@ -77,7 +77,7 @@ struct wl12xx_ie_header {
 
 struct wl12xx_ie_ssid {
 	struct wl12xx_ie_header header;
-	char ssid[IW_ESSID_MAX_SIZE];
+	char ssid[IEEE80211_MAX_SSID_LEN];
 } __packed;
 
 struct wl12xx_ie_rates {