Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6

Conflicts:
	drivers/net/wireless/rtlwifi/efuse.c
	drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
	net/bluetooth/mgmt.c
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 274b32d..05ed6f3 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -35,17 +35,6 @@
 
 ---------------------------
 
-What:	AR9170USB
-When:	2.6.40
-
-Why:	This driver is deprecated and the firmware is no longer
-	maintained. The replacement driver "carl9170" has been
-	around for a while, so the devices are still supported.
-
-Who:	Christian Lamparter <chunkeey@googlemail.com>
-
----------------------------
-
 What:	IRQF_SAMPLE_RANDOM
 Check:	IRQF_SAMPLE_RANDOM
 When:	July 2009
diff --git a/MAINTAINERS b/MAINTAINERS
index 6b4b9cd..9f91049 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1224,13 +1224,6 @@
 S:	Supported
 F:	drivers/net/wireless/ath/ath9k/
 
-ATHEROS AR9170 WIRELESS DRIVER
-M:	Christian Lamparter <chunkeey@web.de>
-L:	linux-wireless@vger.kernel.org
-W:	http://wireless.kernel.org/en/users/Drivers/ar9170
-S:	Obsolete
-F:	drivers/net/wireless/ath/ar9170/
-
 CARL9170 LINUX COMMUNITY WIRELESS DRIVER
 M:	Christian Lamparter <chunkeey@googlemail.com>
 L:	linux-wireless@vger.kernel.org
@@ -3355,6 +3348,12 @@
 F:	drivers/net/wimax/i2400m/
 F:	include/linux/wimax/i2400m.h
 
+INTEL WIRELESS 3945ABG/BG, 4965AGN (iwlegacy)
+M:	Stanislaw Gruszka <sgruszka@redhat.com>
+L:	linux-wireless@vger.kernel.org
+S:	Supported
+F:	drivers/net/wireless/iwlegacy/
+
 INTEL WIRELESS WIFI LINK (iwlwifi)
 M:	Wey-Yi Guy <wey-yi.w.guy@intel.com>
 M:	Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 7aeb113..f354bd4 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -284,5 +284,6 @@
 source "drivers/net/wireless/wl1251/Kconfig"
 source "drivers/net/wireless/wl12xx/Kconfig"
 source "drivers/net/wireless/zd1211rw/Kconfig"
+source "drivers/net/wireless/mwifiex/Kconfig"
 
 endif # WLAN
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index ddd3fb6..7bba6a8 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -56,3 +56,5 @@
 obj-$(CONFIG_WL12XX_PLATFORM_DATA)	+= wl12xx/
 
 obj-$(CONFIG_IWM)	+= iwmc3200wifi/
+
+obj-$(CONFIG_MWIFIEX)	+= mwifiex/
diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig
index 92c2162..d1b2306 100644
--- a/drivers/net/wireless/ath/Kconfig
+++ b/drivers/net/wireless/ath/Kconfig
@@ -24,7 +24,6 @@
 
 source "drivers/net/wireless/ath/ath5k/Kconfig"
 source "drivers/net/wireless/ath/ath9k/Kconfig"
-source "drivers/net/wireless/ath/ar9170/Kconfig"
 source "drivers/net/wireless/ath/carl9170/Kconfig"
 
 endif
diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile
index 6d711ec..0e8f528 100644
--- a/drivers/net/wireless/ath/Makefile
+++ b/drivers/net/wireless/ath/Makefile
@@ -1,6 +1,5 @@
 obj-$(CONFIG_ATH5K)		+= ath5k/
 obj-$(CONFIG_ATH9K_HW)		+= ath9k/
-obj-$(CONFIG_AR9170_USB)        += ar9170/
 obj-$(CONFIG_CARL9170)		+= carl9170/
 
 obj-$(CONFIG_ATH_COMMON)	+= ath.o
diff --git a/drivers/net/wireless/ath/ar9170/Kconfig b/drivers/net/wireless/ath/ar9170/Kconfig
deleted file mode 100644
index 7b9672b..0000000
--- a/drivers/net/wireless/ath/ar9170/Kconfig
+++ /dev/null
@@ -1,20 +0,0 @@
-config AR9170_USB
-	tristate "Atheros AR9170 802.11n USB support (OBSOLETE)"
-	depends on USB && MAC80211
-	select FW_LOADER
-	help
-	  This driver is going to get replaced by carl9170.
-
-	  This is a driver for the Atheros "otus" 802.11n USB devices.
-
-	  These devices require additional firmware (2 files).
-	  For now, these files can be downloaded from here:
-
-	  http://wireless.kernel.org/en/users/Drivers/ar9170
-
-	  If you choose to build a module, it'll be called ar9170usb.
-
-config AR9170_LEDS
-	bool
-	depends on AR9170_USB && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = AR9170_USB)
-	default y
diff --git a/drivers/net/wireless/ath/ar9170/Makefile b/drivers/net/wireless/ath/ar9170/Makefile
deleted file mode 100644
index 8d91c7e..0000000
--- a/drivers/net/wireless/ath/ar9170/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-ar9170usb-objs := usb.o main.o cmd.o mac.o phy.o led.o
-
-obj-$(CONFIG_AR9170_USB) += ar9170usb.o
diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h
deleted file mode 100644
index 371e4ce..0000000
--- a/drivers/net/wireless/ath/ar9170/ar9170.h
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Atheros AR9170 driver
- *
- * Driver specific definitions
- *
- * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.  If not, see
- * http://www.gnu.org/licenses/.
- *
- * This file incorporates work covered by the following copyright and
- * permission notice:
- *    Copyright (c) 2007-2008 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 __AR9170_H
-#define __AR9170_H
-
-#include <linux/completion.h>
-#include <linux/spinlock.h>
-#include <net/cfg80211.h>
-#include <net/mac80211.h>
-#ifdef CONFIG_AR9170_LEDS
-#include <linux/leds.h>
-#endif /* CONFIG_AR9170_LEDS */
-#include "eeprom.h"
-#include "hw.h"
-
-#include "../regd.h"
-
-#define PAYLOAD_MAX	(AR9170_MAX_CMD_LEN/4 - 1)
-
-enum ar9170_bw {
-	AR9170_BW_20,
-	AR9170_BW_40_BELOW,
-	AR9170_BW_40_ABOVE,
-
-	__AR9170_NUM_BW,
-};
-
-static inline enum ar9170_bw nl80211_to_ar9170(enum nl80211_channel_type type)
-{
-	switch (type) {
-	case NL80211_CHAN_NO_HT:
-	case NL80211_CHAN_HT20:
-		return AR9170_BW_20;
-	case NL80211_CHAN_HT40MINUS:
-		return AR9170_BW_40_BELOW;
-	case NL80211_CHAN_HT40PLUS:
-		return AR9170_BW_40_ABOVE;
-	default:
-		BUG();
-	}
-}
-
-enum ar9170_rf_init_mode {
-	AR9170_RFI_NONE,
-	AR9170_RFI_WARM,
-	AR9170_RFI_COLD,
-};
-
-#define AR9170_MAX_RX_BUFFER_SIZE		8192
-
-#ifdef CONFIG_AR9170_LEDS
-struct ar9170;
-
-struct ar9170_led {
-	struct ar9170 *ar;
-	struct led_classdev l;
-	char name[32];
-	unsigned int toggled;
-	bool last_state;
-	bool registered;
-};
-
-#endif /* CONFIG_AR9170_LEDS */
-
-enum ar9170_device_state {
-	AR9170_UNKNOWN_STATE,
-	AR9170_STOPPED,
-	AR9170_IDLE,
-	AR9170_STARTED,
-};
-
-struct ar9170_rxstream_mpdu_merge {
-	struct ar9170_rx_head plcp;
-	bool has_plcp;
-};
-
-struct ar9170_tx_queue_stats {
-	unsigned int len;
-	unsigned int limit;
-	unsigned int count;
-};
-
-#define AR9170_QUEUE_TIMEOUT		64
-#define AR9170_TX_TIMEOUT		8
-#define AR9170_JANITOR_DELAY		128
-#define AR9170_TX_INVALID_RATE		0xffffffff
-
-#define AR9170_NUM_TX_LIMIT_HARD	AR9170_TXQ_DEPTH
-#define AR9170_NUM_TX_LIMIT_SOFT	(AR9170_TXQ_DEPTH - 10)
-
-struct ar9170 {
-	struct ieee80211_hw *hw;
-	struct ath_common common;
-	struct mutex mutex;
-	enum ar9170_device_state state;
-	bool registered;
-	unsigned long bad_hw_nagger;
-
-	int (*open)(struct ar9170 *);
-	void (*stop)(struct ar9170 *);
-	int (*tx)(struct ar9170 *, struct sk_buff *);
-	int (*exec_cmd)(struct ar9170 *, enum ar9170_cmd, u32 ,
-			void *, u32 , void *);
-	void (*callback_cmd)(struct ar9170 *, u32 , void *);
-	int (*flush)(struct ar9170 *);
-
-	/* interface mode settings */
-	struct ieee80211_vif *vif;
-
-	/* beaconing */
-	struct sk_buff *beacon;
-	struct work_struct beacon_work;
-	bool enable_beacon;
-
-	/* cryptographic engine */
-	u64 usedkeys;
-	bool rx_software_decryption;
-	bool disable_offload;
-
-	/* filter settings */
-	u64 cur_mc_hash;
-	u32 cur_filter;
-	unsigned int filter_state;
-	bool sniffer_enabled;
-
-	/* PHY */
-	struct ieee80211_channel *channel;
-	int noise[4];
-
-	/* power calibration data */
-	u8 power_5G_leg[4];
-	u8 power_2G_cck[4];
-	u8 power_2G_ofdm[4];
-	u8 power_5G_ht20[8];
-	u8 power_5G_ht40[8];
-	u8 power_2G_ht20[8];
-	u8 power_2G_ht40[8];
-
-	u8 phy_heavy_clip;
-
-#ifdef CONFIG_AR9170_LEDS
-	struct delayed_work led_work;
-	struct ar9170_led leds[AR9170_NUM_LEDS];
-#endif /* CONFIG_AR9170_LEDS */
-
-	/* qos queue settings */
-	spinlock_t tx_stats_lock;
-	struct ar9170_tx_queue_stats tx_stats[5];
-	struct ieee80211_tx_queue_params edcf[5];
-
-	spinlock_t cmdlock;
-	__le32 cmdbuf[PAYLOAD_MAX + 1];
-
-	/* MAC statistics */
-	struct ieee80211_low_level_stats stats;
-
-	/* EEPROM */
-	struct ar9170_eeprom eeprom;
-
-	/* tx queues - as seen by hw - */
-	struct sk_buff_head tx_pending[__AR9170_NUM_TXQ];
-	struct sk_buff_head tx_status[__AR9170_NUM_TXQ];
-	struct delayed_work tx_janitor;
-
-	/* rxstream mpdu merge */
-	struct ar9170_rxstream_mpdu_merge rx_mpdu;
-	struct sk_buff *rx_failover;
-	int rx_failover_missing;
-
-	/* (cached) HW A-MPDU settings */
-	u8 global_ampdu_density;
-	u8 global_ampdu_factor;
-};
-
-struct ar9170_tx_info {
-	unsigned long timeout;
-};
-
-#define IS_STARTED(a)		(((struct ar9170 *)a)->state >= AR9170_STARTED)
-#define IS_ACCEPTING_CMD(a)	(((struct ar9170 *)a)->state >= AR9170_IDLE)
-
-/* exported interface */
-void *ar9170_alloc(size_t priv_size);
-int ar9170_register(struct ar9170 *ar, struct device *pdev);
-void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb);
-void ar9170_unregister(struct ar9170 *ar);
-void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb);
-void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len);
-int ar9170_nag_limiter(struct ar9170 *ar);
-
-/* MAC */
-void ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
-int ar9170_init_mac(struct ar9170 *ar);
-int ar9170_set_qos(struct ar9170 *ar);
-int ar9170_update_multicast(struct ar9170 *ar, const u64 mc_hast);
-int ar9170_update_frame_filter(struct ar9170 *ar, const u32 filter);
-int ar9170_set_operating_mode(struct ar9170 *ar);
-int ar9170_set_beacon_timers(struct ar9170 *ar);
-int ar9170_set_dyn_sifs_ack(struct ar9170 *ar);
-int ar9170_set_slot_time(struct ar9170 *ar);
-int ar9170_set_basic_rates(struct ar9170 *ar);
-int ar9170_set_hwretry_limit(struct ar9170 *ar, u32 max_retry);
-int ar9170_update_beacon(struct ar9170 *ar);
-void ar9170_new_beacon(struct work_struct *work);
-int ar9170_upload_key(struct ar9170 *ar, u8 id, const u8 *mac, u8 ktype,
-		      u8 keyidx, u8 *keydata, int keylen);
-int ar9170_disable_key(struct ar9170 *ar, u8 id);
-
-/* LEDs */
-#ifdef CONFIG_AR9170_LEDS
-int ar9170_register_leds(struct ar9170 *ar);
-void ar9170_unregister_leds(struct ar9170 *ar);
-#endif /* CONFIG_AR9170_LEDS */
-int ar9170_init_leds(struct ar9170 *ar);
-int ar9170_set_leds_state(struct ar9170 *ar, u32 led_state);
-
-/* PHY / RF */
-int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band);
-int ar9170_init_rf(struct ar9170 *ar);
-int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
-		       enum ar9170_rf_init_mode rfi, enum ar9170_bw bw);
-
-#endif /* __AR9170_H */
diff --git a/drivers/net/wireless/ath/ar9170/cmd.c b/drivers/net/wireless/ath/ar9170/cmd.c
deleted file mode 100644
index 6452c50..0000000
--- a/drivers/net/wireless/ath/ar9170/cmd.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Atheros AR9170 driver
- *
- * Basic HW register/memory/command access functions
- *
- * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.  If not, see
- * http://www.gnu.org/licenses/.
- *
- * This file incorporates work covered by the following copyright and
- * permission notice:
- *    Copyright (c) 2007-2008 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 "ar9170.h"
-#include "cmd.h"
-
-int ar9170_write_mem(struct ar9170 *ar, const __le32 *data, size_t len)
-{
-	int err;
-
-	if (unlikely(!IS_ACCEPTING_CMD(ar)))
-		return 0;
-
-	err = ar->exec_cmd(ar, AR9170_CMD_WMEM, len, (u8 *) data, 0, NULL);
-	if (err)
-		wiphy_debug(ar->hw->wiphy, "writing memory failed\n");
-	return err;
-}
-
-int ar9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val)
-{
-	const __le32 buf[2] = {
-		cpu_to_le32(reg),
-		cpu_to_le32(val),
-	};
-	int err;
-
-	if (unlikely(!IS_ACCEPTING_CMD(ar)))
-		return 0;
-
-	err = ar->exec_cmd(ar, AR9170_CMD_WREG, sizeof(buf),
-			   (u8 *) buf, 0, NULL);
-	if (err)
-		wiphy_debug(ar->hw->wiphy, "writing reg %#x (val %#x) failed\n",
-			    reg, val);
-	return err;
-}
-
-int ar9170_read_mreg(struct ar9170 *ar, int nregs, const u32 *regs, u32 *out)
-{
-	int i, err;
-	__le32 *offs, *res;
-
-	if (unlikely(!IS_ACCEPTING_CMD(ar)))
-		return 0;
-
-	/* abuse "out" for the register offsets, must be same length */
-	offs = (__le32 *)out;
-	for (i = 0; i < nregs; i++)
-		offs[i] = cpu_to_le32(regs[i]);
-
-	/* also use the same buffer for the input */
-	res = (__le32 *)out;
-
-	err = ar->exec_cmd(ar, AR9170_CMD_RREG,
-			   4 * nregs, (u8 *)offs,
-			   4 * nregs, (u8 *)res);
-	if (err)
-		return err;
-
-	/* convert result to cpu endian */
-	for (i = 0; i < nregs; i++)
-		out[i] = le32_to_cpu(res[i]);
-
-	return 0;
-}
-
-int ar9170_read_reg(struct ar9170 *ar, u32 reg, u32 *val)
-{
-	return ar9170_read_mreg(ar, 1, &reg, val);
-}
-
-int ar9170_echo_test(struct ar9170 *ar, u32 v)
-{
-	__le32 echobuf = cpu_to_le32(v);
-	__le32 echores;
-	int err;
-
-	if (unlikely(!IS_ACCEPTING_CMD(ar)))
-		return -ENODEV;
-
-	err = ar->exec_cmd(ar, AR9170_CMD_ECHO,
-			   4, (u8 *)&echobuf,
-			   4, (u8 *)&echores);
-	if (err)
-		return err;
-
-	if (echobuf != echores)
-		return -EINVAL;
-
-	return 0;
-}
diff --git a/drivers/net/wireless/ath/ar9170/cmd.h b/drivers/net/wireless/ath/ar9170/cmd.h
deleted file mode 100644
index ec8134b4..0000000
--- a/drivers/net/wireless/ath/ar9170/cmd.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Atheros AR9170 driver
- *
- * Basic HW register/memory/command access functions
- *
- * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.  If not, see
- * http://www.gnu.org/licenses/.
- *
- * This file incorporates work covered by the following copyright and
- * permission notice:
- *    Copyright (c) 2007-2008 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 __CMD_H
-#define __CMD_H
-
-#include "ar9170.h"
-
-/* basic HW access */
-int ar9170_write_mem(struct ar9170 *ar, const __le32 *data, size_t len);
-int ar9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val);
-int ar9170_read_reg(struct ar9170 *ar, u32 reg, u32 *val);
-int ar9170_read_mreg(struct ar9170 *ar, int nregs, const u32 *regs, u32 *out);
-int ar9170_echo_test(struct ar9170 *ar, u32 v);
-
-/*
- * Macros to facilitate writing multiple registers in a single
- * write-combining USB command. Note that when the first group
- * fails the whole thing will fail without any others attempted,
- * but you won't know which write in the group failed.
- */
-#define ar9170_regwrite_begin(ar)					\
-do {									\
-	int __nreg = 0, __err = 0;					\
-	struct ar9170 *__ar = ar;
-
-#define ar9170_regwrite(r, v) do {					\
-	__ar->cmdbuf[2 * __nreg + 1] = cpu_to_le32(r);			\
-	__ar->cmdbuf[2 * __nreg + 2] = cpu_to_le32(v);			\
-	__nreg++;							\
-	if ((__nreg >= PAYLOAD_MAX/2)) {				\
-		if (IS_ACCEPTING_CMD(__ar))				\
-			__err = ar->exec_cmd(__ar, AR9170_CMD_WREG,	\
-					     8 * __nreg,		\
-					     (u8 *) &__ar->cmdbuf[1],	\
-					     0, NULL);			\
-		__nreg = 0;						\
-		if (__err)						\
-			goto __regwrite_out;				\
-	}								\
-} while (0)
-
-#define ar9170_regwrite_finish()					\
-__regwrite_out :							\
-	if (__nreg) {							\
-		if (IS_ACCEPTING_CMD(__ar))				\
-			__err = ar->exec_cmd(__ar, AR9170_CMD_WREG,	\
-					     8 * __nreg,		\
-					     (u8 *) &__ar->cmdbuf[1],	\
-					     0, NULL);			\
-		__nreg = 0;						\
-	}
-
-#define ar9170_regwrite_result()					\
-	__err;								\
-} while (0);
-
-#endif /* __CMD_H */
diff --git a/drivers/net/wireless/ath/ar9170/eeprom.h b/drivers/net/wireless/ath/ar9170/eeprom.h
deleted file mode 100644
index 6c46638..0000000
--- a/drivers/net/wireless/ath/ar9170/eeprom.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Atheros AR9170 driver
- *
- * EEPROM layout
- *
- * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.  If not, see
- * http://www.gnu.org/licenses/.
- *
- * This file incorporates work covered by the following copyright and
- * permission notice:
- *    Copyright (c) 2007-2008 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 __AR9170_EEPROM_H
-#define __AR9170_EEPROM_H
-
-#define AR5416_MAX_CHAINS		2
-#define AR5416_MODAL_SPURS		5
-
-struct ar9170_eeprom_modal {
-	__le32	antCtrlChain[AR5416_MAX_CHAINS];
-	__le32	antCtrlCommon;
-	s8	antennaGainCh[AR5416_MAX_CHAINS];
-	u8	switchSettling;
-	u8	txRxAttenCh[AR5416_MAX_CHAINS];
-	u8	rxTxMarginCh[AR5416_MAX_CHAINS];
-	s8	adcDesiredSize;
-	s8	pgaDesiredSize;
-	u8	xlnaGainCh[AR5416_MAX_CHAINS];
-	u8	txEndToXpaOff;
-	u8	txEndToRxOn;
-	u8	txFrameToXpaOn;
-	u8	thresh62;
-	s8	noiseFloorThreshCh[AR5416_MAX_CHAINS];
-	u8	xpdGain;
-	u8	xpd;
-	s8	iqCalICh[AR5416_MAX_CHAINS];
-	s8	iqCalQCh[AR5416_MAX_CHAINS];
-	u8	pdGainOverlap;
-	u8	ob;
-	u8	db;
-	u8	xpaBiasLvl;
-	u8	pwrDecreaseFor2Chain;
-	u8	pwrDecreaseFor3Chain;
-	u8	txFrameToDataStart;
-	u8	txFrameToPaOn;
-	u8	ht40PowerIncForPdadc;
-	u8	bswAtten[AR5416_MAX_CHAINS];
-	u8	bswMargin[AR5416_MAX_CHAINS];
-	u8	swSettleHt40;
-	u8	reserved[22];
-	struct spur_channel {
-		__le16 spurChan;
-		u8	spurRangeLow;
-		u8	spurRangeHigh;
-	} __packed spur_channels[AR5416_MODAL_SPURS];
-} __packed;
-
-#define AR5416_NUM_PD_GAINS		4
-#define AR5416_PD_GAIN_ICEPTS		5
-
-struct ar9170_calibration_data_per_freq {
-	u8	pwr_pdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
-	u8	vpd_pdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
-} __packed;
-
-#define AR5416_NUM_5G_CAL_PIERS		8
-#define AR5416_NUM_2G_CAL_PIERS		4
-
-#define AR5416_NUM_5G_TARGET_PWRS	8
-#define AR5416_NUM_2G_CCK_TARGET_PWRS	3
-#define AR5416_NUM_2G_OFDM_TARGET_PWRS	4
-#define AR5416_MAX_NUM_TGT_PWRS		8
-
-struct ar9170_calibration_target_power_legacy {
-	u8	freq;
-	u8	power[4];
-} __packed;
-
-struct ar9170_calibration_target_power_ht {
-	u8	freq;
-	u8	power[8];
-} __packed;
-
-#define AR5416_NUM_CTLS			24
-
-struct ar9170_calctl_edges {
-	u8	channel;
-#define AR9170_CALCTL_EDGE_FLAGS	0xC0
-	u8	power_flags;
-} __packed;
-
-#define AR5416_NUM_BAND_EDGES		8
-
-struct ar9170_calctl_data {
-	struct ar9170_calctl_edges
-		control_edges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES];
-} __packed;
-
-
-struct ar9170_eeprom {
-	__le16	length;
-	__le16	checksum;
-	__le16	version;
-	u8	operating_flags;
-#define AR9170_OPFLAG_5GHZ		1
-#define AR9170_OPFLAG_2GHZ		2
-	u8	misc;
-	__le16	reg_domain[2];
-	u8	mac_address[6];
-	u8	rx_mask;
-	u8	tx_mask;
-	__le16	rf_silent;
-	__le16	bluetooth_options;
-	__le16	device_capabilities;
-	__le32	build_number;
-	u8	deviceType;
-	u8	reserved[33];
-
-	u8	customer_data[64];
-
-	struct ar9170_eeprom_modal
-		modal_header[2];
-
-	u8	cal_freq_pier_5G[AR5416_NUM_5G_CAL_PIERS];
-	u8	cal_freq_pier_2G[AR5416_NUM_2G_CAL_PIERS];
-
-	struct ar9170_calibration_data_per_freq
-		cal_pier_data_5G[AR5416_MAX_CHAINS][AR5416_NUM_5G_CAL_PIERS],
-		cal_pier_data_2G[AR5416_MAX_CHAINS][AR5416_NUM_2G_CAL_PIERS];
-
-	/* power calibration data */
-	struct ar9170_calibration_target_power_legacy
-		cal_tgt_pwr_5G[AR5416_NUM_5G_TARGET_PWRS];
-	struct ar9170_calibration_target_power_ht
-		cal_tgt_pwr_5G_ht20[AR5416_NUM_5G_TARGET_PWRS],
-		cal_tgt_pwr_5G_ht40[AR5416_NUM_5G_TARGET_PWRS];
-
-	struct ar9170_calibration_target_power_legacy
-		cal_tgt_pwr_2G_cck[AR5416_NUM_2G_CCK_TARGET_PWRS],
-		cal_tgt_pwr_2G_ofdm[AR5416_NUM_2G_OFDM_TARGET_PWRS];
-	struct ar9170_calibration_target_power_ht
-		cal_tgt_pwr_2G_ht20[AR5416_NUM_2G_OFDM_TARGET_PWRS],
-		cal_tgt_pwr_2G_ht40[AR5416_NUM_2G_OFDM_TARGET_PWRS];
-
-	/* conformance testing limits */
-	u8	ctl_index[AR5416_NUM_CTLS];
-	struct ar9170_calctl_data
-		ctl_data[AR5416_NUM_CTLS];
-
-	u8	pad;
-	__le16	subsystem_id;
-} __packed;
-
-#endif /* __AR9170_EEPROM_H */
diff --git a/drivers/net/wireless/ath/ar9170/hw.h b/drivers/net/wireless/ath/ar9170/hw.h
deleted file mode 100644
index 06f1f3c..0000000
--- a/drivers/net/wireless/ath/ar9170/hw.h
+++ /dev/null
@@ -1,430 +0,0 @@
-/*
- * Atheros AR9170 driver
- *
- * Hardware-specific definitions
- *
- * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.  If not, see
- * http://www.gnu.org/licenses/.
- *
- * This file incorporates work covered by the following copyright and
- * permission notice:
- *    Copyright (c) 2007-2008 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 __AR9170_HW_H
-#define __AR9170_HW_H
-
-#define AR9170_MAX_CMD_LEN	64
-
-enum ar9170_cmd {
-	AR9170_CMD_RREG		= 0x00,
-	AR9170_CMD_WREG		= 0x01,
-	AR9170_CMD_RMEM		= 0x02,
-	AR9170_CMD_WMEM		= 0x03,
-	AR9170_CMD_BITAND	= 0x04,
-	AR9170_CMD_BITOR	= 0x05,
-	AR9170_CMD_EKEY		= 0x28,
-	AR9170_CMD_DKEY		= 0x29,
-	AR9170_CMD_FREQUENCY	= 0x30,
-	AR9170_CMD_RF_INIT	= 0x31,
-	AR9170_CMD_SYNTH	= 0x32,
-	AR9170_CMD_FREQ_START	= 0x33,
-	AR9170_CMD_ECHO		= 0x80,
-	AR9170_CMD_TALLY	= 0x81,
-	AR9170_CMD_TALLY_APD	= 0x82,
-	AR9170_CMD_CONFIG	= 0x83,
-	AR9170_CMD_RESET	= 0x90,
-	AR9170_CMD_DKRESET	= 0x91,
-	AR9170_CMD_DKTX_STATUS	= 0x92,
-	AR9170_CMD_FDC		= 0xA0,
-	AR9170_CMD_WREEPROM	= 0xB0,
-	AR9170_CMD_WFLASH	= 0xB0,
-	AR9170_CMD_FLASH_ERASE	= 0xB1,
-	AR9170_CMD_FLASH_PROG	= 0xB2,
-	AR9170_CMD_FLASH_CHKSUM	= 0xB3,
-	AR9170_CMD_FLASH_READ	= 0xB4,
-	AR9170_CMD_FW_DL_INIT	= 0xB5,
-	AR9170_CMD_MEM_WREEPROM	= 0xBB,
-};
-
-/* endpoints */
-#define AR9170_EP_TX				1
-#define AR9170_EP_RX				2
-#define AR9170_EP_IRQ				3
-#define AR9170_EP_CMD				4
-
-#define AR9170_EEPROM_START			0x1600
-
-#define AR9170_GPIO_REG_BASE			0x1d0100
-#define AR9170_GPIO_REG_PORT_TYPE		AR9170_GPIO_REG_BASE
-#define AR9170_GPIO_REG_DATA			(AR9170_GPIO_REG_BASE + 4)
-#define AR9170_NUM_LEDS				2
-
-
-#define AR9170_USB_REG_BASE			0x1e1000
-#define AR9170_USB_REG_DMA_CTL			(AR9170_USB_REG_BASE + 0x108)
-#define		AR9170_DMA_CTL_ENABLE_TO_DEVICE		0x1
-#define		AR9170_DMA_CTL_ENABLE_FROM_DEVICE	0x2
-#define		AR9170_DMA_CTL_HIGH_SPEED		0x4
-#define		AR9170_DMA_CTL_PACKET_MODE		0x8
-
-#define AR9170_USB_REG_MAX_AGG_UPLOAD		(AR9170_USB_REG_BASE + 0x110)
-#define AR9170_USB_REG_UPLOAD_TIME_CTL		(AR9170_USB_REG_BASE + 0x114)
-
-
-
-#define AR9170_MAC_REG_BASE			0x1c3000
-
-#define AR9170_MAC_REG_TSF_L			(AR9170_MAC_REG_BASE + 0x514)
-#define AR9170_MAC_REG_TSF_H			(AR9170_MAC_REG_BASE + 0x518)
-
-#define AR9170_MAC_REG_ATIM_WINDOW		(AR9170_MAC_REG_BASE + 0x51C)
-#define AR9170_MAC_REG_BCN_PERIOD		(AR9170_MAC_REG_BASE + 0x520)
-#define AR9170_MAC_REG_PRETBTT			(AR9170_MAC_REG_BASE + 0x524)
-
-#define AR9170_MAC_REG_MAC_ADDR_L		(AR9170_MAC_REG_BASE + 0x610)
-#define AR9170_MAC_REG_MAC_ADDR_H		(AR9170_MAC_REG_BASE + 0x614)
-#define AR9170_MAC_REG_BSSID_L			(AR9170_MAC_REG_BASE + 0x618)
-#define AR9170_MAC_REG_BSSID_H			(AR9170_MAC_REG_BASE + 0x61c)
-
-#define AR9170_MAC_REG_GROUP_HASH_TBL_L		(AR9170_MAC_REG_BASE + 0x624)
-#define AR9170_MAC_REG_GROUP_HASH_TBL_H		(AR9170_MAC_REG_BASE + 0x628)
-
-#define AR9170_MAC_REG_RX_TIMEOUT		(AR9170_MAC_REG_BASE + 0x62C)
-
-#define AR9170_MAC_REG_BASIC_RATE		(AR9170_MAC_REG_BASE + 0x630)
-#define AR9170_MAC_REG_MANDATORY_RATE		(AR9170_MAC_REG_BASE + 0x634)
-#define AR9170_MAC_REG_RTS_CTS_RATE		(AR9170_MAC_REG_BASE + 0x638)
-#define AR9170_MAC_REG_BACKOFF_PROTECT		(AR9170_MAC_REG_BASE + 0x63c)
-#define AR9170_MAC_REG_RX_THRESHOLD		(AR9170_MAC_REG_BASE + 0x640)
-#define AR9170_MAC_REG_RX_PE_DELAY		(AR9170_MAC_REG_BASE + 0x64C)
-
-#define AR9170_MAC_REG_DYNAMIC_SIFS_ACK		(AR9170_MAC_REG_BASE + 0x658)
-#define AR9170_MAC_REG_SNIFFER			(AR9170_MAC_REG_BASE + 0x674)
-#define		AR9170_MAC_REG_SNIFFER_ENABLE_PROMISC	BIT(0)
-#define		AR9170_MAC_REG_SNIFFER_DEFAULTS		0x02000000
-#define AR9170_MAC_REG_ENCRYPTION		(AR9170_MAC_REG_BASE + 0x678)
-#define		AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE	BIT(3)
-#define		AR9170_MAC_REG_ENCRYPTION_DEFAULTS	0x70
-
-#define AR9170_MAC_REG_MISC_680			(AR9170_MAC_REG_BASE + 0x680)
-#define AR9170_MAC_REG_TX_UNDERRUN		(AR9170_MAC_REG_BASE + 0x688)
-
-#define AR9170_MAC_REG_FRAMETYPE_FILTER		(AR9170_MAC_REG_BASE + 0x68c)
-#define		AR9170_MAC_REG_FTF_ASSOC_REQ		BIT(0)
-#define		AR9170_MAC_REG_FTF_ASSOC_RESP		BIT(1)
-#define		AR9170_MAC_REG_FTF_REASSOC_REQ		BIT(2)
-#define		AR9170_MAC_REG_FTF_REASSOC_RESP		BIT(3)
-#define		AR9170_MAC_REG_FTF_PRB_REQ		BIT(4)
-#define		AR9170_MAC_REG_FTF_PRB_RESP		BIT(5)
-#define		AR9170_MAC_REG_FTF_BIT6			BIT(6)
-#define		AR9170_MAC_REG_FTF_BIT7			BIT(7)
-#define		AR9170_MAC_REG_FTF_BEACON		BIT(8)
-#define		AR9170_MAC_REG_FTF_ATIM			BIT(9)
-#define		AR9170_MAC_REG_FTF_DEASSOC		BIT(10)
-#define		AR9170_MAC_REG_FTF_AUTH			BIT(11)
-#define		AR9170_MAC_REG_FTF_DEAUTH		BIT(12)
-#define		AR9170_MAC_REG_FTF_BIT13		BIT(13)
-#define		AR9170_MAC_REG_FTF_BIT14		BIT(14)
-#define		AR9170_MAC_REG_FTF_BIT15		BIT(15)
-#define		AR9170_MAC_REG_FTF_BAR			BIT(24)
-#define		AR9170_MAC_REG_FTF_BA			BIT(25)
-#define		AR9170_MAC_REG_FTF_PSPOLL		BIT(26)
-#define		AR9170_MAC_REG_FTF_RTS			BIT(27)
-#define		AR9170_MAC_REG_FTF_CTS			BIT(28)
-#define		AR9170_MAC_REG_FTF_ACK			BIT(29)
-#define		AR9170_MAC_REG_FTF_CFE			BIT(30)
-#define		AR9170_MAC_REG_FTF_CFE_ACK		BIT(31)
-#define		AR9170_MAC_REG_FTF_DEFAULTS		0x0700ffff
-#define		AR9170_MAC_REG_FTF_MONITOR		0xfd00ffff
-
-#define AR9170_MAC_REG_RX_TOTAL			(AR9170_MAC_REG_BASE + 0x6A0)
-#define AR9170_MAC_REG_RX_CRC32			(AR9170_MAC_REG_BASE + 0x6A4)
-#define AR9170_MAC_REG_RX_CRC16			(AR9170_MAC_REG_BASE + 0x6A8)
-#define AR9170_MAC_REG_RX_ERR_DECRYPTION_UNI	(AR9170_MAC_REG_BASE + 0x6AC)
-#define AR9170_MAC_REG_RX_OVERRUN		(AR9170_MAC_REG_BASE + 0x6B0)
-#define AR9170_MAC_REG_RX_ERR_DECRYPTION_MUL	(AR9170_MAC_REG_BASE + 0x6BC)
-#define AR9170_MAC_REG_TX_RETRY			(AR9170_MAC_REG_BASE + 0x6CC)
-#define AR9170_MAC_REG_TX_TOTAL			(AR9170_MAC_REG_BASE + 0x6F4)
-
-
-#define AR9170_MAC_REG_ACK_EXTENSION		(AR9170_MAC_REG_BASE + 0x690)
-#define AR9170_MAC_REG_EIFS_AND_SIFS		(AR9170_MAC_REG_BASE + 0x698)
-
-#define AR9170_MAC_REG_SLOT_TIME		(AR9170_MAC_REG_BASE + 0x6F0)
-
-#define AR9170_MAC_REG_POWERMANAGEMENT		(AR9170_MAC_REG_BASE + 0x700)
-#define		AR9170_MAC_REG_POWERMGT_IBSS		0xe0
-#define		AR9170_MAC_REG_POWERMGT_AP		0xa1
-#define		AR9170_MAC_REG_POWERMGT_STA		0x2
-#define		AR9170_MAC_REG_POWERMGT_AP_WDS		0x3
-#define		AR9170_MAC_REG_POWERMGT_DEFAULTS	(0xf << 24)
-
-#define AR9170_MAC_REG_ROLL_CALL_TBL_L		(AR9170_MAC_REG_BASE + 0x704)
-#define AR9170_MAC_REG_ROLL_CALL_TBL_H		(AR9170_MAC_REG_BASE + 0x708)
-
-#define AR9170_MAC_REG_AC0_CW			(AR9170_MAC_REG_BASE + 0xB00)
-#define AR9170_MAC_REG_AC1_CW			(AR9170_MAC_REG_BASE + 0xB04)
-#define AR9170_MAC_REG_AC2_CW			(AR9170_MAC_REG_BASE + 0xB08)
-#define AR9170_MAC_REG_AC3_CW			(AR9170_MAC_REG_BASE + 0xB0C)
-#define AR9170_MAC_REG_AC4_CW			(AR9170_MAC_REG_BASE + 0xB10)
-#define AR9170_MAC_REG_AC1_AC0_AIFS		(AR9170_MAC_REG_BASE + 0xB14)
-#define AR9170_MAC_REG_AC3_AC2_AIFS		(AR9170_MAC_REG_BASE + 0xB18)
-
-#define AR9170_MAC_REG_RETRY_MAX		(AR9170_MAC_REG_BASE + 0xB28)
-
-#define AR9170_MAC_REG_FCS_SELECT		(AR9170_MAC_REG_BASE + 0xBB0)
-#define		AR9170_MAC_FCS_SWFCS		0x1
-#define		AR9170_MAC_FCS_FIFO_PROT	0x4
-
-
-#define AR9170_MAC_REG_TXOP_NOT_ENOUGH_IND	(AR9170_MAC_REG_BASE + 0xB30)
-
-#define AR9170_MAC_REG_AC1_AC0_TXOP		(AR9170_MAC_REG_BASE + 0xB44)
-#define AR9170_MAC_REG_AC3_AC2_TXOP		(AR9170_MAC_REG_BASE + 0xB48)
-
-#define AR9170_MAC_REG_AMPDU_FACTOR		(AR9170_MAC_REG_BASE + 0xB9C)
-#define AR9170_MAC_REG_AMPDU_DENSITY		(AR9170_MAC_REG_BASE + 0xBA0)
-
-#define AR9170_MAC_REG_ACK_TABLE		(AR9170_MAC_REG_BASE + 0xC00)
-#define AR9170_MAC_REG_AMPDU_RX_THRESH		(AR9170_MAC_REG_BASE + 0xC50)
-
-#define AR9170_MAC_REG_TXRX_MPI			(AR9170_MAC_REG_BASE + 0xD7C)
-#define		AR9170_MAC_TXRX_MPI_TX_MPI_MASK	0x0000000f
-#define		AR9170_MAC_TXRX_MPI_TX_TO_MASK	0x0000fff0
-#define		AR9170_MAC_TXRX_MPI_RX_MPI_MASK	0x000f0000
-#define		AR9170_MAC_TXRX_MPI_RX_TO_MASK	0xfff00000
-
-#define AR9170_MAC_REG_BCN_ADDR			(AR9170_MAC_REG_BASE + 0xD84)
-#define AR9170_MAC_REG_BCN_LENGTH		(AR9170_MAC_REG_BASE + 0xD88)
-#define AR9170_MAC_REG_BCN_PLCP			(AR9170_MAC_REG_BASE + 0xD90)
-#define AR9170_MAC_REG_BCN_CTRL			(AR9170_MAC_REG_BASE + 0xD94)
-#define AR9170_MAC_REG_BCN_HT1			(AR9170_MAC_REG_BASE + 0xDA0)
-#define AR9170_MAC_REG_BCN_HT2			(AR9170_MAC_REG_BASE + 0xDA4)
-
-
-#define AR9170_PWR_REG_BASE			0x1D4000
-
-#define AR9170_PWR_REG_CLOCK_SEL		(AR9170_PWR_REG_BASE + 0x008)
-#define		AR9170_PWR_CLK_AHB_40MHZ	0
-#define		AR9170_PWR_CLK_AHB_20_22MHZ	1
-#define		AR9170_PWR_CLK_AHB_40_44MHZ	2
-#define		AR9170_PWR_CLK_AHB_80_88MHZ	3
-#define		AR9170_PWR_CLK_DAC_160_INV_DLY	0x70
-
-
-/* put beacon here in memory */
-#define AR9170_BEACON_BUFFER_ADDRESS		0x117900
-
-
-struct ar9170_tx_control {
-	__le16 length;
-	__le16 mac_control;
-	__le32 phy_control;
-	u8 frame_data[0];
-} __packed;
-
-/* these are either-or */
-#define AR9170_TX_MAC_PROT_RTS			0x0001
-#define AR9170_TX_MAC_PROT_CTS			0x0002
-
-#define AR9170_TX_MAC_NO_ACK			0x0004
-/* if unset, MAC will only do SIFS space before frame */
-#define AR9170_TX_MAC_BACKOFF			0x0008
-#define AR9170_TX_MAC_BURST			0x0010
-#define AR9170_TX_MAC_AGGR			0x0020
-
-/* encryption is a two-bit field */
-#define AR9170_TX_MAC_ENCR_NONE			0x0000
-#define AR9170_TX_MAC_ENCR_RC4			0x0040
-#define AR9170_TX_MAC_ENCR_CENC			0x0080
-#define AR9170_TX_MAC_ENCR_AES			0x00c0
-
-#define AR9170_TX_MAC_MMIC			0x0100
-#define AR9170_TX_MAC_HW_DURATION		0x0200
-#define AR9170_TX_MAC_QOS_SHIFT			10
-#define AR9170_TX_MAC_QOS_MASK			(3 << AR9170_TX_MAC_QOS_SHIFT)
-#define AR9170_TX_MAC_AGGR_QOS_BIT1		0x0400
-#define AR9170_TX_MAC_AGGR_QOS_BIT2		0x0800
-#define AR9170_TX_MAC_DISABLE_TXOP		0x1000
-#define AR9170_TX_MAC_TXOP_RIFS			0x2000
-#define AR9170_TX_MAC_IMM_AMPDU			0x4000
-#define AR9170_TX_MAC_RATE_PROBE		0x8000
-
-/* either-or */
-#define AR9170_TX_PHY_MOD_MASK			0x00000003
-#define AR9170_TX_PHY_MOD_CCK			0x00000000
-#define AR9170_TX_PHY_MOD_OFDM			0x00000001
-#define AR9170_TX_PHY_MOD_HT			0x00000002
-
-/* depends on modulation */
-#define AR9170_TX_PHY_SHORT_PREAMBLE		0x00000004
-#define AR9170_TX_PHY_GREENFIELD		0x00000004
-
-#define AR9170_TX_PHY_BW_SHIFT			3
-#define AR9170_TX_PHY_BW_MASK			(3 << AR9170_TX_PHY_BW_SHIFT)
-#define AR9170_TX_PHY_BW_20MHZ			0
-#define AR9170_TX_PHY_BW_40MHZ			2
-#define AR9170_TX_PHY_BW_40MHZ_DUP		3
-
-#define AR9170_TX_PHY_TX_HEAVY_CLIP_SHIFT	6
-#define AR9170_TX_PHY_TX_HEAVY_CLIP_MASK	(7 << AR9170_TX_PHY_TX_HEAVY_CLIP_SHIFT)
-
-#define AR9170_TX_PHY_TX_PWR_SHIFT		9
-#define AR9170_TX_PHY_TX_PWR_MASK		(0x3f << AR9170_TX_PHY_TX_PWR_SHIFT)
-
-/* not part of the hw-spec */
-#define AR9170_TX_PHY_QOS_SHIFT			25
-#define AR9170_TX_PHY_QOS_MASK			(3 << AR9170_TX_PHY_QOS_SHIFT)
-
-#define AR9170_TX_PHY_TXCHAIN_SHIFT		15
-#define AR9170_TX_PHY_TXCHAIN_MASK		(7 << AR9170_TX_PHY_TXCHAIN_SHIFT)
-#define AR9170_TX_PHY_TXCHAIN_1			1
-/* use for cck, ofdm 6/9/12/18/24 and HT if capable */
-#define AR9170_TX_PHY_TXCHAIN_2			5
-
-#define AR9170_TX_PHY_MCS_SHIFT			18
-#define AR9170_TX_PHY_MCS_MASK			(0x7f << AR9170_TX_PHY_MCS_SHIFT)
-
-#define AR9170_TX_PHY_SHORT_GI			0x80000000
-
-#define AR5416_MAX_RATE_POWER                   63
-
-struct ar9170_rx_head {
-	u8 plcp[12];
-} __packed;
-
-struct ar9170_rx_phystatus {
-	union {
-		struct {
-			u8 rssi_ant0, rssi_ant1, rssi_ant2,
-			   rssi_ant0x, rssi_ant1x, rssi_ant2x,
-			   rssi_combined;
-		} __packed;
-		u8 rssi[7];
-	} __packed;
-
-	u8 evm_stream0[6], evm_stream1[6];
-	u8 phy_err;
-} __packed;
-
-struct ar9170_rx_macstatus {
-	u8 SAidx, DAidx;
-	u8 error;
-	u8 status;
-} __packed;
-
-#define AR9170_ENC_ALG_NONE			0x0
-#define AR9170_ENC_ALG_WEP64			0x1
-#define AR9170_ENC_ALG_TKIP			0x2
-#define AR9170_ENC_ALG_AESCCMP			0x4
-#define AR9170_ENC_ALG_WEP128			0x5
-#define AR9170_ENC_ALG_WEP256			0x6
-#define AR9170_ENC_ALG_CENC			0x7
-
-#define AR9170_RX_ENC_SOFTWARE			0x8
-
-static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_macstatus *t)
-{
-	return (t->SAidx & 0xc0) >> 4 |
-	       (t->DAidx & 0xc0) >> 6;
-}
-
-#define AR9170_RX_STATUS_MODULATION_MASK	0x03
-#define AR9170_RX_STATUS_MODULATION_CCK		0x00
-#define AR9170_RX_STATUS_MODULATION_OFDM	0x01
-#define AR9170_RX_STATUS_MODULATION_HT		0x02
-#define AR9170_RX_STATUS_MODULATION_DUPOFDM	0x03
-
-/* depends on modulation */
-#define AR9170_RX_STATUS_SHORT_PREAMBLE		0x08
-#define AR9170_RX_STATUS_GREENFIELD		0x08
-
-#define AR9170_RX_STATUS_MPDU_MASK		0x30
-#define AR9170_RX_STATUS_MPDU_SINGLE		0x00
-#define AR9170_RX_STATUS_MPDU_FIRST		0x20
-#define AR9170_RX_STATUS_MPDU_MIDDLE		0x30
-#define AR9170_RX_STATUS_MPDU_LAST		0x10
-
-#define AR9170_RX_ERROR_RXTO			0x01
-#define AR9170_RX_ERROR_OVERRUN			0x02
-#define AR9170_RX_ERROR_DECRYPT			0x04
-#define AR9170_RX_ERROR_FCS			0x08
-#define AR9170_RX_ERROR_WRONG_RA		0x10
-#define AR9170_RX_ERROR_PLCP			0x20
-#define AR9170_RX_ERROR_MMIC			0x40
-#define AR9170_RX_ERROR_FATAL			0x80
-
-struct ar9170_cmd_tx_status {
-	u8 dst[ETH_ALEN];
-	__le32 rate;
-	__le16 status;
-} __packed;
-
-#define AR9170_TX_STATUS_COMPLETE		0x00
-#define AR9170_TX_STATUS_RETRY			0x01
-#define AR9170_TX_STATUS_FAILED			0x02
-
-struct ar9170_cmd_ba_failed_count {
-	__le16 failed;
-	__le16 rate;
-} __packed;
-
-struct ar9170_cmd_response {
-	u8 flag;
-	u8 type;
-	__le16 padding;
-
-	union {
-		struct ar9170_cmd_tx_status		tx_status;
-		struct ar9170_cmd_ba_failed_count	ba_fail_cnt;
-		u8 data[0];
-	};
-} __packed;
-
-/* QoS */
-
-/* mac80211 queue to HW/FW map */
-static const u8 ar9170_qos_hwmap[4] = { 3, 2, 0, 1 };
-
-/* HW/FW queue to mac80211 map */
-static const u8 ar9170_qos_mac80211map[4] = { 2, 3, 1, 0 };
-
-enum ar9170_txq {
-	AR9170_TXQ_BE,
-	AR9170_TXQ_BK,
-	AR9170_TXQ_VI,
-	AR9170_TXQ_VO,
-
-	__AR9170_NUM_TXQ,
-};
-
-#define AR9170_TXQ_DEPTH	32
-#define AR9170_TX_MAX_PENDING	128
-#define AR9170_RX_STREAM_MAX_SIZE 65535
-
-#endif /* __AR9170_HW_H */
diff --git a/drivers/net/wireless/ath/ar9170/led.c b/drivers/net/wireless/ath/ar9170/led.c
deleted file mode 100644
index 832d900..0000000
--- a/drivers/net/wireless/ath/ar9170/led.c
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Atheros AR9170 driver
- *
- * LED handling
- *
- * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.  If not, see
- * http://www.gnu.org/licenses/.
- *
- * This file incorporates work covered by the following copyright and
- * permission notice:
- *    Copyright (c) 2007-2008 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 "ar9170.h"
-#include "cmd.h"
-
-int ar9170_set_leds_state(struct ar9170 *ar, u32 led_state)
-{
-	return ar9170_write_reg(ar, AR9170_GPIO_REG_DATA, led_state);
-}
-
-int ar9170_init_leds(struct ar9170 *ar)
-{
-	int err;
-
-	/* disable LEDs */
-	/* GPIO [0/1 mode: output, 2/3: input] */
-	err = ar9170_write_reg(ar, AR9170_GPIO_REG_PORT_TYPE, 3);
-	if (err)
-		goto out;
-
-	/* GPIO 0/1 value: off */
-	err = ar9170_set_leds_state(ar, 0);
-
-out:
-	return err;
-}
-
-#ifdef CONFIG_AR9170_LEDS
-static void ar9170_update_leds(struct work_struct *work)
-{
-	struct ar9170 *ar = container_of(work, struct ar9170, led_work.work);
-	int i, tmp, blink_delay = 1000;
-	u32 led_val = 0;
-	bool rerun = false;
-
-	if (unlikely(!IS_ACCEPTING_CMD(ar)))
-		return ;
-
-	mutex_lock(&ar->mutex);
-	for (i = 0; i < AR9170_NUM_LEDS; i++)
-		if (ar->leds[i].registered && ar->leds[i].toggled) {
-			led_val |= 1 << i;
-
-			tmp = 70 + 200 / (ar->leds[i].toggled);
-			if (tmp < blink_delay)
-				blink_delay = tmp;
-
-			if (ar->leds[i].toggled > 1)
-				ar->leds[i].toggled = 0;
-
-			rerun = true;
-		}
-
-	ar9170_set_leds_state(ar, led_val);
-	mutex_unlock(&ar->mutex);
-
-	if (!rerun)
-		return;
-
-	ieee80211_queue_delayed_work(ar->hw,
-				     &ar->led_work,
-				     msecs_to_jiffies(blink_delay));
-}
-
-static void ar9170_led_brightness_set(struct led_classdev *led,
-				      enum led_brightness brightness)
-{
-	struct ar9170_led *arl = container_of(led, struct ar9170_led, l);
-	struct ar9170 *ar = arl->ar;
-
-	if (unlikely(!arl->registered))
-		return ;
-
-	if (arl->last_state != !!brightness) {
-		arl->toggled++;
-		arl->last_state = !!brightness;
-	}
-
-	if (likely(IS_ACCEPTING_CMD(ar) && arl->toggled))
-		ieee80211_queue_delayed_work(ar->hw, &ar->led_work, HZ/10);
-}
-
-static int ar9170_register_led(struct ar9170 *ar, int i, char *name,
-			       char *trigger)
-{
-	int err;
-
-	snprintf(ar->leds[i].name, sizeof(ar->leds[i].name),
-		 "ar9170-%s::%s", wiphy_name(ar->hw->wiphy), name);
-
-	ar->leds[i].ar = ar;
-	ar->leds[i].l.name = ar->leds[i].name;
-	ar->leds[i].l.brightness_set = ar9170_led_brightness_set;
-	ar->leds[i].l.brightness = 0;
-	ar->leds[i].l.default_trigger = trigger;
-
-	err = led_classdev_register(wiphy_dev(ar->hw->wiphy),
-				    &ar->leds[i].l);
-	if (err)
-		wiphy_err(ar->hw->wiphy, "failed to register %s LED (%d).\n",
-			  ar->leds[i].name, err);
-	else
-		ar->leds[i].registered = true;
-
-	return err;
-}
-
-void ar9170_unregister_leds(struct ar9170 *ar)
-{
-	int i;
-
-	for (i = 0; i < AR9170_NUM_LEDS; i++)
-		if (ar->leds[i].registered) {
-			led_classdev_unregister(&ar->leds[i].l);
-			ar->leds[i].registered = false;
-			ar->leds[i].toggled = 0;
-		}
-
-	cancel_delayed_work_sync(&ar->led_work);
-}
-
-int ar9170_register_leds(struct ar9170 *ar)
-{
-	int err;
-
-	INIT_DELAYED_WORK(&ar->led_work, ar9170_update_leds);
-
-	err = ar9170_register_led(ar, 0, "tx",
-				  ieee80211_get_tx_led_name(ar->hw));
-	if (err)
-		goto fail;
-
-	err = ar9170_register_led(ar, 1, "assoc",
-				 ieee80211_get_assoc_led_name(ar->hw));
-	if (err)
-		goto fail;
-
-	return 0;
-
-fail:
-	ar9170_unregister_leds(ar);
-	return err;
-}
-
-#endif /* CONFIG_AR9170_LEDS */
diff --git a/drivers/net/wireless/ath/ar9170/mac.c b/drivers/net/wireless/ath/ar9170/mac.c
deleted file mode 100644
index 857e861..0000000
--- a/drivers/net/wireless/ath/ar9170/mac.c
+++ /dev/null
@@ -1,519 +0,0 @@
-/*
- * Atheros AR9170 driver
- *
- * MAC programming
- *
- * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.  If not, see
- * http://www.gnu.org/licenses/.
- *
- * This file incorporates work covered by the following copyright and
- * permission notice:
- *    Copyright (c) 2007-2008 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 <asm/unaligned.h>
-
-#include "ar9170.h"
-#include "cmd.h"
-
-int ar9170_set_dyn_sifs_ack(struct ar9170 *ar)
-{
-	u32 val;
-
-	if (conf_is_ht40(&ar->hw->conf))
-		val = 0x010a;
-	else {
-		if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ)
-			val = 0x105;
-		else
-			val = 0x104;
-	}
-
-	return ar9170_write_reg(ar, AR9170_MAC_REG_DYNAMIC_SIFS_ACK, val);
-}
-
-int ar9170_set_slot_time(struct ar9170 *ar)
-{
-	u32 slottime = 20;
-
-	if (!ar->vif)
-		return 0;
-
-	if ((ar->hw->conf.channel->band == IEEE80211_BAND_5GHZ) ||
-	    ar->vif->bss_conf.use_short_slot)
-		slottime = 9;
-
-	return ar9170_write_reg(ar, AR9170_MAC_REG_SLOT_TIME, slottime << 10);
-}
-
-int ar9170_set_basic_rates(struct ar9170 *ar)
-{
-	u8 cck, ofdm;
-
-	if (!ar->vif)
-		return 0;
-
-	ofdm = ar->vif->bss_conf.basic_rates >> 4;
-
-	/* FIXME: is still necessary? */
-	if (ar->hw->conf.channel->band == IEEE80211_BAND_5GHZ)
-		cck = 0;
-	else
-		cck = ar->vif->bss_conf.basic_rates & 0xf;
-
-	return ar9170_write_reg(ar, AR9170_MAC_REG_BASIC_RATE,
-				ofdm << 8 | cck);
-}
-
-int ar9170_set_qos(struct ar9170 *ar)
-{
-	ar9170_regwrite_begin(ar);
-
-	ar9170_regwrite(AR9170_MAC_REG_AC0_CW, ar->edcf[0].cw_min |
-			(ar->edcf[0].cw_max << 16));
-	ar9170_regwrite(AR9170_MAC_REG_AC1_CW, ar->edcf[1].cw_min |
-			(ar->edcf[1].cw_max << 16));
-	ar9170_regwrite(AR9170_MAC_REG_AC2_CW, ar->edcf[2].cw_min |
-			(ar->edcf[2].cw_max << 16));
-	ar9170_regwrite(AR9170_MAC_REG_AC3_CW, ar->edcf[3].cw_min |
-			(ar->edcf[3].cw_max << 16));
-	ar9170_regwrite(AR9170_MAC_REG_AC4_CW, ar->edcf[4].cw_min |
-			(ar->edcf[4].cw_max << 16));
-
-	ar9170_regwrite(AR9170_MAC_REG_AC1_AC0_AIFS,
-			((ar->edcf[0].aifs * 9 + 10)) |
-			((ar->edcf[1].aifs * 9 + 10) << 12) |
-			((ar->edcf[2].aifs * 9 + 10) << 24));
-	ar9170_regwrite(AR9170_MAC_REG_AC3_AC2_AIFS,
-			((ar->edcf[2].aifs * 9 + 10) >> 8) |
-			((ar->edcf[3].aifs * 9 + 10) << 4) |
-			((ar->edcf[4].aifs * 9 + 10) << 16));
-
-	ar9170_regwrite(AR9170_MAC_REG_AC1_AC0_TXOP,
-			ar->edcf[0].txop | ar->edcf[1].txop << 16);
-	ar9170_regwrite(AR9170_MAC_REG_AC3_AC2_TXOP,
-			ar->edcf[2].txop | ar->edcf[3].txop << 16);
-
-	ar9170_regwrite_finish();
-
-	return ar9170_regwrite_result();
-}
-
-static int ar9170_set_ampdu_density(struct ar9170 *ar, u8 mpdudensity)
-{
-	u32 val;
-
-	/* don't allow AMPDU density > 8us */
-	if (mpdudensity > 6)
-		return -EINVAL;
-
-	/* Watch out! Otus uses slightly different density values. */
-	val = 0x140a00 | (mpdudensity ? (mpdudensity + 1) : 0);
-
-	ar9170_regwrite_begin(ar);
-	ar9170_regwrite(AR9170_MAC_REG_AMPDU_DENSITY, val);
-	ar9170_regwrite_finish();
-
-	return ar9170_regwrite_result();
-}
-
-int ar9170_init_mac(struct ar9170 *ar)
-{
-	ar9170_regwrite_begin(ar);
-
-	ar9170_regwrite(AR9170_MAC_REG_ACK_EXTENSION, 0x40);
-
-	ar9170_regwrite(AR9170_MAC_REG_RETRY_MAX, 0);
-
-	/* enable MMIC */
-	ar9170_regwrite(AR9170_MAC_REG_SNIFFER,
-			AR9170_MAC_REG_SNIFFER_DEFAULTS);
-
-	ar9170_regwrite(AR9170_MAC_REG_RX_THRESHOLD, 0xc1f80);
-
-	ar9170_regwrite(AR9170_MAC_REG_RX_PE_DELAY, 0x70);
-	ar9170_regwrite(AR9170_MAC_REG_EIFS_AND_SIFS, 0xa144000);
-	ar9170_regwrite(AR9170_MAC_REG_SLOT_TIME, 9 << 10);
-
-	/* CF-END mode */
-	ar9170_regwrite(0x1c3b2c, 0x19000000);
-
-	/* NAV protects ACK only (in TXOP) */
-	ar9170_regwrite(0x1c3b38, 0x201);
-
-	/* Set Beacon PHY CTRL's TPC to 0x7, TA1=1 */
-	/* OTUS set AM to 0x1 */
-	ar9170_regwrite(AR9170_MAC_REG_BCN_HT1, 0x8000170);
-
-	ar9170_regwrite(AR9170_MAC_REG_BACKOFF_PROTECT, 0x105);
-
-	/* AGG test code*/
-	/* Aggregation MAX number and timeout */
-	ar9170_regwrite(0x1c3b9c, 0x10000a);
-
-	ar9170_regwrite(AR9170_MAC_REG_FRAMETYPE_FILTER,
-			AR9170_MAC_REG_FTF_DEFAULTS);
-
-	/* Enable deaggregator, response in sniffer mode */
-	ar9170_regwrite(0x1c3c40, 0x1 | 1<<30);
-
-	/* rate sets */
-	ar9170_regwrite(AR9170_MAC_REG_BASIC_RATE, 0x150f);
-	ar9170_regwrite(AR9170_MAC_REG_MANDATORY_RATE, 0x150f);
-	ar9170_regwrite(AR9170_MAC_REG_RTS_CTS_RATE, 0x10b01bb);
-
-	/* MIMO response control */
-	ar9170_regwrite(0x1c3694, 0x4003C1E);/* bit 26~28  otus-AM */
-
-	/* switch MAC to OTUS interface */
-	ar9170_regwrite(0x1c3600, 0x3);
-
-	ar9170_regwrite(AR9170_MAC_REG_AMPDU_RX_THRESH, 0xffff);
-
-	/* set PHY register read timeout (??) */
-	ar9170_regwrite(AR9170_MAC_REG_MISC_680, 0xf00008);
-
-	/* Disable Rx TimeOut, workaround for BB. */
-	ar9170_regwrite(AR9170_MAC_REG_RX_TIMEOUT, 0x0);
-
-	/* Set CPU clock frequency to 88/80MHz */
-	ar9170_regwrite(AR9170_PWR_REG_CLOCK_SEL,
-			AR9170_PWR_CLK_AHB_80_88MHZ |
-			AR9170_PWR_CLK_DAC_160_INV_DLY);
-
-	/* Set WLAN DMA interrupt mode: generate int per packet */
-	ar9170_regwrite(AR9170_MAC_REG_TXRX_MPI, 0x110011);
-
-	ar9170_regwrite(AR9170_MAC_REG_FCS_SELECT,
-			AR9170_MAC_FCS_FIFO_PROT);
-
-	/* Disables the CF_END frame, undocumented register */
-	ar9170_regwrite(AR9170_MAC_REG_TXOP_NOT_ENOUGH_IND,
-			0x141E0F48);
-
-	ar9170_regwrite_finish();
-
-	return ar9170_regwrite_result();
-}
-
-static int ar9170_set_mac_reg(struct ar9170 *ar, const u32 reg, const u8 *mac)
-{
-	static const u8 zero[ETH_ALEN] = { 0 };
-
-	if (!mac)
-		mac = zero;
-
-	ar9170_regwrite_begin(ar);
-
-	ar9170_regwrite(reg, get_unaligned_le32(mac));
-	ar9170_regwrite(reg + 4, get_unaligned_le16(mac + 4));
-
-	ar9170_regwrite_finish();
-
-	return ar9170_regwrite_result();
-}
-
-int ar9170_update_multicast(struct ar9170 *ar, const u64 mc_hash)
-{
-	int err;
-
-	ar9170_regwrite_begin(ar);
-	ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_H, mc_hash >> 32);
-	ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_L, mc_hash);
-	ar9170_regwrite_finish();
-	err = ar9170_regwrite_result();
-	if (err)
-		return err;
-
-	ar->cur_mc_hash = mc_hash;
-	return 0;
-}
-
-int ar9170_update_frame_filter(struct ar9170 *ar, const u32 filter)
-{
-	int err;
-
-	err = ar9170_write_reg(ar, AR9170_MAC_REG_FRAMETYPE_FILTER, filter);
-	if (err)
-		return err;
-
-	ar->cur_filter = filter;
-	return 0;
-}
-
-static int ar9170_set_promiscouous(struct ar9170 *ar)
-{
-	u32 encr_mode, sniffer;
-	int err;
-
-	err = ar9170_read_reg(ar, AR9170_MAC_REG_SNIFFER, &sniffer);
-	if (err)
-		return err;
-
-	err = ar9170_read_reg(ar, AR9170_MAC_REG_ENCRYPTION, &encr_mode);
-	if (err)
-		return err;
-
-	if (ar->sniffer_enabled) {
-		sniffer |= AR9170_MAC_REG_SNIFFER_ENABLE_PROMISC;
-
-		/*
-		 * Rx decryption works in place.
-		 *
-		 * If we don't disable it, the hardware will render all
-		 * encrypted frames which are encrypted with an unknown
-		 * key useless.
-		 */
-
-		encr_mode |= AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE;
-		ar->sniffer_enabled = true;
-	} else {
-		sniffer &= ~AR9170_MAC_REG_SNIFFER_ENABLE_PROMISC;
-
-		if (ar->rx_software_decryption)
-			encr_mode |= AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE;
-		else
-			encr_mode &= ~AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE;
-	}
-
-	ar9170_regwrite_begin(ar);
-	ar9170_regwrite(AR9170_MAC_REG_ENCRYPTION, encr_mode);
-	ar9170_regwrite(AR9170_MAC_REG_SNIFFER, sniffer);
-	ar9170_regwrite_finish();
-
-	return ar9170_regwrite_result();
-}
-
-int ar9170_set_operating_mode(struct ar9170 *ar)
-{
-	struct ath_common *common = &ar->common;
-	u32 pm_mode = AR9170_MAC_REG_POWERMGT_DEFAULTS;
-	u8 *mac_addr, *bssid;
-	int err;
-
-	if (ar->vif) {
-		mac_addr = common->macaddr;
-		bssid = common->curbssid;
-
-		switch (ar->vif->type) {
-		case NL80211_IFTYPE_MESH_POINT:
-		case NL80211_IFTYPE_ADHOC:
-			pm_mode |= AR9170_MAC_REG_POWERMGT_IBSS;
-			break;
-		case NL80211_IFTYPE_AP:
-			pm_mode |= AR9170_MAC_REG_POWERMGT_AP;
-			break;
-		case NL80211_IFTYPE_WDS:
-			pm_mode |= AR9170_MAC_REG_POWERMGT_AP_WDS;
-			break;
-		case NL80211_IFTYPE_MONITOR:
-			ar->sniffer_enabled = true;
-			ar->rx_software_decryption = true;
-			break;
-		default:
-			pm_mode |= AR9170_MAC_REG_POWERMGT_STA;
-			break;
-		}
-	} else {
-		mac_addr = NULL;
-		bssid = NULL;
-	}
-
-	err = ar9170_set_mac_reg(ar, AR9170_MAC_REG_MAC_ADDR_L, mac_addr);
-	if (err)
-		return err;
-
-	err = ar9170_set_mac_reg(ar, AR9170_MAC_REG_BSSID_L, bssid);
-	if (err)
-		return err;
-
-	err = ar9170_set_promiscouous(ar);
-	if (err)
-		return err;
-
-	/* set AMPDU density to 8us. */
-	err = ar9170_set_ampdu_density(ar, 6);
-	if (err)
-		return err;
-
-	ar9170_regwrite_begin(ar);
-
-	ar9170_regwrite(AR9170_MAC_REG_POWERMANAGEMENT, pm_mode);
-	ar9170_regwrite_finish();
-
-	return ar9170_regwrite_result();
-}
-
-int ar9170_set_hwretry_limit(struct ar9170 *ar, unsigned int max_retry)
-{
-	u32 tmp = min_t(u32, 0x33333, max_retry * 0x11111);
-
-	return ar9170_write_reg(ar, AR9170_MAC_REG_RETRY_MAX, tmp);
-}
-
-int ar9170_set_beacon_timers(struct ar9170 *ar)
-{
-	u32 v = 0;
-	u32 pretbtt = 0;
-
-	if (ar->vif) {
-		v |= ar->vif->bss_conf.beacon_int;
-
-		if (ar->enable_beacon) {
-			switch (ar->vif->type) {
-			case NL80211_IFTYPE_MESH_POINT:
-			case NL80211_IFTYPE_ADHOC:
-				v |= BIT(25);
-				break;
-			case NL80211_IFTYPE_AP:
-				v |= BIT(24);
-				pretbtt = (ar->vif->bss_conf.beacon_int - 6) <<
-					  16;
-				break;
-			default:
-			break;
-			}
-		}
-
-		v |= ar->vif->bss_conf.dtim_period << 16;
-	}
-
-	ar9170_regwrite_begin(ar);
-	ar9170_regwrite(AR9170_MAC_REG_PRETBTT, pretbtt);
-	ar9170_regwrite(AR9170_MAC_REG_BCN_PERIOD, v);
-	ar9170_regwrite_finish();
-	return ar9170_regwrite_result();
-}
-
-int ar9170_update_beacon(struct ar9170 *ar)
-{
-	struct sk_buff *skb;
-	__le32 *data, *old = NULL;
-	u32 word;
-	int i;
-
-	skb = ieee80211_beacon_get(ar->hw, ar->vif);
-	if (!skb)
-		return -ENOMEM;
-
-	data = (__le32 *)skb->data;
-	if (ar->beacon)
-		old = (__le32 *)ar->beacon->data;
-
-	ar9170_regwrite_begin(ar);
-	for (i = 0; i < DIV_ROUND_UP(skb->len, 4); i++) {
-		/*
-		 * XXX: This accesses beyond skb data for up
-		 *	to the last 3 bytes!!
-		 */
-
-		if (old && (data[i] == old[i]))
-			continue;
-
-		word = le32_to_cpu(data[i]);
-		ar9170_regwrite(AR9170_BEACON_BUFFER_ADDRESS + 4 * i, word);
-	}
-
-	/* XXX: use skb->cb info */
-	if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ)
-		ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP,
-				((skb->len + 4) << (3 + 16)) + 0x0400);
-	else
-		ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP,
-				((skb->len + 4) << 16) + 0x001b);
-
-	ar9170_regwrite(AR9170_MAC_REG_BCN_LENGTH, skb->len + 4);
-	ar9170_regwrite(AR9170_MAC_REG_BCN_ADDR, AR9170_BEACON_BUFFER_ADDRESS);
-	ar9170_regwrite(AR9170_MAC_REG_BCN_CTRL, 1);
-
-	ar9170_regwrite_finish();
-
-	dev_kfree_skb(ar->beacon);
-	ar->beacon = skb;
-
-	return ar9170_regwrite_result();
-}
-
-void ar9170_new_beacon(struct work_struct *work)
-{
-	struct ar9170 *ar = container_of(work, struct ar9170,
-					 beacon_work);
-	struct sk_buff *skb;
-
-	if (unlikely(!IS_STARTED(ar)))
-		return ;
-
-	mutex_lock(&ar->mutex);
-
-	if (!ar->vif)
-		goto out;
-
-	ar9170_update_beacon(ar);
-
-	rcu_read_lock();
-	while ((skb = ieee80211_get_buffered_bc(ar->hw, ar->vif)))
-		ar9170_op_tx(ar->hw, skb);
-
-	rcu_read_unlock();
-
- out:
-	mutex_unlock(&ar->mutex);
-}
-
-int ar9170_upload_key(struct ar9170 *ar, u8 id, const u8 *mac, u8 ktype,
-		      u8 keyidx, u8 *keydata, int keylen)
-{
-	__le32 vals[7];
-	static const u8 bcast[ETH_ALEN] =
-		{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-	u8 dummy;
-
-	mac = mac ? : bcast;
-
-	vals[0] = cpu_to_le32((keyidx << 16) + id);
-	vals[1] = cpu_to_le32(mac[1] << 24 | mac[0] << 16 | ktype);
-	vals[2] = cpu_to_le32(mac[5] << 24 | mac[4] << 16 |
-			      mac[3] << 8 | mac[2]);
-	memset(&vals[3], 0, 16);
-	if (keydata)
-		memcpy(&vals[3], keydata, keylen);
-
-	return ar->exec_cmd(ar, AR9170_CMD_EKEY,
-			    sizeof(vals), (u8 *)vals,
-			    1, &dummy);
-}
-
-int ar9170_disable_key(struct ar9170 *ar, u8 id)
-{
-	__le32 val = cpu_to_le32(id);
-	u8 dummy;
-
-	return ar->exec_cmd(ar, AR9170_CMD_EKEY,
-			    sizeof(val), (u8 *)&val,
-			    1, &dummy);
-}
diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c
deleted file mode 100644
index b761fec..0000000
--- a/drivers/net/wireless/ath/ar9170/main.c
+++ /dev/null
@@ -1,2190 +0,0 @@
-/*
- * Atheros AR9170 driver
- *
- * mac80211 interaction code
- *
- * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- * Copyright 2009, Christian Lamparter <chunkeey@web.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.  If not, see
- * http://www.gnu.org/licenses/.
- *
- * This file incorporates work covered by the following copyright and
- * permission notice:
- *    Copyright (c) 2007-2008 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/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/etherdevice.h>
-#include <net/mac80211.h>
-#include "ar9170.h"
-#include "hw.h"
-#include "cmd.h"
-
-static int modparam_nohwcrypt;
-module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
-MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
-
-#define RATE(_bitrate, _hw_rate, _txpidx, _flags) {	\
-	.bitrate	= (_bitrate),			\
-	.flags		= (_flags),			\
-	.hw_value	= (_hw_rate) | (_txpidx) << 4,	\
-}
-
-static struct ieee80211_rate __ar9170_ratetable[] = {
-	RATE(10, 0, 0, 0),
-	RATE(20, 1, 1, IEEE80211_RATE_SHORT_PREAMBLE),
-	RATE(55, 2, 2, IEEE80211_RATE_SHORT_PREAMBLE),
-	RATE(110, 3, 3, IEEE80211_RATE_SHORT_PREAMBLE),
-	RATE(60, 0xb, 0, 0),
-	RATE(90, 0xf, 0, 0),
-	RATE(120, 0xa, 0, 0),
-	RATE(180, 0xe, 0, 0),
-	RATE(240, 0x9, 0, 0),
-	RATE(360, 0xd, 1, 0),
-	RATE(480, 0x8, 2, 0),
-	RATE(540, 0xc, 3, 0),
-};
-#undef RATE
-
-#define ar9170_g_ratetable	(__ar9170_ratetable + 0)
-#define ar9170_g_ratetable_size	12
-#define ar9170_a_ratetable	(__ar9170_ratetable + 4)
-#define ar9170_a_ratetable_size	8
-
-/*
- * NB: The hw_value is used as an index into the ar9170_phy_freq_params
- *     array in phy.c so that we don't have to do frequency lookups!
- */
-#define CHAN(_freq, _idx) {		\
-	.center_freq	= (_freq),	\
-	.hw_value	= (_idx),	\
-	.max_power	= 18, /* XXX */	\
-}
-
-static struct ieee80211_channel ar9170_2ghz_chantable[] = {
-	CHAN(2412,  0),
-	CHAN(2417,  1),
-	CHAN(2422,  2),
-	CHAN(2427,  3),
-	CHAN(2432,  4),
-	CHAN(2437,  5),
-	CHAN(2442,  6),
-	CHAN(2447,  7),
-	CHAN(2452,  8),
-	CHAN(2457,  9),
-	CHAN(2462, 10),
-	CHAN(2467, 11),
-	CHAN(2472, 12),
-	CHAN(2484, 13),
-};
-
-static struct ieee80211_channel ar9170_5ghz_chantable[] = {
-	CHAN(4920, 14),
-	CHAN(4940, 15),
-	CHAN(4960, 16),
-	CHAN(4980, 17),
-	CHAN(5040, 18),
-	CHAN(5060, 19),
-	CHAN(5080, 20),
-	CHAN(5180, 21),
-	CHAN(5200, 22),
-	CHAN(5220, 23),
-	CHAN(5240, 24),
-	CHAN(5260, 25),
-	CHAN(5280, 26),
-	CHAN(5300, 27),
-	CHAN(5320, 28),
-	CHAN(5500, 29),
-	CHAN(5520, 30),
-	CHAN(5540, 31),
-	CHAN(5560, 32),
-	CHAN(5580, 33),
-	CHAN(5600, 34),
-	CHAN(5620, 35),
-	CHAN(5640, 36),
-	CHAN(5660, 37),
-	CHAN(5680, 38),
-	CHAN(5700, 39),
-	CHAN(5745, 40),
-	CHAN(5765, 41),
-	CHAN(5785, 42),
-	CHAN(5805, 43),
-	CHAN(5825, 44),
-	CHAN(5170, 45),
-	CHAN(5190, 46),
-	CHAN(5210, 47),
-	CHAN(5230, 48),
-};
-#undef CHAN
-
-#define AR9170_HT_CAP							\
-{									\
-	.ht_supported	= true,						\
-	.cap		= IEEE80211_HT_CAP_MAX_AMSDU |			\
-			  IEEE80211_HT_CAP_SUP_WIDTH_20_40 |		\
-			  IEEE80211_HT_CAP_SGI_40 |			\
-			  IEEE80211_HT_CAP_GRN_FLD |			\
-			  IEEE80211_HT_CAP_DSSSCCK40 |			\
-			  IEEE80211_HT_CAP_SM_PS,			\
-	.ampdu_factor	= 3,						\
-	.ampdu_density	= 6,						\
-	.mcs		= {						\
-		.rx_mask = { 0xff, 0xff, 0, 0, 0x1, 0, 0, 0, 0, 0, },	\
-		.rx_highest = cpu_to_le16(300),				\
-		.tx_params = IEEE80211_HT_MCS_TX_DEFINED,		\
-	},								\
-}
-
-static struct ieee80211_supported_band ar9170_band_2GHz = {
-	.channels	= ar9170_2ghz_chantable,
-	.n_channels	= ARRAY_SIZE(ar9170_2ghz_chantable),
-	.bitrates	= ar9170_g_ratetable,
-	.n_bitrates	= ar9170_g_ratetable_size,
-	.ht_cap		= AR9170_HT_CAP,
-};
-
-static struct ieee80211_supported_band ar9170_band_5GHz = {
-	.channels	= ar9170_5ghz_chantable,
-	.n_channels	= ARRAY_SIZE(ar9170_5ghz_chantable),
-	.bitrates	= ar9170_a_ratetable,
-	.n_bitrates	= ar9170_a_ratetable_size,
-	.ht_cap		= AR9170_HT_CAP,
-};
-
-static void ar9170_tx(struct ar9170 *ar);
-
-static inline u16 ar9170_get_seq_h(struct ieee80211_hdr *hdr)
-{
-	return le16_to_cpu(hdr->seq_ctrl) >> 4;
-}
-
-static inline u16 ar9170_get_seq(struct sk_buff *skb)
-{
-	struct ar9170_tx_control *txc = (void *) skb->data;
-	return ar9170_get_seq_h((void *) txc->frame_data);
-}
-
-#ifdef AR9170_QUEUE_DEBUG
-static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb)
-{
-	struct ar9170_tx_control *txc = (void *) skb->data;
-	struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
-	struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data;
-	struct ieee80211_hdr *hdr = (void *) txc->frame_data;
-
-	wiphy_debug(ar->hw->wiphy,
-		    "=> FRAME [skb:%p, q:%d, DA:[%pM] s:%d "
-		    "mac_ctrl:%04x, phy_ctrl:%08x, timeout:[%d ms]]\n",
-		    skb, skb_get_queue_mapping(skb),
-		    ieee80211_get_DA(hdr), ar9170_get_seq_h(hdr),
-		    le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control),
-		    jiffies_to_msecs(arinfo->timeout - jiffies));
-}
-
-static void __ar9170_dump_txqueue(struct ar9170 *ar,
-				struct sk_buff_head *queue)
-{
-	struct sk_buff *skb;
-	int i = 0;
-
-	printk(KERN_DEBUG "---[ cut here ]---\n");
-	wiphy_debug(ar->hw->wiphy, "%d entries in queue.\n",
-		    skb_queue_len(queue));
-
-	skb_queue_walk(queue, skb) {
-		printk(KERN_DEBUG "index:%d =>\n", i++);
-		ar9170_print_txheader(ar, skb);
-	}
-	if (i != skb_queue_len(queue))
-		printk(KERN_DEBUG "WARNING: queue frame counter "
-		       "mismatch %d != %d\n", skb_queue_len(queue), i);
-	printk(KERN_DEBUG "---[ end ]---\n");
-}
-#endif /* AR9170_QUEUE_DEBUG */
-
-#ifdef AR9170_QUEUE_DEBUG
-static void ar9170_dump_txqueue(struct ar9170 *ar,
-				struct sk_buff_head *queue)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&queue->lock, flags);
-	__ar9170_dump_txqueue(ar, queue);
-	spin_unlock_irqrestore(&queue->lock, flags);
-}
-#endif /* AR9170_QUEUE_DEBUG */
-
-#ifdef AR9170_QUEUE_STOP_DEBUG
-static void __ar9170_dump_txstats(struct ar9170 *ar)
-{
-	int i;
-
-	wiphy_debug(ar->hw->wiphy, "QoS queue stats\n");
-
-	for (i = 0; i < __AR9170_NUM_TXQ; i++)
-		wiphy_debug(ar->hw->wiphy,
-			    "queue:%d limit:%d len:%d waitack:%d stopped:%d\n",
-			    i, ar->tx_stats[i].limit, ar->tx_stats[i].len,
-			    skb_queue_len(&ar->tx_status[i]),
-			    ieee80211_queue_stopped(ar->hw, i));
-}
-#endif /* AR9170_QUEUE_STOP_DEBUG */
-
-/* caller must guarantee exclusive access for _bin_ queue. */
-static void ar9170_recycle_expired(struct ar9170 *ar,
-				   struct sk_buff_head *queue,
-				   struct sk_buff_head *bin)
-{
-	struct sk_buff *skb, *old = NULL;
-	unsigned long flags;
-
-	spin_lock_irqsave(&queue->lock, flags);
-	while ((skb = skb_peek(queue))) {
-		struct ieee80211_tx_info *txinfo;
-		struct ar9170_tx_info *arinfo;
-
-		txinfo = IEEE80211_SKB_CB(skb);
-		arinfo = (void *) txinfo->rate_driver_data;
-
-		if (time_is_before_jiffies(arinfo->timeout)) {
-#ifdef AR9170_QUEUE_DEBUG
-			wiphy_debug(ar->hw->wiphy,
-				    "[%ld > %ld] frame expired => recycle\n",
-				    jiffies, arinfo->timeout);
-			ar9170_print_txheader(ar, skb);
-#endif /* AR9170_QUEUE_DEBUG */
-			__skb_unlink(skb, queue);
-			__skb_queue_tail(bin, skb);
-		} else {
-			break;
-		}
-
-		if (unlikely(old == skb)) {
-			/* bail out - queue is shot. */
-
-			WARN_ON(1);
-			break;
-		}
-		old = skb;
-	}
-	spin_unlock_irqrestore(&queue->lock, flags);
-}
-
-static void ar9170_tx_status(struct ar9170 *ar, struct sk_buff *skb,
-				    u16 tx_status)
-{
-	struct ieee80211_tx_info *txinfo;
-	unsigned int retries = 0;
-
-	txinfo = IEEE80211_SKB_CB(skb);
-	ieee80211_tx_info_clear_status(txinfo);
-
-	switch (tx_status) {
-	case AR9170_TX_STATUS_RETRY:
-		retries = 2;
-	case AR9170_TX_STATUS_COMPLETE:
-		txinfo->flags |= IEEE80211_TX_STAT_ACK;
-		break;
-
-	case AR9170_TX_STATUS_FAILED:
-		retries = ar->hw->conf.long_frame_max_tx_count;
-		break;
-
-	default:
-		wiphy_err(ar->hw->wiphy,
-			  "invalid tx_status response (%x)\n", tx_status);
-		break;
-	}
-
-	txinfo->status.rates[0].count = retries + 1;
-	skb_pull(skb, sizeof(struct ar9170_tx_control));
-	ieee80211_tx_status_irqsafe(ar->hw, skb);
-}
-
-void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
-{
-	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-	struct ar9170_tx_info *arinfo = (void *) info->rate_driver_data;
-	unsigned int queue = skb_get_queue_mapping(skb);
-	unsigned long flags;
-
-	spin_lock_irqsave(&ar->tx_stats_lock, flags);
-	ar->tx_stats[queue].len--;
-
-	if (ar->tx_stats[queue].len < AR9170_NUM_TX_LIMIT_SOFT) {
-#ifdef AR9170_QUEUE_STOP_DEBUG
-		wiphy_debug(ar->hw->wiphy, "wake queue %d\n", queue);
-		__ar9170_dump_txstats(ar);
-#endif /* AR9170_QUEUE_STOP_DEBUG */
-		ieee80211_wake_queue(ar->hw, queue);
-	}
-	spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
-
-	if (info->flags & IEEE80211_TX_CTL_NO_ACK) {
-		ar9170_tx_status(ar, skb, AR9170_TX_STATUS_FAILED);
-	} else {
-		arinfo->timeout = jiffies +
-			  msecs_to_jiffies(AR9170_TX_TIMEOUT);
-
-		skb_queue_tail(&ar->tx_status[queue], skb);
-	}
-
-	if (!ar->tx_stats[queue].len &&
-	    !skb_queue_empty(&ar->tx_pending[queue])) {
-		ar9170_tx(ar);
-	}
-}
-
-static struct sk_buff *ar9170_get_queued_skb(struct ar9170 *ar,
-					     const u8 *mac,
-					     struct sk_buff_head *queue,
-					     const u32 rate)
-{
-	unsigned long flags;
-	struct sk_buff *skb;
-
-	/*
-	 * Unfortunately, the firmware does not tell to which (queued) frame
-	 * this transmission status report belongs to.
-	 *
-	 * So we have to make risky guesses - with the scarce information
-	 * the firmware provided (-> destination MAC, and phy_control) -
-	 * and hope that we picked the right one...
-	 */
-
-	spin_lock_irqsave(&queue->lock, flags);
-	skb_queue_walk(queue, skb) {
-		struct ar9170_tx_control *txc = (void *) skb->data;
-		struct ieee80211_hdr *hdr = (void *) txc->frame_data;
-		u32 r;
-
-		if (mac && compare_ether_addr(ieee80211_get_DA(hdr), mac)) {
-#ifdef AR9170_QUEUE_DEBUG
-			wiphy_debug(ar->hw->wiphy,
-				    "skip frame => DA %pM != %pM\n",
-				    mac, ieee80211_get_DA(hdr));
-			ar9170_print_txheader(ar, skb);
-#endif /* AR9170_QUEUE_DEBUG */
-			continue;
-		}
-
-		r = (le32_to_cpu(txc->phy_control) & AR9170_TX_PHY_MCS_MASK) >>
-		    AR9170_TX_PHY_MCS_SHIFT;
-
-		if ((rate != AR9170_TX_INVALID_RATE) && (r != rate)) {
-#ifdef AR9170_QUEUE_DEBUG
-			wiphy_debug(ar->hw->wiphy,
-				    "skip frame => rate %d != %d\n", rate, r);
-			ar9170_print_txheader(ar, skb);
-#endif /* AR9170_QUEUE_DEBUG */
-			continue;
-		}
-
-		__skb_unlink(skb, queue);
-		spin_unlock_irqrestore(&queue->lock, flags);
-		return skb;
-	}
-
-#ifdef AR9170_QUEUE_DEBUG
-	wiphy_err(ar->hw->wiphy,
-		  "ESS:[%pM] does not have any outstanding frames in queue.\n",
-		  mac);
-	__ar9170_dump_txqueue(ar, queue);
-#endif /* AR9170_QUEUE_DEBUG */
-	spin_unlock_irqrestore(&queue->lock, flags);
-
-	return NULL;
-}
-
-/*
- * This worker tries to keeps an maintain tx_status queues.
- * So we can guarantee that incoming tx_status reports are
- * actually for a pending frame.
- */
-
-static void ar9170_tx_janitor(struct work_struct *work)
-{
-	struct ar9170 *ar = container_of(work, struct ar9170,
-					 tx_janitor.work);
-	struct sk_buff_head waste;
-	unsigned int i;
-	bool resched = false;
-
-	if (unlikely(!IS_STARTED(ar)))
-		return ;
-
-	skb_queue_head_init(&waste);
-
-	for (i = 0; i < __AR9170_NUM_TXQ; i++) {
-#ifdef AR9170_QUEUE_DEBUG
-		wiphy_debug(ar->hw->wiphy, "garbage collector scans queue:%d\n",
-			    i);
-		ar9170_dump_txqueue(ar, &ar->tx_pending[i]);
-		ar9170_dump_txqueue(ar, &ar->tx_status[i]);
-#endif /* AR9170_QUEUE_DEBUG */
-
-		ar9170_recycle_expired(ar, &ar->tx_status[i], &waste);
-		ar9170_recycle_expired(ar, &ar->tx_pending[i], &waste);
-		skb_queue_purge(&waste);
-
-		if (!skb_queue_empty(&ar->tx_status[i]) ||
-		    !skb_queue_empty(&ar->tx_pending[i]))
-			resched = true;
-	}
-
-	if (!resched)
-		return;
-
-	ieee80211_queue_delayed_work(ar->hw,
-				     &ar->tx_janitor,
-				     msecs_to_jiffies(AR9170_JANITOR_DELAY));
-}
-
-void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
-{
-	struct ar9170_cmd_response *cmd = (void *) buf;
-
-	if ((cmd->type & 0xc0) != 0xc0) {
-		ar->callback_cmd(ar, len, buf);
-		return;
-	}
-
-	/* hardware event handlers */
-	switch (cmd->type) {
-	case 0xc1: {
-		/*
-		 * TX status notification:
-		 * bytes: 0c c1 XX YY M1 M2 M3 M4 M5 M6 R4 R3 R2 R1 S2 S1
-		 *
-		 * XX always 81
-		 * YY always 00
-		 * M1-M6 is the MAC address
-		 * R1-R4 is the transmit rate
-		 * S1-S2 is the transmit status
-		 */
-
-		struct sk_buff *skb;
-		u32 phy = le32_to_cpu(cmd->tx_status.rate);
-		u32 q = (phy & AR9170_TX_PHY_QOS_MASK) >>
-			AR9170_TX_PHY_QOS_SHIFT;
-#ifdef AR9170_QUEUE_DEBUG
-		wiphy_debug(ar->hw->wiphy,
-			    "recv tx_status for %pm, p:%08x, q:%d\n",
-			    cmd->tx_status.dst, phy, q);
-#endif /* AR9170_QUEUE_DEBUG */
-
-		skb = ar9170_get_queued_skb(ar, cmd->tx_status.dst,
-					    &ar->tx_status[q],
-					    AR9170_TX_INVALID_RATE);
-		if (unlikely(!skb))
-			return ;
-
-		ar9170_tx_status(ar, skb, le16_to_cpu(cmd->tx_status.status));
-		break;
-		}
-
-	case 0xc0:
-		/*
-		 * pre-TBTT event
-		 */
-		if (ar->vif && ar->vif->type == NL80211_IFTYPE_AP)
-			ieee80211_queue_work(ar->hw, &ar->beacon_work);
-		break;
-
-	case 0xc2:
-		/*
-		 * (IBSS) beacon send notification
-		 * bytes: 04 c2 XX YY B4 B3 B2 B1
-		 *
-		 * XX always 80
-		 * YY always 00
-		 * B1-B4 "should" be the number of send out beacons.
-		 */
-		break;
-
-	case 0xc3:
-		/* End of Atim Window */
-		break;
-
-	case 0xc4:
-		/* BlockACK bitmap */
-		break;
-
-	case 0xc5:
-		/* BlockACK events */
-		break;
-
-	case 0xc6:
-		/* Watchdog Interrupt */
-		break;
-
-	case 0xc9:
-		/* retransmission issue / SIFS/EIFS collision ?! */
-		break;
-
-	/* firmware debug */
-	case 0xca:
-		printk(KERN_DEBUG "ar9170 FW: %.*s\n", len - 4,
-				(char *)buf + 4);
-		break;
-	case 0xcb:
-		len -= 4;
-
-		switch (len) {
-		case 1:
-			printk(KERN_DEBUG "ar9170 FW: u8: %#.2x\n",
-				*((char *)buf + 4));
-			break;
-		case 2:
-			printk(KERN_DEBUG "ar9170 FW: u8: %#.4x\n",
-				le16_to_cpup((__le16 *)((char *)buf + 4)));
-			break;
-		case 4:
-			printk(KERN_DEBUG "ar9170 FW: u8: %#.8x\n",
-				le32_to_cpup((__le32 *)((char *)buf + 4)));
-			break;
-		case 8:
-			printk(KERN_DEBUG "ar9170 FW: u8: %#.16lx\n",
-				(unsigned long)le64_to_cpup(
-						(__le64 *)((char *)buf + 4)));
-			break;
-		}
-		break;
-	case 0xcc:
-		print_hex_dump_bytes("ar9170 FW:", DUMP_PREFIX_NONE,
-				     (char *)buf + 4, len - 4);
-		break;
-
-	default:
-		pr_info("received unhandled event %x\n", cmd->type);
-		print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE, buf, len);
-		break;
-	}
-}
-
-static void ar9170_rx_reset_rx_mpdu(struct ar9170 *ar)
-{
-	memset(&ar->rx_mpdu.plcp, 0, sizeof(struct ar9170_rx_head));
-	ar->rx_mpdu.has_plcp = false;
-}
-
-int ar9170_nag_limiter(struct ar9170 *ar)
-{
-	bool print_message;
-
-	/*
-	 * we expect all sorts of errors in promiscuous mode.
-	 * don't bother with it, it's OK!
-	 */
-	if (ar->sniffer_enabled)
-		return false;
-
-	/*
-	 * only go for frequent errors! The hardware tends to
-	 * do some stupid thing once in a while under load, in
-	 * noisy environments or just for fun!
-	 */
-	if (time_before(jiffies, ar->bad_hw_nagger) && net_ratelimit())
-		print_message = true;
-	else
-		print_message = false;
-
-	/* reset threshold for "once in a while" */
-	ar->bad_hw_nagger = jiffies + HZ / 4;
-	return print_message;
-}
-
-static int ar9170_rx_mac_status(struct ar9170 *ar,
-				struct ar9170_rx_head *head,
-				struct ar9170_rx_macstatus *mac,
-				struct ieee80211_rx_status *status)
-{
-	u8 error, decrypt;
-
-	BUILD_BUG_ON(sizeof(struct ar9170_rx_head) != 12);
-	BUILD_BUG_ON(sizeof(struct ar9170_rx_macstatus) != 4);
-
-	error = mac->error;
-	if (error & AR9170_RX_ERROR_MMIC) {
-		status->flag |= RX_FLAG_MMIC_ERROR;
-		error &= ~AR9170_RX_ERROR_MMIC;
-	}
-
-	if (error & AR9170_RX_ERROR_PLCP) {
-		status->flag |= RX_FLAG_FAILED_PLCP_CRC;
-		error &= ~AR9170_RX_ERROR_PLCP;
-
-		if (!(ar->filter_state & FIF_PLCPFAIL))
-			return -EINVAL;
-	}
-
-	if (error & AR9170_RX_ERROR_FCS) {
-		status->flag |= RX_FLAG_FAILED_FCS_CRC;
-		error &= ~AR9170_RX_ERROR_FCS;
-
-		if (!(ar->filter_state & FIF_FCSFAIL))
-			return -EINVAL;
-	}
-
-	decrypt = ar9170_get_decrypt_type(mac);
-	if (!(decrypt & AR9170_RX_ENC_SOFTWARE) &&
-	    decrypt != AR9170_ENC_ALG_NONE)
-		status->flag |= RX_FLAG_DECRYPTED;
-
-	/* ignore wrong RA errors */
-	error &= ~AR9170_RX_ERROR_WRONG_RA;
-
-	if (error & AR9170_RX_ERROR_DECRYPT) {
-		error &= ~AR9170_RX_ERROR_DECRYPT;
-		/*
-		 * Rx decryption is done in place,
-		 * the original data is lost anyway.
-		 */
-
-		return -EINVAL;
-	}
-
-	/* drop any other error frames */
-	if (unlikely(error)) {
-		/* TODO: update netdevice's RX dropped/errors statistics */
-
-		if (ar9170_nag_limiter(ar))
-			wiphy_debug(ar->hw->wiphy,
-				    "received frame with suspicious error code (%#x).\n",
-				    error);
-
-		return -EINVAL;
-	}
-
-	status->band = ar->channel->band;
-	status->freq = ar->channel->center_freq;
-
-	switch (mac->status & AR9170_RX_STATUS_MODULATION_MASK) {
-	case AR9170_RX_STATUS_MODULATION_CCK:
-		if (mac->status & AR9170_RX_STATUS_SHORT_PREAMBLE)
-			status->flag |= RX_FLAG_SHORTPRE;
-		switch (head->plcp[0]) {
-		case 0x0a:
-			status->rate_idx = 0;
-			break;
-		case 0x14:
-			status->rate_idx = 1;
-			break;
-		case 0x37:
-			status->rate_idx = 2;
-			break;
-		case 0x6e:
-			status->rate_idx = 3;
-			break;
-		default:
-			if (ar9170_nag_limiter(ar))
-				wiphy_err(ar->hw->wiphy,
-					  "invalid plcp cck rate (%x).\n",
-					  head->plcp[0]);
-			return -EINVAL;
-		}
-		break;
-
-	case AR9170_RX_STATUS_MODULATION_DUPOFDM:
-	case AR9170_RX_STATUS_MODULATION_OFDM:
-		switch (head->plcp[0] & 0xf) {
-		case 0xb:
-			status->rate_idx = 0;
-			break;
-		case 0xf:
-			status->rate_idx = 1;
-			break;
-		case 0xa:
-			status->rate_idx = 2;
-			break;
-		case 0xe:
-			status->rate_idx = 3;
-			break;
-		case 0x9:
-			status->rate_idx = 4;
-			break;
-		case 0xd:
-			status->rate_idx = 5;
-			break;
-		case 0x8:
-			status->rate_idx = 6;
-			break;
-		case 0xc:
-			status->rate_idx = 7;
-			break;
-		default:
-			if (ar9170_nag_limiter(ar))
-				wiphy_err(ar->hw->wiphy,
-					  "invalid plcp ofdm rate (%x).\n",
-					  head->plcp[0]);
-			return -EINVAL;
-		}
-		if (status->band == IEEE80211_BAND_2GHZ)
-			status->rate_idx += 4;
-		break;
-
-	case AR9170_RX_STATUS_MODULATION_HT:
-		if (head->plcp[3] & 0x80)
-			status->flag |= RX_FLAG_40MHZ;
-		if (head->plcp[6] & 0x80)
-			status->flag |= RX_FLAG_SHORT_GI;
-
-		status->rate_idx = clamp(0, 75, head->plcp[6] & 0x7f);
-		status->flag |= RX_FLAG_HT;
-		break;
-
-	default:
-		if (ar9170_nag_limiter(ar))
-			wiphy_err(ar->hw->wiphy, "invalid modulation\n");
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static void ar9170_rx_phy_status(struct ar9170 *ar,
-				 struct ar9170_rx_phystatus *phy,
-				 struct ieee80211_rx_status *status)
-{
-	int i;
-
-	BUILD_BUG_ON(sizeof(struct ar9170_rx_phystatus) != 20);
-
-	for (i = 0; i < 3; i++)
-		if (phy->rssi[i] != 0x80)
-			status->antenna |= BIT(i);
-
-	/* post-process RSSI */
-	for (i = 0; i < 7; i++)
-		if (phy->rssi[i] & 0x80)
-			phy->rssi[i] = ((phy->rssi[i] & 0x7f) + 1) & 0x7f;
-
-	/* TODO: we could do something with phy_errors */
-	status->signal = ar->noise[0] + phy->rssi_combined;
-}
-
-static struct sk_buff *ar9170_rx_copy_data(u8 *buf, int len)
-{
-	struct sk_buff *skb;
-	int reserved = 0;
-	struct ieee80211_hdr *hdr = (void *) buf;
-
-	if (ieee80211_is_data_qos(hdr->frame_control)) {
-		u8 *qc = ieee80211_get_qos_ctl(hdr);
-		reserved += NET_IP_ALIGN;
-
-		if (*qc & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)
-			reserved += NET_IP_ALIGN;
-	}
-
-	if (ieee80211_has_a4(hdr->frame_control))
-		reserved += NET_IP_ALIGN;
-
-	reserved = 32 + (reserved & NET_IP_ALIGN);
-
-	skb = dev_alloc_skb(len + reserved);
-	if (likely(skb)) {
-		skb_reserve(skb, reserved);
-		memcpy(skb_put(skb, len), buf, len);
-	}
-
-	return skb;
-}
-
-/*
- * If the frame alignment is right (or the kernel has
- * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there
- * is only a single MPDU in the USB frame, then we could
- * submit to mac80211 the SKB directly. However, since
- * there may be multiple packets in one SKB in stream
- * mode, and we need to observe the proper ordering,
- * this is non-trivial.
- */
-
-static void ar9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len)
-{
-	struct ar9170_rx_head *head;
-	struct ar9170_rx_macstatus *mac;
-	struct ar9170_rx_phystatus *phy = NULL;
-	struct ieee80211_rx_status status;
-	struct sk_buff *skb;
-	int mpdu_len;
-
-	if (unlikely(!IS_STARTED(ar) || len < (sizeof(*mac))))
-		return ;
-
-	/* Received MPDU */
-	mpdu_len = len - sizeof(*mac);
-
-	mac = (void *)(buf + mpdu_len);
-	if (unlikely(mac->error & AR9170_RX_ERROR_FATAL)) {
-		/* this frame is too damaged and can't be used - drop it */
-
-		return ;
-	}
-
-	switch (mac->status & AR9170_RX_STATUS_MPDU_MASK) {
-	case AR9170_RX_STATUS_MPDU_FIRST:
-		/* first mpdu packet has the plcp header */
-		if (likely(mpdu_len >= sizeof(struct ar9170_rx_head))) {
-			head = (void *) buf;
-			memcpy(&ar->rx_mpdu.plcp, (void *) buf,
-			       sizeof(struct ar9170_rx_head));
-
-			mpdu_len -= sizeof(struct ar9170_rx_head);
-			buf += sizeof(struct ar9170_rx_head);
-			ar->rx_mpdu.has_plcp = true;
-		} else {
-			if (ar9170_nag_limiter(ar))
-				wiphy_err(ar->hw->wiphy,
-					  "plcp info is clipped.\n");
-			return ;
-		}
-		break;
-
-	case AR9170_RX_STATUS_MPDU_LAST:
-		/* last mpdu has a extra tail with phy status information */
-
-		if (likely(mpdu_len >= sizeof(struct ar9170_rx_phystatus))) {
-			mpdu_len -= sizeof(struct ar9170_rx_phystatus);
-			phy = (void *)(buf + mpdu_len);
-		} else {
-			if (ar9170_nag_limiter(ar))
-				wiphy_err(ar->hw->wiphy,
-					  "frame tail is clipped.\n");
-			return ;
-		}
-
-	case AR9170_RX_STATUS_MPDU_MIDDLE:
-		/* middle mpdus are just data */
-		if (unlikely(!ar->rx_mpdu.has_plcp)) {
-			if (!ar9170_nag_limiter(ar))
-				return ;
-
-			wiphy_err(ar->hw->wiphy,
-				  "rx stream did not start with a first_mpdu frame tag.\n");
-
-			return ;
-		}
-
-		head = &ar->rx_mpdu.plcp;
-		break;
-
-	case AR9170_RX_STATUS_MPDU_SINGLE:
-		/* single mpdu - has plcp (head) and phy status (tail) */
-		head = (void *) buf;
-
-		mpdu_len -= sizeof(struct ar9170_rx_head);
-		mpdu_len -= sizeof(struct ar9170_rx_phystatus);
-
-		buf += sizeof(struct ar9170_rx_head);
-		phy = (void *)(buf + mpdu_len);
-		break;
-
-	default:
-		BUG_ON(1);
-		break;
-	}
-
-	if (unlikely(mpdu_len < FCS_LEN))
-		return ;
-
-	memset(&status, 0, sizeof(status));
-	if (unlikely(ar9170_rx_mac_status(ar, head, mac, &status)))
-		return ;
-
-	if (phy)
-		ar9170_rx_phy_status(ar, phy, &status);
-
-	skb = ar9170_rx_copy_data(buf, mpdu_len);
-	if (likely(skb)) {
-		memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
-		ieee80211_rx_irqsafe(ar->hw, skb);
-	}
-}
-
-void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb)
-{
-	unsigned int i, tlen, resplen, wlen = 0, clen = 0;
-	u8 *tbuf, *respbuf;
-
-	tbuf = skb->data;
-	tlen = skb->len;
-
-	while (tlen >= 4) {
-		clen = tbuf[1] << 8 | tbuf[0];
-		wlen = ALIGN(clen, 4);
-
-		/* check if this is stream has a valid tag.*/
-		if (tbuf[2] != 0 || tbuf[3] != 0x4e) {
-			/*
-			 * TODO: handle the highly unlikely event that the
-			 * corrupted stream has the TAG at the right position.
-			 */
-
-			/* check if the frame can be repaired. */
-			if (!ar->rx_failover_missing) {
-				/* this is no "short read". */
-				if (ar9170_nag_limiter(ar)) {
-					wiphy_err(ar->hw->wiphy,
-						  "missing tag!\n");
-					goto err_telluser;
-				} else
-					goto err_silent;
-			}
-
-			if (ar->rx_failover_missing > tlen) {
-				if (ar9170_nag_limiter(ar)) {
-					wiphy_err(ar->hw->wiphy,
-						  "possible multi stream corruption!\n");
-					goto err_telluser;
-				} else
-					goto err_silent;
-			}
-
-			memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen);
-			ar->rx_failover_missing -= tlen;
-
-			if (ar->rx_failover_missing <= 0) {
-				/*
-				 * nested ar9170_rx call!
-				 * termination is guranteed, even when the
-				 * combined frame also have a element with
-				 * a bad tag.
-				 */
-
-				ar->rx_failover_missing = 0;
-				ar9170_rx(ar, ar->rx_failover);
-
-				skb_reset_tail_pointer(ar->rx_failover);
-				skb_trim(ar->rx_failover, 0);
-			}
-
-			return ;
-		}
-
-		/* check if stream is clipped */
-		if (wlen > tlen - 4) {
-			if (ar->rx_failover_missing) {
-				/* TODO: handle double stream corruption. */
-				if (ar9170_nag_limiter(ar)) {
-					wiphy_err(ar->hw->wiphy,
-						  "double rx stream corruption!\n");
-					goto err_telluser;
-				} else
-					goto err_silent;
-			}
-
-			/*
-			 * save incomplete data set.
-			 * the firmware will resend the missing bits when
-			 * the rx - descriptor comes round again.
-			 */
-
-			memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen);
-			ar->rx_failover_missing = clen - tlen;
-			return ;
-		}
-		resplen = clen;
-		respbuf = tbuf + 4;
-		tbuf += wlen + 4;
-		tlen -= wlen + 4;
-
-		i = 0;
-
-		/* weird thing, but this is the same in the original driver */
-		while (resplen > 2 && i < 12 &&
-		       respbuf[0] == 0xff && respbuf[1] == 0xff) {
-			i += 2;
-			resplen -= 2;
-			respbuf += 2;
-		}
-
-		if (resplen < 4)
-			continue;
-
-		/* found the 6 * 0xffff marker? */
-		if (i == 12)
-			ar9170_handle_command_response(ar, respbuf, resplen);
-		else
-			ar9170_handle_mpdu(ar, respbuf, clen);
-	}
-
-	if (tlen) {
-		if (net_ratelimit())
-			wiphy_err(ar->hw->wiphy,
-				  "%d bytes of unprocessed data left in rx stream!\n",
-				  tlen);
-
-		goto err_telluser;
-	}
-
-	return ;
-
-err_telluser:
-	wiphy_err(ar->hw->wiphy,
-		  "damaged RX stream data [want:%d, data:%d, rx:%d, pending:%d ]\n",
-		  clen, wlen, tlen, ar->rx_failover_missing);
-
-	if (ar->rx_failover_missing)
-		print_hex_dump_bytes("rxbuf:", DUMP_PREFIX_OFFSET,
-				     ar->rx_failover->data,
-				     ar->rx_failover->len);
-
-	print_hex_dump_bytes("stream:", DUMP_PREFIX_OFFSET,
-			     skb->data, skb->len);
-
-	wiphy_err(ar->hw->wiphy,
-		  "If you see this message frequently, please check your hardware and cables.\n");
-
-err_silent:
-	if (ar->rx_failover_missing) {
-		skb_reset_tail_pointer(ar->rx_failover);
-		skb_trim(ar->rx_failover, 0);
-		ar->rx_failover_missing = 0;
-	}
-}
-
-#define AR9170_FILL_QUEUE(queue, ai_fs, cwmin, cwmax, _txop)		\
-do {									\
-	queue.aifs = ai_fs;						\
-	queue.cw_min = cwmin;						\
-	queue.cw_max = cwmax;						\
-	queue.txop = _txop;						\
-} while (0)
-
-static int ar9170_op_start(struct ieee80211_hw *hw)
-{
-	struct ar9170 *ar = hw->priv;
-	int err, i;
-
-	mutex_lock(&ar->mutex);
-
-	/* reinitialize queues statistics */
-	memset(&ar->tx_stats, 0, sizeof(ar->tx_stats));
-	for (i = 0; i < __AR9170_NUM_TXQ; i++)
-		ar->tx_stats[i].limit = AR9170_TXQ_DEPTH;
-
-	/* reset QoS defaults */
-	AR9170_FILL_QUEUE(ar->edcf[0], 3, 15, 1023,  0); /* BEST EFFORT*/
-	AR9170_FILL_QUEUE(ar->edcf[1], 7, 15, 1023,  0); /* BACKGROUND */
-	AR9170_FILL_QUEUE(ar->edcf[2], 2, 7,    15, 94); /* VIDEO */
-	AR9170_FILL_QUEUE(ar->edcf[3], 2, 3,     7, 47); /* VOICE */
-	AR9170_FILL_QUEUE(ar->edcf[4], 2, 3,     7,  0); /* SPECIAL */
-
-	/* set sane AMPDU defaults */
-	ar->global_ampdu_density = 6;
-	ar->global_ampdu_factor = 3;
-
-	ar->bad_hw_nagger = jiffies;
-
-	err = ar->open(ar);
-	if (err)
-		goto out;
-
-	err = ar9170_init_mac(ar);
-	if (err)
-		goto out;
-
-	err = ar9170_set_qos(ar);
-	if (err)
-		goto out;
-
-	err = ar9170_init_phy(ar, IEEE80211_BAND_2GHZ);
-	if (err)
-		goto out;
-
-	err = ar9170_init_rf(ar);
-	if (err)
-		goto out;
-
-	/* start DMA */
-	err = ar9170_write_reg(ar, 0x1c3d30, 0x100);
-	if (err)
-		goto out;
-
-	ar->state = AR9170_STARTED;
-
-out:
-	mutex_unlock(&ar->mutex);
-	return err;
-}
-
-static void ar9170_op_stop(struct ieee80211_hw *hw)
-{
-	struct ar9170 *ar = hw->priv;
-	unsigned int i;
-
-	if (IS_STARTED(ar))
-		ar->state = AR9170_IDLE;
-
-	cancel_delayed_work_sync(&ar->tx_janitor);
-#ifdef CONFIG_AR9170_LEDS
-	cancel_delayed_work_sync(&ar->led_work);
-#endif
-	cancel_work_sync(&ar->beacon_work);
-
-	mutex_lock(&ar->mutex);
-
-	if (IS_ACCEPTING_CMD(ar)) {
-		ar9170_set_leds_state(ar, 0);
-
-		/* stop DMA */
-		ar9170_write_reg(ar, 0x1c3d30, 0);
-		ar->stop(ar);
-	}
-
-	for (i = 0; i < __AR9170_NUM_TXQ; i++) {
-		skb_queue_purge(&ar->tx_pending[i]);
-		skb_queue_purge(&ar->tx_status[i]);
-	}
-
-	mutex_unlock(&ar->mutex);
-}
-
-static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
-{
-	struct ieee80211_hdr *hdr;
-	struct ar9170_tx_control *txc;
-	struct ieee80211_tx_info *info;
-	struct ieee80211_tx_rate *txrate;
-	struct ar9170_tx_info *arinfo;
-	unsigned int queue = skb_get_queue_mapping(skb);
-	u16 keytype = 0;
-	u16 len, icv = 0;
-
-	BUILD_BUG_ON(sizeof(*arinfo) > sizeof(info->rate_driver_data));
-
-	hdr = (void *)skb->data;
-	info = IEEE80211_SKB_CB(skb);
-	len = skb->len;
-
-	txc = (void *)skb_push(skb, sizeof(*txc));
-
-	if (info->control.hw_key) {
-		icv = info->control.hw_key->icv_len;
-
-		switch (info->control.hw_key->cipher) {
-		case WLAN_CIPHER_SUITE_WEP40:
-		case WLAN_CIPHER_SUITE_WEP104:
-		case WLAN_CIPHER_SUITE_TKIP:
-			keytype = AR9170_TX_MAC_ENCR_RC4;
-			break;
-		case WLAN_CIPHER_SUITE_CCMP:
-			keytype = AR9170_TX_MAC_ENCR_AES;
-			break;
-		default:
-			WARN_ON(1);
-			goto err_out;
-		}
-	}
-
-	/* Length */
-	txc->length = cpu_to_le16(len + icv + 4);
-
-	txc->mac_control = cpu_to_le16(AR9170_TX_MAC_HW_DURATION |
-				       AR9170_TX_MAC_BACKOFF);
-	txc->mac_control |= cpu_to_le16(ar9170_qos_hwmap[queue] <<
-					AR9170_TX_MAC_QOS_SHIFT);
-	txc->mac_control |= cpu_to_le16(keytype);
-	txc->phy_control = cpu_to_le32(0);
-
-	if (info->flags & IEEE80211_TX_CTL_NO_ACK)
-		txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_NO_ACK);
-
-	txrate = &info->control.rates[0];
-	if (txrate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
-		txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_CTS);
-	else if (txrate->flags & IEEE80211_TX_RC_USE_RTS_CTS)
-		txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_RTS);
-
-	arinfo = (void *)info->rate_driver_data;
-	arinfo->timeout = jiffies + msecs_to_jiffies(AR9170_QUEUE_TIMEOUT);
-
-	if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
-	     (is_valid_ether_addr(ieee80211_get_DA(hdr)))) {
-		/*
-		 * WARNING:
-		 * Putting the QoS queue bits into an unexplored territory is
-		 * certainly not elegant.
-		 *
-		 * In my defense: This idea provides a reasonable way to
-		 * smuggle valuable information to the tx_status callback.
-		 * Also, the idea behind this bit-abuse came straight from
-		 * the original driver code.
-		 */
-
-		txc->phy_control |=
-			cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT);
-
-		txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE);
-	}
-
-	return 0;
-
-err_out:
-	skb_pull(skb, sizeof(*txc));
-	return -EINVAL;
-}
-
-static void ar9170_tx_prepare_phy(struct ar9170 *ar, struct sk_buff *skb)
-{
-	struct ar9170_tx_control *txc;
-	struct ieee80211_tx_info *info;
-	struct ieee80211_rate *rate = NULL;
-	struct ieee80211_tx_rate *txrate;
-	u32 power, chains;
-
-	txc = (void *) skb->data;
-	info = IEEE80211_SKB_CB(skb);
-	txrate = &info->control.rates[0];
-
-	if (txrate->flags & IEEE80211_TX_RC_GREEN_FIELD)
-		txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_GREENFIELD);
-
-	if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
-		txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_SHORT_PREAMBLE);
-
-	if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
-		txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_BW_40MHZ);
-	/* this works because 40 MHz is 2 and dup is 3 */
-	if (txrate->flags & IEEE80211_TX_RC_DUP_DATA)
-		txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_BW_40MHZ_DUP);
-
-	if (txrate->flags & IEEE80211_TX_RC_SHORT_GI)
-		txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_SHORT_GI);
-
-	if (txrate->flags & IEEE80211_TX_RC_MCS) {
-		u32 r = txrate->idx;
-		u8 *txpower;
-
-		/* heavy clip control */
-		txc->phy_control |= cpu_to_le32((r & 0x7) << 7);
-
-		r <<= AR9170_TX_PHY_MCS_SHIFT;
-		BUG_ON(r & ~AR9170_TX_PHY_MCS_MASK);
-
-		txc->phy_control |= cpu_to_le32(r & AR9170_TX_PHY_MCS_MASK);
-		txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_MOD_HT);
-
-		if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) {
-			if (info->band == IEEE80211_BAND_5GHZ)
-				txpower = ar->power_5G_ht40;
-			else
-				txpower = ar->power_2G_ht40;
-		} else {
-			if (info->band == IEEE80211_BAND_5GHZ)
-				txpower = ar->power_5G_ht20;
-			else
-				txpower = ar->power_2G_ht20;
-		}
-
-		power = txpower[(txrate->idx) & 7];
-	} else {
-		u8 *txpower;
-		u32 mod;
-		u32 phyrate;
-		u8 idx = txrate->idx;
-
-		if (info->band != IEEE80211_BAND_2GHZ) {
-			idx += 4;
-			txpower = ar->power_5G_leg;
-			mod = AR9170_TX_PHY_MOD_OFDM;
-		} else {
-			if (idx < 4) {
-				txpower = ar->power_2G_cck;
-				mod = AR9170_TX_PHY_MOD_CCK;
-			} else {
-				mod = AR9170_TX_PHY_MOD_OFDM;
-				txpower = ar->power_2G_ofdm;
-			}
-		}
-
-		rate = &__ar9170_ratetable[idx];
-
-		phyrate = rate->hw_value & 0xF;
-		power = txpower[(rate->hw_value & 0x30) >> 4];
-		phyrate <<= AR9170_TX_PHY_MCS_SHIFT;
-
-		txc->phy_control |= cpu_to_le32(mod);
-		txc->phy_control |= cpu_to_le32(phyrate);
-	}
-
-	power <<= AR9170_TX_PHY_TX_PWR_SHIFT;
-	power &= AR9170_TX_PHY_TX_PWR_MASK;
-	txc->phy_control |= cpu_to_le32(power);
-
-	/* set TX chains */
-	if (ar->eeprom.tx_mask == 1) {
-		chains = AR9170_TX_PHY_TXCHAIN_1;
-	} else {
-		chains = AR9170_TX_PHY_TXCHAIN_2;
-
-		/* >= 36M legacy OFDM - use only one chain */
-		if (rate && rate->bitrate >= 360)
-			chains = AR9170_TX_PHY_TXCHAIN_1;
-	}
-	txc->phy_control |= cpu_to_le32(chains << AR9170_TX_PHY_TXCHAIN_SHIFT);
-}
-
-static void ar9170_tx(struct ar9170 *ar)
-{
-	struct sk_buff *skb;
-	unsigned long flags;
-	struct ieee80211_tx_info *info;
-	struct ar9170_tx_info *arinfo;
-	unsigned int i, frames, frames_failed, remaining_space;
-	int err;
-	bool schedule_garbagecollector = false;
-
-	BUILD_BUG_ON(sizeof(*arinfo) > sizeof(info->rate_driver_data));
-
-	if (unlikely(!IS_STARTED(ar)))
-		return ;
-
-	remaining_space = AR9170_TX_MAX_PENDING;
-
-	for (i = 0; i < __AR9170_NUM_TXQ; i++) {
-		spin_lock_irqsave(&ar->tx_stats_lock, flags);
-		frames = min(ar->tx_stats[i].limit - ar->tx_stats[i].len,
-			     skb_queue_len(&ar->tx_pending[i]));
-
-		if (remaining_space < frames) {
-#ifdef AR9170_QUEUE_DEBUG
-			wiphy_debug(ar->hw->wiphy,
-				    "tx quota reached queue:%d, "
-				    "remaining slots:%d, needed:%d\n",
-				    i, remaining_space, frames);
-#endif /* AR9170_QUEUE_DEBUG */
-			frames = remaining_space;
-		}
-
-		ar->tx_stats[i].len += frames;
-		ar->tx_stats[i].count += frames;
-		if (ar->tx_stats[i].len >= ar->tx_stats[i].limit) {
-#ifdef AR9170_QUEUE_DEBUG
-			wiphy_debug(ar->hw->wiphy, "queue %d full\n", i);
-			wiphy_debug(ar->hw->wiphy, "stuck frames: ===>\n");
-			ar9170_dump_txqueue(ar, &ar->tx_pending[i]);
-			ar9170_dump_txqueue(ar, &ar->tx_status[i]);
-#endif /* AR9170_QUEUE_DEBUG */
-
-#ifdef AR9170_QUEUE_STOP_DEBUG
-			wiphy_debug(ar->hw->wiphy, "stop queue %d\n", i);
-			__ar9170_dump_txstats(ar);
-#endif /* AR9170_QUEUE_STOP_DEBUG */
-			ieee80211_stop_queue(ar->hw, i);
-		}
-
-		spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
-
-		if (!frames)
-			continue;
-
-		frames_failed = 0;
-		while (frames) {
-			skb = skb_dequeue(&ar->tx_pending[i]);
-			if (unlikely(!skb)) {
-				frames_failed += frames;
-				frames = 0;
-				break;
-			}
-
-			info = IEEE80211_SKB_CB(skb);
-			arinfo = (void *) info->rate_driver_data;
-
-			/* TODO: cancel stuck frames */
-			arinfo->timeout = jiffies +
-					  msecs_to_jiffies(AR9170_TX_TIMEOUT);
-
-#ifdef AR9170_QUEUE_DEBUG
-			wiphy_debug(ar->hw->wiphy, "send frame q:%d =>\n", i);
-			ar9170_print_txheader(ar, skb);
-#endif /* AR9170_QUEUE_DEBUG */
-
-			err = ar->tx(ar, skb);
-			if (unlikely(err)) {
-				frames_failed++;
-				dev_kfree_skb_any(skb);
-			} else {
-				remaining_space--;
-				schedule_garbagecollector = true;
-			}
-
-			frames--;
-		}
-
-#ifdef AR9170_QUEUE_DEBUG
-		wiphy_debug(ar->hw->wiphy,
-			    "ar9170_tx report for queue %d\n", i);
-
-		wiphy_debug(ar->hw->wiphy,
-			    "unprocessed pending frames left:\n");
-		ar9170_dump_txqueue(ar, &ar->tx_pending[i]);
-#endif /* AR9170_QUEUE_DEBUG */
-
-		if (unlikely(frames_failed)) {
-#ifdef AR9170_QUEUE_DEBUG
-			wiphy_debug(ar->hw->wiphy,
-				    "frames failed %d =>\n", frames_failed);
-#endif /* AR9170_QUEUE_DEBUG */
-
-			spin_lock_irqsave(&ar->tx_stats_lock, flags);
-			ar->tx_stats[i].len -= frames_failed;
-			ar->tx_stats[i].count -= frames_failed;
-#ifdef AR9170_QUEUE_STOP_DEBUG
-			wiphy_debug(ar->hw->wiphy, "wake queue %d\n", i);
-			__ar9170_dump_txstats(ar);
-#endif /* AR9170_QUEUE_STOP_DEBUG */
-			ieee80211_wake_queue(ar->hw, i);
-			spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
-		}
-	}
-
-	if (!schedule_garbagecollector)
-		return;
-
-	ieee80211_queue_delayed_work(ar->hw,
-				     &ar->tx_janitor,
-				     msecs_to_jiffies(AR9170_JANITOR_DELAY));
-}
-
-void ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
-{
-	struct ar9170 *ar = hw->priv;
-	struct ieee80211_tx_info *info;
-	unsigned int queue;
-
-	if (unlikely(!IS_STARTED(ar)))
-		goto err_free;
-
-	if (unlikely(ar9170_tx_prepare(ar, skb)))
-		goto err_free;
-
-	queue = skb_get_queue_mapping(skb);
-	info = IEEE80211_SKB_CB(skb);
-	ar9170_tx_prepare_phy(ar, skb);
-	skb_queue_tail(&ar->tx_pending[queue], skb);
-
-	ar9170_tx(ar);
-	return;
-
-err_free:
-	dev_kfree_skb_any(skb);
-}
-
-static int ar9170_op_add_interface(struct ieee80211_hw *hw,
-				   struct ieee80211_vif *vif)
-{
-	struct ar9170 *ar = hw->priv;
-	struct ath_common *common = &ar->common;
-	int err = 0;
-
-	mutex_lock(&ar->mutex);
-
-	if (ar->vif) {
-		err = -EBUSY;
-		goto unlock;
-	}
-
-	ar->vif = vif;
-	memcpy(common->macaddr, vif->addr, ETH_ALEN);
-
-	if (modparam_nohwcrypt || (ar->vif->type != NL80211_IFTYPE_STATION)) {
-		ar->rx_software_decryption = true;
-		ar->disable_offload = true;
-	}
-
-	ar->cur_filter = 0;
-	err = ar9170_update_frame_filter(ar, AR9170_MAC_REG_FTF_DEFAULTS);
-	if (err)
-		goto unlock;
-
-	err = ar9170_set_operating_mode(ar);
-
-unlock:
-	mutex_unlock(&ar->mutex);
-	return err;
-}
-
-static void ar9170_op_remove_interface(struct ieee80211_hw *hw,
-				       struct ieee80211_vif *vif)
-{
-	struct ar9170 *ar = hw->priv;
-
-	mutex_lock(&ar->mutex);
-	ar->vif = NULL;
-	ar9170_update_frame_filter(ar, 0);
-	ar9170_set_beacon_timers(ar);
-	dev_kfree_skb(ar->beacon);
-	ar->beacon = NULL;
-	ar->sniffer_enabled = false;
-	ar->rx_software_decryption = false;
-	ar9170_set_operating_mode(ar);
-	mutex_unlock(&ar->mutex);
-}
-
-static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed)
-{
-	struct ar9170 *ar = hw->priv;
-	int err = 0;
-
-	mutex_lock(&ar->mutex);
-
-	if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) {
-		/* TODO */
-		err = 0;
-	}
-
-	if (changed & IEEE80211_CONF_CHANGE_PS) {
-		/* TODO */
-		err = 0;
-	}
-
-	if (changed & IEEE80211_CONF_CHANGE_POWER) {
-		/* TODO */
-		err = 0;
-	}
-
-	if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) {
-		/*
-		 * is it long_frame_max_tx_count or short_frame_max_tx_count?
-		 */
-
-		err = ar9170_set_hwretry_limit(ar,
-			ar->hw->conf.long_frame_max_tx_count);
-		if (err)
-			goto out;
-	}
-
-	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
-
-		/* adjust slot time for 5 GHz */
-		err = ar9170_set_slot_time(ar);
-		if (err)
-			goto out;
-
-		err = ar9170_set_dyn_sifs_ack(ar);
-		if (err)
-			goto out;
-
-		err = ar9170_set_channel(ar, hw->conf.channel,
-				AR9170_RFI_NONE,
-				nl80211_to_ar9170(hw->conf.channel_type));
-		if (err)
-			goto out;
-	}
-
-out:
-	mutex_unlock(&ar->mutex);
-	return err;
-}
-
-static u64 ar9170_op_prepare_multicast(struct ieee80211_hw *hw,
-				       struct netdev_hw_addr_list *mc_list)
-{
-	u64 mchash;
-	struct netdev_hw_addr *ha;
-
-	/* always get broadcast frames */
-	mchash = 1ULL << (0xff >> 2);
-
-	netdev_hw_addr_list_for_each(ha, mc_list)
-		mchash |= 1ULL << (ha->addr[5] >> 2);
-
-	return mchash;
-}
-
-static void ar9170_op_configure_filter(struct ieee80211_hw *hw,
-				       unsigned int changed_flags,
-				       unsigned int *new_flags,
-				       u64 multicast)
-{
-	struct ar9170 *ar = hw->priv;
-
-	if (unlikely(!IS_ACCEPTING_CMD(ar)))
-		return ;
-
-	mutex_lock(&ar->mutex);
-
-	/* mask supported flags */
-	*new_flags &= FIF_ALLMULTI | FIF_CONTROL | FIF_BCN_PRBRESP_PROMISC |
-		      FIF_PROMISC_IN_BSS | FIF_FCSFAIL | FIF_PLCPFAIL;
-	ar->filter_state = *new_flags;
-	/*
-	 * We can support more by setting the sniffer bit and
-	 * then checking the error flags, later.
-	 */
-
-	if (changed_flags & FIF_ALLMULTI && *new_flags & FIF_ALLMULTI)
-		multicast = ~0ULL;
-
-	if (multicast != ar->cur_mc_hash)
-		ar9170_update_multicast(ar, multicast);
-
-	if (changed_flags & FIF_CONTROL) {
-		u32 filter = AR9170_MAC_REG_FTF_PSPOLL |
-			     AR9170_MAC_REG_FTF_RTS |
-			     AR9170_MAC_REG_FTF_CTS |
-			     AR9170_MAC_REG_FTF_ACK |
-			     AR9170_MAC_REG_FTF_CFE |
-			     AR9170_MAC_REG_FTF_CFE_ACK;
-
-		if (*new_flags & FIF_CONTROL)
-			filter |= ar->cur_filter;
-		else
-			filter &= (~ar->cur_filter);
-
-		ar9170_update_frame_filter(ar, filter);
-	}
-
-	if (changed_flags & FIF_PROMISC_IN_BSS) {
-		ar->sniffer_enabled = ((*new_flags) & FIF_PROMISC_IN_BSS) != 0;
-		ar9170_set_operating_mode(ar);
-	}
-
-	mutex_unlock(&ar->mutex);
-}
-
-
-static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw,
-				       struct ieee80211_vif *vif,
-				       struct ieee80211_bss_conf *bss_conf,
-				       u32 changed)
-{
-	struct ar9170 *ar = hw->priv;
-	struct ath_common *common = &ar->common;
-	int err = 0;
-
-	mutex_lock(&ar->mutex);
-
-	if (changed & BSS_CHANGED_BSSID) {
-		memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
-		err = ar9170_set_operating_mode(ar);
-		if (err)
-			goto out;
-	}
-
-	if (changed & BSS_CHANGED_BEACON_ENABLED)
-		ar->enable_beacon = bss_conf->enable_beacon;
-
-	if (changed & BSS_CHANGED_BEACON) {
-		err = ar9170_update_beacon(ar);
-		if (err)
-			goto out;
-	}
-
-	if (changed & (BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_BEACON |
-		       BSS_CHANGED_BEACON_INT)) {
-		err = ar9170_set_beacon_timers(ar);
-		if (err)
-			goto out;
-	}
-
-	if (changed & BSS_CHANGED_ASSOC) {
-#ifndef CONFIG_AR9170_LEDS
-		/* enable assoc LED. */
-		err = ar9170_set_leds_state(ar, bss_conf->assoc ? 2 : 0);
-#endif /* CONFIG_AR9170_LEDS */
-	}
-
-	if (changed & BSS_CHANGED_HT) {
-		/* TODO */
-		err = 0;
-	}
-
-	if (changed & BSS_CHANGED_ERP_SLOT) {
-		err = ar9170_set_slot_time(ar);
-		if (err)
-			goto out;
-	}
-
-	if (changed & BSS_CHANGED_BASIC_RATES) {
-		err = ar9170_set_basic_rates(ar);
-		if (err)
-			goto out;
-	}
-
-out:
-	mutex_unlock(&ar->mutex);
-}
-
-static u64 ar9170_op_get_tsf(struct ieee80211_hw *hw)
-{
-	struct ar9170 *ar = hw->priv;
-	int err;
-	u64 tsf;
-#define NR 3
-	static const u32 addr[NR] = { AR9170_MAC_REG_TSF_H,
-				    AR9170_MAC_REG_TSF_L,
-				    AR9170_MAC_REG_TSF_H };
-	u32 val[NR];
-	int loops = 0;
-
-	mutex_lock(&ar->mutex);
-
-	while (loops++ < 10) {
-		err = ar9170_read_mreg(ar, NR, addr, val);
-		if (err || val[0] == val[2])
-			break;
-	}
-
-	mutex_unlock(&ar->mutex);
-
-	if (WARN_ON(err))
-		return 0;
-	tsf = val[0];
-	tsf = (tsf << 32) | val[1];
-	return tsf;
-#undef NR
-}
-
-static int ar9170_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
-			  struct ieee80211_vif *vif, struct ieee80211_sta *sta,
-			  struct ieee80211_key_conf *key)
-{
-	struct ar9170 *ar = hw->priv;
-	int err = 0, i;
-	u8 ktype;
-
-	if ((!ar->vif) || (ar->disable_offload))
-		return -EOPNOTSUPP;
-
-	switch (key->cipher) {
-	case WLAN_CIPHER_SUITE_WEP40:
-		ktype = AR9170_ENC_ALG_WEP64;
-		break;
-	case WLAN_CIPHER_SUITE_WEP104:
-		ktype = AR9170_ENC_ALG_WEP128;
-		break;
-	case WLAN_CIPHER_SUITE_TKIP:
-		ktype = AR9170_ENC_ALG_TKIP;
-		break;
-	case WLAN_CIPHER_SUITE_CCMP:
-		ktype = AR9170_ENC_ALG_AESCCMP;
-		break;
-	default:
-		return -EOPNOTSUPP;
-	}
-
-	mutex_lock(&ar->mutex);
-	if (cmd == SET_KEY) {
-		if (unlikely(!IS_STARTED(ar))) {
-			err = -EOPNOTSUPP;
-			goto out;
-		}
-
-		/* group keys need all-zeroes address */
-		if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
-			sta = NULL;
-
-		if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
-			for (i = 0; i < 64; i++)
-				if (!(ar->usedkeys & BIT(i)))
-					break;
-			if (i == 64) {
-				ar->rx_software_decryption = true;
-				ar9170_set_operating_mode(ar);
-				err = -ENOSPC;
-				goto out;
-			}
-		} else {
-			i = 64 + key->keyidx;
-		}
-
-		key->hw_key_idx = i;
-
-		err = ar9170_upload_key(ar, i, sta ? sta->addr : NULL, ktype, 0,
-					key->key, min_t(u8, 16, key->keylen));
-		if (err)
-			goto out;
-
-		if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
-			err = ar9170_upload_key(ar, i, sta ? sta->addr : NULL,
-						ktype, 1, key->key + 16, 16);
-			if (err)
-				goto out;
-
-			/*
-			 * hardware is not capable generating the MMIC
-			 * for fragmented frames!
-			 */
-			key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
-		}
-
-		if (i < 64)
-			ar->usedkeys |= BIT(i);
-
-		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
-	} else {
-		if (unlikely(!IS_STARTED(ar))) {
-			/* The device is gone... together with the key ;-) */
-			err = 0;
-			goto out;
-		}
-
-		err = ar9170_disable_key(ar, key->hw_key_idx);
-		if (err)
-			goto out;
-
-		if (key->hw_key_idx < 64) {
-			ar->usedkeys &= ~BIT(key->hw_key_idx);
-		} else {
-			err = ar9170_upload_key(ar, key->hw_key_idx, NULL,
-						AR9170_ENC_ALG_NONE, 0,
-						NULL, 0);
-			if (err)
-				goto out;
-
-			if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
-				err = ar9170_upload_key(ar, key->hw_key_idx,
-							NULL,
-							AR9170_ENC_ALG_NONE, 1,
-							NULL, 0);
-				if (err)
-					goto out;
-			}
-
-		}
-	}
-
-	ar9170_regwrite_begin(ar);
-	ar9170_regwrite(AR9170_MAC_REG_ROLL_CALL_TBL_L, ar->usedkeys);
-	ar9170_regwrite(AR9170_MAC_REG_ROLL_CALL_TBL_H, ar->usedkeys >> 32);
-	ar9170_regwrite_finish();
-	err = ar9170_regwrite_result();
-
-out:
-	mutex_unlock(&ar->mutex);
-
-	return err;
-}
-
-static int ar9170_get_stats(struct ieee80211_hw *hw,
-			    struct ieee80211_low_level_stats *stats)
-{
-	struct ar9170 *ar = hw->priv;
-	u32 val;
-	int err;
-
-	mutex_lock(&ar->mutex);
-	err = ar9170_read_reg(ar, AR9170_MAC_REG_TX_RETRY, &val);
-	ar->stats.dot11ACKFailureCount += val;
-
-	memcpy(stats, &ar->stats, sizeof(*stats));
-	mutex_unlock(&ar->mutex);
-
-	return 0;
-}
-
-static int ar9170_get_survey(struct ieee80211_hw *hw, int idx,
-				struct survey_info *survey)
-{
-	struct ar9170 *ar = hw->priv;
-	struct ieee80211_conf *conf = &hw->conf;
-
-	if (idx != 0)
-		return -ENOENT;
-
-	/* TODO: update noise value, e.g. call ar9170_set_channel */
-
-	survey->channel = conf->channel;
-	survey->filled = SURVEY_INFO_NOISE_DBM;
-	survey->noise = ar->noise[0];
-
-	return 0;
-}
-
-static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue,
-			  const struct ieee80211_tx_queue_params *param)
-{
-	struct ar9170 *ar = hw->priv;
-	int ret;
-
-	mutex_lock(&ar->mutex);
-	if (queue < __AR9170_NUM_TXQ) {
-		memcpy(&ar->edcf[ar9170_qos_hwmap[queue]],
-		       param, sizeof(*param));
-
-		ret = ar9170_set_qos(ar);
-	} else {
-		ret = -EINVAL;
-	}
-
-	mutex_unlock(&ar->mutex);
-	return ret;
-}
-
-static int ar9170_ampdu_action(struct ieee80211_hw *hw,
-			       struct ieee80211_vif *vif,
-			       enum ieee80211_ampdu_mlme_action action,
-			       struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-			       u8 buf_size)
-{
-	switch (action) {
-	case IEEE80211_AMPDU_RX_START:
-	case IEEE80211_AMPDU_RX_STOP:
-		/* Handled by firmware */
-		break;
-
-	default:
-		return -EOPNOTSUPP;
-	}
-
-	return 0;
-}
-
-static const struct ieee80211_ops ar9170_ops = {
-	.start			= ar9170_op_start,
-	.stop			= ar9170_op_stop,
-	.tx			= ar9170_op_tx,
-	.add_interface		= ar9170_op_add_interface,
-	.remove_interface	= ar9170_op_remove_interface,
-	.config			= ar9170_op_config,
-	.prepare_multicast	= ar9170_op_prepare_multicast,
-	.configure_filter	= ar9170_op_configure_filter,
-	.conf_tx		= ar9170_conf_tx,
-	.bss_info_changed	= ar9170_op_bss_info_changed,
-	.get_tsf		= ar9170_op_get_tsf,
-	.set_key		= ar9170_set_key,
-	.get_stats		= ar9170_get_stats,
-	.get_survey		= ar9170_get_survey,
-	.ampdu_action		= ar9170_ampdu_action,
-};
-
-void *ar9170_alloc(size_t priv_size)
-{
-	struct ieee80211_hw *hw;
-	struct ar9170 *ar;
-	struct sk_buff *skb;
-	int i;
-
-	/*
-	 * this buffer is used for rx stream reconstruction.
-	 * Under heavy load this device (or the transport layer?)
-	 * tends to split the streams into separate rx descriptors.
-	 */
-
-	skb = __dev_alloc_skb(AR9170_RX_STREAM_MAX_SIZE, GFP_KERNEL);
-	if (!skb)
-		goto err_nomem;
-
-	hw = ieee80211_alloc_hw(priv_size, &ar9170_ops);
-	if (!hw)
-		goto err_nomem;
-
-	ar = hw->priv;
-	ar->hw = hw;
-	ar->rx_failover = skb;
-
-	mutex_init(&ar->mutex);
-	spin_lock_init(&ar->cmdlock);
-	spin_lock_init(&ar->tx_stats_lock);
-	for (i = 0; i < __AR9170_NUM_TXQ; i++) {
-		skb_queue_head_init(&ar->tx_status[i]);
-		skb_queue_head_init(&ar->tx_pending[i]);
-	}
-	ar9170_rx_reset_rx_mpdu(ar);
-	INIT_WORK(&ar->beacon_work, ar9170_new_beacon);
-	INIT_DELAYED_WORK(&ar->tx_janitor, ar9170_tx_janitor);
-
-	/* all hw supports 2.4 GHz, so set channel to 1 by default */
-	ar->channel = &ar9170_2ghz_chantable[0];
-
-	/* first part of wiphy init */
-	ar->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
-					 BIT(NL80211_IFTYPE_WDS) |
-					 BIT(NL80211_IFTYPE_ADHOC);
-	ar->hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS |
-			 IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
-			 IEEE80211_HW_SIGNAL_DBM;
-
-	ar->hw->queues = __AR9170_NUM_TXQ;
-	ar->hw->extra_tx_headroom = 8;
-
-	ar->hw->max_rates = 1;
-	ar->hw->max_rate_tries = 3;
-
-	for (i = 0; i < ARRAY_SIZE(ar->noise); i++)
-		ar->noise[i] = -95; /* ATH_DEFAULT_NOISE_FLOOR */
-
-	return ar;
-
-err_nomem:
-	kfree_skb(skb);
-	return ERR_PTR(-ENOMEM);
-}
-
-static int ar9170_read_eeprom(struct ar9170 *ar)
-{
-#define RW	8	/* number of words to read at once */
-#define RB	(sizeof(u32) * RW)
-	struct ath_regulatory *regulatory = &ar->common.regulatory;
-	u8 *eeprom = (void *)&ar->eeprom;
-	u8 *addr = ar->eeprom.mac_address;
-	__le32 offsets[RW];
-	unsigned int rx_streams, tx_streams, tx_params = 0;
-	int i, j, err, bands = 0;
-
-	BUILD_BUG_ON(sizeof(ar->eeprom) & 3);
-
-	BUILD_BUG_ON(RB > AR9170_MAX_CMD_LEN - 4);
-#ifndef __CHECKER__
-	/* don't want to handle trailing remains */
-	BUILD_BUG_ON(sizeof(ar->eeprom) % RB);
-#endif
-
-	for (i = 0; i < sizeof(ar->eeprom)/RB; i++) {
-		for (j = 0; j < RW; j++)
-			offsets[j] = cpu_to_le32(AR9170_EEPROM_START +
-						 RB * i + 4 * j);
-
-		err = ar->exec_cmd(ar, AR9170_CMD_RREG,
-				   RB, (u8 *) &offsets,
-				   RB, eeprom + RB * i);
-		if (err)
-			return err;
-	}
-
-#undef RW
-#undef RB
-
-	if (ar->eeprom.length == cpu_to_le16(0xFFFF))
-		return -ENODATA;
-
-	if (ar->eeprom.operating_flags & AR9170_OPFLAG_2GHZ) {
-		ar->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &ar9170_band_2GHz;
-		bands++;
-	}
-	if (ar->eeprom.operating_flags & AR9170_OPFLAG_5GHZ) {
-		ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &ar9170_band_5GHz;
-		bands++;
-	}
-
-	rx_streams = hweight8(ar->eeprom.rx_mask);
-	tx_streams = hweight8(ar->eeprom.tx_mask);
-
-	if (rx_streams != tx_streams)
-		tx_params = IEEE80211_HT_MCS_TX_RX_DIFF;
-
-	if (tx_streams >= 1 && tx_streams <= IEEE80211_HT_MCS_TX_MAX_STREAMS)
-		tx_params = (tx_streams - 1) <<
-			    IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
-
-	ar9170_band_2GHz.ht_cap.mcs.tx_params |= tx_params;
-	ar9170_band_5GHz.ht_cap.mcs.tx_params |= tx_params;
-
-	/*
-	 * I measured this, a bandswitch takes roughly
-	 * 135 ms and a frequency switch about 80.
-	 *
-	 * FIXME: measure these values again once EEPROM settings
-	 *	  are used, that will influence them!
-	 */
-	if (bands == 2)
-		ar->hw->channel_change_time = 135 * 1000;
-	else
-		ar->hw->channel_change_time = 80 * 1000;
-
-	regulatory->current_rd = le16_to_cpu(ar->eeprom.reg_domain[0]);
-	regulatory->current_rd_ext = le16_to_cpu(ar->eeprom.reg_domain[1]);
-
-	/* second part of wiphy init */
-	SET_IEEE80211_PERM_ADDR(ar->hw, addr);
-
-	return bands ? 0 : -EINVAL;
-}
-
-static int ar9170_reg_notifier(struct wiphy *wiphy,
-			struct regulatory_request *request)
-{
-	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
-	struct ar9170 *ar = hw->priv;
-
-	return ath_reg_notifier_apply(wiphy, request, &ar->common.regulatory);
-}
-
-int ar9170_register(struct ar9170 *ar, struct device *pdev)
-{
-	struct ath_regulatory *regulatory = &ar->common.regulatory;
-	int err;
-
-	/* try to read EEPROM, init MAC addr */
-	err = ar9170_read_eeprom(ar);
-	if (err)
-		goto err_out;
-
-	err = ath_regd_init(regulatory, ar->hw->wiphy,
-			    ar9170_reg_notifier);
-	if (err)
-		goto err_out;
-
-	err = ieee80211_register_hw(ar->hw);
-	if (err)
-		goto err_out;
-
-	if (!ath_is_world_regd(regulatory))
-		regulatory_hint(ar->hw->wiphy, regulatory->alpha2);
-
-	err = ar9170_init_leds(ar);
-	if (err)
-		goto err_unreg;
-
-#ifdef CONFIG_AR9170_LEDS
-	err = ar9170_register_leds(ar);
-	if (err)
-		goto err_unreg;
-#endif /* CONFIG_AR9170_LEDS */
-
-	dev_info(pdev, "Atheros AR9170 is registered as '%s'\n",
-		 wiphy_name(ar->hw->wiphy));
-
-	ar->registered = true;
-	return 0;
-
-err_unreg:
-	ieee80211_unregister_hw(ar->hw);
-
-err_out:
-	return err;
-}
-
-void ar9170_unregister(struct ar9170 *ar)
-{
-	if (ar->registered) {
-#ifdef CONFIG_AR9170_LEDS
-		ar9170_unregister_leds(ar);
-#endif /* CONFIG_AR9170_LEDS */
-
-	ieee80211_unregister_hw(ar->hw);
-	}
-
-	kfree_skb(ar->rx_failover);
-	mutex_destroy(&ar->mutex);
-}
diff --git a/drivers/net/wireless/ath/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c
deleted file mode 100644
index 0dbfcf7..0000000
--- a/drivers/net/wireless/ath/ar9170/phy.c
+++ /dev/null
@@ -1,1719 +0,0 @@
-/*
- * Atheros AR9170 driver
- *
- * PHY and RF code
- *
- * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.  If not, see
- * http://www.gnu.org/licenses/.
- *
- * This file incorporates work covered by the following copyright and
- * permission notice:
- *    Copyright (c) 2007-2008 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/bitrev.h>
-#include "ar9170.h"
-#include "cmd.h"
-
-static int ar9170_init_power_cal(struct ar9170 *ar)
-{
-	ar9170_regwrite_begin(ar);
-
-	ar9170_regwrite(0x1bc000 + 0x993c, 0x7f);
-	ar9170_regwrite(0x1bc000 + 0x9934, 0x3f3f3f3f);
-	ar9170_regwrite(0x1bc000 + 0x9938, 0x3f3f3f3f);
-	ar9170_regwrite(0x1bc000 + 0xa234, 0x3f3f3f3f);
-	ar9170_regwrite(0x1bc000 + 0xa238, 0x3f3f3f3f);
-	ar9170_regwrite(0x1bc000 + 0xa38c, 0x3f3f3f3f);
-	ar9170_regwrite(0x1bc000 + 0xa390, 0x3f3f3f3f);
-	ar9170_regwrite(0x1bc000 + 0xa3cc, 0x3f3f3f3f);
-	ar9170_regwrite(0x1bc000 + 0xa3d0, 0x3f3f3f3f);
-	ar9170_regwrite(0x1bc000 + 0xa3d4, 0x3f3f3f3f);
-
-	ar9170_regwrite_finish();
-	return ar9170_regwrite_result();
-}
-
-struct ar9170_phy_init {
-	u32 reg, _5ghz_20, _5ghz_40, _2ghz_40, _2ghz_20;
-};
-
-static struct ar9170_phy_init ar5416_phy_init[] = {
-	{ 0x1c5800, 0x00000007, 0x00000007, 0x00000007, 0x00000007, },
-	{ 0x1c5804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, },
-	{ 0x1c5808, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c580c, 0xad848e19, 0xad848e19, 0xad848e19, 0xad848e19, },
-	{ 0x1c5810, 0x7d14e000, 0x7d14e000, 0x7d14e000, 0x7d14e000, },
-	{ 0x1c5814, 0x9c0a9f6b, 0x9c0a9f6b, 0x9c0a9f6b, 0x9c0a9f6b, },
-	{ 0x1c5818, 0x00000090, 0x00000090, 0x00000090, 0x00000090, },
-	{ 0x1c581c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c5820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, },
-	{ 0x1c5824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, },
-	{ 0x1c5828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, },
-	{ 0x1c582c, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, },
-	{ 0x1c5830, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c5834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, },
-	{ 0x1c5838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, },
-	{ 0x1c583c, 0x00200400, 0x00200400, 0x00200400, 0x00200400, },
-	{ 0x1c5840, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e, },
-	{ 0x1c5844, 0x1372161e, 0x13721c1e, 0x13721c24, 0x137216a4, },
-	{ 0x1c5848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, },
-	{ 0x1c584c, 0x1284233c, 0x1284233c, 0x1284233c, 0x1284233c, },
-	{ 0x1c5850, 0x6c48b4e4, 0x6c48b4e4, 0x6c48b0e4, 0x6c48b0e4, },
-	{ 0x1c5854, 0x00000859, 0x00000859, 0x00000859, 0x00000859, },
-	{ 0x1c5858, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, },
-	{ 0x1c585c, 0x31395c5e, 0x31395c5e, 0x31395c5e, 0x31395c5e, },
-	{ 0x1c5860, 0x0004dd10, 0x0004dd10, 0x0004dd20, 0x0004dd20, },
-	{ 0x1c5868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, },
-	{ 0x1c586c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, },
-	{ 0x1c5900, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c5904, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c5908, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c590c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c5914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, },
-	{ 0x1c5918, 0x00000118, 0x00000230, 0x00000268, 0x00000134, },
-	{ 0x1c591c, 0x10000fff, 0x10000fff, 0x10000fff, 0x10000fff, },
-	{ 0x1c5920, 0x0510081c, 0x0510081c, 0x0510001c, 0x0510001c, },
-	{ 0x1c5924, 0xd0058a15, 0xd0058a15, 0xd0058a15, 0xd0058a15, },
-	{ 0x1c5928, 0x00000001, 0x00000001, 0x00000001, 0x00000001, },
-	{ 0x1c592c, 0x00000004, 0x00000004, 0x00000004, 0x00000004, },
-	{ 0x1c5934, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, },
-	{ 0x1c5938, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, },
-	{ 0x1c593c, 0x0000007f, 0x0000007f, 0x0000007f, 0x0000007f, },
-	{ 0x1c5944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, },
-	{ 0x1c5948, 0x9280b212, 0x9280b212, 0x9280b212, 0x9280b212, },
-	{ 0x1c594c, 0x00020028, 0x00020028, 0x00020028, 0x00020028, },
-	{ 0x1c5954, 0x5d50e188, 0x5d50e188, 0x5d50e188, 0x5d50e188, },
-	{ 0x1c5958, 0x00081fff, 0x00081fff, 0x00081fff, 0x00081fff, },
-	{ 0x1c5960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, },
-	{ 0x1c5964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, },
-	{ 0x1c5970, 0x190fb515, 0x190fb515, 0x190fb515, 0x190fb515, },
-	{ 0x1c5974, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c5978, 0x00000001, 0x00000001, 0x00000001, 0x00000001, },
-	{ 0x1c597c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c5980, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c5984, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c5988, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c598c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c5990, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c5994, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c5998, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c599c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c59a0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c59a4, 0x00000007, 0x00000007, 0x00000007, 0x00000007, },
-	{ 0x1c59a8, 0x001fff00, 0x001fff00, 0x001fff00, 0x001fff00, },
-	{ 0x1c59ac, 0x006f00c4, 0x006f00c4, 0x006f00c4, 0x006f00c4, },
-	{ 0x1c59b0, 0x03051000, 0x03051000, 0x03051000, 0x03051000, },
-	{ 0x1c59b4, 0x00000820, 0x00000820, 0x00000820, 0x00000820, },
-	{ 0x1c59c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, },
-	{ 0x1c59c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, },
-	{ 0x1c59c8, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c, },
-	{ 0x1c59cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, },
-	{ 0x1c59d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, },
-	{ 0x1c59d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c59d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c59dc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c59e0, 0x00000200, 0x00000200, 0x00000200, 0x00000200, },
-	{ 0x1c59e4, 0x64646464, 0x64646464, 0x64646464, 0x64646464, },
-	{ 0x1c59e8, 0x3c787878, 0x3c787878, 0x3c787878, 0x3c787878, },
-	{ 0x1c59ec, 0x000000aa, 0x000000aa, 0x000000aa, 0x000000aa, },
-	{ 0x1c59f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c59fc, 0x00001042, 0x00001042, 0x00001042, 0x00001042, },
-	{ 0x1c5a00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c5a04, 0x00000040, 0x00000040, 0x00000040, 0x00000040, },
-	{ 0x1c5a08, 0x00000080, 0x00000080, 0x00000080, 0x00000080, },
-	{ 0x1c5a0c, 0x000001a1, 0x000001a1, 0x00000141, 0x00000141, },
-	{ 0x1c5a10, 0x000001e1, 0x000001e1, 0x00000181, 0x00000181, },
-	{ 0x1c5a14, 0x00000021, 0x00000021, 0x000001c1, 0x000001c1, },
-	{ 0x1c5a18, 0x00000061, 0x00000061, 0x00000001, 0x00000001, },
-	{ 0x1c5a1c, 0x00000168, 0x00000168, 0x00000041, 0x00000041, },
-	{ 0x1c5a20, 0x000001a8, 0x000001a8, 0x000001a8, 0x000001a8, },
-	{ 0x1c5a24, 0x000001e8, 0x000001e8, 0x000001e8, 0x000001e8, },
-	{ 0x1c5a28, 0x00000028, 0x00000028, 0x00000028, 0x00000028, },
-	{ 0x1c5a2c, 0x00000068, 0x00000068, 0x00000068, 0x00000068, },
-	{ 0x1c5a30, 0x00000189, 0x00000189, 0x000000a8, 0x000000a8, },
-	{ 0x1c5a34, 0x000001c9, 0x000001c9, 0x00000169, 0x00000169, },
-	{ 0x1c5a38, 0x00000009, 0x00000009, 0x000001a9, 0x000001a9, },
-	{ 0x1c5a3c, 0x00000049, 0x00000049, 0x000001e9, 0x000001e9, },
-	{ 0x1c5a40, 0x00000089, 0x00000089, 0x00000029, 0x00000029, },
-	{ 0x1c5a44, 0x00000170, 0x00000170, 0x00000069, 0x00000069, },
-	{ 0x1c5a48, 0x000001b0, 0x000001b0, 0x00000190, 0x00000190, },
-	{ 0x1c5a4c, 0x000001f0, 0x000001f0, 0x000001d0, 0x000001d0, },
-	{ 0x1c5a50, 0x00000030, 0x00000030, 0x00000010, 0x00000010, },
-	{ 0x1c5a54, 0x00000070, 0x00000070, 0x00000050, 0x00000050, },
-	{ 0x1c5a58, 0x00000191, 0x00000191, 0x00000090, 0x00000090, },
-	{ 0x1c5a5c, 0x000001d1, 0x000001d1, 0x00000151, 0x00000151, },
-	{ 0x1c5a60, 0x00000011, 0x00000011, 0x00000191, 0x00000191, },
-	{ 0x1c5a64, 0x00000051, 0x00000051, 0x000001d1, 0x000001d1, },
-	{ 0x1c5a68, 0x00000091, 0x00000091, 0x00000011, 0x00000011, },
-	{ 0x1c5a6c, 0x000001b8, 0x000001b8, 0x00000051, 0x00000051, },
-	{ 0x1c5a70, 0x000001f8, 0x000001f8, 0x00000198, 0x00000198, },
-	{ 0x1c5a74, 0x00000038, 0x00000038, 0x000001d8, 0x000001d8, },
-	{ 0x1c5a78, 0x00000078, 0x00000078, 0x00000018, 0x00000018, },
-	{ 0x1c5a7c, 0x00000199, 0x00000199, 0x00000058, 0x00000058, },
-	{ 0x1c5a80, 0x000001d9, 0x000001d9, 0x00000098, 0x00000098, },
-	{ 0x1c5a84, 0x00000019, 0x00000019, 0x00000159, 0x00000159, },
-	{ 0x1c5a88, 0x00000059, 0x00000059, 0x00000199, 0x00000199, },
-	{ 0x1c5a8c, 0x00000099, 0x00000099, 0x000001d9, 0x000001d9, },
-	{ 0x1c5a90, 0x000000d9, 0x000000d9, 0x00000019, 0x00000019, },
-	{ 0x1c5a94, 0x000000f9, 0x000000f9, 0x00000059, 0x00000059, },
-	{ 0x1c5a98, 0x000000f9, 0x000000f9, 0x00000099, 0x00000099, },
-	{ 0x1c5a9c, 0x000000f9, 0x000000f9, 0x000000d9, 0x000000d9, },
-	{ 0x1c5aa0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
-	{ 0x1c5aa4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
-	{ 0x1c5aa8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
-	{ 0x1c5aac, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
-	{ 0x1c5ab0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
-	{ 0x1c5ab4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
-	{ 0x1c5ab8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
-	{ 0x1c5abc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
-	{ 0x1c5ac0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
-	{ 0x1c5ac4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
-	{ 0x1c5ac8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
-	{ 0x1c5acc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
-	{ 0x1c5ad0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
-	{ 0x1c5ad4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
-	{ 0x1c5ad8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
-	{ 0x1c5adc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
-	{ 0x1c5ae0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
-	{ 0x1c5ae4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
-	{ 0x1c5ae8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
-	{ 0x1c5aec, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
-	{ 0x1c5af0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
-	{ 0x1c5af4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
-	{ 0x1c5af8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
-	{ 0x1c5afc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
-	{ 0x1c5b00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c5b04, 0x00000001, 0x00000001, 0x00000001, 0x00000001, },
-	{ 0x1c5b08, 0x00000002, 0x00000002, 0x00000002, 0x00000002, },
-	{ 0x1c5b0c, 0x00000003, 0x00000003, 0x00000003, 0x00000003, },
-	{ 0x1c5b10, 0x00000004, 0x00000004, 0x00000004, 0x00000004, },
-	{ 0x1c5b14, 0x00000005, 0x00000005, 0x00000005, 0x00000005, },
-	{ 0x1c5b18, 0x00000008, 0x00000008, 0x00000008, 0x00000008, },
-	{ 0x1c5b1c, 0x00000009, 0x00000009, 0x00000009, 0x00000009, },
-	{ 0x1c5b20, 0x0000000a, 0x0000000a, 0x0000000a, 0x0000000a, },
-	{ 0x1c5b24, 0x0000000b, 0x0000000b, 0x0000000b, 0x0000000b, },
-	{ 0x1c5b28, 0x0000000c, 0x0000000c, 0x0000000c, 0x0000000c, },
-	{ 0x1c5b2c, 0x0000000d, 0x0000000d, 0x0000000d, 0x0000000d, },
-	{ 0x1c5b30, 0x00000010, 0x00000010, 0x00000010, 0x00000010, },
-	{ 0x1c5b34, 0x00000011, 0x00000011, 0x00000011, 0x00000011, },
-	{ 0x1c5b38, 0x00000012, 0x00000012, 0x00000012, 0x00000012, },
-	{ 0x1c5b3c, 0x00000013, 0x00000013, 0x00000013, 0x00000013, },
-	{ 0x1c5b40, 0x00000014, 0x00000014, 0x00000014, 0x00000014, },
-	{ 0x1c5b44, 0x00000015, 0x00000015, 0x00000015, 0x00000015, },
-	{ 0x1c5b48, 0x00000018, 0x00000018, 0x00000018, 0x00000018, },
-	{ 0x1c5b4c, 0x00000019, 0x00000019, 0x00000019, 0x00000019, },
-	{ 0x1c5b50, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, },
-	{ 0x1c5b54, 0x0000001b, 0x0000001b, 0x0000001b, 0x0000001b, },
-	{ 0x1c5b58, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c, },
-	{ 0x1c5b5c, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, },
-	{ 0x1c5b60, 0x00000020, 0x00000020, 0x00000020, 0x00000020, },
-	{ 0x1c5b64, 0x00000021, 0x00000021, 0x00000021, 0x00000021, },
-	{ 0x1c5b68, 0x00000022, 0x00000022, 0x00000022, 0x00000022, },
-	{ 0x1c5b6c, 0x00000023, 0x00000023, 0x00000023, 0x00000023, },
-	{ 0x1c5b70, 0x00000024, 0x00000024, 0x00000024, 0x00000024, },
-	{ 0x1c5b74, 0x00000025, 0x00000025, 0x00000025, 0x00000025, },
-	{ 0x1c5b78, 0x00000028, 0x00000028, 0x00000028, 0x00000028, },
-	{ 0x1c5b7c, 0x00000029, 0x00000029, 0x00000029, 0x00000029, },
-	{ 0x1c5b80, 0x0000002a, 0x0000002a, 0x0000002a, 0x0000002a, },
-	{ 0x1c5b84, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b, },
-	{ 0x1c5b88, 0x0000002c, 0x0000002c, 0x0000002c, 0x0000002c, },
-	{ 0x1c5b8c, 0x0000002d, 0x0000002d, 0x0000002d, 0x0000002d, },
-	{ 0x1c5b90, 0x00000030, 0x00000030, 0x00000030, 0x00000030, },
-	{ 0x1c5b94, 0x00000031, 0x00000031, 0x00000031, 0x00000031, },
-	{ 0x1c5b98, 0x00000032, 0x00000032, 0x00000032, 0x00000032, },
-	{ 0x1c5b9c, 0x00000033, 0x00000033, 0x00000033, 0x00000033, },
-	{ 0x1c5ba0, 0x00000034, 0x00000034, 0x00000034, 0x00000034, },
-	{ 0x1c5ba4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
-	{ 0x1c5ba8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
-	{ 0x1c5bac, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
-	{ 0x1c5bb0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
-	{ 0x1c5bb4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
-	{ 0x1c5bb8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
-	{ 0x1c5bbc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
-	{ 0x1c5bc0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
-	{ 0x1c5bc4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
-	{ 0x1c5bc8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
-	{ 0x1c5bcc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
-	{ 0x1c5bd0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
-	{ 0x1c5bd4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
-	{ 0x1c5bd8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
-	{ 0x1c5bdc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
-	{ 0x1c5be0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
-	{ 0x1c5be4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
-	{ 0x1c5be8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
-	{ 0x1c5bec, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
-	{ 0x1c5bf0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
-	{ 0x1c5bf4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
-	{ 0x1c5bf8, 0x00000010, 0x00000010, 0x00000010, 0x00000010, },
-	{ 0x1c5bfc, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, },
-	{ 0x1c5c00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c5c0c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c5c10, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c5c14, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c5c18, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c5c1c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c5c20, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c5c24, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c5c28, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c5c2c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c5c30, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c5c34, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c5c38, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c5c3c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c5cf0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c5cf4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c5cf8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c5cfc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c6200, 0x00000008, 0x00000008, 0x0000000e, 0x0000000e, },
-	{ 0x1c6204, 0x00000440, 0x00000440, 0x00000440, 0x00000440, },
-	{ 0x1c6208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, },
-	{ 0x1c620c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, },
-	{ 0x1c6210, 0x40806333, 0x40806333, 0x40806333, 0x40806333, },
-	{ 0x1c6214, 0x00106c10, 0x00106c10, 0x00106c10, 0x00106c10, },
-	{ 0x1c6218, 0x009c4060, 0x009c4060, 0x009c4060, 0x009c4060, },
-	{ 0x1c621c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, },
-	{ 0x1c6220, 0x018830c6, 0x018830c6, 0x018830c6, 0x018830c6, },
-	{ 0x1c6224, 0x00000400, 0x00000400, 0x00000400, 0x00000400, },
-	{ 0x1c6228, 0x000009b5, 0x000009b5, 0x000009b5, 0x000009b5, },
-	{ 0x1c622c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c6230, 0x00000108, 0x00000210, 0x00000210, 0x00000108, },
-	{ 0x1c6234, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, },
-	{ 0x1c6238, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, },
-	{ 0x1c623c, 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af, },
-	{ 0x1c6240, 0x38490a20, 0x38490a20, 0x38490a20, 0x38490a20, },
-	{ 0x1c6244, 0x00007bb6, 0x00007bb6, 0x00007bb6, 0x00007bb6, },
-	{ 0x1c6248, 0x0fff3ffc, 0x0fff3ffc, 0x0fff3ffc, 0x0fff3ffc, },
-	{ 0x1c624c, 0x00000001, 0x00000001, 0x00000001, 0x00000001, },
-	{ 0x1c6250, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, },
-	{ 0x1c6254, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c6258, 0x0cc75380, 0x0cc75380, 0x0cc75380, 0x0cc75380, },
-	{ 0x1c625c, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, },
-	{ 0x1c6260, 0xdfa91f01, 0xdfa91f01, 0xdfa91f01, 0xdfa91f01, },
-	{ 0x1c6264, 0x00418a11, 0x00418a11, 0x00418a11, 0x00418a11, },
-	{ 0x1c6268, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c626c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, },
-	{ 0x1c6274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, },
-	{ 0x1c6278, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, },
-	{ 0x1c627c, 0x051701ce, 0x051701ce, 0x051701ce, 0x051701ce, },
-	{ 0x1c6300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, },
-	{ 0x1c6304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, },
-	{ 0x1c6308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, },
-	{ 0x1c630c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, },
-	{ 0x1c6310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, },
-	{ 0x1c6314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, },
-	{ 0x1c6318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, },
-	{ 0x1c631c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, },
-	{ 0x1c6320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, },
-	{ 0x1c6324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, },
-	{ 0x1c6328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, },
-	{ 0x1c632c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c6330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c6334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c6338, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c633c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c6340, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c6344, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c6348, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, },
-	{ 0x1c634c, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, },
-	{ 0x1c6350, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, },
-	{ 0x1c6354, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, },
-	{ 0x1c6358, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, },
-	{ 0x1c6388, 0x08000000, 0x08000000, 0x08000000, 0x08000000, },
-	{ 0x1c638c, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, },
-	{ 0x1c6390, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, },
-	{ 0x1c6394, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, },
-	{ 0x1c6398, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, },
-	{ 0x1c639c, 0x00000007, 0x00000007, 0x00000007, 0x00000007, },
-	{ 0x1c63a0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c63a4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c63a8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c63ac, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c63b0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c63b4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c63b8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c63bc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c63c0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c63c4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c63c8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c63cc, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, },
-	{ 0x1c63d0, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, },
-	{ 0x1c63d4, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, },
-	{ 0x1c63d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
-	{ 0x1c63dc, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, },
-	{ 0x1c63e0, 0x000000c0, 0x000000c0, 0x000000c0, 0x000000c0, },
-	{ 0x1c6848, 0x00180a65, 0x00180a65, 0x00180a68, 0x00180a68, },
-	{ 0x1c6920, 0x0510001c, 0x0510001c, 0x0510001c, 0x0510001c, },
-	{ 0x1c6960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, },
-	{ 0x1c720c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, },
-	{ 0x1c726c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, },
-	{ 0x1c7848, 0x00180a65, 0x00180a65, 0x00180a68, 0x00180a68, },
-	{ 0x1c7920, 0x0510001c, 0x0510001c, 0x0510001c, 0x0510001c, },
-	{ 0x1c7960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, },
-	{ 0x1c820c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, },
-	{ 0x1c826c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, },
-/*	{ 0x1c8864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, }, */
-	{ 0x1c8864, 0x0001c600, 0x0001c600, 0x0001c600, 0x0001c600, },
-	{ 0x1c895c, 0x004b6a8e, 0x004b6a8e, 0x004b6a8e, 0x004b6a8e, },
-	{ 0x1c8968, 0x000003ce, 0x000003ce, 0x000003ce, 0x000003ce, },
-	{ 0x1c89bc, 0x00181400, 0x00181400, 0x00181400, 0x00181400, },
-	{ 0x1c9270, 0x00820820, 0x00820820, 0x00820820, 0x00820820, },
-	{ 0x1c935c, 0x066c420f, 0x066c420f, 0x066c420f, 0x066c420f, },
-	{ 0x1c9360, 0x0f282207, 0x0f282207, 0x0f282207, 0x0f282207, },
-	{ 0x1c9364, 0x17601685, 0x17601685, 0x17601685, 0x17601685, },
-	{ 0x1c9368, 0x1f801104, 0x1f801104, 0x1f801104, 0x1f801104, },
-	{ 0x1c936c, 0x37a00c03, 0x37a00c03, 0x37a00c03, 0x37a00c03, },
-	{ 0x1c9370, 0x3fc40883, 0x3fc40883, 0x3fc40883, 0x3fc40883, },
-	{ 0x1c9374, 0x57c00803, 0x57c00803, 0x57c00803, 0x57c00803, },
-	{ 0x1c9378, 0x5fd80682, 0x5fd80682, 0x5fd80682, 0x5fd80682, },
-	{ 0x1c937c, 0x7fe00482, 0x7fe00482, 0x7fe00482, 0x7fe00482, },
-	{ 0x1c9380, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, },
-	{ 0x1c9384, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, }
-};
-
-/*
- * look up a certain register in ar5416_phy_init[] and return the init. value
- * for the band and bandwidth given. Return 0 if register address not found.
- */
-static u32 ar9170_get_default_phy_reg_val(u32 reg, bool is_2ghz, bool is_40mhz)
-{
-	unsigned int i;
-	for (i = 0; i < ARRAY_SIZE(ar5416_phy_init); i++) {
-		if (ar5416_phy_init[i].reg != reg)
-			continue;
-
-		if (is_2ghz) {
-			if (is_40mhz)
-				return ar5416_phy_init[i]._2ghz_40;
-			else
-				return ar5416_phy_init[i]._2ghz_20;
-		} else {
-			if (is_40mhz)
-				return ar5416_phy_init[i]._5ghz_40;
-			else
-				return ar5416_phy_init[i]._5ghz_20;
-		}
-	}
-	return 0;
-}
-
-/*
- * initialize some phy regs from eeprom values in modal_header[]
- * acc. to band and bandwith
- */
-static int ar9170_init_phy_from_eeprom(struct ar9170 *ar,
-				bool is_2ghz, bool is_40mhz)
-{
-	static const u8 xpd2pd[16] = {
-		0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x6, 0x2,
-		0x2, 0x3, 0x7, 0x2, 0xB, 0x2, 0x2, 0x2
-	};
-	u32 defval, newval;
-	/* pointer to the modal_header acc. to band */
-	struct ar9170_eeprom_modal *m = &ar->eeprom.modal_header[is_2ghz];
-
-	ar9170_regwrite_begin(ar);
-
-	/* ant common control (index 0) */
-	newval = le32_to_cpu(m->antCtrlCommon);
-	ar9170_regwrite(0x1c5964, newval);
-
-	/* ant control chain 0 (index 1) */
-	newval = le32_to_cpu(m->antCtrlChain[0]);
-	ar9170_regwrite(0x1c5960, newval);
-
-	/* ant control chain 2 (index 2) */
-	newval = le32_to_cpu(m->antCtrlChain[1]);
-	ar9170_regwrite(0x1c7960, newval);
-
-	/* SwSettle (index 3) */
-	if (!is_40mhz) {
-		defval = ar9170_get_default_phy_reg_val(0x1c5844,
-							is_2ghz, is_40mhz);
-		newval = (defval & ~0x3f80) |
-			((m->switchSettling & 0x7f) << 7);
-		ar9170_regwrite(0x1c5844, newval);
-	}
-
-	/* adcDesired, pdaDesired (index 4) */
-	defval = ar9170_get_default_phy_reg_val(0x1c5850, is_2ghz, is_40mhz);
-	newval = (defval & ~0xffff) | ((u8)m->pgaDesiredSize << 8) |
-		((u8)m->adcDesiredSize);
-	ar9170_regwrite(0x1c5850, newval);
-
-	/* TxEndToXpaOff, TxFrameToXpaOn (index 5) */
-	defval = ar9170_get_default_phy_reg_val(0x1c5834, is_2ghz, is_40mhz);
-	newval = (m->txEndToXpaOff << 24) | (m->txEndToXpaOff << 16) |
-		(m->txFrameToXpaOn << 8) | m->txFrameToXpaOn;
-	ar9170_regwrite(0x1c5834, newval);
-
-	/* TxEndToRxOn (index 6) */
-	defval = ar9170_get_default_phy_reg_val(0x1c5828, is_2ghz, is_40mhz);
-	newval = (defval & ~0xff0000) | (m->txEndToRxOn << 16);
-	ar9170_regwrite(0x1c5828, newval);
-
-	/* thresh62 (index 7) */
-	defval = ar9170_get_default_phy_reg_val(0x1c8864, is_2ghz, is_40mhz);
-	newval = (defval & ~0x7f000) | (m->thresh62 << 12);
-	ar9170_regwrite(0x1c8864, newval);
-
-	/* tx/rx attenuation chain 0 (index 8) */
-	defval = ar9170_get_default_phy_reg_val(0x1c5848, is_2ghz, is_40mhz);
-	newval = (defval & ~0x3f000) | ((m->txRxAttenCh[0] & 0x3f) << 12);
-	ar9170_regwrite(0x1c5848, newval);
-
-	/* tx/rx attenuation chain 2 (index 9) */
-	defval = ar9170_get_default_phy_reg_val(0x1c7848, is_2ghz, is_40mhz);
-	newval = (defval & ~0x3f000) | ((m->txRxAttenCh[1] & 0x3f) << 12);
-	ar9170_regwrite(0x1c7848, newval);
-
-	/* tx/rx margin chain 0 (index 10) */
-	defval = ar9170_get_default_phy_reg_val(0x1c620c, is_2ghz, is_40mhz);
-	newval = (defval & ~0xfc0000) | ((m->rxTxMarginCh[0] & 0x3f) << 18);
-	/* bsw margin chain 0 for 5GHz only */
-	if (!is_2ghz)
-		newval = (newval & ~0x3c00) | ((m->bswMargin[0] & 0xf) << 10);
-	ar9170_regwrite(0x1c620c, newval);
-
-	/* tx/rx margin chain 2 (index 11) */
-	defval = ar9170_get_default_phy_reg_val(0x1c820c, is_2ghz, is_40mhz);
-	newval = (defval & ~0xfc0000) | ((m->rxTxMarginCh[1] & 0x3f) << 18);
-	ar9170_regwrite(0x1c820c, newval);
-
-	/* iqCall, iqCallq chain 0 (index 12) */
-	defval = ar9170_get_default_phy_reg_val(0x1c5920, is_2ghz, is_40mhz);
-	newval = (defval & ~0x7ff) | (((u8)m->iqCalICh[0] & 0x3f) << 5) |
-		((u8)m->iqCalQCh[0] & 0x1f);
-	ar9170_regwrite(0x1c5920, newval);
-
-	/* iqCall, iqCallq chain 2 (index 13) */
-	defval = ar9170_get_default_phy_reg_val(0x1c7920, is_2ghz, is_40mhz);
-	newval = (defval & ~0x7ff) | (((u8)m->iqCalICh[1] & 0x3f) << 5) |
-		((u8)m->iqCalQCh[1] & 0x1f);
-	ar9170_regwrite(0x1c7920, newval);
-
-	/* xpd gain mask (index 14) */
-	defval = ar9170_get_default_phy_reg_val(0x1c6258, is_2ghz, is_40mhz);
-	newval = (defval & ~0xf0000) | (xpd2pd[m->xpdGain & 0xf] << 16);
-	ar9170_regwrite(0x1c6258, newval);
-	ar9170_regwrite_finish();
-
-	return ar9170_regwrite_result();
-}
-
-int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band)
-{
-	int i, err;
-	u32 val;
-	bool is_2ghz = band == IEEE80211_BAND_2GHZ;
-	bool is_40mhz = conf_is_ht40(&ar->hw->conf);
-
-	ar9170_regwrite_begin(ar);
-
-	for (i = 0; i < ARRAY_SIZE(ar5416_phy_init); i++) {
-		if (is_40mhz) {
-			if (is_2ghz)
-				val = ar5416_phy_init[i]._2ghz_40;
-			else
-				val = ar5416_phy_init[i]._5ghz_40;
-		} else {
-			if (is_2ghz)
-				val = ar5416_phy_init[i]._2ghz_20;
-			else
-				val = ar5416_phy_init[i]._5ghz_20;
-		}
-
-		ar9170_regwrite(ar5416_phy_init[i].reg, val);
-	}
-
-	ar9170_regwrite_finish();
-	err = ar9170_regwrite_result();
-	if (err)
-		return err;
-
-	err = ar9170_init_phy_from_eeprom(ar, is_2ghz, is_40mhz);
-	if (err)
-		return err;
-
-	err = ar9170_init_power_cal(ar);
-	if (err)
-		return err;
-
-	/* XXX: remove magic! */
-	if (is_2ghz)
-		err = ar9170_write_reg(ar, 0x1d4014, 0x5163);
-	else
-		err = ar9170_write_reg(ar, 0x1d4014, 0x5143);
-
-	return err;
-}
-
-struct ar9170_rf_init {
-	u32 reg, _5ghz, _2ghz;
-};
-
-static struct ar9170_rf_init ar9170_rf_init[] = {
-     /* bank 0 */
-     { 0x1c58b0,  0x1e5795e5,  0x1e5795e5},
-     { 0x1c58e0,  0x02008020,  0x02008020},
-     /* bank 1 */
-     { 0x1c58b0,  0x02108421,  0x02108421},
-     { 0x1c58ec,  0x00000008,  0x00000008},
-     /* bank 2 */
-     { 0x1c58b0,  0x0e73ff17,  0x0e73ff17},
-     { 0x1c58e0,  0x00000420,  0x00000420},
-     /* bank 3 */
-     { 0x1c58f0,  0x01400018,  0x01c00018},
-     /* bank 4 */
-     { 0x1c58b0,  0x000001a1,  0x000001a1},
-     { 0x1c58e8,  0x00000001,  0x00000001},
-     /* bank 5 */
-     { 0x1c58b0,  0x00000013,  0x00000013},
-     { 0x1c58e4,  0x00000002,  0x00000002},
-     /* bank 6 */
-     { 0x1c58b0,  0x00000000,  0x00000000},
-     { 0x1c58b0,  0x00000000,  0x00000000},
-     { 0x1c58b0,  0x00000000,  0x00000000},
-     { 0x1c58b0,  0x00000000,  0x00000000},
-     { 0x1c58b0,  0x00000000,  0x00000000},
-     { 0x1c58b0,  0x00004000,  0x00004000},
-     { 0x1c58b0,  0x00006c00,  0x00006c00},
-     { 0x1c58b0,  0x00002c00,  0x00002c00},
-     { 0x1c58b0,  0x00004800,  0x00004800},
-     { 0x1c58b0,  0x00004000,  0x00004000},
-     { 0x1c58b0,  0x00006000,  0x00006000},
-     { 0x1c58b0,  0x00001000,  0x00001000},
-     { 0x1c58b0,  0x00004000,  0x00004000},
-     { 0x1c58b0,  0x00007c00,  0x00007c00},
-     { 0x1c58b0,  0x00007c00,  0x00007c00},
-     { 0x1c58b0,  0x00007c00,  0x00007c00},
-     { 0x1c58b0,  0x00007c00,  0x00007c00},
-     { 0x1c58b0,  0x00007c00,  0x00007c00},
-     { 0x1c58b0,  0x00087c00,  0x00087c00},
-     { 0x1c58b0,  0x00007c00,  0x00007c00},
-     { 0x1c58b0,  0x00005400,  0x00005400},
-     { 0x1c58b0,  0x00000c00,  0x00000c00},
-     { 0x1c58b0,  0x00001800,  0x00001800},
-     { 0x1c58b0,  0x00007c00,  0x00007c00},
-     { 0x1c58b0,  0x00006c00,  0x00006c00},
-     { 0x1c58b0,  0x00006c00,  0x00006c00},
-     { 0x1c58b0,  0x00007c00,  0x00007c00},
-     { 0x1c58b0,  0x00002c00,  0x00002c00},
-     { 0x1c58b0,  0x00003c00,  0x00003c00},
-     { 0x1c58b0,  0x00003800,  0x00003800},
-     { 0x1c58b0,  0x00001c00,  0x00001c00},
-     { 0x1c58b0,  0x00000800,  0x00000800},
-     { 0x1c58b0,  0x00000408,  0x00000408},
-     { 0x1c58b0,  0x00004c15,  0x00004c15},
-     { 0x1c58b0,  0x00004188,  0x00004188},
-     { 0x1c58b0,  0x0000201e,  0x0000201e},
-     { 0x1c58b0,  0x00010408,  0x00010408},
-     { 0x1c58b0,  0x00000801,  0x00000801},
-     { 0x1c58b0,  0x00000c08,  0x00000c08},
-     { 0x1c58b0,  0x0000181e,  0x0000181e},
-     { 0x1c58b0,  0x00001016,  0x00001016},
-     { 0x1c58b0,  0x00002800,  0x00002800},
-     { 0x1c58b0,  0x00004010,  0x00004010},
-     { 0x1c58b0,  0x0000081c,  0x0000081c},
-     { 0x1c58b0,  0x00000115,  0x00000115},
-     { 0x1c58b0,  0x00000015,  0x00000015},
-     { 0x1c58b0,  0x00000066,  0x00000066},
-     { 0x1c58b0,  0x0000001c,  0x0000001c},
-     { 0x1c58b0,  0x00000000,  0x00000000},
-     { 0x1c58b0,  0x00000004,  0x00000004},
-     { 0x1c58b0,  0x00000015,  0x00000015},
-     { 0x1c58b0,  0x0000001f,  0x0000001f},
-     { 0x1c58e0,  0x00000000,  0x00000400},
-     /* bank 7 */
-     { 0x1c58b0,  0x000000a0,  0x000000a0},
-     { 0x1c58b0,  0x00000000,  0x00000000},
-     { 0x1c58b0,  0x00000040,  0x00000040},
-     { 0x1c58f0,  0x0000001c,  0x0000001c},
-};
-
-static int ar9170_init_rf_banks_0_7(struct ar9170 *ar, bool band5ghz)
-{
-	int err, i;
-
-	ar9170_regwrite_begin(ar);
-
-	for (i = 0; i < ARRAY_SIZE(ar9170_rf_init); i++)
-		ar9170_regwrite(ar9170_rf_init[i].reg,
-				band5ghz ? ar9170_rf_init[i]._5ghz
-					 : ar9170_rf_init[i]._2ghz);
-
-	ar9170_regwrite_finish();
-	err = ar9170_regwrite_result();
-	if (err)
-		wiphy_err(ar->hw->wiphy, "rf init failed\n");
-	return err;
-}
-
-static int ar9170_init_rf_bank4_pwr(struct ar9170 *ar, bool band5ghz,
-				    u32 freq, enum ar9170_bw bw)
-{
-	int err;
-	u32 d0, d1, td0, td1, fd0, fd1;
-	u8 chansel;
-	u8 refsel0 = 1, refsel1 = 0;
-	u8 lf_synth = 0;
-
-	switch (bw) {
-	case AR9170_BW_40_ABOVE:
-		freq += 10;
-		break;
-	case AR9170_BW_40_BELOW:
-		freq -= 10;
-		break;
-	case AR9170_BW_20:
-		break;
-	case __AR9170_NUM_BW:
-		BUG();
-	}
-
-	if (band5ghz) {
-		if (freq % 10) {
-			chansel = (freq - 4800) / 5;
-		} else {
-			chansel = ((freq - 4800) / 10) * 2;
-			refsel0 = 0;
-			refsel1 = 1;
-		}
-		chansel = byte_rev_table[chansel];
-	} else {
-		if (freq == 2484) {
-			chansel = 10 + (freq - 2274) / 5;
-			lf_synth = 1;
-		} else
-			chansel = 16 + (freq - 2272) / 5;
-		chansel *= 4;
-		chansel = byte_rev_table[chansel];
-	}
-
-	d1 =	chansel;
-	d0 =	0x21 |
-		refsel0 << 3 |
-		refsel1 << 2 |
-		lf_synth << 1;
-	td0 =	d0 & 0x1f;
-	td1 =	d1 & 0x1f;
-	fd0 =	td1 << 5 | td0;
-
-	td0 =	(d0 >> 5) & 0x7;
-	td1 =	(d1 >> 5) & 0x7;
-	fd1 =	td1 << 5 | td0;
-
-	ar9170_regwrite_begin(ar);
-
-	ar9170_regwrite(0x1c58b0, fd0);
-	ar9170_regwrite(0x1c58e8, fd1);
-
-	ar9170_regwrite_finish();
-	err = ar9170_regwrite_result();
-	if (err)
-		return err;
-
-	msleep(10);
-
-	return 0;
-}
-
-struct ar9170_phy_freq_params {
-	u8 coeff_exp;
-	u16 coeff_man;
-	u8 coeff_exp_shgi;
-	u16 coeff_man_shgi;
-};
-
-struct ar9170_phy_freq_entry {
-	u16 freq;
-	struct ar9170_phy_freq_params params[__AR9170_NUM_BW];
-};
-
-/* NB: must be in sync with channel tables in main! */
-static const struct ar9170_phy_freq_entry ar9170_phy_freq_params[] = {
-/*
- *	freq,
- *		20MHz,
- *		40MHz (below),
- *		40Mhz (above),
- */
-	{ 2412, {
-		{ 3, 21737, 3, 19563, },
-		{ 3, 21827, 3, 19644, },
-		{ 3, 21647, 3, 19482, },
-	} },
-	{ 2417, {
-		{ 3, 21692, 3, 19523, },
-		{ 3, 21782, 3, 19604, },
-		{ 3, 21602, 3, 19442, },
-	} },
-	{ 2422, {
-		{ 3, 21647, 3, 19482, },
-		{ 3, 21737, 3, 19563, },
-		{ 3, 21558, 3, 19402, },
-	} },
-	{ 2427, {
-		{ 3, 21602, 3, 19442, },
-		{ 3, 21692, 3, 19523, },
-		{ 3, 21514, 3, 19362, },
-	} },
-	{ 2432, {
-		{ 3, 21558, 3, 19402, },
-		{ 3, 21647, 3, 19482, },
-		{ 3, 21470, 3, 19323, },
-	} },
-	{ 2437, {
-		{ 3, 21514, 3, 19362, },
-		{ 3, 21602, 3, 19442, },
-		{ 3, 21426, 3, 19283, },
-	} },
-	{ 2442, {
-		{ 3, 21470, 3, 19323, },
-		{ 3, 21558, 3, 19402, },
-		{ 3, 21382, 3, 19244, },
-	} },
-	{ 2447, {
-		{ 3, 21426, 3, 19283, },
-		{ 3, 21514, 3, 19362, },
-		{ 3, 21339, 3, 19205, },
-	} },
-	{ 2452, {
-		{ 3, 21382, 3, 19244, },
-		{ 3, 21470, 3, 19323, },
-		{ 3, 21295, 3, 19166, },
-	} },
-	{ 2457, {
-		{ 3, 21339, 3, 19205, },
-		{ 3, 21426, 3, 19283, },
-		{ 3, 21252, 3, 19127, },
-	} },
-	{ 2462, {
-		{ 3, 21295, 3, 19166, },
-		{ 3, 21382, 3, 19244, },
-		{ 3, 21209, 3, 19088, },
-	} },
-	{ 2467, {
-		{ 3, 21252, 3, 19127, },
-		{ 3, 21339, 3, 19205, },
-		{ 3, 21166, 3, 19050, },
-	} },
-	{ 2472, {
-		{ 3, 21209, 3, 19088, },
-		{ 3, 21295, 3, 19166, },
-		{ 3, 21124, 3, 19011, },
-	} },
-	{ 2484, {
-		{ 3, 21107, 3, 18996, },
-		{ 3, 21192, 3, 19073, },
-		{ 3, 21022, 3, 18920, },
-	} },
-	{ 4920, {
-		{ 4, 21313, 4, 19181, },
-		{ 4, 21356, 4, 19220, },
-		{ 4, 21269, 4, 19142, },
-	} },
-	{ 4940, {
-		{ 4, 21226, 4, 19104, },
-		{ 4, 21269, 4, 19142, },
-		{ 4, 21183, 4, 19065, },
-	} },
-	{ 4960, {
-		{ 4, 21141, 4, 19027, },
-		{ 4, 21183, 4, 19065, },
-		{ 4, 21098, 4, 18988, },
-	} },
-	{ 4980, {
-		{ 4, 21056, 4, 18950, },
-		{ 4, 21098, 4, 18988, },
-		{ 4, 21014, 4, 18912, },
-	} },
-	{ 5040, {
-		{ 4, 20805, 4, 18725, },
-		{ 4, 20846, 4, 18762, },
-		{ 4, 20764, 4, 18687, },
-	} },
-	{ 5060, {
-		{ 4, 20723, 4, 18651, },
-		{ 4, 20764, 4, 18687, },
-		{ 4, 20682, 4, 18614, },
-	} },
-	{ 5080, {
-		{ 4, 20641, 4, 18577, },
-		{ 4, 20682, 4, 18614, },
-		{ 4, 20601, 4, 18541, },
-	} },
-	{ 5180, {
-		{ 4, 20243, 4, 18219, },
-		{ 4, 20282, 4, 18254, },
-		{ 4, 20204, 4, 18183, },
-	} },
-	{ 5200, {
-		{ 4, 20165, 4, 18148, },
-		{ 4, 20204, 4, 18183, },
-		{ 4, 20126, 4, 18114, },
-	} },
-	{ 5220, {
-		{ 4, 20088, 4, 18079, },
-		{ 4, 20126, 4, 18114, },
-		{ 4, 20049, 4, 18044, },
-	} },
-	{ 5240, {
-		{ 4, 20011, 4, 18010, },
-		{ 4, 20049, 4, 18044, },
-		{ 4, 19973, 4, 17976, },
-	} },
-	{ 5260, {
-		{ 4, 19935, 4, 17941, },
-		{ 4, 19973, 4, 17976, },
-		{ 4, 19897, 4, 17907, },
-	} },
-	{ 5280, {
-		{ 4, 19859, 4, 17873, },
-		{ 4, 19897, 4, 17907, },
-		{ 4, 19822, 4, 17840, },
-	} },
-	{ 5300, {
-		{ 4, 19784, 4, 17806, },
-		{ 4, 19822, 4, 17840, },
-		{ 4, 19747, 4, 17772, },
-	} },
-	{ 5320, {
-		{ 4, 19710, 4, 17739, },
-		{ 4, 19747, 4, 17772, },
-		{ 4, 19673, 4, 17706, },
-	} },
-	{ 5500, {
-		{ 4, 19065, 4, 17159, },
-		{ 4, 19100, 4, 17190, },
-		{ 4, 19030, 4, 17127, },
-	} },
-	{ 5520, {
-		{ 4, 18996, 4, 17096, },
-		{ 4, 19030, 4, 17127, },
-		{ 4, 18962, 4, 17065, },
-	} },
-	{ 5540, {
-		{ 4, 18927, 4, 17035, },
-		{ 4, 18962, 4, 17065, },
-		{ 4, 18893, 4, 17004, },
-	} },
-	{ 5560, {
-		{ 4, 18859, 4, 16973, },
-		{ 4, 18893, 4, 17004, },
-		{ 4, 18825, 4, 16943, },
-	} },
-	{ 5580, {
-		{ 4, 18792, 4, 16913, },
-		{ 4, 18825, 4, 16943, },
-		{ 4, 18758, 4, 16882, },
-	} },
-	{ 5600, {
-		{ 4, 18725, 4, 16852, },
-		{ 4, 18758, 4, 16882, },
-		{ 4, 18691, 4, 16822, },
-	} },
-	{ 5620, {
-		{ 4, 18658, 4, 16792, },
-		{ 4, 18691, 4, 16822, },
-		{ 4, 18625, 4, 16762, },
-	} },
-	{ 5640, {
-		{ 4, 18592, 4, 16733, },
-		{ 4, 18625, 4, 16762, },
-		{ 4, 18559, 4, 16703, },
-	} },
-	{ 5660, {
-		{ 4, 18526, 4, 16673, },
-		{ 4, 18559, 4, 16703, },
-		{ 4, 18493, 4, 16644, },
-	} },
-	{ 5680, {
-		{ 4, 18461, 4, 16615, },
-		{ 4, 18493, 4, 16644, },
-		{ 4, 18428, 4, 16586, },
-	} },
-	{ 5700, {
-		{ 4, 18396, 4, 16556, },
-		{ 4, 18428, 4, 16586, },
-		{ 4, 18364, 4, 16527, },
-	} },
-	{ 5745, {
-		{ 4, 18252, 4, 16427, },
-		{ 4, 18284, 4, 16455, },
-		{ 4, 18220, 4, 16398, },
-	} },
-	{ 5765, {
-		{ 4, 18189, 5, 32740, },
-		{ 4, 18220, 4, 16398, },
-		{ 4, 18157, 5, 32683, },
-	} },
-	{ 5785, {
-		{ 4, 18126, 5, 32626, },
-		{ 4, 18157, 5, 32683, },
-		{ 4, 18094, 5, 32570, },
-	} },
-	{ 5805, {
-		{ 4, 18063, 5, 32514, },
-		{ 4, 18094, 5, 32570, },
-		{ 4, 18032, 5, 32458, },
-	} },
-	{ 5825, {
-		{ 4, 18001, 5, 32402, },
-		{ 4, 18032, 5, 32458, },
-		{ 4, 17970, 5, 32347, },
-	} },
-	{ 5170, {
-		{ 4, 20282, 4, 18254, },
-		{ 4, 20321, 4, 18289, },
-		{ 4, 20243, 4, 18219, },
-	} },
-	{ 5190, {
-		{ 4, 20204, 4, 18183, },
-		{ 4, 20243, 4, 18219, },
-		{ 4, 20165, 4, 18148, },
-	} },
-	{ 5210, {
-		{ 4, 20126, 4, 18114, },
-		{ 4, 20165, 4, 18148, },
-		{ 4, 20088, 4, 18079, },
-	} },
-	{ 5230, {
-		{ 4, 20049, 4, 18044, },
-		{ 4, 20088, 4, 18079, },
-		{ 4, 20011, 4, 18010, },
-	} },
-};
-
-static const struct ar9170_phy_freq_params *
-ar9170_get_hw_dyn_params(struct ieee80211_channel *channel,
-			 enum ar9170_bw bw)
-{
-	unsigned int chanidx = 0;
-	u16 freq = 2412;
-
-	if (channel) {
-		chanidx = channel->hw_value;
-		freq = channel->center_freq;
-	}
-
-	BUG_ON(chanidx >= ARRAY_SIZE(ar9170_phy_freq_params));
-
-	BUILD_BUG_ON(__AR9170_NUM_BW != 3);
-
-	WARN_ON(ar9170_phy_freq_params[chanidx].freq != freq);
-
-	return &ar9170_phy_freq_params[chanidx].params[bw];
-}
-
-
-int ar9170_init_rf(struct ar9170 *ar)
-{
-	const struct ar9170_phy_freq_params *freqpar;
-	__le32 cmd[7];
-	int err;
-
-	err = ar9170_init_rf_banks_0_7(ar, false);
-	if (err)
-		return err;
-
-	err = ar9170_init_rf_bank4_pwr(ar, false, 2412, AR9170_BW_20);
-	if (err)
-		return err;
-
-	freqpar = ar9170_get_hw_dyn_params(NULL, AR9170_BW_20);
-
-	cmd[0] = cpu_to_le32(2412 * 1000);
-	cmd[1] = cpu_to_le32(0);
-	cmd[2] = cpu_to_le32(1);
-	cmd[3] = cpu_to_le32(freqpar->coeff_exp);
-	cmd[4] = cpu_to_le32(freqpar->coeff_man);
-	cmd[5] = cpu_to_le32(freqpar->coeff_exp_shgi);
-	cmd[6] = cpu_to_le32(freqpar->coeff_man_shgi);
-
-	/* RF_INIT echoes the command back to us */
-	err = ar->exec_cmd(ar, AR9170_CMD_RF_INIT,
-			   sizeof(cmd), (u8 *)cmd,
-			   sizeof(cmd), (u8 *)cmd);
-	if (err)
-		return err;
-
-	msleep(1000);
-
-	return ar9170_echo_test(ar, 0xaabbccdd);
-}
-
-static int ar9170_find_freq_idx(int nfreqs, u8 *freqs, u8 f)
-{
-	int idx = nfreqs - 2;
-
-	while (idx >= 0) {
-		if (f >= freqs[idx])
-			return idx;
-		idx--;
-	}
-
-	return 0;
-}
-
-static s32 ar9170_interpolate_s32(s32 x, s32 x1, s32 y1, s32 x2, s32 y2)
-{
-	/* nothing to interpolate, it's horizontal */
-	if (y2 == y1)
-		return y1;
-
-	/* check if we hit one of the edges */
-	if (x == x1)
-		return y1;
-	if (x == x2)
-		return y2;
-
-	/* x1 == x2 is bad, hopefully == x */
-	if (x2 == x1)
-		return y1;
-
-	return y1 + (((y2 - y1) * (x - x1)) / (x2 - x1));
-}
-
-static u8 ar9170_interpolate_u8(u8 x, u8 x1, u8 y1, u8 x2, u8 y2)
-{
-#define SHIFT		8
-	s32 y;
-
-	y = ar9170_interpolate_s32(x << SHIFT,
-				   x1 << SHIFT, y1 << SHIFT,
-				   x2 << SHIFT, y2 << SHIFT);
-
-	/*
-	 * XXX: unwrap this expression
-	 *	Isn't it just DIV_ROUND_UP(y, 1<<SHIFT)?
-	 *	Can we rely on the compiler to optimise away the div?
-	 */
-	return (y >> SHIFT) + ((y & (1<<(SHIFT-1))) >> (SHIFT - 1));
-#undef SHIFT
-}
-
-static u8 ar9170_interpolate_val(u8 x, u8 *x_array, u8 *y_array)
-{
-	int i;
-
-	for (i = 0; i < 3; i++)
-		if (x <= x_array[i + 1])
-			break;
-
-	return ar9170_interpolate_u8(x,
-				     x_array[i],
-				     y_array[i],
-				     x_array[i + 1],
-				     y_array[i + 1]);
-}
-
-static int ar9170_set_freq_cal_data(struct ar9170 *ar,
-				    struct ieee80211_channel *channel)
-{
-	u8 *cal_freq_pier;
-	u8 vpds[2][AR5416_PD_GAIN_ICEPTS];
-	u8 pwrs[2][AR5416_PD_GAIN_ICEPTS];
-	int chain, idx, i;
-	u32 phy_data = 0;
-	u8 f, tmp;
-
-	switch (channel->band) {
-	case IEEE80211_BAND_2GHZ:
-		f = channel->center_freq - 2300;
-		cal_freq_pier = ar->eeprom.cal_freq_pier_2G;
-		i = AR5416_NUM_2G_CAL_PIERS - 1;
-		break;
-
-	case IEEE80211_BAND_5GHZ:
-		f = (channel->center_freq - 4800) / 5;
-		cal_freq_pier = ar->eeprom.cal_freq_pier_5G;
-		i = AR5416_NUM_5G_CAL_PIERS - 1;
-		break;
-
-	default:
-		return -EINVAL;
-		break;
-	}
-
-	for (; i >= 0; i--) {
-		if (cal_freq_pier[i] != 0xff)
-			break;
-	}
-	if (i < 0)
-		return -EINVAL;
-
-	idx = ar9170_find_freq_idx(i, cal_freq_pier, f);
-
-	ar9170_regwrite_begin(ar);
-
-	for (chain = 0; chain < AR5416_MAX_CHAINS; chain++) {
-		for (i = 0; i < AR5416_PD_GAIN_ICEPTS; i++) {
-			struct ar9170_calibration_data_per_freq *cal_pier_data;
-			int j;
-
-			switch (channel->band) {
-			case IEEE80211_BAND_2GHZ:
-				cal_pier_data = &ar->eeprom.
-					cal_pier_data_2G[chain][idx];
-				break;
-
-			case IEEE80211_BAND_5GHZ:
-				cal_pier_data = &ar->eeprom.
-					cal_pier_data_5G[chain][idx];
-				break;
-
-			default:
-				return -EINVAL;
-			}
-
-			for (j = 0; j < 2; j++) {
-				vpds[j][i] = ar9170_interpolate_u8(f,
-					cal_freq_pier[idx],
-					cal_pier_data->vpd_pdg[j][i],
-					cal_freq_pier[idx + 1],
-					cal_pier_data[1].vpd_pdg[j][i]);
-
-				pwrs[j][i] = ar9170_interpolate_u8(f,
-					cal_freq_pier[idx],
-					cal_pier_data->pwr_pdg[j][i],
-					cal_freq_pier[idx + 1],
-					cal_pier_data[1].pwr_pdg[j][i]) / 2;
-			}
-		}
-
-		for (i = 0; i < 76; i++) {
-			if (i < 25) {
-				tmp = ar9170_interpolate_val(i, &pwrs[0][0],
-							     &vpds[0][0]);
-			} else {
-				tmp = ar9170_interpolate_val(i - 12,
-							     &pwrs[1][0],
-							     &vpds[1][0]);
-			}
-
-			phy_data |= tmp << ((i & 3) << 3);
-			if ((i & 3) == 3) {
-				ar9170_regwrite(0x1c6280 + chain * 0x1000 +
-						(i & ~3), phy_data);
-				phy_data = 0;
-			}
-		}
-
-		for (i = 19; i < 32; i++)
-			ar9170_regwrite(0x1c6280 + chain * 0x1000 + (i << 2),
-					0x0);
-	}
-
-	ar9170_regwrite_finish();
-	return ar9170_regwrite_result();
-}
-
-static u8 ar9170_get_max_edge_power(struct ar9170 *ar,
-				    struct ar9170_calctl_edges edges[],
-				    u32 freq)
-{
-	int i;
-	u8 rc = AR5416_MAX_RATE_POWER;
-	u8 f;
-	if (freq < 3000)
-		f = freq - 2300;
-	else
-		f = (freq - 4800) / 5;
-
-	for (i = 0; i < AR5416_NUM_BAND_EDGES; i++) {
-		if (edges[i].channel == 0xff)
-			break;
-		if (f == edges[i].channel) {
-			/* exact freq match */
-			rc = edges[i].power_flags & ~AR9170_CALCTL_EDGE_FLAGS;
-			break;
-		}
-		if (i > 0 && f < edges[i].channel) {
-			if (f > edges[i - 1].channel &&
-			    edges[i - 1].power_flags &
-			    AR9170_CALCTL_EDGE_FLAGS) {
-				/* lower channel has the inband flag set */
-				rc = edges[i - 1].power_flags &
-					~AR9170_CALCTL_EDGE_FLAGS;
-			}
-			break;
-		}
-	}
-
-	if (i == AR5416_NUM_BAND_EDGES) {
-		if (f > edges[i - 1].channel &&
-		    edges[i - 1].power_flags & AR9170_CALCTL_EDGE_FLAGS) {
-			/* lower channel has the inband flag set */
-			rc = edges[i - 1].power_flags &
-				~AR9170_CALCTL_EDGE_FLAGS;
-		}
-	}
-	return rc;
-}
-
-static u8 ar9170_get_heavy_clip(struct ar9170 *ar,
-				struct ar9170_calctl_edges edges[],
-				u32 freq, enum ar9170_bw bw)
-{
-	u8 f;
-	int i;
-	u8 rc = 0;
-
-	if (freq < 3000)
-		f = freq - 2300;
-	else
-		f = (freq - 4800) / 5;
-
-	if (bw == AR9170_BW_40_BELOW || bw == AR9170_BW_40_ABOVE)
-		rc |= 0xf0;
-
-	for (i = 0; i < AR5416_NUM_BAND_EDGES; i++) {
-		if (edges[i].channel == 0xff)
-			break;
-		if (f == edges[i].channel) {
-			if (!(edges[i].power_flags & AR9170_CALCTL_EDGE_FLAGS))
-				rc |= 0x0f;
-			break;
-		}
-	}
-
-	return rc;
-}
-
-/*
- * calculate the conformance test limits and the heavy clip parameter
- * and apply them to ar->power* (derived from otus hal/hpmain.c, line 3706)
- */
-static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw)
-{
-	u8 ctl_grp; /* CTL group */
-	u8 ctl_idx; /* CTL index */
-	int i, j;
-	struct ctl_modes {
-		u8 ctl_mode;
-		u8 max_power;
-		u8 *pwr_cal_data;
-		int pwr_cal_len;
-	} *modes;
-
-	/*
-	 * order is relevant in the mode_list_*: we fall back to the
-	 * lower indices if any mode is missed in the EEPROM.
-	 */
-	struct ctl_modes mode_list_2ghz[] = {
-		{ CTL_11B, 0, ar->power_2G_cck, 4 },
-		{ CTL_11G, 0, ar->power_2G_ofdm, 4 },
-		{ CTL_2GHT20, 0, ar->power_2G_ht20, 8 },
-		{ CTL_2GHT40, 0, ar->power_2G_ht40, 8 },
-	};
-	struct ctl_modes mode_list_5ghz[] = {
-		{ CTL_11A, 0, ar->power_5G_leg, 4 },
-		{ CTL_5GHT20, 0, ar->power_5G_ht20, 8 },
-		{ CTL_5GHT40, 0, ar->power_5G_ht40, 8 },
-	};
-	int nr_modes;
-
-#define EDGES(c, n) (ar->eeprom.ctl_data[c].control_edges[n])
-
-	ar->phy_heavy_clip = 0;
-
-	/*
-	 * TODO: investigate the differences between OTUS'
-	 * hpreg.c::zfHpGetRegulatoryDomain() and
-	 * ath/regd.c::ath_regd_get_band_ctl() -
-	 * e.g. for FCC3_WORLD the OTUS procedure
-	 * always returns CTL_FCC, while the one in ath/ delivers
-	 * CTL_ETSI for 2GHz and CTL_FCC for 5GHz.
-	 */
-	ctl_grp = ath_regd_get_band_ctl(&ar->common.regulatory,
-					ar->hw->conf.channel->band);
-
-	/* ctl group not found - either invalid band (NO_CTL) or ww roaming */
-	if (ctl_grp == NO_CTL || ctl_grp == SD_NO_CTL)
-		ctl_grp = CTL_FCC;
-
-	if (ctl_grp != CTL_FCC)
-		/* skip CTL and heavy clip for CTL_MKK and CTL_ETSI */
-		return;
-
-	if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) {
-		modes = mode_list_2ghz;
-		nr_modes = ARRAY_SIZE(mode_list_2ghz);
-	} else {
-		modes = mode_list_5ghz;
-		nr_modes = ARRAY_SIZE(mode_list_5ghz);
-	}
-
-	for (i = 0; i < nr_modes; i++) {
-		u8 c = ctl_grp | modes[i].ctl_mode;
-		for (ctl_idx = 0; ctl_idx < AR5416_NUM_CTLS; ctl_idx++)
-			if (c == ar->eeprom.ctl_index[ctl_idx])
-				break;
-		if (ctl_idx < AR5416_NUM_CTLS) {
-			int f_off = 0;
-
-			/* determine heav clip parameter from
-			   the 11G edges array */
-			if (modes[i].ctl_mode == CTL_11G) {
-				ar->phy_heavy_clip =
-					ar9170_get_heavy_clip(ar,
-							      EDGES(ctl_idx, 1),
-							      freq, bw);
-			}
-
-			/* adjust freq for 40MHz */
-			if (modes[i].ctl_mode == CTL_2GHT40 ||
-			    modes[i].ctl_mode == CTL_5GHT40) {
-				if (bw == AR9170_BW_40_BELOW)
-					f_off = -10;
-				else
-					f_off = 10;
-			}
-
-			modes[i].max_power =
-				ar9170_get_max_edge_power(ar, EDGES(ctl_idx, 1),
-							  freq+f_off);
-
-			/*
-			 * TODO: check if the regulatory max. power is
-			 *  controlled by cfg80211 for DFS
-			 * (hpmain applies it to max_power itself for DFS freq)
-			 */
-
-		} else {
-			/*
-			 * Workaround in otus driver, hpmain.c, line 3906:
-			 * if no data for 5GHT20 are found, take the
-			 * legacy 5G value.
-			 * We extend this here to fallback from any other *HT or
-			 * 11G, too.
-			 */
-			int k = i;
-
-			modes[i].max_power = AR5416_MAX_RATE_POWER;
-			while (k-- > 0) {
-				if (modes[k].max_power !=
-				    AR5416_MAX_RATE_POWER) {
-					modes[i].max_power = modes[k].max_power;
-					break;
-				}
-			}
-		}
-
-		/* apply max power to pwr_cal_data (ar->power_*) */
-		for (j = 0; j < modes[i].pwr_cal_len; j++) {
-			modes[i].pwr_cal_data[j] = min(modes[i].pwr_cal_data[j],
-						       modes[i].max_power);
-		}
-	}
-
-	if (ar->phy_heavy_clip & 0xf0) {
-		ar->power_2G_ht40[0]--;
-		ar->power_2G_ht40[1]--;
-		ar->power_2G_ht40[2]--;
-	}
-	if (ar->phy_heavy_clip & 0xf) {
-		ar->power_2G_ht20[0]++;
-		ar->power_2G_ht20[1]++;
-		ar->power_2G_ht20[2]++;
-	}
-
-
-#undef EDGES
-}
-
-static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw)
-{
-	struct ar9170_calibration_target_power_legacy *ctpl;
-	struct ar9170_calibration_target_power_ht *ctph;
-	u8 *ctpres;
-	int ntargets;
-	int idx, i, n;
-	u8 ackpower, ackchains, f;
-	u8 pwr_freqs[AR5416_MAX_NUM_TGT_PWRS];
-
-	if (freq < 3000)
-		f = freq - 2300;
-	else
-		f = (freq - 4800)/5;
-
-	/*
-	 * cycle through the various modes
-	 *
-	 * legacy modes first: 5G, 2G CCK, 2G OFDM
-	 */
-	for (i = 0; i < 3; i++) {
-		switch (i) {
-		case 0: /* 5 GHz legacy */
-			ctpl = &ar->eeprom.cal_tgt_pwr_5G[0];
-			ntargets = AR5416_NUM_5G_TARGET_PWRS;
-			ctpres = ar->power_5G_leg;
-			break;
-		case 1: /* 2.4 GHz CCK */
-			ctpl = &ar->eeprom.cal_tgt_pwr_2G_cck[0];
-			ntargets = AR5416_NUM_2G_CCK_TARGET_PWRS;
-			ctpres = ar->power_2G_cck;
-			break;
-		case 2: /* 2.4 GHz OFDM */
-			ctpl = &ar->eeprom.cal_tgt_pwr_2G_ofdm[0];
-			ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS;
-			ctpres = ar->power_2G_ofdm;
-			break;
-		default:
-			BUG();
-		}
-
-		for (n = 0; n < ntargets; n++) {
-			if (ctpl[n].freq == 0xff)
-				break;
-			pwr_freqs[n] = ctpl[n].freq;
-		}
-		ntargets = n;
-		idx = ar9170_find_freq_idx(ntargets, pwr_freqs, f);
-		for (n = 0; n < 4; n++)
-			ctpres[n] = ar9170_interpolate_u8(
-					f,
-					ctpl[idx + 0].freq,
-					ctpl[idx + 0].power[n],
-					ctpl[idx + 1].freq,
-					ctpl[idx + 1].power[n]);
-	}
-
-	/*
-	 * HT modes now: 5G HT20, 5G HT40, 2G CCK, 2G OFDM, 2G HT20, 2G HT40
-	 */
-	for (i = 0; i < 4; i++) {
-		switch (i) {
-		case 0: /* 5 GHz HT 20 */
-			ctph = &ar->eeprom.cal_tgt_pwr_5G_ht20[0];
-			ntargets = AR5416_NUM_5G_TARGET_PWRS;
-			ctpres = ar->power_5G_ht20;
-			break;
-		case 1: /* 5 GHz HT 40 */
-			ctph = &ar->eeprom.cal_tgt_pwr_5G_ht40[0];
-			ntargets = AR5416_NUM_5G_TARGET_PWRS;
-			ctpres = ar->power_5G_ht40;
-			break;
-		case 2: /* 2.4 GHz HT 20 */
-			ctph = &ar->eeprom.cal_tgt_pwr_2G_ht20[0];
-			ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS;
-			ctpres = ar->power_2G_ht20;
-			break;
-		case 3: /* 2.4 GHz HT 40 */
-			ctph = &ar->eeprom.cal_tgt_pwr_2G_ht40[0];
-			ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS;
-			ctpres = ar->power_2G_ht40;
-			break;
-		default:
-			BUG();
-		}
-
-		for (n = 0; n < ntargets; n++) {
-			if (ctph[n].freq == 0xff)
-				break;
-			pwr_freqs[n] = ctph[n].freq;
-		}
-		ntargets = n;
-		idx = ar9170_find_freq_idx(ntargets, pwr_freqs, f);
-		for (n = 0; n < 8; n++)
-			ctpres[n] = ar9170_interpolate_u8(
-					f,
-					ctph[idx + 0].freq,
-					ctph[idx + 0].power[n],
-					ctph[idx + 1].freq,
-					ctph[idx + 1].power[n]);
-	}
-
-
-	/* calc. conformance test limits and apply to ar->power*[] */
-	ar9170_calc_ctl(ar, freq, bw);
-
-	/* set ACK/CTS TX power */
-	ar9170_regwrite_begin(ar);
-
-	if (ar->eeprom.tx_mask != 1)
-		ackchains = AR9170_TX_PHY_TXCHAIN_2;
-	else
-		ackchains = AR9170_TX_PHY_TXCHAIN_1;
-
-	if (freq < 3000)
-		ackpower = ar->power_2G_ofdm[0] & 0x3f;
-	else
-		ackpower = ar->power_5G_leg[0] & 0x3f;
-
-	ar9170_regwrite(0x1c3694, ackpower << 20 | ackchains << 26);
-	ar9170_regwrite(0x1c3bb4, ackpower << 5 | ackchains << 11 |
-				  ackpower << 21 | ackchains << 27);
-
-	ar9170_regwrite_finish();
-	return ar9170_regwrite_result();
-}
-
-static int ar9170_calc_noise_dbm(u32 raw_noise)
-{
-	if (raw_noise & 0x100)
-		return ~((raw_noise & 0x0ff) >> 1);
-	else
-		return (raw_noise & 0xff) >> 1;
-}
-
-int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
-		       enum ar9170_rf_init_mode rfi, enum ar9170_bw bw)
-{
-	const struct ar9170_phy_freq_params *freqpar;
-	u32 cmd, tmp, offs;
-	__le32 vals[8];
-	int i, err;
-	bool bandswitch;
-
-	/* clear BB heavy clip enable */
-	err = ar9170_write_reg(ar, 0x1c59e0, 0x200);
-	if (err)
-		return err;
-
-	/* may be NULL at first setup */
-	if (ar->channel)
-		bandswitch = ar->channel->band != channel->band;
-	else
-		bandswitch = true;
-
-	/* HW workaround */
-	if (!ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] &&
-	    channel->center_freq <= 2417)
-		bandswitch = true;
-
-	err = ar->exec_cmd(ar, AR9170_CMD_FREQ_START, 0, NULL, 0, NULL);
-	if (err)
-		return err;
-
-	if (rfi != AR9170_RFI_NONE || bandswitch) {
-		u32 val = 0x400;
-
-		if (rfi == AR9170_RFI_COLD)
-			val = 0x800;
-
-		/* warm/cold reset BB/ADDA */
-		err = ar9170_write_reg(ar, 0x1d4004, val);
-		if (err)
-			return err;
-
-		err = ar9170_write_reg(ar, 0x1d4004, 0x0);
-		if (err)
-			return err;
-
-		err = ar9170_init_phy(ar, channel->band);
-		if (err)
-			return err;
-
-		err = ar9170_init_rf_banks_0_7(ar,
-			channel->band == IEEE80211_BAND_5GHZ);
-		if (err)
-			return err;
-
-		cmd = AR9170_CMD_RF_INIT;
-	} else {
-		cmd = AR9170_CMD_FREQUENCY;
-	}
-
-	err = ar9170_init_rf_bank4_pwr(ar,
-		channel->band == IEEE80211_BAND_5GHZ,
-		channel->center_freq, bw);
-	if (err)
-		return err;
-
-	switch (bw) {
-	case AR9170_BW_20:
-		tmp = 0x240;
-		offs = 0;
-		break;
-	case AR9170_BW_40_BELOW:
-		tmp = 0x2c4;
-		offs = 3;
-		break;
-	case AR9170_BW_40_ABOVE:
-		tmp = 0x2d4;
-		offs = 1;
-		break;
-	default:
-		BUG();
-		return -ENOSYS;
-	}
-
-	if (ar->eeprom.tx_mask != 1)
-		tmp |= 0x100;
-
-	err = ar9170_write_reg(ar, 0x1c5804, tmp);
-	if (err)
-		return err;
-
-	err = ar9170_set_freq_cal_data(ar, channel);
-	if (err)
-		return err;
-
-	err = ar9170_set_power_cal(ar, channel->center_freq, bw);
-	if (err)
-		return err;
-
-	freqpar = ar9170_get_hw_dyn_params(channel, bw);
-
-	vals[0] = cpu_to_le32(channel->center_freq * 1000);
-	vals[1] = cpu_to_le32(conf_is_ht40(&ar->hw->conf));
-	vals[2] = cpu_to_le32(offs << 2 | 1);
-	vals[3] = cpu_to_le32(freqpar->coeff_exp);
-	vals[4] = cpu_to_le32(freqpar->coeff_man);
-	vals[5] = cpu_to_le32(freqpar->coeff_exp_shgi);
-	vals[6] = cpu_to_le32(freqpar->coeff_man_shgi);
-	vals[7] = cpu_to_le32(1000);
-
-	err = ar->exec_cmd(ar, cmd, sizeof(vals), (u8 *)vals,
-			   sizeof(vals), (u8 *)vals);
-	if (err)
-		return err;
-
-	if (ar->phy_heavy_clip) {
-		err = ar9170_write_reg(ar, 0x1c59e0,
-				       0x200 | ar->phy_heavy_clip);
-		if (err) {
-			if (ar9170_nag_limiter(ar))
-				wiphy_err(ar->hw->wiphy,
-					  "failed to set heavy clip\n");
-		}
-	}
-
-	for (i = 0; i < 2; i++) {
-		ar->noise[i] = ar9170_calc_noise_dbm(
-				(le32_to_cpu(vals[2 + i]) >> 19) & 0x1ff);
-
-		ar->noise[i + 2] = ar9170_calc_noise_dbm(
-				    (le32_to_cpu(vals[5 + i]) >> 23) & 0x1ff);
-	}
-
-	ar->channel = channel;
-	return 0;
-}
diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c
deleted file mode 100644
index d3be6f9..0000000
--- a/drivers/net/wireless/ath/ar9170/usb.c
+++ /dev/null
@@ -1,1008 +0,0 @@
-/*
- * Atheros AR9170 driver
- *
- * USB - frontend
- *
- * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- * Copyright 2009, Christian Lamparter <chunkeey@web.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.  If not, see
- * http://www.gnu.org/licenses/.
- *
- * This file incorporates work covered by the following copyright and
- * permission notice:
- *    Copyright (c) 2007-2008 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/module.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/firmware.h>
-#include <linux/etherdevice.h>
-#include <linux/device.h>
-#include <net/mac80211.h>
-#include "ar9170.h"
-#include "cmd.h"
-#include "hw.h"
-#include "usb.h"
-
-MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
-MODULE_AUTHOR("Christian Lamparter <chunkeey@web.de>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Atheros AR9170 802.11n USB wireless");
-MODULE_FIRMWARE("ar9170.fw");
-
-enum ar9170_requirements {
-	AR9170_REQ_FW1_ONLY = 1,
-};
-
-static struct usb_device_id ar9170_usb_ids[] = {
-	/* Atheros 9170 */
-	{ USB_DEVICE(0x0cf3, 0x9170) },
-	/* Atheros TG121N */
-	{ USB_DEVICE(0x0cf3, 0x1001) },
-	/* TP-Link TL-WN821N v2 */
-	{ USB_DEVICE(0x0cf3, 0x1002) },
-	/* 3Com Dual Band 802.11n USB Adapter */
-	{ USB_DEVICE(0x0cf3, 0x1010) },
-	/* H3C Dual Band 802.11n USB Adapter */
-	{ USB_DEVICE(0x0cf3, 0x1011) },
-	/* Cace Airpcap NX */
-	{ USB_DEVICE(0xcace, 0x0300) },
-	/* D-Link DWA 160 A1 */
-	{ USB_DEVICE(0x07d1, 0x3c10) },
-	/* D-Link DWA 160 A2 */
-	{ USB_DEVICE(0x07d1, 0x3a09) },
-	/* Netgear WNA1000 */
-	{ USB_DEVICE(0x0846, 0x9040) },
-	/* Netgear WNDA3100 */
-	{ USB_DEVICE(0x0846, 0x9010) },
-	/* Netgear WN111 v2 */
-	{ USB_DEVICE(0x0846, 0x9001) },
-	/* Zydas ZD1221 */
-	{ USB_DEVICE(0x0ace, 0x1221) },
-	/* Proxim ORiNOCO 802.11n USB */
-	{ USB_DEVICE(0x1435, 0x0804) },
-	/* WNC Generic 11n USB Dongle */
-	{ USB_DEVICE(0x1435, 0x0326) },
-	/* ZyXEL NWD271N */
-	{ USB_DEVICE(0x0586, 0x3417) },
-	/* Z-Com UB81 BG */
-	{ USB_DEVICE(0x0cde, 0x0023) },
-	/* Z-Com UB82 ABG */
-	{ USB_DEVICE(0x0cde, 0x0026) },
-	/* Sphairon Homelink 1202 */
-	{ USB_DEVICE(0x0cde, 0x0027) },
-	/* Arcadyan WN7512 */
-	{ USB_DEVICE(0x083a, 0xf522) },
-	/* Planex GWUS300 */
-	{ USB_DEVICE(0x2019, 0x5304) },
-	/* IO-Data WNGDNUS2 */
-	{ USB_DEVICE(0x04bb, 0x093f) },
-	/* AVM FRITZ!WLAN USB Stick N */
-	{ USB_DEVICE(0x057C, 0x8401) },
-	/* NEC WL300NU-G */
-	{ USB_DEVICE(0x0409, 0x0249) },
-	/* AVM FRITZ!WLAN USB Stick N 2.4 */
-	{ USB_DEVICE(0x057C, 0x8402), .driver_info = AR9170_REQ_FW1_ONLY },
-	/* Qwest/Actiontec 802AIN Wireless N USB Network Adapter */
-	{ USB_DEVICE(0x1668, 0x1200) },
-
-	/* terminate */
-	{}
-};
-MODULE_DEVICE_TABLE(usb, ar9170_usb_ids);
-
-static void ar9170_usb_submit_urb(struct ar9170_usb *aru)
-{
-	struct urb *urb;
-	unsigned long flags;
-	int err;
-
-	if (unlikely(!IS_STARTED(&aru->common)))
-		return ;
-
-	spin_lock_irqsave(&aru->tx_urb_lock, flags);
-	if (atomic_read(&aru->tx_submitted_urbs) >= AR9170_NUM_TX_URBS) {
-		spin_unlock_irqrestore(&aru->tx_urb_lock, flags);
-		return ;
-	}
-	atomic_inc(&aru->tx_submitted_urbs);
-
-	urb = usb_get_from_anchor(&aru->tx_pending);
-	if (!urb) {
-		atomic_dec(&aru->tx_submitted_urbs);
-		spin_unlock_irqrestore(&aru->tx_urb_lock, flags);
-
-		return ;
-	}
-	spin_unlock_irqrestore(&aru->tx_urb_lock, flags);
-
-	aru->tx_pending_urbs--;
-	usb_anchor_urb(urb, &aru->tx_submitted);
-
-	err = usb_submit_urb(urb, GFP_ATOMIC);
-	if (unlikely(err)) {
-		if (ar9170_nag_limiter(&aru->common))
-			dev_err(&aru->udev->dev, "submit_urb failed (%d).\n",
-				err);
-
-		usb_unanchor_urb(urb);
-		atomic_dec(&aru->tx_submitted_urbs);
-		ar9170_tx_callback(&aru->common, urb->context);
-	}
-
-	usb_free_urb(urb);
-}
-
-static void ar9170_usb_tx_urb_complete_frame(struct urb *urb)
-{
-	struct sk_buff *skb = urb->context;
-	struct ar9170_usb *aru = usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
-
-	if (unlikely(!aru)) {
-		dev_kfree_skb_irq(skb);
-		return ;
-	}
-
-	atomic_dec(&aru->tx_submitted_urbs);
-
-	ar9170_tx_callback(&aru->common, skb);
-
-	ar9170_usb_submit_urb(aru);
-}
-
-static void ar9170_usb_tx_urb_complete(struct urb *urb)
-{
-}
-
-static void ar9170_usb_irq_completed(struct urb *urb)
-{
-	struct ar9170_usb *aru = urb->context;
-
-	switch (urb->status) {
-	/* everything is fine */
-	case 0:
-		break;
-
-	/* disconnect */
-	case -ENOENT:
-	case -ECONNRESET:
-	case -ENODEV:
-	case -ESHUTDOWN:
-		goto free;
-
-	default:
-		goto resubmit;
-	}
-
-	ar9170_handle_command_response(&aru->common, urb->transfer_buffer,
-				       urb->actual_length);
-
-resubmit:
-	usb_anchor_urb(urb, &aru->rx_submitted);
-	if (usb_submit_urb(urb, GFP_ATOMIC)) {
-		usb_unanchor_urb(urb);
-		goto free;
-	}
-
-	return;
-
-free:
-	usb_free_coherent(aru->udev, 64, urb->transfer_buffer, urb->transfer_dma);
-}
-
-static void ar9170_usb_rx_completed(struct urb *urb)
-{
-	struct sk_buff *skb = urb->context;
-	struct ar9170_usb *aru = usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
-	int err;
-
-	if (!aru)
-		goto free;
-
-	switch (urb->status) {
-	/* everything is fine */
-	case 0:
-		break;
-
-	/* disconnect */
-	case -ENOENT:
-	case -ECONNRESET:
-	case -ENODEV:
-	case -ESHUTDOWN:
-		goto free;
-
-	default:
-		goto resubmit;
-	}
-
-	skb_put(skb, urb->actual_length);
-	ar9170_rx(&aru->common, skb);
-
-resubmit:
-	skb_reset_tail_pointer(skb);
-	skb_trim(skb, 0);
-
-	usb_anchor_urb(urb, &aru->rx_submitted);
-	err = usb_submit_urb(urb, GFP_ATOMIC);
-	if (unlikely(err)) {
-		usb_unanchor_urb(urb);
-		goto free;
-	}
-
-	return ;
-
-free:
-	dev_kfree_skb_irq(skb);
-}
-
-static int ar9170_usb_prep_rx_urb(struct ar9170_usb *aru,
-				  struct urb *urb, gfp_t gfp)
-{
-	struct sk_buff *skb;
-
-	skb = __dev_alloc_skb(AR9170_MAX_RX_BUFFER_SIZE + 32, gfp);
-	if (!skb)
-		return -ENOMEM;
-
-	/* reserve some space for mac80211's radiotap */
-	skb_reserve(skb, 32);
-
-	usb_fill_bulk_urb(urb, aru->udev,
-			  usb_rcvbulkpipe(aru->udev, AR9170_EP_RX),
-			  skb->data, min(skb_tailroom(skb),
-			  AR9170_MAX_RX_BUFFER_SIZE),
-			  ar9170_usb_rx_completed, skb);
-
-	return 0;
-}
-
-static int ar9170_usb_alloc_rx_irq_urb(struct ar9170_usb *aru)
-{
-	struct urb *urb = NULL;
-	void *ibuf;
-	int err = -ENOMEM;
-
-	/* initialize interrupt endpoint */
-	urb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!urb)
-		goto out;
-
-	ibuf = usb_alloc_coherent(aru->udev, 64, GFP_KERNEL, &urb->transfer_dma);
-	if (!ibuf)
-		goto out;
-
-	usb_fill_int_urb(urb, aru->udev,
-			 usb_rcvintpipe(aru->udev, AR9170_EP_IRQ), ibuf,
-			 64, ar9170_usb_irq_completed, aru, 1);
-	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-	usb_anchor_urb(urb, &aru->rx_submitted);
-	err = usb_submit_urb(urb, GFP_KERNEL);
-	if (err) {
-		usb_unanchor_urb(urb);
-		usb_free_coherent(aru->udev, 64, urb->transfer_buffer,
-				  urb->transfer_dma);
-	}
-
-out:
-	usb_free_urb(urb);
-	return err;
-}
-
-static int ar9170_usb_alloc_rx_bulk_urbs(struct ar9170_usb *aru)
-{
-	struct urb *urb;
-	int i;
-	int err = -EINVAL;
-
-	for (i = 0; i < AR9170_NUM_RX_URBS; i++) {
-		err = -ENOMEM;
-		urb = usb_alloc_urb(0, GFP_KERNEL);
-		if (!urb)
-			goto err_out;
-
-		err = ar9170_usb_prep_rx_urb(aru, urb, GFP_KERNEL);
-		if (err) {
-			usb_free_urb(urb);
-			goto err_out;
-		}
-
-		usb_anchor_urb(urb, &aru->rx_submitted);
-		err = usb_submit_urb(urb, GFP_KERNEL);
-		if (err) {
-			usb_unanchor_urb(urb);
-			dev_kfree_skb_any((void *) urb->transfer_buffer);
-			usb_free_urb(urb);
-			goto err_out;
-		}
-		usb_free_urb(urb);
-	}
-
-	/* the device now waiting for a firmware. */
-	aru->common.state = AR9170_IDLE;
-	return 0;
-
-err_out:
-
-	usb_kill_anchored_urbs(&aru->rx_submitted);
-	return err;
-}
-
-static int ar9170_usb_flush(struct ar9170 *ar)
-{
-	struct ar9170_usb *aru = (void *) ar;
-	struct urb *urb;
-	int ret, err = 0;
-
-	if (IS_STARTED(ar))
-		aru->common.state = AR9170_IDLE;
-
-	usb_wait_anchor_empty_timeout(&aru->tx_pending,
-					    msecs_to_jiffies(800));
-	while ((urb = usb_get_from_anchor(&aru->tx_pending))) {
-		ar9170_tx_callback(&aru->common, (void *) urb->context);
-		usb_free_urb(urb);
-	}
-
-	/* lets wait a while until the tx - queues are dried out */
-	ret = usb_wait_anchor_empty_timeout(&aru->tx_submitted,
-					    msecs_to_jiffies(100));
-	if (ret == 0)
-		err = -ETIMEDOUT;
-
-	usb_kill_anchored_urbs(&aru->tx_submitted);
-
-	if (IS_ACCEPTING_CMD(ar))
-		aru->common.state = AR9170_STARTED;
-
-	return err;
-}
-
-static void ar9170_usb_cancel_urbs(struct ar9170_usb *aru)
-{
-	int err;
-
-	aru->common.state = AR9170_UNKNOWN_STATE;
-
-	err = ar9170_usb_flush(&aru->common);
-	if (err)
-		dev_err(&aru->udev->dev, "stuck tx urbs!\n");
-
-	usb_poison_anchored_urbs(&aru->tx_submitted);
-	usb_poison_anchored_urbs(&aru->rx_submitted);
-}
-
-static int ar9170_usb_exec_cmd(struct ar9170 *ar, enum ar9170_cmd cmd,
-			       unsigned int plen, void *payload,
-			       unsigned int outlen, void *out)
-{
-	struct ar9170_usb *aru = (void *) ar;
-	struct urb *urb = NULL;
-	unsigned long flags;
-	int err = -ENOMEM;
-
-	if (unlikely(!IS_ACCEPTING_CMD(ar)))
-		return -EPERM;
-
-	if (WARN_ON(plen > AR9170_MAX_CMD_LEN - 4))
-		return -EINVAL;
-
-	urb = usb_alloc_urb(0, GFP_ATOMIC);
-	if (unlikely(!urb))
-		goto err_free;
-
-	ar->cmdbuf[0] = cpu_to_le32(plen);
-	ar->cmdbuf[0] |= cpu_to_le32(cmd << 8);
-	/* writing multiple regs fills this buffer already */
-	if (plen && payload != (u8 *)(&ar->cmdbuf[1]))
-		memcpy(&ar->cmdbuf[1], payload, plen);
-
-	spin_lock_irqsave(&aru->common.cmdlock, flags);
-	aru->readbuf = (u8 *)out;
-	aru->readlen = outlen;
-	spin_unlock_irqrestore(&aru->common.cmdlock, flags);
-
-	usb_fill_int_urb(urb, aru->udev,
-			 usb_sndintpipe(aru->udev, AR9170_EP_CMD),
-			 aru->common.cmdbuf, plen + 4,
-			 ar9170_usb_tx_urb_complete, NULL, 1);
-
-	usb_anchor_urb(urb, &aru->tx_submitted);
-	err = usb_submit_urb(urb, GFP_ATOMIC);
-	if (unlikely(err)) {
-		usb_unanchor_urb(urb);
-		usb_free_urb(urb);
-		goto err_unbuf;
-	}
-	usb_free_urb(urb);
-
-	err = wait_for_completion_timeout(&aru->cmd_wait, HZ);
-	if (err == 0) {
-		err = -ETIMEDOUT;
-		goto err_unbuf;
-	}
-
-	if (aru->readlen != outlen) {
-		err = -EMSGSIZE;
-		goto err_unbuf;
-	}
-
-	return 0;
-
-err_unbuf:
-	/* Maybe the device was removed in the second we were waiting? */
-	if (IS_STARTED(ar)) {
-		dev_err(&aru->udev->dev, "no command feedback "
-					 "received (%d).\n", err);
-
-		/* provide some maybe useful debug information */
-		print_hex_dump_bytes("ar9170 cmd: ", DUMP_PREFIX_NONE,
-				     aru->common.cmdbuf, plen + 4);
-		dump_stack();
-	}
-
-	/* invalidate to avoid completing the next prematurely */
-	spin_lock_irqsave(&aru->common.cmdlock, flags);
-	aru->readbuf = NULL;
-	aru->readlen = 0;
-	spin_unlock_irqrestore(&aru->common.cmdlock, flags);
-
-err_free:
-
-	return err;
-}
-
-static int ar9170_usb_tx(struct ar9170 *ar, struct sk_buff *skb)
-{
-	struct ar9170_usb *aru = (struct ar9170_usb *) ar;
-	struct urb *urb;
-
-	if (unlikely(!IS_STARTED(ar))) {
-		/* Seriously, what were you drink... err... thinking!? */
-		return -EPERM;
-	}
-
-	urb = usb_alloc_urb(0, GFP_ATOMIC);
-	if (unlikely(!urb))
-		return -ENOMEM;
-
-	usb_fill_bulk_urb(urb, aru->udev,
-			  usb_sndbulkpipe(aru->udev, AR9170_EP_TX),
-			  skb->data, skb->len,
-			  ar9170_usb_tx_urb_complete_frame, skb);
-	urb->transfer_flags |= URB_ZERO_PACKET;
-
-	usb_anchor_urb(urb, &aru->tx_pending);
-	aru->tx_pending_urbs++;
-
-	usb_free_urb(urb);
-
-	ar9170_usb_submit_urb(aru);
-	return 0;
-}
-
-static void ar9170_usb_callback_cmd(struct ar9170 *ar, u32 len , void *buffer)
-{
-	struct ar9170_usb *aru = (void *) ar;
-	unsigned long flags;
-	u32 in, out;
-
-	if (unlikely(!buffer))
-		return ;
-
-	in = le32_to_cpup((__le32 *)buffer);
-	out = le32_to_cpu(ar->cmdbuf[0]);
-
-	/* mask off length byte */
-	out &= ~0xFF;
-
-	if (aru->readlen >= 0) {
-		/* add expected length */
-		out |= aru->readlen;
-	} else {
-		/* add obtained length */
-		out |= in & 0xFF;
-	}
-
-	/*
-	 * Some commands (e.g: AR9170_CMD_FREQUENCY) have a variable response
-	 * length and we cannot predict the correct length in advance.
-	 * So we only check if we provided enough space for the data.
-	 */
-	if (unlikely(out < in)) {
-		dev_warn(&aru->udev->dev, "received invalid command response "
-					  "got %d bytes, instead of %d bytes "
-					  "and the resp length is %d bytes\n",
-			 in, out, len);
-		print_hex_dump_bytes("ar9170 invalid resp: ",
-				     DUMP_PREFIX_OFFSET, buffer, len);
-		/*
-		 * Do not complete, then the command times out,
-		 * and we get a stack trace from there.
-		 */
-		return ;
-	}
-
-	spin_lock_irqsave(&aru->common.cmdlock, flags);
-	if (aru->readbuf && len > 0) {
-		memcpy(aru->readbuf, buffer + 4, len - 4);
-		aru->readbuf = NULL;
-	}
-	complete(&aru->cmd_wait);
-	spin_unlock_irqrestore(&aru->common.cmdlock, flags);
-}
-
-static int ar9170_usb_upload(struct ar9170_usb *aru, const void *data,
-			     size_t len, u32 addr, bool complete)
-{
-	int transfer, err;
-	u8 *buf = kmalloc(4096, GFP_KERNEL);
-
-	if (!buf)
-		return -ENOMEM;
-
-	while (len) {
-		transfer = min_t(int, len, 4096);
-		memcpy(buf, data, transfer);
-
-		err = usb_control_msg(aru->udev, usb_sndctrlpipe(aru->udev, 0),
-				      0x30 /* FW DL */, 0x40 | USB_DIR_OUT,
-				      addr >> 8, 0, buf, transfer, 1000);
-
-		if (err < 0) {
-			kfree(buf);
-			return err;
-		}
-
-		len -= transfer;
-		data += transfer;
-		addr += transfer;
-	}
-	kfree(buf);
-
-	if (complete) {
-		err = usb_control_msg(aru->udev, usb_sndctrlpipe(aru->udev, 0),
-				      0x31 /* FW DL COMPLETE */,
-				      0x40 | USB_DIR_OUT, 0, 0, NULL, 0, 5000);
-	}
-
-	return 0;
-}
-
-static int ar9170_usb_reset(struct ar9170_usb *aru)
-{
-	int ret, lock = (aru->intf->condition != USB_INTERFACE_BINDING);
-
-	if (lock) {
-		ret = usb_lock_device_for_reset(aru->udev, aru->intf);
-		if (ret < 0) {
-			dev_err(&aru->udev->dev, "unable to lock device "
-				"for reset (%d).\n", ret);
-			return ret;
-		}
-	}
-
-	ret = usb_reset_device(aru->udev);
-	if (lock)
-		usb_unlock_device(aru->udev);
-
-	/* let it rest - for a second - */
-	msleep(1000);
-
-	return ret;
-}
-
-static int ar9170_usb_upload_firmware(struct ar9170_usb *aru)
-{
-	int err;
-
-	if (!aru->init_values)
-		goto upload_fw_start;
-
-	/* First, upload initial values to device RAM */
-	err = ar9170_usb_upload(aru, aru->init_values->data,
-				aru->init_values->size, 0x102800, false);
-	if (err) {
-		dev_err(&aru->udev->dev, "firmware part 1 "
-			"upload failed (%d).\n", err);
-		return err;
-	}
-
-upload_fw_start:
-
-	/* Then, upload the firmware itself and start it */
-	return ar9170_usb_upload(aru, aru->firmware->data, aru->firmware->size,
-				0x200000, true);
-}
-
-static int ar9170_usb_init_transport(struct ar9170_usb *aru)
-{
-	struct ar9170 *ar = (void *) &aru->common;
-	int err;
-
-	ar9170_regwrite_begin(ar);
-
-	/* Set USB Rx stream mode MAX packet number to 2 */
-	ar9170_regwrite(AR9170_USB_REG_MAX_AGG_UPLOAD, 0x4);
-
-	/* Set USB Rx stream mode timeout to 10us */
-	ar9170_regwrite(AR9170_USB_REG_UPLOAD_TIME_CTL, 0x80);
-
-	ar9170_regwrite_finish();
-
-	err = ar9170_regwrite_result();
-	if (err)
-		dev_err(&aru->udev->dev, "USB setup failed (%d).\n", err);
-
-	return err;
-}
-
-static void ar9170_usb_stop(struct ar9170 *ar)
-{
-	struct ar9170_usb *aru = (void *) ar;
-	int ret;
-
-	if (IS_ACCEPTING_CMD(ar))
-		aru->common.state = AR9170_STOPPED;
-
-	ret = ar9170_usb_flush(ar);
-	if (ret)
-		dev_err(&aru->udev->dev, "kill pending tx urbs.\n");
-
-	usb_poison_anchored_urbs(&aru->tx_submitted);
-
-	/*
-	 * Note:
-	 * So far we freed all tx urbs, but we won't dare to touch any rx urbs.
-	 * Else we would end up with a unresponsive device...
-	 */
-}
-
-static int ar9170_usb_open(struct ar9170 *ar)
-{
-	struct ar9170_usb *aru = (void *) ar;
-	int err;
-
-	usb_unpoison_anchored_urbs(&aru->tx_submitted);
-	err = ar9170_usb_init_transport(aru);
-	if (err) {
-		usb_poison_anchored_urbs(&aru->tx_submitted);
-		return err;
-	}
-
-	aru->common.state = AR9170_IDLE;
-	return 0;
-}
-
-static int ar9170_usb_init_device(struct ar9170_usb *aru)
-{
-	int err;
-
-	err = ar9170_usb_alloc_rx_irq_urb(aru);
-	if (err)
-		goto err_out;
-
-	err = ar9170_usb_alloc_rx_bulk_urbs(aru);
-	if (err)
-		goto err_unrx;
-
-	err = ar9170_usb_upload_firmware(aru);
-	if (err) {
-		err = ar9170_echo_test(&aru->common, 0x60d43110);
-		if (err) {
-			/* force user invention, by disabling the device */
-			err = usb_driver_set_configuration(aru->udev, -1);
-			dev_err(&aru->udev->dev, "device is in a bad state. "
-						 "please reconnect it!\n");
-			goto err_unrx;
-		}
-	}
-
-	return 0;
-
-err_unrx:
-	ar9170_usb_cancel_urbs(aru);
-
-err_out:
-	return err;
-}
-
-static void ar9170_usb_firmware_failed(struct ar9170_usb *aru)
-{
-	struct device *parent = aru->udev->dev.parent;
-	struct usb_device *udev;
-
-	/*
-	 * Store a copy of the usb_device pointer locally.
-	 * This is because device_release_driver initiates
-	 * ar9170_usb_disconnect, which in turn frees our
-	 * driver context (aru).
-	 */
-	udev = aru->udev;
-
-	complete(&aru->firmware_loading_complete);
-
-	/* unbind anything failed */
-	if (parent)
-		device_lock(parent);
-
-	device_release_driver(&udev->dev);
-	if (parent)
-		device_unlock(parent);
-
-	usb_put_dev(udev);
-}
-
-static void ar9170_usb_firmware_finish(const struct firmware *fw, void *context)
-{
-	struct ar9170_usb *aru = context;
-	int err;
-
-	aru->firmware = fw;
-
-	if (!fw) {
-		dev_err(&aru->udev->dev, "firmware file not found.\n");
-		goto err_freefw;
-	}
-
-	err = ar9170_usb_init_device(aru);
-	if (err)
-		goto err_freefw;
-
-	err = ar9170_usb_open(&aru->common);
-	if (err)
-		goto err_unrx;
-
-	err = ar9170_register(&aru->common, &aru->udev->dev);
-
-	ar9170_usb_stop(&aru->common);
-	if (err)
-		goto err_unrx;
-
-	complete(&aru->firmware_loading_complete);
-	usb_put_dev(aru->udev);
-	return;
-
- err_unrx:
-	ar9170_usb_cancel_urbs(aru);
-
- err_freefw:
-	ar9170_usb_firmware_failed(aru);
-}
-
-static void ar9170_usb_firmware_inits(const struct firmware *fw,
-				      void *context)
-{
-	struct ar9170_usb *aru = context;
-	int err;
-
-	if (!fw) {
-		dev_err(&aru->udev->dev, "file with init values not found.\n");
-		ar9170_usb_firmware_failed(aru);
-		return;
-	}
-
-	aru->init_values = fw;
-
-	/* ok so we have the init values -- get code for two-stage */
-
-	err = request_firmware_nowait(THIS_MODULE, 1, "ar9170-2.fw",
-				      &aru->udev->dev, GFP_KERNEL, aru,
-				      ar9170_usb_firmware_finish);
-	if (err)
-		ar9170_usb_firmware_failed(aru);
-}
-
-static void ar9170_usb_firmware_step2(const struct firmware *fw, void *context)
-{
-	struct ar9170_usb *aru = context;
-	int err;
-
-	if (fw) {
-		ar9170_usb_firmware_finish(fw, context);
-		return;
-	}
-
-	if (aru->req_one_stage_fw) {
-		dev_err(&aru->udev->dev, "ar9170.fw firmware file "
-			"not found and is required for this device\n");
-		ar9170_usb_firmware_failed(aru);
-		return;
-	}
-
-	dev_err(&aru->udev->dev, "ar9170.fw firmware file "
-		"not found, trying old firmware...\n");
-
-	err = request_firmware_nowait(THIS_MODULE, 1, "ar9170-1.fw",
-				      &aru->udev->dev, GFP_KERNEL, aru,
-				      ar9170_usb_firmware_inits);
-	if (err)
-		ar9170_usb_firmware_failed(aru);
-}
-
-static bool ar9170_requires_one_stage(const struct usb_device_id *id)
-{
-	if (!id->driver_info)
-		return false;
-	if (id->driver_info == AR9170_REQ_FW1_ONLY)
-		return true;
-	return false;
-}
-
-static int ar9170_usb_probe(struct usb_interface *intf,
-			const struct usb_device_id *id)
-{
-	struct ar9170_usb *aru;
-	struct ar9170 *ar;
-	struct usb_device *udev;
-	int err;
-
-	aru = ar9170_alloc(sizeof(*aru));
-	if (IS_ERR(aru)) {
-		err = PTR_ERR(aru);
-		goto out;
-	}
-
-	udev = interface_to_usbdev(intf);
-	usb_get_dev(udev);
-	aru->udev = udev;
-	aru->intf = intf;
-	ar = &aru->common;
-
-	aru->req_one_stage_fw = ar9170_requires_one_stage(id);
-
-	usb_set_intfdata(intf, aru);
-	SET_IEEE80211_DEV(ar->hw, &intf->dev);
-
-	init_usb_anchor(&aru->rx_submitted);
-	init_usb_anchor(&aru->tx_pending);
-	init_usb_anchor(&aru->tx_submitted);
-	init_completion(&aru->cmd_wait);
-	init_completion(&aru->firmware_loading_complete);
-	spin_lock_init(&aru->tx_urb_lock);
-
-	aru->tx_pending_urbs = 0;
-	atomic_set(&aru->tx_submitted_urbs, 0);
-
-	aru->common.stop = ar9170_usb_stop;
-	aru->common.flush = ar9170_usb_flush;
-	aru->common.open = ar9170_usb_open;
-	aru->common.tx = ar9170_usb_tx;
-	aru->common.exec_cmd = ar9170_usb_exec_cmd;
-	aru->common.callback_cmd = ar9170_usb_callback_cmd;
-
-#ifdef CONFIG_PM
-	udev->reset_resume = 1;
-#endif /* CONFIG_PM */
-	err = ar9170_usb_reset(aru);
-	if (err)
-		goto err_freehw;
-
-	usb_get_dev(aru->udev);
-	return request_firmware_nowait(THIS_MODULE, 1, "ar9170.fw",
-				       &aru->udev->dev, GFP_KERNEL, aru,
-				       ar9170_usb_firmware_step2);
-err_freehw:
-	usb_set_intfdata(intf, NULL);
-	usb_put_dev(udev);
-	ieee80211_free_hw(ar->hw);
-out:
-	return err;
-}
-
-static void ar9170_usb_disconnect(struct usb_interface *intf)
-{
-	struct ar9170_usb *aru = usb_get_intfdata(intf);
-
-	if (!aru)
-		return;
-
-	aru->common.state = AR9170_IDLE;
-
-	wait_for_completion(&aru->firmware_loading_complete);
-
-	ar9170_unregister(&aru->common);
-	ar9170_usb_cancel_urbs(aru);
-
-	usb_put_dev(aru->udev);
-	usb_set_intfdata(intf, NULL);
-	ieee80211_free_hw(aru->common.hw);
-
-	release_firmware(aru->init_values);
-	release_firmware(aru->firmware);
-}
-
-#ifdef CONFIG_PM
-static int ar9170_suspend(struct usb_interface *intf,
-			  pm_message_t  message)
-{
-	struct ar9170_usb *aru = usb_get_intfdata(intf);
-
-	if (!aru)
-		return -ENODEV;
-
-	aru->common.state = AR9170_IDLE;
-	ar9170_usb_cancel_urbs(aru);
-
-	return 0;
-}
-
-static int ar9170_resume(struct usb_interface *intf)
-{
-	struct ar9170_usb *aru = usb_get_intfdata(intf);
-	int err;
-
-	if (!aru)
-		return -ENODEV;
-
-	usb_unpoison_anchored_urbs(&aru->rx_submitted);
-	usb_unpoison_anchored_urbs(&aru->tx_submitted);
-
-	err = ar9170_usb_init_device(aru);
-	if (err)
-		goto err_unrx;
-
-	err = ar9170_usb_open(&aru->common);
-	if (err)
-		goto err_unrx;
-
-	return 0;
-
-err_unrx:
-	aru->common.state = AR9170_IDLE;
-	ar9170_usb_cancel_urbs(aru);
-
-	return err;
-}
-#endif /* CONFIG_PM */
-
-static struct usb_driver ar9170_driver = {
-	.name = "ar9170usb",
-	.probe = ar9170_usb_probe,
-	.disconnect = ar9170_usb_disconnect,
-	.id_table = ar9170_usb_ids,
-	.soft_unbind = 1,
-#ifdef CONFIG_PM
-	.suspend = ar9170_suspend,
-	.resume = ar9170_resume,
-	.reset_resume = ar9170_resume,
-#endif /* CONFIG_PM */
-};
-
-static int __init ar9170_init(void)
-{
-	return usb_register(&ar9170_driver);
-}
-
-static void __exit ar9170_exit(void)
-{
-	usb_deregister(&ar9170_driver);
-}
-
-module_init(ar9170_init);
-module_exit(ar9170_exit);
diff --git a/drivers/net/wireless/ath/ar9170/usb.h b/drivers/net/wireless/ath/ar9170/usb.h
deleted file mode 100644
index 919b060..0000000
--- a/drivers/net/wireless/ath/ar9170/usb.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Atheros AR9170 USB driver
- *
- * Driver specific definitions
- *
- * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- * Copyright 2009, Christian Lamparter <chunkeey@web.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.  If not, see
- * http://www.gnu.org/licenses/.
- *
- * This file incorporates work covered by the following copyright and
- * permission notice:
- *    Copyright (c) 2007-2008 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 __USB_H
-#define __USB_H
-
-#include <linux/usb.h>
-#include <linux/completion.h>
-#include <linux/spinlock.h>
-#include <linux/leds.h>
-#include <net/cfg80211.h>
-#include <net/mac80211.h>
-#include <linux/firmware.h>
-#include "eeprom.h"
-#include "hw.h"
-#include "ar9170.h"
-
-#define AR9170_NUM_RX_URBS			16
-#define AR9170_NUM_TX_URBS			8
-
-struct firmware;
-
-struct ar9170_usb {
-	struct ar9170 common;
-	struct usb_device *udev;
-	struct usb_interface *intf;
-
-	struct usb_anchor rx_submitted;
-	struct usb_anchor tx_pending;
-	struct usb_anchor tx_submitted;
-
-	bool req_one_stage_fw;
-
-	spinlock_t tx_urb_lock;
-	atomic_t tx_submitted_urbs;
-	unsigned int tx_pending_urbs;
-
-	struct completion cmd_wait;
-	struct completion firmware_loading_complete;
-	int readlen;
-	u8 *readbuf;
-
-	const struct firmware *init_values;
-	const struct firmware *firmware;
-};
-
-#endif /* __USB_H */
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h
index a6c6a46..6d7105b 100644
--- a/drivers/net/wireless/ath/ath.h
+++ b/drivers/net/wireless/ath/ath.h
@@ -119,6 +119,7 @@
 	void (*write)(void *, u32 val, u32 reg_offset);
 	void (*enable_write_buffer)(void *);
 	void (*write_flush) (void *);
+	u32 (*rmw)(void *, u32 reg_offset, u32 set, u32 clr);
 };
 
 struct ath_common;
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
index ffcf44a..4361704 100644
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
@@ -44,6 +44,34 @@
 static const int m2ThreshExt_off = 127;
 
 
+static void ar5008_rf_bank_setup(u32 *bank, struct ar5416IniArray *array,
+				 int col)
+{
+	int i;
+
+	for (i = 0; i < array->ia_rows; i++)
+		bank[i] = INI_RA(array, i, col);
+}
+
+
+#define REG_WRITE_RF_ARRAY(iniarray, regData, regWr) \
+	ar5008_write_rf_array(ah, iniarray, regData, &(regWr))
+
+static void ar5008_write_rf_array(struct ath_hw *ah, struct ar5416IniArray *array,
+				  u32 *data, unsigned int *writecnt)
+{
+	int r;
+
+	ENABLE_REGWRITE_BUFFER(ah);
+
+	for (r = 0; r < array->ia_rows; r++) {
+		REG_WRITE(ah, INI_RA(array, r, 0), data[r]);
+		DO_DELAY(*writecnt);
+	}
+
+	REGWRITE_BUFFER_FLUSH(ah);
+}
+
 /**
  * ar5008_hw_phy_modify_rx_buffer() - perform analog swizzling of parameters
  * @rfbuf:
@@ -530,16 +558,16 @@
 	eepMinorRev = ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV);
 
 	/* Setup Bank 0 Write */
-	RF_BANK_SETUP(ah->analogBank0Data, &ah->iniBank0, 1);
+	ar5008_rf_bank_setup(ah->analogBank0Data, &ah->iniBank0, 1);
 
 	/* Setup Bank 1 Write */
-	RF_BANK_SETUP(ah->analogBank1Data, &ah->iniBank1, 1);
+	ar5008_rf_bank_setup(ah->analogBank1Data, &ah->iniBank1, 1);
 
 	/* Setup Bank 2 Write */
-	RF_BANK_SETUP(ah->analogBank2Data, &ah->iniBank2, 1);
+	ar5008_rf_bank_setup(ah->analogBank2Data, &ah->iniBank2, 1);
 
 	/* Setup Bank 6 Write */
-	RF_BANK_SETUP(ah->analogBank3Data, &ah->iniBank3,
+	ar5008_rf_bank_setup(ah->analogBank3Data, &ah->iniBank3,
 		      modesIndex);
 	{
 		int i;
@@ -569,7 +597,7 @@
 	}
 
 	/* Setup Bank 7 Setup */
-	RF_BANK_SETUP(ah->analogBank7Data, &ah->iniBank7, 1);
+	ar5008_rf_bank_setup(ah->analogBank7Data, &ah->iniBank7, 1);
 
 	/* Write Analog registers */
 	REG_WRITE_RF_ARRAY(&ah->iniBank0, ah->analogBank0Data,
@@ -729,6 +757,7 @@
 				 struct ath9k_channel *chan)
 {
 	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+	struct ath_common *common = ath9k_hw_common(ah);
 	int i, regWrites = 0;
 	struct ieee80211_channel *channel = chan->chan;
 	u32 modesIndex, freqIndex;
@@ -805,7 +834,8 @@
 		REG_WRITE(ah, reg, val);
 
 		if (reg >= 0x7800 && reg < 0x78a0
-		    && ah->config.analog_shiftreg) {
+		    && ah->config.analog_shiftreg
+		    && (common->bus_ops->ath_bus_type != ATH_USB)) {
 			udelay(100);
 		}
 
@@ -835,7 +865,8 @@
 		REG_WRITE(ah, reg, val);
 
 		if (reg >= 0x7800 && reg < 0x78a0
-		    && ah->config.analog_shiftreg) {
+		    && ah->config.analog_shiftreg
+		    && (common->bus_ops->ath_bus_type != ATH_USB)) {
 			udelay(100);
 		}
 
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
index 76388c6..cb611b2 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
@@ -26,6 +26,27 @@
 	IQ_MISMATCH_CAL = BIT(2),
 };
 
+static bool ar9002_hw_is_cal_supported(struct ath_hw *ah,
+				struct ath9k_channel *chan,
+				enum ar9002_cal_types cal_type)
+{
+	bool supported = false;
+	switch (ah->supp_cals & cal_type) {
+	case IQ_MISMATCH_CAL:
+		/* Run IQ Mismatch for non-CCK only */
+		if (!IS_CHAN_B(chan))
+			supported = true;
+		break;
+	case ADC_GAIN_CAL:
+	case ADC_DC_CAL:
+		/* Run ADC Gain Cal for non-CCK & non 2GHz-HT20 only */
+		if (!IS_CHAN_B(chan) &&
+		    !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan)))
+			supported = true;
+		break;
+	}
+	return supported;
+}
 
 static void ar9002_hw_setup_calibration(struct ath_hw *ah,
 					struct ath9k_cal_list *currCal)
@@ -858,26 +879,32 @@
 	if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {
 		ah->supp_cals = IQ_MISMATCH_CAL;
 
-		if (AR_SREV_9160_10_OR_LATER(ah) &&
-		    !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan))) {
+		if (AR_SREV_9160_10_OR_LATER(ah))
 			ah->supp_cals |= ADC_GAIN_CAL | ADC_DC_CAL;
 
+		if (AR_SREV_9287(ah))
+			ah->supp_cals &= ~ADC_GAIN_CAL;
 
+		if (ar9002_hw_is_cal_supported(ah, chan, ADC_GAIN_CAL)) {
 			INIT_CAL(&ah->adcgain_caldata);
 			INSERT_CAL(ah, &ah->adcgain_caldata);
 			ath_dbg(common, ATH_DBG_CALIBRATE,
-				"enabling ADC Gain Calibration.\n");
+					"enabling ADC Gain Calibration.\n");
+		}
 
+		if (ar9002_hw_is_cal_supported(ah, chan, ADC_DC_CAL)) {
 			INIT_CAL(&ah->adcdc_caldata);
 			INSERT_CAL(ah, &ah->adcdc_caldata);
 			ath_dbg(common, ATH_DBG_CALIBRATE,
-				"enabling ADC DC Calibration.\n");
+					"enabling ADC DC Calibration.\n");
 		}
 
-		INIT_CAL(&ah->iq_caldata);
-		INSERT_CAL(ah, &ah->iq_caldata);
-		ath_dbg(common, ATH_DBG_CALIBRATE,
-			"enabling IQ Calibration.\n");
+		if (ar9002_hw_is_cal_supported(ah, chan, IQ_MISMATCH_CAL)) {
+			INIT_CAL(&ah->iq_caldata);
+			INSERT_CAL(ah, &ah->iq_caldata);
+			ath_dbg(common, ATH_DBG_CALIBRATE,
+					"enabling IQ Calibration.\n");
+		}
 
 		ah->cal_list_curr = ah->cal_list;
 
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
index 399ab3b..8dd8f63 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
@@ -415,17 +415,6 @@
 	ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur);
 }
 
-static void ar9002_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds,
-					    u32 vmf)
-{
-	struct ar5416_desc *ads = AR5416DESC(ds);
-
-	if (vmf)
-		ads->ds_ctl0 |= AR_VirtMoreFrag;
-	else
-		ads->ds_ctl0 &= ~AR_VirtMoreFrag;
-}
-
 void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
 			  u32 size, u32 flags)
 {
@@ -459,5 +448,4 @@
 	ops->set11n_aggr_last = ar9002_hw_set11n_aggr_last;
 	ops->clr11n_aggr = ar9002_hw_clr11n_aggr;
 	ops->set11n_burstduration = ar9002_hw_set11n_burstduration;
-	ops->set11n_virtualmorefrag = ar9002_hw_set11n_virtualmorefrag;
 }
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
index 7f5de6e..aebaad9 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
@@ -66,8 +66,8 @@
 
 		/* rx/tx gain */
 		INIT_INI_ARRAY(&ah->iniModesRxGain,
-				ar9485_common_rx_gain_1_1,
-				ARRAY_SIZE(ar9485_common_rx_gain_1_1), 2);
+				ar9485Common_wo_xlna_rx_gain_1_1,
+				ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), 2);
 		INIT_INI_ARRAY(&ah->iniModesTxGain,
 				ar9485_modes_lowest_ob_db_tx_gain_1_1,
 				ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1),
@@ -88,66 +88,6 @@
 				ar9485_1_1_pcie_phy_clkreq_disable_L1,
 				ARRAY_SIZE(ar9485_1_1_pcie_phy_clkreq_disable_L1),
 				2);
-	} else if (AR_SREV_9485(ah)) {
-		/* mac */
-		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
-		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
-				ar9485_1_0_mac_core,
-				ARRAY_SIZE(ar9485_1_0_mac_core), 2);
-		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
-				ar9485_1_0_mac_postamble,
-				ARRAY_SIZE(ar9485_1_0_mac_postamble), 5);
-
-		/* bb */
-		INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], ar9485_1_0,
-				ARRAY_SIZE(ar9485_1_0), 2);
-		INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
-				ar9485_1_0_baseband_core,
-				ARRAY_SIZE(ar9485_1_0_baseband_core), 2);
-		INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
-				ar9485_1_0_baseband_postamble,
-				ARRAY_SIZE(ar9485_1_0_baseband_postamble), 5);
-
-		/* radio */
-		INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0);
-		INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
-				ar9485_1_0_radio_core,
-				ARRAY_SIZE(ar9485_1_0_radio_core), 2);
-		INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],
-				ar9485_1_0_radio_postamble,
-				ARRAY_SIZE(ar9485_1_0_radio_postamble), 2);
-
-		/* soc */
-		INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE],
-				ar9485_1_0_soc_preamble,
-				ARRAY_SIZE(ar9485_1_0_soc_preamble), 2);
-		INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0);
-		INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], NULL, 0, 0);
-
-		/* rx/tx gain */
-		INIT_INI_ARRAY(&ah->iniModesRxGain,
-				ar9485Common_rx_gain_1_0,
-				ARRAY_SIZE(ar9485Common_rx_gain_1_0), 2);
-		INIT_INI_ARRAY(&ah->iniModesTxGain,
-				ar9485Modes_lowest_ob_db_tx_gain_1_0,
-				ARRAY_SIZE(ar9485Modes_lowest_ob_db_tx_gain_1_0),
-				5);
-
-		/* Load PCIE SERDES settings from INI */
-
-		/* Awake Setting */
-
-		INIT_INI_ARRAY(&ah->iniPcieSerdes,
-				ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1,
-				ARRAY_SIZE(ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1),
-				2);
-
-		/* Sleep Setting */
-
-		INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
-				ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1,
-				ARRAY_SIZE(ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1),
-				2);
 	} else {
 		/* mac */
 		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
@@ -228,11 +168,6 @@
 				       ar9485_modes_lowest_ob_db_tx_gain_1_1,
 				       ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1),
 				       5);
-		else if (AR_SREV_9485(ah))
-			INIT_INI_ARRAY(&ah->iniModesTxGain,
-				       ar9485Modes_lowest_ob_db_tx_gain_1_0,
-				       ARRAY_SIZE(ar9485Modes_lowest_ob_db_tx_gain_1_0),
-				       5);
 		else
 			INIT_INI_ARRAY(&ah->iniModesTxGain,
 				       ar9300Modes_lowest_ob_db_tx_gain_table_2p2,
@@ -245,11 +180,6 @@
 				       ar9485Modes_high_ob_db_tx_gain_1_1,
 				       ARRAY_SIZE(ar9485Modes_high_ob_db_tx_gain_1_1),
 				       5);
-		else if (AR_SREV_9485(ah))
-			INIT_INI_ARRAY(&ah->iniModesTxGain,
-				       ar9485Modes_high_ob_db_tx_gain_1_0,
-				       ARRAY_SIZE(ar9485Modes_high_ob_db_tx_gain_1_0),
-				       5);
 		else
 			INIT_INI_ARRAY(&ah->iniModesTxGain,
 				       ar9300Modes_high_ob_db_tx_gain_table_2p2,
@@ -262,11 +192,6 @@
 				       ar9485Modes_low_ob_db_tx_gain_1_1,
 				       ARRAY_SIZE(ar9485Modes_low_ob_db_tx_gain_1_1),
 				       5);
-		else if (AR_SREV_9485(ah))
-			INIT_INI_ARRAY(&ah->iniModesTxGain,
-				       ar9485Modes_low_ob_db_tx_gain_1_0,
-				       ARRAY_SIZE(ar9485Modes_low_ob_db_tx_gain_1_0),
-				       5);
 		else
 			INIT_INI_ARRAY(&ah->iniModesTxGain,
 				       ar9300Modes_low_ob_db_tx_gain_table_2p2,
@@ -279,11 +204,6 @@
 				       ar9485Modes_high_power_tx_gain_1_1,
 				       ARRAY_SIZE(ar9485Modes_high_power_tx_gain_1_1),
 				       5);
-		else if (AR_SREV_9485(ah))
-			INIT_INI_ARRAY(&ah->iniModesTxGain,
-				       ar9485Modes_high_power_tx_gain_1_0,
-				       ARRAY_SIZE(ar9485Modes_high_power_tx_gain_1_0),
-				       5);
 		else
 			INIT_INI_ARRAY(&ah->iniModesTxGain,
 				       ar9300Modes_high_power_tx_gain_table_2p2,
@@ -300,13 +220,8 @@
 	default:
 		if (AR_SREV_9485_11(ah))
 			INIT_INI_ARRAY(&ah->iniModesRxGain,
-				       ar9485_common_rx_gain_1_1,
-				       ARRAY_SIZE(ar9485_common_rx_gain_1_1),
-				       2);
-		else if (AR_SREV_9485(ah))
-			INIT_INI_ARRAY(&ah->iniModesRxGain,
-				       ar9485Common_rx_gain_1_0,
-				       ARRAY_SIZE(ar9485Common_rx_gain_1_0),
+				       ar9485Common_wo_xlna_rx_gain_1_1,
+				       ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1),
 				       2);
 		else
 			INIT_INI_ARRAY(&ah->iniModesRxGain,
@@ -320,11 +235,6 @@
 				       ar9485Common_wo_xlna_rx_gain_1_1,
 				       ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1),
 				       2);
-		else if (AR_SREV_9485(ah))
-			INIT_INI_ARRAY(&ah->iniModesRxGain,
-				       ar9485Common_wo_xlna_rx_gain_1_0,
-				       ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_0),
-				       2);
 		else
 			INIT_INI_ARRAY(&ah->iniModesRxGain,
 				       ar9300Common_wo_xlna_rx_gain_table_2p2,
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
index 038a0cb..724ac24 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
@@ -485,17 +485,6 @@
 
 }
 
-static void ar9003_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds,
-					     u32 vmf)
-{
-	struct ar9003_txc *ads = (struct ar9003_txc *) ds;
-
-	if (vmf)
-		ads->ctl11 |=  AR_VirtMoreFrag;
-	else
-		ads->ctl11 &= ~AR_VirtMoreFrag;
-}
-
 void ar9003_hw_set_paprd_txdesc(struct ath_hw *ah, void *ds, u8 chains)
 {
 	struct ar9003_txc *ads = ds;
@@ -521,7 +510,6 @@
 	ops->set11n_aggr_last = ar9003_hw_set11n_aggr_last;
 	ops->clr11n_aggr = ar9003_hw_clr11n_aggr;
 	ops->set11n_burstduration = ar9003_hw_set11n_burstduration;
-	ops->set11n_virtualmorefrag = ar9003_hw_set11n_virtualmorefrag;
 }
 
 void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size)
diff --git a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h
index 71cc0a3..f91f73e 100644
--- a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h
@@ -17,931 +17,6 @@
 #ifndef INITVALS_9485_H
 #define INITVALS_9485_H
 
-static const u32 ar9485Common_1_0[][2] = {
-	/*   Addr     allmodes */
-	{0x00007010, 0x00000022},
-	{0x00007020, 0x00000000},
-	{0x00007034, 0x00000002},
-	{0x00007038, 0x000004c2},
-};
-
-static const u32 ar9485_1_0_mac_postamble[][5] = {
-	/* Addr     5G_HT20     5G_HT40     2G_HT40     2G_HT20    */
-	{0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160},
-	{0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c},
-	{0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38},
-	{0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00},
-	{0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b},
-	{0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810},
-	{0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a},
-	{0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440},
-};
-
-static const u32 ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1[][2] = {
-	/*   Addr     allmodes */
-	{0x00018c00, 0x10212e5e},
-	{0x00018c04, 0x000801d8},
-	{0x00018c08, 0x0000580c},
-};
-
-static const u32 ar9485Common_wo_xlna_rx_gain_1_0[][2] = {
-	/*   Addr     allmodes */
-	{0x0000a000, 0x00010000},
-	{0x0000a004, 0x00030002},
-	{0x0000a008, 0x00050004},
-	{0x0000a00c, 0x00810080},
-	{0x0000a010, 0x01800082},
-	{0x0000a014, 0x01820181},
-	{0x0000a018, 0x01840183},
-	{0x0000a01c, 0x01880185},
-	{0x0000a020, 0x018a0189},
-	{0x0000a024, 0x02850284},
-	{0x0000a028, 0x02890288},
-	{0x0000a02c, 0x03850384},
-	{0x0000a030, 0x03890388},
-	{0x0000a034, 0x038b038a},
-	{0x0000a038, 0x038d038c},
-	{0x0000a03c, 0x03910390},
-	{0x0000a040, 0x03930392},
-	{0x0000a044, 0x03950394},
-	{0x0000a048, 0x00000396},
-	{0x0000a04c, 0x00000000},
-	{0x0000a050, 0x00000000},
-	{0x0000a054, 0x00000000},
-	{0x0000a058, 0x00000000},
-	{0x0000a05c, 0x00000000},
-	{0x0000a060, 0x00000000},
-	{0x0000a064, 0x00000000},
-	{0x0000a068, 0x00000000},
-	{0x0000a06c, 0x00000000},
-	{0x0000a070, 0x00000000},
-	{0x0000a074, 0x00000000},
-	{0x0000a078, 0x00000000},
-	{0x0000a07c, 0x00000000},
-	{0x0000a080, 0x28282828},
-	{0x0000a084, 0x28282828},
-	{0x0000a088, 0x28282828},
-	{0x0000a08c, 0x28282828},
-	{0x0000a090, 0x28282828},
-	{0x0000a094, 0x21212128},
-	{0x0000a098, 0x171c1c1c},
-	{0x0000a09c, 0x02020212},
-	{0x0000a0a0, 0x00000202},
-	{0x0000a0a4, 0x00000000},
-	{0x0000a0a8, 0x00000000},
-	{0x0000a0ac, 0x00000000},
-	{0x0000a0b0, 0x00000000},
-	{0x0000a0b4, 0x00000000},
-	{0x0000a0b8, 0x00000000},
-	{0x0000a0bc, 0x00000000},
-	{0x0000a0c0, 0x001f0000},
-	{0x0000a0c4, 0x111f1100},
-	{0x0000a0c8, 0x111d111e},
-	{0x0000a0cc, 0x111b111c},
-	{0x0000a0d0, 0x22032204},
-	{0x0000a0d4, 0x22012202},
-	{0x0000a0d8, 0x221f2200},
-	{0x0000a0dc, 0x221d221e},
-	{0x0000a0e0, 0x33013302},
-	{0x0000a0e4, 0x331f3300},
-	{0x0000a0e8, 0x4402331e},
-	{0x0000a0ec, 0x44004401},
-	{0x0000a0f0, 0x441e441f},
-	{0x0000a0f4, 0x55015502},
-	{0x0000a0f8, 0x551f5500},
-	{0x0000a0fc, 0x6602551e},
-	{0x0000a100, 0x66006601},
-	{0x0000a104, 0x661e661f},
-	{0x0000a108, 0x7703661d},
-	{0x0000a10c, 0x77017702},
-	{0x0000a110, 0x00007700},
-	{0x0000a114, 0x00000000},
-	{0x0000a118, 0x00000000},
-	{0x0000a11c, 0x00000000},
-	{0x0000a120, 0x00000000},
-	{0x0000a124, 0x00000000},
-	{0x0000a128, 0x00000000},
-	{0x0000a12c, 0x00000000},
-	{0x0000a130, 0x00000000},
-	{0x0000a134, 0x00000000},
-	{0x0000a138, 0x00000000},
-	{0x0000a13c, 0x00000000},
-	{0x0000a140, 0x001f0000},
-	{0x0000a144, 0x111f1100},
-	{0x0000a148, 0x111d111e},
-	{0x0000a14c, 0x111b111c},
-	{0x0000a150, 0x22032204},
-	{0x0000a154, 0x22012202},
-	{0x0000a158, 0x221f2200},
-	{0x0000a15c, 0x221d221e},
-	{0x0000a160, 0x33013302},
-	{0x0000a164, 0x331f3300},
-	{0x0000a168, 0x4402331e},
-	{0x0000a16c, 0x44004401},
-	{0x0000a170, 0x441e441f},
-	{0x0000a174, 0x55015502},
-	{0x0000a178, 0x551f5500},
-	{0x0000a17c, 0x6602551e},
-	{0x0000a180, 0x66006601},
-	{0x0000a184, 0x661e661f},
-	{0x0000a188, 0x7703661d},
-	{0x0000a18c, 0x77017702},
-	{0x0000a190, 0x00007700},
-	{0x0000a194, 0x00000000},
-	{0x0000a198, 0x00000000},
-	{0x0000a19c, 0x00000000},
-	{0x0000a1a0, 0x00000000},
-	{0x0000a1a4, 0x00000000},
-	{0x0000a1a8, 0x00000000},
-	{0x0000a1ac, 0x00000000},
-	{0x0000a1b0, 0x00000000},
-	{0x0000a1b4, 0x00000000},
-	{0x0000a1b8, 0x00000000},
-	{0x0000a1bc, 0x00000000},
-	{0x0000a1c0, 0x00000000},
-	{0x0000a1c4, 0x00000000},
-	{0x0000a1c8, 0x00000000},
-	{0x0000a1cc, 0x00000000},
-	{0x0000a1d0, 0x00000000},
-	{0x0000a1d4, 0x00000000},
-	{0x0000a1d8, 0x00000000},
-	{0x0000a1dc, 0x00000000},
-	{0x0000a1e0, 0x00000000},
-	{0x0000a1e4, 0x00000000},
-	{0x0000a1e8, 0x00000000},
-	{0x0000a1ec, 0x00000000},
-	{0x0000a1f0, 0x00000396},
-	{0x0000a1f4, 0x00000396},
-	{0x0000a1f8, 0x00000396},
-	{0x0000a1fc, 0x00000296},
-};
-
-static const u32 ar9485Modes_high_power_tx_gain_1_0[][5] = {
-	/*   Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20 */
-	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
-	{0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
-	{0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002},
-	{0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004},
-	{0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200},
-	{0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202},
-	{0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400},
-	{0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402},
-	{0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404},
-	{0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603},
-	{0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605},
-	{0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03},
-	{0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04},
-	{0x0000a530, 0x48023ec6, 0x48023ec6, 0x2e000a20, 0x2e000a20},
-	{0x0000a534, 0x4d023f01, 0x4d023f01, 0x34000e20, 0x34000e20},
-	{0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000e22, 0x38000e22},
-	{0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3c000e24, 0x3c000e24},
-	{0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x40000e26, 0x40000e26},
-	{0x0000a544, 0x6502feca, 0x6502feca, 0x43001640, 0x43001640},
-	{0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46001660, 0x46001660},
-	{0x0000a54c, 0x7203feca, 0x7203feca, 0x49001861, 0x49001861},
-	{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4c001a81, 0x4c001a81},
-	{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4f001a83, 0x4f001a83},
-	{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x54001c85, 0x54001c85},
-	{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x58001ce5, 0x58001ce5},
-	{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5b001ce9, 0x5b001ce9},
-	{0x0000a564, 0x960fffcb, 0x960fffcb, 0x60001eeb, 0x60001eeb},
-	{0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
-	{0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
-	{0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
-	{0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
-	{0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
-	{0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
-	{0x00016044, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db},
-};
-
-static const u32 ar9485_1_0[][2] = {
-	/*  Addr      allmodes */
-	{0x0000a580, 0x00000000},
-	{0x0000a584, 0x00000000},
-	{0x0000a588, 0x00000000},
-	{0x0000a58c, 0x00000000},
-	{0x0000a590, 0x00000000},
-	{0x0000a594, 0x00000000},
-	{0x0000a598, 0x00000000},
-	{0x0000a59c, 0x00000000},
-	{0x0000a5a0, 0x00000000},
-	{0x0000a5a4, 0x00000000},
-	{0x0000a5a8, 0x00000000},
-	{0x0000a5ac, 0x00000000},
-	{0x0000a5b0, 0x00000000},
-	{0x0000a5b4, 0x00000000},
-	{0x0000a5b8, 0x00000000},
-	{0x0000a5bc, 0x00000000},
-};
-
-static const u32 ar9485_1_0_radio_core[][2] = {
-	/*   Addr     allmodes */
-	{0x00016000, 0x36db6db6},
-	{0x00016004, 0x6db6db40},
-	{0x00016008, 0x73800000},
-	{0x0001600c, 0x00000000},
-	{0x00016040, 0x7f80fff8},
-	{0x00016048, 0x6c92426e},
-	{0x0001604c, 0x000f0278},
-	{0x00016050, 0x6db6db6c},
-	{0x00016054, 0x6db60000},
-	{0x00016080, 0x00080000},
-	{0x00016084, 0x0e48048c},
-	{0x00016088, 0x14214514},
-	{0x0001608c, 0x119f081e},
-	{0x00016090, 0x24926490},
-	{0x00016098, 0xd28b3330},
-	{0x000160a0, 0xc2108ffe},
-	{0x000160a4, 0x812fc370},
-	{0x000160a8, 0x423c8000},
-	{0x000160b4, 0x92480040},
-	{0x000160c0, 0x006db6db},
-	{0x000160c4, 0x0186db60},
-	{0x000160c8, 0x6db6db6c},
-	{0x000160cc, 0x6de6fbe0},
-	{0x000160d0, 0xf7dfcf3c},
-	{0x00016100, 0x04cb0001},
-	{0x00016104, 0xfff80015},
-	{0x00016108, 0x00080010},
-	{0x00016144, 0x01884080},
-	{0x00016148, 0x00008040},
-	{0x00016180, 0x08453333},
-	{0x00016184, 0x18e82f01},
-	{0x00016188, 0x00000000},
-	{0x0001618c, 0x00000000},
-	{0x00016240, 0x08400000},
-	{0x00016244, 0x1bf90f00},
-	{0x00016248, 0x00000000},
-	{0x0001624c, 0x00000000},
-	{0x00016280, 0x01000015},
-	{0x00016284, 0x00d30000},
-	{0x00016288, 0x00318000},
-	{0x0001628c, 0x50000000},
-	{0x00016290, 0x4b96210f},
-	{0x00016380, 0x00000000},
-	{0x00016384, 0x00000000},
-	{0x00016388, 0x00800700},
-	{0x0001638c, 0x00800700},
-	{0x00016390, 0x00800700},
-	{0x00016394, 0x00000000},
-	{0x00016398, 0x00000000},
-	{0x0001639c, 0x00000000},
-	{0x000163a0, 0x00000001},
-	{0x000163a4, 0x00000001},
-	{0x000163a8, 0x00000000},
-	{0x000163ac, 0x00000000},
-	{0x000163b0, 0x00000000},
-	{0x000163b4, 0x00000000},
-	{0x000163b8, 0x00000000},
-	{0x000163bc, 0x00000000},
-	{0x000163c0, 0x000000a0},
-	{0x000163c4, 0x000c0000},
-	{0x000163c8, 0x14021402},
-	{0x000163cc, 0x00001402},
-	{0x000163d0, 0x00000000},
-	{0x000163d4, 0x00000000},
-	{0x00016c40, 0x1319c178},
-	{0x00016c44, 0x10000000},
-};
-
-static const u32 ar9485Modes_lowest_ob_db_tx_gain_1_0[][5] = {
-	/*  Addr       5G_HT20     5G_HT40     2G_HT40     2G_HT20 */
-	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
-	{0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
-	{0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002},
-	{0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004},
-	{0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200},
-	{0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202},
-	{0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400},
-	{0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402},
-	{0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404},
-	{0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603},
-	{0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605},
-	{0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03},
-	{0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04},
-	{0x0000a530, 0x48023ec6, 0x48023ec6, 0x2e000a20, 0x2e000a20},
-	{0x0000a534, 0x4d023f01, 0x4d023f01, 0x34000e20, 0x34000e20},
-	{0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000e22, 0x38000e22},
-	{0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3c000e24, 0x3c000e24},
-	{0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x40000e26, 0x40000e26},
-	{0x0000a544, 0x6502feca, 0x6502feca, 0x43001640, 0x43001640},
-	{0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46001660, 0x46001660},
-	{0x0000a54c, 0x7203feca, 0x7203feca, 0x49001861, 0x49001861},
-	{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4c001a81, 0x4c001a81},
-	{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4f001a83, 0x4f001a83},
-	{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x54001c85, 0x54001c85},
-	{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x58001ce5, 0x58001ce5},
-	{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5b001ce9, 0x5b001ce9},
-	{0x0000a564, 0x960fffcb, 0x960fffcb, 0x60001eeb, 0x60001eeb},
-	{0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
-	{0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
-	{0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
-	{0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
-	{0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
-	{0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
-	{0x00016044, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db},
-};
-
-static const u32 ar9485_1_0_baseband_core[][2] = {
-	/* Addr      allmodes  */
-	{0x00009800, 0xafe68e30},
-	{0x00009804, 0xfd14e000},
-	{0x00009808, 0x9c0a8f6b},
-	{0x0000980c, 0x04800000},
-	{0x00009814, 0x9280c00a},
-	{0x00009818, 0x00000000},
-	{0x0000981c, 0x00020028},
-	{0x00009834, 0x5f3ca3de},
-	{0x00009838, 0x0108ecff},
-	{0x0000983c, 0x14750600},
-	{0x00009880, 0x201fff00},
-	{0x00009884, 0x00001042},
-	{0x000098a4, 0x00200400},
-	{0x000098b0, 0x52440bbe},
-	{0x000098bc, 0x00000002},
-	{0x000098d0, 0x004b6a8e},
-	{0x000098d4, 0x00000820},
-	{0x000098dc, 0x00000000},
-	{0x000098f0, 0x00000000},
-	{0x000098f4, 0x00000000},
-	{0x00009c04, 0x00000000},
-	{0x00009c08, 0x03200000},
-	{0x00009c0c, 0x00000000},
-	{0x00009c10, 0x00000000},
-	{0x00009c14, 0x00046384},
-	{0x00009c18, 0x05b6b440},
-	{0x00009c1c, 0x00b6b440},
-	{0x00009d00, 0xc080a333},
-	{0x00009d04, 0x40206c10},
-	{0x00009d08, 0x009c4060},
-	{0x00009d0c, 0x1883800a},
-	{0x00009d10, 0x01834061},
-	{0x00009d14, 0x00c00400},
-	{0x00009d18, 0x00000000},
-	{0x00009d1c, 0x00000000},
-	{0x00009e08, 0x0038233c},
-	{0x00009e24, 0x990bb515},
-	{0x00009e28, 0x0a6f0000},
-	{0x00009e30, 0x06336f77},
-	{0x00009e34, 0x6af6532f},
-	{0x00009e38, 0x0cc80c00},
-	{0x00009e40, 0x0d261820},
-	{0x00009e4c, 0x00001004},
-	{0x00009e50, 0x00ff03f1},
-	{0x00009fc0, 0x80be4788},
-	{0x00009fc4, 0x0001efb5},
-	{0x00009fcc, 0x40000014},
-	{0x0000a20c, 0x00000000},
-	{0x0000a210, 0x00000000},
-	{0x0000a220, 0x00000000},
-	{0x0000a224, 0x00000000},
-	{0x0000a228, 0x10002310},
-	{0x0000a23c, 0x00000000},
-	{0x0000a244, 0x0c000000},
-	{0x0000a2a0, 0x00000001},
-	{0x0000a2c0, 0x00000001},
-	{0x0000a2c8, 0x00000000},
-	{0x0000a2cc, 0x18c43433},
-	{0x0000a2d4, 0x00000000},
-	{0x0000a2dc, 0x00000000},
-	{0x0000a2e0, 0x00000000},
-	{0x0000a2e4, 0x00000000},
-	{0x0000a2e8, 0x00000000},
-	{0x0000a2ec, 0x00000000},
-	{0x0000a2f0, 0x00000000},
-	{0x0000a2f4, 0x00000000},
-	{0x0000a2f8, 0x00000000},
-	{0x0000a344, 0x00000000},
-	{0x0000a34c, 0x00000000},
-	{0x0000a350, 0x0000a000},
-	{0x0000a364, 0x00000000},
-	{0x0000a370, 0x00000000},
-	{0x0000a390, 0x00000001},
-	{0x0000a394, 0x00000444},
-	{0x0000a398, 0x001f0e0f},
-	{0x0000a39c, 0x0075393f},
-	{0x0000a3a0, 0xb79f6427},
-	{0x0000a3a4, 0x00000000},
-	{0x0000a3a8, 0xaaaaaaaa},
-	{0x0000a3ac, 0x3c466478},
-	{0x0000a3c0, 0x20202020},
-	{0x0000a3c4, 0x22222220},
-	{0x0000a3c8, 0x20200020},
-	{0x0000a3cc, 0x20202020},
-	{0x0000a3d0, 0x20202020},
-	{0x0000a3d4, 0x20202020},
-	{0x0000a3d8, 0x20202020},
-	{0x0000a3dc, 0x20202020},
-	{0x0000a3e0, 0x20202020},
-	{0x0000a3e4, 0x20202020},
-	{0x0000a3e8, 0x20202020},
-	{0x0000a3ec, 0x20202020},
-	{0x0000a3f0, 0x00000000},
-	{0x0000a3f4, 0x00000006},
-	{0x0000a3f8, 0x0cdbd380},
-	{0x0000a3fc, 0x000f0f01},
-	{0x0000a400, 0x8fa91f01},
-	{0x0000a404, 0x00000000},
-	{0x0000a408, 0x0e79e5c6},
-	{0x0000a40c, 0x00820820},
-	{0x0000a414, 0x1ce739ce},
-	{0x0000a418, 0x2d0011ce},
-	{0x0000a41c, 0x1ce739ce},
-	{0x0000a420, 0x000001ce},
-	{0x0000a424, 0x1ce739ce},
-	{0x0000a428, 0x000001ce},
-	{0x0000a42c, 0x1ce739ce},
-	{0x0000a430, 0x1ce739ce},
-	{0x0000a434, 0x00000000},
-	{0x0000a438, 0x00001801},
-	{0x0000a43c, 0x00000000},
-	{0x0000a440, 0x00000000},
-	{0x0000a444, 0x00000000},
-	{0x0000a448, 0x04000000},
-	{0x0000a44c, 0x00000001},
-	{0x0000a450, 0x00010000},
-	{0x0000a458, 0x00000000},
-	{0x0000a5c4, 0x3fad9d74},
-	{0x0000a5c8, 0x0048060a},
-	{0x0000a5cc, 0x00000637},
-	{0x0000a760, 0x03020100},
-	{0x0000a764, 0x09080504},
-	{0x0000a768, 0x0d0c0b0a},
-	{0x0000a76c, 0x13121110},
-	{0x0000a770, 0x31301514},
-	{0x0000a774, 0x35343332},
-	{0x0000a778, 0x00000036},
-	{0x0000a780, 0x00000838},
-	{0x0000a7c0, 0x00000000},
-	{0x0000a7c4, 0xfffffffc},
-	{0x0000a7c8, 0x00000000},
-	{0x0000a7cc, 0x00000000},
-	{0x0000a7d0, 0x00000000},
-	{0x0000a7d4, 0x00000004},
-	{0x0000a7dc, 0x00000001},
-};
-
-static const u32 ar9485Modes_high_ob_db_tx_gain_1_0[][5] = {
-	/* Addr        5G_HT20     5G_HT40     2G_HT40    2G_HT20  */
-	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
-	{0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
-	{0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002},
-	{0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004},
-	{0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200},
-	{0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202},
-	{0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400},
-	{0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402},
-	{0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404},
-	{0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603},
-	{0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605},
-	{0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03},
-	{0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04},
-	{0x0000a530, 0x48023ec6, 0x48023ec6, 0x2e000a20, 0x2e000a20},
-	{0x0000a534, 0x4d023f01, 0x4d023f01, 0x34000e20, 0x34000e20},
-	{0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000e22, 0x38000e22},
-	{0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3c000e24, 0x3c000e24},
-	{0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x40000e26, 0x40000e26},
-	{0x0000a544, 0x6502feca, 0x6502feca, 0x43001640, 0x43001640},
-	{0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46001660, 0x46001660},
-	{0x0000a54c, 0x7203feca, 0x7203feca, 0x49001861, 0x49001861},
-	{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4c001a81, 0x4c001a81},
-	{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4f001a83, 0x4f001a83},
-	{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x54001c85, 0x54001c85},
-	{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x58001ce5, 0x58001ce5},
-	{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5b001ce9, 0x5b001ce9},
-	{0x0000a564, 0x960fffcb, 0x960fffcb, 0x60001eeb, 0x60001eeb},
-	{0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
-	{0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
-	{0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
-	{0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
-	{0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
-	{0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
-	{0x00016044, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db},
-};
-
-static const u32 ar9485Common_rx_gain_1_0[][2] = {
-	/* Addr      allmodes  */
-	{0x0000a000, 0x00010000},
-	{0x0000a004, 0x00030002},
-	{0x0000a008, 0x00050004},
-	{0x0000a00c, 0x00810080},
-	{0x0000a010, 0x01800082},
-	{0x0000a014, 0x01820181},
-	{0x0000a018, 0x01840183},
-	{0x0000a01c, 0x01880185},
-	{0x0000a020, 0x018a0189},
-	{0x0000a024, 0x02850284},
-	{0x0000a028, 0x02890288},
-	{0x0000a02c, 0x03850384},
-	{0x0000a030, 0x03890388},
-	{0x0000a034, 0x038b038a},
-	{0x0000a038, 0x038d038c},
-	{0x0000a03c, 0x03910390},
-	{0x0000a040, 0x03930392},
-	{0x0000a044, 0x03950394},
-	{0x0000a048, 0x00000396},
-	{0x0000a04c, 0x00000000},
-	{0x0000a050, 0x00000000},
-	{0x0000a054, 0x00000000},
-	{0x0000a058, 0x00000000},
-	{0x0000a05c, 0x00000000},
-	{0x0000a060, 0x00000000},
-	{0x0000a064, 0x00000000},
-	{0x0000a068, 0x00000000},
-	{0x0000a06c, 0x00000000},
-	{0x0000a070, 0x00000000},
-	{0x0000a074, 0x00000000},
-	{0x0000a078, 0x00000000},
-	{0x0000a07c, 0x00000000},
-	{0x0000a080, 0x28282828},
-	{0x0000a084, 0x28282828},
-	{0x0000a088, 0x28282828},
-	{0x0000a08c, 0x28282828},
-	{0x0000a090, 0x28282828},
-	{0x0000a094, 0x21212128},
-	{0x0000a098, 0x171c1c1c},
-	{0x0000a09c, 0x02020212},
-	{0x0000a0a0, 0x00000202},
-	{0x0000a0a4, 0x00000000},
-	{0x0000a0a8, 0x00000000},
-	{0x0000a0ac, 0x00000000},
-	{0x0000a0b0, 0x00000000},
-	{0x0000a0b4, 0x00000000},
-	{0x0000a0b8, 0x00000000},
-	{0x0000a0bc, 0x00000000},
-	{0x0000a0c0, 0x001f0000},
-	{0x0000a0c4, 0x111f1100},
-	{0x0000a0c8, 0x111d111e},
-	{0x0000a0cc, 0x111b111c},
-	{0x0000a0d0, 0x22032204},
-	{0x0000a0d4, 0x22012202},
-	{0x0000a0d8, 0x221f2200},
-	{0x0000a0dc, 0x221d221e},
-	{0x0000a0e0, 0x33013302},
-	{0x0000a0e4, 0x331f3300},
-	{0x0000a0e8, 0x4402331e},
-	{0x0000a0ec, 0x44004401},
-	{0x0000a0f0, 0x441e441f},
-	{0x0000a0f4, 0x55015502},
-	{0x0000a0f8, 0x551f5500},
-	{0x0000a0fc, 0x6602551e},
-	{0x0000a100, 0x66006601},
-	{0x0000a104, 0x661e661f},
-	{0x0000a108, 0x7703661d},
-	{0x0000a10c, 0x77017702},
-	{0x0000a110, 0x00007700},
-	{0x0000a114, 0x00000000},
-	{0x0000a118, 0x00000000},
-	{0x0000a11c, 0x00000000},
-	{0x0000a120, 0x00000000},
-	{0x0000a124, 0x00000000},
-	{0x0000a128, 0x00000000},
-	{0x0000a12c, 0x00000000},
-	{0x0000a130, 0x00000000},
-	{0x0000a134, 0x00000000},
-	{0x0000a138, 0x00000000},
-	{0x0000a13c, 0x00000000},
-	{0x0000a140, 0x001f0000},
-	{0x0000a144, 0x111f1100},
-	{0x0000a148, 0x111d111e},
-	{0x0000a14c, 0x111b111c},
-	{0x0000a150, 0x22032204},
-	{0x0000a154, 0x22012202},
-	{0x0000a158, 0x221f2200},
-	{0x0000a15c, 0x221d221e},
-	{0x0000a160, 0x33013302},
-	{0x0000a164, 0x331f3300},
-	{0x0000a168, 0x4402331e},
-	{0x0000a16c, 0x44004401},
-	{0x0000a170, 0x441e441f},
-	{0x0000a174, 0x55015502},
-	{0x0000a178, 0x551f5500},
-	{0x0000a17c, 0x6602551e},
-	{0x0000a180, 0x66006601},
-	{0x0000a184, 0x661e661f},
-	{0x0000a188, 0x7703661d},
-	{0x0000a18c, 0x77017702},
-	{0x0000a190, 0x00007700},
-	{0x0000a194, 0x00000000},
-	{0x0000a198, 0x00000000},
-	{0x0000a19c, 0x00000000},
-	{0x0000a1a0, 0x00000000},
-	{0x0000a1a4, 0x00000000},
-	{0x0000a1a8, 0x00000000},
-	{0x0000a1ac, 0x00000000},
-	{0x0000a1b0, 0x00000000},
-	{0x0000a1b4, 0x00000000},
-	{0x0000a1b8, 0x00000000},
-	{0x0000a1bc, 0x00000000},
-	{0x0000a1c0, 0x00000000},
-	{0x0000a1c4, 0x00000000},
-	{0x0000a1c8, 0x00000000},
-	{0x0000a1cc, 0x00000000},
-	{0x0000a1d0, 0x00000000},
-	{0x0000a1d4, 0x00000000},
-	{0x0000a1d8, 0x00000000},
-	{0x0000a1dc, 0x00000000},
-	{0x0000a1e0, 0x00000000},
-	{0x0000a1e4, 0x00000000},
-	{0x0000a1e8, 0x00000000},
-	{0x0000a1ec, 0x00000000},
-	{0x0000a1f0, 0x00000396},
-	{0x0000a1f4, 0x00000396},
-	{0x0000a1f8, 0x00000396},
-	{0x0000a1fc, 0x00000296},
-};
-
-static const u32 ar9485_1_0_pcie_phy_pll_on_clkreq_enable_L1[][2] = {
-	/*   Addr    allmodes  */
-	{0x00018c00, 0x10252e5e},
-	{0x00018c04, 0x000801d8},
-	{0x00018c08, 0x0000580c},
-};
-
-static const u32 ar9485_1_0_pcie_phy_clkreq_enable_L1[][2] = {
-	/*  Addr    allmodes   */
-	{0x00018c00, 0x10253e5e},
-	{0x00018c04, 0x000801d8},
-	{0x00018c08, 0x0000580c},
-};
-
-static const u32 ar9485_1_0_soc_preamble[][2] = {
-	/*   Addr     allmodes */
-	{0x00004090, 0x00aa10aa},
-	{0x000040a4, 0x00a0c9c9},
-	{0x00007048, 0x00000004},
-};
-
-static const u32 ar9485_fast_clock_1_0_baseband_postamble[][3] = {
-	/*   Addr      5G_HT20     5G_HT40 */
-	{0x00009e00, 0x03721821, 0x03721821},
-	{0x0000a230, 0x0000400b, 0x00004016},
-	{0x0000a254, 0x00000898, 0x00001130},
-};
-
-static const u32 ar9485_1_0_baseband_postamble[][5] = {
-	/* Addr        5G_HT20     5G_HT40     2G_HT40     2G_HT20 */
-	{0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8005},
-	{0x00009820, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e},
-	{0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
-	{0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881},
-	{0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
-	{0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x0000059c},
-	{0x00009c00, 0x00000044, 0x00000044, 0x00000044, 0x00000044},
-	{0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0},
-	{0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020},
-	{0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2},
-	{0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec80d2e, 0x7ec80d2e},
-	{0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e},
-	{0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-	{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
-	{0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
-	{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
-	{0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222},
-	{0x00009e44, 0x02321e27, 0x02321e27, 0x02282324, 0x02282324},
-	{0x00009e48, 0x5030201a, 0x5030201a, 0x50302010, 0x50302010},
-	{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
-	{0x0000a204, 0x01303fc0, 0x01303fc4, 0x01303fc4, 0x01303fc0},
-	{0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
-	{0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b},
-	{0x0000a234, 0x10000fff, 0x10000fff, 0x10000fff, 0x10000fff},
-	{0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018},
-	{0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108},
-	{0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898},
-	{0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002},
-	{0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e},
-	{0x0000a260, 0x3a021501, 0x3a021501, 0x3a021501, 0x3a021501},
-	{0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
-	{0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b},
-	{0x0000a284, 0x00000000, 0x00000000, 0x000002a0, 0x000002a0},
-	{0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-	{0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-	{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
-	{0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071982},
-	{0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a},
-	{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-	{0x0000be04, 0x00802020, 0x00802020, 0x00802020, 0x00802020},
-	{0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-};
-
-static const u32 ar9485Modes_low_ob_db_tx_gain_1_0[][5] = {
-	/*  Addr      5G_HT20    5G_HT40     2G_HT40     2G_HT20   */
-	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
-	{0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
-	{0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002},
-	{0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004},
-	{0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200},
-	{0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202},
-	{0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400},
-	{0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402},
-	{0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404},
-	{0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603},
-	{0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605},
-	{0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03},
-	{0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04},
-	{0x0000a530, 0x48023ec6, 0x48023ec6, 0x2e000a20, 0x2e000a20},
-	{0x0000a534, 0x4d023f01, 0x4d023f01, 0x34000e20, 0x34000e20},
-	{0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000e22, 0x38000e22},
-	{0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3c000e24, 0x3c000e24},
-	{0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x40000e26, 0x40000e26},
-	{0x0000a544, 0x6502feca, 0x6502feca, 0x43001640, 0x43001640},
-	{0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46001660, 0x46001660},
-	{0x0000a54c, 0x7203feca, 0x7203feca, 0x49001861, 0x49001861},
-	{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4c001a81, 0x4c001a81},
-	{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4f001a83, 0x4f001a83},
-	{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x54001c85, 0x54001c85},
-	{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x58001ce5, 0x58001ce5},
-	{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5b001ce9, 0x5b001ce9},
-	{0x0000a564, 0x960fffcb, 0x960fffcb, 0x60001eeb, 0x60001eeb},
-	{0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
-	{0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
-	{0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
-	{0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
-	{0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
-	{0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
-	{0x00016044, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db},
-};
-
-static const u32 ar9485_1_0_pcie_phy_clkreq_disable_L1[][2] = {
-	/*   Addr     allmodes */
-	{0x00018c00, 0x10213e5e},
-	{0x00018c04, 0x000801d8},
-	{0x00018c08, 0x0000580c},
-};
-
-static const u32 ar9485_1_0_radio_postamble[][2] = {
-	/*   Addr     allmodes */
-	{0x0001609c, 0x0b283f31},
-	{0x000160ac, 0x24611800},
-	{0x000160b0, 0x03284f3e},
-	{0x0001610c, 0x00170000},
-	{0x00016140, 0x10804008},
-};
-
-static const u32 ar9485_1_0_mac_core[][2] = {
-	/*  Addr      allmodes */
-	{0x00000008, 0x00000000},
-	{0x00000030, 0x00020085},
-	{0x00000034, 0x00000005},
-	{0x00000040, 0x00000000},
-	{0x00000044, 0x00000000},
-	{0x00000048, 0x00000008},
-	{0x0000004c, 0x00000010},
-	{0x00000050, 0x00000000},
-	{0x00001040, 0x002ffc0f},
-	{0x00001044, 0x002ffc0f},
-	{0x00001048, 0x002ffc0f},
-	{0x0000104c, 0x002ffc0f},
-	{0x00001050, 0x002ffc0f},
-	{0x00001054, 0x002ffc0f},
-	{0x00001058, 0x002ffc0f},
-	{0x0000105c, 0x002ffc0f},
-	{0x00001060, 0x002ffc0f},
-	{0x00001064, 0x002ffc0f},
-	{0x000010f0, 0x00000100},
-	{0x00001270, 0x00000000},
-	{0x000012b0, 0x00000000},
-	{0x000012f0, 0x00000000},
-	{0x0000143c, 0x00000000},
-	{0x0000147c, 0x00000000},
-	{0x00008000, 0x00000000},
-	{0x00008004, 0x00000000},
-	{0x00008008, 0x00000000},
-	{0x0000800c, 0x00000000},
-	{0x00008018, 0x00000000},
-	{0x00008020, 0x00000000},
-	{0x00008038, 0x00000000},
-	{0x0000803c, 0x00000000},
-	{0x00008040, 0x00000000},
-	{0x00008044, 0x00000000},
-	{0x00008048, 0x00000000},
-	{0x0000804c, 0xffffffff},
-	{0x00008054, 0x00000000},
-	{0x00008058, 0x00000000},
-	{0x0000805c, 0x000fc78f},
-	{0x00008060, 0x0000000f},
-	{0x00008064, 0x00000000},
-	{0x00008070, 0x00000310},
-	{0x00008074, 0x00000020},
-	{0x00008078, 0x00000000},
-	{0x0000809c, 0x0000000f},
-	{0x000080a0, 0x00000000},
-	{0x000080a4, 0x02ff0000},
-	{0x000080a8, 0x0e070605},
-	{0x000080ac, 0x0000000d},
-	{0x000080b0, 0x00000000},
-	{0x000080b4, 0x00000000},
-	{0x000080b8, 0x00000000},
-	{0x000080bc, 0x00000000},
-	{0x000080c0, 0x2a800000},
-	{0x000080c4, 0x06900168},
-	{0x000080c8, 0x13881c20},
-	{0x000080cc, 0x01f40000},
-	{0x000080d0, 0x00252500},
-	{0x000080d4, 0x00a00000},
-	{0x000080d8, 0x00400000},
-	{0x000080dc, 0x00000000},
-	{0x000080e0, 0xffffffff},
-	{0x000080e4, 0x0000ffff},
-	{0x000080e8, 0x3f3f3f3f},
-	{0x000080ec, 0x00000000},
-	{0x000080f0, 0x00000000},
-	{0x000080f4, 0x00000000},
-	{0x000080fc, 0x00020000},
-	{0x00008100, 0x00000000},
-	{0x00008108, 0x00000052},
-	{0x0000810c, 0x00000000},
-	{0x00008110, 0x00000000},
-	{0x00008114, 0x000007ff},
-	{0x00008118, 0x000000aa},
-	{0x0000811c, 0x00003210},
-	{0x00008124, 0x00000000},
-	{0x00008128, 0x00000000},
-	{0x0000812c, 0x00000000},
-	{0x00008130, 0x00000000},
-	{0x00008134, 0x00000000},
-	{0x00008138, 0x00000000},
-	{0x0000813c, 0x0000ffff},
-	{0x00008144, 0xffffffff},
-	{0x00008168, 0x00000000},
-	{0x0000816c, 0x00000000},
-	{0x00008170, 0x18486200},
-	{0x00008174, 0x33332210},
-	{0x00008178, 0x00000000},
-	{0x0000817c, 0x00020000},
-	{0x000081c0, 0x00000000},
-	{0x000081c4, 0x33332210},
-	{0x000081c8, 0x00000000},
-	{0x000081cc, 0x00000000},
-	{0x000081d4, 0x00000000},
-	{0x000081ec, 0x00000000},
-	{0x000081f0, 0x00000000},
-	{0x000081f4, 0x00000000},
-	{0x000081f8, 0x00000000},
-	{0x000081fc, 0x00000000},
-	{0x00008240, 0x00100000},
-	{0x00008244, 0x0010f400},
-	{0x00008248, 0x00000800},
-	{0x0000824c, 0x0001e800},
-	{0x00008250, 0x00000000},
-	{0x00008254, 0x00000000},
-	{0x00008258, 0x00000000},
-	{0x0000825c, 0x40000000},
-	{0x00008260, 0x00080922},
-	{0x00008264, 0x9ca00010},
-	{0x00008268, 0xffffffff},
-	{0x0000826c, 0x0000ffff},
-	{0x00008270, 0x00000000},
-	{0x00008274, 0x40000000},
-	{0x00008278, 0x003e4180},
-	{0x0000827c, 0x00000004},
-	{0x00008284, 0x0000002c},
-	{0x00008288, 0x0000002c},
-	{0x0000828c, 0x000000ff},
-	{0x00008294, 0x00000000},
-	{0x00008298, 0x00000000},
-	{0x0000829c, 0x00000000},
-	{0x00008300, 0x00000140},
-	{0x00008314, 0x00000000},
-	{0x0000831c, 0x0000010d},
-	{0x00008328, 0x00000000},
-	{0x0000832c, 0x00000007},
-	{0x00008330, 0x00000302},
-	{0x00008334, 0x00000700},
-	{0x00008338, 0x00ff0000},
-	{0x0000833c, 0x02400000},
-	{0x00008340, 0x000107ff},
-	{0x00008344, 0xa248105b},
-	{0x00008348, 0x008f0000},
-	{0x0000835c, 0x00000000},
-	{0x00008360, 0xffffffff},
-	{0x00008364, 0xffffffff},
-	{0x00008368, 0x00000000},
-	{0x00008370, 0x00000000},
-	{0x00008374, 0x000000ff},
-	{0x00008378, 0x00000000},
-	{0x0000837c, 0x00000000},
-	{0x00008380, 0xffffffff},
-	{0x00008384, 0xffffffff},
-	{0x00008390, 0xffffffff},
-	{0x00008394, 0xffffffff},
-	{0x00008398, 0x00000000},
-	{0x0000839c, 0x00000000},
-	{0x000083a0, 0x00000000},
-	{0x000083a4, 0x0000fa14},
-	{0x000083a8, 0x000f0c00},
-	{0x000083ac, 0x33332210},
-	{0x000083b0, 0x33332210},
-	{0x000083b4, 0x33332210},
-	{0x000083b8, 0x33332210},
-	{0x000083bc, 0x00000000},
-	{0x000083c0, 0x00000000},
-	{0x000083c4, 0x00000000},
-	{0x000083c8, 0x00000000},
-	{0x000083cc, 0x00000200},
-	{0x000083d0, 0x000301ff},
-};
-
 static const u32 ar9485_1_1_mac_core[][2] = {
 	/*  Addr       allmodes */
 	{0x00000008, 0x00000000},
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 099bd41..38835bc 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -120,13 +120,11 @@
 /* RX / TX */
 /***********/
 
-#define ATH_MAX_ANTENNA         3
 #define ATH_RXBUF               512
 #define ATH_TXBUF               512
 #define ATH_TXBUF_RESERVE       5
 #define ATH_MAX_QDEPTH          (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE)
 #define ATH_TXMAXTRY            13
-#define ATH_MGT_TXMAXTRY        4
 
 #define TID_TO_WME_AC(_tid)				\
 	((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE :	\
@@ -346,11 +344,9 @@
 
 struct ath_vif {
 	int av_bslot;
-	bool is_bslot_active;
+	bool is_bslot_active, primary_sta_vif;
 	__le64 tsf_adjust; /* TSF adjustment for staggered beacons */
-	enum nl80211_iftype av_opmode;
 	struct ath_buf *av_bcbuf;
-	u8 bssid[ETH_ALEN]; /* current BSSID from config_interface */
 };
 
 /*******************/
@@ -362,7 +358,7 @@
  * number of BSSIDs) if a given beacon does not go out even after waiting this
  * number of beacon intervals, the game's up.
  */
-#define BSTUCK_THRESH           	(9 * ATH_BCBUF)
+#define BSTUCK_THRESH           	9
 #define	ATH_BCBUF               	4
 #define ATH_DEFAULT_BINTVAL     	100 /* TU */
 #define ATH_DEFAULT_BMISS_LIMIT 	10
@@ -386,7 +382,7 @@
 	u32 beaconq;
 	u32 bmisscnt;
 	u32 ast_be_xmit;
-	u64 bc_tstamp;
+	u32 bc_tstamp;
 	struct ieee80211_vif *bslot[ATH_BCBUF];
 	int slottime;
 	int slotupdate;
@@ -401,6 +397,7 @@
 int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif);
 void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp);
 int ath_beaconq_config(struct ath_softc *sc);
+void ath_set_beacon(struct ath_softc *sc);
 void ath9k_set_beaconing_status(struct ath_softc *sc, bool status);
 
 /*******/
@@ -550,6 +547,7 @@
 #define SC_OP_BT_SCAN		     BIT(13)
 #define SC_OP_ANI_RUN		     BIT(14)
 #define SC_OP_ENABLE_APM	     BIT(15)
+#define SC_OP_PRIM_STA_VIF	     BIT(16)
 
 /* Powersave flags */
 #define PS_WAIT_FOR_BEACON        BIT(0)
@@ -688,8 +686,6 @@
 
 u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate);
 
-void ath9k_set_bssid_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
-
 void ath_start_rfkill_poll(struct ath_softc *sc);
 extern void ath9k_rfkill_poll_state(struct ieee80211_hw *hw);
 void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 6d2a545f..eccb0ec 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -57,8 +57,8 @@
 
 /*
  *  Associates the beacon frame buffer with a transmit descriptor.  Will set
- *  up all required antenna switch parameters, rate codes, and channel flags.
- *  Beacons are always sent out at the lowest rate, and are not retried.
+ *  up rate codes, and channel flags. Beacons are always sent out at the
+ *  lowest rate, and are not retried.
 */
 static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
 			     struct ath_buf *bf, int rateidx)
@@ -68,7 +68,7 @@
 	struct ath_common *common = ath9k_hw_common(ah);
 	struct ath_desc *ds;
 	struct ath9k_11n_rate_series series[4];
-	int flags, antenna, ctsrate = 0, ctsduration = 0;
+	int flags, ctsrate = 0, ctsduration = 0;
 	struct ieee80211_supported_band *sband;
 	u8 rate = 0;
 
@@ -76,12 +76,6 @@
 	flags = ATH9K_TXDESC_NOACK;
 
 	ds->ds_link = 0;
-	/*
-	 * Switch antenna every beacon.
-	 * Should only switch every beacon period, not for every SWBA
-	 * XXX assumes two antennae
-	 */
-	antenna = ((sc->beacon.ast_be_xmit / sc->nbcnvifs) & 1 ? 2 : 1);
 
 	sband = &sc->sbands[common->hw->conf.channel->band];
 	rate = sband->bitrates[rateidx].hw_value;
@@ -278,7 +272,7 @@
 		return -ENOMEM;
 
 	tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
-	sc->beacon.bc_tstamp = le64_to_cpu(tstamp);
+	sc->beacon.bc_tstamp = (u32) le64_to_cpu(tstamp);
 	/* Calculate a TSF adjustment factor required for staggered beacons. */
 	if (avp->av_bslot > 0) {
 		u64 tsfadjust;
@@ -294,8 +288,8 @@
 		 * adjustment. Other slots are adjusted to get the timestamp
 		 * close to the TBTT for the BSS.
 		 */
-		tsfadjust = intval * avp->av_bslot / ATH_BCBUF;
-		avp->tsf_adjust = cpu_to_le64(TU_TO_USEC(tsfadjust));
+		tsfadjust = TU_TO_USEC(intval * avp->av_bslot) / ATH_BCBUF;
+		avp->tsf_adjust = cpu_to_le64(tsfadjust);
 
 		ath_dbg(common, ATH_DBG_BEACON,
 			"stagger beacons, bslot %d intval %u tsfadjust %llu\n",
@@ -329,6 +323,7 @@
 		if (avp->av_bslot != -1) {
 			sc->beacon.bslot[avp->av_bslot] = NULL;
 			sc->nbcnvifs--;
+			avp->av_bslot = -1;
 		}
 
 		bf = avp->av_bcbuf;
@@ -369,12 +364,13 @@
 	if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) {
 		sc->beacon.bmisscnt++;
 
-		if (sc->beacon.bmisscnt < BSTUCK_THRESH) {
+		if (sc->beacon.bmisscnt < BSTUCK_THRESH * sc->nbcnvifs) {
 			ath_dbg(common, ATH_DBG_BSTUCK,
 				"missed %u consecutive beacons\n",
 				sc->beacon.bmisscnt);
 			ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq);
-			ath9k_hw_bstuck_nfcal(ah);
+			if (sc->beacon.bmisscnt > 3)
+				ath9k_hw_bstuck_nfcal(ah);
 		} else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
 			ath_dbg(common, ATH_DBG_BSTUCK,
 				"beacon is officially stuck\n");
@@ -385,13 +381,6 @@
 		return;
 	}
 
-	if (sc->beacon.bmisscnt != 0) {
-		ath_dbg(common, ATH_DBG_BSTUCK,
-			"resume beacon xmit after %u misses\n",
-			sc->beacon.bmisscnt);
-		sc->beacon.bmisscnt = 0;
-	}
-
 	/*
 	 * Generate beacon frames. we are sending frames
 	 * staggered so calculate the slot for this frame based
@@ -401,21 +390,14 @@
 	intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL;
 
 	tsf = ath9k_hw_gettsf64(ah);
-	tsftu = TSF_TO_TU(tsf>>32, tsf);
-	slot = ((tsftu % intval) * ATH_BCBUF) / intval;
-	/*
-	 * Reverse the slot order to get slot 0 on the TBTT offset that does
-	 * not require TSF adjustment and other slots adding
-	 * slot/ATH_BCBUF * beacon_int to timestamp. For example, with
-	 * ATH_BCBUF = 4, we process beacon slots as follows: 3 2 1 0 3 2 1 ..
-	 * and slot 0 is at correct offset to TBTT.
-	 */
-	slot = ATH_BCBUF - slot - 1;
+	tsf += TU_TO_USEC(ah->config.sw_beacon_response_time);
+	tsftu = TSF_TO_TU((tsf * ATH_BCBUF) >>32, tsf * ATH_BCBUF);
+	slot = (tsftu % (intval * ATH_BCBUF)) / intval;
 	vif = sc->beacon.bslot[slot];
 
 	ath_dbg(common, ATH_DBG_BEACON,
 		"slot %d [tsf %llu tsftu %u intval %u] vif %p\n",
-		slot, tsf, tsftu, intval, vif);
+		slot, tsf, tsftu / ATH_BCBUF, intval, vif);
 
 	bfaddr = 0;
 	if (vif) {
@@ -424,6 +406,13 @@
 			bfaddr = bf->bf_daddr;
 			bc = 1;
 		}
+
+		if (sc->beacon.bmisscnt != 0) {
+			ath_dbg(common, ATH_DBG_BSTUCK,
+				"resume beacon xmit after %u misses\n",
+				sc->beacon.bmisscnt);
+			sc->beacon.bmisscnt = 0;
+		}
 	}
 
 	/*
@@ -463,13 +452,17 @@
 			      u32 next_beacon,
 			      u32 beacon_period)
 {
-	if (beacon_period & ATH9K_BEACON_RESET_TSF)
+	if (sc->sc_flags & SC_OP_TSF_RESET) {
 		ath9k_ps_wakeup(sc);
+		ath9k_hw_reset_tsf(sc->sc_ah);
+	}
 
 	ath9k_hw_beaconinit(sc->sc_ah, next_beacon, beacon_period);
 
-	if (beacon_period & ATH9K_BEACON_RESET_TSF)
+	if (sc->sc_flags & SC_OP_TSF_RESET) {
 		ath9k_ps_restore(sc);
+		sc->sc_flags &= ~SC_OP_TSF_RESET;
+	}
 }
 
 /*
@@ -484,18 +477,14 @@
 	u32 nexttbtt, intval;
 
 	/* NB: the beacon interval is kept internally in TU's */
-	intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
+	intval = TU_TO_USEC(conf->beacon_interval & ATH9K_BEACON_PERIOD);
 	intval /= ATH_BCBUF;    /* for staggered beacons */
 	nexttbtt = intval;
 
-	if (sc->sc_flags & SC_OP_TSF_RESET)
-		intval |= ATH9K_BEACON_RESET_TSF;
-
 	/*
 	 * In AP mode we enable the beacon timers and SWBA interrupts to
 	 * prepare beacon frames.
 	 */
-	intval |= ATH9K_BEACON_ENA;
 	ah->imask |= ATH9K_INT_SWBA;
 	ath_beaconq_config(sc);
 
@@ -505,11 +494,6 @@
 	ath9k_beacon_init(sc, nexttbtt, intval);
 	sc->beacon.bmisscnt = 0;
 	ath9k_hw_set_interrupts(ah, ah->imask);
-
-	/* Clear the reset TSF flag, so that subsequent beacon updation
-	   will not reset the HW TSF. */
-
-	sc->sc_flags &= ~SC_OP_TSF_RESET;
 }
 
 /*
@@ -643,25 +627,20 @@
 {
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_common *common = ath9k_hw_common(ah);
-	u64 tsf;
-	u32 tsftu, intval, nexttbtt;
+	u32 tsf, delta, intval, nexttbtt;
 
-	intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
+	tsf = ath9k_hw_gettsf32(ah) + TU_TO_USEC(FUDGE);
+	intval = TU_TO_USEC(conf->beacon_interval & ATH9K_BEACON_PERIOD);
 
-
-	/* Pull nexttbtt forward to reflect the current TSF */
-
-	nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp);
-	if (nexttbtt == 0)
-                nexttbtt = intval;
-        else if (intval)
-                nexttbtt = roundup(nexttbtt, intval);
-
-	tsf = ath9k_hw_gettsf64(ah);
-	tsftu = TSF_TO_TU((u32)(tsf>>32), (u32)tsf) + FUDGE;
-	do {
-		nexttbtt += intval;
-	} while (nexttbtt < tsftu);
+	if (!sc->beacon.bc_tstamp)
+		nexttbtt = tsf + intval;
+	else {
+		if (tsf > sc->beacon.bc_tstamp)
+			delta = (tsf - sc->beacon.bc_tstamp);
+		else
+			delta = (tsf + 1 + (~0U - sc->beacon.bc_tstamp));
+		nexttbtt = tsf + roundup(delta, intval);
+	}
 
 	ath_dbg(common, ATH_DBG_BEACON,
 		"IBSS nexttbtt %u intval %u (%u)\n",
@@ -672,7 +651,6 @@
 	 * if we need to manually prepare beacon frames.  Otherwise we use a
 	 * self-linked tx descriptor and let the hardware deal with things.
 	 */
-	intval |= ATH9K_BEACON_ENA;
 	ah->imask |= ATH9K_INT_SWBA;
 
 	ath_beaconq_config(sc);
@@ -685,22 +663,63 @@
 	ath9k_hw_set_interrupts(ah, ah->imask);
 }
 
-void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
+static bool ath9k_allow_beacon_config(struct ath_softc *sc,
+				      struct ieee80211_vif *vif)
 {
 	struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-	enum nl80211_iftype iftype;
+	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+	struct ath_vif *avp = (void *)vif->drv_priv;
+
+	/*
+	 * Can not have different beacon interval on multiple
+	 * AP interface case
+	 */
+	if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) &&
+	    (sc->nbcnvifs > 1) &&
+	    (vif->type == NL80211_IFTYPE_AP) &&
+	    (cur_conf->beacon_interval != bss_conf->beacon_int)) {
+		ath_dbg(common, ATH_DBG_CONFIG,
+			"Changing beacon interval of multiple \
+			AP interfaces !\n");
+		return false;
+	}
+	/*
+	 * Can not configure station vif's beacon config
+	 * while on AP opmode
+	 */
+	if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) &&
+	    (vif->type != NL80211_IFTYPE_AP)) {
+		ath_dbg(common, ATH_DBG_CONFIG,
+			"STA vif's beacon not allowed on AP mode\n");
+		return false;
+	}
+	/*
+	 * Do not allow beacon config if HW was already configured
+	 * with another STA vif
+	 */
+	if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) &&
+	    (vif->type == NL80211_IFTYPE_STATION) &&
+	    (sc->sc_flags & SC_OP_BEACONS) &&
+	    !avp->primary_sta_vif) {
+		ath_dbg(common, ATH_DBG_CONFIG,
+			"Beacon already configured for a station interface\n");
+		return false;
+	}
+	return true;
+}
+
+void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
+{
+	struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
+	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+
+	if (!ath9k_allow_beacon_config(sc, vif))
+		return;
 
 	/* Setup the beacon configuration parameters */
-	if (vif) {
-		struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
-		iftype = vif->type;
-		cur_conf->beacon_interval = bss_conf->beacon_int;
-		cur_conf->dtim_period = bss_conf->dtim_period;
-	} else {
-		iftype = sc->sc_ah->opmode;
-	}
-
+	cur_conf->beacon_interval = bss_conf->beacon_int;
+	cur_conf->dtim_period = bss_conf->dtim_period;
 	cur_conf->listen_interval = 1;
 	cur_conf->dtim_count = 1;
 	cur_conf->bmiss_timeout =
@@ -723,7 +742,16 @@
 	if (cur_conf->dtim_period == 0)
 		cur_conf->dtim_period = 1;
 
-	switch (iftype) {
+	ath_set_beacon(sc);
+	sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
+}
+
+void ath_set_beacon(struct ath_softc *sc)
+{
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+	struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
+
+	switch (sc->sc_ah->opmode) {
 	case NL80211_IFTYPE_AP:
 		ath_beacon_config_ap(sc, cur_conf);
 		break;
@@ -750,22 +778,23 @@
 	int slot;
 	bool found = false;
 
-	ath9k_ps_wakeup(sc);
-	if (status) {
-		for (slot = 0; slot < ATH_BCBUF; slot++) {
-			if (sc->beacon.bslot[slot]) {
-				avp = (void *)sc->beacon.bslot[slot]->drv_priv;
-				if (avp->is_bslot_active) {
-					found = true;
-					break;
-				}
+	for (slot = 0; slot < ATH_BCBUF; slot++) {
+		if (sc->beacon.bslot[slot]) {
+			avp = (void *)sc->beacon.bslot[slot]->drv_priv;
+			if (avp->is_bslot_active) {
+				found = true;
+				break;
 			}
 		}
-		if (found) {
-			/* Re-enable beaconing */
-			ah->imask |= ATH9K_INT_SWBA;
-			ath9k_hw_set_interrupts(ah, ah->imask);
-		}
+	}
+	if (!found)
+		return;
+
+	ath9k_ps_wakeup(sc);
+	if (status) {
+		/* Re-enable beaconing */
+		ah->imask |= ATH9K_INT_SWBA;
+		ath9k_hw_set_interrupts(ah, ah->imask);
 	} else {
 		/* Disable SWBA interrupt */
 		ah->imask &= ~ATH9K_INT_SWBA;
diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c
index 615e682..16ba8c6 100644
--- a/drivers/net/wireless/ath/ath9k/common.c
+++ b/drivers/net/wireless/ath/ath9k/common.c
@@ -116,7 +116,7 @@
 
 	if (chan->band == IEEE80211_BAND_2GHZ) {
 		ichan->chanmode = CHANNEL_G;
-		ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM | CHANNEL_G;
+		ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM;
 	} else {
 		ichan->chanmode = CHANNEL_A;
 		ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM;
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 8df5a92..a762cad 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -1088,67 +1088,43 @@
 		return -ENOMEM;
 
 #ifdef CONFIG_ATH_DEBUG
-	if (!debugfs_create_file("debug", S_IRUSR | S_IWUSR,
-			sc->debug.debugfs_phy, sc, &fops_debug))
-		goto err;
+	debugfs_create_file("debug", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
+			    sc, &fops_debug);
 #endif
+	debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc,
+			    &fops_dma);
+	debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy, sc,
+			    &fops_interrupt);
+	debugfs_create_file("wiphy", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
+			    sc, &fops_wiphy);
+	debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy, sc,
+			    &fops_xmit);
+	debugfs_create_file("stations", S_IRUSR, sc->debug.debugfs_phy, sc,
+			    &fops_stations);
+	debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy, sc,
+			    &fops_misc);
+	debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy, sc,
+			    &fops_recv);
+	debugfs_create_file("rx_chainmask", S_IRUSR | S_IWUSR,
+			    sc->debug.debugfs_phy, sc, &fops_rx_chainmask);
+	debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR,
+			    sc->debug.debugfs_phy, sc, &fops_tx_chainmask);
+	debugfs_create_file("regidx", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
+			    sc, &fops_regidx);
+	debugfs_create_file("regval", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
+			    sc, &fops_regval);
+	debugfs_create_bool("ignore_extcca", S_IRUSR | S_IWUSR,
+			    sc->debug.debugfs_phy,
+			    &ah->config.cwm_ignore_extcca);
+	debugfs_create_file("regdump", S_IRUSR, sc->debug.debugfs_phy, sc,
+			    &fops_regdump);
 
-	if (!debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy,
-			sc, &fops_dma))
-		goto err;
+	debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR,
+			   sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask);
 
-	if (!debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy,
-			sc, &fops_interrupt))
-		goto err;
-
-	if (!debugfs_create_file("wiphy", S_IRUSR | S_IWUSR,
-			sc->debug.debugfs_phy, sc, &fops_wiphy))
-		goto err;
-
-	if (!debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy,
-			sc, &fops_xmit))
-		goto err;
-
-	if (!debugfs_create_file("stations", S_IRUSR, sc->debug.debugfs_phy,
-			sc, &fops_stations))
-		goto err;
-
-	if (!debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy,
-			sc, &fops_misc))
-		goto err;
-
-	if (!debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy,
-			sc, &fops_recv))
-		goto err;
-
-	if (!debugfs_create_file("rx_chainmask", S_IRUSR | S_IWUSR,
-			sc->debug.debugfs_phy, sc, &fops_rx_chainmask))
-		goto err;
-
-	if (!debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR,
-			sc->debug.debugfs_phy, sc, &fops_tx_chainmask))
-		goto err;
-
-	if (!debugfs_create_file("regidx", S_IRUSR | S_IWUSR,
-			sc->debug.debugfs_phy, sc, &fops_regidx))
-		goto err;
-
-	if (!debugfs_create_file("regval", S_IRUSR | S_IWUSR,
-			sc->debug.debugfs_phy, sc, &fops_regval))
-		goto err;
-
-	if (!debugfs_create_bool("ignore_extcca", S_IRUSR | S_IWUSR,
-			sc->debug.debugfs_phy, &ah->config.cwm_ignore_extcca))
-		goto err;
-
-	if (!debugfs_create_file("regdump", S_IRUSR, sc->debug.debugfs_phy,
-			sc, &fops_regdump))
-		goto err;
+	debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR,
+			   sc->debug.debugfs_phy, &sc->sc_ah->gpio_val);
 
 	sc->debug.regidx = 0;
 	return 0;
-err:
-	debugfs_remove_recursive(sc->debug.debugfs_phy);
-	sc->debug.debugfs_phy = NULL;
-	return -ENOMEM;
 }
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
index 8cd8333..2f0712e 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
@@ -392,6 +392,8 @@
 							   numXpdGain);
 			}
 
+			ENABLE_REGWRITE_BUFFER(ah);
+
 			if (i == 0) {
 				if (!ath9k_hw_ar9287_get_eeprom(ah,
 							EEP_OL_PWRCTRL)) {
@@ -442,6 +444,7 @@
 					regOffset += 4;
 				}
 			}
+			REGWRITE_BUFFER_FLUSH(ah);
 		}
 	}
 
@@ -757,6 +760,8 @@
 			ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2;
 	}
 
+	ENABLE_REGWRITE_BUFFER(ah);
+
 	/* OFDM power per rate */
 	REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
 		  ATH9K_POW_SM(ratesArray[rate18mb], 24)
@@ -840,6 +845,7 @@
 			  | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
 			  | ATH9K_POW_SM(ratesArray[rateDupCck], 0));
 	}
+	REGWRITE_BUFFER_FLUSH(ah);
 }
 
 static void ath9k_hw_ar9287_set_addac(struct ath_hw *ah,
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c
index fccd87d..995949d 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
@@ -799,6 +799,8 @@
 							   pwr_table_offset,
 							   &diff);
 
+			ENABLE_REGWRITE_BUFFER(ah);
+
 			if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) {
 				if (OLC_FOR_AR9280_20_LATER) {
 					REG_WRITE(ah,
@@ -847,6 +849,7 @@
 
 				regOffset += 4;
 			}
+			REGWRITE_BUFFER_FLUSH(ah);
 		}
 	}
 
@@ -1205,6 +1208,8 @@
 		}
 	}
 
+	ENABLE_REGWRITE_BUFFER(ah);
+
 	REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
 		  ATH9K_POW_SM(ratesArray[rate18mb], 24)
 		  | ATH9K_POW_SM(ratesArray[rate12mb], 16)
@@ -1291,6 +1296,8 @@
 	REG_WRITE(ah, AR_PHY_POWER_TX_SUB,
 		  ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6)
 		  | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0));
+
+	REGWRITE_BUFFER_FLUSH(ah);
 }
 
 static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz)
diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c
index 0fb8f8a..44a0a88 100644
--- a/drivers/net/wireless/ath/ath9k/gpio.c
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
@@ -41,12 +41,14 @@
 {
 	int ret;
 
-	if (AR_SREV_9287(sc->sc_ah))
-		sc->sc_ah->led_pin = ATH_LED_PIN_9287;
-	else if (AR_SREV_9485(sc->sc_ah))
-		sc->sc_ah->led_pin = ATH_LED_PIN_9485;
-	else
-		sc->sc_ah->led_pin = ATH_LED_PIN_DEF;
+	if (sc->sc_ah->led_pin < 0) {
+		if (AR_SREV_9287(sc->sc_ah))
+			sc->sc_ah->led_pin = ATH_LED_PIN_9287;
+		else if (AR_SREV_9485(sc->sc_ah))
+			sc->sc_ah->led_pin = ATH_LED_PIN_9485;
+		else
+			sc->sc_ah->led_pin = ATH_LED_PIN_DEF;
+	}
 
 	/* Configure gpio 1 for output */
 	ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin,
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index 753a245..ec47be9 100644
--- a/drivers/net/wireless/ath/ath9k/htc.h
+++ b/drivers/net/wireless/ath/ath9k/htc.h
@@ -328,7 +328,7 @@
 #endif /* CONFIG_ATH9K_HTC_DEBUGFS */
 
 #define ATH_LED_PIN_DEF             1
-#define ATH_LED_PIN_9287            8
+#define ATH_LED_PIN_9287            10
 #define ATH_LED_PIN_9271            15
 #define ATH_LED_PIN_7010            12
 #define ATH_LED_ON_DURATION_IDLE    350	/* in msecs */
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
index 8d1d879..8f56158 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
@@ -155,7 +155,7 @@
 	nexttbtt = intval;
 
 	if (priv->op_flags & OP_TSF_RESET) {
-		intval |= ATH9K_BEACON_RESET_TSF;
+		ath9k_hw_reset_tsf(priv->ah);
 		priv->op_flags &= ~OP_TSF_RESET;
 	} else {
 		/*
@@ -168,8 +168,6 @@
 		} while (nexttbtt < tsftu);
 	}
 
-	intval |= ATH9K_BEACON_ENA;
-
 	if (priv->op_flags & OP_ENABLE_BEACON)
 		imask |= ATH9K_INT_SWBA;
 
@@ -178,7 +176,7 @@
 		bss_conf->beacon_interval, nexttbtt, imask);
 
 	WMI_CMD(WMI_DISABLE_INTR_CMDID);
-	ath9k_hw_beaconinit(priv->ah, nexttbtt, intval);
+	ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval));
 	priv->bmiss_cnt = 0;
 	htc_imask = cpu_to_be32(imask);
 	WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
@@ -207,7 +205,6 @@
 		nexttbtt += intval;
 	} while (nexttbtt < tsftu);
 
-	intval |= ATH9K_BEACON_ENA;
 	if (priv->op_flags & OP_ENABLE_BEACON)
 		imask |= ATH9K_INT_SWBA;
 
@@ -216,7 +213,7 @@
 		bss_conf->beacon_interval, nexttbtt, imask);
 
 	WMI_CMD(WMI_DISABLE_INTR_CMDID);
-	ath9k_hw_beaconinit(priv->ah, nexttbtt, intval);
+	ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval));
 	priv->bmiss_cnt = 0;
 	htc_imask = cpu_to_be32(imask);
 	WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index fc67c93..8303b34 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -430,13 +430,16 @@
 	mutex_unlock(&priv->wmi->multi_write_mutex);
 }
 
-static const struct ath_ops ath9k_common_ops = {
-	.read = ath9k_regread,
-	.multi_read = ath9k_multi_regread,
-	.write = ath9k_regwrite,
-	.enable_write_buffer = ath9k_enable_regwrite_buffer,
-	.write_flush = ath9k_regwrite_flush,
-};
+static u32 ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr)
+{
+	u32 val;
+
+	val = ath9k_regread(hw_priv, reg_offset);
+	val &= ~clr;
+	val |= set;
+	ath9k_regwrite(hw_priv, val, reg_offset);
+	return val;
+}
 
 static void ath_usb_read_cachesize(struct ath_common *common, int *csz)
 {
@@ -561,13 +564,7 @@
 	int i = 0;
 
 	/* Get the hardware key cache size. */
-	common->keymax = priv->ah->caps.keycache_size;
-	if (common->keymax > ATH_KEYMAX) {
-		ath_dbg(common, ATH_DBG_ANY,
-			"Warning, using only %u entries in %u key cache\n",
-			ATH_KEYMAX, common->keymax);
-		common->keymax = ATH_KEYMAX;
-	}
+	common->keymax = AR_KEYTABLE_SIZE;
 
 	if (priv->ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA)
 		common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED;
@@ -658,10 +655,16 @@
 	ah->hw_version.subsysid = 0; /* FIXME */
 	ah->hw_version.usbdev = drv_info;
 	ah->ah_flags |= AH_USE_EEPROM;
+	ah->reg_ops.read = ath9k_regread;
+	ah->reg_ops.multi_read = ath9k_multi_regread;
+	ah->reg_ops.write = ath9k_regwrite;
+	ah->reg_ops.enable_write_buffer = ath9k_enable_regwrite_buffer;
+	ah->reg_ops.write_flush = ath9k_regwrite_flush;
+	ah->reg_ops.rmw = ath9k_reg_rmw;
 	priv->ah = ah;
 
 	common = ath9k_hw_common(ah);
-	common->ops = &ath9k_common_ops;
+	common->ops = &ah->reg_ops;
 	common->bus_ops = &ath9k_usb_bus_ops;
 	common->ah = ah;
 	common->hw = priv->hw;
diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h
index c8f254f..22ee888 100644
--- a/drivers/net/wireless/ath/ath9k/hw-ops.h
+++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
@@ -122,12 +122,6 @@
 	ath9k_hw_ops(ah)->set11n_burstduration(ah, ds, burstDuration);
 }
 
-static inline void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds,
-						   u32 vmf)
-{
-	ath9k_hw_ops(ah)->set11n_virtualmorefrag(ah, ds, vmf);
-}
-
 /* Private hardware call ops */
 
 /* PHY ops */
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 1ec9bcd..1b5bd13 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -130,6 +130,20 @@
 }
 EXPORT_SYMBOL(ath9k_hw_wait);
 
+void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array,
+			  int column, unsigned int *writecnt)
+{
+	int r;
+
+	ENABLE_REGWRITE_BUFFER(ah);
+	for (r = 0; r < array->ia_rows; r++) {
+		REG_WRITE(ah, INI_RA(array, r, 0),
+			  INI_RA(array, r, column));
+		DO_DELAY(*writecnt);
+	}
+	REGWRITE_BUFFER_FLUSH(ah);
+}
+
 u32 ath9k_hw_reverse_bits(u32 val, u32 n)
 {
 	u32 retval;
@@ -142,25 +156,6 @@
 	return retval;
 }
 
-bool ath9k_get_channel_edges(struct ath_hw *ah,
-			     u16 flags, u16 *low,
-			     u16 *high)
-{
-	struct ath9k_hw_capabilities *pCap = &ah->caps;
-
-	if (flags & CHANNEL_5GHZ) {
-		*low = pCap->low_5ghz_chan;
-		*high = pCap->high_5ghz_chan;
-		return true;
-	}
-	if ((flags & CHANNEL_2GHZ)) {
-		*low = pCap->low_2ghz_chan;
-		*high = pCap->high_2ghz_chan;
-		return true;
-	}
-	return false;
-}
-
 u16 ath9k_hw_computetxtime(struct ath_hw *ah,
 			   u8 phy, int kbps,
 			   u32 frameLen, u16 rateix,
@@ -364,11 +359,6 @@
 		ah->config.spurchans[i][1] = AR_NO_SPUR;
 	}
 
-	if (ah->hw_version.devid != AR2427_DEVID_PCIE)
-		ah->config.ht_enable = 1;
-	else
-		ah->config.ht_enable = 0;
-
 	/* PAPRD needs some more work to be enabled */
 	ah->config.paprd_disable = 1;
 
@@ -410,6 +400,8 @@
 	ah->sta_id1_defaults =
 		AR_STA_ID1_CRPT_MIC_ENABLE |
 		AR_STA_ID1_MCAST_KSRCH;
+	if (AR_SREV_9100(ah))
+		ah->sta_id1_defaults |= AR_STA_ID1_AR9100_BA_FIX;
 	ah->enable_32kHz_clock = DONT_USE_32KHZ;
 	ah->slottime = 20;
 	ah->globaltxtimeout = (u32) -1;
@@ -673,14 +665,14 @@
 
 unsigned long ar9003_get_pll_sqsum_dvc(struct ath_hw *ah)
 {
-		REG_WRITE(ah, PLL3, (REG_READ(ah, PLL3) & ~(PLL3_DO_MEAS_MASK)));
+	REG_CLR_BIT(ah, PLL3, PLL3_DO_MEAS_MASK);
+	udelay(100);
+	REG_SET_BIT(ah, PLL3, PLL3_DO_MEAS_MASK);
+
+	while ((REG_READ(ah, PLL4) & PLL4_MEAS_DONE) == 0)
 		udelay(100);
-		REG_WRITE(ah, PLL3, (REG_READ(ah, PLL3) | PLL3_DO_MEAS_MASK));
 
-		while ((REG_READ(ah, PLL4) & PLL4_MEAS_DONE) == 0)
-			udelay(100);
-
-		return (REG_READ(ah, PLL3) & SQSUM_DVC_MASK) >> 3;
+	return (REG_READ(ah, PLL3) & SQSUM_DVC_MASK) >> 3;
 }
 EXPORT_SYMBOL(ar9003_get_pll_sqsum_dvc);
 
@@ -830,8 +822,7 @@
 		ah->misc_mode);
 
 	if (ah->misc_mode != 0)
-		REG_WRITE(ah, AR_PCU_MISC,
-			  REG_READ(ah, AR_PCU_MISC) | ah->misc_mode);
+		REG_SET_BIT(ah, AR_PCU_MISC, ah->misc_mode);
 
 	if (conf->channel && conf->channel->band == IEEE80211_BAND_5GHZ)
 		sifstime = 16;
@@ -899,23 +890,19 @@
 static inline void ath9k_hw_set_dma(struct ath_hw *ah)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
-	u32 regval;
 
 	ENABLE_REGWRITE_BUFFER(ah);
 
 	/*
 	 * set AHB_MODE not to do cacheline prefetches
 	*/
-	if (!AR_SREV_9300_20_OR_LATER(ah)) {
-		regval = REG_READ(ah, AR_AHB_MODE);
-		REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN);
-	}
+	if (!AR_SREV_9300_20_OR_LATER(ah))
+		REG_SET_BIT(ah, AR_AHB_MODE, AR_AHB_PREFETCH_RD_EN);
 
 	/*
 	 * let mac dma reads be in 128 byte chunks
 	 */
-	regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK;
-	REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B);
+	REG_RMW(ah, AR_TXCFG, AR_TXCFG_DMASZ_128B, AR_TXCFG_DMASZ_MASK);
 
 	REGWRITE_BUFFER_FLUSH(ah);
 
@@ -932,8 +919,7 @@
 	/*
 	 * let mac dma writes be in 128 byte chunks
 	 */
-	regval = REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK;
-	REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B);
+	REG_RMW(ah, AR_RXCFG, AR_RXCFG_DMASZ_128B, AR_RXCFG_DMASZ_MASK);
 
 	/*
 	 * Setup receive FIFO threshold to hold off TX activities
@@ -972,30 +958,27 @@
 
 static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode)
 {
-	u32 val;
+	u32 mask = AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC;
+	u32 set = AR_STA_ID1_KSRCH_MODE;
 
-	val = REG_READ(ah, AR_STA_ID1);
-	val &= ~(AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC);
 	switch (opmode) {
-	case NL80211_IFTYPE_AP:
-		REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_STA_AP
-			  | AR_STA_ID1_KSRCH_MODE);
-		REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
-		break;
 	case NL80211_IFTYPE_ADHOC:
 	case NL80211_IFTYPE_MESH_POINT:
-		REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_ADHOC
-			  | AR_STA_ID1_KSRCH_MODE);
+		set |= AR_STA_ID1_ADHOC;
 		REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
 		break;
+	case NL80211_IFTYPE_AP:
+		set |= AR_STA_ID1_STA_AP;
+		/* fall through */
 	case NL80211_IFTYPE_STATION:
-		REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE);
+		REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
 		break;
 	default:
-		if (ah->is_monitoring)
-			REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE);
+		if (!ah->is_monitoring)
+			set = 0;
 		break;
 	}
+	REG_RMW(ah, AR_STA_ID1, set, mask);
 }
 
 void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled,
@@ -1021,10 +1004,8 @@
 	u32 tmpReg;
 
 	if (AR_SREV_9100(ah)) {
-		u32 val = REG_READ(ah, AR_RTC_DERIVED_CLK);
-		val &= ~AR_RTC_DERIVED_CLK_PERIOD;
-		val |= SM(1, AR_RTC_DERIVED_CLK_PERIOD);
-		REG_WRITE(ah, AR_RTC_DERIVED_CLK, val);
+		REG_RMW_FIELD(ah, AR_RTC_DERIVED_CLK,
+			      AR_RTC_DERIVED_CLK_PERIOD, 1);
 		(void)REG_READ(ah, AR_RTC_DERIVED_CLK);
 	}
 
@@ -1212,6 +1193,20 @@
 	return true;
 }
 
+static void ath9k_hw_apply_gpio_override(struct ath_hw *ah)
+{
+	u32 gpio_mask = ah->gpio_mask;
+	int i;
+
+	for (i = 0; gpio_mask; i++, gpio_mask >>= 1) {
+		if (!(gpio_mask & 1))
+			continue;
+
+		ath9k_hw_cfg_output(ah, i, AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+		ath9k_hw_set_gpio(ah, i, !!(ah->gpio_val & BIT(i)));
+	}
+}
+
 bool ath9k_hw_check_alive(struct ath_hw *ah)
 {
 	int count = 50;
@@ -1418,7 +1413,7 @@
 	REGWRITE_BUFFER_FLUSH(ah);
 
 	ah->intr_txqs = 0;
-	for (i = 0; i < ah->caps.total_queues; i++)
+	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
 		ath9k_hw_resettxqueue(ah, i);
 
 	ath9k_hw_init_interrupt_masks(ah, ah->opmode);
@@ -1435,8 +1430,7 @@
 		ar9002_hw_enable_wep_aggregation(ah);
 	}
 
-	REG_WRITE(ah, AR_STA_ID1,
-		  REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM);
+	REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM);
 
 	ath9k_hw_set_dma(ah);
 
@@ -1500,6 +1494,8 @@
 	if (AR_SREV_9300_20_OR_LATER(ah))
 		ar9003_hw_bb_watchdog_config(ah);
 
+	ath9k_hw_apply_gpio_override(ah);
+
 	return 0;
 }
 EXPORT_SYMBOL(ath9k_hw_reset);
@@ -1679,21 +1675,15 @@
 	case NL80211_IFTYPE_MESH_POINT:
 		REG_SET_BIT(ah, AR_TXCFG,
 			    AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY);
-		REG_WRITE(ah, AR_NEXT_NDP_TIMER,
-			  TU_TO_USEC(next_beacon +
-				     (ah->atim_window ? ah->
-				      atim_window : 1)));
+		REG_WRITE(ah, AR_NEXT_NDP_TIMER, next_beacon +
+			  TU_TO_USEC(ah->atim_window ? ah->atim_window : 1));
 		flags |= AR_NDP_TIMER_EN;
 	case NL80211_IFTYPE_AP:
-		REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon));
-		REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT,
-			  TU_TO_USEC(next_beacon -
-				     ah->config.
-				     dma_beacon_response_time));
-		REG_WRITE(ah, AR_NEXT_SWBA,
-			  TU_TO_USEC(next_beacon -
-				     ah->config.
-				     sw_beacon_response_time));
+		REG_WRITE(ah, AR_NEXT_TBTT_TIMER, next_beacon);
+		REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, next_beacon -
+			  TU_TO_USEC(ah->config.dma_beacon_response_time));
+		REG_WRITE(ah, AR_NEXT_SWBA, next_beacon -
+			  TU_TO_USEC(ah->config.sw_beacon_response_time));
 		flags |=
 			AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN;
 		break;
@@ -1705,18 +1695,13 @@
 		break;
 	}
 
-	REG_WRITE(ah, AR_BEACON_PERIOD, TU_TO_USEC(beacon_period));
-	REG_WRITE(ah, AR_DMA_BEACON_PERIOD, TU_TO_USEC(beacon_period));
-	REG_WRITE(ah, AR_SWBA_PERIOD, TU_TO_USEC(beacon_period));
-	REG_WRITE(ah, AR_NDP_PERIOD, TU_TO_USEC(beacon_period));
+	REG_WRITE(ah, AR_BEACON_PERIOD, beacon_period);
+	REG_WRITE(ah, AR_DMA_BEACON_PERIOD, beacon_period);
+	REG_WRITE(ah, AR_SWBA_PERIOD, beacon_period);
+	REG_WRITE(ah, AR_NDP_PERIOD, beacon_period);
 
 	REGWRITE_BUFFER_FLUSH(ah);
 
-	beacon_period &= ~ATH9K_BEACON_ENA;
-	if (beacon_period & ATH9K_BEACON_RESET_TSF) {
-		ath9k_hw_reset_tsf(ah);
-	}
-
 	REG_SET_BIT(ah, AR_TIMER_MODE, flags);
 }
 EXPORT_SYMBOL(ath9k_hw_beaconinit);
@@ -1851,6 +1836,8 @@
 	    !(AR_SREV_9271(ah)))
 		/* CB71: GPIO 0 is pulled down to indicate 3 rx chains */
 		pCap->rx_chainmask = ath9k_hw_gpio_get(ah, 0) ? 0x5 : 0x7;
+	else if (AR_SREV_9100(ah))
+		pCap->rx_chainmask = 0x7;
 	else
 		/* Use rx_chainmask from EEPROM. */
 		pCap->rx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_RX_MASK);
@@ -1861,36 +1848,13 @@
 	if (AR_SREV_9300_20_OR_LATER(ah))
 		ah->misc_mode |= AR_PCU_ALWAYS_PERFORM_KEYSEARCH;
 
-	pCap->low_2ghz_chan = 2312;
-	pCap->high_2ghz_chan = 2732;
-
-	pCap->low_5ghz_chan = 4920;
-	pCap->high_5ghz_chan = 6100;
-
 	common->crypt_caps |= ATH_CRYPT_CAP_CIPHER_AESCCM;
 
-	if (ah->config.ht_enable)
+	if (ah->hw_version.devid != AR2427_DEVID_PCIE)
 		pCap->hw_caps |= ATH9K_HW_CAP_HT;
 	else
 		pCap->hw_caps &= ~ATH9K_HW_CAP_HT;
 
-	if (capField & AR_EEPROM_EEPCAP_MAXQCU)
-		pCap->total_queues =
-			MS(capField, AR_EEPROM_EEPCAP_MAXQCU);
-	else
-		pCap->total_queues = ATH9K_NUM_TX_QUEUES;
-
-	if (capField & AR_EEPROM_EEPCAP_KC_ENTRIES)
-		pCap->keycache_size =
-			1 << MS(capField, AR_EEPROM_EEPCAP_KC_ENTRIES);
-	else
-		pCap->keycache_size = AR_KEYTABLE_SIZE;
-
-	if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
-		pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD >> 1;
-	else
-		pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD;
-
 	if (AR_SREV_9271(ah))
 		pCap->num_gpio_pins = AR9271_NUM_GPIO;
 	else if (AR_DEVID_7010(ah))
@@ -1909,8 +1873,6 @@
 		pCap->rts_aggr_limit = (8 * 1024);
 	}
 
-	pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM;
-
 #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
 	ah->rfsilent = ah->eep_ops->get_eeprom(ah, EEP_RF_SILENT);
 	if (ah->rfsilent & EEP_RFSILENT_ENABLED) {
@@ -1932,23 +1894,6 @@
 	else
 		pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS;
 
-	if (regulatory->current_rd_ext & (1 << REG_EXT_JAPAN_MIDBAND)) {
-		pCap->reg_cap =
-			AR_EEPROM_EEREGCAP_EN_KK_NEW_11A |
-			AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN |
-			AR_EEPROM_EEREGCAP_EN_KK_U2 |
-			AR_EEPROM_EEREGCAP_EN_KK_MIDBAND;
-	} else {
-		pCap->reg_cap =
-			AR_EEPROM_EEREGCAP_EN_KK_NEW_11A |
-			AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN;
-	}
-
-	/* Advertise midband for AR5416 with FCC midband set in eeprom */
-	if (regulatory->current_rd_ext & (1 << REG_EXT_FCC_MIDBAND) &&
-	    AR_SREV_5416(ah))
-		pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND;
-
 	if (AR_SREV_9280_20_OR_LATER(ah) && common->btcoex_enabled) {
 		btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO;
 		btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO;
@@ -2195,11 +2140,9 @@
 	REG_WRITE(ah, AR_PHY_ERR, phybits);
 
 	if (phybits)
-		REG_WRITE(ah, AR_RXCFG,
-			  REG_READ(ah, AR_RXCFG) | AR_RXCFG_ZLFDMA);
+		REG_SET_BIT(ah, AR_RXCFG, AR_RXCFG_ZLFDMA);
 	else
-		REG_WRITE(ah, AR_RXCFG,
-			  REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA);
+		REG_CLR_BIT(ah, AR_RXCFG, AR_RXCFG_ZLFDMA);
 
 	REGWRITE_BUFFER_FLUSH(ah);
 }
@@ -2375,10 +2318,11 @@
 	return timer_table->gen_timer_index[b];
 }
 
-static u32 ath9k_hw_gettsf32(struct ath_hw *ah)
+u32 ath9k_hw_gettsf32(struct ath_hw *ah)
 {
 	return REG_READ(ah, AR_TSF_L32);
 }
+EXPORT_SYMBOL(ath9k_hw_gettsf32);
 
 struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
 					  void (*trigger)(void *),
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 6650fd4..a778b66 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -65,53 +65,49 @@
 
 /* Register read/write primitives */
 #define REG_WRITE(_ah, _reg, _val) \
-	ath9k_hw_common(_ah)->ops->write((_ah), (_val), (_reg))
+	(_ah)->reg_ops.write((_ah), (_val), (_reg))
 
 #define REG_READ(_ah, _reg) \
-	ath9k_hw_common(_ah)->ops->read((_ah), (_reg))
+	(_ah)->reg_ops.read((_ah), (_reg))
 
 #define REG_READ_MULTI(_ah, _addr, _val, _cnt)		\
-	ath9k_hw_common(_ah)->ops->multi_read((_ah), (_addr), (_val), (_cnt))
+	(_ah)->reg_ops.multi_read((_ah), (_addr), (_val), (_cnt))
+
+#define REG_RMW(_ah, _reg, _set, _clr) \
+	(_ah)->reg_ops.rmw((_ah), (_reg), (_set), (_clr))
 
 #define ENABLE_REGWRITE_BUFFER(_ah)					\
 	do {								\
-		if (ath9k_hw_common(_ah)->ops->enable_write_buffer)	\
-			ath9k_hw_common(_ah)->ops->enable_write_buffer((_ah)); \
+		if ((_ah)->reg_ops.enable_write_buffer)	\
+			(_ah)->reg_ops.enable_write_buffer((_ah)); \
 	} while (0)
 
 #define REGWRITE_BUFFER_FLUSH(_ah)					\
 	do {								\
-		if (ath9k_hw_common(_ah)->ops->write_flush)		\
-			ath9k_hw_common(_ah)->ops->write_flush((_ah));	\
+		if ((_ah)->reg_ops.write_flush)		\
+			(_ah)->reg_ops.write_flush((_ah));	\
 	} while (0)
 
 #define SM(_v, _f)  (((_v) << _f##_S) & _f)
 #define MS(_v, _f)  (((_v) & _f) >> _f##_S)
-#define REG_RMW(_a, _r, _set, _clr)    \
-	REG_WRITE(_a, _r, (REG_READ(_a, _r) & ~(_clr)) | (_set))
 #define REG_RMW_FIELD(_a, _r, _f, _v) \
-	REG_WRITE(_a, _r, \
-	(REG_READ(_a, _r) & ~_f) | (((_v) << _f##_S) & _f))
+	REG_RMW(_a, _r, (((_v) << _f##_S) & _f), (_f))
 #define REG_READ_FIELD(_a, _r, _f) \
 	(((REG_READ(_a, _r) & _f) >> _f##_S))
 #define REG_SET_BIT(_a, _r, _f) \
-	REG_WRITE(_a, _r, REG_READ(_a, _r) | (_f))
+	REG_RMW(_a, _r, (_f), 0)
 #define REG_CLR_BIT(_a, _r, _f) \
-	REG_WRITE(_a, _r, REG_READ(_a, _r) & ~(_f))
+	REG_RMW(_a, _r, 0, (_f))
 
-#define DO_DELAY(x) do {			\
-		if ((++(x) % 64) == 0)          \
-			udelay(1);		\
+#define DO_DELAY(x) do {					\
+		if (((++(x) % 64) == 0) &&			\
+		    (ath9k_hw_common(ah)->bus_ops->ath_bus_type	\
+			!= ATH_USB))				\
+			udelay(1);				\
 	} while (0)
 
-#define REG_WRITE_ARRAY(iniarray, column, regWr) do {                   \
-		int r;							\
-		for (r = 0; r < ((iniarray)->ia_rows); r++) {		\
-			REG_WRITE(ah, INI_RA((iniarray), (r), 0),	\
-				  INI_RA((iniarray), r, (column)));	\
-			DO_DELAY(regWr);				\
-		}							\
-	} while (0)
+#define REG_WRITE_ARRAY(iniarray, column, regWr) \
+	ath9k_hw_write_array(ah, iniarray, column, &(regWr))
 
 #define AR_GPIO_OUTPUT_MUX_AS_OUTPUT             0
 #define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1
@@ -178,7 +174,6 @@
 	ATH9K_HW_CAP_HT                         = BIT(0),
 	ATH9K_HW_CAP_RFSILENT                   = BIT(1),
 	ATH9K_HW_CAP_CST                        = BIT(2),
-	ATH9K_HW_CAP_ENHANCEDPM                 = BIT(3),
 	ATH9K_HW_CAP_AUTOSLEEP                  = BIT(4),
 	ATH9K_HW_CAP_4KB_SPLITTRANS             = BIT(5),
 	ATH9K_HW_CAP_EDMA			= BIT(6),
@@ -195,17 +190,11 @@
 
 struct ath9k_hw_capabilities {
 	u32 hw_caps; /* ATH9K_HW_CAP_* from ath9k_hw_caps */
-	u16 total_queues;
-	u16 keycache_size;
-	u16 low_5ghz_chan, high_5ghz_chan;
-	u16 low_2ghz_chan, high_2ghz_chan;
 	u16 rts_aggr_limit;
 	u8 tx_chainmask;
 	u8 rx_chainmask;
 	u8 max_txchains;
 	u8 max_rxchains;
-	u16 tx_triglevel_max;
-	u16 reg_cap;
 	u8 num_gpio_pins;
 	u8 rx_hp_qdepth;
 	u8 rx_lp_qdepth;
@@ -227,7 +216,6 @@
 	u8 pcie_clock_req;
 	u32 pcie_waen;
 	u8 analog_shiftreg;
-	u8 ht_enable;
 	u8 paprd_disable;
 	u32 ofdm_trig_low;
 	u32 ofdm_trig_high;
@@ -412,8 +400,6 @@
 	u32 bs_nextdtim;
 	u32 bs_intval;
 #define ATH9K_BEACON_PERIOD       0x0000ffff
-#define ATH9K_BEACON_ENA          0x00800000
-#define ATH9K_BEACON_RESET_TSF    0x01000000
 #define ATH9K_TSFOOR_THRESHOLD    0x00004240 /* 16k us */
 	u32 bs_dtimperiod;
 	u16 bs_cfpperiod;
@@ -640,8 +626,6 @@
 	void (*clr11n_aggr)(struct ath_hw *ah, void *ds);
 	void (*set11n_burstduration)(struct ath_hw *ah, void *ds,
 				     u32 burstDuration);
-	void (*set11n_virtualmorefrag)(struct ath_hw *ah, void *ds,
-				       u32 vmf);
 };
 
 struct ath_nf_limits {
@@ -655,6 +639,8 @@
 #define AH_UNPLUGGED    0x2 /* The card has been physically removed. */
 
 struct ath_hw {
+	struct ath_ops reg_ops;
+
 	struct ieee80211_hw *hw;
 	struct ath_common common;
 	struct ath9k_hw_version hw_version;
@@ -794,7 +780,9 @@
 	u32 originalGain[22];
 	int initPDADC;
 	int PDADCdelta;
-	u8 led_pin;
+	int led_pin;
+	u32 gpio_mask;
+	u32 gpio_val;
 
 	struct ar5416IniArray iniModes;
 	struct ar5416IniArray iniCommon;
@@ -907,8 +895,9 @@
 
 /* General Operation */
 bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout);
+void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array,
+			  int column, unsigned int *writecnt);
 u32 ath9k_hw_reverse_bits(u32 val, u32 n);
-bool ath9k_get_channel_edges(struct ath_hw *ah, u16 flags, u16 *low, u16 *high);
 u16 ath9k_hw_computetxtime(struct ath_hw *ah,
 			   u8 phy, int kbps,
 			   u32 frameLen, u16 rateix, bool shortPreamble);
@@ -924,6 +913,7 @@
 void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1);
 void ath9k_hw_setbssidmask(struct ath_hw *ah);
 void ath9k_hw_write_associd(struct ath_hw *ah);
+u32 ath9k_hw_gettsf32(struct ath_hw *ah);
 u64 ath9k_hw_gettsf64(struct ath_hw *ah);
 void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64);
 void ath9k_hw_reset_tsf(struct ath_hw *ah);
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 79aec98..1ac8318 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -15,6 +15,7 @@
  */
 
 #include <linux/slab.h>
+#include <linux/ath9k_platform.h>
 
 #include "ath9k.h"
 
@@ -195,10 +196,27 @@
 	return val;
 }
 
-static const struct ath_ops ath9k_common_ops = {
-	.read = ath9k_ioread32,
-	.write = ath9k_iowrite32,
-};
+static unsigned int ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr)
+{
+	struct ath_hw *ah = (struct ath_hw *) hw_priv;
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ath_softc *sc = (struct ath_softc *) common->priv;
+	unsigned long uninitialized_var(flags);
+	u32 val;
+
+	if (ah->config.serialize_regmode == SER_REG_MODE_ON)
+		spin_lock_irqsave(&sc->sc_serial_rw, flags);
+
+	val = ioread32(sc->mem + reg_offset);
+	val &= ~clr;
+	val |= set;
+	iowrite32(val, sc->mem + reg_offset);
+
+	if (ah->config.serialize_regmode == SER_REG_MODE_ON)
+		spin_unlock_irqrestore(&sc->sc_serial_rw, flags);
+
+	return val;
+}
 
 /**************************/
 /*     Initialization     */
@@ -389,13 +407,7 @@
 	int i = 0;
 
 	/* Get the hardware key cache size. */
-	common->keymax = sc->sc_ah->caps.keycache_size;
-	if (common->keymax > ATH_KEYMAX) {
-		ath_dbg(common, ATH_DBG_ANY,
-			"Warning, using only %u entries in %u key cache\n",
-			ATH_KEYMAX, common->keymax);
-		common->keymax = ATH_KEYMAX;
-	}
+	common->keymax = AR_KEYTABLE_SIZE;
 
 	/*
 	 * Reset the key cache since some parts do not
@@ -537,6 +549,7 @@
 static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
 			    const struct ath_bus_ops *bus_ops)
 {
+	struct ath9k_platform_data *pdata = sc->dev->platform_data;
 	struct ath_hw *ah = NULL;
 	struct ath_common *common;
 	int ret = 0, i;
@@ -549,13 +562,22 @@
 	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;
 	sc->sc_ah = ah;
 
-	if (!sc->dev->platform_data)
+	if (!pdata) {
 		ah->ah_flags |= AH_USE_EEPROM;
+		sc->sc_ah->led_pin = -1;
+	} else {
+		sc->sc_ah->gpio_mask = pdata->gpio_mask;
+		sc->sc_ah->gpio_val = pdata->gpio_val;
+		sc->sc_ah->led_pin = pdata->led_pin;
+	}
 
 	common = ath9k_hw_common(ah);
-	common->ops = &ath9k_common_ops;
+	common->ops = &ah->reg_ops;
 	common->bus_ops = bus_ops;
 	common->ah = ah;
 	common->hw = sc->hw;
@@ -587,6 +609,9 @@
 	if (ret)
 		goto err_hw;
 
+	if (pdata && pdata->macaddr)
+		memcpy(common->macaddr, pdata->macaddr, ETH_ALEN);
+
 	ret = ath9k_init_queues(sc);
 	if (ret)
 		goto err_queues;
@@ -679,6 +704,8 @@
 	if (AR_SREV_5416(sc->sc_ah))
 		hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
 
+	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
+
 	hw->queues = 4;
 	hw->max_rates = 4;
 	hw->channel_change_time = 5000;
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index 562257a..6f431cb 100644
--- a/drivers/net/wireless/ath/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -209,15 +209,8 @@
 {
 	u32 cw;
 	struct ath_common *common = ath9k_hw_common(ah);
-	struct ath9k_hw_capabilities *pCap = &ah->caps;
 	struct ath9k_tx_queue_info *qi;
 
-	if (q >= pCap->total_queues) {
-		ath_dbg(common, ATH_DBG_QUEUE,
-			"Set TXQ properties, invalid queue: %u\n", q);
-		return false;
-	}
-
 	qi = &ah->txq[q];
 	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
 		ath_dbg(common, ATH_DBG_QUEUE,
@@ -280,15 +273,8 @@
 			    struct ath9k_tx_queue_info *qinfo)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
-	struct ath9k_hw_capabilities *pCap = &ah->caps;
 	struct ath9k_tx_queue_info *qi;
 
-	if (q >= pCap->total_queues) {
-		ath_dbg(common, ATH_DBG_QUEUE,
-			"Get TXQ properties, invalid queue: %u\n", q);
-		return false;
-	}
-
 	qi = &ah->txq[q];
 	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
 		ath_dbg(common, ATH_DBG_QUEUE,
@@ -320,28 +306,27 @@
 {
 	struct ath_common *common = ath9k_hw_common(ah);
 	struct ath9k_tx_queue_info *qi;
-	struct ath9k_hw_capabilities *pCap = &ah->caps;
 	int q;
 
 	switch (type) {
 	case ATH9K_TX_QUEUE_BEACON:
-		q = pCap->total_queues - 1;
+		q = ATH9K_NUM_TX_QUEUES - 1;
 		break;
 	case ATH9K_TX_QUEUE_CAB:
-		q = pCap->total_queues - 2;
+		q = ATH9K_NUM_TX_QUEUES - 2;
 		break;
 	case ATH9K_TX_QUEUE_PSPOLL:
 		q = 1;
 		break;
 	case ATH9K_TX_QUEUE_UAPSD:
-		q = pCap->total_queues - 3;
+		q = ATH9K_NUM_TX_QUEUES - 3;
 		break;
 	case ATH9K_TX_QUEUE_DATA:
-		for (q = 0; q < pCap->total_queues; q++)
+		for (q = 0; q < ATH9K_NUM_TX_QUEUES; q++)
 			if (ah->txq[q].tqi_type ==
 			    ATH9K_TX_QUEUE_INACTIVE)
 				break;
-		if (q == pCap->total_queues) {
+		if (q == ATH9K_NUM_TX_QUEUES) {
 			ath_err(common, "No available TX queue\n");
 			return -1;
 		}
@@ -382,15 +367,9 @@
 
 bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q)
 {
-	struct ath9k_hw_capabilities *pCap = &ah->caps;
 	struct ath_common *common = ath9k_hw_common(ah);
 	struct ath9k_tx_queue_info *qi;
 
-	if (q >= pCap->total_queues) {
-		ath_dbg(common, ATH_DBG_QUEUE,
-			"Release TXQ, invalid queue: %u\n", q);
-		return false;
-	}
 	qi = &ah->txq[q];
 	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
 		ath_dbg(common, ATH_DBG_QUEUE,
@@ -414,18 +393,11 @@
 
 bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
 {
-	struct ath9k_hw_capabilities *pCap = &ah->caps;
 	struct ath_common *common = ath9k_hw_common(ah);
 	struct ath9k_channel *chan = ah->curchan;
 	struct ath9k_tx_queue_info *qi;
 	u32 cwMin, chanCwMin, value;
 
-	if (q >= pCap->total_queues) {
-		ath_dbg(common, ATH_DBG_QUEUE,
-			"Reset TXQ, invalid queue: %u\n", q);
-		return false;
-	}
-
 	qi = &ah->txq[q];
 	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
 		ath_dbg(common, ATH_DBG_QUEUE,
@@ -465,10 +437,9 @@
 		REG_WRITE(ah, AR_QCBRCFG(q),
 			  SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) |
 			  SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_OVF_THRESH));
-		REG_WRITE(ah, AR_QMISC(q),
-			  REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_FSP_CBR |
-			  (qi->tqi_cbrOverflowLimit ?
-			   AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0));
+		REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_FSP_CBR |
+			    (qi->tqi_cbrOverflowLimit ?
+			     AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0));
 	}
 	if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) {
 		REG_WRITE(ah, AR_QRDYTIMECFG(q),
@@ -481,40 +452,31 @@
 		  (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0));
 
 	if (qi->tqi_burstTime
-	    && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) {
-		REG_WRITE(ah, AR_QMISC(q),
-			  REG_READ(ah, AR_QMISC(q)) |
-			  AR_Q_MISC_RDYTIME_EXP_POLICY);
+	    && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE))
+		REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_RDYTIME_EXP_POLICY);
 
-	}
-
-	if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) {
-		REG_WRITE(ah, AR_DMISC(q),
-			  REG_READ(ah, AR_DMISC(q)) |
-			  AR_D_MISC_POST_FR_BKOFF_DIS);
-	}
+	if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE)
+		REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_POST_FR_BKOFF_DIS);
 
 	REGWRITE_BUFFER_FLUSH(ah);
 
-	if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) {
-		REG_WRITE(ah, AR_DMISC(q),
-			  REG_READ(ah, AR_DMISC(q)) |
-			  AR_D_MISC_FRAG_BKOFF_EN);
-	}
+	if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE)
+		REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_FRAG_BKOFF_EN);
+
 	switch (qi->tqi_type) {
 	case ATH9K_TX_QUEUE_BEACON:
 		ENABLE_REGWRITE_BUFFER(ah);
 
-		REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
-			  | AR_Q_MISC_FSP_DBA_GATED
-			  | AR_Q_MISC_BEACON_USE
-			  | AR_Q_MISC_CBR_INCR_DIS1);
+		REG_SET_BIT(ah, AR_QMISC(q),
+			    AR_Q_MISC_FSP_DBA_GATED
+			    | AR_Q_MISC_BEACON_USE
+			    | AR_Q_MISC_CBR_INCR_DIS1);
 
-		REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
-			  | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
+		REG_SET_BIT(ah, AR_DMISC(q),
+			    (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
 			     AR_D_MISC_ARB_LOCKOUT_CNTRL_S)
-			  | AR_D_MISC_BEACON_USE
-			  | AR_D_MISC_POST_FR_BKOFF_DIS);
+			    | AR_D_MISC_BEACON_USE
+			    | AR_D_MISC_POST_FR_BKOFF_DIS);
 
 		REGWRITE_BUFFER_FLUSH(ah);
 
@@ -533,41 +495,38 @@
 	case ATH9K_TX_QUEUE_CAB:
 		ENABLE_REGWRITE_BUFFER(ah);
 
-		REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
-			  | AR_Q_MISC_FSP_DBA_GATED
-			  | AR_Q_MISC_CBR_INCR_DIS1
-			  | AR_Q_MISC_CBR_INCR_DIS0);
+		REG_SET_BIT(ah, AR_QMISC(q),
+			    AR_Q_MISC_FSP_DBA_GATED
+			    | AR_Q_MISC_CBR_INCR_DIS1
+			    | AR_Q_MISC_CBR_INCR_DIS0);
 		value = (qi->tqi_readyTime -
 			 (ah->config.sw_beacon_response_time -
 			  ah->config.dma_beacon_response_time) -
 			 ah->config.additional_swba_backoff) * 1024;
 		REG_WRITE(ah, AR_QRDYTIMECFG(q),
 			  value | AR_Q_RDYTIMECFG_EN);
-		REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
-			  | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
+		REG_SET_BIT(ah, AR_DMISC(q),
+			    (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
 			     AR_D_MISC_ARB_LOCKOUT_CNTRL_S));
 
 		REGWRITE_BUFFER_FLUSH(ah);
 
 		break;
 	case ATH9K_TX_QUEUE_PSPOLL:
-		REG_WRITE(ah, AR_QMISC(q),
-			  REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_CBR_INCR_DIS1);
+		REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_CBR_INCR_DIS1);
 		break;
 	case ATH9K_TX_QUEUE_UAPSD:
-		REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) |
-			  AR_D_MISC_POST_FR_BKOFF_DIS);
+		REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_POST_FR_BKOFF_DIS);
 		break;
 	default:
 		break;
 	}
 
 	if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) {
-		REG_WRITE(ah, AR_DMISC(q),
-			  REG_READ(ah, AR_DMISC(q)) |
-			  SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,
-			     AR_D_MISC_ARB_LOCKOUT_CNTRL) |
-			  AR_D_MISC_POST_FR_BKOFF_DIS);
+		REG_SET_BIT(ah, AR_DMISC(q),
+			    SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,
+			       AR_D_MISC_ARB_LOCKOUT_CNTRL) |
+			    AR_D_MISC_POST_FR_BKOFF_DIS);
 	}
 
 	if (AR_SREV_9300_20_OR_LATER(ah))
@@ -754,7 +713,6 @@
 bool ath9k_hw_stopdmarecv(struct ath_hw *ah)
 {
 #define AH_RX_STOP_DMA_TIMEOUT 10000   /* usec */
-#define AH_RX_TIME_QUANTUM     100     /* usec */
 	struct ath_common *common = ath9k_hw_common(ah);
 	int i;
 
@@ -778,7 +736,6 @@
 		return true;
 	}
 
-#undef AH_RX_TIME_QUANTUM
 #undef AH_RX_STOP_DMA_TIMEOUT
 }
 EXPORT_SYMBOL(ath9k_hw_stopdmarecv);
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index dddb85d..ba1c9a6 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -299,7 +299,7 @@
 
 	if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) {
 		if (sc->sc_flags & SC_OP_BEACONS)
-			ath_beacon_config(sc, NULL);
+			ath_set_beacon(sc);
 		ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
 		ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2);
 		ath_start_ani(common);
@@ -828,48 +828,6 @@
 #undef SCHED_INTR
 }
 
-static void ath9k_bss_assoc_info(struct ath_softc *sc,
-				 struct ieee80211_hw *hw,
-				 struct ieee80211_vif *vif,
-				 struct ieee80211_bss_conf *bss_conf)
-{
-	struct ath_hw *ah = sc->sc_ah;
-	struct ath_common *common = ath9k_hw_common(ah);
-
-	if (bss_conf->assoc) {
-		ath_dbg(common, ATH_DBG_CONFIG,
-			"Bss Info ASSOC %d, bssid: %pM\n",
-			bss_conf->aid, common->curbssid);
-
-		/* New association, store aid */
-		common->curaid = bss_conf->aid;
-		ath9k_hw_write_associd(ah);
-
-		/*
-		 * Request a re-configuration of Beacon related timers
-		 * on the receipt of the first Beacon frame (i.e.,
-		 * after time sync with the AP).
-		 */
-		sc->ps_flags |= PS_BEACON_SYNC;
-
-		/* Configure the beacon */
-		ath_beacon_config(sc, vif);
-
-		/* Reset rssi stats */
-		sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
-		sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
-
-		sc->sc_flags |= SC_OP_ANI_RUN;
-		ath_start_ani(common);
-	} else {
-		ath_dbg(common, ATH_DBG_CONFIG, "Bss Info DISASSOC\n");
-		common->curaid = 0;
-		/* Stop ANI */
-		sc->sc_flags &= ~SC_OP_ANI_RUN;
-		del_timer_sync(&common->ani.timer);
-	}
-}
-
 void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
 {
 	struct ath_hw *ah = sc->sc_ah;
@@ -899,7 +857,7 @@
 		goto out;
 	}
 	if (sc->sc_flags & SC_OP_BEACONS)
-		ath_beacon_config(sc, NULL);	/* restart beacons */
+		ath_set_beacon(sc);	/* restart beacons */
 
 	/* Re-Enable  interrupts */
 	ath9k_hw_set_interrupts(ah, ah->imask);
@@ -1006,7 +964,7 @@
 			       sc->config.txpowlimit, &sc->curtxpow);
 
 	if ((sc->sc_flags & SC_OP_BEACONS) || !(sc->sc_flags & (SC_OP_OFFCHANNEL)))
-		ath_beacon_config(sc, NULL);	/* restart beacons */
+		ath_set_beacon(sc);	/* restart beacons */
 
 	ath9k_hw_set_interrupts(ah, ah->imask);
 
@@ -1417,9 +1375,6 @@
 	if ((iter_data.naps + iter_data.nadhocs) > 0) {
 		sc->sc_flags |= SC_OP_ANI_RUN;
 		ath_start_ani(common);
-	} else {
-		sc->sc_flags &= ~SC_OP_ANI_RUN;
-		del_timer_sync(&common->ani.timer);
 	}
 }
 
@@ -1454,7 +1409,6 @@
 	struct ath_softc *sc = hw->priv;
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_common *common = ath9k_hw_common(ah);
-	struct ath_vif *avp = (void *)vif->drv_priv;
 	int ret = 0;
 
 	mutex_lock(&sc->mutex);
@@ -1483,8 +1437,9 @@
 		}
 	}
 
-	if ((vif->type == NL80211_IFTYPE_ADHOC) &&
-	    sc->nvifs > 0) {
+	if ((ah->opmode == NL80211_IFTYPE_ADHOC) ||
+	    ((vif->type == NL80211_IFTYPE_ADHOC) &&
+	     sc->nvifs > 0)) {
 		ath_err(common, "Cannot create ADHOC interface when other"
 			" interfaces already exist.\n");
 		ret = -EINVAL;
@@ -1494,10 +1449,6 @@
 	ath_dbg(common, ATH_DBG_CONFIG,
 		"Attach a VIF of type: %d\n", vif->type);
 
-	/* Set the VIF opmode */
-	avp->av_opmode = vif->type;
-	avp->av_bslot = -1;
-
 	sc->nvifs++;
 
 	ath9k_do_vif_add_setup(hw, vif);
@@ -1849,6 +1800,20 @@
 	if (ath9k_modparam_nohwcrypt)
 		return -ENOSPC;
 
+	if (vif->type == NL80211_IFTYPE_ADHOC &&
+	    (key->cipher == WLAN_CIPHER_SUITE_TKIP ||
+	     key->cipher == WLAN_CIPHER_SUITE_CCMP) &&
+	    !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
+		/*
+		 * For now, disable hw crypto for the RSN IBSS group keys. This
+		 * could be optimized in the future to use a modified key cache
+		 * design to support per-STA RX GTK, but until that gets
+		 * implemented, use of software crypto for group addressed
+		 * frames is a acceptable to allow RSN IBSS to be used.
+		 */
+		return -EOPNOTSUPP;
+	}
+
 	mutex_lock(&sc->mutex);
 	ath9k_ps_wakeup(sc);
 	ath_dbg(common, ATH_DBG_CONFIG, "Set HW Key\n");
@@ -1880,6 +1845,86 @@
 
 	return ret;
 }
+static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
+{
+	struct ath_softc *sc = data;
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+	struct ath_vif *avp = (void *)vif->drv_priv;
+
+	switch (sc->sc_ah->opmode) {
+	case NL80211_IFTYPE_ADHOC:
+		/* There can be only one vif available */
+		memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
+		common->curaid = bss_conf->aid;
+		ath9k_hw_write_associd(sc->sc_ah);
+		/* configure beacon */
+		if (bss_conf->enable_beacon)
+			ath_beacon_config(sc, vif);
+		break;
+	case NL80211_IFTYPE_STATION:
+		/*
+		 * Skip iteration if primary station vif's bss info
+		 * was not changed
+		 */
+		if (sc->sc_flags & SC_OP_PRIM_STA_VIF)
+			break;
+
+		if (bss_conf->assoc) {
+			sc->sc_flags |= SC_OP_PRIM_STA_VIF;
+			avp->primary_sta_vif = true;
+			memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
+			common->curaid = bss_conf->aid;
+			ath9k_hw_write_associd(sc->sc_ah);
+			ath_dbg(common, ATH_DBG_CONFIG,
+				"Bss Info ASSOC %d, bssid: %pM\n",
+				bss_conf->aid, common->curbssid);
+			ath_beacon_config(sc, vif);
+			/* Reset rssi stats */
+			sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
+			sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
+
+			sc->sc_flags |= SC_OP_ANI_RUN;
+			ath_start_ani(common);
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif)
+{
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+	struct ath_vif *avp = (void *)vif->drv_priv;
+
+	/* Reconfigure bss info */
+	if (avp->primary_sta_vif && !bss_conf->assoc) {
+		ath_dbg(common, ATH_DBG_CONFIG,
+			"Bss Info DISASSOC %d, bssid %pM\n",
+			common->curaid, common->curbssid);
+		sc->sc_flags &= ~(SC_OP_PRIM_STA_VIF | SC_OP_BEACONS);
+		avp->primary_sta_vif = false;
+		memset(common->curbssid, 0, ETH_ALEN);
+		common->curaid = 0;
+	}
+
+	ieee80211_iterate_active_interfaces_atomic(
+			sc->hw, ath9k_bss_iter, sc);
+
+	/*
+	 * None of station vifs are associated.
+	 * Clear bssid & aid
+	 */
+	if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) &&
+	    !(sc->sc_flags & SC_OP_PRIM_STA_VIF)) {
+		ath9k_hw_write_associd(sc->sc_ah);
+		/* Stop ANI */
+		sc->sc_flags &= ~SC_OP_ANI_RUN;
+		del_timer_sync(&common->ani.timer);
+	}
+}
 
 static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
 				   struct ieee80211_vif *vif,
@@ -1887,7 +1932,6 @@
 				   u32 changed)
 {
 	struct ath_softc *sc = hw->priv;
-	struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_common *common = ath9k_hw_common(ah);
 	struct ath_vif *avp = (void *)vif->drv_priv;
@@ -1897,20 +1941,13 @@
 	mutex_lock(&sc->mutex);
 
 	if (changed & BSS_CHANGED_BSSID) {
-		/* Set BSSID */
-		memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
-		memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN);
-		common->curaid = 0;
-		ath9k_hw_write_associd(ah);
+		ath9k_config_bss(sc, vif);
 
 		/* Set aggregation protection mode parameters */
 		sc->config.ath_aggr_prot = 0;
 
 		ath_dbg(common, ATH_DBG_CONFIG, "BSSID: %pM aid: 0x%x\n",
 			common->curbssid, common->curaid);
-
-		/* need to reconfigure the beacon */
-		sc->sc_flags &= ~SC_OP_BEACONS ;
 	}
 
 	/* Enable transmission of beacons (AP, IBSS, MESH) */
@@ -1951,7 +1988,6 @@
 	}
 
 	if (changed & BSS_CHANGED_BEACON_INT) {
-		cur_conf->beacon_interval = bss_conf->beacon_int;
 		/*
 		 * In case of AP mode, the HW TSF has to be reset
 		 * when the beacon interval changes.
@@ -1963,9 +1999,8 @@
 			if (!error)
 				ath_beacon_config(sc, vif);
 			ath9k_set_beaconing_status(sc, true);
-		} else {
+		} else
 			ath_beacon_config(sc, vif);
-		}
 	}
 
 	if (changed & BSS_CHANGED_ERP_PREAMBLE) {
@@ -1987,12 +2022,6 @@
 			sc->sc_flags &= ~SC_OP_PROTECT_ENABLE;
 	}
 
-	if (changed & BSS_CHANGED_ASSOC) {
-		ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
-			bss_conf->assoc);
-		ath9k_bss_assoc_info(sc, hw, vif, bss_conf);
-	}
-
 	mutex_unlock(&sc->mutex);
 }
 
diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h
index 5e3d749..f50e2c2 100644
--- a/drivers/net/wireless/ath/ath9k/phy.h
+++ b/drivers/net/wireless/ath/ath9k/phy.h
@@ -38,25 +38,11 @@
 #define AR_PHY_CLC_Q0        0x0000ffd0
 #define AR_PHY_CLC_Q0_S      5
 
-#define REG_WRITE_RF_ARRAY(iniarray, regData, regWr) do {               \
-		int r;							\
-		for (r = 0; r < ((iniarray)->ia_rows); r++) {		\
-			REG_WRITE(ah, INI_RA((iniarray), r, 0), (regData)[r]); \
-			DO_DELAY(regWr);				\
-		}							\
-	} while (0)
-
 #define ANTSWAP_AB 0x0001
 #define REDUCE_CHAIN_0 0x00000050
 #define REDUCE_CHAIN_1 0x00000051
 #define AR_PHY_CHIP_ID 0x9818
 
-#define RF_BANK_SETUP(_bank, _iniarray, _col) do {			\
-		int i;							\
-		for (i = 0; i < (_iniarray)->ia_rows; i++)		\
-			(_bank)[i] = INI_RA((_iniarray), i, _col);;	\
-	} while (0)
-
 #define	AR_PHY_TIMING11_SPUR_FREQ_SD		0x3FF00000
 #define	AR_PHY_TIMING11_SPUR_FREQ_SD_S		20
 
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index a9c3f46..3842b75 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -574,7 +574,7 @@
 		sc->ps_flags &= ~PS_BEACON_SYNC;
 		ath_dbg(common, ATH_DBG_PS,
 			"Reconfigure Beacon timers based on timestamp from the AP\n");
-		ath_beacon_config(sc, NULL);
+		ath_set_beacon(sc);
 	}
 
 	if (ath_beacon_dtim_pending_cab(skb)) {
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index 8fa8acf..693d543 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -1396,6 +1396,7 @@
 #define AR_STA_ID1_PCF             0x00100000
 #define AR_STA_ID1_USE_DEFANT      0x00200000
 #define AR_STA_ID1_DEFANT_UPDATE   0x00400000
+#define AR_STA_ID1_AR9100_BA_FIX   0x00400000
 #define AR_STA_ID1_RTS_USE_DEF     0x00800000
 #define AR_STA_ID1_ACKCTS_6MB      0x01000000
 #define AR_STA_ID1_BASE_RATE_11B   0x02000000
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 26734e5..5943bdc 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1980,7 +1980,7 @@
 		if (ieee80211_is_data(hdr->frame_control) &&
 		    (ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN |
 		                     ATH9K_TX_DELIM_UNDERRUN)) &&
-		    ah->tx_trig_level >= sc->sc_ah->caps.tx_triglevel_max)
+		    ah->tx_trig_level >= sc->sc_ah->config.max_txtrig_level)
 			tx_info->status.rates[tx_rateindex].count =
 				hw->max_rate_tries;
 	}
@@ -2144,33 +2144,6 @@
 				} else {
 					txq->axq_tx_inprogress = true;
 				}
-			} else {
-				/* If the queue has pending buffers, then it
-				 * should be doing tx work (and have axq_depth).
-				 * Shouldn't get to this state I think..but
-				 * we do.
-				 */
-				if (!(sc->sc_flags & (SC_OP_OFFCHANNEL)) &&
-				    (txq->pending_frames > 0 ||
-				     !list_empty(&txq->axq_acq) ||
-				     txq->stopped)) {
-					ath_err(ath9k_hw_common(sc->sc_ah),
-						"txq: %p axq_qnum: %u,"
-						" mac80211_qnum: %i"
-						" axq_link: %p"
-						" pending frames: %i"
-						" axq_acq empty: %i"
-						" stopped: %i"
-						" axq_depth: 0  Attempting to"
-						" restart tx logic.\n",
-						txq, txq->axq_qnum,
-						txq->mac80211_qnum,
-						txq->axq_link,
-						txq->pending_frames,
-						list_empty(&txq->axq_acq),
-						txq->stopped);
-					ath_txq_schedule(sc, txq);
-				}
 			}
 			spin_unlock_bh(&txq->axq_lock);
 		}
diff --git a/drivers/net/wireless/ath/key.c b/drivers/net/wireless/ath/key.c
index 37b8e11..0d4f39c 100644
--- a/drivers/net/wireless/ath/key.c
+++ b/drivers/net/wireless/ath/key.c
@@ -23,6 +23,14 @@
 
 #define REG_READ			(common->ops->read)
 #define REG_WRITE(_ah, _reg, _val)	(common->ops->write)(_ah, _val, _reg)
+#define ENABLE_REGWRITE_BUFFER(_ah)			\
+	if (common->ops->enable_write_buffer)		\
+		common->ops->enable_write_buffer((_ah));
+
+#define REGWRITE_BUFFER_FLUSH(_ah)			\
+	if (common->ops->write_flush)			\
+		common->ops->write_flush((_ah));
+
 
 #define IEEE80211_WEP_NKID      4       /* number of key ids */
 
@@ -42,6 +50,8 @@
 
 	keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry));
 
+	ENABLE_REGWRITE_BUFFER(ah);
+
 	REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0);
 	REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0);
 	REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0);
@@ -66,6 +76,8 @@
 
 	}
 
+	REGWRITE_BUFFER_FLUSH(ah);
+
 	return true;
 }
 EXPORT_SYMBOL(ath_hw_keyreset);
@@ -104,9 +116,13 @@
 	} else {
 		macLo = macHi = 0;
 	}
+	ENABLE_REGWRITE_BUFFER(ah);
+
 	REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo);
 	REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | unicast_flag);
 
+	REGWRITE_BUFFER_FLUSH(ah);
+
 	return true;
 }
 
@@ -223,6 +239,8 @@
 			mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff;
 			mic4 = get_unaligned_le32(k->kv_txmic + 4);
 
+			ENABLE_REGWRITE_BUFFER(ah);
+
 			/* Write RX[31:0] and TX[31:16] */
 			REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
 			REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1);
@@ -236,6 +254,8 @@
 			REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
 				  AR_KEYTABLE_TYPE_CLR);
 
+			REGWRITE_BUFFER_FLUSH(ah);
+
 		} else {
 			/*
 			 * TKIP uses four key cache entries (two for group
@@ -258,6 +278,8 @@
 			mic0 = get_unaligned_le32(k->kv_mic + 0);
 			mic2 = get_unaligned_le32(k->kv_mic + 4);
 
+			ENABLE_REGWRITE_BUFFER(ah);
+
 			/* Write MIC key[31:0] */
 			REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
 			REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
@@ -270,8 +292,12 @@
 			REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0);
 			REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
 				  AR_KEYTABLE_TYPE_CLR);
+
+			REGWRITE_BUFFER_FLUSH(ah);
 		}
 
+		ENABLE_REGWRITE_BUFFER(ah);
+
 		/* MAC address registers are reserved for the MIC entry */
 		REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0);
 		REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0);
@@ -283,7 +309,11 @@
 		 */
 		REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
 		REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
+
+		REGWRITE_BUFFER_FLUSH(ah);
 	} else {
+		ENABLE_REGWRITE_BUFFER(ah);
+
 		/* Write key[47:0] */
 		REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
 		REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
@@ -296,6 +326,8 @@
 		REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
 		REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
 
+		REGWRITE_BUFFER_FLUSH(ah);
+
 		/* Write MAC address for the entry */
 		(void) ath_hw_keysetmac(common, entry, mac);
 	}
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index 9d6ee83..3652931 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -2,7 +2,7 @@
 obj-$(CONFIG_IWLAGN)	+= iwlagn.o
 iwlagn-objs		:= iwl-agn.o iwl-agn-rs.o iwl-agn-led.o
 iwlagn-objs		+= iwl-agn-ucode.o iwl-agn-tx.o
-iwlagn-objs		+= iwl-agn-lib.o iwl-agn-calib.o
+iwlagn-objs		+= iwl-agn-lib.o iwl-agn-calib.o iwl-io.o
 iwlagn-objs		+= iwl-agn-tt.o iwl-agn-sta.o iwl-agn-eeprom.o
 
 iwlagn-objs 		+= iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index 27c5007..1b27992 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -141,7 +141,6 @@
 	priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE;
 	priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE;
 
-	priv->hw_params.max_bsm_size = 0;
 	priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
 					BIT(IEEE80211_BAND_5GHZ);
 	priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
@@ -179,21 +178,16 @@
 	.txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl,
 	.txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl,
 	.txq_set_sched = iwlagn_txq_set_sched,
-	.txq_agg_enable = iwlagn_txq_agg_enable,
-	.txq_agg_disable = iwlagn_txq_agg_disable,
 	.txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
 	.txq_free_tfd = iwl_hw_txq_free_tfd,
 	.txq_init = iwl_hw_tx_queue_init,
 	.rx_handler_setup = iwlagn_rx_handler_setup,
 	.setup_deferred_work = iwlagn_setup_deferred_work,
 	.is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
-	.load_ucode = iwlagn_load_ucode,
 	.dump_nic_event_log = iwl_dump_nic_event_log,
 	.dump_nic_error_log = iwl_dump_nic_error_log,
 	.dump_csr = iwl_dump_csr,
 	.dump_fh = iwl_dump_fh,
-	.init_alive_start = iwlagn_init_alive_start,
-	.alive_notify = iwlagn_alive_notify,
 	.send_tx_power = iwlagn_send_tx_power,
 	.update_chain_flags = iwl_update_chain_flags,
 	.apm_ops = {
@@ -215,13 +209,6 @@
 		.calib_version	= iwlagn_eeprom_calib_version,
 		.query_addr = iwlagn_eeprom_query_addr,
 	},
-	.isr_ops = {
-		.isr = iwl_isr_ict,
-		.free = iwl_free_isr_ict,
-		.alloc = iwl_alloc_isr_ict,
-		.reset = iwl_reset_ict,
-		.disable = iwl_disable_ict,
-	},
 	.temp_ops = {
 		.temperature = iwlagn_temperature,
 	 },
@@ -255,7 +242,6 @@
 	.eeprom_size = OTP_LOW_IMAGE_SIZE,
 	.pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
 	.set_l0s = true,
-	.use_bsm = false,
 	.max_ll_items = OTP_MAX_LL_ITEMS_1000,
 	.shadow_ram_support = false,
 	.led_compensation = 51,
diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c
index d7b6126..f602af4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-2000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-2000.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -147,7 +147,6 @@
 	priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE;
 	priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE;
 
-	priv->hw_params.max_bsm_size = 0;
 	priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
 					BIT(IEEE80211_BAND_5GHZ);
 	priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
@@ -259,8 +258,6 @@
 	.txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl,
 	.txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl,
 	.txq_set_sched = iwlagn_txq_set_sched,
-	.txq_agg_enable = iwlagn_txq_agg_enable,
-	.txq_agg_disable = iwlagn_txq_agg_disable,
 	.txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
 	.txq_free_tfd = iwl_hw_txq_free_tfd,
 	.txq_init = iwl_hw_tx_queue_init,
@@ -268,13 +265,10 @@
 	.setup_deferred_work = iwlagn_bt_setup_deferred_work,
 	.cancel_deferred_work = iwlagn_bt_cancel_deferred_work,
 	.is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
-	.load_ucode = iwlagn_load_ucode,
 	.dump_nic_event_log = iwl_dump_nic_event_log,
 	.dump_nic_error_log = iwl_dump_nic_error_log,
 	.dump_csr = iwl_dump_csr,
 	.dump_fh = iwl_dump_fh,
-	.init_alive_start = iwlagn_init_alive_start,
-	.alive_notify = iwlagn_alive_notify,
 	.send_tx_power = iwlagn_send_tx_power,
 	.update_chain_flags = iwl_update_chain_flags,
 	.set_channel_switch = iwl2030_hw_channel_switch,
@@ -298,13 +292,6 @@
 		.query_addr = iwlagn_eeprom_query_addr,
 		.update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
 	},
-	.isr_ops = {
-		.isr = iwl_isr_ict,
-		.free = iwl_free_isr_ict,
-		.alloc = iwl_alloc_isr_ict,
-		.reset = iwl_reset_ict,
-		.disable = iwl_disable_ict,
-	},
 	.temp_ops = {
 		.temperature = iwlagn_temperature,
 	},
@@ -362,7 +349,6 @@
 	.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
 	.pll_cfg_val = 0,
 	.set_l0s = true,
-	.use_bsm = false,
 	.max_ll_items = OTP_MAX_LL_ITEMS_2x00,
 	.shadow_ram_support = true,
 	.led_compensation = 51,
@@ -386,7 +372,6 @@
 	.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
 	.pll_cfg_val = 0,
 	.set_l0s = true,
-	.use_bsm = false,
 	.max_ll_items = OTP_MAX_LL_ITEMS_2x00,
 	.shadow_ram_support = true,
 	.led_compensation = 57,
@@ -471,37 +456,6 @@
 	IWL_DEVICE_2030,
 };
 
-#define IWL_DEVICE_6035						\
-	.fw_name_pre = IWL2030_FW_PRE,				\
-	.ucode_api_max = IWL2030_UCODE_API_MAX,			\
-	.ucode_api_min = IWL2030_UCODE_API_MIN,			\
-	.eeprom_ver = EEPROM_6035_EEPROM_VERSION,		\
-	.eeprom_calib_ver = EEPROM_6035_TX_POWER_VERSION,	\
-	.ops = &iwl2030_ops,					\
-	.mod_params = &iwlagn_mod_params,			\
-	.base_params = &iwl2030_base_params,			\
-	.bt_params = &iwl2030_bt_params,			\
-	.need_dc_calib = true,					\
-	.need_temp_offset_calib = true,				\
-	.led_mode = IWL_LED_RF_STATE,				\
-	.adv_pm = true						\
-
-struct iwl_cfg iwl6035_2agn_cfg = {
-	.name = "2000 Series 2x2 AGN/BT",
-	IWL_DEVICE_6035,
-	.ht_params = &iwl2000_ht_params,
-};
-
-struct iwl_cfg iwl6035_2abg_cfg = {
-	.name = "2000 Series 2x2 ABG/BT",
-	IWL_DEVICE_6035,
-};
-
-struct iwl_cfg iwl6035_2bg_cfg = {
-	.name = "2000 Series 2x2 BG/BT",
-	IWL_DEVICE_6035,
-};
-
 #define IWL_DEVICE_200						\
 	.fw_name_pre = IWL200_FW_PRE,				\
 	.ucode_api_max = IWL200_UCODE_API_MAX,			\
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
index 3975e45..05ad476 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index 22e045b..66f5fe8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -185,7 +185,6 @@
 	priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE;
 	priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE;
 
-	priv->hw_params.max_bsm_size = 0;
 	priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
 					BIT(IEEE80211_BAND_5GHZ);
 	priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
@@ -231,7 +230,6 @@
 	priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE;
 	priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE;
 
-	priv->hw_params.max_bsm_size = 0;
 	priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
 					BIT(IEEE80211_BAND_5GHZ);
 	priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
@@ -348,8 +346,6 @@
 	.txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl,
 	.txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl,
 	.txq_set_sched = iwlagn_txq_set_sched,
-	.txq_agg_enable = iwlagn_txq_agg_enable,
-	.txq_agg_disable = iwlagn_txq_agg_disable,
 	.txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
 	.txq_free_tfd = iwl_hw_txq_free_tfd,
 	.txq_init = iwl_hw_tx_queue_init,
@@ -360,9 +356,6 @@
 	.dump_nic_error_log = iwl_dump_nic_error_log,
 	.dump_csr = iwl_dump_csr,
 	.dump_fh = iwl_dump_fh,
-	.load_ucode = iwlagn_load_ucode,
-	.init_alive_start = iwlagn_init_alive_start,
-	.alive_notify = iwlagn_alive_notify,
 	.send_tx_power = iwlagn_send_tx_power,
 	.update_chain_flags = iwl_update_chain_flags,
 	.set_channel_switch = iwl5000_hw_channel_switch,
@@ -385,13 +378,6 @@
 		.calib_version	= iwlagn_eeprom_calib_version,
 		.query_addr = iwlagn_eeprom_query_addr,
 	},
-	.isr_ops = {
-		.isr = iwl_isr_ict,
-		.free = iwl_free_isr_ict,
-		.alloc = iwl_alloc_isr_ict,
-		.reset = iwl_reset_ict,
-		.disable = iwl_disable_ict,
-	},
 	.temp_ops = {
 		.temperature = iwlagn_temperature,
 	 },
@@ -416,8 +402,6 @@
 	.txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl,
 	.txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl,
 	.txq_set_sched = iwlagn_txq_set_sched,
-	.txq_agg_enable = iwlagn_txq_agg_enable,
-	.txq_agg_disable = iwlagn_txq_agg_disable,
 	.txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
 	.txq_free_tfd = iwl_hw_txq_free_tfd,
 	.txq_init = iwl_hw_tx_queue_init,
@@ -427,9 +411,6 @@
 	.dump_nic_event_log = iwl_dump_nic_event_log,
 	.dump_nic_error_log = iwl_dump_nic_error_log,
 	.dump_csr = iwl_dump_csr,
-	.load_ucode = iwlagn_load_ucode,
-	.init_alive_start = iwlagn_init_alive_start,
-	.alive_notify = iwlagn_alive_notify,
 	.send_tx_power = iwlagn_send_tx_power,
 	.update_chain_flags = iwl_update_chain_flags,
 	.set_channel_switch = iwl5000_hw_channel_switch,
@@ -452,13 +433,6 @@
 		.calib_version	= iwlagn_eeprom_calib_version,
 		.query_addr = iwlagn_eeprom_query_addr,
 	},
-	.isr_ops = {
-		.isr = iwl_isr_ict,
-		.free = iwl_free_isr_ict,
-		.alloc = iwl_alloc_isr_ict,
-		.reset = iwl_reset_ict,
-		.disable = iwl_disable_ict,
-	},
 	.temp_ops = {
 		.temperature = iwl5150_temperature,
 	 },
@@ -500,7 +474,6 @@
 	.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
 	.pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
 	.set_l0s = true,
-	.use_bsm = false,
 	.led_compensation = 51,
 	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000-hw.h b/drivers/net/wireless/iwlwifi/iwl-6000-hw.h
index 47891e1..b27986e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-6000-hw.h
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index a745b01..24d105b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -176,7 +176,6 @@
 	priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE;
 	priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE;
 
-	priv->hw_params.max_bsm_size = 0;
 	priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
 					BIT(IEEE80211_BAND_5GHZ);
 	priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
@@ -288,21 +287,16 @@
 	.txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl,
 	.txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl,
 	.txq_set_sched = iwlagn_txq_set_sched,
-	.txq_agg_enable = iwlagn_txq_agg_enable,
-	.txq_agg_disable = iwlagn_txq_agg_disable,
 	.txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
 	.txq_free_tfd = iwl_hw_txq_free_tfd,
 	.txq_init = iwl_hw_tx_queue_init,
 	.rx_handler_setup = iwlagn_rx_handler_setup,
 	.setup_deferred_work = iwlagn_setup_deferred_work,
 	.is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
-	.load_ucode = iwlagn_load_ucode,
 	.dump_nic_event_log = iwl_dump_nic_event_log,
 	.dump_nic_error_log = iwl_dump_nic_error_log,
 	.dump_csr = iwl_dump_csr,
 	.dump_fh = iwl_dump_fh,
-	.init_alive_start = iwlagn_init_alive_start,
-	.alive_notify = iwlagn_alive_notify,
 	.send_tx_power = iwlagn_send_tx_power,
 	.update_chain_flags = iwl_update_chain_flags,
 	.set_channel_switch = iwl6000_hw_channel_switch,
@@ -326,13 +320,6 @@
 		.query_addr = iwlagn_eeprom_query_addr,
 		.update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
 	},
-	.isr_ops = {
-		.isr = iwl_isr_ict,
-		.free = iwl_free_isr_ict,
-		.alloc = iwl_alloc_isr_ict,
-		.reset = iwl_reset_ict,
-		.disable = iwl_disable_ict,
-	},
 	.temp_ops = {
 		.temperature = iwlagn_temperature,
 	 },
@@ -357,8 +344,6 @@
 	.txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl,
 	.txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl,
 	.txq_set_sched = iwlagn_txq_set_sched,
-	.txq_agg_enable = iwlagn_txq_agg_enable,
-	.txq_agg_disable = iwlagn_txq_agg_disable,
 	.txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
 	.txq_free_tfd = iwl_hw_txq_free_tfd,
 	.txq_init = iwl_hw_tx_queue_init,
@@ -366,13 +351,10 @@
 	.setup_deferred_work = iwlagn_bt_setup_deferred_work,
 	.cancel_deferred_work = iwlagn_bt_cancel_deferred_work,
 	.is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
-	.load_ucode = iwlagn_load_ucode,
 	.dump_nic_event_log = iwl_dump_nic_event_log,
 	.dump_nic_error_log = iwl_dump_nic_error_log,
 	.dump_csr = iwl_dump_csr,
 	.dump_fh = iwl_dump_fh,
-	.init_alive_start = iwlagn_init_alive_start,
-	.alive_notify = iwlagn_alive_notify,
 	.send_tx_power = iwlagn_send_tx_power,
 	.update_chain_flags = iwl_update_chain_flags,
 	.set_channel_switch = iwl6000_hw_channel_switch,
@@ -396,13 +378,6 @@
 		.query_addr = iwlagn_eeprom_query_addr,
 		.update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
 	},
-	.isr_ops = {
-		.isr = iwl_isr_ict,
-		.free = iwl_free_isr_ict,
-		.alloc = iwl_alloc_isr_ict,
-		.reset = iwl_reset_ict,
-		.disable = iwl_disable_ict,
-	},
 	.temp_ops = {
 		.temperature = iwlagn_temperature,
 	 },
@@ -470,7 +445,6 @@
 	.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
 	.pll_cfg_val = 0,
 	.set_l0s = true,
-	.use_bsm = false,
 	.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
 	.shadow_ram_support = true,
 	.led_compensation = 51,
@@ -493,7 +467,6 @@
 	.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
 	.pll_cfg_val = 0,
 	.set_l0s = true,
-	.use_bsm = false,
 	.max_ll_items = OTP_MAX_LL_ITEMS_6x50,
 	.shadow_ram_support = true,
 	.led_compensation = 51,
@@ -515,7 +488,6 @@
 	.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
 	.pll_cfg_val = 0,
 	.set_l0s = true,
-	.use_bsm = false,
 	.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
 	.shadow_ram_support = true,
 	.led_compensation = 57,
@@ -613,6 +585,22 @@
 	IWL_DEVICE_6030,
 };
 
+struct iwl_cfg iwl6035_2agn_cfg = {
+	.name = "6035 Series 2x2 AGN/BT",
+	IWL_DEVICE_6030,
+	.ht_params = &iwl6000_ht_params,
+};
+
+struct iwl_cfg iwl6035_2abg_cfg = {
+	.name = "6035 Series 2x2 ABG/BT",
+	IWL_DEVICE_6030,
+};
+
+struct iwl_cfg iwl6035_2bg_cfg = {
+	.name = "6035 Series 2x2 BG/BT",
+	IWL_DEVICE_6030,
+};
+
 struct iwl_cfg iwl1030_bgn_cfg = {
 	.name = "Intel(R) Centrino(R) Wireless-N 1030 BGN",
 	IWL_DEVICE_6030,
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
index 9006293..7b761de 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.h b/drivers/net/wireless/iwlwifi/iwl-agn-calib.h
index e37ae726..ef4d507 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.h
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c
index b500aaa..d1834aa 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c
@@ -1,30 +1,30 @@
 /******************************************************************************
-*
-* GPL LICENSE SUMMARY
-*
-* Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
-*
-* This program is free software; you can redistribute it and/or modify
-* it under the terms of version 2 of the GNU General Public License as
-* published by the Free Software Foundation.
-*
-* This program is distributed in the hope that it will be useful, but
-* WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-* General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program; if not, write to the Free Software
-* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
-* USA
-*
-* The full GNU General Public License is included in this distribution
-* in the file called LICENSE.GPL.
-*
-* Contact Information:
-*  Intel Linux Wireless <ilw@linux.intel.com>
-* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-*****************************************************************************/
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *****************************************************************************/
 #include "iwl-agn.h"
 #include "iwl-agn-debugfs.h"
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h
index f2573b5..9a3f329 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h
@@ -2,7 +2,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c
index 27b5a3e..3bcaa10 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -103,7 +103,7 @@
 				CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
 				EEPROM_SEM_TIMEOUT);
 		if (ret >= 0) {
-			IWL_DEBUG_IO(priv,
+			IWL_DEBUG_EEPROM(priv,
 				"Acquired semaphore after %d tries.\n",
 				count+1);
 			return ret;
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
index 41543ad..861cc93 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
@@ -2,7 +2,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h
index a52b82c..7bd19f4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c
index b5cb3be..34d77d2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c
@@ -2,7 +2,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -59,8 +59,6 @@
 int iwl_alloc_isr_ict(struct iwl_priv *priv)
 {
 
-	if (priv->cfg->base_params->use_isr_legacy)
-		return 0;
 	/* allocate shrared data table */
 	priv->_agn.ict_tbl_vir =
 		dma_alloc_coherent(&priv->pci_dev->dev,
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-led.c b/drivers/net/wireless/iwlwifi/iwl-agn-led.c
index c1190d9..4bb877e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-led.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-led.h b/drivers/net/wireless/iwlwifi/iwl-agn-led.h
index 96f323d..c0b7611 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-led.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-led.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
index 08ccb94..9e47be6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
@@ -2,7 +2,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -652,8 +652,7 @@
 	const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */
 	u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT for all devices? */
 
-	if (!priv->cfg->base_params->use_isr_legacy)
-		rb_timeout = RX_RB_TIMEOUT;
+	rb_timeout = RX_RB_TIMEOUT;
 
 	if (priv->cfg->mod_params->amsdu_size_8K)
 		rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K;
@@ -913,7 +912,6 @@
 
 		list_add_tail(&rxb->list, &rxq->rx_free);
 		rxq->free_count++;
-		priv->alloc_rxb_page++;
 
 		spin_unlock_irqrestore(&rxq->lock, flags);
 	}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index d03b473..dbe6295 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -115,13 +115,18 @@
 	/* FIXME:RS:          ^^    should be INV (legacy) */
 };
 
+static inline u8 rs_extract_rate(u32 rate_n_flags)
+{
+	return (u8)(rate_n_flags & RATE_MCS_RATE_MSK);
+}
+
 static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags)
 {
 	int idx = 0;
 
 	/* HT rate format */
 	if (rate_n_flags & RATE_MCS_HT_MSK) {
-		idx = (rate_n_flags & 0xff);
+		idx = rs_extract_rate(rate_n_flags);
 
 		if (idx >= IWL_RATE_MIMO3_6M_PLCP)
 			idx = idx - IWL_RATE_MIMO3_6M_PLCP;
@@ -138,7 +143,8 @@
 	/* legacy rate format, search for match in table */
 	} else {
 		for (idx = 0; idx < ARRAY_SIZE(iwl_rates); idx++)
-			if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF))
+			if (iwl_rates[idx].plcp ==
+					rs_extract_rate(rate_n_flags))
 				return idx;
 	}
 
@@ -239,11 +245,6 @@
 
 #define MCS_INDEX_PER_STREAM	(8)
 
-static inline u8 rs_extract_rate(u32 rate_n_flags)
-{
-	return (u8)(rate_n_flags & 0xFF);
-}
-
 static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window)
 {
 	window->data = 0;
@@ -2770,16 +2771,13 @@
 static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta,
 			  gfp_t gfp)
 {
-	struct iwl_lq_sta *lq_sta;
 	struct iwl_station_priv *sta_priv = (struct iwl_station_priv *) sta->drv_priv;
 	struct iwl_priv *priv;
 
 	priv = (struct iwl_priv *)priv_rate;
 	IWL_DEBUG_RATE(priv, "create station rate scale window\n");
 
-	lq_sta = &sta_priv->lq_sta;
-
-	return lq_sta;
+	return &sta_priv->lq_sta;
 }
 
 /*
@@ -2912,7 +2910,8 @@
 		ant_toggle_cnt = 1;
 		repeat_rate = IWL_NUMBER_TRY;
 	} else {
-		repeat_rate = IWL_HT_NUMBER_TRY;
+		repeat_rate = min(IWL_HT_NUMBER_TRY,
+				  LINK_QUAL_AGG_DISABLE_START_DEF - 1);
 	}
 
 	lq_cmd->general_params.mimo_delimiter =
@@ -3257,7 +3256,6 @@
 {
 	char buff[120];
 	int desc = 0;
-	ssize_t ret;
 
 	struct iwl_lq_sta *lq_sta = file->private_data;
 	struct iwl_priv *priv;
@@ -3274,8 +3272,7 @@
 				"Bit Rate= %d Mb/s\n",
 				iwl_rates[lq_sta->last_txrate_idx].ieee >> 1);
 
-	ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
-	return ret;
+	return simple_read_from_buffer(user_buf, count, ppos, buff, desc);
 }
 
 static const struct file_operations rs_sta_dbgfs_rate_scale_data_ops = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
index 184828c..69a2993 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -41,20 +41,6 @@
 	u8 next_rs_tgg;  /* next rate used in TGG rs algo */
 };
 
-struct iwl3945_rate_info {
-	u8 plcp;		/* uCode API:  IWL_RATE_6M_PLCP, etc. */
-	u8 ieee;		/* MAC header:  IWL_RATE_6M_IEEE, etc. */
-	u8 prev_ieee;		/* previous rate in IEEE speeds */
-	u8 next_ieee;		/* next rate in IEEE speeds */
-	u8 prev_rs;		/* previous rate used in rs algo */
-	u8 next_rs;		/* next rate used in rs algo */
-	u8 prev_rs_tgg;		/* previous rate used in TGG rs algo */
-	u8 next_rs_tgg;		/* next rate used in TGG rs algo */
-	u8 table_rs_index;	/* index in rate scale table cmd */
-	u8 prev_table_rs;	/* prev in rate table cmd */
-};
-
-
 /*
  * These serve as indexes into
  * struct iwl_rate_info iwl_rates[IWL_RATE_COUNT];
@@ -75,7 +61,6 @@
 	IWL_RATE_60M_INDEX,
 	IWL_RATE_COUNT, /*FIXME:RS:change to IWL_RATE_INDEX_COUNT,*/
 	IWL_RATE_COUNT_LEGACY = IWL_RATE_COUNT - 1,	/* Excluding 60M */
-	IWL_RATE_COUNT_3945 = IWL_RATE_COUNT - 1,
 	IWL_RATE_INVM_INDEX = IWL_RATE_COUNT,
 	IWL_RATE_INVALID = IWL_RATE_COUNT,
 };
@@ -213,7 +198,6 @@
 	 IWL_CCK_BASIC_RATES_MASK)
 
 #define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1)
-#define IWL_RATES_MASK_3945 ((1 << IWL_RATE_COUNT_3945) - 1)
 
 #define IWL_INVALID_VALUE    -1
 
@@ -453,19 +437,9 @@
 }
 
 
-/**
- * iwl3945_rate_scale_init - Initialize the rate scale table based on assoc info
- *
- * The specific throughput table used is based on the type of network
- * the associated with, including A, B, G, and G w/ TGG protection
- */
-extern void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id);
-
 /* Initialize station's rate scaling information after adding station */
 extern void iwl_rs_rate_init(struct iwl_priv *priv,
 			     struct ieee80211_sta *sta, u8 sta_id);
-extern void iwl3945_rs_rate_init(struct iwl_priv *priv,
-				 struct ieee80211_sta *sta, u8 sta_id);
 
 /**
  * iwl_rate_control_register - Register the rate control algorithm callbacks
@@ -478,7 +452,6 @@
  *
  */
 extern int iwlagn_rate_control_register(void);
-extern int iwl3945_rate_control_register(void);
 
 /**
  * iwl_rate_control_unregister - Unregister the rate control callbacks
@@ -487,6 +460,5 @@
  * the driver is unloaded.
  */
 extern void iwlagn_rate_control_unregister(void);
-extern void iwl3945_rate_control_unregister(void);
 
 #endif /* __iwl_agn__rs__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
index dfdbea6..c335ee6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c
index 35f085a..079275f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
@@ -474,7 +474,7 @@
 	memset(&priv->stations[sta_id].keyinfo, 0,
 					sizeof(struct iwl_hw_key));
 	memset(&priv->stations[sta_id].sta.key, 0,
-					sizeof(struct iwl4965_keyinfo));
+					sizeof(struct iwl_keyinfo));
 	priv->stations[sta_id].sta.key.key_flags =
 			STA_KEY_FLG_NO_ENC | STA_KEY_FLG_INVALID;
 	priv->stations[sta_id].sta.key.key_offset = WEP_INVALID_OFFSET;
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c
index e3a8216..348f74f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.h b/drivers/net/wireless/iwlwifi/iwl-agn-tt.h
index d550604..d118ed2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tt.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tt.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index a709d05..2816b43 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -2,7 +2,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -222,13 +222,8 @@
 		       scd_retry ? "BA" : "AC/CMD", txq_id, tx_fifo_id);
 }
 
-int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id,
-			  int tx_fifo, int sta_id, int tid, u16 ssn_idx)
+static int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, int sta_id, int tid)
 {
-	unsigned long flags;
-	u16 ra_tid;
-	int ret;
-
 	if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) ||
 	    (IWLAGN_FIRST_AMPDU_QUEUE +
 		priv->cfg->base_params->num_of_ampdu_queues <= txq_id)) {
@@ -240,12 +235,33 @@
 		return -EINVAL;
 	}
 
-	ra_tid = BUILD_RAxTID(sta_id, tid);
-
 	/* Modify device's station table to Tx this TID */
-	ret = iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
-	if (ret)
-		return ret;
+	return iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
+}
+
+void iwlagn_txq_agg_queue_setup(struct iwl_priv *priv,
+				struct ieee80211_sta *sta,
+				int tid, int frame_limit)
+{
+	int sta_id, tx_fifo, txq_id, ssn_idx;
+	u16 ra_tid;
+	unsigned long flags;
+	struct iwl_tid_data *tid_data;
+
+	sta_id = iwl_sta_id(sta);
+	if (WARN_ON(sta_id == IWL_INVALID_STATION))
+		return;
+	if (WARN_ON(tid >= MAX_TID_COUNT))
+		return;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+	tid_data = &priv->stations[sta_id].tid[tid];
+	ssn_idx = SEQ_TO_SN(tid_data->seq_number);
+	txq_id = tid_data->agg.txq_id;
+	tx_fifo = tid_data->agg.tx_fifo;
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+	ra_tid = BUILD_RAxTID(sta_id, tid);
 
 	spin_lock_irqsave(&priv->lock, flags);
 
@@ -271,10 +287,10 @@
 	iwl_write_targ_mem(priv, priv->scd_base_addr +
 			IWLAGN_SCD_CONTEXT_QUEUE_OFFSET(txq_id) +
 			sizeof(u32),
-			((SCD_WIN_SIZE <<
+			((frame_limit <<
 			IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
 			IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
-			((SCD_FRAME_LIMIT <<
+			((frame_limit <<
 			IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
 			IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
 
@@ -284,12 +300,10 @@
 	iwlagn_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1);
 
 	spin_unlock_irqrestore(&priv->lock, flags);
-
-	return 0;
 }
 
-int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
-			   u16 ssn_idx, u8 tx_fifo)
+static int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
+				  u16 ssn_idx, u8 tx_fifo)
 {
 	if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) ||
 	    (IWLAGN_FIRST_AMPDU_QUEUE +
@@ -1034,11 +1048,11 @@
 	tid_data = &priv->stations[sta_id].tid[tid];
 	*ssn = SEQ_TO_SN(tid_data->seq_number);
 	tid_data->agg.txq_id = txq_id;
+	tid_data->agg.tx_fifo = tx_fifo;
 	iwl_set_swq_id(&priv->txq[txq_id], get_ac_from_tid(tid), txq_id);
 	spin_unlock_irqrestore(&priv->sta_lock, flags);
 
-	ret = priv->cfg->ops->lib->txq_agg_enable(priv, txq_id, tx_fifo,
-						  sta_id, tid, *ssn);
+	ret = iwlagn_txq_agg_enable(priv, txq_id, sta_id, tid);
 	if (ret)
 		return ret;
 
@@ -1125,8 +1139,7 @@
 	 * to deactivate the uCode queue, just return "success" to allow
 	 *  mac80211 to clean up it own data.
 	 */
-	priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn,
-						   tx_fifo_id);
+	iwlagn_txq_agg_disable(priv, txq_id, ssn, tx_fifo_id);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
@@ -1155,8 +1168,7 @@
 			u16 ssn = SEQ_TO_SN(tid_data->seq_number);
 			int tx_fifo = get_fifo_from_tid(ctx, tid);
 			IWL_DEBUG_HT(priv, "HW queue empty: continue DELBA flow\n");
-			priv->cfg->ops->lib->txq_agg_disable(priv, txq_id,
-							     ssn, tx_fifo);
+			iwlagn_txq_agg_disable(priv, txq_id, ssn, tx_fifo);
 			tid_data->agg.state = IWL_AGG_OFF;
 			ieee80211_stop_tx_ba_cb_irqsafe(ctx->vif, addr, tid);
 		}
@@ -1251,11 +1263,11 @@
 				 struct iwl_compressed_ba_resp *ba_resp)
 
 {
-	int i, sh, ack;
+	int sh;
 	u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl);
 	u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
-	int successes = 0;
 	struct ieee80211_tx_info *info;
+	u64 bitmap, sent_bitmap;
 
 	if (unlikely(!agg->wait_for_ba))  {
 		if (unlikely(ba_resp->bitmap))
@@ -1269,70 +1281,42 @@
 
 	/* Calculate shift to align block-ack bits with our Tx window bits */
 	sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl >> 4);
-	if (sh < 0) /* tbw something is wrong with indices */
+	if (sh < 0)
 		sh += 0x100;
 
-	if (agg->frame_count > (64 - sh)) {
-		IWL_DEBUG_TX_REPLY(priv, "more frames than bitmap size");
-		return -1;
-	}
-	if (!priv->cfg->base_params->no_agg_framecnt_info && ba_resp->txed) {
+	/*
+	 * Check for success or failure according to the
+	 * transmitted bitmap and block-ack bitmap
+	 */
+	bitmap = le64_to_cpu(ba_resp->bitmap) >> sh;
+	sent_bitmap = bitmap & agg->bitmap;
+
+	/* Sanity check values reported by uCode */
+	if (ba_resp->txed_2_done > ba_resp->txed) {
+		IWL_DEBUG_TX_REPLY(priv,
+			"bogus sent(%d) and ack(%d) count\n",
+			ba_resp->txed, ba_resp->txed_2_done);
 		/*
-		 * sent and ack information provided by uCode
-		 * use it instead of figure out ourself
+		 * set txed_2_done = txed,
+		 * so it won't impact rate scale
 		 */
-		if (ba_resp->txed_2_done > ba_resp->txed) {
-			IWL_DEBUG_TX_REPLY(priv,
-				"bogus sent(%d) and ack(%d) count\n",
-				ba_resp->txed, ba_resp->txed_2_done);
-			/*
-			 * set txed_2_done = txed,
-			 * so it won't impact rate scale
-			 */
-			ba_resp->txed = ba_resp->txed_2_done;
-		}
-		IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n",
-				ba_resp->txed, ba_resp->txed_2_done);
-	} else {
-		u64 bitmap, sent_bitmap;
+		ba_resp->txed = ba_resp->txed_2_done;
+	}
+	IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n",
+			ba_resp->txed, ba_resp->txed_2_done);
 
-		/* don't use 64-bit values for now */
-		bitmap = le64_to_cpu(ba_resp->bitmap) >> sh;
-
-		/* check for success or failure according to the
-		 * transmitted bitmap and block-ack bitmap */
-		sent_bitmap = bitmap & agg->bitmap;
-
-		/* For each frame attempted in aggregation,
-		 * update driver's record of tx frame's status. */
-		i = 0;
-		while (sent_bitmap) {
-			ack = sent_bitmap & 1ULL;
-			successes += ack;
-			IWL_DEBUG_TX_REPLY(priv, "%s ON i=%d idx=%d raw=%d\n",
-				ack ? "ACK" : "NACK", i,
-				(agg->start_idx + i) & 0xff,
-				agg->start_idx + i);
-			sent_bitmap >>= 1;
-			++i;
-		}
-
-		IWL_DEBUG_TX_REPLY(priv, "Bitmap %llx\n",
-				   (unsigned long long)bitmap);
+	/* Find the first ACKed frame to store the TX status */
+	while (sent_bitmap && !(sent_bitmap & 1)) {
+		agg->start_idx = (agg->start_idx + 1) & 0xff;
+		sent_bitmap >>= 1;
 	}
 
 	info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb);
 	memset(&info->status, 0, sizeof(info->status));
 	info->flags |= IEEE80211_TX_STAT_ACK;
 	info->flags |= IEEE80211_TX_STAT_AMPDU;
-	if (!priv->cfg->base_params->no_agg_framecnt_info && ba_resp->txed) {
-		info->status.ampdu_ack_len = ba_resp->txed_2_done;
-		info->status.ampdu_len = ba_resp->txed;
-
-	} else {
-		info->status.ampdu_ack_len = successes;
-		info->status.ampdu_len = agg->frame_count;
-	}
+	info->status.ampdu_ack_len = ba_resp->txed_2_done;
+	info->status.ampdu_len = ba_resp->txed;
 	iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, info);
 
 	return 0;
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
index d807e5e..01a6d2f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
@@ -2,7 +2,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -311,14 +311,14 @@
 	/* initialize uCode was loaded... verify inst image.
 	 * This is a paranoid check, because we would not have gotten the
 	 * "initialize" alive if code weren't properly loaded.  */
-	if (iwl_verify_ucode(priv)) {
+	if (iwl_verify_ucode(priv, &priv->ucode_init)) {
 		/* Runtime instruction load was bad;
 		 * take it all the way back down so we can try again */
 		IWL_DEBUG_INFO(priv, "Bad \"initialize\" uCode load.\n");
 		goto restart;
 	}
 
-	ret = priv->cfg->ops->lib->alive_notify(priv);
+	ret = iwlagn_alive_notify(priv);
 	if (ret) {
 		IWL_WARN(priv,
 			"Could not complete ALIVE transition: %d\n", ret);
@@ -432,6 +432,7 @@
 	unsigned long flags;
 	int i, chan;
 	u32 reg_val;
+	int ret;
 
 	spin_lock_irqsave(&priv->lock, flags);
 
@@ -527,12 +528,15 @@
 	iwl_clear_bits_prph(priv, APMG_PCIDEV_STT_REG,
 			  APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
 
-	iwlagn_send_wimax_coex(priv);
+	ret = iwlagn_send_wimax_coex(priv);
+	if (ret)
+		return ret;
 
-	iwlagn_set_Xtal_calib(priv);
-	iwl_send_calib_results(priv);
+	ret = iwlagn_set_Xtal_calib(priv);
+	if (ret)
+		return ret;
 
-	return 0;
+	return iwl_send_calib_results(priv);
 }
 
 
@@ -541,11 +545,12 @@
  *   using sample data 100 bytes apart.  If these sample points are good,
  *   it's a pretty good bet that everything between them is good, too.
  */
-static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
+static int iwlcore_verify_inst_sparse(struct iwl_priv *priv,
+				      struct fw_desc *fw_desc)
 {
+	__le32 *image = (__le32 *)fw_desc->v_addr;
+	u32 len = fw_desc->len;
 	u32 val;
-	int ret = 0;
-	u32 errcnt = 0;
 	u32 i;
 
 	IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len);
@@ -556,104 +561,55 @@
 		 * if IWL_DL_IO is set */
 		iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR,
 			i + IWLAGN_RTC_INST_LOWER_BOUND);
-		val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
-		if (val != le32_to_cpu(*image)) {
-			ret = -EIO;
-			errcnt++;
-			if (errcnt >= 3)
-				break;
-		}
+		val = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
+		if (val != le32_to_cpu(*image))
+			return -EIO;
 	}
 
-	return ret;
+	return 0;
 }
 
-/**
- * iwlcore_verify_inst_full - verify runtime uCode image in card vs. host,
- *     looking at all data.
- */
-static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 *image,
-				 u32 len)
+static void iwl_print_mismatch_inst(struct iwl_priv *priv,
+				    struct fw_desc *fw_desc)
 {
+	__le32 *image = (__le32 *)fw_desc->v_addr;
+	u32 len = fw_desc->len;
 	u32 val;
-	u32 save_len = len;
-	int ret = 0;
-	u32 errcnt;
+	u32 offs;
+	int errors = 0;
 
 	IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len);
 
 	iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR,
 			   IWLAGN_RTC_INST_LOWER_BOUND);
 
-	errcnt = 0;
-	for (; len > 0; len -= sizeof(u32), image++) {
+	for (offs = 0;
+	     offs < len && errors < 20;
+	     offs += sizeof(u32), image++) {
 		/* read data comes through single port, auto-incr addr */
-		/* NOTE: Use the debugless read so we don't flood kernel log
-		 * if IWL_DL_IO is set */
-		val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+		val = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
 		if (val != le32_to_cpu(*image)) {
-			IWL_ERR(priv, "uCode INST section is invalid at "
-				  "offset 0x%x, is 0x%x, s/b 0x%x\n",
-				  save_len - len, val, le32_to_cpu(*image));
-			ret = -EIO;
-			errcnt++;
-			if (errcnt >= 20)
-				break;
+			IWL_ERR(priv, "uCode INST section at "
+				"offset 0x%x, is 0x%x, s/b 0x%x\n",
+				offs, val, le32_to_cpu(*image));
+			errors++;
 		}
 	}
-
-	if (!errcnt)
-		IWL_DEBUG_INFO(priv,
-		    "ucode image in INSTRUCTION memory is good\n");
-
-	return ret;
 }
 
 /**
  * iwl_verify_ucode - determine which instruction image is in SRAM,
  *    and verify its contents
  */
-int iwl_verify_ucode(struct iwl_priv *priv)
+int iwl_verify_ucode(struct iwl_priv *priv, struct fw_desc *fw_desc)
 {
-	__le32 *image;
-	u32 len;
-	int ret;
-
-	/* Try bootstrap */
-	image = (__le32 *)priv->ucode_boot.v_addr;
-	len = priv->ucode_boot.len;
-	ret = iwlcore_verify_inst_sparse(priv, image, len);
-	if (!ret) {
-		IWL_DEBUG_INFO(priv, "Bootstrap uCode is good in inst SRAM\n");
+	if (!iwlcore_verify_inst_sparse(priv, fw_desc)) {
+		IWL_DEBUG_INFO(priv, "uCode is good in inst SRAM\n");
 		return 0;
 	}
 
-	/* Try initialize */
-	image = (__le32 *)priv->ucode_init.v_addr;
-	len = priv->ucode_init.len;
-	ret = iwlcore_verify_inst_sparse(priv, image, len);
-	if (!ret) {
-		IWL_DEBUG_INFO(priv, "Initialize uCode is good in inst SRAM\n");
-		return 0;
-	}
+	IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n");
 
-	/* Try runtime/protocol */
-	image = (__le32 *)priv->ucode_code.v_addr;
-	len = priv->ucode_code.len;
-	ret = iwlcore_verify_inst_sparse(priv, image, len);
-	if (!ret) {
-		IWL_DEBUG_INFO(priv, "Runtime uCode is good in inst SRAM\n");
-		return 0;
-	}
-
-	IWL_ERR(priv, "NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n");
-
-	/* Since nothing seems to match, show first several data entries in
-	 * instruction SRAM, so maybe visual inspection will give a clue.
-	 * Selection of bootstrap image (vs. other images) is arbitrary. */
-	image = (__le32 *)priv->ucode_boot.v_addr;
-	len = priv->ucode_boot.len;
-	ret = iwl_verify_inst_full(priv, image, len);
-
-	return ret;
+	iwl_print_mismatch_inst(priv, fw_desc);
+	return -EIO;
 }
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 321b18b..60bfde7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
@@ -409,7 +409,7 @@
  * Tell nic where to find circular buffer of Tx Frame Descriptors for
  * given Tx queue, and enable the DMA channel used for that queue.
  *
- * 4965 supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA
+ * supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA
  * channels supported in hardware.
  */
 int iwl_hw_tx_queue_init(struct iwl_priv *priv,
@@ -483,12 +483,14 @@
 		container_of(work, struct iwl_priv, bt_full_concurrency);
 	struct iwl_rxon_context *ctx;
 
+	mutex_lock(&priv->mutex);
+
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-		return;
+		goto out;
 
 	/* dont send host command if rf-kill is on */
 	if (!iwl_is_ready_rf(priv))
-		return;
+		goto out;
 
 	IWL_DEBUG_INFO(priv, "BT coex in %s mode\n",
 		       priv->bt_full_concurrent ?
@@ -498,15 +500,15 @@
 	 * LQ & RXON updated cmds must be sent before BT Config cmd
 	 * to avoid 3-wire collisions
 	 */
-	mutex_lock(&priv->mutex);
 	for_each_context(priv, ctx) {
 		if (priv->cfg->ops->hcmd->set_rxon_chain)
 			priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
 		iwlcore_commit_rxon(priv, ctx);
 	}
-	mutex_unlock(&priv->mutex);
 
 	priv->cfg->ops->hcmd->send_bt_config(priv);
+out:
+	mutex_unlock(&priv->mutex);
 }
 
 /**
@@ -556,7 +558,7 @@
 	}
 
 	/* Set starting address; reads will auto-increment */
-	_iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr);
+	iwl_write32(priv, HBUS_TARG_MEM_RADDR, ptr);
 	rmb();
 
 	/*
@@ -564,13 +566,13 @@
 	 * place event id # at far right for easier visual parsing.
 	 */
 	for (i = 0; i < num_events; i++) {
-		ev = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
-		time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+		ev = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
+		time = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
 		if (mode == 0) {
 			trace_iwlwifi_dev_ucode_cont_event(priv,
 							0, time, ev);
 		} else {
-			data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+			data = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
 			trace_iwlwifi_dev_ucode_cont_event(priv,
 						time, data, ev);
 		}
@@ -588,10 +590,7 @@
 	u32 num_wraps;  /* # times uCode wrapped to top of log */
 	u32 next_entry; /* index of next entry to be written by uCode */
 
-	if (priv->ucode_type == UCODE_INIT)
-		base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
-	else
-		base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+	base = priv->device_pointers.error_event_table;
 	if (priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
 		capacity = iwl_read_targ_mem(priv, base);
 		num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
@@ -845,191 +844,6 @@
 	tasklet_kill(&priv->irq_tasklet);
 }
 
-static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
-{
-	u32 inta, handled = 0;
-	u32 inta_fh;
-	unsigned long flags;
-	u32 i;
-#ifdef CONFIG_IWLWIFI_DEBUG
-	u32 inta_mask;
-#endif
-
-	spin_lock_irqsave(&priv->lock, flags);
-
-	/* Ack/clear/reset pending uCode interrupts.
-	 * Note:  Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS,
-	 *  and will clear only when CSR_FH_INT_STATUS gets cleared. */
-	inta = iwl_read32(priv, CSR_INT);
-	iwl_write32(priv, CSR_INT, inta);
-
-	/* Ack/clear/reset pending flow-handler (DMA) interrupts.
-	 * Any new interrupts that happen after this, either while we're
-	 * in this tasklet, or later, will show up in next ISR/tasklet. */
-	inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
-	iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh);
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-	if (iwl_get_debug_level(priv) & IWL_DL_ISR) {
-		/* just for debug */
-		inta_mask = iwl_read32(priv, CSR_INT_MASK);
-		IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
-			      inta, inta_mask, inta_fh);
-	}
-#endif
-
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	/* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not
-	 * atomic, make sure that inta covers all the interrupts that
-	 * we've discovered, even if FH interrupt came in just after
-	 * reading CSR_INT. */
-	if (inta_fh & CSR49_FH_INT_RX_MASK)
-		inta |= CSR_INT_BIT_FH_RX;
-	if (inta_fh & CSR49_FH_INT_TX_MASK)
-		inta |= CSR_INT_BIT_FH_TX;
-
-	/* Now service all interrupt bits discovered above. */
-	if (inta & CSR_INT_BIT_HW_ERR) {
-		IWL_ERR(priv, "Hardware error detected.  Restarting.\n");
-
-		/* Tell the device to stop sending interrupts */
-		iwl_disable_interrupts(priv);
-
-		priv->isr_stats.hw++;
-		iwl_irq_handle_error(priv);
-
-		handled |= CSR_INT_BIT_HW_ERR;
-
-		return;
-	}
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-	if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) {
-		/* NIC fires this, but we don't use it, redundant with WAKEUP */
-		if (inta & CSR_INT_BIT_SCD) {
-			IWL_DEBUG_ISR(priv, "Scheduler finished to transmit "
-				      "the frame/frames.\n");
-			priv->isr_stats.sch++;
-		}
-
-		/* Alive notification via Rx interrupt will do the real work */
-		if (inta & CSR_INT_BIT_ALIVE) {
-			IWL_DEBUG_ISR(priv, "Alive interrupt\n");
-			priv->isr_stats.alive++;
-		}
-	}
-#endif
-	/* Safely ignore these bits for debug checks below */
-	inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE);
-
-	/* HW RF KILL switch toggled */
-	if (inta & CSR_INT_BIT_RF_KILL) {
-		int hw_rf_kill = 0;
-		if (!(iwl_read32(priv, CSR_GP_CNTRL) &
-				CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
-			hw_rf_kill = 1;
-
-		IWL_WARN(priv, "RF_KILL bit toggled to %s.\n",
-				hw_rf_kill ? "disable radio" : "enable radio");
-
-		priv->isr_stats.rfkill++;
-
-		/* driver only loads ucode once setting the interface up.
-		 * the driver allows loading the ucode even if the radio
-		 * is killed. Hence update the killswitch state here. The
-		 * rfkill handler will care about restarting if needed.
-		 */
-		if (!test_bit(STATUS_ALIVE, &priv->status)) {
-			if (hw_rf_kill)
-				set_bit(STATUS_RF_KILL_HW, &priv->status);
-			else
-				clear_bit(STATUS_RF_KILL_HW, &priv->status);
-			wiphy_rfkill_set_hw_state(priv->hw->wiphy, hw_rf_kill);
-		}
-
-		handled |= CSR_INT_BIT_RF_KILL;
-	}
-
-	/* Chip got too hot and stopped itself */
-	if (inta & CSR_INT_BIT_CT_KILL) {
-		IWL_ERR(priv, "Microcode CT kill error detected.\n");
-		priv->isr_stats.ctkill++;
-		handled |= CSR_INT_BIT_CT_KILL;
-	}
-
-	/* Error detected by uCode */
-	if (inta & CSR_INT_BIT_SW_ERR) {
-		IWL_ERR(priv, "Microcode SW error detected. "
-			" Restarting 0x%X.\n", inta);
-		priv->isr_stats.sw++;
-		iwl_irq_handle_error(priv);
-		handled |= CSR_INT_BIT_SW_ERR;
-	}
-
-	/*
-	 * uCode wakes up after power-down sleep.
-	 * Tell device about any new tx or host commands enqueued,
-	 * and about any Rx buffers made available while asleep.
-	 */
-	if (inta & CSR_INT_BIT_WAKEUP) {
-		IWL_DEBUG_ISR(priv, "Wakeup interrupt\n");
-		iwl_rx_queue_update_write_ptr(priv, &priv->rxq);
-		for (i = 0; i < priv->hw_params.max_txq_num; i++)
-			iwl_txq_update_write_ptr(priv, &priv->txq[i]);
-		priv->isr_stats.wakeup++;
-		handled |= CSR_INT_BIT_WAKEUP;
-	}
-
-	/* All uCode command responses, including Tx command responses,
-	 * Rx "responses" (frame-received notification), and other
-	 * notifications from uCode come through here*/
-	if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
-		iwl_rx_handle(priv);
-		priv->isr_stats.rx++;
-		handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
-	}
-
-	/* This "Tx" DMA channel is used only for loading uCode */
-	if (inta & CSR_INT_BIT_FH_TX) {
-		IWL_DEBUG_ISR(priv, "uCode load interrupt\n");
-		priv->isr_stats.tx++;
-		handled |= CSR_INT_BIT_FH_TX;
-		/* Wake up uCode load routine, now that load is complete */
-		priv->ucode_write_complete = 1;
-		wake_up_interruptible(&priv->wait_command_queue);
-	}
-
-	if (inta & ~handled) {
-		IWL_ERR(priv, "Unhandled INTA bits 0x%08x\n", inta & ~handled);
-		priv->isr_stats.unhandled++;
-	}
-
-	if (inta & ~(priv->inta_mask)) {
-		IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n",
-			 inta & ~priv->inta_mask);
-		IWL_WARN(priv, "   with FH_INT = 0x%08x\n", inta_fh);
-	}
-
-	/* Re-enable all interrupts */
-	/* only Re-enable if disabled by irq */
-	if (test_bit(STATUS_INT_ENABLED, &priv->status))
-		iwl_enable_interrupts(priv);
-	/* Re-enable RF_KILL if it occurred */
-	else if (handled & CSR_INT_BIT_RF_KILL)
-		iwl_enable_rfkill_int(priv);
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-	if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) {
-		inta = iwl_read32(priv, CSR_INT);
-		inta_mask = iwl_read32(priv, CSR_INT_MASK);
-		inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
-		IWL_DEBUG_ISR(priv, "End inta 0x%08x, enabled 0x%08x, fh 0x%08x, "
-			"flags 0x%08lx\n", inta, inta_mask, inta_fh, flags);
-	}
-#endif
-}
-
 /* tasklet for iwlagn interrupt */
 static void iwl_irq_tasklet(struct iwl_priv *priv)
 {
@@ -1171,7 +985,7 @@
 		if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
 			handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
 			iwl_write32(priv, CSR_FH_INT_STATUS,
-					CSR49_FH_INT_RX_MASK);
+					CSR_FH_INT_RX_MASK);
 		}
 		if (inta & CSR_INT_BIT_RX_PERIODIC) {
 			handled |= CSR_INT_BIT_RX_PERIODIC;
@@ -1209,7 +1023,7 @@
 
 	/* This "Tx" DMA channel is used only for loading uCode */
 	if (inta & CSR_INT_BIT_FH_TX) {
-		iwl_write32(priv, CSR_FH_INT_STATUS, CSR49_FH_INT_TX_MASK);
+		iwl_write32(priv, CSR_FH_INT_STATUS, CSR_FH_INT_TX_MASK);
 		IWL_DEBUG_ISR(priv, "uCode load interrupt\n");
 		priv->isr_stats.tx++;
 		handled |= CSR_INT_BIT_FH_TX;
@@ -1361,10 +1175,8 @@
 {
 	iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code);
 	iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data);
-	iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data_backup);
 	iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init);
 	iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init_data);
-	iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot);
 }
 
 static void iwl_nic_start(struct iwl_priv *priv)
@@ -1376,7 +1188,7 @@
 struct iwlagn_ucode_capabilities {
 	u32 max_probe_length;
 	u32 standard_phy_calibration_size;
-	bool pan;
+	u32 flags;
 };
 
 static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context);
@@ -1422,8 +1234,8 @@
 }
 
 struct iwlagn_firmware_pieces {
-	const void *inst, *data, *init, *init_data, *boot;
-	size_t inst_size, data_size, init_size, init_data_size, boot_size;
+	const void *inst, *data, *init, *init_data;
+	size_t inst_size, data_size, init_size, init_data_size;
 
 	u32 build;
 
@@ -1444,28 +1256,18 @@
 
 	switch (api_ver) {
 	default:
-		/*
-		 * 4965 doesn't revision the firmware file format
-		 * along with the API version, it always uses v1
-		 * file format.
-		 */
-		if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) !=
-				CSR_HW_REV_TYPE_4965) {
-			hdr_size = 28;
-			if (ucode_raw->size < hdr_size) {
-				IWL_ERR(priv, "File size too small!\n");
-				return -EINVAL;
-			}
-			pieces->build = le32_to_cpu(ucode->u.v2.build);
-			pieces->inst_size = le32_to_cpu(ucode->u.v2.inst_size);
-			pieces->data_size = le32_to_cpu(ucode->u.v2.data_size);
-			pieces->init_size = le32_to_cpu(ucode->u.v2.init_size);
-			pieces->init_data_size = le32_to_cpu(ucode->u.v2.init_data_size);
-			pieces->boot_size = le32_to_cpu(ucode->u.v2.boot_size);
-			src = ucode->u.v2.data;
-			break;
+		hdr_size = 28;
+		if (ucode_raw->size < hdr_size) {
+			IWL_ERR(priv, "File size too small!\n");
+			return -EINVAL;
 		}
-		/* fall through for 4965 */
+		pieces->build = le32_to_cpu(ucode->u.v2.build);
+		pieces->inst_size = le32_to_cpu(ucode->u.v2.inst_size);
+		pieces->data_size = le32_to_cpu(ucode->u.v2.data_size);
+		pieces->init_size = le32_to_cpu(ucode->u.v2.init_size);
+		pieces->init_data_size = le32_to_cpu(ucode->u.v2.init_data_size);
+		src = ucode->u.v2.data;
+		break;
 	case 0:
 	case 1:
 	case 2:
@@ -1479,7 +1281,6 @@
 		pieces->data_size = le32_to_cpu(ucode->u.v1.data_size);
 		pieces->init_size = le32_to_cpu(ucode->u.v1.init_size);
 		pieces->init_data_size = le32_to_cpu(ucode->u.v1.init_data_size);
-		pieces->boot_size = le32_to_cpu(ucode->u.v1.boot_size);
 		src = ucode->u.v1.data;
 		break;
 	}
@@ -1487,7 +1288,7 @@
 	/* Verify size of file vs. image size info in file's header */
 	if (ucode_raw->size != hdr_size + pieces->inst_size +
 				pieces->data_size + pieces->init_size +
-				pieces->init_data_size + pieces->boot_size) {
+				pieces->init_data_size) {
 
 		IWL_ERR(priv,
 			"uCode file size %d does not match expected size\n",
@@ -1503,8 +1304,6 @@
 	src += pieces->init_size;
 	pieces->init_data = src;
 	src += pieces->init_data_size;
-	pieces->boot = src;
-	src += pieces->boot_size;
 
 	return 0;
 }
@@ -1605,8 +1404,7 @@
 			pieces->init_data_size = tlv_len;
 			break;
 		case IWL_UCODE_TLV_BOOT:
-			pieces->boot = tlv_data;
-			pieces->boot_size = tlv_len;
+			IWL_ERR(priv, "Found unexpected BOOT ucode\n");
 			break;
 		case IWL_UCODE_TLV_PROBE_MAX_LEN:
 			if (tlv_len != sizeof(u32))
@@ -1617,7 +1415,23 @@
 		case IWL_UCODE_TLV_PAN:
 			if (tlv_len)
 				goto invalid_tlv_len;
-			capa->pan = true;
+			capa->flags |= IWL_UCODE_TLV_FLAGS_PAN;
+			break;
+		case IWL_UCODE_TLV_FLAGS:
+			/* must be at least one u32 */
+			if (tlv_len < sizeof(u32))
+				goto invalid_tlv_len;
+			/* and a proper number of u32s */
+			if (tlv_len % sizeof(u32))
+				goto invalid_tlv_len;
+			/*
+			 * This driver only reads the first u32 as
+			 * right now no more features are defined,
+			 * if that changes then either the driver
+			 * will not work with the new firmware, or
+			 * it'll not take advantage of new features.
+			 */
+			capa->flags = le32_to_cpup((__le32 *)tlv_data);
 			break;
 		case IWL_UCODE_TLV_INIT_EVTLOG_PTR:
 			if (tlv_len != sizeof(u32))
@@ -1806,8 +1620,6 @@
 		       pieces.init_size);
 	IWL_DEBUG_INFO(priv, "f/w package hdr init data size = %Zd\n",
 		       pieces.init_data_size);
-	IWL_DEBUG_INFO(priv, "f/w package hdr boot inst size = %Zd\n",
-		       pieces.boot_size);
 
 	/* Verify that uCode images will fit in card's SRAM */
 	if (pieces.inst_size > priv->hw_params.max_inst_size) {
@@ -1834,12 +1646,6 @@
 		goto try_again;
 	}
 
-	if (pieces.boot_size > priv->hw_params.max_bsm_size) {
-		IWL_ERR(priv, "uCode boot instr len %Zd too large to fit in\n",
-			pieces.boot_size);
-		goto try_again;
-	}
-
 	/* Allocate ucode buffers for card's bus-master loading ... */
 
 	/* Runtime instructions and 2 copies of data:
@@ -1851,11 +1657,7 @@
 	priv->ucode_data.len = pieces.data_size;
 	iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data);
 
-	priv->ucode_data_backup.len = pieces.data_size;
-	iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data_backup);
-
-	if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr ||
-	    !priv->ucode_data_backup.v_addr)
+	if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr)
 		goto err_pci_alloc;
 
 	/* Initialization instructions and data */
@@ -1870,15 +1672,6 @@
 			goto err_pci_alloc;
 	}
 
-	/* Bootstrap (instructions only, no data) */
-	if (pieces.boot_size) {
-		priv->ucode_boot.len = pieces.boot_size;
-		iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_boot);
-
-		if (!priv->ucode_boot.v_addr)
-			goto err_pci_alloc;
-	}
-
 	/* Now that we can no longer fail, copy information */
 
 	/*
@@ -1901,12 +1694,21 @@
 			priv->cfg->base_params->max_event_log_size;
 	priv->_agn.inst_errlog_ptr = pieces.inst_errlog_ptr;
 
-	if (ucode_capa.pan) {
+	if (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->valid_contexts != BIT(IWL_RXON_CTX_BSS))
+		priv->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM;
+	else
+		priv->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM;
+
+	if (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BTSTATS ||
+	    (priv->cfg->bt_params && priv->cfg->bt_params->bt_statistics))
+		priv->bt_statistics = true;
+
 	/* Copy images into buffers for card's bus-master reads ... */
 
 	/* Runtime instructions (first block of data in file) */
@@ -1924,7 +1726,6 @@
 	IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n",
 			pieces.data_size);
 	memcpy(priv->ucode_data.v_addr, pieces.data, pieces.data_size);
-	memcpy(priv->ucode_data_backup.v_addr, pieces.data, pieces.data_size);
 
 	/* Initialization instructions */
 	if (pieces.init_size) {
@@ -1941,11 +1742,6 @@
 		       pieces.init_data_size);
 	}
 
-	/* Bootstrap instructions */
-	IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n",
-			pieces.boot_size);
-	memcpy(priv->ucode_boot.v_addr, pieces.boot, pieces.boot_size);
-
 	/*
 	 * figure out the offset of chain noise reset and gain commands
 	 * base on the size of standard phy calibration commands table size
@@ -2077,12 +1873,11 @@
 	u32 blink1, blink2, ilink1, ilink2;
 	u32 pc, hcmd;
 
+	base = priv->device_pointers.error_event_table;
 	if (priv->ucode_type == UCODE_INIT) {
-		base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
 		if (!base)
 			base = priv->_agn.init_errlog_ptr;
 	} else {
-		base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
 		if (!base)
 			base = priv->_agn.inst_errlog_ptr;
 	}
@@ -2147,12 +1942,11 @@
 	if (num_events == 0)
 		return pos;
 
+	base = priv->device_pointers.log_event_table;
 	if (priv->ucode_type == UCODE_INIT) {
-		base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
 		if (!base)
 			base = priv->_agn.init_evtlog_ptr;
 	} else {
-		base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
 		if (!base)
 			base = priv->_agn.inst_evtlog_ptr;
 	}
@@ -2169,14 +1963,14 @@
 	iwl_grab_nic_access(priv);
 
 	/* Set starting address; reads will auto-increment */
-	_iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr);
+	iwl_write32(priv, HBUS_TARG_MEM_RADDR, ptr);
 	rmb();
 
 	/* "time" is actually "data" for mode 0 (no timestamp).
 	* place event id # at far right for easier visual parsing. */
 	for (i = 0; i < num_events; i++) {
-		ev = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
-		time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+		ev = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
+		time = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
 		if (mode == 0) {
 			/* data, ev */
 			if (bufsz) {
@@ -2190,7 +1984,7 @@
 					time, ev);
 			}
 		} else {
-			data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+			data = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
 			if (bufsz) {
 				pos += scnprintf(*buf + pos, bufsz - pos,
 						"EVT_LOGT:%010u:0x%08x:%04u\n",
@@ -2261,13 +2055,12 @@
 	int pos = 0;
 	size_t bufsz = 0;
 
+	base = priv->device_pointers.log_event_table;
 	if (priv->ucode_type == UCODE_INIT) {
-		base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
 		logsize = priv->_agn.init_evtlog_size;
 		if (!base)
 			base = priv->_agn.init_evtlog_ptr;
 	} else {
-		base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
 		logsize = priv->_agn.inst_evtlog_size;
 		if (!base)
 			base = priv->_agn.inst_evtlog_ptr;
@@ -2433,14 +2226,14 @@
 	/* Initialize uCode has loaded Runtime uCode ... verify inst image.
 	 * This is a paranoid check, because we would not have gotten the
 	 * "runtime" alive if code weren't properly loaded.  */
-	if (iwl_verify_ucode(priv)) {
+	if (iwl_verify_ucode(priv, &priv->ucode_code)) {
 		/* Runtime instruction load was bad;
 		 * take it all the way back down so we can try again */
 		IWL_DEBUG_INFO(priv, "Bad runtime uCode load.\n");
 		goto restart;
 	}
 
-	ret = priv->cfg->ops->lib->alive_notify(priv);
+	ret = iwlagn_alive_notify(priv);
 	if (ret) {
 		IWL_WARN(priv,
 			"Could not complete ALIVE transition [ntf]: %d\n", ret);
@@ -2537,7 +2330,7 @@
 static void __iwl_down(struct iwl_priv *priv)
 {
 	unsigned long flags;
-	int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status);
+	int exit_pending;
 
 	IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n");
 
@@ -2563,9 +2356,6 @@
 	priv->bt_full_concurrent = false;
 	priv->bt_ci_compliance = 0;
 
-	/* Unblock any waiting calls */
-	wake_up_interruptible_all(&priv->wait_command_queue);
-
 	/* Wipe out the EXIT_PENDING status bit if we are not actually
 	 * exiting the module */
 	if (!exit_pending)
@@ -2607,8 +2397,7 @@
 				STATUS_EXIT_PENDING;
 
 	/* device going down, Stop using ICT table */
-	if (priv->cfg->ops->lib->isr_ops.disable)
-		priv->cfg->ops->lib->isr_ops.disable(priv);
+	iwl_disable_ict(priv);
 
 	iwlagn_txq_ctx_stop(priv);
 	iwlagn_rxq_stop(priv);
@@ -2624,8 +2413,6 @@
 	iwl_apm_stop(priv);
 
  exit:
-	memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp));
-
 	dev_kfree_skb(priv->beacon_skb);
 	priv->beacon_skb = NULL;
 
@@ -2704,11 +2491,6 @@
 		return -EIO;
 	}
 
-	if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) {
-		IWL_ERR(priv, "ucode not available for device bringup\n");
-		return -EIO;
-	}
-
 	for_each_context(priv, ctx) {
 		ret = iwlagn_alloc_bcast_station(priv, ctx);
 		if (ret) {
@@ -2740,12 +2522,6 @@
 
 	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
 
-	/* must be initialised before iwl_hw_nic_init */
-	if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS))
-		priv->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM;
-	else
-		priv->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM;
-
 	ret = iwlagn_hw_nic_init(priv);
 	if (ret) {
 		IWL_ERR(priv, "Unable to init nic\n");
@@ -2765,18 +2541,12 @@
 	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
 	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
 
-	/* Copy original ucode data image from disk into backup cache.
-	 * This will be used to initialize the on-board processor's
-	 * data SRAM for a clean start when the runtime program first loads. */
-	memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr,
-	       priv->ucode_data.len);
-
 	for (i = 0; i < MAX_HW_RESTARTS; i++) {
 
 		/* load bootstrap state machine,
 		 * load bootstrap program into processor's memory,
 		 * prepare to load the "initialize" uCode */
-		ret = priv->cfg->ops->lib->load_ucode(priv);
+		ret = iwlagn_load_ucode(priv);
 
 		if (ret) {
 			IWL_ERR(priv, "Unable to set up bootstrap uCode: %d\n",
@@ -2814,11 +2584,14 @@
 	struct iwl_priv *priv =
 	    container_of(data, struct iwl_priv, init_alive_start.work);
 
-	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-		return;
-
 	mutex_lock(&priv->mutex);
-	priv->cfg->ops->lib->init_alive_start(priv);
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+		mutex_unlock(&priv->mutex);
+		return;
+	}
+
+	iwlagn_init_alive_start(priv);
 	mutex_unlock(&priv->mutex);
 }
 
@@ -2827,15 +2600,15 @@
 	struct iwl_priv *priv =
 	    container_of(data, struct iwl_priv, alive_start.work);
 
+	mutex_lock(&priv->mutex);
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-		return;
+		goto unlock;
 
 	/* enable dram interrupt */
-	if (priv->cfg->ops->lib->isr_ops.reset)
-		priv->cfg->ops->lib->isr_ops.reset(priv);
+	iwl_reset_ict(priv);
 
-	mutex_lock(&priv->mutex);
 	iwl_alive_start(priv);
+unlock:
 	mutex_unlock(&priv->mutex);
 }
 
@@ -3063,6 +2836,9 @@
 		hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
 			     IEEE80211_HW_SUPPORTS_STATIC_SMPS;
 
+	if (capa->flags & IWL_UCODE_TLV_FLAGS_MFP)
+		hw->flags |= IEEE80211_HW_MFP_CAPABLE;
+
 	hw->sta_data_size = sizeof(struct iwl_station_priv);
 	hw->vif_data_size = sizeof(struct iwl_vif_priv);
 
@@ -3112,7 +2888,7 @@
 }
 
 
-int iwlagn_mac_start(struct ieee80211_hw *hw)
+static int iwlagn_mac_start(struct ieee80211_hw *hw)
 {
 	struct iwl_priv *priv = hw->priv;
 	int ret;
@@ -3153,7 +2929,7 @@
 	return 0;
 }
 
-void iwlagn_mac_stop(struct ieee80211_hw *hw)
+static void iwlagn_mac_stop(struct ieee80211_hw *hw)
 {
 	struct iwl_priv *priv = hw->priv;
 
@@ -3176,7 +2952,7 @@
 	IWL_DEBUG_MAC80211(priv, "leave\n");
 }
 
-void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+static void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
 	struct iwl_priv *priv = hw->priv;
 
@@ -3191,11 +2967,11 @@
 	IWL_DEBUG_MACDUMP(priv, "leave\n");
 }
 
-void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
-				struct ieee80211_vif *vif,
-				struct ieee80211_key_conf *keyconf,
-				struct ieee80211_sta *sta,
-				u32 iv32, u16 *phase1key)
+static void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
+				       struct ieee80211_vif *vif,
+				       struct ieee80211_key_conf *keyconf,
+				       struct ieee80211_sta *sta,
+				       u32 iv32, u16 *phase1key)
 {
 	struct iwl_priv *priv = hw->priv;
 	struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
@@ -3208,9 +2984,10 @@
 	IWL_DEBUG_MAC80211(priv, "leave\n");
 }
 
-int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
-		       struct ieee80211_vif *vif, struct ieee80211_sta *sta,
-		       struct ieee80211_key_conf *key)
+static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+			      struct ieee80211_vif *vif,
+			      struct ieee80211_sta *sta,
+			      struct ieee80211_key_conf *key)
 {
 	struct iwl_priv *priv = hw->priv;
 	struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
@@ -3285,11 +3062,11 @@
 	return ret;
 }
 
-int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
-			    struct ieee80211_vif *vif,
-			    enum ieee80211_ampdu_mlme_action action,
-			    struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-			    u8 buf_size)
+static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
+				   struct ieee80211_vif *vif,
+				   enum ieee80211_ampdu_mlme_action action,
+				   struct ieee80211_sta *sta, u16 tid, u16 *ssn,
+				   u8 buf_size)
 {
 	struct iwl_priv *priv = hw->priv;
 	int ret = -EINVAL;
@@ -3348,6 +3125,10 @@
 		}
 		break;
 	case IEEE80211_AMPDU_TX_OPERATIONAL:
+		buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF);
+
+		iwlagn_txq_agg_queue_setup(priv, sta, tid, buf_size);
+
 		/*
 		 * If the limit is 0, then it wasn't initialised yet,
 		 * use the default. We can do that since we take the
@@ -3392,9 +3173,9 @@
 	return ret;
 }
 
-int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
-		       struct ieee80211_vif *vif,
-		       struct ieee80211_sta *sta)
+static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
+			      struct ieee80211_vif *vif,
+			      struct ieee80211_sta *sta)
 {
 	struct iwl_priv *priv = hw->priv;
 	struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
@@ -3435,8 +3216,8 @@
 	return 0;
 }
 
-void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
-			       struct ieee80211_channel_switch *ch_switch)
+static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
+				struct ieee80211_channel_switch *ch_switch)
 {
 	struct iwl_priv *priv = hw->priv;
 	const struct iwl_channel_info *ch_info;
@@ -3457,21 +3238,22 @@
 
 	IWL_DEBUG_MAC80211(priv, "enter\n");
 
+	mutex_lock(&priv->mutex);
+
 	if (iwl_is_rfkill(priv))
-		goto out_exit;
+		goto out;
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
 	    test_bit(STATUS_SCANNING, &priv->status))
-		goto out_exit;
+		goto out;
 
 	if (!iwl_is_associated_ctx(ctx))
-		goto out_exit;
+		goto out;
 
 	/* channel switch in progress */
 	if (priv->switch_rxon.switch_in_progress == true)
-		goto out_exit;
+		goto out;
 
-	mutex_lock(&priv->mutex);
 	if (priv->cfg->ops->lib->set_channel_switch) {
 
 		ch = channel->hw_value;
@@ -3527,16 +3309,15 @@
 	}
 out:
 	mutex_unlock(&priv->mutex);
-out_exit:
 	if (!priv->switch_rxon.switch_in_progress)
 		ieee80211_chswitch_done(ctx->vif, false);
 	IWL_DEBUG_MAC80211(priv, "leave\n");
 }
 
-void iwlagn_configure_filter(struct ieee80211_hw *hw,
-			     unsigned int changed_flags,
-			     unsigned int *total_flags,
-			     u64 multicast)
+static void iwlagn_configure_filter(struct ieee80211_hw *hw,
+				    unsigned int changed_flags,
+				    unsigned int *total_flags,
+				    u64 multicast)
 {
 	struct iwl_priv *priv = hw->priv;
 	__le32 filter_or = 0, filter_nand = 0;
@@ -3583,7 +3364,7 @@
 			FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
 }
 
-void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
+static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
 {
 	struct iwl_priv *priv = hw->priv;
 
@@ -3750,12 +3531,8 @@
 	priv->watchdog.data = (unsigned long)priv;
 	priv->watchdog.function = iwl_bg_watchdog;
 
-	if (!priv->cfg->base_params->use_isr_legacy)
-		tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
-			iwl_irq_tasklet, (unsigned long)priv);
-	else
-		tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
-			iwl_irq_tasklet_legacy, (unsigned long)priv);
+	tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
+		iwl_irq_tasklet, (unsigned long)priv);
 }
 
 static void iwl_cancel_deferred_work(struct iwl_priv *priv)
@@ -3808,7 +3585,6 @@
 	INIT_LIST_HEAD(&priv->free_frames);
 
 	mutex_init(&priv->mutex);
-	mutex_init(&priv->sync_cmd_mutex);
 
 	priv->ieee_channels = NULL;
 	priv->ieee_rates = NULL;
@@ -3907,12 +3683,13 @@
 	.offchannel_tx_cancel_wait = iwl_mac_offchannel_tx_cancel_wait,
 };
 
-static void iwl_hw_detect(struct iwl_priv *priv)
+static u32 iwl_hw_detect(struct iwl_priv *priv)
 {
-	priv->hw_rev = _iwl_read32(priv, CSR_HW_REV);
-	priv->hw_wa_rev = _iwl_read32(priv, CSR_HW_REV_WA_REG);
-	priv->rev_id = priv->pci_dev->revision;
-	IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", priv->rev_id);
+	u8 rev_id;
+
+	pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id);
+	IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", rev_id);
+	return iwl_read32(priv, CSR_HW_REV);
 }
 
 static int iwl_set_hw_params(struct iwl_priv *priv)
@@ -3963,19 +3740,12 @@
 	struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data);
 	unsigned long flags;
 	u16 pci_cmd, num_mac;
+	u32 hw_rev;
 
 	/************************
 	 * 1. Allocating HW data
 	 ************************/
 
-	/* Disabling hardware scan means that mac80211 will perform scans
-	 * "the hard way", rather than using device's scan. */
-	if (cfg->mod_params->disable_hw_scan) {
-		dev_printk(KERN_DEBUG, &(pdev->dev),
-			"sw scan support is deprecated\n");
-		iwlagn_hw_ops.hw_scan = NULL;
-	}
-
 	hw = iwl_alloc_all(cfg);
 	if (!hw) {
 		err = -ENOMEM;
@@ -4116,9 +3886,9 @@
 	 */
 	iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
 
-	iwl_hw_detect(priv);
+	hw_rev = iwl_hw_detect(priv);
 	IWL_INFO(priv, "Detected %s, REV=0x%X\n",
-		priv->cfg->name, priv->hw_rev);
+		priv->cfg->name, hw_rev);
 
 	/* We disable the RETRY_TIMEOUT register (0x41) to keep
 	 * PCI Tx retries from interfering with C3 CPU state */
@@ -4134,7 +3904,7 @@
 	 * 4. Read EEPROM
 	 *****************/
 	/* Read the EEPROM */
-	err = iwl_eeprom_init(priv);
+	err = iwl_eeprom_init(priv, hw_rev);
 	if (err) {
 		IWL_ERR(priv, "Unable to init EEPROM\n");
 		goto out_iounmap;
@@ -4186,10 +3956,9 @@
 
 	pci_enable_msi(priv->pci_dev);
 
-	if (priv->cfg->ops->lib->isr_ops.alloc)
-		priv->cfg->ops->lib->isr_ops.alloc(priv);
+	iwl_alloc_isr_ict(priv);
 
-	err = request_irq(priv->pci_dev->irq, priv->cfg->ops->lib->isr_ops.isr,
+	err = request_irq(priv->pci_dev->irq, iwl_isr_ict,
 			  IRQF_SHARED, DRV_NAME, priv);
 	if (err) {
 		IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq);
@@ -4236,8 +4005,7 @@
 	destroy_workqueue(priv->workqueue);
 	priv->workqueue = NULL;
 	free_irq(priv->pci_dev->irq, priv);
-	if (priv->cfg->ops->lib->isr_ops.free)
-		priv->cfg->ops->lib->isr_ops.free(priv);
+	iwl_free_isr_ict(priv);
  out_disable_msi:
 	pci_disable_msi(priv->pci_dev);
 	iwl_uninit_drv(priv);
@@ -4335,8 +4103,7 @@
 
 	iwl_uninit_drv(priv);
 
-	if (priv->cfg->ops->lib->isr_ops.free)
-		priv->cfg->ops->lib->isr_ops.free(priv);
+	iwl_free_isr_ict(priv);
 
 	dev_kfree_skb(priv->beacon_skb);
 
@@ -4585,43 +4352,21 @@
 module_init(iwl_init);
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-module_param_named(debug50, iwl_debug_level, uint, S_IRUGO);
-MODULE_PARM_DESC(debug50, "50XX debug output mask (deprecated)");
 module_param_named(debug, iwl_debug_level, uint, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "debug output mask");
 #endif
 
-module_param_named(swcrypto50, iwlagn_mod_params.sw_crypto, bool, S_IRUGO);
-MODULE_PARM_DESC(swcrypto50,
-		 "using crypto in software (default 0 [hardware]) (deprecated)");
 module_param_named(swcrypto, iwlagn_mod_params.sw_crypto, int, S_IRUGO);
 MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])");
-module_param_named(queues_num50,
-		   iwlagn_mod_params.num_of_queues, int, S_IRUGO);
-MODULE_PARM_DESC(queues_num50,
-		 "number of hw queues in 50xx series (deprecated)");
 module_param_named(queues_num, iwlagn_mod_params.num_of_queues, int, S_IRUGO);
 MODULE_PARM_DESC(queues_num, "number of hw queues.");
-module_param_named(11n_disable50, iwlagn_mod_params.disable_11n, int, S_IRUGO);
-MODULE_PARM_DESC(11n_disable50, "disable 50XX 11n functionality (deprecated)");
 module_param_named(11n_disable, iwlagn_mod_params.disable_11n, int, S_IRUGO);
 MODULE_PARM_DESC(11n_disable, "disable 11n functionality");
-module_param_named(amsdu_size_8K50, iwlagn_mod_params.amsdu_size_8K,
-		   int, S_IRUGO);
-MODULE_PARM_DESC(amsdu_size_8K50,
-		 "enable 8K amsdu size in 50XX series (deprecated)");
 module_param_named(amsdu_size_8K, iwlagn_mod_params.amsdu_size_8K,
 		   int, S_IRUGO);
 MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size");
-module_param_named(fw_restart50, iwlagn_mod_params.restart_fw, int, S_IRUGO);
-MODULE_PARM_DESC(fw_restart50,
-		 "restart firmware in case of error (deprecated)");
 module_param_named(fw_restart, iwlagn_mod_params.restart_fw, int, S_IRUGO);
 MODULE_PARM_DESC(fw_restart, "restart firmware in case of error");
-module_param_named(
-	disable_hw_scan, iwlagn_mod_params.disable_hw_scan, int, S_IRUGO);
-MODULE_PARM_DESC(disable_hw_scan,
-		 "disable hardware scanning (default 0) (deprecated)");
 
 module_param_named(ucode_alternative, iwlagn_wanted_ucode_alternative, int,
 		   S_IRUGO);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h
index 20f8e41..016b79e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.h
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -66,7 +66,6 @@
 #include "iwl-dev.h"
 
 /* configuration for the _agn devices */
-extern struct iwl_cfg iwl4965_agn_cfg;
 extern struct iwl_cfg iwl5300_agn_cfg;
 extern struct iwl_cfg iwl5100_agn_cfg;
 extern struct iwl_cfg iwl5350_agn_cfg;
@@ -114,7 +113,6 @@
 extern struct iwl_hcmd_utils_ops iwlagn_hcmd_utils;
 
 extern struct ieee80211_ops iwlagn_hw_ops;
-extern struct ieee80211_ops iwl4965_hw_ops;
 
 int iwl_reset_ict(struct iwl_priv *priv);
 void iwl_disable_ict(struct iwl_priv *priv);
@@ -133,10 +131,6 @@
 				    u16 byte_cnt);
 void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
 				   struct iwl_tx_queue *txq);
-int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id,
-			  int tx_fifo, int sta_id, int tid, u16 ssn_idx);
-int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
-			   u16 ssn_idx, u8 tx_fifo);
 void iwlagn_txq_set_sched(struct iwl_priv *priv, u32 mask);
 void iwl_free_tfds_in_queue(struct iwl_priv *priv,
 			    int sta_id, int tid, int freed);
@@ -158,7 +152,7 @@
 			   struct iwl_rx_mem_buffer *rxb);
 void iwlagn_init_alive_start(struct iwl_priv *priv);
 int iwlagn_alive_notify(struct iwl_priv *priv);
-int iwl_verify_ucode(struct iwl_priv *priv);
+int iwl_verify_ucode(struct iwl_priv *priv, struct fw_desc *fw_desc);
 void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type);
 void iwlagn_send_prio_tbl(struct iwl_priv *priv);
 
@@ -206,6 +200,9 @@
 			struct ieee80211_sta *sta, u16 tid, u16 *ssn);
 int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
 		       struct ieee80211_sta *sta, u16 tid);
+void iwlagn_txq_agg_queue_setup(struct iwl_priv *priv,
+				struct ieee80211_sta *sta,
+				int tid, int frame_limit);
 int iwlagn_txq_check_empty(struct iwl_priv *priv,
 			   int sta_id, u8 tid, int txq_id);
 void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
@@ -311,7 +308,7 @@
 
 static inline u8 iwl_hw_get_rate(__le32 rate_n_flags)
 {
-	return le32_to_cpu(rate_n_flags) & 0xFF;
+	return le32_to_cpu(rate_n_flags) & RATE_MCS_RATE_MSK;
 }
 
 static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags)
@@ -340,32 +337,4 @@
 iwlagn_remove_notification(struct iwl_priv *priv,
 			   struct iwl_notification_wait *wait_entry);
 
-/* mac80211 handlers (for 4965) */
-void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
-int iwlagn_mac_start(struct ieee80211_hw *hw);
-void iwlagn_mac_stop(struct ieee80211_hw *hw);
-void iwlagn_configure_filter(struct ieee80211_hw *hw,
-			     unsigned int changed_flags,
-			     unsigned int *total_flags,
-			     u64 multicast);
-int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
-		       struct ieee80211_vif *vif, struct ieee80211_sta *sta,
-		       struct ieee80211_key_conf *key);
-void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
-				struct ieee80211_vif *vif,
-				struct ieee80211_key_conf *keyconf,
-				struct ieee80211_sta *sta,
-				u32 iv32, u16 *phase1key);
-int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
-			    struct ieee80211_vif *vif,
-			    enum ieee80211_ampdu_mlme_action action,
-			    struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-			    u8 buf_size);
-int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
-		       struct ieee80211_vif *vif,
-		       struct ieee80211_sta *sta);
-void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
-			       struct ieee80211_channel_switch *ch_switch);
-void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop);
-
 #endif /* __iwl_agn_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index ca42ffa..a1a5c1b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -103,9 +103,7 @@
 	REPLY_WEPKEY = 0x20,
 
 	/* RX, TX, LEDs */
-	REPLY_3945_RX = 0x1b,           /* 3945 only */
 	REPLY_TX = 0x1c,
-	REPLY_RATE_SCALE = 0x47,	/* 3945 only */
 	REPLY_LEDS_CMD = 0x48,
 	REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* for 4965 and up */
 
@@ -229,7 +227,7 @@
 	 * There is one exception:  uCode sets bit 15 when it originates
 	 * the response/notification, i.e. when the response/notification
 	 * is not a direct response to a command sent by the driver.  For
-	 * example, uCode issues REPLY_3945_RX when it sends a received frame
+	 * example, uCode issues REPLY_RX when it sends a received frame
 	 * to the driver; it is not a direct response to any driver command.
 	 *
 	 * The Linux driver uses the following format:
@@ -249,36 +247,6 @@
 
 
 /**
- * struct iwl3945_tx_power
- *
- * Used in REPLY_TX_PWR_TABLE_CMD, REPLY_SCAN_CMD, REPLY_CHANNEL_SWITCH
- *
- * Each entry contains two values:
- * 1)  DSP gain (or sometimes called DSP attenuation).  This is a fine-grained
- *     linear value that multiplies the output of the digital signal processor,
- *     before being sent to the analog radio.
- * 2)  Radio gain.  This sets the analog gain of the radio Tx path.
- *     It is a coarser setting, and behaves in a logarithmic (dB) fashion.
- *
- * Driver obtains values from struct iwl3945_tx_power power_gain_table[][].
- */
-struct iwl3945_tx_power {
-	u8 tx_gain;		/* gain for analog radio */
-	u8 dsp_atten;		/* gain for DSP */
-} __packed;
-
-/**
- * struct iwl3945_power_per_rate
- *
- * Used in REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH
- */
-struct iwl3945_power_per_rate {
-	u8 rate;		/* plcp */
-	struct iwl3945_tx_power tpc;
-	u8 reserved;
-} __packed;
-
-/**
  * iwlagn rate_n_flags bit fields
  *
  * rate_n_flags format is used in following iwlagn commands:
@@ -324,6 +292,8 @@
 #define RATE_MCS_SPATIAL_MSK 0x18
 #define RATE_MCS_HT_DUP_POS 5
 #define RATE_MCS_HT_DUP_MSK 0x20
+/* Both legacy and HT use bits 7:0 as the CCK/OFDM rate or HT MCS */
+#define RATE_MCS_RATE_MSK 0xff
 
 /* Bit 8: (1) HT format, (0) legacy format in bits 7:0 */
 #define RATE_MCS_FLAGS_POS 8
@@ -375,30 +345,6 @@
 #define IWL_PWR_CCK_ENTRIES			2
 
 /**
- * union iwl4965_tx_power_dual_stream
- *
- * Host format used for REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH
- * Use __le32 version (struct tx_power_dual_stream) when building command.
- *
- * Driver provides radio gain and DSP attenuation settings to device in pairs,
- * one value for each transmitter chain.  The first value is for transmitter A,
- * second for transmitter B.
- *
- * For SISO bit rates, both values in a pair should be identical.
- * For MIMO rates, one value may be different from the other,
- * in order to balance the Tx output between the two transmitters.
- *
- * See more details in doc for TXPOWER in iwl-4965-hw.h.
- */
-union iwl4965_tx_power_dual_stream {
-	struct {
-		u8 radio_tx_gain[2];
-		u8 dsp_predis_atten[2];
-	} s;
-	u32 dw;
-};
-
-/**
  * struct tx_power_dual_stream
  *
  * Table entries in REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH
@@ -410,15 +356,6 @@
 } __packed;
 
 /**
- * struct iwl4965_tx_power_db
- *
- * Entire table within REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH
- */
-struct iwl4965_tx_power_db {
-	struct tx_power_dual_stream power_tbl[POWER_TABLE_NUM_ENTRIES];
-} __packed;
-
-/**
  * Command REPLY_TX_POWER_DBM_CMD = 0x98
  * struct iwlagn_tx_power_dbm_cmd
  */
@@ -451,54 +388,6 @@
 #define UCODE_VALID_OK	cpu_to_le32(0x1)
 #define INITIALIZE_SUBTYPE    (9)
 
-/*
- * ("Initialize") REPLY_ALIVE = 0x1 (response only, not a command)
- *
- * uCode issues this "initialize alive" notification once the initialization
- * uCode image has completed its work, and is ready to load the runtime image.
- * This is the *first* "alive" notification that the driver will receive after
- * rebooting uCode; the "initialize" alive is indicated by subtype field == 9.
- *
- * See comments documenting "BSM" (bootstrap state machine).
- *
- * For 4965, this notification contains important calibration data for
- * calculating txpower settings:
- *
- * 1)  Power supply voltage indication.  The voltage sensor outputs higher
- *     values for lower voltage, and vice verse.
- *
- * 2)  Temperature measurement parameters, for each of two channel widths
- *     (20 MHz and 40 MHz) supported by the radios.  Temperature sensing
- *     is done via one of the receiver chains, and channel width influences
- *     the results.
- *
- * 3)  Tx gain compensation to balance 4965's 2 Tx chains for MIMO operation,
- *     for each of 5 frequency ranges.
- */
-struct iwl_init_alive_resp {
-	u8 ucode_minor;
-	u8 ucode_major;
-	__le16 reserved1;
-	u8 sw_rev[8];
-	u8 ver_type;
-	u8 ver_subtype;		/* "9" for initialize alive */
-	__le16 reserved2;
-	__le32 log_event_table_ptr;
-	__le32 error_event_table_ptr;
-	__le32 timestamp;
-	__le32 is_valid;
-
-	/* calibration values from "initialize" uCode */
-	__le32 voltage;		/* signed, higher value is lower voltage */
-	__le32 therm_r1[2];	/* signed, 1st for normal, 2nd for HT40 */
-	__le32 therm_r2[2];	/* signed */
-	__le32 therm_r3[2];	/* signed */
-	__le32 therm_r4[2];	/* signed */
-	__le32 tx_atten[5][2];	/* signed MIMO gain comp, 5 freq groups,
-				 * 2 Tx chains */
-} __packed;
-
-
 /**
  * REPLY_ALIVE = 0x1 (response only, not a command)
  *
@@ -722,46 +611,6 @@
  *        regardless of whether RXON_FILTER_ASSOC_MSK is set.
  */
 
-struct iwl3945_rxon_cmd {
-	u8 node_addr[6];
-	__le16 reserved1;
-	u8 bssid_addr[6];
-	__le16 reserved2;
-	u8 wlap_bssid_addr[6];
-	__le16 reserved3;
-	u8 dev_type;
-	u8 air_propagation;
-	__le16 reserved4;
-	u8 ofdm_basic_rates;
-	u8 cck_basic_rates;
-	__le16 assoc_id;
-	__le32 flags;
-	__le32 filter_flags;
-	__le16 channel;
-	__le16 reserved5;
-} __packed;
-
-struct iwl4965_rxon_cmd {
-	u8 node_addr[6];
-	__le16 reserved1;
-	u8 bssid_addr[6];
-	__le16 reserved2;
-	u8 wlap_bssid_addr[6];
-	__le16 reserved3;
-	u8 dev_type;
-	u8 air_propagation;
-	__le16 rx_chain;
-	u8 ofdm_basic_rates;
-	u8 cck_basic_rates;
-	__le16 assoc_id;
-	__le32 flags;
-	__le32 filter_flags;
-	__le16 channel;
-	u8 ofdm_ht_single_stream_basic_rates;
-	u8 ofdm_ht_dual_stream_basic_rates;
-} __packed;
-
-/* 5000 HW just extend this command */
 struct iwl_rxon_cmd {
 	u8 node_addr[6];
 	__le16 reserved1;
@@ -789,25 +638,6 @@
 /*
  * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response)
  */
-struct iwl3945_rxon_assoc_cmd {
-	__le32 flags;
-	__le32 filter_flags;
-	u8 ofdm_basic_rates;
-	u8 cck_basic_rates;
-	__le16 reserved;
-} __packed;
-
-struct iwl4965_rxon_assoc_cmd {
-	__le32 flags;
-	__le32 filter_flags;
-	u8 ofdm_basic_rates;
-	u8 cck_basic_rates;
-	u8 ofdm_ht_single_stream_basic_rates;
-	u8 ofdm_ht_dual_stream_basic_rates;
-	__le16 rx_chain_select_flags;
-	__le16 reserved;
-} __packed;
-
 struct iwl5000_rxon_assoc_cmd {
 	__le32 flags;
 	__le32 filter_flags;
@@ -843,26 +673,6 @@
 /*
  * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response)
  */
-struct iwl3945_channel_switch_cmd {
-	u8 band;
-	u8 expect_beacon;
-	__le16 channel;
-	__le32 rxon_flags;
-	__le32 rxon_filter_flags;
-	__le32 switch_time;
-	struct iwl3945_power_per_rate power[IWL_MAX_RATES];
-} __packed;
-
-struct iwl4965_channel_switch_cmd {
-	u8 band;
-	u8 expect_beacon;
-	__le16 channel;
-	__le32 rxon_flags;
-	__le32 rxon_filter_flags;
-	__le32 switch_time;
-	struct iwl4965_tx_power_db tx_power;
-} __packed;
-
 /**
  * struct iwl5000_channel_switch_cmd
  * @band: 0- 5.2GHz, 1- 2.4GHz
@@ -976,15 +786,10 @@
 #define	IWL_AP_ID		0
 #define	IWL_AP_ID_PAN		1
 #define	IWL_STA_ID		2
-#define	IWL3945_BROADCAST_ID	24
-#define IWL3945_STATION_COUNT	25
-#define IWL4965_BROADCAST_ID	31
-#define	IWL4965_STATION_COUNT	32
 #define IWLAGN_PAN_BCAST_ID	14
 #define IWLAGN_BROADCAST_ID	15
 #define	IWLAGN_STATION_COUNT	16
 
-#define	IWL_STATION_COUNT	32 	/* MAX(3945,4965)*/
 #define	IWL_INVALID_STATION 	255
 
 #define STA_FLG_TX_RATE_MSK		cpu_to_le32(1 << 2)
@@ -1032,16 +837,6 @@
  * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */
 #define BUILD_RAxTID(sta_id, tid)	(((sta_id) << 4) + (tid))
 
-struct iwl4965_keyinfo {
-	__le16 key_flags;
-	u8 tkip_rx_tsc_byte2;	/* TSC[2] for key mix ph1 detection */
-	u8 reserved1;
-	__le16 tkip_rx_ttak[5];	/* 10-byte unicast TKIP TTAK */
-	u8 key_offset;
-	u8 reserved2;
-	u8 key[16];		/* 16-byte unicast decryption key */
-} __packed;
-
 /* agn */
 struct iwl_keyinfo {
 	__le16 key_flags;
@@ -1083,7 +878,6 @@
  * with info on security keys, aggregation parameters, and Tx rates for
  * initial Tx attempt and any retries (agn devices uses
  * REPLY_TX_LINK_QUALITY_CMD,
- * 3945 uses REPLY_RATE_SCALE to set up rate tables).
  *
  * REPLY_ADD_STA sets up the table entry for one station, either creating
  * a new entry, or modifying a pre-existing one.
@@ -1103,72 +897,6 @@
  *        entries for all STAs in network, starting with index IWL_STA_ID.
  */
 
-struct iwl3945_addsta_cmd {
-	u8 mode;		/* 1: modify existing, 0: add new station */
-	u8 reserved[3];
-	struct sta_id_modify sta;
-	struct iwl4965_keyinfo key;
-	__le32 station_flags;		/* STA_FLG_* */
-	__le32 station_flags_msk;	/* STA_FLG_* */
-
-	/* bit field to disable (1) or enable (0) Tx for Traffic ID (TID)
-	 * corresponding to bit (e.g. bit 5 controls TID 5).
-	 * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */
-	__le16 tid_disable_tx;
-
-	__le16 rate_n_flags;
-
-	/* TID for which to add block-ack support.
-	 * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
-	u8 add_immediate_ba_tid;
-
-	/* TID for which to remove block-ack support.
-	 * Set modify_mask bit STA_MODIFY_DELBA_TID_MSK to use this field. */
-	u8 remove_immediate_ba_tid;
-
-	/* Starting Sequence Number for added block-ack support.
-	 * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
-	__le16 add_immediate_ba_ssn;
-} __packed;
-
-struct iwl4965_addsta_cmd {
-	u8 mode;		/* 1: modify existing, 0: add new station */
-	u8 reserved[3];
-	struct sta_id_modify sta;
-	struct iwl4965_keyinfo key;
-	__le32 station_flags;		/* STA_FLG_* */
-	__le32 station_flags_msk;	/* STA_FLG_* */
-
-	/* bit field to disable (1) or enable (0) Tx for Traffic ID (TID)
-	 * corresponding to bit (e.g. bit 5 controls TID 5).
-	 * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */
-	__le16 tid_disable_tx;
-
-	__le16	reserved1;
-
-	/* TID for which to add block-ack support.
-	 * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
-	u8 add_immediate_ba_tid;
-
-	/* TID for which to remove block-ack support.
-	 * Set modify_mask bit STA_MODIFY_DELBA_TID_MSK to use this field. */
-	u8 remove_immediate_ba_tid;
-
-	/* Starting Sequence Number for added block-ack support.
-	 * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
-	__le16 add_immediate_ba_ssn;
-
-	/*
-	 * Number of packets OK to transmit to station even though
-	 * it is asleep -- used to synchronise PS-poll and u-APSD
-	 * responses while ucode keeps track of STA sleep state.
-	 */
-	__le16 sleep_tx_count;
-
-	__le16 reserved2;
-} __packed;
-
-/* agn */
 struct iwl_addsta_cmd {
 	u8 mode;		/* 1: modify existing, 0: add new station */
 	u8 reserved[3];
@@ -1337,62 +1065,6 @@
 #define RX_MPDU_RES_STATUS_DEC_DONE_MSK	(0x800)
 
 
-struct iwl3945_rx_frame_stats {
-	u8 phy_count;
-	u8 id;
-	u8 rssi;
-	u8 agc;
-	__le16 sig_avg;
-	__le16 noise_diff;
-	u8 payload[0];
-} __packed;
-
-struct iwl3945_rx_frame_hdr {
-	__le16 channel;
-	__le16 phy_flags;
-	u8 reserved1;
-	u8 rate;
-	__le16 len;
-	u8 payload[0];
-} __packed;
-
-struct iwl3945_rx_frame_end {
-	__le32 status;
-	__le64 timestamp;
-	__le32 beacon_timestamp;
-} __packed;
-
-/*
- * REPLY_3945_RX = 0x1b (response only, not a command)
- *
- * NOTE:  DO NOT dereference from casts to this structure
- * It is provided only for calculating minimum data set size.
- * The actual offsets of the hdr and end are dynamic based on
- * stats.phy_count
- */
-struct iwl3945_rx_frame {
-	struct iwl3945_rx_frame_stats stats;
-	struct iwl3945_rx_frame_hdr hdr;
-	struct iwl3945_rx_frame_end end;
-} __packed;
-
-#define IWL39_RX_FRAME_SIZE	(4 + sizeof(struct iwl3945_rx_frame))
-
-/* Fixed (non-configurable) rx data from phy */
-
-#define IWL49_RX_RES_PHY_CNT 14
-#define IWL49_RX_PHY_FLAGS_ANTENNAE_OFFSET	(4)
-#define IWL49_RX_PHY_FLAGS_ANTENNAE_MASK	(0x70)
-#define IWL49_AGC_DB_MASK			(0x3f80)	/* MASK(7,13) */
-#define IWL49_AGC_DB_POS			(7)
-struct iwl4965_rx_non_cfg_phy {
-	__le16 ant_selection;	/* ant A bit 4, ant B bit 5, ant C bit 6 */
-	__le16 agc_info;	/* agc code 0:6, agc dB 7:13, reserved 14:15 */
-	u8 rssi_info[6];	/* we use even entries, 0/2/4 for A/B/C rssi */
-	u8 pad[0];
-} __packed;
-
-
 #define IWLAGN_RX_RES_PHY_CNT 8
 #define IWLAGN_RX_RES_AGC_IDX     1
 #define IWLAGN_RX_RES_RSSI_AB_IDX 2
@@ -1576,80 +1248,6 @@
  * REPLY_TX = 0x1c (command)
  */
 
-struct iwl3945_tx_cmd {
-	/*
-	 * MPDU byte count:
-	 * MAC header (24/26/30/32 bytes) + 2 bytes pad if 26/30 header size,
-	 * + 8 byte IV for CCM or TKIP (not used for WEP)
-	 * + Data payload
-	 * + 8-byte MIC (not used for CCM/WEP)
-	 * NOTE:  Does not include Tx command bytes, post-MAC pad bytes,
-	 *        MIC (CCM) 8 bytes, ICV (WEP/TKIP/CKIP) 4 bytes, CRC 4 bytes.i
-	 * Range: 14-2342 bytes.
-	 */
-	__le16 len;
-
-	/*
-	 * MPDU or MSDU byte count for next frame.
-	 * Used for fragmentation and bursting, but not 11n aggregation.
-	 * Same as "len", but for next frame.  Set to 0 if not applicable.
-	 */
-	__le16 next_frame_len;
-
-	__le32 tx_flags;	/* TX_CMD_FLG_* */
-
-	u8 rate;
-
-	/* Index of recipient station in uCode's station table */
-	u8 sta_id;
-	u8 tid_tspec;
-	u8 sec_ctl;
-	u8 key[16];
-	union {
-		u8 byte[8];
-		__le16 word[4];
-		__le32 dw[2];
-	} tkip_mic;
-	__le32 next_frame_info;
-	union {
-		__le32 life_time;
-		__le32 attempt;
-	} stop_time;
-	u8 supp_rates[2];
-	u8 rts_retry_limit;	/*byte 50 */
-	u8 data_retry_limit;	/*byte 51 */
-	union {
-		__le16 pm_frame_timeout;
-		__le16 attempt_duration;
-	} timeout;
-
-	/*
-	 * Duration of EDCA burst Tx Opportunity, in 32-usec units.
-	 * Set this if txop time is not specified by HCCA protocol (e.g. by AP).
-	 */
-	__le16 driver_txop;
-
-	/*
-	 * MAC header goes here, followed by 2 bytes padding if MAC header
-	 * length is 26 or 30 bytes, followed by payload data
-	 */
-	u8 payload[0];
-	struct ieee80211_hdr hdr[0];
-} __packed;
-
-/*
- * REPLY_TX = 0x1c (response)
- */
-struct iwl3945_tx_resp {
-	u8 failure_rts;
-	u8 failure_frame;
-	u8 bt_kill_count;
-	u8 rate;
-	__le32 wireless_media_time;
-	__le32 status;		/* TX status */
-} __packed;
-
-
 /*
  * 4965 uCode updates these Tx attempt count values in host DRAM.
  * Used for managing Tx retries when expecting block-acks.
@@ -1740,54 +1338,6 @@
 	struct ieee80211_hdr hdr[0];
 } __packed;
 
-/* TX command response is sent after *3945* transmission attempts.
- *
- * NOTES:
- *
- * TX_STATUS_FAIL_NEXT_FRAG
- *
- * If the fragment flag in the MAC header for the frame being transmitted
- * is set and there is insufficient time to transmit the next frame, the
- * TX status will be returned with 'TX_STATUS_FAIL_NEXT_FRAG'.
- *
- * TX_STATUS_FIFO_UNDERRUN
- *
- * Indicates the host did not provide bytes to the FIFO fast enough while
- * a TX was in progress.
- *
- * TX_STATUS_FAIL_MGMNT_ABORT
- *
- * This status is only possible if the ABORT ON MGMT RX parameter was
- * set to true with the TX command.
- *
- * If the MSB of the status parameter is set then an abort sequence is
- * required.  This sequence consists of the host activating the TX Abort
- * control line, and then waiting for the TX Abort command response.  This
- * indicates that a the device is no longer in a transmit state, and that the
- * command FIFO has been cleared.  The host must then deactivate the TX Abort
- * control line.  Receiving is still allowed in this case.
- */
-enum {
-	TX_3945_STATUS_SUCCESS = 0x01,
-	TX_3945_STATUS_DIRECT_DONE = 0x02,
-	TX_3945_STATUS_FAIL_SHORT_LIMIT = 0x82,
-	TX_3945_STATUS_FAIL_LONG_LIMIT = 0x83,
-	TX_3945_STATUS_FAIL_FIFO_UNDERRUN = 0x84,
-	TX_3945_STATUS_FAIL_MGMNT_ABORT = 0x85,
-	TX_3945_STATUS_FAIL_NEXT_FRAG = 0x86,
-	TX_3945_STATUS_FAIL_LIFE_EXPIRE = 0x87,
-	TX_3945_STATUS_FAIL_DEST_PS = 0x88,
-	TX_3945_STATUS_FAIL_ABORTED = 0x89,
-	TX_3945_STATUS_FAIL_BT_RETRY = 0x8a,
-	TX_3945_STATUS_FAIL_STA_INVALID = 0x8b,
-	TX_3945_STATUS_FAIL_FRAG_DROPPED = 0x8c,
-	TX_3945_STATUS_FAIL_TID_DISABLE = 0x8d,
-	TX_3945_STATUS_FAIL_FRAME_FLUSHED = 0x8e,
-	TX_3945_STATUS_FAIL_INSUFFICIENT_CF_POLL = 0x8f,
-	TX_3945_STATUS_FAIL_TX_LOCKED = 0x90,
-	TX_3945_STATUS_FAIL_NO_BEACON_ON_RADAR = 0x91,
-};
-
 /*
  * TX command response is sent after *agn* transmission attempts.
  *
@@ -1905,43 +1455,6 @@
 	__le16 sequence;
 } __packed;
 
-struct iwl4965_tx_resp {
-	u8 frame_count;		/* 1 no aggregation, >1 aggregation */
-	u8 bt_kill_count;	/* # blocked by bluetooth (unused for agg) */
-	u8 failure_rts;		/* # failures due to unsuccessful RTS */
-	u8 failure_frame;	/* # failures due to no ACK (unused for agg) */
-
-	/* For non-agg:  Rate at which frame was successful.
-	 * For agg:  Rate at which all frames were transmitted. */
-	__le32 rate_n_flags;	/* RATE_MCS_*  */
-
-	/* For non-agg:  RTS + CTS + frame tx attempts time + ACK.
-	 * For agg:  RTS + CTS + aggregation tx time + block-ack time. */
-	__le16 wireless_media_time;	/* uSecs */
-
-	__le16 reserved;
-	__le32 pa_power1;	/* RF power amplifier measurement (not used) */
-	__le32 pa_power2;
-
-	/*
-	 * For non-agg:  frame status TX_STATUS_*
-	 * For agg:  status of 1st frame, AGG_TX_STATE_*; other frame status
-	 *           fields follow this one, up to frame_count.
-	 *           Bit fields:
-	 *           11- 0:  AGG_TX_STATE_* status code
-	 *           15-12:  Retry count for 1st frame in aggregation (retries
-	 *                   occur if tx failed for this frame when it was a
-	 *                   member of a previous aggregation block).  If rate
-	 *                   scaling is used, retry count indicates the rate
-	 *                   table entry used for all frames in the new agg.
-	 *           31-16:  Sequence # for this frame's Tx cmd (not SSN!)
-	 */
-	union {
-		__le32 status;
-		struct agg_tx_status agg_status[0]; /* for each agg frame */
-	} u;
-} __packed;
-
 /*
  * definitions for initial rate index field
  * bits [3:0] initial rate index
@@ -2030,52 +1543,8 @@
 /*
  * REPLY_TX_PWR_TABLE_CMD = 0x97 (command, has simple generic response)
  *
- * See details under "TXPOWER" in iwl-4965-hw.h.
  */
 
-struct iwl3945_txpowertable_cmd {
-	u8 band;		/* 0: 5 GHz, 1: 2.4 GHz */
-	u8 reserved;
-	__le16 channel;
-	struct iwl3945_power_per_rate power[IWL_MAX_RATES];
-} __packed;
-
-struct iwl4965_txpowertable_cmd {
-	u8 band;		/* 0: 5 GHz, 1: 2.4 GHz */
-	u8 reserved;
-	__le16 channel;
-	struct iwl4965_tx_power_db tx_power;
-} __packed;
-
-
-/**
- * struct iwl3945_rate_scaling_cmd - Rate Scaling Command & Response
- *
- * REPLY_RATE_SCALE = 0x47 (command, has simple generic response)
- *
- * NOTE: The table of rates passed to the uCode via the
- * RATE_SCALE command sets up the corresponding order of
- * rates used for all related commands, including rate
- * masks, etc.
- *
- * For example, if you set 9MB (PLCP 0x0f) as the first
- * rate in the rate table, the bit mask for that rate
- * when passed through ofdm_basic_rates on the REPLY_RXON
- * command would be bit 0 (1 << 0)
- */
-struct iwl3945_rate_scaling_info {
-	__le16 rate_n_flags;
-	u8 try_cnt;
-	u8 next_rate_index;
-} __packed;
-
-struct iwl3945_rate_scaling_cmd {
-	u8 table_id;
-	u8 reserved[3];
-	struct iwl3945_rate_scaling_info table[IWL_MAX_RATES];
-} __packed;
-
-
 /*RS_NEW_API: only TLC_RTS remains and moved to bit 0 */
 #define  LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK	(1 << 0)
 
@@ -2130,7 +1599,7 @@
 #define LINK_QUAL_AGG_DISABLE_START_MAX	(255)
 #define LINK_QUAL_AGG_DISABLE_START_MIN	(0)
 
-#define LINK_QUAL_AGG_FRAME_LIMIT_DEF	(31)
+#define LINK_QUAL_AGG_FRAME_LIMIT_DEF	(63)
 #define LINK_QUAL_AGG_FRAME_LIMIT_MAX	(63)
 #define LINK_QUAL_AGG_FRAME_LIMIT_MIN	(0)
 
@@ -2696,14 +2165,6 @@
 #define IWL_POWER_BT_SCO_ENA			cpu_to_le16(BIT(8))
 #define IWL_POWER_ADVANCE_PM_ENA_MSK		cpu_to_le16(BIT(9))
 
-struct iwl3945_powertable_cmd {
-	__le16 flags;
-	u8 reserved[2];
-	__le32 rx_data_timeout;
-	__le32 tx_data_timeout;
-	__le32 sleep_interval[IWL_POWER_VEC_SIZE];
-} __packed;
-
 struct iwl_powertable_cmd {
 	__le16 flags;
 	u8 keep_alive_seconds;		/* 3945 reserved */
@@ -2806,25 +2267,6 @@
  *     active_dwell < max_out_time
  */
 
-/* FIXME: rename to AP1, remove tpc */
-struct iwl3945_scan_channel {
-	/*
-	 * type is defined as:
-	 * 0:0 1 = active, 0 = passive
-	 * 1:4 SSID direct bit map; if a bit is set, then corresponding
-	 *     SSID IE is transmitted in probe request.
-	 * 5:7 reserved
-	 */
-	u8 type;
-	u8 channel;	/* band is selected by iwl3945_scan_cmd "flags" field */
-	struct iwl3945_tx_power tpc;
-	__le16 active_dwell;	/* in 1024-uSec TU (time units), typ 5-50 */
-	__le16 passive_dwell;	/* in 1024-uSec TU (time units), typ 20-500 */
-} __packed;
-
-/* set number of direct probes u8 type */
-#define IWL39_SCAN_PROBE_MASK(n) ((BIT(n) | (BIT(n) - BIT(1))))
-
 struct iwl_scan_channel {
 	/*
 	 * type is defined as:
@@ -2920,50 +2362,6 @@
  * struct iwl_scan_channel.
  */
 
-struct iwl3945_scan_cmd {
-	__le16 len;
-	u8 reserved0;
-	u8 channel_count;	/* # channels in channel list */
-	__le16 quiet_time;	/* dwell only this # millisecs on quiet channel
-				 * (only for active scan) */
-	__le16 quiet_plcp_th;	/* quiet chnl is < this # pkts (typ. 1) */
-	__le16 good_CRC_th;	/* passive -> active promotion threshold */
-	__le16 reserved1;
-	__le32 max_out_time;	/* max usec to be away from associated (service)
-				 * channel */
-	__le32 suspend_time;	/* pause scan this long (in "extended beacon
-				 * format") when returning to service channel:
-				 * 3945; 31:24 # beacons, 19:0 additional usec,
-				 * 4965; 31:22 # beacons, 21:0 additional usec.
-				 */
-	__le32 flags;		/* RXON_FLG_* */
-	__le32 filter_flags;	/* RXON_FILTER_* */
-
-	/* For active scans (set to all-0s for passive scans).
-	 * Does not include payload.  Must specify Tx rate; no rate scaling. */
-	struct iwl3945_tx_cmd tx_cmd;
-
-	/* For directed active scans (set to all-0s otherwise) */
-	struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX_3945];
-
-	/*
-	 * Probe request frame, followed by channel list.
-	 *
-	 * Size of probe request frame is specified by byte count in tx_cmd.
-	 * Channel list follows immediately after probe request frame.
-	 * Number of channels in list is specified by channel_count.
-	 * Each channel in list is of type:
-	 *
-	 * struct iwl3945_scan_channel channels[0];
-	 *
-	 * NOTE:  Only one band of channels can be scanned per pass.  You
-	 * must not mix 2.4GHz channels and 5.2GHz channels, and you must wait
-	 * for one scan to complete (i.e. receive SCAN_COMPLETE_NOTIFICATION)
-	 * before requesting another scan.
-	 */
-	u8 data[0];
-} __packed;
-
 enum iwl_scan_flags {
 	/* BIT(0) currently unused */
 	IWL_SCAN_FLAGS_ACTION_FRAME_TX	= BIT(1),
@@ -3090,20 +2488,6 @@
  * BEACON_NOTIFICATION = 0x90 (notification only, not a command)
  */
 
-struct iwl3945_beacon_notif {
-	struct iwl3945_tx_resp beacon_notify_hdr;
-	__le32 low_tsf;
-	__le32 high_tsf;
-	__le32 ibss_mgr_status;
-} __packed;
-
-struct iwl4965_beacon_notif {
-	struct iwl4965_tx_resp beacon_notify_hdr;
-	__le32 low_tsf;
-	__le32 high_tsf;
-	__le32 ibss_mgr_status;
-} __packed;
-
 struct iwlagn_beacon_notif {
 	struct iwlagn_tx_resp beacon_notify_hdr;
 	__le32 low_tsf;
@@ -3115,14 +2499,6 @@
  * REPLY_TX_BEACON = 0x91 (command, has simple generic response)
  */
 
-struct iwl3945_tx_beacon_cmd {
-	struct iwl3945_tx_cmd tx;
-	__le16 tim_idx;
-	u8 tim_size;
-	u8 reserved1;
-	struct ieee80211_hdr frame[0];	/* beacon frame */
-} __packed;
-
 struct iwl_tx_beacon_cmd {
 	struct iwl_tx_cmd tx;
 	__le16 tim_idx;
@@ -3471,13 +2847,6 @@
 #define STATISTICS_REPLY_FLG_BAND_24G_MSK         cpu_to_le32(0x2)
 #define STATISTICS_REPLY_FLG_HT40_MODE_MSK        cpu_to_le32(0x8)
 
-struct iwl3945_notif_statistics {
-	__le32 flag;
-	struct iwl39_statistics_rx rx;
-	struct iwl39_statistics_tx tx;
-	struct iwl39_statistics_general general;
-} __packed;
-
 struct iwl_notif_statistics {
 	__le32 flag;
 	struct statistics_rx rx;
@@ -4451,10 +3820,6 @@
 	__le32 len_n_flags;
 	struct iwl_cmd_header hdr;
 	union {
-		struct iwl3945_rx_frame rx_frame;
-		struct iwl3945_tx_resp tx_resp;
-		struct iwl3945_beacon_notif beacon_status;
-
 		struct iwl_alive_resp alive_frame;
 		struct iwl_spectrum_notification spectrum_notif;
 		struct iwl_csa_notification csa_notif;
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 6c30fa6..c46be36 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -2,7 +2,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -890,10 +890,8 @@
 	IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id));
 }
 #endif
-/**
- * iwl_irq_handle_error - called for HW or SW error interrupt from card
- */
-void iwl_irq_handle_error(struct iwl_priv *priv)
+
+void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
 {
 	unsigned int reload_msec;
 	unsigned long reload_jiffies;
@@ -904,18 +902,62 @@
 	/* Cancel currently queued command. */
 	clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
 
+	/* Keep the restart process from trying to send host
+	 * commands by clearing the ready bit */
+	clear_bit(STATUS_READY, &priv->status);
+
+	wake_up_interruptible(&priv->wait_command_queue);
+
+	if (!ondemand) {
+		/*
+		 * If firmware keep reloading, then it indicate something
+		 * serious wrong and firmware having problem to recover
+		 * from it. Instead of keep trying which will fill the syslog
+		 * and hang the system, let's just stop it
+		 */
+		reload_jiffies = jiffies;
+		reload_msec = jiffies_to_msecs((long) reload_jiffies -
+					(long) priv->reload_jiffies);
+		priv->reload_jiffies = reload_jiffies;
+		if (reload_msec <= IWL_MIN_RELOAD_DURATION) {
+			priv->reload_count++;
+			if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) {
+				IWL_ERR(priv, "BUG_ON, Stop restarting\n");
+				return;
+			}
+		} else
+			priv->reload_count = 0;
+	}
+
+	if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+		if (priv->cfg->mod_params->restart_fw) {
+			IWL_DEBUG(priv, IWL_DL_FW_ERRORS,
+				  "Restarting adapter due to uCode error.\n");
+			queue_work(priv->workqueue, &priv->restart);
+		} else
+			IWL_DEBUG(priv, IWL_DL_FW_ERRORS,
+				  "Detected FW error, but not restarting\n");
+	}
+}
+
+/**
+ * iwl_irq_handle_error - called for HW or SW error interrupt from card
+ */
+void iwl_irq_handle_error(struct iwl_priv *priv)
+{
 	/* W/A for WiFi/WiMAX coex and WiMAX own the RF */
 	if (priv->cfg->internal_wimax_coex &&
 	    (!(iwl_read_prph(priv, APMG_CLK_CTRL_REG) &
 			APMS_CLK_VAL_MRB_FUNC_MODE) ||
 	     (iwl_read_prph(priv, APMG_PS_CTRL_REG) &
 			APMG_PS_CTRL_VAL_RESET_REQ))) {
-		wake_up_interruptible(&priv->wait_command_queue);
 		/*
-		 *Keep the restart process from trying to send host
-		 * commands by clearing the INIT status bit
+		 * Keep the restart process from trying to send host
+		 * commands by clearing the ready bit.
 		 */
 		clear_bit(STATUS_READY, &priv->status);
+		clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+		wake_up_interruptible(&priv->wait_command_queue);
 		IWL_ERR(priv, "RF is used by WiMAX\n");
 		return;
 	}
@@ -935,38 +977,7 @@
 					&priv->contexts[IWL_RXON_CTX_BSS]);
 #endif
 
-	wake_up_interruptible(&priv->wait_command_queue);
-
-	/* Keep the restart process from trying to send host
-	 * commands by clearing the INIT status bit */
-	clear_bit(STATUS_READY, &priv->status);
-
-	/*
-	 * If firmware keep reloading, then it indicate something
-	 * serious wrong and firmware having problem to recover
-	 * from it. Instead of keep trying which will fill the syslog
-	 * and hang the system, let's just stop it
-	 */
-	reload_jiffies = jiffies;
-	reload_msec = jiffies_to_msecs((long) reload_jiffies -
-				(long) priv->reload_jiffies);
-	priv->reload_jiffies = reload_jiffies;
-	if (reload_msec <= IWL_MIN_RELOAD_DURATION) {
-		priv->reload_count++;
-		if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) {
-			IWL_ERR(priv, "BUG_ON, Stop restarting\n");
-			return;
-		}
-	} else
-		priv->reload_count = 0;
-
-	if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
-		IWL_DEBUG(priv, IWL_DL_FW_ERRORS,
-			  "Restarting adapter due to uCode error.\n");
-
-		if (priv->cfg->mod_params->restart_fw)
-			queue_work(priv->workqueue, &priv->restart);
-	}
+	iwlagn_fw_error(priv, false);
 }
 
 static int iwl_apm_stop_master(struct iwl_priv *priv)
@@ -1094,21 +1105,13 @@
 	}
 
 	/*
-	 * Enable DMA and BSM (if used) clocks, wait for them to stabilize.
-	 * BSM (Boostrap State Machine) is only in 3945 and 4965;
-	 * later devices (i.e. 5000 and later) have non-volatile SRAM,
-	 * and don't need BSM to restore data after power-saving sleep.
+	 * Enable DMA clock and wait for it to stabilize.
 	 *
 	 * Write to "CLK_EN_REG"; "1" bits enable clocks, while "0" bits
 	 * do not disable clocks.  This preserves any hardware bits already
 	 * set by default in "CLK_CTRL_REG" after reset.
 	 */
-	if (priv->cfg->base_params->use_bsm)
-		iwl_write_prph(priv, APMG_CLK_EN_REG,
-			APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT);
-	else
-		iwl_write_prph(priv, APMG_CLK_EN_REG,
-			APMG_CLK_VAL_DMA_CLK_RQT);
+	iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT);
 	udelay(20);
 
 	/* Disable L1-Active */
@@ -1430,7 +1433,6 @@
 
 	iwl_teardown_interface(priv, vif, false);
 
-	memset(priv->bssid, 0, ETH_ALEN);
 	mutex_unlock(&priv->mutex);
 
 	IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -1756,15 +1758,7 @@
 			break;
 		}
 		IWL_ERR(priv, "On demand firmware reload\n");
-		/* Set the FW error flag -- cleared on iwl_down */
-		set_bit(STATUS_FW_ERROR, &priv->status);
-		wake_up_interruptible(&priv->wait_command_queue);
-		/*
-		 * Keep the restart process from trying to send host
-		 * commands by clearing the INIT status bit
-		 */
-		clear_bit(STATUS_READY, &priv->status);
-		queue_work(priv->workqueue, &priv->restart);
+		iwlagn_fw_error(priv, true);
 		break;
 	}
 	return 0;
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index b316d83..82939f8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -73,7 +73,7 @@
 
 
 #define IWLWIFI_VERSION "in-tree:"
-#define DRV_COPYRIGHT	"Copyright(c) 2003-2010 Intel Corporation"
+#define DRV_COPYRIGHT	"Copyright(c) 2003-2011 Intel Corporation"
 #define DRV_AUTHOR     "<ilw@linux.intel.com>"
 
 #define IWL_PCI_DEVICE(dev, subdev, cfg) \
@@ -122,14 +122,6 @@
 	void (*config)(struct iwl_priv *priv);
 };
 
-struct iwl_isr_ops {
-	irqreturn_t (*isr) (int irq, void *data);
-	void (*free)(struct iwl_priv *priv);
-	int (*alloc)(struct iwl_priv *priv);
-	int (*reset)(struct iwl_priv *priv);
-	void (*disable)(struct iwl_priv *priv);
-};
-
 struct iwl_debugfs_ops {
 	ssize_t (*rx_stats_read)(struct file *file, char __user *user_buf,
 				 size_t count, loff_t *ppos);
@@ -171,25 +163,15 @@
 			     struct iwl_tx_queue *txq);
 	int (*txq_init)(struct iwl_priv *priv,
 			struct iwl_tx_queue *txq);
-	/* aggregations */
-	int (*txq_agg_enable)(struct iwl_priv *priv, int txq_id, int tx_fifo,
-			      int sta_id, int tid, u16 ssn_idx);
-	int (*txq_agg_disable)(struct iwl_priv *priv, u16 txq_id, u16 ssn_idx,
-			       u8 tx_fifo);
 	/* setup Rx handler */
 	void (*rx_handler_setup)(struct iwl_priv *priv);
 	/* setup deferred work */
 	void (*setup_deferred_work)(struct iwl_priv *priv);
 	/* cancel deferred work */
 	void (*cancel_deferred_work)(struct iwl_priv *priv);
-	/* alive notification after init uCode load */
-	void (*init_alive_start)(struct iwl_priv *priv);
-	/* alive notification */
-	int (*alive_notify)(struct iwl_priv *priv);
 	/* check validity of rtc data address */
 	int (*is_valid_rtc_data_addr)(u32 addr);
-	/* 1st ucode load */
-	int (*load_ucode)(struct iwl_priv *priv);
+
 	int (*dump_nic_event_log)(struct iwl_priv *priv,
 				  bool full_log, char **buf, bool display);
 	void (*dump_nic_error_log)(struct iwl_priv *priv);
@@ -204,9 +186,6 @@
 	int (*send_tx_power) (struct iwl_priv *priv);
 	void (*update_chain_flags)(struct iwl_priv *priv);
 
-	/* isr */
-	struct iwl_isr_ops isr_ops;
-
 	/* eeprom operations (as defined in iwl-eeprom.h) */
 	struct iwl_eeprom_ops eeprom_ops;
 
@@ -252,7 +231,6 @@
 
 struct iwl_mod_params {
 	int sw_crypto;		/* def: 0 = using hardware encryption */
-	int disable_hw_scan;	/* def: 0 = use h/w scan */
 	int num_of_queues;	/* def: HW dependent */
 	int disable_11n;	/* def: 0 = 11n capabilities enabled */
 	int amsdu_size_8K;	/* def: 1 = enable 8K amsdu size */
@@ -286,8 +264,6 @@
  * @chain_noise_calib_by_driver: driver has the capability to perform
  *	chain noise calibration operation
  * @shadow_reg_enable: HW shadhow register bit
- * @no_agg_framecnt_info: uCode do not provide aggregation frame count
- *	information
  */
 struct iwl_base_params {
 	int eeprom_size;
@@ -296,9 +272,7 @@
 	/* for iwl_apm_init() */
 	u32 pll_cfg_val;
 	bool set_l0s;
-	bool use_bsm;
 
-	bool use_isr_legacy;
 	const u16 max_ll_items;
 	const bool shadow_ram_support;
 	u16 led_compensation;
@@ -317,7 +291,6 @@
 	const bool sensitivity_calib_by_driver;
 	const bool chain_noise_calib_by_driver;
 	const bool shadow_reg_enable;
-	const bool no_agg_framecnt_info;
 };
 /*
  * @advanced_bt_coexist: support advanced bt coexist
@@ -738,10 +711,13 @@
 
 static inline bool iwl_bt_statistics(struct iwl_priv *priv)
 {
-	return priv->cfg->bt_params && priv->cfg->bt_params->bt_statistics;
+	return priv->bt_statistics;
 }
 
 extern bool bt_coex_active;
 extern bool bt_siso_mode;
 
+
+void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand);
+
 #endif /* __iwl_core_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index f52bc04..5ab90ba 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -155,18 +155,10 @@
 #define CSR_DBG_LINK_PWR_MGMT_REG	(CSR_BASE+0x250)
 
 /* Bits for CSR_HW_IF_CONFIG_REG */
-#define CSR49_HW_IF_CONFIG_REG_BIT_4965_R	(0x00000010)
 #define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER	(0x00000C00)
 #define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI 	(0x00000100)
 #define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI	(0x00000200)
 
-#define CSR39_HW_IF_CONFIG_REG_BIT_3945_MB         (0x00000100)
-#define CSR39_HW_IF_CONFIG_REG_BIT_3945_MM         (0x00000200)
-#define CSR39_HW_IF_CONFIG_REG_BIT_SKU_MRC            (0x00000400)
-#define CSR39_HW_IF_CONFIG_REG_BIT_BOARD_TYPE         (0x00000800)
-#define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A    (0x00000000)
-#define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B    (0x00001000)
-
 #define CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A	(0x00080000)
 #define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM	(0x00200000)
 #define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY	(0x00400000) /* PCI_OWN_SEM */
@@ -186,7 +178,7 @@
 #define CSR_INT_BIT_SW_ERR       (1 << 25) /* uCode error */
 #define CSR_INT_BIT_RF_KILL      (1 << 7)  /* HW RFKILL switch GP_CNTRL[27] toggled */
 #define CSR_INT_BIT_CT_KILL      (1 << 6)  /* Critical temp (chip too hot) rfkill */
-#define CSR_INT_BIT_SW_RX        (1 << 3)  /* Rx, command responses, 3945 */
+#define CSR_INT_BIT_SW_RX        (1 << 3)  /* Rx, command responses */
 #define CSR_INT_BIT_WAKEUP       (1 << 1)  /* NIC controller waking up (pwr mgmt) */
 #define CSR_INT_BIT_ALIVE        (1 << 0)  /* uCode interrupts once it initializes */
 
@@ -202,29 +194,17 @@
 /* interrupt flags in FH (flow handler) (PCI busmaster DMA) */
 #define CSR_FH_INT_BIT_ERR       (1 << 31) /* Error */
 #define CSR_FH_INT_BIT_HI_PRIOR  (1 << 30) /* High priority Rx, bypass coalescing */
-#define CSR39_FH_INT_BIT_RX_CHNL2  (1 << 18) /* Rx channel 2 (3945 only) */
 #define CSR_FH_INT_BIT_RX_CHNL1  (1 << 17) /* Rx channel 1 */
 #define CSR_FH_INT_BIT_RX_CHNL0  (1 << 16) /* Rx channel 0 */
-#define CSR39_FH_INT_BIT_TX_CHNL6  (1 << 6)  /* Tx channel 6 (3945 only) */
 #define CSR_FH_INT_BIT_TX_CHNL1  (1 << 1)  /* Tx channel 1 */
 #define CSR_FH_INT_BIT_TX_CHNL0  (1 << 0)  /* Tx channel 0 */
 
-#define CSR39_FH_INT_RX_MASK	(CSR_FH_INT_BIT_HI_PRIOR | \
-				 CSR39_FH_INT_BIT_RX_CHNL2 | \
-				 CSR_FH_INT_BIT_RX_CHNL1 | \
-				 CSR_FH_INT_BIT_RX_CHNL0)
+#define CSR_FH_INT_RX_MASK	(CSR_FH_INT_BIT_HI_PRIOR | \
+				CSR_FH_INT_BIT_RX_CHNL1 | \
+				CSR_FH_INT_BIT_RX_CHNL0)
 
-
-#define CSR39_FH_INT_TX_MASK	(CSR39_FH_INT_BIT_TX_CHNL6 | \
-				 CSR_FH_INT_BIT_TX_CHNL1 | \
-				 CSR_FH_INT_BIT_TX_CHNL0)
-
-#define CSR49_FH_INT_RX_MASK	(CSR_FH_INT_BIT_HI_PRIOR | \
-				 CSR_FH_INT_BIT_RX_CHNL1 | \
-				 CSR_FH_INT_BIT_RX_CHNL0)
-
-#define CSR49_FH_INT_TX_MASK	(CSR_FH_INT_BIT_TX_CHNL1 | \
-				 CSR_FH_INT_BIT_TX_CHNL0)
+#define CSR_FH_INT_TX_MASK	(CSR_FH_INT_BIT_TX_CHNL1 | \
+				CSR_FH_INT_BIT_TX_CHNL0)
 
 /* GPIO */
 #define CSR_GPIO_IN_BIT_AUX_POWER                   (0x00000200)
@@ -268,7 +248,7 @@
  *         Indicates MAC (ucode processor, etc.) is powered up and can run.
  *         Internal resources are accessible.
  *         NOTE:  This does not indicate that the processor is actually running.
- *         NOTE:  This does not indicate that 4965 or 3945 has completed
+ *         NOTE:  This does not indicate that device has completed
  *                init or post-power-down restore of internal SRAM memory.
  *                Use CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP as indication that
  *                SRAM is restored and uCode is in normal operation mode.
@@ -291,8 +271,6 @@
 
 /* HW REV */
 #define CSR_HW_REV_TYPE_MSK            (0x00001F0)
-#define CSR_HW_REV_TYPE_3945           (0x00000D0)
-#define CSR_HW_REV_TYPE_4965           (0x0000000)
 #define CSR_HW_REV_TYPE_5300           (0x0000020)
 #define CSR_HW_REV_TYPE_5350           (0x0000030)
 #define CSR_HW_REV_TYPE_5100           (0x0000050)
@@ -363,7 +341,7 @@
  *     0:  MAC_SLEEP
  *         uCode sets this when preparing a power-saving power-down.
  *         uCode resets this when power-up is complete and SRAM is sane.
- *         NOTE:  3945/4965 saves internal SRAM data to host when powering down,
+ *         NOTE:  device saves internal SRAM data to host when powering down,
  *                and must restore this data after powering back up.
  *                MAC_SLEEP is the best indication that restore is complete.
  *                Later devices (5xxx/6xxx/1xxx) use non-volatile SRAM, and
@@ -394,7 +372,6 @@
 #define CSR_LED_REG_TRUN_OFF (0x38)
 
 /* ANA_PLL */
-#define CSR39_ANA_PLL_CFG_VAL        (0x01000000)
 #define CSR50_ANA_PLL_CFG_VAL        (0x00880300)
 
 /* HPET MEM debug */
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index ebdea3b..2824ccb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project.
  *
@@ -146,7 +146,6 @@
 #define IWL_DL_RX		(1 << 24)
 #define IWL_DL_ISR		(1 << 25)
 #define IWL_DL_HT		(1 << 26)
-#define IWL_DL_IO		(1 << 27)
 /* 0xF0000000 - 0x10000000 */
 #define IWL_DL_11H		(1 << 28)
 #define IWL_DL_STATS		(1 << 29)
@@ -174,7 +173,6 @@
 		IWL_DEBUG_LIMIT(p, IWL_DL_DROP, f, ## a)
 #define IWL_DEBUG_AP(p, f, a...)	IWL_DEBUG(p, IWL_DL_AP, f, ## a)
 #define IWL_DEBUG_TXPOWER(p, f, a...)	IWL_DEBUG(p, IWL_DL_TXPOWER, f, ## a)
-#define IWL_DEBUG_IO(p, f, a...)	IWL_DEBUG(p, IWL_DL_IO, f, ## a)
 #define IWL_DEBUG_RATE(p, f, a...)	IWL_DEBUG(p, IWL_DL_RATE, f, ## a)
 #define IWL_DEBUG_RATE_LIMIT(p, f, a...)	\
 		IWL_DEBUG_LIMIT(p, IWL_DL_RATE, f, ## a)
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 8842411..92f6efd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -2,7 +2,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -1572,12 +1572,10 @@
 	int pos = 0;
 	char buf[200];
 	const size_t bufsz = sizeof(buf);
-	ssize_t ret;
 
 	if (!priv->bt_enable_flag) {
 		pos += scnprintf(buf + pos, bufsz - pos, "BT coex disabled\n");
-		ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-		return ret;
+		return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 	}
 	pos += scnprintf(buf + pos, bufsz - pos, "BT enable flag: 0x%x\n",
 		priv->bt_enable_flag);
@@ -1608,8 +1606,7 @@
 		break;
 	}
 
-	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-	return ret;
+	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 }
 
 static ssize_t iwl_dbgfs_protection_mode_read(struct file *file,
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 68b953f..7213336 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -26,7 +26,6 @@
 /*
  * Please use this file (iwl-dev.h) for driver implementation definitions.
  * Please use iwl-commands.h for uCode API definitions.
- * Please use iwl-4965-hw.h for hardware-related definitions.
  */
 
 #ifndef __iwl_dev_h__
@@ -179,53 +178,12 @@
 
 #define IWL_NUM_SCAN_RATES         (2)
 
-struct iwl4965_channel_tgd_info {
-	u8 type;
-	s8 max_power;
-};
-
-struct iwl4965_channel_tgh_info {
-	s64 last_radar_time;
-};
-
-#define IWL4965_MAX_RATE (33)
-
-struct iwl3945_clip_group {
-	/* maximum power level to prevent clipping for each rate, derived by
-	 *   us from this band's saturation power in EEPROM */
-	const s8 clip_powers[IWL_MAX_RATES];
-};
-
-/* current Tx power values to use, one for each rate for each channel.
- * requested power is limited by:
- * -- regulatory EEPROM limits for this channel
- * -- hardware capabilities (clip-powers)
- * -- spectrum management
- * -- user preference (e.g. iwconfig)
- * when requested power is set, base power index must also be set. */
-struct iwl3945_channel_power_info {
-	struct iwl3945_tx_power tpc;	/* actual radio and DSP gain settings */
-	s8 power_table_index;	/* actual (compenst'd) index into gain table */
-	s8 base_power_index;	/* gain index for power at factory temp. */
-	s8 requested_power;	/* power (dBm) requested for this chnl/rate */
-};
-
-/* current scan Tx power values to use, one for each scan rate for each
- * channel. */
-struct iwl3945_scan_power_info {
-	struct iwl3945_tx_power tpc;	/* actual radio and DSP gain settings */
-	s8 power_table_index;	/* actual (compenst'd) index into gain table */
-	s8 requested_power;	/* scan pwr (dBm) requested for chnl/rate */
-};
-
 /*
  * One for each channel, holds all channel setup data
  * Some of the fields (e.g. eeprom and flags/max_power_avg) are redundant
  *     with one another!
  */
 struct iwl_channel_info {
-	struct iwl4965_channel_tgd_info tgd;
-	struct iwl4965_channel_tgh_info tgh;
 	struct iwl_eeprom_channel eeprom;	/* EEPROM regulatory limit */
 	struct iwl_eeprom_channel ht40_eeprom;	/* EEPROM regulatory limit for
 						 * HT40 channel */
@@ -245,14 +203,6 @@
 	s8 ht40_max_power_avg;	/* (dBm) regul. eeprom, normal Tx, any rate */
 	u8 ht40_flags;		/* flags copied from EEPROM */
 	u8 ht40_extension_channel; /* HT_IE_EXT_CHANNEL_* */
-
-	/* Radio/DSP gain settings for each "normal" data Tx rate.
-	 * These include, in addition to RF and DSP gain, a few fields for
-	 *   remembering/modifying gain settings (indexes). */
-	struct iwl3945_channel_power_info power_info[IWL4965_MAX_RATE];
-
-	/* Radio/DSP gain settings for each scan rate, for directed scans. */
-	struct iwl3945_scan_power_info scan_pwr_info[IWL_NUM_SCAN_RATES];
 };
 
 #define IWL_TX_FIFO_BK		0	/* shared */
@@ -309,6 +259,7 @@
 	CMD_SIZE_HUGE = (1 << 0),
 	CMD_ASYNC = (1 << 1),
 	CMD_WANT_SKB = (1 << 2),
+	CMD_MAPPED = (1 << 3),
 };
 
 #define DEF_CMD_PAYLOAD_SIZE 320
@@ -416,6 +367,7 @@
 #define IWL_EMPTYING_HW_QUEUE_ADDBA 2
 #define IWL_EMPTYING_HW_QUEUE_DELBA 3
 	u8 state;
+	u8 tx_fifo;
 };
 
 
@@ -499,9 +451,6 @@
  * When mac80211 creates a station it reserves some space (hw->sta_data_size)
  * in the structure for use by driver. This structure is places in that
  * space.
- *
- * The common struct MUST be first because it is shared between
- * 3945 and agn!
  */
 struct iwl_station_priv {
 	struct iwl_station_priv_common common;
@@ -586,6 +535,22 @@
 	IWL_UCODE_TLV_INIT_ERRLOG_PTR	= 13,
 	IWL_UCODE_TLV_ENHANCE_SENS_TBL	= 14,
 	IWL_UCODE_TLV_PHY_CALIBRATION_SIZE = 15,
+	/* 16 and 17 reserved for future use */
+	IWL_UCODE_TLV_FLAGS		= 18,
+};
+
+/**
+ * enum iwl_ucode_tlv_flag - ucode API flags
+ * @IWL_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously
+ *	was a separate TLV but moved here to save space.
+ * @IWL_UCODE_TLV_FLAGS_BTSTATS: This uCode image uses BT statistics, which
+ *	may be true even if the device doesn't have BT.
+ * @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w).
+ */
+enum iwl_ucode_tlv_flag {
+	IWL_UCODE_TLV_FLAGS_PAN		= BIT(0),
+	IWL_UCODE_TLV_FLAGS_BTSTATS	= BIT(1),
+	IWL_UCODE_TLV_FLAGS_MFP		= BIT(2),
 };
 
 struct iwl_ucode_tlv {
@@ -619,14 +584,6 @@
 	u8 data[0];
 };
 
-struct iwl4965_ibss_seq {
-	u8 mac[ETH_ALEN];
-	u16 seq_num;
-	u16 frag_num;
-	unsigned long packet_time;
-	struct list_head list;
-};
-
 struct iwl_sensitivity_ranges {
 	u16 min_nrg_cck;
 	u16 max_nrg_cck;
@@ -700,7 +657,6 @@
 	u8  max_beacon_itrvl;	/* in 1024 ms */
 	u32 max_inst_size;
 	u32 max_data_size;
-	u32 max_bsm_size;
 	u32 ct_kill_threshold; /* value in hw-dependent units */
 	u32 ct_kill_exit_threshold; /* value in hw-dependent units */
 				    /* for 1000, 6000 series and up */
@@ -722,8 +678,6 @@
  * Naming convention --
  * iwl_         <-- Is part of iwlwifi
  * iwlXXXX_     <-- Hardware specific (implemented in iwl-XXXX.c for XXXX)
- * iwl4965_bg_      <-- Called from work queue context
- * iwl4965_mac_     <-- mac80211 callback
  *
  ****************************************************************************/
 extern void iwl_update_chain_flags(struct iwl_priv *priv);
@@ -772,7 +726,6 @@
 
 /* Sensitivity and chain noise calibration */
 #define INITIALIZATION_VALUE		0xFFFF
-#define IWL4965_CAL_NUM_BEACONS		20
 #define IWL_CAL_NUM_BEACONS		16
 #define MAXIMUM_ALLOWED_PATHLOSS	15
 
@@ -806,24 +759,19 @@
 #define NRG_NUM_PREV_STAT_L     20
 #define NUM_RX_CHAINS           3
 
-enum iwl4965_false_alarm_state {
+enum iwlagn_false_alarm_state {
 	IWL_FA_TOO_MANY = 0,
 	IWL_FA_TOO_FEW = 1,
 	IWL_FA_GOOD_RANGE = 2,
 };
 
-enum iwl4965_chain_noise_state {
+enum iwlagn_chain_noise_state {
 	IWL_CHAIN_NOISE_ALIVE = 0,  /* must be 0 */
 	IWL_CHAIN_NOISE_ACCUMULATE,
 	IWL_CHAIN_NOISE_CALIBRATED,
 	IWL_CHAIN_NOISE_DONE,
 };
 
-enum iwl4965_calib_enabled_state {
-	IWL_CALIB_DISABLED = 0,  /* must be 0 */
-	IWL_CALIB_ENABLED = 1,
-};
-
 
 /*
  * enum iwl_calib
@@ -1131,12 +1079,6 @@
 
 /* extend beacon time format bit shifting  */
 /*
- * for _3945 devices
- * bits 31:24 - extended
- * bits 23:0  - interval
- */
-#define IWL3945_EXT_BEACON_TIME_POS	24
-/*
  * for _agn devices
  * bits 31:22 - extended
  * bits 21:0  - interval
@@ -1249,7 +1191,6 @@
 	int frames_count;
 
 	enum ieee80211_band band;
-	int alloc_rxb_page;
 
 	void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv,
 				       struct iwl_rx_mem_buffer *rxb);
@@ -1305,16 +1246,12 @@
 	spinlock_t hcmd_lock;	/* protect hcmd */
 	spinlock_t reg_lock;	/* protect hw register access */
 	struct mutex mutex;
-	struct mutex sync_cmd_mutex; /* enable serialization of sync commands */
 
 	/* basic pci-network driver stuff */
 	struct pci_dev *pci_dev;
 
 	/* pci hardware address support */
 	void __iomem *hw_base;
-	u32  hw_rev;
-	u32  hw_wa_rev;
-	u8   rev_id;
 
 	/* microcode/device supports multiple contexts */
 	u8 valid_contexts;
@@ -1334,10 +1271,8 @@
 					   iwl_ucode.ver */
 	struct fw_desc ucode_code;	/* runtime inst */
 	struct fw_desc ucode_data;	/* runtime data original */
-	struct fw_desc ucode_data_backup;	/* runtime data save/restore */
 	struct fw_desc ucode_init;	/* initialization inst */
 	struct fw_desc ucode_init_data;	/* initialization data */
-	struct fw_desc ucode_boot;	/* bootstrap inst */
 	enum ucode_type ucode_type;
 	u8 ucode_write_complete;	/* the image write is complete */
 	char firmware_name[25];
@@ -1346,10 +1281,10 @@
 
 	struct iwl_switch_rxon switch_rxon;
 
-	/* 1st responses from initialize and runtime uCode images.
-	 * _agn's initialize alive response contains some calibration data. */
-	struct iwl_init_alive_resp card_alive_init;
-	struct iwl_alive_resp card_alive;
+	struct {
+		u32 error_event_table;
+		u32 log_event_table;
+	} device_pointers;
 
 	u16 active_rate;
 
@@ -1390,15 +1325,12 @@
 	struct iwl_power_mgr power_data;
 	struct iwl_tt_mgmt thermal_throttle;
 
-	/* context information */
-	u8 bssid[ETH_ALEN]; /* used only on 3945 but filled by core */
-
 	/* station table variables */
 
 	/* Note: if lock and sta_lock are needed, lock must be acquired first */
 	spinlock_t sta_lock;
 	int num_stations;
-	struct iwl_station_entry stations[IWL_STATION_COUNT];
+	struct iwl_station_entry stations[IWLAGN_STATION_COUNT];
 	unsigned long ucode_key_table;
 
 	/* queue refcounts */
@@ -1422,101 +1354,66 @@
 	/* Last Rx'd beacon timestamp */
 	u64 timestamp;
 
-	union {
-#if defined(CONFIG_IWL3945) || defined(CONFIG_IWL3945_MODULE)
-		struct {
-			void *shared_virt;
-			dma_addr_t shared_phys;
+	struct {
+		/* INT ICT Table */
+		__le32 *ict_tbl;
+		void *ict_tbl_vir;
+		dma_addr_t ict_tbl_dma;
+		dma_addr_t aligned_ict_tbl_dma;
+		int ict_index;
+		u32 inta;
+		bool use_ict;
+		/*
+		 * reporting the number of tids has AGG on. 0 means
+		 * no AGGREGATION
+		 */
+		u8 agg_tids_count;
 
-			struct delayed_work thermal_periodic;
-			struct delayed_work rfkill_poll;
+		struct iwl_rx_phy_res last_phy_res;
+		bool last_phy_res_valid;
 
-			struct iwl3945_notif_statistics statistics;
+		struct completion firmware_loading_complete;
+
+		u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr;
+		u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr;
+
+		/*
+		 * chain noise reset and gain commands are the
+		 * two extra calibration commands follows the standard
+		 * phy calibration commands
+		 */
+		u8 phy_calib_chain_noise_reset_cmd;
+		u8 phy_calib_chain_noise_gain_cmd;
+
+		struct iwl_notif_statistics statistics;
+		struct iwl_bt_notif_statistics statistics_bt;
+		/* counts reply_tx error */
+		struct reply_tx_error_statistics reply_tx_stats;
+		struct reply_agg_tx_error_statistics reply_agg_tx_stats;
 #ifdef CONFIG_IWLWIFI_DEBUGFS
-			struct iwl3945_notif_statistics accum_statistics;
-			struct iwl3945_notif_statistics delta_statistics;
-			struct iwl3945_notif_statistics max_delta;
+		struct iwl_notif_statistics accum_statistics;
+		struct iwl_notif_statistics delta_statistics;
+		struct iwl_notif_statistics max_delta;
+		struct iwl_bt_notif_statistics accum_statistics_bt;
+		struct iwl_bt_notif_statistics delta_statistics_bt;
+		struct iwl_bt_notif_statistics max_delta_bt;
 #endif
+		/* notification wait support */
+		struct list_head notif_waits;
+		spinlock_t notif_wait_lock;
+		wait_queue_head_t notif_waitq;
 
-			u32 sta_supp_rates;
-			int last_rx_rssi;	/* From Rx packet statistics */
+		/* remain-on-channel offload support */
+		struct ieee80211_channel *hw_roc_channel;
+		struct delayed_work hw_roc_work;
+		enum nl80211_channel_type hw_roc_chantype;
+		int hw_roc_duration;
+		bool hw_roc_setup;
 
-			/* Rx'd packet timing information */
-			u32 last_beacon_time;
-			u64 last_tsf;
-
-			/*
-			 * each calibration channel group in the
-			 * EEPROM has a derived clip setting for
-			 * each rate.
-			 */
-			const struct iwl3945_clip_group clip_groups[5];
-
-		} _3945;
-#endif
-#if defined(CONFIG_IWLAGN) || defined(CONFIG_IWLAGN_MODULE)
-		struct {
-			/* INT ICT Table */
-			__le32 *ict_tbl;
-			void *ict_tbl_vir;
-			dma_addr_t ict_tbl_dma;
-			dma_addr_t aligned_ict_tbl_dma;
-			int ict_index;
-			u32 inta;
-			bool use_ict;
-			/*
-			 * reporting the number of tids has AGG on. 0 means
-			 * no AGGREGATION
-			 */
-			u8 agg_tids_count;
-
-			struct iwl_rx_phy_res last_phy_res;
-			bool last_phy_res_valid;
-
-			struct completion firmware_loading_complete;
-
-			u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr;
-			u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr;
-
-			/*
-			 * chain noise reset and gain commands are the
-			 * two extra calibration commands follows the standard
-			 * phy calibration commands
-			 */
-			u8 phy_calib_chain_noise_reset_cmd;
-			u8 phy_calib_chain_noise_gain_cmd;
-
-			struct iwl_notif_statistics statistics;
-			struct iwl_bt_notif_statistics statistics_bt;
-			/* counts reply_tx error */
-			struct reply_tx_error_statistics reply_tx_stats;
-			struct reply_agg_tx_error_statistics reply_agg_tx_stats;
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-			struct iwl_notif_statistics accum_statistics;
-			struct iwl_notif_statistics delta_statistics;
-			struct iwl_notif_statistics max_delta;
-			struct iwl_bt_notif_statistics accum_statistics_bt;
-			struct iwl_bt_notif_statistics delta_statistics_bt;
-			struct iwl_bt_notif_statistics max_delta_bt;
-#endif
-
-			/* notification wait support */
-			struct list_head notif_waits;
-			spinlock_t notif_wait_lock;
-			wait_queue_head_t notif_waitq;
-
-			/* remain-on-channel offload support */
-			struct ieee80211_channel *hw_roc_channel;
-			struct delayed_work hw_roc_work;
-			enum nl80211_channel_type hw_roc_chantype;
-			int hw_roc_duration;
-
-			struct sk_buff *offchan_tx_skb;
-			int offchan_tx_timeout;
-			struct ieee80211_channel *offchan_tx_chan;
-		} _agn;
-#endif
-	};
+		struct sk_buff *offchan_tx_skb;
+		int offchan_tx_timeout;
+		struct ieee80211_channel *offchan_tx_chan;
+	} _agn;
 
 	/* bt coex */
 	u8 bt_enable_flag;
@@ -1525,6 +1422,7 @@
 	bool bt_ch_announce;
 	bool bt_full_concurrent;
 	bool bt_ant_couple_ok;
+	bool bt_statistics;
 	__le32 kill_ack_mask;
 	__le32 kill_cts_mask;
 	__le16 bt_valid;
@@ -1710,12 +1608,10 @@
 static inline void __iwl_free_pages(struct iwl_priv *priv, struct page *page)
 {
 	__free_pages(page, priv->hw_params.rx_page_order);
-	priv->alloc_rxb_page--;
 }
 
 static inline void iwl_free_pages(struct iwl_priv *priv, unsigned long page)
 {
 	free_pages(page, priv->hw_params.rx_page_order);
-	priv->alloc_rxb_page--;
 }
 #endif				/* __iwl_dev_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/iwlwifi/iwl-devtrace.c
index 4a48763..a635a7e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-devtrace.c
+++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2009 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2009 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h
index 4cf864c..f00172c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h
+++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2009 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2009 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index 833194a..859b94a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -188,18 +188,16 @@
 				CSR_OTP_GP_REG_OTP_ACCESS_MODE);
 }
 
-static int iwlcore_get_nvm_type(struct iwl_priv *priv)
+static int iwlcore_get_nvm_type(struct iwl_priv *priv, u32 hw_rev)
 {
 	u32 otpgp;
 	int nvm_type;
 
 	/* OTP only valid for CP/PP and after */
-	switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
+	switch (hw_rev & CSR_HW_REV_TYPE_MSK) {
 	case CSR_HW_REV_TYPE_NONE:
 		IWL_ERR(priv, "Unknown hardware type\n");
 		return -ENOENT;
-	case CSR_HW_REV_TYPE_3945:
-	case CSR_HW_REV_TYPE_4965:
 	case CSR_HW_REV_TYPE_5300:
 	case CSR_HW_REV_TYPE_5350:
 	case CSR_HW_REV_TYPE_5100:
@@ -228,15 +226,15 @@
 	int ret;
 
 	/* Enable 40MHz radio clock */
-	_iwl_write32(priv, CSR_GP_CNTRL,
-		     _iwl_read32(priv, CSR_GP_CNTRL) |
-		     CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+	iwl_write32(priv, CSR_GP_CNTRL,
+		    iwl_read32(priv, CSR_GP_CNTRL) |
+		    CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
 
 	/* wait for clock to be ready */
 	ret = iwl_poll_bit(priv, CSR_GP_CNTRL,
-				  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
-				  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
-				  25000);
+				 CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+				 CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+				 25000);
 	if (ret < 0)
 		IWL_ERR(priv, "Time out access OTP\n");
 	else {
@@ -263,17 +261,17 @@
 	u32 r;
 	u32 otpgp;
 
-	_iwl_write32(priv, CSR_EEPROM_REG,
-		     CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
+	iwl_write32(priv, CSR_EEPROM_REG,
+		    CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
 	ret = iwl_poll_bit(priv, CSR_EEPROM_REG,
-				  CSR_EEPROM_REG_READ_VALID_MSK,
-				  CSR_EEPROM_REG_READ_VALID_MSK,
-				  IWL_EEPROM_ACCESS_TIMEOUT);
+				 CSR_EEPROM_REG_READ_VALID_MSK,
+				 CSR_EEPROM_REG_READ_VALID_MSK,
+				 IWL_EEPROM_ACCESS_TIMEOUT);
 	if (ret < 0) {
 		IWL_ERR(priv, "Time out reading OTP[%d]\n", addr);
 		return ret;
 	}
-	r = _iwl_read_direct32(priv, CSR_EEPROM_REG);
+	r = iwl_read32(priv, CSR_EEPROM_REG);
 	/* check for ECC errors: */
 	otpgp = iwl_read32(priv, CSR_OTP_GP_REG);
 	if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) {
@@ -396,7 +394,7 @@
  *
  * NOTE:  This routine uses the non-debug IO access functions.
  */
-int iwl_eeprom_init(struct iwl_priv *priv)
+int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
 {
 	__le16 *e;
 	u32 gp = iwl_read32(priv, CSR_EEPROM_GP);
@@ -406,7 +404,7 @@
 	u16 validblockaddr = 0;
 	u16 cache_addr = 0;
 
-	priv->nvm_device_type = iwlcore_get_nvm_type(priv);
+	priv->nvm_device_type = iwlcore_get_nvm_type(priv, hw_rev);
 	if (priv->nvm_device_type == -ENOENT)
 		return -ENOENT;
 	/* allocate eeprom */
@@ -444,9 +442,9 @@
 			ret = -ENOENT;
 			goto done;
 		}
-		_iwl_write32(priv, CSR_EEPROM_GP,
-			     iwl_read32(priv, CSR_EEPROM_GP) &
-			     ~CSR_EEPROM_GP_IF_OWNER_MSK);
+		iwl_write32(priv, CSR_EEPROM_GP,
+			    iwl_read32(priv, CSR_EEPROM_GP) &
+			    ~CSR_EEPROM_GP_IF_OWNER_MSK);
 
 		iwl_set_bit(priv, CSR_OTP_GP_REG,
 			     CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK |
@@ -473,8 +471,8 @@
 		for (addr = 0; addr < sz; addr += sizeof(u16)) {
 			u32 r;
 
-			_iwl_write32(priv, CSR_EEPROM_REG,
-				     CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
+			iwl_write32(priv, CSR_EEPROM_REG,
+				    CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
 
 			ret = iwl_poll_bit(priv, CSR_EEPROM_REG,
 						  CSR_EEPROM_REG_READ_VALID_MSK,
@@ -484,7 +482,7 @@
 				IWL_ERR(priv, "Time out reading EEPROM[%d]\n", addr);
 				goto done;
 			}
-			r = _iwl_read_direct32(priv, CSR_EEPROM_REG);
+			r = iwl_read32(priv, CSR_EEPROM_REG);
 			e[addr / 2] = cpu_to_le16(r >> 16);
 		}
 	}
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
index 20b6646..0e9d970 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -110,10 +110,6 @@
 };
 
 /* SKU Capabilities */
-/* 3945 only */
-#define EEPROM_SKU_CAP_SW_RF_KILL_ENABLE                (1 << 0)
-#define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE                (1 << 1)
-
 /* 5000 and up */
 #define EEPROM_SKU_CAP_BAND_POS				(4)
 #define EEPROM_SKU_CAP_BAND_SELECTION	                \
@@ -168,28 +164,6 @@
 	s8 mimo3_max;
 } __packed;
 
-/* 3945 Specific */
-#define EEPROM_3945_EEPROM_VERSION	(0x2f)
-
-/* 4965 has two radio transmitters (and 3 radio receivers) */
-#define EEPROM_TX_POWER_TX_CHAINS      (2)
-
-/* 4965 has room for up to 8 sets of txpower calibration data */
-#define EEPROM_TX_POWER_BANDS          (8)
-
-/* 4965 factory calibration measures txpower gain settings for
- * each of 3 target output levels */
-#define EEPROM_TX_POWER_MEASUREMENTS   (3)
-
-/* 4965 Specific */
-/* 4965 driver does not work with txpower calibration version < 5 */
-#define EEPROM_4965_TX_POWER_VERSION    (5)
-#define EEPROM_4965_EEPROM_VERSION	(0x2f)
-#define EEPROM_4965_CALIB_VERSION_OFFSET       (2*0xB6) /* 2 bytes */
-#define EEPROM_4965_CALIB_TXPOWER_OFFSET       (2*0xE8) /* 48  bytes */
-#define EEPROM_4965_BOARD_REVISION             (2*0x4F) /* 2 bytes */
-#define EEPROM_4965_BOARD_PBA                  (2*0x56+1) /* 9 bytes */
-
 /* 5000 Specific */
 #define EEPROM_5000_TX_POWER_VERSION    (4)
 #define EEPROM_5000_EEPROM_VERSION	(0x11A)
@@ -282,90 +256,6 @@
 /* 2.4 GHz */
 extern const u8 iwl_eeprom_band_1[14];
 
-/*
- * factory calibration data for one txpower level, on one channel,
- * measured on one of the 2 tx chains (radio transmitter and associated
- * antenna).  EEPROM contains:
- *
- * 1)  Temperature (degrees Celsius) of device when measurement was made.
- *
- * 2)  Gain table index used to achieve the target measurement power.
- *     This refers to the "well-known" gain tables (see iwl-4965-hw.h).
- *
- * 3)  Actual measured output power, in half-dBm ("34" = 17 dBm).
- *
- * 4)  RF power amplifier detector level measurement (not used).
- */
-struct iwl_eeprom_calib_measure {
-	u8 temperature;		/* Device temperature (Celsius) */
-	u8 gain_idx;		/* Index into gain table */
-	u8 actual_pow;		/* Measured RF output power, half-dBm */
-	s8 pa_det;		/* Power amp detector level (not used) */
-} __packed;
-
-
-/*
- * measurement set for one channel.  EEPROM contains:
- *
- * 1)  Channel number measured
- *
- * 2)  Measurements for each of 3 power levels for each of 2 radio transmitters
- *     (a.k.a. "tx chains") (6 measurements altogether)
- */
-struct iwl_eeprom_calib_ch_info {
-	u8 ch_num;
-	struct iwl_eeprom_calib_measure
-		measurements[EEPROM_TX_POWER_TX_CHAINS]
-			[EEPROM_TX_POWER_MEASUREMENTS];
-} __packed;
-
-/*
- * txpower subband info.
- *
- * For each frequency subband, EEPROM contains the following:
- *
- * 1)  First and last channels within range of the subband.  "0" values
- *     indicate that this sample set is not being used.
- *
- * 2)  Sample measurement sets for 2 channels close to the range endpoints.
- */
-struct iwl_eeprom_calib_subband_info {
-	u8 ch_from;	/* channel number of lowest channel in subband */
-	u8 ch_to;	/* channel number of highest channel in subband */
-	struct iwl_eeprom_calib_ch_info ch1;
-	struct iwl_eeprom_calib_ch_info ch2;
-} __packed;
-
-
-/*
- * txpower calibration info.  EEPROM contains:
- *
- * 1)  Factory-measured saturation power levels (maximum levels at which
- *     tx power amplifier can output a signal without too much distortion).
- *     There is one level for 2.4 GHz band and one for 5 GHz band.  These
- *     values apply to all channels within each of the bands.
- *
- * 2)  Factory-measured power supply voltage level.  This is assumed to be
- *     constant (i.e. same value applies to all channels/bands) while the
- *     factory measurements are being made.
- *
- * 3)  Up to 8 sets of factory-measured txpower calibration values.
- *     These are for different frequency ranges, since txpower gain
- *     characteristics of the analog radio circuitry vary with frequency.
- *
- *     Not all sets need to be filled with data;
- *     struct iwl_eeprom_calib_subband_info contains range of channels
- *     (0 if unused) for each set of data.
- */
-struct iwl_eeprom_calib_info {
-	u8 saturation_power24;	/* half-dBm (e.g. "34" = 17 dBm) */
-	u8 saturation_power52;	/* half-dBm */
-	__le16 voltage;		/* signed */
-	struct iwl_eeprom_calib_subband_info
-		band_info[EEPROM_TX_POWER_BANDS];
-} __packed;
-
-
 #define ADDRESS_MSK                 0x0000FFFF
 #define INDIRECT_TYPE_MSK           0x000F0000
 #define INDIRECT_HOST               0x00010000
@@ -398,83 +288,8 @@
 #define EEPROM_RF_CFG_TX_ANT_MSK(x) ((x >> 8)  & 0xF) /* bits 8-11  */
 #define EEPROM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */
 
-#define EEPROM_3945_RF_CFG_TYPE_MAX  0x0
-#define EEPROM_4965_RF_CFG_TYPE_MAX  0x1
-
-/* Radio Config for 5000 and up */
-#define EEPROM_RF_CONFIG_TYPE_R3x3	0x0
-#define EEPROM_RF_CONFIG_TYPE_R2x2	0x1
-#define EEPROM_RF_CONFIG_TYPE_R1x2	0x2
 #define EEPROM_RF_CONFIG_TYPE_MAX	0x3
 
-/*
- * Per-channel regulatory data.
- *
- * Each channel that *might* be supported by iwl has a fixed location
- * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory
- * txpower (MSB).
- *
- * Entries immediately below are for 20 MHz channel width.  HT40 (40 MHz)
- * channels (only for 4965, not supported by 3945) appear later in the EEPROM.
- *
- * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
- */
-#define EEPROM_REGULATORY_SKU_ID            (2*0x60)    /* 4  bytes */
-#define EEPROM_REGULATORY_BAND_1            (2*0x62)	/* 2  bytes */
-#define EEPROM_REGULATORY_BAND_1_CHANNELS   (2*0x63)	/* 28 bytes */
-
-/*
- * 4.9 GHz channels 183, 184, 185, 187, 188, 189, 192, 196,
- * 5.0 GHz channels 7, 8, 11, 12, 16
- * (4915-5080MHz) (none of these is ever supported)
- */
-#define EEPROM_REGULATORY_BAND_2            (2*0x71)	/* 2  bytes */
-#define EEPROM_REGULATORY_BAND_2_CHANNELS   (2*0x72)	/* 26 bytes */
-
-/*
- * 5.2 GHz channels 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64
- * (5170-5320MHz)
- */
-#define EEPROM_REGULATORY_BAND_3            (2*0x7F)	/* 2  bytes */
-#define EEPROM_REGULATORY_BAND_3_CHANNELS   (2*0x80)	/* 24 bytes */
-
-/*
- * 5.5 GHz channels 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140
- * (5500-5700MHz)
- */
-#define EEPROM_REGULATORY_BAND_4            (2*0x8C)	/* 2  bytes */
-#define EEPROM_REGULATORY_BAND_4_CHANNELS   (2*0x8D)	/* 22 bytes */
-
-/*
- * 5.7 GHz channels 145, 149, 153, 157, 161, 165
- * (5725-5825MHz)
- */
-#define EEPROM_REGULATORY_BAND_5            (2*0x98)	/* 2  bytes */
-#define EEPROM_REGULATORY_BAND_5_CHANNELS   (2*0x99)	/* 12 bytes */
-
-/*
- * 2.4 GHz HT40 channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11)
- *
- * The channel listed is the center of the lower 20 MHz half of the channel.
- * The overall center frequency is actually 2 channels (10 MHz) above that,
- * and the upper half of each HT40 channel is centered 4 channels (20 MHz) away
- * from the lower half; e.g. the upper half of HT40 channel 1 is channel 5,
- * and the overall HT40 channel width centers on channel 3.
- *
- * NOTE:  The RXON command uses 20 MHz channel numbers to specify the
- *        control channel to which to tune.  RXON also specifies whether the
- *        control channel is the upper or lower half of a HT40 channel.
- *
- * NOTE:  4965 does not support HT40 channels on 2.4 GHz.
- */
-#define EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS (2*0xA0)	/* 14 bytes */
-
-/*
- * 5.2 GHz HT40 channels 36 (40), 44 (48), 52 (56), 60 (64),
- * 100 (104), 108 (112), 116 (120), 124 (128), 132 (136), 149 (153), 157 (161)
- */
-#define EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS (2*0xA8)	/* 22 bytes */
-
 #define EEPROM_REGULATORY_BAND_NO_HT40			(0)
 
 struct iwl_eeprom_ops {
@@ -487,7 +302,7 @@
 };
 
 
-int iwl_eeprom_init(struct iwl_priv *priv);
+int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev);
 void iwl_eeprom_free(struct iwl_priv *priv);
 int  iwl_eeprom_check_version(struct iwl_priv *priv);
 int  iwl_eeprom_check_sku(struct iwl_priv *priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h
index 55b8370..da06d13 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fh.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fh.h
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
index 02499f6..9177b55 100644
--- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
@@ -2,7 +2,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -51,9 +51,7 @@
 		IWL_CMD(REPLY_REMOVE_ALL_STA);
 		IWL_CMD(REPLY_TXFIFO_FLUSH);
 		IWL_CMD(REPLY_WEPKEY);
-		IWL_CMD(REPLY_3945_RX);
 		IWL_CMD(REPLY_TX);
-		IWL_CMD(REPLY_RATE_SCALE);
 		IWL_CMD(REPLY_LEDS_CMD);
 		IWL_CMD(REPLY_TX_LINK_QUALITY_CMD);
 		IWL_CMD(COEX_PRIORITY_TABLE_CMD);
@@ -171,14 +169,13 @@
 	int cmd_idx;
 	int ret;
 
-	BUG_ON(cmd->flags & CMD_ASYNC);
+	lockdep_assert_held(&priv->mutex);
 
 	 /* A synchronous command can not have a callback set. */
-	BUG_ON(cmd->callback);
+	BUG_ON((cmd->flags & CMD_ASYNC) || cmd->callback);
 
 	IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n",
 			get_cmd_string(cmd->id));
-	mutex_lock(&priv->sync_cmd_mutex);
 
 	set_bit(STATUS_HCMD_ACTIVE, &priv->status);
 	IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s\n",
@@ -189,7 +186,7 @@
 		ret = cmd_idx;
 		IWL_ERR(priv, "Error sending %s: enqueue_hcmd failed: %d\n",
 			  get_cmd_string(cmd->id), ret);
-		goto out;
+		return ret;
 	}
 
 	ret = wait_event_interruptible_timeout(priv->wait_command_queue,
@@ -229,8 +226,7 @@
 		goto cancel;
 	}
 
-	ret = 0;
-	goto out;
+	return 0;
 
 cancel:
 	if (cmd->flags & CMD_WANT_SKB) {
@@ -248,8 +244,7 @@
 		iwl_free_pages(priv, cmd->reply_page);
 		cmd->reply_page = 0;
 	}
-out:
-	mutex_unlock(&priv->sync_cmd_mutex);
+
 	return ret;
 }
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h
index 8821f08..5da5761 100644
--- a/drivers/net/wireless/iwlwifi/iwl-helpers.h
+++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c
new file mode 100644
index 0000000..5133741
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-io.c
@@ -0,0 +1,274 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include "iwl-io.h"
+
+#define IWL_POLL_INTERVAL 10	/* microseconds */
+
+static inline void __iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask)
+{
+	iwl_write32(priv, reg, iwl_read32(priv, reg) | mask);
+}
+
+static inline void __iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask)
+{
+	iwl_write32(priv, reg, iwl_read32(priv, reg) & ~mask);
+}
+
+void iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->reg_lock, flags);
+	__iwl_set_bit(priv, reg, mask);
+	spin_unlock_irqrestore(&priv->reg_lock, flags);
+}
+
+void iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->reg_lock, flags);
+	__iwl_clear_bit(priv, reg, mask);
+	spin_unlock_irqrestore(&priv->reg_lock, flags);
+}
+
+int iwl_poll_bit(struct iwl_priv *priv, u32 addr,
+		 u32 bits, u32 mask, int timeout)
+{
+	int t = 0;
+
+	do {
+		if ((iwl_read32(priv, addr) & mask) == (bits & mask))
+			return t;
+		udelay(IWL_POLL_INTERVAL);
+		t += IWL_POLL_INTERVAL;
+	} while (t < timeout);
+
+	return -ETIMEDOUT;
+}
+
+int iwl_grab_nic_access(struct iwl_priv *priv)
+{
+	int ret;
+	u32 val;
+
+	lockdep_assert_held(&priv->reg_lock);
+
+	/* this bit wakes up the NIC */
+	__iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+
+	/*
+	 * These bits say the device is running, and should keep running for
+	 * at least a short while (at least as long as MAC_ACCESS_REQ stays 1),
+	 * but they do not indicate that embedded SRAM is restored yet;
+	 * 3945 and 4965 have volatile SRAM, and must save/restore contents
+	 * to/from host DRAM when sleeping/waking for power-saving.
+	 * Each direction takes approximately 1/4 millisecond; with this
+	 * overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a
+	 * series of register accesses are expected (e.g. reading Event Log),
+	 * to keep device from sleeping.
+	 *
+	 * CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that
+	 * SRAM is okay/restored.  We don't check that here because this call
+	 * is just for hardware register access; but GP1 MAC_SLEEP check is a
+	 * good idea before accessing 3945/4965 SRAM (e.g. reading Event Log).
+	 *
+	 * 5000 series and later (including 1000 series) have non-volatile SRAM,
+	 * and do not save/restore SRAM when power cycling.
+	 */
+	ret = iwl_poll_bit(priv, CSR_GP_CNTRL,
+			   CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
+			   (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
+			    CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000);
+	if (ret < 0) {
+		val = iwl_read32(priv, CSR_GP_CNTRL);
+		IWL_ERR(priv,
+			"MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val);
+		iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+void iwl_release_nic_access(struct iwl_priv *priv)
+{
+	lockdep_assert_held(&priv->reg_lock);
+	__iwl_clear_bit(priv, CSR_GP_CNTRL,
+			CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+}
+
+u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg)
+{
+	u32 value;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->reg_lock, flags);
+	iwl_grab_nic_access(priv);
+	value = iwl_read32(priv, reg);
+	iwl_release_nic_access(priv);
+	spin_unlock_irqrestore(&priv->reg_lock, flags);
+
+	return value;
+}
+
+void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->reg_lock, flags);
+	if (!iwl_grab_nic_access(priv)) {
+		iwl_write32(priv, reg, value);
+		iwl_release_nic_access(priv);
+	}
+	spin_unlock_irqrestore(&priv->reg_lock, flags);
+}
+
+int iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, u32 mask,
+			int timeout)
+{
+	int t = 0;
+
+	do {
+		if ((iwl_read_direct32(priv, addr) & mask) == mask)
+			return t;
+		udelay(IWL_POLL_INTERVAL);
+		t += IWL_POLL_INTERVAL;
+	} while (t < timeout);
+
+	return -ETIMEDOUT;
+}
+
+static inline u32 __iwl_read_prph(struct iwl_priv *priv, u32 reg)
+{
+	iwl_write32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24));
+	rmb();
+	return iwl_read32(priv, HBUS_TARG_PRPH_RDAT);
+}
+
+static inline void __iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val)
+{
+	iwl_write32(priv, HBUS_TARG_PRPH_WADDR,
+		    ((addr & 0x0000FFFF) | (3 << 24)));
+	wmb();
+	iwl_write32(priv, HBUS_TARG_PRPH_WDAT, val);
+}
+
+u32 iwl_read_prph(struct iwl_priv *priv, u32 reg)
+{
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&priv->reg_lock, flags);
+	iwl_grab_nic_access(priv);
+	val = __iwl_read_prph(priv, reg);
+	iwl_release_nic_access(priv);
+	spin_unlock_irqrestore(&priv->reg_lock, flags);
+	return val;
+}
+
+void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->reg_lock, flags);
+	if (!iwl_grab_nic_access(priv)) {
+		__iwl_write_prph(priv, addr, val);
+		iwl_release_nic_access(priv);
+	}
+	spin_unlock_irqrestore(&priv->reg_lock, flags);
+}
+
+void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->reg_lock, flags);
+	iwl_grab_nic_access(priv);
+	__iwl_write_prph(priv, reg, __iwl_read_prph(priv, reg) | mask);
+	iwl_release_nic_access(priv);
+	spin_unlock_irqrestore(&priv->reg_lock, flags);
+}
+
+void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg,
+			    u32 bits, u32 mask)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->reg_lock, flags);
+	iwl_grab_nic_access(priv);
+	__iwl_write_prph(priv, reg,
+			 (__iwl_read_prph(priv, reg) & mask) | bits);
+	iwl_release_nic_access(priv);
+	spin_unlock_irqrestore(&priv->reg_lock, flags);
+}
+
+void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask)
+{
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&priv->reg_lock, flags);
+	iwl_grab_nic_access(priv);
+	val = __iwl_read_prph(priv, reg);
+	__iwl_write_prph(priv, reg, (val & ~mask));
+	iwl_release_nic_access(priv);
+	spin_unlock_irqrestore(&priv->reg_lock, flags);
+}
+
+u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr)
+{
+	unsigned long flags;
+	u32 value;
+
+	spin_lock_irqsave(&priv->reg_lock, flags);
+	iwl_grab_nic_access(priv);
+
+	iwl_write32(priv, HBUS_TARG_MEM_RADDR, addr);
+	rmb();
+	value = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
+
+	iwl_release_nic_access(priv);
+	spin_unlock_irqrestore(&priv->reg_lock, flags);
+	return value;
+}
+
+void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->reg_lock, flags);
+	if (!iwl_grab_nic_access(priv)) {
+		iwl_write32(priv, HBUS_TARG_MEM_WADDR, addr);
+		wmb();
+		iwl_write32(priv, HBUS_TARG_MEM_WDAT, val);
+		iwl_release_nic_access(priv);
+	}
+	spin_unlock_irqrestore(&priv->reg_lock, flags);
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h
index 0203a3b..ab632ba 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.h
+++ b/drivers/net/wireless/iwlwifi/iwl-io.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project.
  *
@@ -35,494 +35,47 @@
 #include "iwl-debug.h"
 #include "iwl-devtrace.h"
 
-/*
- * IO, register, and NIC memory access functions
- *
- * NOTE on naming convention and macro usage for these
- *
- * A single _ prefix before a an access function means that no state
- * check or debug information is printed when that function is called.
- *
- * A double __ prefix before an access function means that state is checked
- * and the current line number and caller function name are printed in addition
- * to any other debug output.
- *
- * The non-prefixed name is the #define that maps the caller into a
- * #define that provides the caller's name and __LINE__ to the double
- * prefix version.
- *
- * If you wish to call the function without any debug or state checking,
- * you should use the single _ prefix version (as is used by dependent IO
- * routines, for example _iwl_read_direct32 calls the non-check version of
- * _iwl_read32.)
- *
- * These declarations are *extremely* useful in quickly isolating code deltas
- * which result in misconfiguration of the hardware I/O.  In combination with
- * git-bisect and the IO debug level you can quickly determine the specific
- * commit which breaks the IO sequence to the hardware.
- *
- */
-
-static inline void _iwl_write8(struct iwl_priv *priv, u32 ofs, u8 val)
+static inline void iwl_write8(struct iwl_priv *priv, u32 ofs, u8 val)
 {
 	trace_iwlwifi_dev_iowrite8(priv, ofs, val);
 	iowrite8(val, priv->hw_base + ofs);
 }
 
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline void __iwl_write8(const char *f, u32 l, struct iwl_priv *priv,
-				 u32 ofs, u8 val)
-{
-	IWL_DEBUG_IO(priv, "write8(0x%08X, 0x%02X) - %s %d\n", ofs, val, f, l);
-	_iwl_write8(priv, ofs, val);
-}
-#define iwl_write8(priv, ofs, val) \
-	__iwl_write8(__FILE__, __LINE__, priv, ofs, val)
-#else
-#define iwl_write8(priv, ofs, val) _iwl_write8(priv, ofs, val)
-#endif
-
-
-static inline void _iwl_write32(struct iwl_priv *priv, u32 ofs, u32 val)
+static inline void iwl_write32(struct iwl_priv *priv, u32 ofs, u32 val)
 {
 	trace_iwlwifi_dev_iowrite32(priv, ofs, val);
 	iowrite32(val, priv->hw_base + ofs);
 }
 
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline void __iwl_write32(const char *f, u32 l, struct iwl_priv *priv,
-				 u32 ofs, u32 val)
-{
-	IWL_DEBUG_IO(priv, "write32(0x%08X, 0x%08X) - %s %d\n", ofs, val, f, l);
-	_iwl_write32(priv, ofs, val);
-}
-#define iwl_write32(priv, ofs, val) \
-	__iwl_write32(__FILE__, __LINE__, priv, ofs, val)
-#else
-#define iwl_write32(priv, ofs, val) _iwl_write32(priv, ofs, val)
-#endif
-
-static inline u32 _iwl_read32(struct iwl_priv *priv, u32 ofs)
+static inline u32 iwl_read32(struct iwl_priv *priv, u32 ofs)
 {
 	u32 val = ioread32(priv->hw_base + ofs);
 	trace_iwlwifi_dev_ioread32(priv, ofs, val);
 	return val;
 }
 
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline u32 __iwl_read32(char *f, u32 l, struct iwl_priv *priv, u32 ofs)
-{
-	IWL_DEBUG_IO(priv, "read_direct32(0x%08X) - %s %d\n", ofs, f, l);
-	return _iwl_read32(priv, ofs);
-}
-#define iwl_read32(priv, ofs) __iwl_read32(__FILE__, __LINE__, priv, ofs)
-#else
-#define iwl_read32(p, o) _iwl_read32(p, o)
-#endif
+void iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask);
+void iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask);
 
-#define IWL_POLL_INTERVAL 10	/* microseconds */
-static inline int _iwl_poll_bit(struct iwl_priv *priv, u32 addr,
-				u32 bits, u32 mask, int timeout)
-{
-	int t = 0;
+int iwl_poll_bit(struct iwl_priv *priv, u32 addr,
+		 u32 bits, u32 mask, int timeout);
+int iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, u32 mask,
+			int timeout);
 
-	do {
-		if ((_iwl_read32(priv, addr) & mask) == (bits & mask))
-			return t;
-		udelay(IWL_POLL_INTERVAL);
-		t += IWL_POLL_INTERVAL;
-	} while (t < timeout);
+int iwl_grab_nic_access(struct iwl_priv *priv);
+void iwl_release_nic_access(struct iwl_priv *priv);
 
-	return -ETIMEDOUT;
-}
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline int __iwl_poll_bit(const char *f, u32 l,
-				 struct iwl_priv *priv, u32 addr,
-				 u32 bits, u32 mask, int timeout)
-{
-	int ret = _iwl_poll_bit(priv, addr, bits, mask, timeout);
-	IWL_DEBUG_IO(priv, "poll_bit(0x%08X, 0x%08X, 0x%08X) - %s- %s %d\n",
-		     addr, bits, mask,
-		     unlikely(ret  == -ETIMEDOUT) ? "timeout" : "", f, l);
-	return ret;
-}
-#define iwl_poll_bit(priv, addr, bits, mask, timeout) \
-	__iwl_poll_bit(__FILE__, __LINE__, priv, addr, bits, mask, timeout)
-#else
-#define iwl_poll_bit(p, a, b, m, t) _iwl_poll_bit(p, a, b, m, t)
-#endif
+u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg);
+void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value);
 
-static inline void _iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask)
-{
-	_iwl_write32(priv, reg, _iwl_read32(priv, reg) | mask);
-}
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline void __iwl_set_bit(const char *f, u32 l,
-				 struct iwl_priv *priv, u32 reg, u32 mask)
-{
-	u32 val = _iwl_read32(priv, reg) | mask;
-	IWL_DEBUG_IO(priv, "set_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val);
-	_iwl_write32(priv, reg, val);
-}
-static inline void iwl_set_bit(struct iwl_priv *p, u32 r, u32 m)
-{
-	unsigned long reg_flags;
 
-	spin_lock_irqsave(&p->reg_lock, reg_flags);
-	__iwl_set_bit(__FILE__, __LINE__, p, r, m);
-	spin_unlock_irqrestore(&p->reg_lock, reg_flags);
-}
-#else
-static inline void iwl_set_bit(struct iwl_priv *p, u32 r, u32 m)
-{
-	unsigned long reg_flags;
+u32 iwl_read_prph(struct iwl_priv *priv, u32 reg);
+void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val);
+void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask);
+void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg,
+			    u32 bits, u32 mask);
+void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask);
 
-	spin_lock_irqsave(&p->reg_lock, reg_flags);
-	_iwl_set_bit(p, r, m);
-	spin_unlock_irqrestore(&p->reg_lock, reg_flags);
-}
-#endif
-
-static inline void _iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask)
-{
-	_iwl_write32(priv, reg, _iwl_read32(priv, reg) & ~mask);
-}
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline void __iwl_clear_bit(const char *f, u32 l,
-				   struct iwl_priv *priv, u32 reg, u32 mask)
-{
-	u32 val = _iwl_read32(priv, reg) & ~mask;
-	IWL_DEBUG_IO(priv, "clear_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val);
-	_iwl_write32(priv, reg, val);
-}
-static inline void iwl_clear_bit(struct iwl_priv *p, u32 r, u32 m)
-{
-	unsigned long reg_flags;
-
-	spin_lock_irqsave(&p->reg_lock, reg_flags);
-	__iwl_clear_bit(__FILE__, __LINE__, p, r, m);
-	spin_unlock_irqrestore(&p->reg_lock, reg_flags);
-}
-#else
-static inline void iwl_clear_bit(struct iwl_priv *p, u32 r, u32 m)
-{
-	unsigned long reg_flags;
-
-	spin_lock_irqsave(&p->reg_lock, reg_flags);
-	_iwl_clear_bit(p, r, m);
-	spin_unlock_irqrestore(&p->reg_lock, reg_flags);
-}
-#endif
-
-static inline int _iwl_grab_nic_access(struct iwl_priv *priv)
-{
-	int ret;
-	u32 val;
-
-	/* this bit wakes up the NIC */
-	_iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-
-	/*
-	 * These bits say the device is running, and should keep running for
-	 * at least a short while (at least as long as MAC_ACCESS_REQ stays 1),
-	 * but they do not indicate that embedded SRAM is restored yet;
-	 * 3945 and 4965 have volatile SRAM, and must save/restore contents
-	 * to/from host DRAM when sleeping/waking for power-saving.
-	 * Each direction takes approximately 1/4 millisecond; with this
-	 * overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a
-	 * series of register accesses are expected (e.g. reading Event Log),
-	 * to keep device from sleeping.
-	 *
-	 * CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that
-	 * SRAM is okay/restored.  We don't check that here because this call
-	 * is just for hardware register access; but GP1 MAC_SLEEP check is a
-	 * good idea before accessing 3945/4965 SRAM (e.g. reading Event Log).
-	 *
-	 * 5000 series and later (including 1000 series) have non-volatile SRAM,
-	 * and do not save/restore SRAM when power cycling.
-	 */
-	ret = _iwl_poll_bit(priv, CSR_GP_CNTRL,
-			   CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
-			   (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
-			    CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000);
-	if (ret < 0) {
-		val = _iwl_read32(priv, CSR_GP_CNTRL);
-		IWL_ERR(priv, "MAC is in deep sleep!.  CSR_GP_CNTRL = 0x%08X\n", val);
-		_iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI);
-		return -EIO;
-	}
-
-	return 0;
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline int __iwl_grab_nic_access(const char *f, u32 l,
-					       struct iwl_priv *priv)
-{
-	IWL_DEBUG_IO(priv, "grabbing nic access - %s %d\n", f, l);
-	return _iwl_grab_nic_access(priv);
-}
-#define iwl_grab_nic_access(priv) \
-	__iwl_grab_nic_access(__FILE__, __LINE__, priv)
-#else
-#define iwl_grab_nic_access(priv) \
-	_iwl_grab_nic_access(priv)
-#endif
-
-static inline void _iwl_release_nic_access(struct iwl_priv *priv)
-{
-	_iwl_clear_bit(priv, CSR_GP_CNTRL,
-			CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-}
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline void __iwl_release_nic_access(const char *f, u32 l,
-					    struct iwl_priv *priv)
-{
-
-	IWL_DEBUG_IO(priv, "releasing nic access - %s %d\n", f, l);
-	_iwl_release_nic_access(priv);
-}
-#define iwl_release_nic_access(priv) \
-	__iwl_release_nic_access(__FILE__, __LINE__, priv)
-#else
-#define iwl_release_nic_access(priv) \
-	_iwl_release_nic_access(priv)
-#endif
-
-static inline u32 _iwl_read_direct32(struct iwl_priv *priv, u32 reg)
-{
-	return _iwl_read32(priv, reg);
-}
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline u32 __iwl_read_direct32(const char *f, u32 l,
-					struct iwl_priv *priv, u32 reg)
-{
-	u32 value = _iwl_read_direct32(priv, reg);
-	IWL_DEBUG_IO(priv, "read_direct32(0x%4X) = 0x%08x - %s %d\n", reg, value,
-		     f, l);
-	return value;
-}
-static inline u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg)
-{
-	u32 value;
-	unsigned long reg_flags;
-
-	spin_lock_irqsave(&priv->reg_lock, reg_flags);
-	iwl_grab_nic_access(priv);
-	value = __iwl_read_direct32(__FILE__, __LINE__, priv, reg);
-	iwl_release_nic_access(priv);
-	spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
-	return value;
-}
-
-#else
-static inline u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg)
-{
-	u32 value;
-	unsigned long reg_flags;
-
-	spin_lock_irqsave(&priv->reg_lock, reg_flags);
-	iwl_grab_nic_access(priv);
-	value = _iwl_read_direct32(priv, reg);
-	iwl_release_nic_access(priv);
-	spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
-	return value;
-
-}
-#endif
-
-static inline void _iwl_write_direct32(struct iwl_priv *priv,
-					 u32 reg, u32 value)
-{
-	_iwl_write32(priv, reg, value);
-}
-static inline void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value)
-{
-	unsigned long reg_flags;
-
-	spin_lock_irqsave(&priv->reg_lock, reg_flags);
-	if (!iwl_grab_nic_access(priv)) {
-		_iwl_write_direct32(priv, reg, value);
-		iwl_release_nic_access(priv);
-	}
-	spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
-}
-
-static inline void iwl_write_reg_buf(struct iwl_priv *priv,
-					       u32 reg, u32 len, u32 *values)
-{
-	u32 count = sizeof(u32);
-
-	if ((priv != NULL) && (values != NULL)) {
-		for (; 0 < len; len -= count, reg += count, values++)
-			iwl_write_direct32(priv, reg, *values);
-	}
-}
-
-static inline int _iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr,
-				       u32 mask, int timeout)
-{
-	int t = 0;
-
-	do {
-		if ((iwl_read_direct32(priv, addr) & mask) == mask)
-			return t;
-		udelay(IWL_POLL_INTERVAL);
-		t += IWL_POLL_INTERVAL;
-	} while (t < timeout);
-
-	return -ETIMEDOUT;
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline int __iwl_poll_direct_bit(const char *f, u32 l,
-					    struct iwl_priv *priv,
-					    u32 addr, u32 mask, int timeout)
-{
-	int ret  = _iwl_poll_direct_bit(priv, addr, mask, timeout);
-
-	if (unlikely(ret == -ETIMEDOUT))
-		IWL_DEBUG_IO(priv, "poll_direct_bit(0x%08X, 0x%08X) - "
-			     "timedout - %s %d\n", addr, mask, f, l);
-	else
-		IWL_DEBUG_IO(priv, "poll_direct_bit(0x%08X, 0x%08X) = 0x%08X "
-			     "- %s %d\n", addr, mask, ret, f, l);
-	return ret;
-}
-#define iwl_poll_direct_bit(priv, addr, mask, timeout) \
-	__iwl_poll_direct_bit(__FILE__, __LINE__, priv, addr, mask, timeout)
-#else
-#define iwl_poll_direct_bit _iwl_poll_direct_bit
-#endif
-
-static inline u32 _iwl_read_prph(struct iwl_priv *priv, u32 reg)
-{
-	_iwl_write_direct32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24));
-	rmb();
-	return _iwl_read_direct32(priv, HBUS_TARG_PRPH_RDAT);
-}
-static inline u32 iwl_read_prph(struct iwl_priv *priv, u32 reg)
-{
-	unsigned long reg_flags;
-	u32 val;
-
-	spin_lock_irqsave(&priv->reg_lock, reg_flags);
-	iwl_grab_nic_access(priv);
-	val = _iwl_read_prph(priv, reg);
-	iwl_release_nic_access(priv);
-	spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
-	return val;
-}
-
-static inline void _iwl_write_prph(struct iwl_priv *priv,
-					     u32 addr, u32 val)
-{
-	_iwl_write_direct32(priv, HBUS_TARG_PRPH_WADDR,
-			      ((addr & 0x0000FFFF) | (3 << 24)));
-	wmb();
-	_iwl_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val);
-}
-
-static inline void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val)
-{
-	unsigned long reg_flags;
-
-	spin_lock_irqsave(&priv->reg_lock, reg_flags);
-	if (!iwl_grab_nic_access(priv)) {
-		_iwl_write_prph(priv, addr, val);
-		iwl_release_nic_access(priv);
-	}
-	spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
-}
-
-#define _iwl_set_bits_prph(priv, reg, mask) \
-	_iwl_write_prph(priv, reg, (_iwl_read_prph(priv, reg) | mask))
-
-static inline void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask)
-{
-	unsigned long reg_flags;
-
-	spin_lock_irqsave(&priv->reg_lock, reg_flags);
-	iwl_grab_nic_access(priv);
-	_iwl_set_bits_prph(priv, reg, mask);
-	iwl_release_nic_access(priv);
-	spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
-}
-
-#define _iwl_set_bits_mask_prph(priv, reg, bits, mask) \
-	_iwl_write_prph(priv, reg, ((_iwl_read_prph(priv, reg) & mask) | bits))
-
-static inline void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg,
-				u32 bits, u32 mask)
-{
-	unsigned long reg_flags;
-
-	spin_lock_irqsave(&priv->reg_lock, reg_flags);
-	iwl_grab_nic_access(priv);
-	_iwl_set_bits_mask_prph(priv, reg, bits, mask);
-	iwl_release_nic_access(priv);
-	spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
-}
-
-static inline void iwl_clear_bits_prph(struct iwl_priv
-						 *priv, u32 reg, u32 mask)
-{
-	unsigned long reg_flags;
-	u32 val;
-
-	spin_lock_irqsave(&priv->reg_lock, reg_flags);
-	iwl_grab_nic_access(priv);
-	val = _iwl_read_prph(priv, reg);
-	_iwl_write_prph(priv, reg, (val & ~mask));
-	iwl_release_nic_access(priv);
-	spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
-}
-
-static inline u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr)
-{
-	unsigned long reg_flags;
-	u32 value;
-
-	spin_lock_irqsave(&priv->reg_lock, reg_flags);
-	iwl_grab_nic_access(priv);
-
-	_iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr);
-	rmb();
-	value = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
-
-	iwl_release_nic_access(priv);
-	spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
-	return value;
-}
-
-static inline void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val)
-{
-	unsigned long reg_flags;
-
-	spin_lock_irqsave(&priv->reg_lock, reg_flags);
-	if (!iwl_grab_nic_access(priv)) {
-		_iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr);
-		wmb();
-		_iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, val);
-		iwl_release_nic_access(priv);
-	}
-	spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
-}
-
-static inline void iwl_write_targ_mem_buf(struct iwl_priv *priv, u32 addr,
-					  u32 len, u32 *values)
-{
-	unsigned long reg_flags;
-
-	spin_lock_irqsave(&priv->reg_lock, reg_flags);
-	if (!iwl_grab_nic_access(priv)) {
-		_iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr);
-		wmb();
-		for (; 0 < len; len -= sizeof(u32), values++)
-			_iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values);
-
-		iwl_release_nic_access(priv);
-	}
-	spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
-}
+u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr);
+void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val);
 #endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c
index d7f2a0b..c2862d4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-led.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h
index 101eef1..05b8e8f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.h
+++ b/drivers/net/wireless/iwlwifi/iwl-led.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
index 576795e..c43c8e6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.c
+++ b/drivers/net/wireless/iwlwifi/iwl-power.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h
index fe01203..59635d7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.h
+++ b/drivers/net/wireless/iwlwifi/iwl-power.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index 86f5123..c960195 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -91,7 +91,6 @@
 #define APMG_PS_CTRL_VAL_RESET_REQ		(0x04000000)
 #define APMG_PS_CTRL_MSK_PWR_SRC		(0x03000000)
 #define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN		(0x00000000)
-#define APMG_PS_CTRL_VAL_PWR_SRC_MAX		(0x01000000) /* 3945 only */
 #define APMG_PS_CTRL_VAL_PWR_SRC_VAUX		(0x02000000)
 #define APMG_SVR_VOLTAGE_CONFIG_BIT_MSK	(0x000001E0) /* bit 8:5 */
 #define APMG_SVR_DIGITAL_VOLTAGE_1_32		(0x00000060)
@@ -99,152 +98,6 @@
 #define APMG_PCIDEV_STT_VAL_L1_ACT_DIS		(0x00000800)
 
 /**
- * BSM (Bootstrap State Machine)
- *
- * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program
- * in special SRAM that does not power down when the embedded control
- * processor is sleeping (e.g. for periodic power-saving shutdowns of radio).
- *
- * When powering back up after sleeps (or during initial uCode load), the BSM
- * internally loads the short bootstrap program from the special SRAM into the
- * embedded processor's instruction SRAM, and starts the processor so it runs
- * the bootstrap program.
- *
- * This bootstrap program loads (via PCI busmaster DMA) instructions and data
- * images for a uCode program from host DRAM locations.  The host driver
- * indicates DRAM locations and sizes for instruction and data images via the
- * four BSM_DRAM_* registers.  Once the bootstrap program loads the new program,
- * the new program starts automatically.
- *
- * The uCode used for open-source drivers includes two programs:
- *
- * 1)  Initialization -- performs hardware calibration and sets up some
- *     internal data, then notifies host via "initialize alive" notification
- *     (struct iwl_init_alive_resp) that it has completed all of its work.
- *     After signal from host, it then loads and starts the runtime program.
- *     The initialization program must be used when initially setting up the
- *     NIC after loading the driver.
- *
- * 2)  Runtime/Protocol -- performs all normal runtime operations.  This
- *     notifies host via "alive" notification (struct iwl_alive_resp) that it
- *     is ready to be used.
- *
- * When initializing the NIC, the host driver does the following procedure:
- *
- * 1)  Load bootstrap program (instructions only, no data image for bootstrap)
- *     into bootstrap memory.  Use dword writes starting at BSM_SRAM_LOWER_BOUND
- *
- * 2)  Point (via BSM_DRAM_*) to the "initialize" uCode data and instruction
- *     images in host DRAM.
- *
- * 3)  Set up BSM to copy from BSM SRAM into uCode instruction SRAM when asked:
- *     BSM_WR_MEM_SRC_REG = 0
- *     BSM_WR_MEM_DST_REG = RTC_INST_LOWER_BOUND
- *     BSM_WR_MEM_DWCOUNT_REG = # dwords in bootstrap instruction image
- *
- * 4)  Load bootstrap into instruction SRAM:
- *     BSM_WR_CTRL_REG = BSM_WR_CTRL_REG_BIT_START
- *
- * 5)  Wait for load completion:
- *     Poll BSM_WR_CTRL_REG for BSM_WR_CTRL_REG_BIT_START = 0
- *
- * 6)  Enable future boot loads whenever NIC's power management triggers it:
- *     BSM_WR_CTRL_REG = BSM_WR_CTRL_REG_BIT_START_EN
- *
- * 7)  Start the NIC by removing all reset bits:
- *     CSR_RESET = 0
- *
- *     The bootstrap uCode (already in instruction SRAM) loads initialization
- *     uCode.  Initialization uCode performs data initialization, sends
- *     "initialize alive" notification to host, and waits for a signal from
- *     host to load runtime code.
- *
- * 4)  Point (via BSM_DRAM_*) to the "runtime" uCode data and instruction
- *     images in host DRAM.  The last register loaded must be the instruction
- *     byte count register ("1" in MSbit tells initialization uCode to load
- *     the runtime uCode):
- *     BSM_DRAM_INST_BYTECOUNT_REG = byte count | BSM_DRAM_INST_LOAD
- *
- * 5)  Wait for "alive" notification, then issue normal runtime commands.
- *
- * Data caching during power-downs:
- *
- * Just before the embedded controller powers down (e.g for automatic
- * power-saving modes, or for RFKILL), uCode stores (via PCI busmaster DMA)
- * a current snapshot of the embedded processor's data SRAM into host DRAM.
- * This caches the data while the embedded processor's memory is powered down.
- * Location and size are controlled by BSM_DRAM_DATA_* registers.
- *
- * NOTE:  Instruction SRAM does not need to be saved, since that doesn't
- *        change during operation; the original image (from uCode distribution
- *        file) can be used for reload.
- *
- * When powering back up, the BSM loads the bootstrap program.  Bootstrap looks
- * at the BSM_DRAM_* registers, which now point to the runtime instruction
- * image and the cached (modified) runtime data (*not* the initialization
- * uCode).  Bootstrap reloads these runtime images into SRAM, and restarts the
- * uCode from where it left off before the power-down.
- *
- * NOTE:  Initialization uCode does *not* run as part of the save/restore
- *        procedure.
- *
- * This save/restore method is mostly for autonomous power management during
- * normal operation (result of POWER_TABLE_CMD).  Platform suspend/resume and
- * RFKILL should use complete restarts (with total re-initialization) of uCode,
- * allowing total shutdown (including BSM memory).
- *
- * Note that, during normal operation, the host DRAM that held the initial
- * startup data for the runtime code is now being used as a backup data cache
- * for modified data!  If you need to completely re-initialize the NIC, make
- * sure that you use the runtime data image from the uCode distribution file,
- * not the modified/saved runtime data.  You may want to store a separate
- * "clean" runtime data image in DRAM to avoid disk reads of distribution file.
- */
-
-/* BSM bit fields */
-#define BSM_WR_CTRL_REG_BIT_START     (0x80000000) /* start boot load now */
-#define BSM_WR_CTRL_REG_BIT_START_EN  (0x40000000) /* enable boot after pwrup*/
-#define BSM_DRAM_INST_LOAD            (0x80000000) /* start program load now */
-
-/* BSM addresses */
-#define BSM_BASE                     (PRPH_BASE + 0x3400)
-#define BSM_END                      (PRPH_BASE + 0x3800)
-
-#define BSM_WR_CTRL_REG              (BSM_BASE + 0x000) /* ctl and status */
-#define BSM_WR_MEM_SRC_REG           (BSM_BASE + 0x004) /* source in BSM mem */
-#define BSM_WR_MEM_DST_REG           (BSM_BASE + 0x008) /* dest in SRAM mem */
-#define BSM_WR_DWCOUNT_REG           (BSM_BASE + 0x00C) /* bytes */
-#define BSM_WR_STATUS_REG            (BSM_BASE + 0x010) /* bit 0:  1 == done */
-
-/*
- * Pointers and size regs for bootstrap load and data SRAM save/restore.
- * NOTE:  3945 pointers use bits 31:0 of DRAM address.
- *        4965 pointers use bits 35:4 of DRAM address.
- */
-#define BSM_DRAM_INST_PTR_REG        (BSM_BASE + 0x090)
-#define BSM_DRAM_INST_BYTECOUNT_REG  (BSM_BASE + 0x094)
-#define BSM_DRAM_DATA_PTR_REG        (BSM_BASE + 0x098)
-#define BSM_DRAM_DATA_BYTECOUNT_REG  (BSM_BASE + 0x09C)
-
-/*
- * BSM special memory, stays powered on during power-save sleeps.
- * Read/write, address range from LOWER_BOUND to (LOWER_BOUND + SIZE -1)
- */
-#define BSM_SRAM_LOWER_BOUND         (PRPH_BASE + 0x3800)
-#define BSM_SRAM_SIZE			(1024) /* bytes */
-
-
-/* 3945 Tx scheduler registers */
-#define ALM_SCD_BASE                        (PRPH_BASE + 0x2E00)
-#define ALM_SCD_MODE_REG                    (ALM_SCD_BASE + 0x000)
-#define ALM_SCD_ARASTAT_REG                 (ALM_SCD_BASE + 0x004)
-#define ALM_SCD_TXFACT_REG                  (ALM_SCD_BASE + 0x010)
-#define ALM_SCD_TXF4MF_REG                  (ALM_SCD_BASE + 0x014)
-#define ALM_SCD_TXF5MF_REG                  (ALM_SCD_BASE + 0x020)
-#define ALM_SCD_SBYP_MODE_1_REG             (ALM_SCD_BASE + 0x02C)
-#define ALM_SCD_SBYP_MODE_2_REG             (ALM_SCD_BASE + 0x030)
-
-/**
  * Tx Scheduler
  *
  * The Tx Scheduler selects the next frame to be transmitted, choosing TFDs
@@ -330,201 +183,10 @@
  * Max Tx window size is the max number of contiguous TFDs that the scheduler
  * can keep track of at one time when creating block-ack chains of frames.
  * Note that "64" matches the number of ack bits in a block-ack packet.
- * Driver should use SCD_WIN_SIZE and SCD_FRAME_LIMIT values to initialize
- * IWL49_SCD_CONTEXT_QUEUE_OFFSET(x) values.
  */
 #define SCD_WIN_SIZE				64
 #define SCD_FRAME_LIMIT				64
 
-/* SCD registers are internal, must be accessed via HBUS_TARG_PRPH regs */
-#define IWL49_SCD_START_OFFSET		0xa02c00
-
-/*
- * 4965 tells driver SRAM address for internal scheduler structs via this reg.
- * Value is valid only after "Alive" response from uCode.
- */
-#define IWL49_SCD_SRAM_BASE_ADDR           (IWL49_SCD_START_OFFSET + 0x0)
-
-/*
- * Driver may need to update queue-empty bits after changing queue's
- * write and read pointers (indexes) during (re-)initialization (i.e. when
- * scheduler is not tracking what's happening).
- * Bit fields:
- * 31-16:  Write mask -- 1: update empty bit, 0: don't change empty bit
- * 15-00:  Empty state, one for each queue -- 1: empty, 0: non-empty
- * NOTE:  This register is not used by Linux driver.
- */
-#define IWL49_SCD_EMPTY_BITS               (IWL49_SCD_START_OFFSET + 0x4)
-
-/*
- * Physical base address of array of byte count (BC) circular buffers (CBs).
- * Each Tx queue has a BC CB in host DRAM to support Scheduler-ACK mode.
- * This register points to BC CB for queue 0, must be on 1024-byte boundary.
- * Others are spaced by 1024 bytes.
- * Each BC CB is 2 bytes * (256 + 64) = 740 bytes, followed by 384 bytes pad.
- * (Index into a queue's BC CB) = (index into queue's TFD CB) = (SSN & 0xff).
- * Bit fields:
- * 25-00:  Byte Count CB physical address [35:10], must be 1024-byte aligned.
- */
-#define IWL49_SCD_DRAM_BASE_ADDR           (IWL49_SCD_START_OFFSET + 0x10)
-
-/*
- * Enables any/all Tx DMA/FIFO channels.
- * Scheduler generates requests for only the active channels.
- * Set this to 0xff to enable all 8 channels (normal usage).
- * Bit fields:
- *  7- 0:  Enable (1), disable (0), one bit for each channel 0-7
- */
-#define IWL49_SCD_TXFACT                   (IWL49_SCD_START_OFFSET + 0x1c)
-/*
- * Queue (x) Write Pointers (indexes, really!), one for each Tx queue.
- * Initialized and updated by driver as new TFDs are added to queue.
- * NOTE:  If using Block Ack, index must correspond to frame's
- *        Start Sequence Number; index = (SSN & 0xff)
- * NOTE:  Alternative to HBUS_TARG_WRPTR, which is what Linux driver uses?
- */
-#define IWL49_SCD_QUEUE_WRPTR(x)  (IWL49_SCD_START_OFFSET + 0x24 + (x) * 4)
-
-/*
- * Queue (x) Read Pointers (indexes, really!), one for each Tx queue.
- * For FIFO mode, index indicates next frame to transmit.
- * For Scheduler-ACK mode, index indicates first frame in Tx window.
- * Initialized by driver, updated by scheduler.
- */
-#define IWL49_SCD_QUEUE_RDPTR(x)  (IWL49_SCD_START_OFFSET + 0x64 + (x) * 4)
-
-/*
- * Select which queues work in chain mode (1) vs. not (0).
- * Use chain mode to build chains of aggregated frames.
- * Bit fields:
- * 31-16:  Reserved
- * 15-00:  Mode, one bit for each queue -- 1: Chain mode, 0: one-at-a-time
- * NOTE:  If driver sets up queue for chain mode, it should be also set up
- *        Scheduler-ACK mode as well, via SCD_QUEUE_STATUS_BITS(x).
- */
-#define IWL49_SCD_QUEUECHAIN_SEL  (IWL49_SCD_START_OFFSET + 0xd0)
-
-/*
- * Select which queues interrupt driver when scheduler increments
- * a queue's read pointer (index).
- * Bit fields:
- * 31-16:  Reserved
- * 15-00:  Interrupt enable, one bit for each queue -- 1: enabled, 0: disabled
- * NOTE:  This functionality is apparently a no-op; driver relies on interrupts
- *        from Rx queue to read Tx command responses and update Tx queues.
- */
-#define IWL49_SCD_INTERRUPT_MASK  (IWL49_SCD_START_OFFSET + 0xe4)
-
-/*
- * Queue search status registers.  One for each queue.
- * Sets up queue mode and assigns queue to Tx DMA channel.
- * Bit fields:
- * 19-10: Write mask/enable bits for bits 0-9
- *     9: Driver should init to "0"
- *     8: Scheduler-ACK mode (1), non-Scheduler-ACK (i.e. FIFO) mode (0).
- *        Driver should init to "1" for aggregation mode, or "0" otherwise.
- *   7-6: Driver should init to "0"
- *     5: Window Size Left; indicates whether scheduler can request
- *        another TFD, based on window size, etc.  Driver should init
- *        this bit to "1" for aggregation mode, or "0" for non-agg.
- *   4-1: Tx FIFO to use (range 0-7).
- *     0: Queue is active (1), not active (0).
- * Other bits should be written as "0"
- *
- * NOTE:  If enabling Scheduler-ACK mode, chain mode should also be enabled
- *        via SCD_QUEUECHAIN_SEL.
- */
-#define IWL49_SCD_QUEUE_STATUS_BITS(x)\
-	(IWL49_SCD_START_OFFSET + 0x104 + (x) * 4)
-
-/* Bit field positions */
-#define IWL49_SCD_QUEUE_STTS_REG_POS_ACTIVE	(0)
-#define IWL49_SCD_QUEUE_STTS_REG_POS_TXF	(1)
-#define IWL49_SCD_QUEUE_STTS_REG_POS_WSL	(5)
-#define IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACK	(8)
-
-/* Write masks */
-#define IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN	(10)
-#define IWL49_SCD_QUEUE_STTS_REG_MSK		(0x0007FC00)
-
-/**
- * 4965 internal SRAM structures for scheduler, shared with driver ...
- *
- * Driver should clear and initialize the following areas after receiving
- * "Alive" response from 4965 uCode, i.e. after initial
- * uCode load, or after a uCode load done for error recovery:
- *
- * SCD_CONTEXT_DATA_OFFSET (size 128 bytes)
- * SCD_TX_STTS_BITMAP_OFFSET (size 256 bytes)
- * SCD_TRANSLATE_TBL_OFFSET (size 32 bytes)
- *
- * Driver accesses SRAM via HBUS_TARG_MEM_* registers.
- * Driver reads base address of this scheduler area from SCD_SRAM_BASE_ADDR.
- * All OFFSET values must be added to this base address.
- */
-
-/*
- * Queue context.  One 8-byte entry for each of 16 queues.
- *
- * Driver should clear this entire area (size 0x80) to 0 after receiving
- * "Alive" notification from uCode.  Additionally, driver should init
- * each queue's entry as follows:
- *
- * LS Dword bit fields:
- *  0-06:  Max Tx window size for Scheduler-ACK.  Driver should init to 64.
- *
- * MS Dword bit fields:
- * 16-22:  Frame limit.  Driver should init to 10 (0xa).
- *
- * Driver should init all other bits to 0.
- *
- * Init must be done after driver receives "Alive" response from 4965 uCode,
- * and when setting up queue for aggregation.
- */
-#define IWL49_SCD_CONTEXT_DATA_OFFSET			0x380
-#define IWL49_SCD_CONTEXT_QUEUE_OFFSET(x) \
-			(IWL49_SCD_CONTEXT_DATA_OFFSET + ((x) * 8))
-
-#define IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_POS		(0)
-#define IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK		(0x0000007F)
-#define IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS	(16)
-#define IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK	(0x007F0000)
-
-/*
- * Tx Status Bitmap
- *
- * Driver should clear this entire area (size 0x100) to 0 after receiving
- * "Alive" notification from uCode.  Area is used only by device itself;
- * no other support (besides clearing) is required from driver.
- */
-#define IWL49_SCD_TX_STTS_BITMAP_OFFSET		0x400
-
-/*
- * RAxTID to queue translation mapping.
- *
- * When queue is in Scheduler-ACK mode, frames placed in a that queue must be
- * for only one combination of receiver address (RA) and traffic ID (TID), i.e.
- * one QOS priority level destined for one station (for this wireless link,
- * not final destination).  The SCD_TRANSLATE_TABLE area provides 16 16-bit
- * mappings, one for each of the 16 queues.  If queue is not in Scheduler-ACK
- * mode, the device ignores the mapping value.
- *
- * Bit fields, for each 16-bit map:
- * 15-9:  Reserved, set to 0
- *  8-4:  Index into device's station table for recipient station
- *  3-0:  Traffic ID (tid), range 0-15
- *
- * Driver should clear this entire area (size 32 bytes) to 0 after receiving
- * "Alive" notification from uCode.  To update a 16-bit map value, driver
- * must read a dword-aligned value from device SRAM, replace the 16-bit map
- * value of interest, and write the dword value back into device SRAM.
- */
-#define IWL49_SCD_TRANSLATE_TBL_OFFSET		0x500
-
-/* Find translation table dword to read/write for given queue */
-#define IWL49_SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \
-	((IWL49_SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffffffc)
-
 #define IWL_SCD_TXFIFO_POS_TID			(0)
 #define IWL_SCD_TXFIFO_POS_RA			(4)
 #define IWL_SCD_QUEUE_RA_TID_MAP_RATID_MSK	(0x01FF)
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index 6f9a2fa..c421f56 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
@@ -239,16 +239,16 @@
 		       palive->is_valid, palive->ver_type,
 		       palive->ver_subtype);
 
+	priv->device_pointers.log_event_table =
+		le32_to_cpu(palive->log_event_table_ptr);
+	priv->device_pointers.error_event_table =
+		le32_to_cpu(palive->error_event_table_ptr);
+
 	if (palive->ver_subtype == INITIALIZE_SUBTYPE) {
 		IWL_DEBUG_INFO(priv, "Initialization Alive received.\n");
-		memcpy(&priv->card_alive_init,
-		       &pkt->u.alive_frame,
-		       sizeof(struct iwl_init_alive_resp));
 		pwork = &priv->init_alive_start;
 	} else {
 		IWL_DEBUG_INFO(priv, "Runtime Alive received.\n");
-		memcpy(&priv->card_alive, &pkt->u.alive_frame,
-		       sizeof(struct iwl_alive_resp));
 		pwork = &priv->alive_start;
 	}
 
@@ -898,7 +898,6 @@
 	memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
 
 	ieee80211_rx(priv->hw, skb);
-	priv->alloc_rxb_page--;
 	rxb->page = NULL;
 }
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index 3a4d9e6..c517f6d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -2,7 +2,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.h b/drivers/net/wireless/iwlwifi/iwl-spectrum.h
index c4ca0b5..cb80bb4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-spectrum.h
+++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ieee80211 subsystem header files.
  *
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index bc90a12..c215156 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
@@ -233,7 +233,6 @@
 	struct iwl_station_entry *station;
 	int i;
 	u8 sta_id = IWL_INVALID_STATION;
-	u16 rate;
 
 	if (is_ap)
 		sta_id = ctx->ap_sta_id;
@@ -306,12 +305,6 @@
 	 */
 	iwl_set_ht_add_station(priv, sta_id, sta, ctx);
 
-	/* 3945 only */
-	rate = (priv->band == IEEE80211_BAND_5GHZ) ?
-		IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP;
-	/* Turn on both antennas for the station... */
-	station->sta.rate_n_flags = cpu_to_le16(rate | RATE_MCS_ANT_AB_MSK);
-
 	return sta_id;
 
 }
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h
index 206f1e1..ff64027 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.h
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 277c917..565980f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
@@ -149,32 +149,31 @@
 	struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
 	struct iwl_queue *q = &txq->q;
 	int i;
-	bool huge = false;
 
 	if (q->n_bd == 0)
 		return;
 
 	while (q->read_ptr != q->write_ptr) {
-		/* we have no way to tell if it is a huge cmd ATM */
 		i = get_cmd_index(q, q->read_ptr, 0);
 
-		if (txq->meta[i].flags & CMD_SIZE_HUGE)
-			huge = true;
-		else
+		if (txq->meta[i].flags & CMD_MAPPED) {
 			pci_unmap_single(priv->pci_dev,
 					 dma_unmap_addr(&txq->meta[i], mapping),
 					 dma_unmap_len(&txq->meta[i], len),
 					 PCI_DMA_BIDIRECTIONAL);
+			txq->meta[i].flags = 0;
+		}
 
-	     q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd);
+		q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd);
 	}
 
-	if (huge) {
-		i = q->n_window;
+	i = q->n_window;
+	if (txq->meta[i].flags & CMD_MAPPED) {
 		pci_unmap_single(priv->pci_dev,
 				 dma_unmap_addr(&txq->meta[i], mapping),
 				 dma_unmap_len(&txq->meta[i], len),
 				 PCI_DMA_BIDIRECTIONAL);
+		txq->meta[i].flags = 0;
 	}
 }
 
@@ -463,7 +462,11 @@
 		return -EIO;
 	}
 
+	spin_lock_irqsave(&priv->hcmd_lock, flags);
+
 	if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) {
+		spin_unlock_irqrestore(&priv->hcmd_lock, flags);
+
 		IWL_ERR(priv, "No space in command queue\n");
 		if (priv->cfg->ops->lib->tt_ops.ct_kill_check) {
 			is_ct_kill =
@@ -471,27 +474,22 @@
 		}
 		if (!is_ct_kill) {
 			IWL_ERR(priv, "Restarting adapter due to queue full\n");
-			queue_work(priv->workqueue, &priv->restart);
+			iwlagn_fw_error(priv, false);
 		}
 		return -ENOSPC;
 	}
 
-	spin_lock_irqsave(&priv->hcmd_lock, flags);
-
-	/* If this is a huge cmd, mark the huge flag also on the meta.flags
-	 * of the _original_ cmd. This is used for DMA mapping clean up.
-	 */
-	if (cmd->flags & CMD_SIZE_HUGE) {
-		idx = get_cmd_index(q, q->write_ptr, 0);
-		txq->meta[idx].flags = CMD_SIZE_HUGE;
-	}
-
 	idx = get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE);
 	out_cmd = txq->cmd[idx];
 	out_meta = &txq->meta[idx];
 
+	if (WARN_ON(out_meta->flags & CMD_MAPPED)) {
+		spin_unlock_irqrestore(&priv->hcmd_lock, flags);
+		return -ENOSPC;
+	}
+
 	memset(out_meta, 0, sizeof(*out_meta));	/* re-initialize to NULL */
-	out_meta->flags = cmd->flags;
+	out_meta->flags = cmd->flags | CMD_MAPPED;
 	if (cmd->flags & CMD_WANT_SKB)
 		out_meta->source = cmd;
 	if (cmd->flags & CMD_ASYNC)
@@ -584,7 +582,7 @@
 		if (nfreed++ > 0) {
 			IWL_ERR(priv, "HCMD skipped: index (%d) %d %d\n", idx,
 					q->write_ptr, q->read_ptr);
-			queue_work(priv->workqueue, &priv->restart);
+			iwlagn_fw_error(priv, false);
 		}
 
 	}
@@ -609,6 +607,10 @@
 	struct iwl_device_cmd *cmd;
 	struct iwl_cmd_meta *meta;
 	struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
+	unsigned long flags;
+	void (*callback) (struct iwl_priv *priv, struct iwl_device_cmd *cmd,
+			  struct iwl_rx_packet *pkt);
+
 
 	/* If a Tx command is being handled and it isn't in the actual
 	 * command queue then there a command routing bug has been introduced
@@ -622,14 +624,8 @@
 		return;
 	}
 
-	/* If this is a huge cmd, clear the huge flag on the meta.flags
-	 * of the _original_ cmd. So that iwl_cmd_queue_free won't unmap
-	 * the DMA buffer for the scan (huge) command.
-	 */
-	if (huge) {
-		cmd_index = get_cmd_index(&txq->q, index, 0);
-		txq->meta[cmd_index].flags = 0;
-	}
+	spin_lock_irqsave(&priv->hcmd_lock, flags);
+
 	cmd_index = get_cmd_index(&txq->q, index, huge);
 	cmd = txq->cmd[cmd_index];
 	meta = &txq->meta[cmd_index];
@@ -639,12 +635,13 @@
 			 dma_unmap_len(meta, len),
 			 PCI_DMA_BIDIRECTIONAL);
 
+	callback = NULL;
 	/* Input error checking is done when commands are added to queue. */
 	if (meta->flags & CMD_WANT_SKB) {
 		meta->source->reply_page = (unsigned long)rxb_addr(rxb);
 		rxb->page = NULL;
-	} else if (meta->callback)
-		meta->callback(priv, cmd, pkt);
+	} else
+		callback = meta->callback;
 
 	iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index);
 
@@ -654,5 +651,12 @@
 			       get_cmd_string(cmd->hdr.cmd));
 		wake_up_interruptible(&priv->wait_command_queue);
 	}
+
+	/* Mark as unmapped */
 	meta->flags = 0;
+
+	spin_unlock_irqrestore(&priv->hcmd_lock, flags);
+
+	if (callback)
+		callback(priv, cmd, pkt);
 }
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
index f6c2cd6..078ef43 100644
--- a/drivers/net/wireless/libertas/if_spi.c
+++ b/drivers/net/wireless/libertas/if_spi.c
@@ -57,6 +57,7 @@
 	/* Handles all SPI communication (except for FW load) */
 	struct workqueue_struct		*workqueue;
 	struct work_struct		packet_work;
+	struct work_struct		resume_work;
 
 	u8				cmd_buffer[IF_SPI_CMD_BUF_SIZE];
 
@@ -68,6 +69,9 @@
 
 	/* Protects cmd_packet_list and data_packet_list */
 	spinlock_t			buffer_lock;
+
+	/* True is card suspended */
+	u8				suspended;
 };
 
 static void free_if_spi_card(struct if_spi_card *card)
@@ -1057,6 +1061,28 @@
 	return err;
 }
 
+static void if_spi_resume_worker(struct work_struct *work)
+{
+	struct if_spi_card *card;
+
+	card = container_of(work, struct if_spi_card, resume_work);
+
+	if (card->suspended) {
+		if (card->pdata->setup)
+			card->pdata->setup(card->spi);
+
+		/* Init card ... */
+		if_spi_init_card(card);
+
+		enable_irq(card->spi->irq);
+
+		/* And resume it ... */
+		lbs_resume(card->priv);
+
+		card->suspended = 0;
+	}
+}
+
 static int __devinit if_spi_probe(struct spi_device *spi)
 {
 	struct if_spi_card *card;
@@ -1107,6 +1133,7 @@
 		goto free_card;
 	}
 	card->priv = priv;
+	priv->setup_fw_on_resume = 1;
 	priv->card = card;
 	priv->hw_host_to_card = if_spi_host_to_card;
 	priv->enter_deep_sleep = NULL;
@@ -1117,6 +1144,7 @@
 	/* Initialize interrupt handling stuff. */
 	card->workqueue = create_workqueue("libertas_spi");
 	INIT_WORK(&card->packet_work, if_spi_host_to_card_worker);
+	INIT_WORK(&card->resume_work, if_spi_resume_worker);
 
 	err = request_irq(spi->irq, if_spi_host_interrupt,
 			IRQF_TRIGGER_FALLING, "libertas_spi", card);
@@ -1161,6 +1189,8 @@
 	lbs_deb_spi("libertas_spi_remove\n");
 	lbs_deb_enter(LBS_DEB_SPI);
 
+	cancel_work_sync(&card->resume_work);
+
 	lbs_stop_card(priv);
 	lbs_remove_card(priv); /* will call free_netdev */
 
@@ -1174,6 +1204,40 @@
 	return 0;
 }
 
+static int if_spi_suspend(struct device *dev)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct if_spi_card *card = spi_get_drvdata(spi);
+
+	if (!card->suspended) {
+		lbs_suspend(card->priv);
+		flush_workqueue(card->workqueue);
+		disable_irq(spi->irq);
+
+		if (card->pdata->teardown)
+			card->pdata->teardown(spi);
+		card->suspended = 1;
+	}
+
+	return 0;
+}
+
+static int if_spi_resume(struct device *dev)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct if_spi_card *card = spi_get_drvdata(spi);
+
+	/* Schedule delayed work */
+	schedule_work(&card->resume_work);
+
+	return 0;
+}
+
+static const struct dev_pm_ops if_spi_pm_ops = {
+	.suspend	= if_spi_suspend,
+	.resume		= if_spi_resume,
+};
+
 static struct spi_driver libertas_spi_driver = {
 	.probe	= if_spi_probe,
 	.remove = __devexit_p(libertas_spi_remove),
@@ -1181,6 +1245,7 @@
 		.name	= "libertas_spi",
 		.bus	= &spi_bus_type,
 		.owner	= THIS_MODULE,
+		.pm	= &if_spi_pm_ops,
 	},
 };
 
diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c
new file mode 100644
index 0000000..73a6e62
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/11n.c
@@ -0,0 +1,809 @@
+/*
+ * Marvell Wireless LAN device driver: 802.11n
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+#include "11n.h"
+
+/*
+ * Fills HT capability information field, AMPDU Parameters field, HT extended
+ * capability field, and supported MCS set fields.
+ *
+ * Only the following HT capability information fields are used, all other
+ * fields are always turned off.
+ *
+ *  Bit 1 : Supported channel width (0: 20MHz, 1: Both 20 and 40 MHz)
+ *  Bit 4 : Greenfield support (0: Not supported, 1: Supported)
+ *  Bit 5 : Short GI for 20 MHz support (0: Not supported, 1: Supported)
+ *  Bit 6 : Short GI for 40 MHz support (0: Not supported, 1: Supported)
+ *  Bit 7 : Tx STBC (0: Not supported, 1: Supported)
+ *  Bit 8-9 : Rx STBC (0: Not supported, X: Support for up to X spatial streams)
+ *  Bit 10 : Delayed BA support (0: Not supported, 1: Supported)
+ *  Bit 11 : Maximum AMSDU length (0: 3839 octets, 1: 7935 octets)
+ *  Bit 14 : 40-Mhz intolerant support (0: Not supported, 1: Supported)
+ *
+ *  In addition, the following AMPDU Parameters are set -
+ *      - Maximum AMPDU length exponent (set to 3)
+ *      - Minimum AMPDU start spacing (set to 0 - No restrictions)
+ *
+ *  MCS is set for 1x1, with MSC32 for infra mode or ad-hoc mode with 40 MHz
+ *  support.
+ *
+ *  RD responder bit to set to clear in the extended capability header.
+ */
+void
+mwifiex_fill_cap_info(struct mwifiex_private *priv,
+		      struct mwifiex_ie_types_htcap *ht_cap)
+{
+	struct mwifiex_adapter *adapter = priv->adapter;
+	u8 *mcs;
+	int rx_mcs_supp;
+	uint16_t ht_cap_info = le16_to_cpu(ht_cap->ht_cap.cap_info);
+	uint16_t ht_ext_cap = le16_to_cpu(ht_cap->ht_cap.extended_ht_cap_info);
+
+	/* Convert dev_cap to IEEE80211_HT_CAP */
+	if (ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap))
+		ht_cap_info |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+	else
+		ht_cap_info &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+
+	if (ISSUPP_SHORTGI20(adapter->hw_dot_11n_dev_cap))
+		ht_cap_info |= IEEE80211_HT_CAP_SGI_20;
+	else
+		ht_cap_info &= ~IEEE80211_HT_CAP_SGI_20;
+
+	if (ISSUPP_SHORTGI40(adapter->hw_dot_11n_dev_cap))
+		ht_cap_info |= IEEE80211_HT_CAP_SGI_40;
+	else
+		ht_cap_info &= ~IEEE80211_HT_CAP_SGI_40;
+
+	if (ISSUPP_TXSTBC(adapter->hw_dot_11n_dev_cap))
+		ht_cap_info |= IEEE80211_HT_CAP_TX_STBC;
+	else
+		ht_cap_info &= ~IEEE80211_HT_CAP_TX_STBC;
+
+	if (ISSUPP_RXSTBC(adapter->hw_dot_11n_dev_cap))
+		ht_cap_info |= 1 << IEEE80211_HT_CAP_RX_STBC_SHIFT;
+	else
+		ht_cap_info &= ~(3 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
+
+	if (ISSUPP_GREENFIELD(adapter->hw_dot_11n_dev_cap))
+		ht_cap_info |= IEEE80211_HT_CAP_GRN_FLD;
+	else
+		ht_cap_info &= ~IEEE80211_HT_CAP_GRN_FLD;
+
+	ht_cap_info &= ~IEEE80211_HT_CAP_MAX_AMSDU;
+	ht_cap_info |= IEEE80211_HT_CAP_SM_PS;
+
+	ht_cap->ht_cap.ampdu_params_info |= IEEE80211_HT_AMPDU_PARM_FACTOR;
+	ht_cap->ht_cap.ampdu_params_info &= ~IEEE80211_HT_AMPDU_PARM_DENSITY;
+
+	rx_mcs_supp = GET_RXMCSSUPP(adapter->hw_dev_mcs_support);
+
+	mcs = (u8 *)&ht_cap->ht_cap.mcs;
+
+	/* Set MCS for 1x1 */
+	memset(mcs, 0xff, rx_mcs_supp);
+
+	/* Clear all the other values */
+	memset(&mcs[rx_mcs_supp], 0,
+			sizeof(struct ieee80211_mcs_info) - rx_mcs_supp);
+
+	if (priv->bss_mode == NL80211_IFTYPE_STATION ||
+			(ht_cap_info & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
+		/* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */
+		SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask);
+
+	/* Clear RD responder bit */
+	RESETHT_EXTCAP_RDG(ht_ext_cap);
+
+	ht_cap->ht_cap.cap_info = cpu_to_le16(ht_cap_info);
+	ht_cap->ht_cap.extended_ht_cap_info = cpu_to_le16(ht_ext_cap);
+}
+
+/*
+ * This function returns the pointer to an entry in BA Stream
+ * table which matches the requested BA status.
+ */
+static struct mwifiex_tx_ba_stream_tbl *
+mwifiex_11n_get_tx_ba_stream_status(struct mwifiex_private *priv,
+				  enum mwifiex_ba_status ba_status)
+{
+	struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
+	list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
+		if (tx_ba_tsr_tbl->ba_status == ba_status) {
+			spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock,
+					       flags);
+			return tx_ba_tsr_tbl;
+		}
+	}
+	spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
+	return NULL;
+}
+
+/*
+ * This function handles the command response of delete a block
+ * ack request.
+ *
+ * The function checks the response success status and takes action
+ * accordingly (send an add BA request in case of success, or recreate
+ * the deleted stream in case of failure, if the add BA was also
+ * initiated by us).
+ */
+int mwifiex_ret_11n_delba(struct mwifiex_private *priv,
+			  struct host_cmd_ds_command *resp)
+{
+	int tid;
+	struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl;
+	struct host_cmd_ds_11n_delba *del_ba =
+		(struct host_cmd_ds_11n_delba *) &resp->params.del_ba;
+	uint16_t del_ba_param_set = le16_to_cpu(del_ba->del_ba_param_set);
+
+	tid = del_ba_param_set >> DELBA_TID_POS;
+	if (del_ba->del_result == BA_RESULT_SUCCESS) {
+		mwifiex_11n_delete_ba_stream_tbl(priv, tid,
+				del_ba->peer_mac_addr, TYPE_DELBA_SENT,
+				INITIATOR_BIT(del_ba_param_set));
+
+		tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_status(priv,
+						BA_STREAM_SETUP_INPROGRESS);
+		if (tx_ba_tbl)
+			mwifiex_send_addba(priv, tx_ba_tbl->tid,
+					   tx_ba_tbl->ra);
+	} else { /*
+		  * In case of failure, recreate the deleted stream in case
+		  * we initiated the ADDBA
+		  */
+		if (INITIATOR_BIT(del_ba_param_set)) {
+			mwifiex_11n_create_tx_ba_stream_tbl(priv,
+					del_ba->peer_mac_addr, tid,
+					BA_STREAM_SETUP_INPROGRESS);
+
+			tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_status(priv,
+					BA_STREAM_SETUP_INPROGRESS);
+			if (tx_ba_tbl)
+				mwifiex_11n_delete_ba_stream_tbl(priv,
+						tx_ba_tbl->tid, tx_ba_tbl->ra,
+						TYPE_DELBA_SENT, true);
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * This function handles the command response of add a block
+ * ack request.
+ *
+ * Handling includes changing the header fields to CPU formats, checking
+ * the response success status and taking actions accordingly (delete the
+ * BA stream table in case of failure).
+ */
+int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv,
+			      struct host_cmd_ds_command *resp)
+{
+	int tid;
+	struct host_cmd_ds_11n_addba_rsp *add_ba_rsp =
+		(struct host_cmd_ds_11n_addba_rsp *) &resp->params.add_ba_rsp;
+	struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl;
+
+	add_ba_rsp->ssn = cpu_to_le16((le16_to_cpu(add_ba_rsp->ssn))
+			& SSN_MASK);
+
+	tid = (le16_to_cpu(add_ba_rsp->block_ack_param_set)
+		& IEEE80211_ADDBA_PARAM_TID_MASK)
+		>> BLOCKACKPARAM_TID_POS;
+	if (le16_to_cpu(add_ba_rsp->status_code) == BA_RESULT_SUCCESS) {
+		tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid,
+						add_ba_rsp->peer_mac_addr);
+		if (tx_ba_tbl) {
+			dev_dbg(priv->adapter->dev, "info: BA stream complete\n");
+			tx_ba_tbl->ba_status = BA_STREAM_SETUP_COMPLETE;
+		} else {
+			dev_err(priv->adapter->dev, "BA stream not created\n");
+		}
+	} else {
+		mwifiex_11n_delete_ba_stream_tbl(priv, tid,
+						add_ba_rsp->peer_mac_addr,
+						TYPE_DELBA_SENT, true);
+		if (add_ba_rsp->add_rsp_result != BA_RESULT_TIMEOUT)
+			priv->aggr_prio_tbl[tid].ampdu_ap =
+				BA_STREAM_NOT_ALLOWED;
+	}
+
+	return 0;
+}
+
+/*
+ * This function handles the command response of 11n configuration request.
+ *
+ * Handling includes changing the header fields into CPU format.
+ */
+int mwifiex_ret_11n_cfg(struct mwifiex_private *priv,
+			struct host_cmd_ds_command *resp,
+			void *data_buf)
+{
+	struct mwifiex_ds_11n_tx_cfg *tx_cfg = NULL;
+	struct host_cmd_ds_11n_cfg *htcfg = &resp->params.htcfg;
+
+	if (data_buf) {
+		tx_cfg = (struct mwifiex_ds_11n_tx_cfg *) data_buf;
+		tx_cfg->tx_htcap = le16_to_cpu(htcfg->ht_tx_cap);
+		tx_cfg->tx_htinfo = le16_to_cpu(htcfg->ht_tx_info);
+	}
+	return 0;
+}
+
+/*
+ * This function prepares command of reconfigure Tx buffer.
+ *
+ * Preparation includes -
+ *      - Setting command ID, action and proper size
+ *      - Setting Tx buffer size (for SET only)
+ *      - Ensuring correct endian-ness
+ */
+int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv,
+			     struct host_cmd_ds_command *cmd, int cmd_action,
+			     void *data_buf)
+{
+	struct host_cmd_ds_txbuf_cfg *tx_buf = &cmd->params.tx_buf;
+	u16 action = (u16) cmd_action;
+	u16 buf_size = *((u16 *) data_buf);
+
+	cmd->command = cpu_to_le16(HostCmd_CMD_RECONFIGURE_TX_BUFF);
+	cmd->size =
+		cpu_to_le16(sizeof(struct host_cmd_ds_txbuf_cfg) + S_DS_GEN);
+	tx_buf->action = cpu_to_le16(action);
+	switch (action) {
+	case HostCmd_ACT_GEN_SET:
+		dev_dbg(priv->adapter->dev, "cmd: set tx_buf=%d\n", buf_size);
+		tx_buf->buff_size = cpu_to_le16(buf_size);
+		break;
+	case HostCmd_ACT_GEN_GET:
+	default:
+		tx_buf->buff_size = 0;
+		break;
+	}
+	return 0;
+}
+
+/*
+ * This function prepares command of AMSDU aggregation control.
+ *
+ * Preparation includes -
+ *      - Setting command ID, action and proper size
+ *      - Setting AMSDU control parameters (for SET only)
+ *      - Ensuring correct endian-ness
+ */
+int mwifiex_cmd_amsdu_aggr_ctrl(struct mwifiex_private *priv,
+				struct host_cmd_ds_command *cmd,
+				int cmd_action, void *data_buf)
+{
+	struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl =
+		&cmd->params.amsdu_aggr_ctrl;
+	u16 action = (u16) cmd_action;
+	struct mwifiex_ds_11n_amsdu_aggr_ctrl *aa_ctrl =
+		(struct mwifiex_ds_11n_amsdu_aggr_ctrl *) data_buf;
+
+	cmd->command = cpu_to_le16(HostCmd_CMD_AMSDU_AGGR_CTRL);
+	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_amsdu_aggr_ctrl)
+				+ S_DS_GEN);
+	amsdu_ctrl->action = cpu_to_le16(action);
+	switch (action) {
+	case HostCmd_ACT_GEN_SET:
+		amsdu_ctrl->enable = cpu_to_le16(aa_ctrl->enable);
+		amsdu_ctrl->curr_buf_size = 0;
+		break;
+	case HostCmd_ACT_GEN_GET:
+	default:
+		amsdu_ctrl->curr_buf_size = 0;
+		break;
+	}
+	return 0;
+}
+
+/*
+ * This function handles the command response of AMSDU aggregation
+ * control request.
+ *
+ * Handling includes changing the header fields into CPU format.
+ */
+int mwifiex_ret_amsdu_aggr_ctrl(struct mwifiex_private *priv,
+				struct host_cmd_ds_command *resp,
+				void *data_buf)
+{
+	struct mwifiex_ds_11n_amsdu_aggr_ctrl *amsdu_aggr_ctrl = NULL;
+	struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl =
+		&resp->params.amsdu_aggr_ctrl;
+
+	if (data_buf) {
+		amsdu_aggr_ctrl =
+			(struct mwifiex_ds_11n_amsdu_aggr_ctrl *) data_buf;
+		amsdu_aggr_ctrl->enable = le16_to_cpu(amsdu_ctrl->enable);
+		amsdu_aggr_ctrl->curr_buf_size =
+			le16_to_cpu(amsdu_ctrl->curr_buf_size);
+	}
+	return 0;
+}
+
+/*
+ * This function prepares 11n configuration command.
+ *
+ * Preparation includes -
+ *      - Setting command ID, action and proper size
+ *      - Setting HT Tx capability and HT Tx information fields
+ *      - Ensuring correct endian-ness
+ */
+int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv,
+			struct host_cmd_ds_command *cmd,
+			u16 cmd_action, void *data_buf)
+{
+	struct host_cmd_ds_11n_cfg *htcfg = &cmd->params.htcfg;
+	struct mwifiex_ds_11n_tx_cfg *txcfg =
+		(struct mwifiex_ds_11n_tx_cfg *) data_buf;
+
+	cmd->command = cpu_to_le16(HostCmd_CMD_11N_CFG);
+	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_11n_cfg) + S_DS_GEN);
+	htcfg->action = cpu_to_le16(cmd_action);
+	htcfg->ht_tx_cap = cpu_to_le16(txcfg->tx_htcap);
+	htcfg->ht_tx_info = cpu_to_le16(txcfg->tx_htinfo);
+	return 0;
+}
+
+/*
+ * This function appends an 11n TLV to a buffer.
+ *
+ * Buffer allocation is responsibility of the calling
+ * function. No size validation is made here.
+ *
+ * The function fills up the following sections, if applicable -
+ *      - HT capability IE
+ *      - HT information IE (with channel list)
+ *      - 20/40 BSS Coexistence IE
+ *      - HT Extended Capabilities IE
+ */
+int
+mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
+			   struct mwifiex_bssdescriptor *bss_desc,
+			   u8 **buffer)
+{
+	struct mwifiex_ie_types_htcap *ht_cap;
+	struct mwifiex_ie_types_htinfo *ht_info;
+	struct mwifiex_ie_types_chan_list_param_set *chan_list;
+	struct mwifiex_ie_types_2040bssco *bss_co_2040;
+	struct mwifiex_ie_types_extcap *ext_cap;
+	int ret_len = 0;
+
+	if (!buffer || !*buffer)
+		return ret_len;
+
+	if (bss_desc->bcn_ht_cap) {
+		ht_cap = (struct mwifiex_ie_types_htcap *) *buffer;
+		memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap));
+		ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY);
+		ht_cap->header.len =
+				cpu_to_le16(sizeof(struct ieee80211_ht_cap));
+		memcpy((u8 *) ht_cap + sizeof(struct mwifiex_ie_types_header),
+		       (u8 *) bss_desc->bcn_ht_cap +
+		       sizeof(struct ieee_types_header),
+		       le16_to_cpu(ht_cap->header.len));
+
+		mwifiex_fill_cap_info(priv, ht_cap);
+
+		*buffer += sizeof(struct mwifiex_ie_types_htcap);
+		ret_len += sizeof(struct mwifiex_ie_types_htcap);
+	}
+
+	if (bss_desc->bcn_ht_info) {
+		if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
+			ht_info = (struct mwifiex_ie_types_htinfo *) *buffer;
+			memset(ht_info, 0,
+			       sizeof(struct mwifiex_ie_types_htinfo));
+			ht_info->header.type =
+					cpu_to_le16(WLAN_EID_HT_INFORMATION);
+			ht_info->header.len =
+				cpu_to_le16(sizeof(struct ieee80211_ht_info));
+
+			memcpy((u8 *) ht_info +
+			       sizeof(struct mwifiex_ie_types_header),
+			       (u8 *) bss_desc->bcn_ht_info +
+			       sizeof(struct ieee_types_header),
+			       le16_to_cpu(ht_info->header.len));
+
+			if (!ISSUPP_CHANWIDTH40
+					(priv->adapter->hw_dot_11n_dev_cap))
+				ht_info->ht_info.ht_param &=
+					~(IEEE80211_HT_PARAM_CHAN_WIDTH_ANY |
+					IEEE80211_HT_PARAM_CHA_SEC_OFFSET);
+
+			*buffer += sizeof(struct mwifiex_ie_types_htinfo);
+			ret_len += sizeof(struct mwifiex_ie_types_htinfo);
+		}
+
+		chan_list =
+			(struct mwifiex_ie_types_chan_list_param_set *) *buffer;
+		memset(chan_list, 0,
+		       sizeof(struct mwifiex_ie_types_chan_list_param_set));
+		chan_list->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
+		chan_list->header.len = cpu_to_le16(
+			sizeof(struct mwifiex_ie_types_chan_list_param_set) -
+			sizeof(struct mwifiex_ie_types_header));
+		chan_list->chan_scan_param[0].chan_number =
+			bss_desc->bcn_ht_info->control_chan;
+		chan_list->chan_scan_param[0].radio_type =
+			mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
+
+		if (ISSUPP_CHANWIDTH40(priv->adapter->hw_dot_11n_dev_cap)
+			&& (bss_desc->bcn_ht_info->ht_param &
+				IEEE80211_HT_PARAM_CHAN_WIDTH_ANY))
+			SET_SECONDARYCHAN(chan_list->chan_scan_param[0].
+					  radio_type,
+					  (bss_desc->bcn_ht_info->ht_param &
+					  IEEE80211_HT_PARAM_CHA_SEC_OFFSET));
+
+		*buffer += sizeof(struct mwifiex_ie_types_chan_list_param_set);
+		ret_len += sizeof(struct mwifiex_ie_types_chan_list_param_set);
+	}
+
+	if (bss_desc->bcn_bss_co_2040) {
+		bss_co_2040 = (struct mwifiex_ie_types_2040bssco *) *buffer;
+		memset(bss_co_2040, 0,
+		       sizeof(struct mwifiex_ie_types_2040bssco));
+		bss_co_2040->header.type = cpu_to_le16(WLAN_EID_BSS_COEX_2040);
+		bss_co_2040->header.len =
+		       cpu_to_le16(sizeof(bss_co_2040->bss_co_2040));
+
+		memcpy((u8 *) bss_co_2040 +
+		       sizeof(struct mwifiex_ie_types_header),
+		       (u8 *) bss_desc->bcn_bss_co_2040 +
+		       sizeof(struct ieee_types_header),
+		       le16_to_cpu(bss_co_2040->header.len));
+
+		*buffer += sizeof(struct mwifiex_ie_types_2040bssco);
+		ret_len += sizeof(struct mwifiex_ie_types_2040bssco);
+	}
+
+	if (bss_desc->bcn_ext_cap) {
+		ext_cap = (struct mwifiex_ie_types_extcap *) *buffer;
+		memset(ext_cap, 0, sizeof(struct mwifiex_ie_types_extcap));
+		ext_cap->header.type = cpu_to_le16(WLAN_EID_EXT_CAPABILITY);
+		ext_cap->header.len = cpu_to_le16(sizeof(ext_cap->ext_cap));
+
+		memcpy((u8 *) ext_cap +
+		       sizeof(struct mwifiex_ie_types_header),
+		       (u8 *) bss_desc->bcn_ext_cap +
+		       sizeof(struct ieee_types_header),
+		       le16_to_cpu(ext_cap->header.len));
+
+		*buffer += sizeof(struct mwifiex_ie_types_extcap);
+		ret_len += sizeof(struct mwifiex_ie_types_extcap);
+	}
+
+	return ret_len;
+}
+
+/*
+ * This function reconfigures the Tx buffer size in firmware.
+ *
+ * This function prepares a firmware command and issues it, if
+ * the current Tx buffer size is different from the one requested.
+ * Maximum configurable Tx buffer size is limited by the HT capability
+ * field value.
+ */
+void
+mwifiex_cfg_tx_buf(struct mwifiex_private *priv,
+		   struct mwifiex_bssdescriptor *bss_desc)
+{
+	u16 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_2K;
+	u16 tx_buf = 0;
+	u16 curr_tx_buf_size = 0;
+
+	if (bss_desc->bcn_ht_cap) {
+		if (le16_to_cpu(bss_desc->bcn_ht_cap->cap_info) &
+				IEEE80211_HT_CAP_MAX_AMSDU)
+			max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_8K;
+		else
+			max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_4K;
+	}
+
+	tx_buf = min(priv->adapter->max_tx_buf_size, max_amsdu);
+
+	dev_dbg(priv->adapter->dev, "info: max_amsdu=%d, max_tx_buf=%d\n",
+			max_amsdu, priv->adapter->max_tx_buf_size);
+
+	if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_2K)
+		curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
+	else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_4K)
+		curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K;
+	else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_8K)
+		curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_8K;
+	if (curr_tx_buf_size != tx_buf)
+		mwifiex_prepare_cmd(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF,
+			HostCmd_ACT_GEN_SET, 0,
+			NULL, &tx_buf);
+
+	return;
+}
+
+/*
+ * This function checks if the given pointer is valid entry of
+ * Tx BA Stream table.
+ */
+static int mwifiex_is_tx_ba_stream_ptr_valid(struct mwifiex_private *priv,
+				struct mwifiex_tx_ba_stream_tbl *tx_tbl_ptr)
+{
+	struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
+
+	list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
+		if (tx_ba_tsr_tbl == tx_tbl_ptr)
+			return true;
+	}
+
+	return false;
+}
+
+/*
+ * This function deletes the given entry in Tx BA Stream table.
+ *
+ * The function also performs a validity check on the supplied
+ * pointer before trying to delete.
+ */
+void mwifiex_11n_delete_tx_ba_stream_tbl_entry(struct mwifiex_private *priv,
+				struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl)
+{
+	if (!tx_ba_tsr_tbl &&
+			mwifiex_is_tx_ba_stream_ptr_valid(priv, tx_ba_tsr_tbl))
+		return;
+
+	dev_dbg(priv->adapter->dev, "info: tx_ba_tsr_tbl %p\n", tx_ba_tsr_tbl);
+
+	list_del(&tx_ba_tsr_tbl->list);
+
+	kfree(tx_ba_tsr_tbl);
+
+	return;
+}
+
+/*
+ * This function deletes all the entries in Tx BA Stream table.
+ */
+void mwifiex_11n_delete_all_tx_ba_stream_tbl(struct mwifiex_private *priv)
+{
+	int i;
+	struct mwifiex_tx_ba_stream_tbl *del_tbl_ptr, *tmp_node;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
+	list_for_each_entry_safe(del_tbl_ptr, tmp_node,
+				 &priv->tx_ba_stream_tbl_ptr, list)
+		mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, del_tbl_ptr);
+	spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
+
+	INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr);
+
+	for (i = 0; i < MAX_NUM_TID; ++i)
+		priv->aggr_prio_tbl[i].ampdu_ap =
+			priv->aggr_prio_tbl[i].ampdu_user;
+}
+
+/*
+ * This function returns the pointer to an entry in BA Stream
+ * table which matches the given RA/TID pair.
+ */
+struct mwifiex_tx_ba_stream_tbl *
+mwifiex_11n_get_tx_ba_stream_tbl(struct mwifiex_private *priv,
+				 int tid, u8 *ra)
+{
+	struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
+	list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
+		if ((!memcmp(tx_ba_tsr_tbl->ra, ra, ETH_ALEN))
+		    && (tx_ba_tsr_tbl->tid == tid)) {
+			spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock,
+					       flags);
+			return tx_ba_tsr_tbl;
+		}
+	}
+	spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
+	return NULL;
+}
+
+/*
+ * This function creates an entry in Tx BA stream table for the
+ * given RA/TID pair.
+ */
+void mwifiex_11n_create_tx_ba_stream_tbl(struct mwifiex_private *priv,
+					 u8 *ra, int tid,
+					 enum mwifiex_ba_status ba_status)
+{
+	struct mwifiex_tx_ba_stream_tbl *new_node;
+	unsigned long flags;
+
+	if (!mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, ra)) {
+		new_node = kzalloc(sizeof(struct mwifiex_tx_ba_stream_tbl),
+				   GFP_ATOMIC);
+		if (!new_node) {
+			dev_err(priv->adapter->dev,
+				"%s: failed to alloc new_node\n", __func__);
+			return;
+		}
+
+		INIT_LIST_HEAD(&new_node->list);
+
+		new_node->tid = tid;
+		new_node->ba_status = ba_status;
+		memcpy(new_node->ra, ra, ETH_ALEN);
+
+		spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
+		list_add_tail(&new_node->list, &priv->tx_ba_stream_tbl_ptr);
+		spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
+	}
+
+	return;
+}
+
+/*
+ * This function sends an add BA request to the given TID/RA pair.
+ */
+int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac)
+{
+	struct host_cmd_ds_11n_addba_req add_ba_req;
+	static u8 dialog_tok;
+	int ret;
+
+	dev_dbg(priv->adapter->dev, "cmd: %s: tid %d\n", __func__, tid);
+
+	add_ba_req.block_ack_param_set = cpu_to_le16(
+		(u16) ((tid << BLOCKACKPARAM_TID_POS) |
+			 (priv->add_ba_param.
+			  tx_win_size << BLOCKACKPARAM_WINSIZE_POS) |
+			 IMMEDIATE_BLOCK_ACK));
+	add_ba_req.block_ack_tmo = cpu_to_le16((u16)priv->add_ba_param.timeout);
+
+	++dialog_tok;
+
+	if (dialog_tok == 0)
+		dialog_tok = 1;
+
+	add_ba_req.dialog_token = dialog_tok;
+	memcpy(&add_ba_req.peer_mac_addr, peer_mac, ETH_ALEN);
+
+	/* We don't wait for the response of this command */
+	ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_11N_ADDBA_REQ,
+				  0, 0, NULL, &add_ba_req);
+
+	return ret;
+}
+
+/*
+ * This function sends a delete BA request to the given TID/RA pair.
+ */
+int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac,
+		       int initiator)
+{
+	struct host_cmd_ds_11n_delba delba;
+	int ret;
+	uint16_t del_ba_param_set;
+
+	memset(&delba, 0, sizeof(delba));
+	delba.del_ba_param_set = cpu_to_le16(tid << DELBA_TID_POS);
+
+	del_ba_param_set = le16_to_cpu(delba.del_ba_param_set);
+	if (initiator)
+		del_ba_param_set |= IEEE80211_DELBA_PARAM_INITIATOR_MASK;
+	else
+		del_ba_param_set &= ~IEEE80211_DELBA_PARAM_INITIATOR_MASK;
+
+	memcpy(&delba.peer_mac_addr, peer_mac, ETH_ALEN);
+
+	/* We don't wait for the response of this command */
+	ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_11N_DELBA,
+				  HostCmd_ACT_GEN_SET, 0, NULL, &delba);
+
+	return ret;
+}
+
+/*
+ * This function handles the command response of a delete BA request.
+ */
+void mwifiex_11n_delete_ba_stream(struct mwifiex_private *priv, u8 *del_ba)
+{
+	struct host_cmd_ds_11n_delba *cmd_del_ba =
+		(struct host_cmd_ds_11n_delba *) del_ba;
+	uint16_t del_ba_param_set = le16_to_cpu(cmd_del_ba->del_ba_param_set);
+	int tid;
+
+	tid = del_ba_param_set >> DELBA_TID_POS;
+
+	mwifiex_11n_delete_ba_stream_tbl(priv, tid, cmd_del_ba->peer_mac_addr,
+					 TYPE_DELBA_RECEIVE,
+					 INITIATOR_BIT(del_ba_param_set));
+}
+
+/*
+ * This function retrieves the Rx reordering table.
+ */
+int mwifiex_get_rx_reorder_tbl(struct mwifiex_private *priv,
+			       struct mwifiex_ds_rx_reorder_tbl *buf)
+{
+	int i;
+	struct mwifiex_ds_rx_reorder_tbl *rx_reo_tbl = buf;
+	struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr;
+	int count = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
+	list_for_each_entry(rx_reorder_tbl_ptr, &priv->rx_reorder_tbl_ptr,
+			    list) {
+		rx_reo_tbl->tid = (u16) rx_reorder_tbl_ptr->tid;
+		memcpy(rx_reo_tbl->ta, rx_reorder_tbl_ptr->ta, ETH_ALEN);
+		rx_reo_tbl->start_win = rx_reorder_tbl_ptr->start_win;
+		rx_reo_tbl->win_size = rx_reorder_tbl_ptr->win_size;
+		for (i = 0; i < rx_reorder_tbl_ptr->win_size; ++i) {
+			if (rx_reorder_tbl_ptr->rx_reorder_ptr[i])
+				rx_reo_tbl->buffer[i] = true;
+			else
+				rx_reo_tbl->buffer[i] = false;
+		}
+		rx_reo_tbl++;
+		count++;
+
+		if (count >= MWIFIEX_MAX_RX_BASTREAM_SUPPORTED)
+			break;
+	}
+	spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
+
+	return count;
+}
+
+/*
+ * This function retrieves the Tx BA stream table.
+ */
+int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv,
+				 struct mwifiex_ds_tx_ba_stream_tbl *buf)
+{
+	struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
+	struct mwifiex_ds_tx_ba_stream_tbl *rx_reo_tbl = buf;
+	int count = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
+	list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
+		rx_reo_tbl->tid = (u16) tx_ba_tsr_tbl->tid;
+		dev_dbg(priv->adapter->dev, "data: %s tid=%d\n",
+						__func__, rx_reo_tbl->tid);
+		memcpy(rx_reo_tbl->ra, tx_ba_tsr_tbl->ra, ETH_ALEN);
+		rx_reo_tbl++;
+		count++;
+		if (count >= MWIFIEX_MAX_TX_BASTREAM_SUPPORTED)
+			break;
+	}
+	spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
+
+	return count;
+}
diff --git a/drivers/net/wireless/mwifiex/11n.h b/drivers/net/wireless/mwifiex/11n.h
new file mode 100644
index 0000000..71a853e
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/11n.h
@@ -0,0 +1,176 @@
+/*
+ * Marvell Wireless LAN device driver: 802.11n
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#ifndef _MWIFIEX_11N_H_
+#define _MWIFIEX_11N_H_
+
+#include "11n_aggr.h"
+#include "11n_rxreorder.h"
+#include "wmm.h"
+
+int mwifiex_ret_11n_delba(struct mwifiex_private *priv,
+			  struct host_cmd_ds_command *resp);
+int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv,
+			      struct host_cmd_ds_command *resp);
+int mwifiex_ret_11n_cfg(struct mwifiex_private *priv,
+			struct host_cmd_ds_command *resp,
+			void *data_buf);
+int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv,
+			struct host_cmd_ds_command *cmd,
+			u16 cmd_action, void *data_buf);
+
+int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv,
+			struct host_cmd_ds_command *cmd,
+			u16 cmd_action, void *data_buf);
+
+int mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
+			       struct mwifiex_bssdescriptor *bss_desc,
+			       u8 **buffer);
+void mwifiex_cfg_tx_buf(struct mwifiex_private *priv,
+			struct mwifiex_bssdescriptor *bss_desc);
+void mwifiex_fill_cap_info(struct mwifiex_private *,
+			   struct mwifiex_ie_types_htcap *);
+int mwifiex_set_get_11n_htcap_cfg(struct mwifiex_private *priv,
+				  u16 action, int *htcap_cfg);
+void mwifiex_11n_delete_tx_ba_stream_tbl_entry(struct mwifiex_private *priv,
+					     struct mwifiex_tx_ba_stream_tbl
+					     *tx_tbl);
+void mwifiex_11n_delete_all_tx_ba_stream_tbl(struct mwifiex_private *priv);
+struct mwifiex_tx_ba_stream_tbl *mwifiex_11n_get_tx_ba_stream_tbl(struct
+							     mwifiex_private
+							     *priv, int tid,
+							     u8 *ra);
+void mwifiex_11n_create_tx_ba_stream_tbl(struct mwifiex_private *priv, u8 *ra,
+				       int tid,
+				       enum mwifiex_ba_status ba_status);
+int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac);
+int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac,
+		       int initiator);
+void mwifiex_11n_delete_ba_stream(struct mwifiex_private *priv, u8 *del_ba);
+int mwifiex_get_rx_reorder_tbl(struct mwifiex_private *priv,
+			      struct mwifiex_ds_rx_reorder_tbl *buf);
+int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv,
+			       struct mwifiex_ds_tx_ba_stream_tbl *buf);
+int mwifiex_ret_amsdu_aggr_ctrl(struct mwifiex_private *priv,
+				struct host_cmd_ds_command
+				*resp,
+				void *data_buf);
+int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv,
+			     struct host_cmd_ds_command *cmd,
+			     int cmd_action, void *data_buf);
+int mwifiex_cmd_amsdu_aggr_ctrl(struct mwifiex_private *priv,
+				struct host_cmd_ds_command *cmd,
+				int cmd_action,
+				void *data_buf);
+
+/*
+ * This function checks whether AMPDU is allowed or not for a particular TID.
+ */
+static inline u8
+mwifiex_is_ampdu_allowed(struct mwifiex_private *priv,
+			 struct mwifiex_ra_list_tbl *ptr, int tid)
+{
+	return ((priv->aggr_prio_tbl[tid].ampdu_ap != BA_STREAM_NOT_ALLOWED)
+		? true : false);
+}
+
+/*
+ * This function checks whether AMSDU is allowed or not for a particular TID.
+ */
+static inline u8
+mwifiex_is_amsdu_allowed(struct mwifiex_private *priv,
+			 struct mwifiex_ra_list_tbl *ptr, int tid)
+{
+	return (((priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED)
+			&& ((priv->is_data_rate_auto)
+			|| !((priv->bitmap_rates[2]) & 0x03)))
+		? true : false);
+}
+
+/*
+ * This function checks whether a BA stream is available or not.
+ */
+static inline u8
+mwifiex_is_ba_stream_avail(struct mwifiex_private *priv)
+{
+	struct mwifiex_private *pmpriv = NULL;
+	u8 i = 0;
+	u32 ba_stream_num = 0;
+
+	for (i = 0; i < priv->adapter->priv_num; i++) {
+		pmpriv = priv->adapter->priv[i];
+		if (pmpriv)
+			ba_stream_num +=
+				mwifiex_wmm_list_len(priv->adapter,
+						     (struct list_head
+						      *) &pmpriv->
+						     tx_ba_stream_tbl_ptr);
+	}
+
+	return ((ba_stream_num <
+		 MWIFIEX_MAX_TX_BASTREAM_SUPPORTED) ? true : false);
+}
+
+/*
+ * This function finds the correct Tx BA stream to delete.
+ *
+ * Upon successfully locating, both the TID and the RA are returned.
+ */
+static inline u8
+mwifiex_find_stream_to_delete(struct mwifiex_private *priv,
+			      struct mwifiex_ra_list_tbl *ptr, int ptr_tid,
+			      int *ptid, u8 *ra)
+{
+	int tid;
+	u8 ret = false;
+	struct mwifiex_tx_ba_stream_tbl *tx_tbl;
+	unsigned long flags;
+
+	tid = priv->aggr_prio_tbl[ptr_tid].ampdu_user;
+
+	spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
+	list_for_each_entry(tx_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
+		if (tid > priv->aggr_prio_tbl[tx_tbl->tid].ampdu_user) {
+			tid = priv->aggr_prio_tbl[tx_tbl->tid].ampdu_user;
+			*ptid = tx_tbl->tid;
+			memcpy(ra, tx_tbl->ra, ETH_ALEN);
+			ret = true;
+		}
+	}
+	spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
+
+	return ret;
+}
+
+/*
+ * This function checks whether BA stream is set up or not.
+ */
+static inline int
+mwifiex_is_ba_stream_setup(struct mwifiex_private *priv,
+			  struct mwifiex_ra_list_tbl *ptr, int tid)
+{
+	struct mwifiex_tx_ba_stream_tbl *tx_tbl;
+
+	tx_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, ptr->ra);
+	if (tx_tbl && IS_BASTREAM_SETUP(tx_tbl))
+		return true;
+
+	return false;
+}
+#endif /* !_MWIFIEX_11N_H_ */
diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c
new file mode 100644
index 0000000..c2abced
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/11n_aggr.c
@@ -0,0 +1,423 @@
+/*
+ * Marvell Wireless LAN device driver: 802.11n Aggregation
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+#include "11n.h"
+#include "11n_aggr.h"
+
+/*
+ * Creates an AMSDU subframe for aggregation into one AMSDU packet.
+ *
+ * The resultant AMSDU subframe format is -
+ *
+ * +---- ~ -----+---- ~ ------+---- ~ -----+----- ~ -----+---- ~ -----+
+ * |     DA     |     SA      |   Length   | SNAP header |   MSDU     |
+ * | data[0..5] | data[6..11] |            |             | data[14..] |
+ * +---- ~ -----+---- ~ ------+---- ~ -----+----- ~ -----+---- ~ -----+
+ * <--6-bytes--> <--6-bytes--> <--2-bytes--><--8-bytes--> <--n-bytes-->
+ *
+ * This function also computes the amount of padding required to make the
+ * buffer length multiple of 4 bytes.
+ *
+ * Data => |DA|SA|SNAP-TYPE|........    .|
+ * MSDU => |DA|SA|Length|SNAP|......   ..|
+ */
+static int
+mwifiex_11n_form_amsdu_pkt(struct mwifiex_adapter *adapter,
+			   struct sk_buff *skb_aggr,
+			   struct sk_buff *skb_src, int *pad)
+
+{
+	int dt_offset;
+	struct rfc_1042_hdr snap = {
+		0xaa,		/* LLC DSAP */
+		0xaa,		/* LLC SSAP */
+		0x03,		/* LLC CTRL */
+		{0x00, 0x00, 0x00},	/* SNAP OUI */
+		0x0000		/* SNAP type */
+			/*
+			 * This field will be overwritten
+			 * later with ethertype
+			 */
+	};
+	struct tx_packet_hdr *tx_header = NULL;
+
+	skb_put(skb_aggr, sizeof(*tx_header));
+
+	tx_header = (struct tx_packet_hdr *) skb_aggr->data;
+
+	/* Copy DA and SA */
+	dt_offset = 2 * ETH_ALEN;
+	memcpy(&tx_header->eth803_hdr, skb_src->data, dt_offset);
+
+	/* Copy SNAP header */
+	snap.snap_type = *(u16 *) ((u8 *)skb_src->data + dt_offset);
+	dt_offset += sizeof(u16);
+
+	memcpy(&tx_header->rfc1042_hdr, &snap, sizeof(struct rfc_1042_hdr));
+
+	skb_pull(skb_src, dt_offset);
+
+	/* Update Length field */
+	tx_header->eth803_hdr.h_proto = htons(skb_src->len + LLC_SNAP_LEN);
+
+	/* Add payload */
+	skb_put(skb_aggr, skb_src->len);
+	memcpy(skb_aggr->data + sizeof(*tx_header), skb_src->data,
+							skb_src->len);
+	*pad = (((skb_src->len + LLC_SNAP_LEN) & 3)) ? (4 - (((skb_src->len +
+						      LLC_SNAP_LEN)) & 3)) : 0;
+	skb_put(skb_aggr, *pad);
+
+	return skb_aggr->len + *pad;
+}
+
+/*
+ * Adds TxPD to AMSDU header.
+ *
+ * Each AMSDU packet will contain one TxPD at the beginning,
+ * followed by multiple AMSDU subframes.
+ */
+static void
+mwifiex_11n_form_amsdu_txpd(struct mwifiex_private *priv,
+			    struct sk_buff *skb)
+{
+	struct txpd *local_tx_pd;
+
+	skb_push(skb, sizeof(*local_tx_pd));
+
+	local_tx_pd = (struct txpd *) skb->data;
+	memset(local_tx_pd, 0, sizeof(struct txpd));
+
+	/* Original priority has been overwritten */
+	local_tx_pd->priority = (u8) skb->priority;
+	local_tx_pd->pkt_delay_2ms =
+		mwifiex_wmm_compute_drv_pkt_delay(priv, skb);
+	local_tx_pd->bss_num = priv->bss_num;
+	local_tx_pd->bss_type = priv->bss_type;
+	/* Always zero as the data is followed by struct txpd */
+	local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd));
+	local_tx_pd->tx_pkt_type = cpu_to_le16(PKT_TYPE_AMSDU);
+	local_tx_pd->tx_pkt_length = cpu_to_le16(skb->len -
+			sizeof(*local_tx_pd));
+
+	if (local_tx_pd->tx_control == 0)
+		/* TxCtrl set by user or default */
+		local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl);
+
+	if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
+		(priv->adapter->pps_uapsd_mode)) {
+		if (true == mwifiex_check_last_packet_indication(priv)) {
+			priv->adapter->tx_lock_flag = true;
+			local_tx_pd->flags =
+				MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET;
+		}
+	}
+}
+
+/*
+ * Counts the number of subframes in an aggregate packet.
+ *
+ * This function parses an aggregate packet buffer, looking for
+ * subframes and counting the number of such subframe found. The
+ * function automatically skips the DA/SA fields at the beginning
+ * of each subframe and padding at the end.
+ */
+static int
+mwifiex_11n_get_num_aggr_pkts(u8 *data, int total_pkt_len)
+{
+	int pkt_count = 0, pkt_len, pad;
+
+	while (total_pkt_len > 0) {
+		/* Length will be in network format, change it to host */
+		pkt_len = ntohs((*(__be16 *)(data + 2 * ETH_ALEN)));
+		pad = (((pkt_len + sizeof(struct ethhdr)) & 3)) ?
+			(4 - ((pkt_len + sizeof(struct ethhdr)) & 3)) : 0;
+		data += pkt_len + pad + sizeof(struct ethhdr);
+		total_pkt_len -= pkt_len + pad + sizeof(struct ethhdr);
+		++pkt_count;
+	}
+
+	return pkt_count;
+}
+
+/*
+ * De-aggregate received packets.
+ *
+ * This function parses the received aggregate buffer, extracts each subframe,
+ * strips off the SNAP header from them and sends the data portion for further
+ * processing.
+ *
+ * Each subframe body is copied onto a separate buffer, which are freed by
+ * upper layer after processing. The function also performs sanity tests on
+ * the received buffer.
+ */
+int mwifiex_11n_deaggregate_pkt(struct mwifiex_private *priv,
+				struct sk_buff *skb)
+{
+	u16 pkt_len;
+	int total_pkt_len;
+	u8 *data;
+	int pad;
+	struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
+	struct rxpd *local_rx_pd = (struct rxpd *) skb->data;
+	struct sk_buff *skb_daggr;
+	struct mwifiex_rxinfo *rx_info_daggr = NULL;
+	int ret = -1;
+	struct rx_packet_hdr *rx_pkt_hdr;
+	struct mwifiex_adapter *adapter = priv->adapter;
+	u8 rfc1042_eth_hdr[ETH_ALEN] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
+
+	data = (u8 *) (local_rx_pd + local_rx_pd->rx_pkt_offset);
+	total_pkt_len = local_rx_pd->rx_pkt_length;
+
+	/* Sanity test */
+	if (total_pkt_len > MWIFIEX_RX_DATA_BUF_SIZE) {
+		dev_err(adapter->dev, "total pkt len greater than buffer"
+		       " size %d\n", total_pkt_len);
+		return -1;
+	}
+
+	rx_info->use_count = mwifiex_11n_get_num_aggr_pkts(data, total_pkt_len);
+
+	while (total_pkt_len > 0) {
+		rx_pkt_hdr = (struct rx_packet_hdr *) data;
+		/* Length will be in network format, change it to host */
+		pkt_len = ntohs((*(__be16 *) (data + 2 * ETH_ALEN)));
+		if (pkt_len > total_pkt_len) {
+			dev_err(adapter->dev, "pkt_len %d > total_pkt_len %d\n",
+			       total_pkt_len, pkt_len);
+			break;
+		}
+
+		pad = (((pkt_len + sizeof(struct ethhdr)) & 3)) ?
+			(4 - ((pkt_len + sizeof(struct ethhdr)) & 3)) : 0;
+
+		total_pkt_len -= pkt_len + pad + sizeof(struct ethhdr);
+
+		if (memcmp(&rx_pkt_hdr->rfc1042_hdr,
+			   rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) {
+			memmove(data + LLC_SNAP_LEN, data, 2 * ETH_ALEN);
+			data += LLC_SNAP_LEN;
+			pkt_len += sizeof(struct ethhdr) - LLC_SNAP_LEN;
+		} else {
+			*(u16 *) (data + 2 * ETH_ALEN) = (u16) 0;
+			pkt_len += sizeof(struct ethhdr);
+		}
+
+		skb_daggr = dev_alloc_skb(pkt_len);
+		if (!skb_daggr) {
+			dev_err(adapter->dev, "%s: failed to alloc skb_daggr\n",
+			       __func__);
+			return -1;
+		}
+		rx_info_daggr = MWIFIEX_SKB_RXCB(skb_daggr);
+
+		rx_info_daggr->bss_index = rx_info->bss_index;
+		skb_daggr->tstamp = skb->tstamp;
+		rx_info_daggr->parent = skb;
+		skb_daggr->priority = skb->priority;
+		skb_put(skb_daggr, pkt_len);
+		memcpy(skb_daggr->data, data, pkt_len);
+
+		ret = mwifiex_recv_packet(adapter, skb_daggr);
+
+		switch (ret) {
+		case -EINPROGRESS:
+			break;
+		case -1:
+			dev_err(adapter->dev, "deaggr: host_to_card failed\n");
+		case 0:
+			mwifiex_recv_packet_complete(adapter, skb_daggr, ret);
+			break;
+		default:
+			break;
+		}
+
+		data += pkt_len + pad;
+	}
+
+	return ret;
+}
+
+/*
+ * Create aggregated packet.
+ *
+ * This function creates an aggregated MSDU packet, by combining buffers
+ * from the RA list. Each individual buffer is encapsulated as an AMSDU
+ * subframe and all such subframes are concatenated together to form the
+ * AMSDU packet.
+ *
+ * A TxPD is also added to the front of the resultant AMSDU packets for
+ * transmission. The resultant packets format is -
+ *
+ * +---- ~ ----+------ ~ ------+------ ~ ------+-..-+------ ~ ------+
+ * |    TxPD   |AMSDU sub-frame|AMSDU sub-frame| .. |AMSDU sub-frame|
+ * |           |       1       |       2       | .. |       n       |
+ * +---- ~ ----+------ ~ ------+------ ~ ------+ .. +------ ~ ------+
+ */
+int
+mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
+			  struct mwifiex_ra_list_tbl *pra_list, int headroom,
+			  int ptrindex, unsigned long ra_list_flags)
+			  __releases(&priv->wmm.ra_list_spinlock)
+{
+	struct mwifiex_adapter *adapter = priv->adapter;
+	struct sk_buff *skb_aggr, *skb_src;
+	struct mwifiex_txinfo *tx_info_aggr, *tx_info_src;
+	int pad = 0;
+	int ret = 0;
+	struct mwifiex_tx_param tx_param;
+	struct txpd *ptx_pd = NULL;
+
+	if (skb_queue_empty(&pra_list->skb_head)) {
+		spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+				       ra_list_flags);
+		return 0;
+	}
+	skb_src = skb_peek(&pra_list->skb_head);
+	tx_info_src = MWIFIEX_SKB_TXCB(skb_src);
+	skb_aggr = dev_alloc_skb(adapter->tx_buf_size);
+	if (!skb_aggr) {
+		dev_err(adapter->dev, "%s: alloc skb_aggr\n", __func__);
+		spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+				       ra_list_flags);
+		return -1;
+	}
+	skb_reserve(skb_aggr, headroom + sizeof(struct txpd));
+	tx_info_aggr =  MWIFIEX_SKB_TXCB(skb_aggr);
+
+	tx_info_aggr->bss_index = tx_info_src->bss_index;
+	skb_aggr->priority = skb_src->priority;
+
+	while (skb_src && ((skb_headroom(skb_aggr) + skb_src->len
+					+ LLC_SNAP_LEN)
+				<= adapter->tx_buf_size)) {
+
+		if (!skb_queue_empty(&pra_list->skb_head))
+			skb_src = skb_dequeue(&pra_list->skb_head);
+		else
+			skb_src = NULL;
+
+		pra_list->total_pkts_size -= skb_src->len;
+
+		spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+				       ra_list_flags);
+		mwifiex_11n_form_amsdu_pkt(adapter, skb_aggr, skb_src, &pad);
+
+		mwifiex_write_data_complete(adapter, skb_src, 0);
+
+		spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
+
+		if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) {
+			spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+					       ra_list_flags);
+			return -1;
+		}
+
+		if (!skb_queue_empty(&pra_list->skb_head))
+			skb_src = skb_peek(&pra_list->skb_head);
+		else
+			skb_src = NULL;
+	}
+
+	spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags);
+
+	/* Last AMSDU packet does not need padding */
+	skb_trim(skb_aggr, skb_aggr->len - pad);
+
+	/* Form AMSDU */
+	mwifiex_11n_form_amsdu_txpd(priv, skb_aggr);
+	if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA)
+		ptx_pd = (struct txpd *)skb_aggr->data;
+
+	skb_push(skb_aggr, headroom);
+
+	tx_param.next_pkt_len = ((pra_list->total_pkts_size) ?
+				 (((pra_list->total_pkts_size) >
+				   adapter->tx_buf_size) ? adapter->
+				  tx_buf_size : pra_list->total_pkts_size +
+				  LLC_SNAP_LEN + sizeof(struct txpd)) : 0);
+	ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
+					     skb_aggr->data,
+					     skb_aggr->len, &tx_param);
+	switch (ret) {
+	case -EBUSY:
+		spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
+		if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) {
+			spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+					       ra_list_flags);
+			mwifiex_write_data_complete(adapter, skb_aggr, -1);
+			return -1;
+		}
+		if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
+			(adapter->pps_uapsd_mode) &&
+			(adapter->tx_lock_flag)) {
+				priv->adapter->tx_lock_flag = false;
+				ptx_pd->flags = 0;
+		}
+
+		skb_queue_tail(&pra_list->skb_head, skb_aggr);
+
+		pra_list->total_pkts_size += skb_aggr->len;
+
+		tx_info_aggr->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT;
+		spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+				       ra_list_flags);
+		dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
+		break;
+	case -1:
+		adapter->data_sent = false;
+		dev_err(adapter->dev, "%s: host_to_card failed: %#x\n",
+						__func__, ret);
+		adapter->dbg.num_tx_host_to_card_failure++;
+		mwifiex_write_data_complete(adapter, skb_aggr, ret);
+		return 0;
+	case -EINPROGRESS:
+		adapter->data_sent = false;
+		break;
+	case 0:
+		mwifiex_write_data_complete(adapter, skb_aggr, ret);
+		break;
+	default:
+		break;
+	}
+	if (ret != -EBUSY) {
+		spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
+		if (mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) {
+			priv->wmm.packets_out[ptrindex]++;
+			priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr = pra_list;
+		}
+		/* Now bss_prio_cur pointer points to next node */
+		adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur =
+			list_first_entry(
+				&adapter->bss_prio_tbl[priv->bss_priority]
+				.bss_prio_cur->list,
+				struct mwifiex_bss_prio_node, list);
+		spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+				       ra_list_flags);
+	}
+
+	return 0;
+}
diff --git a/drivers/net/wireless/mwifiex/11n_aggr.h b/drivers/net/wireless/mwifiex/11n_aggr.h
new file mode 100644
index 0000000..9c6dca7
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/11n_aggr.h
@@ -0,0 +1,32 @@
+/*
+ * Marvell Wireless LAN device driver: 802.11n Aggregation
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#ifndef _MWIFIEX_11N_AGGR_H_
+#define _MWIFIEX_11N_AGGR_H_
+
+#define PKT_TYPE_AMSDU	0xE6
+
+int mwifiex_11n_deaggregate_pkt(struct mwifiex_private *priv,
+				struct sk_buff *skb);
+int mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
+			      struct mwifiex_ra_list_tbl *ptr, int headroom,
+			      int ptr_index, unsigned long flags)
+			      __releases(&priv->wmm.ra_list_spinlock);
+
+#endif /* !_MWIFIEX_11N_AGGR_H_ */
diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c
new file mode 100644
index 0000000..8e94e62
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c
@@ -0,0 +1,637 @@
+/*
+ * Marvell Wireless LAN device driver: 802.11n RX Re-ordering
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+#include "11n.h"
+#include "11n_rxreorder.h"
+
+/*
+ * This function processes a received packet and forwards
+ * it to the kernel/upper layer.
+ */
+static int mwifiex_11n_dispatch_pkt(struct mwifiex_private *priv, void *payload)
+{
+	int ret = 0;
+	struct mwifiex_adapter *adapter = priv->adapter;
+
+	ret = mwifiex_process_rx_packet(adapter, (struct sk_buff *) payload);
+	return ret;
+}
+
+/*
+ * This function dispatches all packets in the Rx reorder table.
+ *
+ * There could be holes in the buffer, which are skipped by the function.
+ * Since the buffer is linear, the function uses rotation to simulate
+ * circular buffer.
+ */
+static int
+mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv,
+					 struct mwifiex_rx_reorder_tbl
+					 *rx_reor_tbl_ptr, int start_win)
+{
+	int no_pkt_to_send, i, xchg;
+	void *rx_tmp_ptr = NULL;
+	unsigned long flags;
+
+	no_pkt_to_send = (start_win > rx_reor_tbl_ptr->start_win) ?
+		min((start_win - rx_reor_tbl_ptr->start_win),
+		    rx_reor_tbl_ptr->win_size) : rx_reor_tbl_ptr->win_size;
+
+	for (i = 0; i < no_pkt_to_send; ++i) {
+		spin_lock_irqsave(&priv->rx_pkt_lock, flags);
+		rx_tmp_ptr = NULL;
+		if (rx_reor_tbl_ptr->rx_reorder_ptr[i]) {
+			rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i];
+			rx_reor_tbl_ptr->rx_reorder_ptr[i] = NULL;
+		}
+		spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
+		if (rx_tmp_ptr)
+			mwifiex_11n_dispatch_pkt(priv, rx_tmp_ptr);
+	}
+
+	spin_lock_irqsave(&priv->rx_pkt_lock, flags);
+	/*
+	 * We don't have a circular buffer, hence use rotation to simulate
+	 * circular buffer
+	 */
+	xchg = rx_reor_tbl_ptr->win_size - no_pkt_to_send;
+	for (i = 0; i < xchg; ++i) {
+		rx_reor_tbl_ptr->rx_reorder_ptr[i] =
+			rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i];
+		rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i] = NULL;
+	}
+
+	rx_reor_tbl_ptr->start_win = start_win;
+	spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
+
+	return 0;
+}
+
+/*
+ * This function dispatches all packets in the Rx reorder table until
+ * a hole is found.
+ *
+ * The start window is adjusted automatically when a hole is located.
+ * Since the buffer is linear, the function uses rotation to simulate
+ * circular buffer.
+ */
+static int
+mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv,
+			      struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr)
+{
+	int i, j, xchg;
+	void *rx_tmp_ptr = NULL;
+	unsigned long flags;
+
+	for (i = 0; i < rx_reor_tbl_ptr->win_size; ++i) {
+		spin_lock_irqsave(&priv->rx_pkt_lock, flags);
+		if (!rx_reor_tbl_ptr->rx_reorder_ptr[i]) {
+			spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
+			break;
+		}
+		rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i];
+		rx_reor_tbl_ptr->rx_reorder_ptr[i] = NULL;
+		spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
+		mwifiex_11n_dispatch_pkt(priv, rx_tmp_ptr);
+	}
+
+	spin_lock_irqsave(&priv->rx_pkt_lock, flags);
+	/*
+	 * We don't have a circular buffer, hence use rotation to simulate
+	 * circular buffer
+	 */
+	if (i > 0) {
+		xchg = rx_reor_tbl_ptr->win_size - i;
+		for (j = 0; j < xchg; ++j) {
+			rx_reor_tbl_ptr->rx_reorder_ptr[j] =
+				rx_reor_tbl_ptr->rx_reorder_ptr[i + j];
+			rx_reor_tbl_ptr->rx_reorder_ptr[i + j] = NULL;
+		}
+	}
+	rx_reor_tbl_ptr->start_win = (rx_reor_tbl_ptr->start_win + i)
+		&(MAX_TID_VALUE - 1);
+	spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
+	return 0;
+}
+
+/*
+ * This function deletes the Rx reorder table and frees the memory.
+ *
+ * The function stops the associated timer and dispatches all the
+ * pending packets in the Rx reorder table before deletion.
+ */
+static void
+mwifiex_11n_delete_rx_reorder_tbl_entry(struct mwifiex_private *priv,
+				       struct mwifiex_rx_reorder_tbl
+				       *rx_reor_tbl_ptr)
+{
+	unsigned long flags;
+
+	if (!rx_reor_tbl_ptr)
+		return;
+
+	mwifiex_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr,
+						 (rx_reor_tbl_ptr->start_win +
+						  rx_reor_tbl_ptr->win_size)
+						 &(MAX_TID_VALUE - 1));
+
+	del_timer(&rx_reor_tbl_ptr->timer_context.timer);
+
+	spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
+	list_del(&rx_reor_tbl_ptr->list);
+	spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
+
+	kfree(rx_reor_tbl_ptr->rx_reorder_ptr);
+	kfree(rx_reor_tbl_ptr);
+}
+
+/*
+ * This function returns the pointer to an entry in Rx reordering
+ * table which matches the given TA/TID pair.
+ */
+static struct mwifiex_rx_reorder_tbl *
+mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta)
+{
+	struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
+	list_for_each_entry(rx_reor_tbl_ptr, &priv->rx_reorder_tbl_ptr, list) {
+		if ((!memcmp(rx_reor_tbl_ptr->ta, ta, ETH_ALEN))
+		    && (rx_reor_tbl_ptr->tid == tid)) {
+			spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock,
+					       flags);
+			return rx_reor_tbl_ptr;
+		}
+	}
+	spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
+
+	return NULL;
+}
+
+/*
+ * This function finds the last sequence number used in the packets
+ * buffered in Rx reordering table.
+ */
+static int
+mwifiex_11n_find_last_seq_num(struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr)
+{
+	int i;
+
+	for (i = (rx_reorder_tbl_ptr->win_size - 1); i >= 0; --i)
+		if (rx_reorder_tbl_ptr->rx_reorder_ptr[i])
+			return i;
+
+	return -1;
+}
+
+/*
+ * This function flushes all the packets in Rx reordering table.
+ *
+ * The function checks if any packets are currently buffered in the
+ * table or not. In case there are packets available, it dispatches
+ * them and then dumps the Rx reordering table.
+ */
+static void
+mwifiex_flush_data(unsigned long context)
+{
+	struct reorder_tmr_cnxt *reorder_cnxt =
+		(struct reorder_tmr_cnxt *) context;
+	int start_win;
+
+	start_win = mwifiex_11n_find_last_seq_num(reorder_cnxt->ptr);
+	if (start_win >= 0) {
+		dev_dbg(reorder_cnxt->priv->adapter->dev,
+				"info: flush data %d\n", start_win);
+		mwifiex_11n_dispatch_pkt_until_start_win(reorder_cnxt->priv,
+				reorder_cnxt->ptr,
+				((reorder_cnxt->ptr->start_win +
+				  start_win + 1) & (MAX_TID_VALUE - 1)));
+	}
+}
+
+/*
+ * This function creates an entry in Rx reordering table for the
+ * given TA/TID.
+ *
+ * The function also initializes the entry with sequence number, window
+ * size as well as initializes the timer.
+ *
+ * If the received TA/TID pair is already present, all the packets are
+ * dispatched and the window size is moved until the SSN.
+ */
+static void
+mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
+				 int tid, int win_size, int seq_num)
+{
+	int i;
+	struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr, *new_node;
+	u16 last_seq = 0;
+	unsigned long flags;
+
+	/*
+	 * If we get a TID, ta pair which is already present dispatch all the
+	 * the packets and move the window size until the ssn
+	 */
+	rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta);
+	if (rx_reor_tbl_ptr) {
+		mwifiex_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr,
+							 seq_num);
+		return;
+	}
+	/* if !rx_reor_tbl_ptr then create one */
+	new_node = kzalloc(sizeof(struct mwifiex_rx_reorder_tbl), GFP_KERNEL);
+	if (!new_node) {
+		dev_err(priv->adapter->dev, "%s: failed to alloc new_node\n",
+		       __func__);
+		return;
+	}
+
+	INIT_LIST_HEAD(&new_node->list);
+	new_node->tid = tid;
+	memcpy(new_node->ta, ta, ETH_ALEN);
+	new_node->start_win = seq_num;
+	if (mwifiex_queuing_ra_based(priv))
+		/* TODO for adhoc */
+		dev_dbg(priv->adapter->dev,
+			"info: ADHOC:last_seq=%d start_win=%d\n",
+			last_seq, new_node->start_win);
+	else
+		last_seq = priv->rx_seq[tid];
+
+	if (last_seq >= new_node->start_win)
+		new_node->start_win = last_seq + 1;
+
+	new_node->win_size = win_size;
+
+	new_node->rx_reorder_ptr = kzalloc(sizeof(void *) * win_size,
+					GFP_KERNEL);
+	if (!new_node->rx_reorder_ptr) {
+		kfree((u8 *) new_node);
+		dev_err(priv->adapter->dev,
+			"%s: failed to alloc reorder_ptr\n", __func__);
+		return;
+	}
+
+	new_node->timer_context.ptr = new_node;
+	new_node->timer_context.priv = priv;
+
+	init_timer(&new_node->timer_context.timer);
+	new_node->timer_context.timer.function = mwifiex_flush_data;
+	new_node->timer_context.timer.data =
+			(unsigned long) &new_node->timer_context;
+
+	for (i = 0; i < win_size; ++i)
+		new_node->rx_reorder_ptr[i] = NULL;
+
+	spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
+	list_add_tail(&new_node->list, &priv->rx_reorder_tbl_ptr);
+	spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
+
+	return;
+}
+
+/*
+ * This function prepares command for adding a BA request.
+ *
+ * Preparation includes -
+ *      - Setting command ID and proper size
+ *      - Setting add BA request buffer
+ *      - Ensuring correct endian-ness
+ */
+int mwifiex_cmd_11n_addba_req(struct mwifiex_private *priv,
+			      struct host_cmd_ds_command *cmd, void *data_buf)
+{
+	struct host_cmd_ds_11n_addba_req *add_ba_req =
+		(struct host_cmd_ds_11n_addba_req *)
+		&cmd->params.add_ba_req;
+
+	cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_REQ);
+	cmd->size = cpu_to_le16(sizeof(*add_ba_req) + S_DS_GEN);
+	memcpy(add_ba_req, data_buf, sizeof(*add_ba_req));
+
+	return 0;
+}
+
+/*
+ * This function prepares command for adding a BA response.
+ *
+ * Preparation includes -
+ *      - Setting command ID and proper size
+ *      - Setting add BA response buffer
+ *      - Ensuring correct endian-ness
+ */
+int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv,
+				  struct host_cmd_ds_command *cmd,
+				  void *data_buf)
+{
+	struct host_cmd_ds_11n_addba_rsp *add_ba_rsp =
+		(struct host_cmd_ds_11n_addba_rsp *)
+		&cmd->params.add_ba_rsp;
+	struct host_cmd_ds_11n_addba_req *cmd_addba_req =
+		(struct host_cmd_ds_11n_addba_req *) data_buf;
+	u8 tid = 0;
+	int win_size = 0;
+	uint16_t block_ack_param_set;
+
+	cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_RSP);
+	cmd->size = cpu_to_le16(sizeof(*add_ba_rsp) + S_DS_GEN);
+
+	memcpy(add_ba_rsp->peer_mac_addr, cmd_addba_req->peer_mac_addr,
+	       ETH_ALEN);
+	add_ba_rsp->dialog_token = cmd_addba_req->dialog_token;
+	add_ba_rsp->block_ack_tmo = cmd_addba_req->block_ack_tmo;
+	add_ba_rsp->ssn = cmd_addba_req->ssn;
+
+	block_ack_param_set = le16_to_cpu(cmd_addba_req->block_ack_param_set);
+	tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK)
+		>> BLOCKACKPARAM_TID_POS;
+	add_ba_rsp->status_code = cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT);
+	block_ack_param_set &= ~IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK;
+	/* We donot support AMSDU inside AMPDU, hence reset the bit */
+	block_ack_param_set &= ~BLOCKACKPARAM_AMSDU_SUPP_MASK;
+	block_ack_param_set |= (priv->add_ba_param.rx_win_size <<
+					     BLOCKACKPARAM_WINSIZE_POS);
+	add_ba_rsp->block_ack_param_set = cpu_to_le16(block_ack_param_set);
+	win_size = (le16_to_cpu(add_ba_rsp->block_ack_param_set)
+					& IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK)
+					>> BLOCKACKPARAM_WINSIZE_POS;
+	cmd_addba_req->block_ack_param_set = cpu_to_le16(block_ack_param_set);
+
+	mwifiex_11n_create_rx_reorder_tbl(priv, cmd_addba_req->peer_mac_addr,
+			    tid, win_size, le16_to_cpu(cmd_addba_req->ssn));
+	return 0;
+}
+
+/*
+ * This function prepares command for deleting a BA request.
+ *
+ * Preparation includes -
+ *      - Setting command ID and proper size
+ *      - Setting del BA request buffer
+ *      - Ensuring correct endian-ness
+ */
+int mwifiex_cmd_11n_delba(struct mwifiex_private *priv,
+			  struct host_cmd_ds_command *cmd, void *data_buf)
+{
+	struct host_cmd_ds_11n_delba *del_ba = (struct host_cmd_ds_11n_delba *)
+		&cmd->params.del_ba;
+
+	cmd->command = cpu_to_le16(HostCmd_CMD_11N_DELBA);
+	cmd->size = cpu_to_le16(sizeof(*del_ba) + S_DS_GEN);
+	memcpy(del_ba, data_buf, sizeof(*del_ba));
+
+	return 0;
+}
+
+/*
+ * This function identifies if Rx reordering is needed for a received packet.
+ *
+ * In case reordering is required, the function will do the reordering
+ * before sending it to kernel.
+ *
+ * The Rx reorder table is checked first with the received TID/TA pair. If
+ * not found, the received packet is dispatched immediately. But if found,
+ * the packet is reordered and all the packets in the updated Rx reordering
+ * table is dispatched until a hole is found.
+ *
+ * For sequence number less than the starting window, the packet is dropped.
+ */
+int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
+				u16 seq_num, u16 tid,
+				u8 *ta, u8 pkt_type, void *payload)
+{
+	struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
+	int start_win, end_win, win_size;
+	int ret = 0;
+	u16 pkt_index = 0;
+
+	rx_reor_tbl_ptr =
+		mwifiex_11n_get_rx_reorder_tbl((struct mwifiex_private *) priv,
+						tid, ta);
+	if (!rx_reor_tbl_ptr) {
+		if (pkt_type != PKT_TYPE_BAR)
+			mwifiex_11n_dispatch_pkt(priv, payload);
+		return 0;
+	}
+	start_win = rx_reor_tbl_ptr->start_win;
+	win_size = rx_reor_tbl_ptr->win_size;
+	end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
+	del_timer(&rx_reor_tbl_ptr->timer_context.timer);
+	mod_timer(&rx_reor_tbl_ptr->timer_context.timer, jiffies
+			+ (MIN_FLUSH_TIMER_MS * win_size * HZ) / 1000);
+
+	/*
+	 * If seq_num is less then starting win then ignore and drop the
+	 * packet
+	 */
+	if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) {/* Wrap */
+		if (seq_num >= ((start_win + (TWOPOW11)) & (MAX_TID_VALUE - 1))
+				&& (seq_num < start_win))
+			return -1;
+	} else if ((seq_num < start_win)
+			|| (seq_num > (start_win + (TWOPOW11)))) {
+		return -1;
+	}
+
+	/*
+	 * If this packet is a BAR we adjust seq_num as
+	 * WinStart = seq_num
+	 */
+	if (pkt_type == PKT_TYPE_BAR)
+		seq_num = ((seq_num + win_size) - 1) & (MAX_TID_VALUE - 1);
+
+	if (((end_win < start_win)
+	     && (seq_num < (TWOPOW11 - (MAX_TID_VALUE - start_win)))
+	     && (seq_num > end_win)) || ((end_win > start_win)
+	     && ((seq_num > end_win) || (seq_num < start_win)))) {
+		end_win = seq_num;
+		if (((seq_num - win_size) + 1) >= 0)
+			start_win = (end_win - win_size) + 1;
+		else
+			start_win = (MAX_TID_VALUE - (win_size - seq_num)) + 1;
+		ret = mwifiex_11n_dispatch_pkt_until_start_win(priv,
+						rx_reor_tbl_ptr, start_win);
+
+		if (ret)
+			return ret;
+	}
+
+	if (pkt_type != PKT_TYPE_BAR) {
+		if (seq_num >= start_win)
+			pkt_index = seq_num - start_win;
+		else
+			pkt_index = (seq_num+MAX_TID_VALUE) - start_win;
+
+		if (rx_reor_tbl_ptr->rx_reorder_ptr[pkt_index])
+			return -1;
+
+		rx_reor_tbl_ptr->rx_reorder_ptr[pkt_index] = payload;
+	}
+
+	/*
+	 * Dispatch all packets sequentially from start_win until a
+	 * hole is found and adjust the start_win appropriately
+	 */
+	ret = mwifiex_11n_scan_and_dispatch(priv, rx_reor_tbl_ptr);
+
+	return ret;
+}
+
+/*
+ * This function deletes an entry for a given TID/TA pair.
+ *
+ * The TID/TA are taken from del BA event body.
+ */
+void
+mwifiex_11n_delete_ba_stream_tbl(struct mwifiex_private *priv, int tid,
+				u8 *peer_mac, u8 type, int initiator)
+{
+	struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
+	struct mwifiex_tx_ba_stream_tbl *ptx_tbl;
+	u8 cleanup_rx_reorder_tbl;
+	unsigned long flags;
+
+	if (type == TYPE_DELBA_RECEIVE)
+		cleanup_rx_reorder_tbl = (initiator) ? true : false;
+	else
+		cleanup_rx_reorder_tbl = (initiator) ? false : true;
+
+	dev_dbg(priv->adapter->dev, "event: DELBA: %pM tid=%d, "
+	       "initiator=%d\n", peer_mac, tid, initiator);
+
+	if (cleanup_rx_reorder_tbl) {
+		rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
+								 peer_mac);
+		if (!rx_reor_tbl_ptr) {
+			dev_dbg(priv->adapter->dev,
+					"event: TID, TA not found in table\n");
+			return;
+		}
+		mwifiex_11n_delete_rx_reorder_tbl_entry(priv, rx_reor_tbl_ptr);
+	} else {
+		ptx_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, peer_mac);
+		if (!ptx_tbl) {
+			dev_dbg(priv->adapter->dev,
+					"event: TID, RA not found in table\n");
+			return;
+		}
+
+		spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
+		mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, ptx_tbl);
+		spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
+	}
+}
+
+/*
+ * This function handles the command response of an add BA response.
+ *
+ * Handling includes changing the header fields into CPU format and
+ * creating the stream, provided the add BA is accepted.
+ */
+int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv,
+			       struct host_cmd_ds_command *resp)
+{
+	struct host_cmd_ds_11n_addba_rsp *add_ba_rsp =
+		(struct host_cmd_ds_11n_addba_rsp *)
+		&resp->params.add_ba_rsp;
+	int tid, win_size;
+	struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr = NULL;
+	uint16_t block_ack_param_set;
+
+	block_ack_param_set = le16_to_cpu(add_ba_rsp->block_ack_param_set);
+
+	tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK)
+		>> BLOCKACKPARAM_TID_POS;
+	/*
+	 * Check if we had rejected the ADDBA, if yes then do not create
+	 * the stream
+	 */
+	if (le16_to_cpu(add_ba_rsp->status_code) == BA_RESULT_SUCCESS) {
+		win_size = (block_ack_param_set &
+			IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK)
+			>> BLOCKACKPARAM_WINSIZE_POS;
+
+		dev_dbg(priv->adapter->dev, "cmd: ADDBA RSP: %pM"
+		       " tid=%d ssn=%d win_size=%d\n",
+		       add_ba_rsp->peer_mac_addr,
+		       tid, add_ba_rsp->ssn, win_size);
+	} else {
+		dev_err(priv->adapter->dev, "ADDBA RSP: failed %pM tid=%d)\n",
+					add_ba_rsp->peer_mac_addr, tid);
+
+		rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv,
+					tid, add_ba_rsp->peer_mac_addr);
+		if (rx_reor_tbl_ptr)
+			mwifiex_11n_delete_rx_reorder_tbl_entry(priv,
+				rx_reor_tbl_ptr);
+	}
+
+	return 0;
+}
+
+/*
+ * This function handles BA stream timeout event by preparing and sending
+ * a command to the firmware.
+ */
+void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv,
+				   struct host_cmd_ds_11n_batimeout *event)
+{
+	struct host_cmd_ds_11n_delba delba;
+
+	memset(&delba, 0, sizeof(struct host_cmd_ds_11n_delba));
+	memcpy(delba.peer_mac_addr, event->peer_mac_addr, ETH_ALEN);
+
+	delba.del_ba_param_set |=
+		cpu_to_le16((u16) event->tid << DELBA_TID_POS);
+	delba.del_ba_param_set |= cpu_to_le16(
+		(u16) event->origninator << DELBA_INITIATOR_POS);
+	delba.reason_code = cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT);
+	mwifiex_prepare_cmd(priv, HostCmd_CMD_11N_DELBA, 0, 0, NULL, &delba);
+
+	return;
+}
+
+/*
+ * This function cleans up the Rx reorder table by deleting all the entries
+ * and re-initializing.
+ */
+void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv)
+{
+	struct mwifiex_rx_reorder_tbl *del_tbl_ptr, *tmp_node;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
+	list_for_each_entry_safe(del_tbl_ptr, tmp_node,
+				 &priv->rx_reorder_tbl_ptr, list) {
+		spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
+		mwifiex_11n_delete_rx_reorder_tbl_entry(priv, del_tbl_ptr);
+		spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
+	}
+	spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
+
+	INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr);
+	memset(priv->rx_seq, 0, sizeof(priv->rx_seq));
+}
diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.h b/drivers/net/wireless/mwifiex/11n_rxreorder.h
new file mode 100644
index 0000000..42f5690
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/11n_rxreorder.h
@@ -0,0 +1,67 @@
+/*
+ * Marvell Wireless LAN device driver: 802.11n RX Re-ordering
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#ifndef _MWIFIEX_11N_RXREORDER_H_
+#define _MWIFIEX_11N_RXREORDER_H_
+
+#define MIN_FLUSH_TIMER_MS		50
+
+#define PKT_TYPE_BAR 0xE7
+#define MAX_TID_VALUE			(2 << 11)
+#define TWOPOW11			(2 << 10)
+
+#define BLOCKACKPARAM_TID_POS		2
+#define BLOCKACKPARAM_AMSDU_SUPP_MASK	0x1
+#define BLOCKACKPARAM_WINSIZE_POS	6
+#define DELBA_TID_POS			12
+#define DELBA_INITIATOR_POS		11
+#define TYPE_DELBA_SENT			1
+#define TYPE_DELBA_RECEIVE		2
+#define IMMEDIATE_BLOCK_ACK		0x2
+
+#define ADDBA_RSP_STATUS_ACCEPT 0
+
+int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *,
+			       u16 seqNum,
+			       u16 tid, u8 *ta,
+			       u8 pkttype, void *payload);
+void mwifiex_11n_delete_ba_stream_tbl(struct mwifiex_private *priv, int Tid,
+				     u8 *PeerMACAddr, u8 type,
+				     int initiator);
+void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv,
+				   struct host_cmd_ds_11n_batimeout *event);
+int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv,
+			       struct host_cmd_ds_command
+			       *resp);
+int mwifiex_cmd_11n_delba(struct mwifiex_private *priv,
+			  struct host_cmd_ds_command *cmd,
+			  void *data_buf);
+int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv,
+				  struct host_cmd_ds_command
+				  *cmd, void *data_buf);
+int mwifiex_cmd_11n_addba_req(struct mwifiex_private *priv,
+			      struct host_cmd_ds_command *cmd,
+			      void *data_buf);
+void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv);
+struct mwifiex_rx_reorder_tbl *mwifiex_11n_get_rxreorder_tbl(struct
+							   mwifiex_private
+							   *priv, int tid,
+							   u8 *ta);
+
+#endif /* _MWIFIEX_11N_RXREORDER_H_ */
diff --git a/drivers/net/wireless/mwifiex/Kconfig b/drivers/net/wireless/mwifiex/Kconfig
new file mode 100644
index 0000000..8696292
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/Kconfig
@@ -0,0 +1,21 @@
+config MWIFIEX
+	tristate "Marvell WiFi-Ex Driver"
+	depends on CFG80211
+	select LIB80211
+	---help---
+	  This adds support for wireless adapters based on Marvell
+	  802.11n chipsets.
+
+	  If you choose to build it as a module, it will be called
+	  mwifiex.
+
+config MWIFIEX_SDIO
+	tristate "Marvell WiFi-Ex Driver for SD8787"
+	depends on MWIFIEX && MMC
+	select FW_LOADER
+	---help---
+	  This adds support for wireless adapters based on Marvell
+	  8787 chipset with SDIO interface.
+
+	  If you choose to build it as a module, it will be called
+	  mwifiex_sdio.
diff --git a/drivers/net/wireless/mwifiex/Makefile b/drivers/net/wireless/mwifiex/Makefile
new file mode 100644
index 0000000..42cb733
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/Makefile
@@ -0,0 +1,41 @@
+#
+# Copyright (C) 2011, Marvell International Ltd.
+#
+# This software file (the "File") is distributed by Marvell International
+# Ltd. under the terms of the GNU General Public License Version 2, June 1991
+# (the "License").  You may use, redistribute and/or modify this File in
+# accordance with the terms and conditions of the License, a copy of which
+# is available by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+# worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+#
+# THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+# ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+# this warranty disclaimer.
+
+
+mwifiex-y += main.o
+mwifiex-y += init.o
+mwifiex-y += cfp.o
+mwifiex-y += cmdevt.o
+mwifiex-y += util.o
+mwifiex-y += txrx.o
+mwifiex-y += wmm.o
+mwifiex-y += 11n.o
+mwifiex-y += 11n_aggr.o
+mwifiex-y += 11n_rxreorder.o
+mwifiex-y += scan.o
+mwifiex-y += join.o
+mwifiex-y += sta_ioctl.o
+mwifiex-y += sta_cmd.o
+mwifiex-y += sta_cmdresp.o
+mwifiex-y += sta_event.o
+mwifiex-y += sta_tx.o
+mwifiex-y += sta_rx.o
+mwifiex-y += cfg80211.o
+mwifiex-$(CONFIG_DEBUG_FS) += debugfs.o
+obj-$(CONFIG_MWIFIEX) += mwifiex.o
+
+mwifiex_sdio-y += sdio.o
+obj-$(CONFIG_MWIFIEX_SDIO) += mwifiex_sdio.o
diff --git a/drivers/net/wireless/mwifiex/README b/drivers/net/wireless/mwifiex/README
new file mode 100644
index 0000000..338377f
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/README
@@ -0,0 +1,204 @@
+# Copyright (C) 2011, Marvell International Ltd.
+#
+# This software file (the "File") is distributed by Marvell International
+# Ltd. under the terms of the GNU General Public License Version 2, June 1991
+# (the "License").  You may use, redistribute and/or modify this File in
+# accordance with the terms and conditions of the License, a copy of which
+# is available by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+# worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+#
+# THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+# ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+# this warranty disclaimer.
+
+
+===============================================================================
+			U S E R  M A N U A L
+
+1) FOR DRIVER INSTALL
+
+	a) Copy sd8787.bin to /lib/firmware/mrvl/ directory,
+	   create the directory if it doesn't exist.
+	b) Install WLAN driver,
+		insmod mwifiex.ko
+	c) Uninstall WLAN driver,
+		ifconfig mlanX down
+		rmmod mwifiex
+
+
+2) FOR DRIVER CONFIGURATION AND INFO
+	The configurations can be done either using the 'iw' user space
+	utility or debugfs.
+
+	a) 'iw' utility commands
+
+	Following are some useful iw commands:-
+
+iw dev mlan0 scan
+
+	This command will trigger a scan.
+	The command will then display the scan table entries
+
+iw dev mlan0 connect -w <SSID> [<freq in MHz>] [<bssid>] [key 0:abcde d:1123456789a]
+	The above command can be used to connect to an AP with a particular SSID.
+	Ap's operating frequency can be specified or even the bssid. If the AP is using
+	WEP encryption, wep keys can be specified in the command.
+	Note: Every time before connecting to an AP scan command (iw dev mlan0 scan) should be used by user.
+
+iw dev mlan0 disconnect
+	This command will be used to disconnect from an AP.
+
+
+iw dev mlan0 ibss join <SSID> <freq in MHz> [fixed-freq] [fixed-bssid] [key 0:abcde]
+	The command will be used to join or create an ibss. Optionally, operating frequency,
+	bssid and the security related parameters can be specified while joining/creating
+	and ibss.
+
+iw dev mlan0 ibss leave
+	The command will be used to leave an ibss network.
+
+iw dev mlan0 link
+	The command will be used to get the connection status. The command will return parameters
+	such as SSID, operating frequency, rx/tx packets, signal strength, tx bitrate.
+
+	Apart from the iw utility all standard configurations using the 'iwconfig' utility are also supported.
+
+	b) Debugfs interface
+
+	The debugfs interface can be used for configurations and for getting
+	some useful information from the driver.
+	The section below explains the configurations that can be
+	done.
+
+	Mount debugfs to /debugfs mount point:
+
+		mkdir /debugfs
+		mount -t debugfs debugfs /debugfs
+
+	The information is provided in /debugfs/mwifiex/mlanX/:
+
+iw reg set <country code>
+	The command will be used to change the regulatory domain.
+
+iw reg get
+	The command will be used to get current regulatory domain.
+
+info
+	This command is used to get driver info.
+
+	Usage:
+		cat info
+
+	driver_name = "mwifiex"
+	driver_version = <driver_name, driver_version, (firmware_version)>
+	interface_name = "mlanX"
+	bss_mode = "Ad-hoc" | "Managed" | "Auto" | "Unknown"
+	media_state = "Disconnected" | "Connected"
+	mac_address = <6-byte adapter MAC address>
+	multicase_count = <multicast address count>
+	essid = <current SSID>
+	bssid = <current BSSID>
+	channel = <current channel>
+	region_code = <current region code>
+	multicasr_address[n] = <multicast address>
+	num_tx_bytes = <number of bytes sent to device>
+	num_rx_bytes = <number of bytes received from device and sent to kernel>
+	num_tx_pkts = <number of packets sent to device>
+	num_rx_pkts = <number of packets received from device and sent to kernel>
+	num_tx_pkts_dropped = <number of Tx packets dropped by driver>
+	num_rx_pkts_dropped = <number of Rx packets dropped by driver>
+	num_tx_pkts_err = <number of Tx packets failed to send to device>
+	num_rx_pkts_err = <number of Rx packets failed to receive from device>
+	carrier "on" | "off"
+	tx queue "stopped" | "started"
+
+	The following debug info are provided in /debugfs/mwifiex/mlanX/debug:
+
+	int_counter = <interrupt count, cleared when interrupt handled>
+	wmm_ac_vo = <number of packets sent to device from WMM AcVo queue>
+	wmm_ac_vi = <number of packets sent to device from WMM AcVi queue>
+	wmm_ac_be = <number of packets sent to device from WMM AcBE queue>
+	wmm_ac_bk = <number of packets sent to device from WMM AcBK queue>
+	max_tx_buf_size = <maximum Tx buffer size>
+	tx_buf_size = <current Tx buffer size>
+	curr_tx_buf_size = <current Tx buffer size>
+	ps_mode = <0/1, CAM mode/PS mode>
+	ps_state = <0/1/2/3, full power state/awake state/pre-sleep state/sleep state>
+	is_deep_sleep = <0/1, not deep sleep state/deep sleep state>
+	wakeup_dev_req = <0/1, wakeup device not required/required>
+	wakeup_tries = <wakeup device count, cleared when device awake>
+	hs_configured = <0/1, host sleep not configured/configured>
+	hs_activated = <0/1, extended host sleep not activated/activated>
+	num_tx_timeout = <number of Tx timeout>
+	num_cmd_timeout = <number of timeout commands>
+	timeout_cmd_id = <command id of the last timeout command>
+	timeout_cmd_act = <command action of the last timeout command>
+	last_cmd_id = <command id of the last several commands sent to device>
+	last_cmd_act = <command action of the last several commands sent to device>
+	last_cmd_index = <0 based last command index>
+	last_cmd_resp_id = <command id of the last several command responses received from device>
+	last_cmd_resp_index = <0 based last command response index>
+	last_event = <event id of the last several events received from device>
+	last_event_index = <0 based last event index>
+	num_cmd_h2c_fail = <number of commands failed to send to device>
+	num_cmd_sleep_cfm_fail = <number of sleep confirm failed to send to device>
+	num_tx_h2c_fail = <number of data packets failed to send to device>
+	num_evt_deauth = <number of deauthenticated events received from device>
+	num_evt_disassoc = <number of disassociated events received from device>
+	num_evt_link_lost = <number of link lost events received from device>
+	num_cmd_deauth = <number of deauthenticate commands sent to device>
+	num_cmd_assoc_ok = <number of associate commands with success return>
+	num_cmd_assoc_fail = <number of associate commands with failure return>
+	cmd_sent = <0/1, send command resources available/sending command to device>
+	data_sent = <0/1, send data resources available/sending data to device>
+	mp_rd_bitmap = <SDIO multi-port read bitmap>
+	mp_wr_bitmap = <SDIO multi-port write bitmap>
+	cmd_resp_received = <0/1, no cmd response to process/response received and yet to process>
+	event_received = <0/1, no event to process/event received and yet to process>
+	ioctl_pending = <number of ioctl pending>
+	tx_pending = <number of Tx packet pending>
+	rx_pending = <number of Rx packet pending>
+
+
+3) FOR DRIVER CONFIGURATION
+
+regrdwr
+	This command is used to read/write the adapter register.
+
+	Usage:
+		echo " <type> <offset> [value]" > regrdwr
+		cat regrdwr
+
+	where the parameters are,
+		<type>:     1:MAC/SOC, 2:BBP, 3:RF, 4:PMIC, 5:CAU
+		<offset>:   offset of register
+		[value]:    value to be written
+
+	Examples:
+		echo "1 0xa060" > regrdwr           : Read the MAC register
+		echo "1 0xa060 0x12" > regrdwr      : Write the MAC register
+		echo "1 0xa794 0x80000000" > regrdwr
+		                                    : Write 0x80000000 to MAC register
+rdeeprom
+	This command is used to read the EEPROM contents of the card.
+
+	Usage:
+		echo "<offset> <length>" > rdeeprom
+		cat rdeeprom
+
+	where the parameters are,
+		<offset>:   multiples of 4
+		<length>:   4-20, multiples of 4
+
+	Example:
+		echo "0 20" > rdeeprom      : Read 20 bytes of EEPROM data from offset 0
+
+getlog
+        This command is used to get the statistics available in the station.
+	Usage:
+
+	cat getlog
+
+===============================================================================
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
new file mode 100644
index 0000000..ec0895f
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -0,0 +1,1456 @@
+/*
+ * Marvell Wireless LAN device driver: CFG80211
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "cfg80211.h"
+#include "main.h"
+
+/*
+ * This function maps the nl802.11 channel type into driver channel type.
+ *
+ * The mapping is as follows -
+ *      NL80211_CHAN_NO_HT     -> NO_SEC_CHANNEL
+ *      NL80211_CHAN_HT20      -> NO_SEC_CHANNEL
+ *      NL80211_CHAN_HT40PLUS  -> SEC_CHANNEL_ABOVE
+ *      NL80211_CHAN_HT40MINUS -> SEC_CHANNEL_BELOW
+ *      Others                 -> NO_SEC_CHANNEL
+ */
+static int
+mwifiex_cfg80211_channel_type_to_mwifiex_channels(enum nl80211_channel_type
+						  channel_type)
+{
+	int channel;
+	switch (channel_type) {
+	case NL80211_CHAN_NO_HT:
+	case NL80211_CHAN_HT20:
+		channel = NO_SEC_CHANNEL;
+		break;
+	case NL80211_CHAN_HT40PLUS:
+		channel = SEC_CHANNEL_ABOVE;
+		break;
+	case NL80211_CHAN_HT40MINUS:
+		channel = SEC_CHANNEL_BELOW;
+		break;
+	default:
+		channel = NO_SEC_CHANNEL;
+	}
+	return channel;
+}
+
+/*
+ * This function maps the driver channel type into nl802.11 channel type.
+ *
+ * The mapping is as follows -
+ *      NO_SEC_CHANNEL      -> NL80211_CHAN_HT20
+ *      SEC_CHANNEL_ABOVE   -> NL80211_CHAN_HT40PLUS
+ *      SEC_CHANNEL_BELOW   -> NL80211_CHAN_HT40MINUS
+ *      Others              -> NL80211_CHAN_HT20
+ */
+static enum nl80211_channel_type
+mwifiex_channels_to_cfg80211_channel_type(int channel_type)
+{
+	int channel;
+	switch (channel_type) {
+	case NO_SEC_CHANNEL:
+		channel = NL80211_CHAN_HT20;
+		break;
+	case SEC_CHANNEL_ABOVE:
+		channel = NL80211_CHAN_HT40PLUS;
+		break;
+	case SEC_CHANNEL_BELOW:
+		channel = NL80211_CHAN_HT40MINUS;
+		break;
+	default:
+		channel = NL80211_CHAN_HT20;
+	}
+	return channel;
+}
+
+/*
+ * This function checks whether WEP is set.
+ */
+static int
+mwifiex_is_alg_wep(u32 cipher)
+{
+	int alg = 0;
+
+	switch (cipher) {
+	case WLAN_CIPHER_SUITE_WEP40:
+	case WLAN_CIPHER_SUITE_WEP104:
+		alg = 1;
+		break;
+	default:
+		alg = 0;
+		break;
+	}
+	return alg;
+}
+
+/*
+ * This function retrieves the private structure from kernel wiphy structure.
+ */
+static void *mwifiex_cfg80211_get_priv(struct wiphy *wiphy)
+{
+	return (void *) (*(unsigned long *) wiphy_priv(wiphy));
+}
+
+/*
+ * CFG802.11 operation handler to delete a network key.
+ */
+static int
+mwifiex_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev,
+			 u8 key_index, bool pairwise, const u8 *mac_addr)
+{
+	struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
+	int ret = 0;
+
+	ret = mwifiex_set_encode(priv, NULL, 0, key_index, 1);
+	if (ret) {
+		wiphy_err(wiphy, "deleting the crypto keys\n");
+		return -EFAULT;
+	}
+
+	wiphy_dbg(wiphy, "info: crypto keys deleted\n");
+	return 0;
+}
+
+/*
+ * CFG802.11 operation handler to set Tx power.
+ */
+static int
+mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy,
+			      enum nl80211_tx_power_setting type,
+			      int dbm)
+{
+	int ret = 0;
+	struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
+
+	ret = mwifiex_set_tx_power(priv, type, dbm);
+
+	return ret;
+}
+
+/*
+ * CFG802.11 operation handler to set Power Save option.
+ *
+ * The timeout value, if provided, is currently ignored.
+ */
+static int
+mwifiex_cfg80211_set_power_mgmt(struct wiphy *wiphy,
+				struct net_device *dev,
+				bool enabled, int timeout)
+{
+	int ret = 0;
+	struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
+
+	if (timeout)
+		wiphy_dbg(wiphy,
+			"info: ignoring the timeout value"
+			" for IEEE power save\n");
+
+	ret = mwifiex_drv_set_power(priv, enabled);
+
+	return ret;
+}
+
+/*
+ * CFG802.11 operation handler to set the default network key.
+ */
+static int
+mwifiex_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
+				 u8 key_index, bool unicast,
+				 bool multicast)
+{
+	struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
+	int ret;
+
+	/* Return if WEP key not configured */
+	if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED)
+		return 0;
+
+	ret = mwifiex_set_encode(priv, NULL, 0, key_index, 0);
+
+	wiphy_dbg(wiphy, "info: set default Tx key index\n");
+
+	if (ret)
+		return -EFAULT;
+
+	return 0;
+}
+
+/*
+ * CFG802.11 operation handler to add a network key.
+ */
+static int
+mwifiex_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev,
+			 u8 key_index, bool pairwise, const u8 *mac_addr,
+			 struct key_params *params)
+{
+	struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
+	int ret = 0;
+
+	ret = mwifiex_set_encode(priv, params->key, params->key_len,
+								key_index, 0);
+
+	wiphy_dbg(wiphy, "info: crypto keys added\n");
+
+	if (ret)
+		return -EFAULT;
+
+	return 0;
+}
+
+/*
+ * This function sends domain information to the firmware.
+ *
+ * The following information are passed to the firmware -
+ *      - Country codes
+ *      - Sub bands (first channel, number of channels, maximum Tx power)
+ */
+static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy)
+{
+	u8 no_of_triplet = 0;
+	struct ieee80211_country_ie_triplet *t;
+	u8 no_of_parsed_chan = 0;
+	u8 first_chan = 0, next_chan = 0, max_pwr = 0;
+	u8 i, flag = 0;
+	enum ieee80211_band band;
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_channel *ch;
+	struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
+	struct mwifiex_adapter *adapter = priv->adapter;
+	struct mwifiex_802_11d_domain_reg *domain_info = &adapter->domain_reg;
+	int ret = 0;
+
+	/* Set country code */
+	domain_info->country_code[0] = priv->country_code[0];
+	domain_info->country_code[1] = priv->country_code[1];
+	domain_info->country_code[2] = ' ';
+
+	band = mwifiex_band_to_radio_type(adapter->config_bands);
+	if (!wiphy->bands[band]) {
+		wiphy_err(wiphy, "11D: setting domain info in FW\n");
+		return -1;
+	}
+
+	sband = wiphy->bands[band];
+
+	for (i = 0; i < sband->n_channels ; i++) {
+		ch = &sband->channels[i];
+		if (ch->flags & IEEE80211_CHAN_DISABLED)
+			continue;
+
+		if (!flag) {
+			flag = 1;
+			first_chan = (u32) ch->hw_value;
+			next_chan = first_chan;
+			max_pwr = ch->max_power;
+			no_of_parsed_chan = 1;
+			continue;
+		}
+
+		if (ch->hw_value == next_chan + 1 &&
+				ch->max_power == max_pwr) {
+			next_chan++;
+			no_of_parsed_chan++;
+		} else {
+			t = &domain_info->triplet[no_of_triplet];
+			t->chans.first_channel = first_chan;
+			t->chans.num_channels = no_of_parsed_chan;
+			t->chans.max_power = max_pwr;
+			no_of_triplet++;
+			first_chan = (u32) ch->hw_value;
+			next_chan = first_chan;
+			max_pwr = ch->max_power;
+			no_of_parsed_chan = 1;
+		}
+	}
+
+	if (flag) {
+		t = &domain_info->triplet[no_of_triplet];
+		t->chans.first_channel = first_chan;
+		t->chans.num_channels = no_of_parsed_chan;
+		t->chans.max_power = max_pwr;
+		no_of_triplet++;
+	}
+
+	domain_info->no_of_triplet = no_of_triplet;
+	/* Send cmd to FW to set domain info */
+	ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11D_DOMAIN_INFO,
+				  HostCmd_ACT_GEN_SET, 0, NULL, NULL);
+	if (ret)
+		wiphy_err(wiphy, "11D: setting domain info in FW\n");
+
+	return ret;
+}
+
+/*
+ * CFG802.11 regulatory domain callback function.
+ *
+ * This function is called when the regulatory domain is changed due to the
+ * following reasons -
+ *      - Set by driver
+ *      - Set by system core
+ *      - Set by user
+ *      - Set bt Country IE
+ */
+static int mwifiex_reg_notifier(struct wiphy *wiphy,
+		struct regulatory_request *request)
+{
+	struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
+
+	wiphy_dbg(wiphy, "info: cfg80211 regulatory domain callback for domain"
+			" %c%c\n", request->alpha2[0], request->alpha2[1]);
+
+	memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2));
+
+	switch (request->initiator) {
+	case NL80211_REGDOM_SET_BY_DRIVER:
+	case NL80211_REGDOM_SET_BY_CORE:
+	case NL80211_REGDOM_SET_BY_USER:
+		break;
+		/* Todo: apply driver specific changes in channel flags based
+		   on the request initiator if necessary. */
+	case NL80211_REGDOM_SET_BY_COUNTRY_IE:
+		break;
+	}
+	mwifiex_send_domain_info_cmd_fw(wiphy);
+
+	return 0;
+}
+
+/*
+ * This function sets the RF channel.
+ *
+ * This function creates multiple IOCTL requests, populates them accordingly
+ * and issues them to set the band/channel and frequency.
+ */
+static int
+mwifiex_set_rf_channel(struct mwifiex_private *priv,
+		       struct ieee80211_channel *chan,
+		       enum nl80211_channel_type channel_type)
+{
+	struct mwifiex_chan_freq_power cfp;
+	int ret = 0;
+	int status = 0;
+	struct mwifiex_ds_band_cfg band_cfg;
+	u32 config_bands = 0;
+	struct wiphy *wiphy = priv->wdev->wiphy;
+
+	if (chan) {
+		memset(&band_cfg, 0, sizeof(band_cfg));
+		/* Set appropriate bands */
+		if (chan->band == IEEE80211_BAND_2GHZ)
+			config_bands = BAND_B | BAND_G | BAND_GN;
+		else
+			config_bands = BAND_AN | BAND_A;
+		if (priv->bss_mode == NL80211_IFTYPE_STATION
+		    || priv->bss_mode == NL80211_IFTYPE_UNSPECIFIED) {
+			band_cfg.config_bands = config_bands;
+		} else if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
+			band_cfg.config_bands = config_bands;
+			band_cfg.adhoc_start_band = config_bands;
+		}
+		/* Set channel offset */
+		band_cfg.sec_chan_offset =
+			mwifiex_cfg80211_channel_type_to_mwifiex_channels
+			(channel_type);
+		status = mwifiex_radio_ioctl_band_cfg(priv, HostCmd_ACT_GEN_SET,
+						      &band_cfg);
+
+		if (status)
+			return -EFAULT;
+		mwifiex_send_domain_info_cmd_fw(wiphy);
+	}
+
+	wiphy_dbg(wiphy, "info: setting band %d, channel offset %d and "
+		"mode %d\n", config_bands, band_cfg.sec_chan_offset,
+		priv->bss_mode);
+	if (!chan)
+		return ret;
+
+	memset(&cfp, 0, sizeof(cfp));
+	cfp.freq = chan->center_freq;
+	/* Convert frequency to channel */
+	cfp.channel = ieee80211_frequency_to_channel(chan->center_freq);
+
+	status = mwifiex_bss_ioctl_channel(priv, HostCmd_ACT_GEN_SET, &cfp);
+	if (status)
+		return -EFAULT;
+
+	ret = mwifiex_drv_change_adhoc_chan(priv, cfp.channel);
+
+	return ret;
+}
+
+/*
+ * CFG802.11 operation handler to set channel.
+ *
+ * This function can only be used when station is not connected.
+ */
+static int
+mwifiex_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
+			     struct ieee80211_channel *chan,
+			     enum nl80211_channel_type channel_type)
+{
+	struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
+
+	if (priv->media_connected) {
+		wiphy_err(wiphy, "This setting is valid only when station "
+				"is not connected\n");
+		return -EINVAL;
+	}
+
+	return mwifiex_set_rf_channel(priv, chan, channel_type);
+}
+
+/*
+ * This function sets the fragmentation threshold.
+ *
+ * This function creates an IOCTL request, populates it accordingly
+ * and issues an IOCTL.
+ *
+ * The fragmentation threshold value must lies between MWIFIEX_FRAG_MIN_VALUE
+ * and MWIFIEX_FRAG_MAX_VALUE.
+ */
+static int
+mwifiex_set_frag(struct mwifiex_private *priv, u32 frag_thr)
+{
+	int ret = 0;
+	int status = 0;
+	struct mwifiex_wait_queue *wait = NULL;
+	u8 wait_option = MWIFIEX_IOCTL_WAIT;
+
+	if (frag_thr < MWIFIEX_FRAG_MIN_VALUE
+	    || frag_thr > MWIFIEX_FRAG_MAX_VALUE)
+		return -EINVAL;
+
+	wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
+	if (!wait)
+		return -ENOMEM;
+
+	status = mwifiex_snmp_mib_ioctl(priv, wait, FRAG_THRESH_I,
+					HostCmd_ACT_GEN_SET, &frag_thr);
+
+	if (mwifiex_request_ioctl(priv, wait, status, wait_option))
+		ret = -EFAULT;
+
+	kfree(wait);
+	return ret;
+}
+
+/*
+ * This function sets the RTS threshold.
+ *
+ * This function creates an IOCTL request, populates it accordingly
+ * and issues an IOCTL.
+ */
+static int
+mwifiex_set_rts(struct mwifiex_private *priv, u32 rts_thr)
+{
+	int ret = 0;
+	struct mwifiex_wait_queue *wait = NULL;
+	int status = 0;
+	u8 wait_option = MWIFIEX_IOCTL_WAIT;
+
+	if (rts_thr < MWIFIEX_RTS_MIN_VALUE || rts_thr > MWIFIEX_RTS_MAX_VALUE)
+		rts_thr = MWIFIEX_RTS_MAX_VALUE;
+
+	wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
+	if (!wait)
+		return -ENOMEM;
+
+	status = mwifiex_snmp_mib_ioctl(priv, wait, RTS_THRESH_I,
+					HostCmd_ACT_GEN_SET, &rts_thr);
+
+	if (mwifiex_request_ioctl(priv, wait, status, wait_option))
+		ret = -EFAULT;
+
+	kfree(wait);
+	return ret;
+}
+
+/*
+ * CFG802.11 operation handler to set wiphy parameters.
+ *
+ * This function can be used to set the RTS threshold and the
+ * Fragmentation threshold of the driver.
+ */
+static int
+mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
+{
+	struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
+
+	int ret = 0;
+
+	if (changed & WIPHY_PARAM_RTS_THRESHOLD)
+		ret = mwifiex_set_rts(priv, wiphy->rts_threshold);
+
+	if (changed & WIPHY_PARAM_FRAG_THRESHOLD)
+		ret = mwifiex_set_frag(priv, wiphy->frag_threshold);
+
+	return ret;
+}
+
+/*
+ * CFG802.11 operation handler to change interface type.
+ */
+static int
+mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
+				     struct net_device *dev,
+				     enum nl80211_iftype type, u32 *flags,
+				     struct vif_params *params)
+{
+	int ret = 0;
+	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+	struct mwifiex_wait_queue *wait = NULL;
+
+	if (priv->bss_mode == type) {
+		wiphy_warn(wiphy, "already set to required type\n");
+		return 0;
+	}
+
+	priv->bss_mode = type;
+
+	switch (type) {
+	case NL80211_IFTYPE_ADHOC:
+		dev->ieee80211_ptr->iftype = NL80211_IFTYPE_ADHOC;
+		wiphy_dbg(wiphy, "info: setting interface type to adhoc\n");
+		break;
+	case NL80211_IFTYPE_STATION:
+		dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION;
+		wiphy_dbg(wiphy, "info: setting interface type to managed\n");
+		break;
+	case NL80211_IFTYPE_UNSPECIFIED:
+		dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION;
+		wiphy_dbg(wiphy, "info: setting interface type to auto\n");
+		return 0;
+	default:
+		wiphy_err(wiphy, "unknown interface type: %d\n", type);
+		return -EINVAL;
+	}
+
+	wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT);
+	if (!wait)
+		return -ENOMEM;
+
+	mwifiex_deauthenticate(priv, wait, NULL);
+
+	priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM;
+
+	ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_SET_BSS_MODE,
+				  HostCmd_ACT_GEN_SET, 0, wait, NULL);
+	if (!ret)
+		ret = -EINPROGRESS;
+
+	ret = mwifiex_request_ioctl(priv, wait, ret, MWIFIEX_IOCTL_WAIT);
+	if (ret)
+		ret = -EFAULT;
+
+	kfree(wait);
+	return ret;
+}
+
+/*
+ * This function dumps the station information on a buffer.
+ *
+ * The following information are shown -
+ *      - Total bytes transmitted
+ *      - Total bytes received
+ *      - Total packets transmitted
+ *      - Total packets received
+ *      - Signal quality level
+ *      - Transmission rate
+ */
+static int
+mwifiex_dump_station_info(struct mwifiex_private *priv,
+			  struct station_info *sinfo)
+{
+	struct mwifiex_ds_get_signal signal;
+	struct mwifiex_rate_cfg rate;
+	int ret = 0;
+
+	sinfo->filled = STATION_INFO_RX_BYTES | STATION_INFO_TX_BYTES |
+		STATION_INFO_RX_PACKETS |
+		STATION_INFO_TX_PACKETS
+		| STATION_INFO_SIGNAL | STATION_INFO_TX_BITRATE;
+
+	/* Get signal information from the firmware */
+	memset(&signal, 0, sizeof(struct mwifiex_ds_get_signal));
+	if (mwifiex_get_signal_info(priv, MWIFIEX_IOCTL_WAIT, &signal)) {
+		dev_err(priv->adapter->dev, "getting signal information\n");
+		ret = -EFAULT;
+	}
+
+	if (mwifiex_drv_get_data_rate(priv, &rate)) {
+		dev_err(priv->adapter->dev, "getting data rate\n");
+		ret = -EFAULT;
+	}
+
+	sinfo->rx_bytes = priv->stats.rx_bytes;
+	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->txrate.legacy = rate.rate;
+
+	return ret;
+}
+
+/*
+ * CFG802.11 operation handler to get station information.
+ *
+ * This function only works in connected mode, and dumps the
+ * requested station information, if available.
+ */
+static int
+mwifiex_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
+			     u8 *mac, struct station_info *sinfo)
+{
+	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+	int ret = 0;
+
+	mwifiex_dump_station_info(priv, sinfo);
+
+	if (!priv->media_connected)
+		return -ENOENT;
+	if (memcmp(mac, priv->cfg_bssid, ETH_ALEN))
+		return -ENOENT;
+
+
+	ret = mwifiex_dump_station_info(priv, sinfo);
+
+	return ret;
+}
+
+/* Supported rates to be advertised to the cfg80211 */
+
+static struct ieee80211_rate mwifiex_rates[] = {
+	{.bitrate = 10, .hw_value = 2, },
+	{.bitrate = 20, .hw_value = 4, },
+	{.bitrate = 55, .hw_value = 11, },
+	{.bitrate = 110, .hw_value = 22, },
+	{.bitrate = 220, .hw_value = 44, },
+	{.bitrate = 60, .hw_value = 12, },
+	{.bitrate = 90, .hw_value = 18, },
+	{.bitrate = 120, .hw_value = 24, },
+	{.bitrate = 180, .hw_value = 36, },
+	{.bitrate = 240, .hw_value = 48, },
+	{.bitrate = 360, .hw_value = 72, },
+	{.bitrate = 480, .hw_value = 96, },
+	{.bitrate = 540, .hw_value = 108, },
+	{.bitrate = 720, .hw_value = 144, },
+};
+
+/* Channel definitions to be advertised to cfg80211 */
+
+static struct ieee80211_channel mwifiex_channels_2ghz[] = {
+	{.center_freq = 2412, .hw_value = 1, },
+	{.center_freq = 2417, .hw_value = 2, },
+	{.center_freq = 2422, .hw_value = 3, },
+	{.center_freq = 2427, .hw_value = 4, },
+	{.center_freq = 2432, .hw_value = 5, },
+	{.center_freq = 2437, .hw_value = 6, },
+	{.center_freq = 2442, .hw_value = 7, },
+	{.center_freq = 2447, .hw_value = 8, },
+	{.center_freq = 2452, .hw_value = 9, },
+	{.center_freq = 2457, .hw_value = 10, },
+	{.center_freq = 2462, .hw_value = 11, },
+	{.center_freq = 2467, .hw_value = 12, },
+	{.center_freq = 2472, .hw_value = 13, },
+	{.center_freq = 2484, .hw_value = 14, },
+};
+
+static struct ieee80211_supported_band mwifiex_band_2ghz = {
+	.channels = mwifiex_channels_2ghz,
+	.n_channels = ARRAY_SIZE(mwifiex_channels_2ghz),
+	.bitrates = mwifiex_rates,
+	.n_bitrates = 14,
+};
+
+static struct ieee80211_channel mwifiex_channels_5ghz[] = {
+	{.center_freq = 5040, .hw_value = 8, },
+	{.center_freq = 5060, .hw_value = 12, },
+	{.center_freq = 5080, .hw_value = 16, },
+	{.center_freq = 5170, .hw_value = 34, },
+	{.center_freq = 5190, .hw_value = 38, },
+	{.center_freq = 5210, .hw_value = 42, },
+	{.center_freq = 5230, .hw_value = 46, },
+	{.center_freq = 5180, .hw_value = 36, },
+	{.center_freq = 5200, .hw_value = 40, },
+	{.center_freq = 5220, .hw_value = 44, },
+	{.center_freq = 5240, .hw_value = 48, },
+	{.center_freq = 5260, .hw_value = 52, },
+	{.center_freq = 5280, .hw_value = 56, },
+	{.center_freq = 5300, .hw_value = 60, },
+	{.center_freq = 5320, .hw_value = 64, },
+	{.center_freq = 5500, .hw_value = 100, },
+	{.center_freq = 5520, .hw_value = 104, },
+	{.center_freq = 5540, .hw_value = 108, },
+	{.center_freq = 5560, .hw_value = 112, },
+	{.center_freq = 5580, .hw_value = 116, },
+	{.center_freq = 5600, .hw_value = 120, },
+	{.center_freq = 5620, .hw_value = 124, },
+	{.center_freq = 5640, .hw_value = 128, },
+	{.center_freq = 5660, .hw_value = 132, },
+	{.center_freq = 5680, .hw_value = 136, },
+	{.center_freq = 5700, .hw_value = 140, },
+	{.center_freq = 5745, .hw_value = 149, },
+	{.center_freq = 5765, .hw_value = 153, },
+	{.center_freq = 5785, .hw_value = 157, },
+	{.center_freq = 5805, .hw_value = 161, },
+	{.center_freq = 5825, .hw_value = 165, },
+};
+
+static struct ieee80211_supported_band mwifiex_band_5ghz = {
+	.channels = mwifiex_channels_5ghz,
+	.n_channels = ARRAY_SIZE(mwifiex_channels_5ghz),
+	.bitrates = mwifiex_rates - 4,
+	.n_bitrates = ARRAY_SIZE(mwifiex_rates) + 4,
+};
+
+
+/* Supported crypto cipher suits to be advertised to cfg80211 */
+
+static const u32 mwifiex_cipher_suites[] = {
+	WLAN_CIPHER_SUITE_WEP40,
+	WLAN_CIPHER_SUITE_WEP104,
+	WLAN_CIPHER_SUITE_TKIP,
+	WLAN_CIPHER_SUITE_CCMP,
+};
+
+/*
+ * CFG802.11 operation handler for disconnection request.
+ *
+ * This function does not work when there is already a disconnection
+ * procedure going on.
+ */
+static int
+mwifiex_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
+			    u16 reason_code)
+{
+	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+
+	if (priv->disconnect)
+		return -EBUSY;
+
+	priv->disconnect = 1;
+	if (mwifiex_disconnect(priv, MWIFIEX_IOCTL_WAIT, NULL))
+		return -EFAULT;
+
+	wiphy_dbg(wiphy, "info: successfully disconnected from %pM:"
+		" reason code %d\n", priv->cfg_bssid, reason_code);
+
+	queue_work(priv->workqueue, &priv->cfg_workqueue);
+
+	return 0;
+}
+
+/*
+ * This function informs the CFG802.11 subsystem of a new IBSS.
+ *
+ * The following information are sent to the CFG802.11 subsystem
+ * to register the new IBSS. If we do not register the new IBSS,
+ * a kernel panic will result.
+ *      - SSID
+ *      - SSID length
+ *      - BSSID
+ *      - Channel
+ */
+static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv)
+{
+	int ret = 0;
+	struct ieee80211_channel *chan;
+	struct mwifiex_bss_info bss_info;
+	int ie_len = 0;
+	u8 ie_buf[IEEE80211_MAX_SSID_LEN + sizeof(struct ieee_types_header)];
+
+	ret = mwifiex_get_bss_info(priv, &bss_info);
+	if (ret)
+		return ret;
+
+	ie_buf[0] = WLAN_EID_SSID;
+	ie_buf[1] = bss_info.ssid.ssid_len;
+
+	memcpy(&ie_buf[sizeof(struct ieee_types_header)],
+			&bss_info.ssid.ssid,
+			bss_info.ssid.ssid_len);
+	ie_len = ie_buf[1] + sizeof(struct ieee_types_header);
+
+	chan = __ieee80211_get_channel(priv->wdev->wiphy,
+			ieee80211_channel_to_frequency(bss_info.bss_chan,
+						priv->curr_bss_params.band));
+
+	cfg80211_inform_bss(priv->wdev->wiphy, chan,
+		bss_info.bssid, 0, WLAN_CAPABILITY_IBSS,
+		0, ie_buf, ie_len, 0, GFP_KERNEL);
+	memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN);
+
+	return ret;
+}
+
+/*
+ * 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_scan_resp scan_resp;
+	struct mwifiex_bssdescriptor *scan_table;
+	int i, j;
+	struct ieee80211_channel *chan;
+	u8 *ie, *tmp, *ie_buf;
+	u32 ie_len;
+	u64 ts = 0;
+	u8 *beacon;
+	int beacon_size;
+	u8 element_id, element_len;
+
+	memset(&scan_resp, 0, sizeof(scan_resp));
+	if (mwifiex_get_scan_table(priv, MWIFIEX_IOCTL_WAIT, &scan_resp))
+		return -EFAULT;
+
+#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 = (struct mwifiex_bssdescriptor *) scan_resp.scan_table;
+	for (i = 0; i < scan_resp.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;
+				tmp = (u8 *) beacon;
+				memcpy(&ie[sizeof(struct ieee_types_header)],
+				       tmp + 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,
+					ts, 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
+ * validity checking on the provided parameters, disconnects from the
+ * current BSS (if any), sets up the association/scan parameters,
+ * including security settings, and performs specific SSID scan before
+ * trying to connect.
+ *
+ * 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.
+ */
+static int
+mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid,
+		       u8 *bssid, int mode, struct ieee80211_channel *channel,
+		       struct cfg80211_connect_params *sme, bool privacy)
+{
+	struct mwifiex_802_11_ssid req_ssid;
+	struct mwifiex_ssid_bssid ssid_bssid;
+	int ret = 0;
+	int auth_type = 0, pairwise_encrypt_mode = 0;
+	int group_encrypt_mode = 0;
+	int alg_is_wep = 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) {
+		dev_err(priv->adapter->dev, "invalid SSID - aborting\n");
+		return -EINVAL;
+	}
+
+	memcpy(req_ssid.ssid, ssid, ssid_len);
+	if (!req_ssid.ssid_len || req_ssid.ssid[0] < 0x20) {
+		dev_err(priv->adapter->dev, "invalid SSID - aborting\n");
+		return -EINVAL;
+	}
+
+	/* disconnect before try to associate */
+	mwifiex_disconnect(priv, MWIFIEX_IOCTL_WAIT, NULL);
+
+	if (channel)
+		ret = mwifiex_set_rf_channel(priv, channel,
+				mwifiex_channels_to_cfg80211_channel_type
+				(priv->adapter->chan_offset));
+
+	ret = mwifiex_set_encode(priv, NULL, 0, 0, 1);	/* Disable keys */
+
+	if (mode == NL80211_IFTYPE_ADHOC) {
+		/* "privacy" is set only for ad-hoc mode */
+		if (privacy) {
+			/*
+			 * Keep WLAN_CIPHER_SUITE_WEP104 for now so that
+			 * the firmware can find a matching network from the
+			 * scan. The cfg80211 does not give us the encryption
+			 * mode at this stage so just setting it to WEP here.
+			 */
+			priv->sec_info.encryption_mode =
+					WLAN_CIPHER_SUITE_WEP104;
+			priv->sec_info.authentication_mode =
+					NL80211_AUTHTYPE_OPEN_SYSTEM;
+		}
+
+		goto done;
+	}
+
+	/* Now handle infra mode. "sme" is valid for infra mode only */
+	if (sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC
+			|| sme->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM)
+		auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM;
+	else if (sme->auth_type == NL80211_AUTHTYPE_SHARED_KEY)
+		auth_type = NL80211_AUTHTYPE_SHARED_KEY;
+
+	if (sme->crypto.n_ciphers_pairwise) {
+		priv->sec_info.encryption_mode =
+						sme->crypto.ciphers_pairwise[0];
+		priv->sec_info.authentication_mode = auth_type;
+	}
+
+	if (sme->crypto.cipher_group) {
+		priv->sec_info.encryption_mode = sme->crypto.cipher_group;
+		priv->sec_info.authentication_mode = auth_type;
+	}
+	if (sme->ie)
+		ret = mwifiex_set_gen_ie(priv, sme->ie, sme->ie_len);
+
+	if (sme->key) {
+		alg_is_wep = mwifiex_is_alg_wep(pairwise_encrypt_mode)
+			| mwifiex_is_alg_wep(group_encrypt_mode);
+		if (alg_is_wep) {
+			dev_dbg(priv->adapter->dev,
+				"info: setting wep encryption"
+				" with key len %d\n", sme->key_len);
+			ret = mwifiex_set_encode(priv, sme->key, sme->key_len,
+							sme->key_idx, 0);
+		}
+	}
+done:
+	/* Do specific SSID scanning */
+	if (mwifiex_request_scan(priv, MWIFIEX_IOCTL_WAIT, &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, MWIFIEX_IOCTL_WAIT,
+					  &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;
+	}
+
+	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 (mwifiex_bss_start(priv, MWIFIEX_IOCTL_WAIT, &ssid_bssid))
+		return -EFAULT;
+
+	if (mode == NL80211_IFTYPE_ADHOC) {
+		/* Inform the BSS information to kernel, otherwise
+		 * kernel will give a panic after successful assoc */
+		if (mwifiex_cfg80211_inform_ibss_bss(priv))
+			return -EFAULT;
+	}
+
+	return ret;
+}
+
+/*
+ * CFG802.11 operation handler for association request.
+ *
+ * This function does not work when the current mode is set to Ad-Hoc, or
+ * when there is already an association procedure going on. The given BSS
+ * information is used to associate.
+ */
+static int
+mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
+			 struct cfg80211_connect_params *sme)
+{
+	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+	int ret = 0;
+
+	if (priv->assoc_request)
+		return -EBUSY;
+
+	if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
+		wiphy_err(wiphy, "received infra assoc request "
+				"when station is in ibss mode\n");
+		goto done;
+	}
+
+	priv->assoc_request = 1;
+
+	wiphy_dbg(wiphy, "info: Trying to associate to %s and bssid %pM\n",
+	       (char *) sme->ssid, sme->bssid);
+
+	ret = mwifiex_cfg80211_assoc(priv, sme->ssid_len, sme->ssid, sme->bssid,
+				     priv->bss_mode, sme->channel, sme, 0);
+
+done:
+	priv->assoc_result = ret;
+	queue_work(priv->workqueue, &priv->cfg_workqueue);
+	return ret;
+}
+
+/*
+ * CFG802.11 operation handler to join an IBSS.
+ *
+ * This function does not work in any mode other than Ad-Hoc, or if
+ * a join operation is already in progress.
+ */
+static int
+mwifiex_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
+			   struct cfg80211_ibss_params *params)
+{
+	struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
+	int ret = 0;
+
+	if (priv->ibss_join_request)
+		return -EBUSY;
+
+	if (priv->bss_mode != NL80211_IFTYPE_ADHOC) {
+		wiphy_err(wiphy, "request to join ibss received "
+				"when station is not in ibss mode\n");
+		goto done;
+	}
+
+	priv->ibss_join_request = 1;
+
+	wiphy_dbg(wiphy, "info: trying to join to %s and bssid %pM\n",
+	       (char *) params->ssid, params->bssid);
+
+	ret = mwifiex_cfg80211_assoc(priv, params->ssid_len, params->ssid,
+				params->bssid, priv->bss_mode,
+				params->channel, NULL, params->privacy);
+done:
+	priv->ibss_join_result = ret;
+	queue_work(priv->workqueue, &priv->cfg_workqueue);
+	return ret;
+}
+
+/*
+ * CFG802.11 operation handler to leave an IBSS.
+ *
+ * This function does not work if a leave operation is
+ * already in progress.
+ */
+static int
+mwifiex_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
+{
+	struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
+
+	if (priv->disconnect)
+		return -EBUSY;
+
+	priv->disconnect = 1;
+
+	wiphy_dbg(wiphy, "info: disconnecting from essid %pM\n",
+			priv->cfg_bssid);
+	if (mwifiex_disconnect(priv, MWIFIEX_IOCTL_WAIT, NULL))
+		return -EFAULT;
+
+	queue_work(priv->workqueue, &priv->cfg_workqueue);
+
+	return 0;
+}
+
+/*
+ * CFG802.11 operation handler for scan request.
+ *
+ * This function issues a scan request to the firmware based upon
+ * the user specified scan configuration. On successfull completion,
+ * it also informs the results.
+ */
+static int
+mwifiex_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev,
+		      struct cfg80211_scan_request *request)
+{
+	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+
+	wiphy_dbg(wiphy, "info: received scan request on %s\n", dev->name);
+
+	if (priv->scan_request && priv->scan_request != request)
+		return -EBUSY;
+
+	priv->scan_request = request;
+
+	queue_work(priv->workqueue, &priv->cfg_workqueue);
+	return 0;
+}
+
+/*
+ * This function sets up the CFG802.11 specific HT capability fields
+ * with default values.
+ *
+ * The following default values are set -
+ *      - HT Supported = True
+ *      - Maximum AMPDU length factor = 0x3
+ *      - Minimum AMPDU spacing = 0x6
+ *      - HT Capabilities map = IEEE80211_HT_CAP_SUP_WIDTH_20_40 (0x0002)
+ *      - MCS information, Rx mask = 0xff
+ *      - MCD information, Tx parameters = IEEE80211_HT_MCS_TX_DEFINED (0x01)
+ */
+static void
+mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info,
+		      struct mwifiex_private *priv)
+{
+	int rx_mcs_supp;
+	struct ieee80211_mcs_info mcs_set;
+	u8 *mcs = (u8 *)&mcs_set;
+	struct mwifiex_adapter *adapter = priv->adapter;
+
+	ht_info->ht_supported = true;
+	ht_info->ampdu_factor = 0x3;
+	ht_info->ampdu_density = 0x6;
+
+	memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
+	ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+
+	rx_mcs_supp = GET_RXMCSSUPP(priv->adapter->hw_dev_mcs_support);
+	/* Set MCS for 1x1 */
+	memset(mcs, 0xff, rx_mcs_supp);
+	/* Clear all the other values */
+	memset(&mcs[rx_mcs_supp], 0,
+			sizeof(struct ieee80211_mcs_info) - rx_mcs_supp);
+	if (priv->bss_mode == NL80211_IFTYPE_STATION ||
+			ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap))
+		/* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */
+		SETHT_MCS32(mcs_set.rx_mask);
+
+	memcpy((u8 *) &ht_info->mcs, mcs, sizeof(struct ieee80211_mcs_info));
+
+	ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+}
+
+/* station cfg80211 operations */
+static struct cfg80211_ops mwifiex_cfg80211_ops = {
+	.change_virtual_intf = mwifiex_cfg80211_change_virtual_intf,
+	.scan = mwifiex_cfg80211_scan,
+	.connect = mwifiex_cfg80211_connect,
+	.disconnect = mwifiex_cfg80211_disconnect,
+	.get_station = mwifiex_cfg80211_get_station,
+	.set_wiphy_params = mwifiex_cfg80211_set_wiphy_params,
+	.set_channel = mwifiex_cfg80211_set_channel,
+	.join_ibss = mwifiex_cfg80211_join_ibss,
+	.leave_ibss = mwifiex_cfg80211_leave_ibss,
+	.add_key = mwifiex_cfg80211_add_key,
+	.del_key = mwifiex_cfg80211_del_key,
+	.set_default_key = mwifiex_cfg80211_set_default_key,
+	.set_power_mgmt = mwifiex_cfg80211_set_power_mgmt,
+	.set_tx_power = mwifiex_cfg80211_set_tx_power,
+};
+
+/*
+ * This function registers the device with CFG802.11 subsystem.
+ *
+ * The function creates the wireless device/wiphy, populates it with
+ * default parameters and handler function pointers, and finally
+ * registers the device.
+ */
+int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac,
+			      struct mwifiex_private *priv)
+{
+	int ret = 0;
+	void *wdev_priv = NULL;
+	struct wireless_dev *wdev;
+
+	wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
+	if (!wdev) {
+		dev_err(priv->adapter->dev, "%s: allocating wireless device\n",
+						__func__);
+		return -ENOMEM;
+	}
+	wdev->wiphy =
+		wiphy_new(&mwifiex_cfg80211_ops,
+			  sizeof(struct mwifiex_private *));
+	if (!wdev->wiphy)
+		return -ENOMEM;
+	wdev->iftype = NL80211_IFTYPE_STATION;
+	wdev->wiphy->max_scan_ssids = 10;
+	wdev->wiphy->interface_modes =
+		BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
+	wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &mwifiex_band_2ghz;
+	wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &mwifiex_band_5ghz;
+
+	/* Initialize cipher suits */
+	wdev->wiphy->cipher_suites = mwifiex_cipher_suites;
+	wdev->wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites);
+
+	/* Initialize parameters for 2GHz band */
+
+	mwifiex_setup_ht_caps(&wdev->wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap,
+									priv);
+	mwifiex_setup_ht_caps(&wdev->wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap,
+									priv);
+
+	memcpy(wdev->wiphy->perm_addr, mac, 6);
+	wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+
+	/* We are using custom domains */
+	wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
+
+	wdev->wiphy->reg_notifier = mwifiex_reg_notifier;
+
+	/* Set struct mwifiex_private pointer in wiphy_priv */
+	wdev_priv = wiphy_priv(wdev->wiphy);
+
+	*(unsigned long *) wdev_priv = (unsigned long) priv;
+
+	ret = wiphy_register(wdev->wiphy);
+	if (ret < 0) {
+		dev_err(priv->adapter->dev, "%s: registering cfg80211 device\n",
+						__func__);
+		wiphy_free(wdev->wiphy);
+		return ret;
+	} else {
+		dev_dbg(priv->adapter->dev,
+				"info: successfully registered wiphy device\n");
+	}
+
+	dev_net_set(dev, wiphy_net(wdev->wiphy));
+	dev->ieee80211_ptr = wdev;
+	memcpy(dev->dev_addr, wdev->wiphy->perm_addr, 6);
+	memcpy(dev->perm_addr, wdev->wiphy->perm_addr, 6);
+	SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy));
+	priv->wdev = wdev;
+
+	dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
+	dev->watchdog_timeo = MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT;
+	dev->hard_header_len += MWIFIEX_MIN_DATA_HEADER_LEN;
+
+	return ret;
+}
+
+/*
+ * This function handles the result of different pending network operations.
+ *
+ * The following operations are handled and CFG802.11 subsystem is
+ * notified accordingly -
+ *      - Scan request completion
+ *      - Association request completion
+ *      - IBSS join request completion
+ *      - Disconnect request completion
+ */
+void
+mwifiex_cfg80211_results(struct work_struct *work)
+{
+	struct mwifiex_private *priv =
+		container_of(work, struct mwifiex_private, cfg_workqueue);
+	struct mwifiex_user_scan_cfg *scan_req;
+	int ret = 0, i;
+	struct ieee80211_channel *chan;
+
+	if (priv->scan_request) {
+		scan_req = kzalloc(sizeof(struct mwifiex_user_scan_cfg),
+				   GFP_KERNEL);
+		if (!scan_req) {
+			dev_err(priv->adapter->dev, "failed to alloc "
+						    "scan_req\n");
+			return;
+		}
+		for (i = 0; i < priv->scan_request->n_ssids; i++) {
+			memcpy(scan_req->ssid_list[i].ssid,
+					priv->scan_request->ssids[i].ssid,
+					priv->scan_request->ssids[i].ssid_len);
+			scan_req->ssid_list[i].max_len =
+					priv->scan_request->ssids[i].ssid_len;
+		}
+		for (i = 0; i < priv->scan_request->n_channels; i++) {
+			chan = priv->scan_request->channels[i];
+			scan_req->chan_list[i].chan_number = chan->hw_value;
+			scan_req->chan_list[i].radio_type = chan->band;
+			if (chan->flags & IEEE80211_CHAN_DISABLED)
+				scan_req->chan_list[i].scan_type =
+					MWIFIEX_SCAN_TYPE_PASSIVE;
+			else
+				scan_req->chan_list[i].scan_type =
+					MWIFIEX_SCAN_TYPE_ACTIVE;
+			scan_req->chan_list[i].scan_time = 0;
+		}
+		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__);
+		cfg80211_scan_done(priv->scan_request,
+				(priv->scan_result_status < 0));
+		priv->scan_request = NULL;
+		kfree(scan_req);
+	}
+
+	if (priv->assoc_request) {
+		if (!priv->assoc_result) {
+			cfg80211_connect_result(priv->netdev, priv->cfg_bssid,
+						NULL, 0, NULL, 0,
+						WLAN_STATUS_SUCCESS,
+						GFP_KERNEL);
+			dev_dbg(priv->adapter->dev,
+				"info: associated to bssid %pM successfully\n",
+			       priv->cfg_bssid);
+		} else {
+			dev_dbg(priv->adapter->dev,
+				"info: association to bssid %pM failed\n",
+			       priv->cfg_bssid);
+			memset(priv->cfg_bssid, 0, ETH_ALEN);
+		}
+		priv->assoc_request = 0;
+		priv->assoc_result = 0;
+	}
+
+	if (priv->ibss_join_request) {
+		if (!priv->ibss_join_result) {
+			cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid,
+					     GFP_KERNEL);
+			dev_dbg(priv->adapter->dev,
+				"info: joined/created adhoc network with bssid"
+					" %pM successfully\n", priv->cfg_bssid);
+		} else {
+			dev_dbg(priv->adapter->dev,
+				"info: failed creating/joining adhoc network\n");
+		}
+		priv->ibss_join_request = 0;
+		priv->ibss_join_result = 0;
+	}
+
+	if (priv->disconnect) {
+		memset(priv->cfg_bssid, 0, ETH_ALEN);
+		priv->disconnect = 0;
+	}
+
+	return;
+}
diff --git a/drivers/net/wireless/mwifiex/cfg80211.h b/drivers/net/wireless/mwifiex/cfg80211.h
new file mode 100644
index 0000000..c4db8f3
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/cfg80211.h
@@ -0,0 +1,31 @@
+/*
+ * Marvell Wireless LAN device driver: CFG80211
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#ifndef __MWIFIEX_CFG80211__
+#define __MWIFIEX_CFG80211__
+
+#include <net/cfg80211.h>
+
+#include "main.h"
+
+int mwifiex_register_cfg80211(struct net_device *, u8 *,
+				struct mwifiex_private *);
+
+void mwifiex_cfg80211_results(struct work_struct *work);
+#endif
diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c
new file mode 100644
index 0000000..07187a4
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/cfp.c
@@ -0,0 +1,367 @@
+/*
+ * Marvell Wireless LAN device driver: Channel, Frequence and Power
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "cfg80211.h"
+
+/* 100mW */
+#define MWIFIEX_TX_PWR_DEFAULT     20
+/* 100mW */
+#define MWIFIEX_TX_PWR_US_DEFAULT      20
+/* 50mW */
+#define MWIFIEX_TX_PWR_JP_DEFAULT      16
+/* 100mW */
+#define MWIFIEX_TX_PWR_FR_100MW        20
+/* 10mW */
+#define MWIFIEX_TX_PWR_FR_10MW         10
+/* 100mW */
+#define MWIFIEX_TX_PWR_EMEA_DEFAULT    20
+
+static u8 adhoc_rates_b[B_SUPPORTED_RATES] = { 0x82, 0x84, 0x8b, 0x96, 0 };
+
+static u8 adhoc_rates_g[G_SUPPORTED_RATES] = { 0x8c, 0x12, 0x98, 0x24,
+					       0xb0, 0x48, 0x60, 0x6c, 0 };
+
+static u8 adhoc_rates_bg[BG_SUPPORTED_RATES] = { 0x82, 0x84, 0x8b, 0x96,
+						 0x0c, 0x12, 0x18, 0x24,
+						 0x30, 0x48, 0x60, 0x6c, 0 };
+
+static u8 adhoc_rates_a[A_SUPPORTED_RATES] = { 0x8c, 0x12, 0x98, 0x24,
+					       0xb0, 0x48, 0x60, 0x6c, 0 };
+u8 supported_rates_a[A_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24,
+					0xb0, 0x48, 0x60, 0x6c, 0 };
+static u16 mwifiex_data_rates[MWIFIEX_SUPPORTED_RATES_EXT] = { 0x02, 0x04,
+					0x0B, 0x16, 0x00, 0x0C, 0x12, 0x18,
+					0x24, 0x30, 0x48, 0x60, 0x6C, 0x90,
+					0x0D, 0x1A, 0x27, 0x34, 0x4E, 0x68,
+					0x75, 0x82, 0x0C, 0x1B, 0x36, 0x51,
+					0x6C, 0xA2, 0xD8, 0xF3, 0x10E, 0x00 };
+
+u8 supported_rates_b[B_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x16, 0 };
+
+u8 supported_rates_g[G_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24,
+					0x30, 0x48, 0x60, 0x6c, 0 };
+
+u8 supported_rates_bg[BG_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x0c,
+					0x12, 0x16, 0x18, 0x24, 0x30, 0x48,
+					0x60, 0x6c, 0 };
+
+u16 region_code_index[MWIFIEX_MAX_REGION_CODE] = { 0x10, 0x20, 0x30,
+						0x32, 0x40, 0x41, 0xff };
+
+u8 supported_rates_n[N_SUPPORTED_RATES] = { 0x02, 0x04, 0 };
+
+/*
+ * This function maps an index in supported rates table into
+ * the corresponding data rate.
+ */
+u32 mwifiex_index_to_data_rate(struct mwifiex_adapter *adapter, u8 index,
+			       u8 ht_info)
+{
+	u16 mcs_rate[4][8] = {
+		{0x1b, 0x36, 0x51, 0x6c, 0xa2, 0xd8, 0xf3, 0x10e}
+	,			/* LG 40M */
+	{0x1e, 0x3c, 0x5a, 0x78, 0xb4, 0xf0, 0x10e, 0x12c}
+	,			/* SG 40M */
+	{0x0d, 0x1a, 0x27, 0x34, 0x4e, 0x68, 0x75, 0x82}
+	,			/* LG 20M */
+	{0x0e, 0x1c, 0x2b, 0x39, 0x56, 0x73, 0x82, 0x90}
+	};			/* SG 20M */
+
+	u32 rate;
+
+	if (ht_info & BIT(0)) {
+		if (index == MWIFIEX_RATE_BITMAP_MCS0) {
+			if (ht_info & BIT(2))
+				rate = 0x0D;	/* MCS 32 SGI rate */
+			else
+				rate = 0x0C;	/* MCS 32 LGI rate */
+		} else if (index < 8) {
+			if (ht_info & BIT(1)) {
+				if (ht_info & BIT(2))
+					/* SGI, 40M */
+					rate = mcs_rate[1][index];
+				else
+					/* LGI, 40M */
+					rate = mcs_rate[0][index];
+			} else {
+				if (ht_info & BIT(2))
+					/* SGI, 20M */
+					rate = mcs_rate[3][index];
+				else
+					/* LGI, 20M */
+					rate = mcs_rate[2][index];
+			}
+		} else
+			rate = mwifiex_data_rates[0];
+	} else {
+		if (index >= MWIFIEX_SUPPORTED_RATES_EXT)
+			index = 0;
+		rate = mwifiex_data_rates[index];
+	}
+	return rate;
+}
+
+/*
+ * This function maps a data rate value into corresponding index in supported
+ * rates table.
+ */
+u8 mwifiex_data_rate_to_index(struct mwifiex_adapter *adapter, u32 rate)
+{
+	u16 *ptr;
+
+	if (rate) {
+		ptr = memchr(mwifiex_data_rates, rate,
+				sizeof(mwifiex_data_rates));
+		if (ptr)
+			return (u8) (ptr - mwifiex_data_rates);
+	}
+	return 0;
+}
+
+/*
+ * This function returns the current active data rates.
+ *
+ * The result may vary depending upon connection status.
+ */
+u32 mwifiex_get_active_data_rates(struct mwifiex_private *priv, u8 *rates)
+{
+	u32 k;
+
+	if (!priv->media_connected)
+		k = mwifiex_get_supported_rates(priv, rates);
+	else
+		k = mwifiex_copy_rates(rates, 0,
+				       priv->curr_bss_params.data_rates,
+				       priv->curr_bss_params.num_of_rates);
+
+	return k;
+}
+
+/*
+ * This function locates the Channel-Frequency-Power triplet based upon
+ * band and channel parameters.
+ */
+struct mwifiex_chan_freq_power *
+mwifiex_get_cfp_by_band_and_channel_from_cfg80211(struct mwifiex_private
+						  *priv, u8 band, u16 channel)
+{
+	struct mwifiex_chan_freq_power *cfp = NULL;
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_channel *ch;
+	int i;
+
+	if (mwifiex_band_to_radio_type(band) == HostCmd_SCAN_RADIO_TYPE_BG)
+		sband = priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ];
+	else
+		sband = priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ];
+
+	if (!sband) {
+		dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d"
+				" & channel %d\n", __func__, band, channel);
+		return cfp;
+	}
+
+	for (i = 0; i < sband->n_channels; i++) {
+		ch = &sband->channels[i];
+		if (((ch->hw_value == channel) ||
+			(channel == FIRST_VALID_CHANNEL))
+			&& !(ch->flags & IEEE80211_CHAN_DISABLED)) {
+			priv->cfp.channel = channel;
+			priv->cfp.freq = ch->center_freq;
+			priv->cfp.max_tx_power = ch->max_power;
+			cfp = &priv->cfp;
+			break;
+		}
+	}
+	if (i == sband->n_channels)
+		dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d"
+				" & channel %d\n", __func__, band, channel);
+
+	return cfp;
+}
+
+/*
+ * This function locates the Channel-Frequency-Power triplet based upon
+ * band and frequency parameters.
+ */
+struct mwifiex_chan_freq_power *
+mwifiex_get_cfp_by_band_and_freq_from_cfg80211(struct mwifiex_private *priv,
+					       u8 band, u32 freq)
+{
+	struct mwifiex_chan_freq_power *cfp = NULL;
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_channel *ch;
+	int i;
+
+	if (mwifiex_band_to_radio_type(band) == HostCmd_SCAN_RADIO_TYPE_BG)
+		sband = priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ];
+	else
+		sband = priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ];
+
+	if (!sband) {
+		dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d"
+				" & freq %d\n", __func__, band, freq);
+		return cfp;
+	}
+
+	for (i = 0; i < sband->n_channels; i++) {
+		ch = &sband->channels[i];
+		if ((ch->center_freq == freq) &&
+			!(ch->flags & IEEE80211_CHAN_DISABLED)) {
+			priv->cfp.channel = ch->hw_value;
+			priv->cfp.freq = freq;
+			priv->cfp.max_tx_power = ch->max_power;
+			cfp = &priv->cfp;
+			break;
+		}
+	}
+	if (i == sband->n_channels)
+		dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d"
+				" & freq %d\n", __func__, band, freq);
+
+	return cfp;
+}
+
+/*
+ * This function checks if the data rate is set to auto.
+ */
+u8
+mwifiex_is_rate_auto(struct mwifiex_private *priv)
+{
+	u32 i;
+	int rate_num = 0;
+
+	for (i = 0; i < ARRAY_SIZE(priv->bitmap_rates); i++)
+		if (priv->bitmap_rates[i])
+			rate_num++;
+
+	if (rate_num > 1)
+		return true;
+	else
+		return false;
+}
+
+/*
+ * This function converts rate bitmap into rate index.
+ */
+int
+mwifiex_get_rate_index(struct mwifiex_adapter *adapter, u16 *rate_bitmap,
+		       int size)
+{
+	int i;
+
+	for (i = 0; i < size * 8; i++)
+		if (rate_bitmap[i / 16] & (1 << (i % 16)))
+			return i;
+
+	return 0;
+}
+
+/*
+ * This function gets the supported data rates.
+ *
+ * The function works in both Ad-Hoc and infra mode by printing the
+ * band and returning the data rates.
+ */
+u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
+{
+	u32 k = 0;
+	struct mwifiex_adapter *adapter = priv->adapter;
+	if (priv->bss_mode == NL80211_IFTYPE_STATION) {
+		switch (adapter->config_bands) {
+		case BAND_B:
+			dev_dbg(adapter->dev, "info: infra band=%d "
+				"supported_rates_b\n", adapter->config_bands);
+			k = mwifiex_copy_rates(rates, k, supported_rates_b,
+					       sizeof(supported_rates_b));
+			break;
+		case BAND_G:
+		case BAND_G | BAND_GN:
+			dev_dbg(adapter->dev, "info: infra band=%d "
+				"supported_rates_g\n", adapter->config_bands);
+			k = mwifiex_copy_rates(rates, k, supported_rates_g,
+					       sizeof(supported_rates_g));
+			break;
+		case BAND_B | BAND_G:
+		case BAND_A | BAND_B | BAND_G:
+		case BAND_A | BAND_B:
+		case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN:
+		case BAND_B | BAND_G | BAND_GN:
+			dev_dbg(adapter->dev, "info: infra band=%d "
+				"supported_rates_bg\n", adapter->config_bands);
+			k = mwifiex_copy_rates(rates, k, supported_rates_bg,
+					       sizeof(supported_rates_bg));
+			break;
+		case BAND_A:
+		case BAND_A | BAND_G:
+			dev_dbg(adapter->dev, "info: infra band=%d "
+				"supported_rates_a\n", adapter->config_bands);
+			k = mwifiex_copy_rates(rates, k, supported_rates_a,
+					       sizeof(supported_rates_a));
+			break;
+		case BAND_A | BAND_AN:
+		case BAND_A | BAND_G | BAND_AN | BAND_GN:
+			dev_dbg(adapter->dev, "info: infra band=%d "
+				"supported_rates_a\n", adapter->config_bands);
+			k = mwifiex_copy_rates(rates, k, supported_rates_a,
+					       sizeof(supported_rates_a));
+			break;
+		case BAND_GN:
+			dev_dbg(adapter->dev, "info: infra band=%d "
+				"supported_rates_n\n", adapter->config_bands);
+			k = mwifiex_copy_rates(rates, k, supported_rates_n,
+					       sizeof(supported_rates_n));
+			break;
+		}
+	} else {
+		/* Ad-hoc mode */
+		switch (adapter->adhoc_start_band) {
+		case BAND_B:
+			dev_dbg(adapter->dev, "info: adhoc B\n");
+			k = mwifiex_copy_rates(rates, k, adhoc_rates_b,
+					       sizeof(adhoc_rates_b));
+			break;
+		case BAND_G:
+		case BAND_G | BAND_GN:
+			dev_dbg(adapter->dev, "info: adhoc G only\n");
+			k = mwifiex_copy_rates(rates, k, adhoc_rates_g,
+					       sizeof(adhoc_rates_g));
+			break;
+		case BAND_B | BAND_G:
+		case BAND_B | BAND_G | BAND_GN:
+			dev_dbg(adapter->dev, "info: adhoc BG\n");
+			k = mwifiex_copy_rates(rates, k, adhoc_rates_bg,
+					       sizeof(adhoc_rates_bg));
+			break;
+		case BAND_A:
+		case BAND_A | BAND_AN:
+			dev_dbg(adapter->dev, "info: adhoc A\n");
+			k = mwifiex_copy_rates(rates, k, adhoc_rates_a,
+					       sizeof(adhoc_rates_a));
+			break;
+		}
+	}
+
+	return k;
+}
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c
new file mode 100644
index 0000000..a9aeb31
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/cmdevt.c
@@ -0,0 +1,1459 @@
+/*
+ * Marvell Wireless LAN device driver: commands and events
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+#include "11n.h"
+
+/*
+ * This function initializes a command node.
+ *
+ * The actual allocation of the node is not done by this function. It only
+ * initiates a node by filling it with default parameters. Similarly,
+ * allocation of the different buffers used (IOCTL buffer, data buffer) are
+ * not done by this function either.
+ */
+static void
+mwifiex_init_cmd_node(struct mwifiex_private *priv,
+		      struct cmd_ctrl_node *cmd_node,
+		      u32 cmd_oid, void *wait_queue, void *data_buf)
+{
+	cmd_node->priv = priv;
+	cmd_node->cmd_oid = cmd_oid;
+	cmd_node->wq_buf = wait_queue;
+	cmd_node->data_buf = data_buf;
+	cmd_node->cmd_skb = cmd_node->skb;
+}
+
+/*
+ * This function returns a command node from the free queue depending upon
+ * availability.
+ */
+static struct cmd_ctrl_node *
+mwifiex_get_cmd_node(struct mwifiex_adapter *adapter)
+{
+	struct cmd_ctrl_node *cmd_node;
+	unsigned long flags;
+
+	spin_lock_irqsave(&adapter->cmd_free_q_lock, flags);
+	if (list_empty(&adapter->cmd_free_q)) {
+		dev_err(adapter->dev, "GET_CMD_NODE: cmd node not available\n");
+		spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags);
+		return NULL;
+	}
+	cmd_node = list_first_entry(&adapter->cmd_free_q,
+			struct cmd_ctrl_node, list);
+	list_del(&cmd_node->list);
+	spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags);
+
+	return cmd_node;
+}
+
+/*
+ * This function cleans up a command node.
+ *
+ * The function resets the fields including the buffer pointers.
+ * This function does not try to free the buffers. They must be
+ * freed before calling this function.
+ *
+ * This function will however call the receive completion callback
+ * in case a response buffer is still available before resetting
+ * the pointer.
+ */
+static void
+mwifiex_clean_cmd_node(struct mwifiex_adapter *adapter,
+		       struct cmd_ctrl_node *cmd_node)
+{
+	cmd_node->cmd_oid = 0;
+	cmd_node->cmd_flag = 0;
+	cmd_node->wq_buf = NULL;
+	cmd_node->data_buf = NULL;
+
+	if (cmd_node->resp_skb) {
+		mwifiex_recv_complete(adapter, cmd_node->resp_skb, 0);
+		cmd_node->resp_skb = NULL;
+	}
+
+	return;
+}
+
+/*
+ * This function returns a command node from the pending queue which
+ * matches the given IOCTL request.
+ */
+static struct cmd_ctrl_node *
+mwifiex_get_pending_ioctl_cmd(struct mwifiex_adapter *adapter,
+			      struct mwifiex_wait_queue *wait_queue)
+{
+	unsigned long flags;
+	struct cmd_ctrl_node *cmd_node;
+
+	spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
+	list_for_each_entry(cmd_node, &adapter->cmd_pending_q, list) {
+		if (cmd_node->wq_buf == wait_queue) {
+			spin_unlock_irqrestore(&adapter->cmd_pending_q_lock,
+					       flags);
+			return cmd_node;
+		}
+	}
+	spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
+
+	return NULL;
+}
+
+/*
+ * This function sends a host command to the firmware.
+ *
+ * The function copies the host command into the driver command
+ * buffer, which will be transferred to the firmware later by the
+ * main thread.
+ */
+static int mwifiex_cmd_host_cmd(struct mwifiex_private *priv,
+				struct host_cmd_ds_command *cmd, void *data_buf)
+{
+	struct mwifiex_ds_misc_cmd *pcmd_ptr =
+		(struct mwifiex_ds_misc_cmd *) data_buf;
+
+	/* Copy the HOST command to command buffer */
+	memcpy((void *) cmd, pcmd_ptr->cmd, pcmd_ptr->len);
+	dev_dbg(priv->adapter->dev, "cmd: host cmd size = %d\n", pcmd_ptr->len);
+	return 0;
+}
+
+/*
+ * This function downloads a command to the firmware.
+ *
+ * The function performs sanity tests, sets the command sequence
+ * number and size, converts the header fields to CPU format before
+ * sending. Afterwards, it logs the command ID and action for debugging
+ * and sets up the command timeout timer.
+ */
+static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
+				  struct cmd_ctrl_node *cmd_node)
+{
+
+	struct mwifiex_adapter *adapter = priv->adapter;
+	int ret = 0;
+	struct host_cmd_ds_command *host_cmd;
+	struct mwifiex_wait_queue *wait_queue = NULL;
+	uint16_t cmd_code;
+	uint16_t cmd_size;
+	struct timeval tstamp;
+	unsigned long flags;
+
+	if (!adapter || !cmd_node)
+		return -1;
+
+	host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data);
+	if (cmd_node->wq_buf)
+		wait_queue = (struct mwifiex_wait_queue *) cmd_node->wq_buf;
+
+	/* Sanity test */
+	if (host_cmd == NULL || host_cmd->size == 0) {
+		dev_err(adapter->dev, "DNLD_CMD: host_cmd is null"
+			" or cmd size is 0, not sending\n");
+		if (wait_queue)
+			wait_queue->status = MWIFIEX_ERROR_CMD_DNLD_FAIL;
+		mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+		return -1;
+	}
+
+	/* Set command sequence number */
+	adapter->seq_num++;
+	host_cmd->seq_num = cpu_to_le16(HostCmd_SET_SEQ_NO_BSS_INFO
+			    (adapter->seq_num, cmd_node->priv->bss_num,
+			     cmd_node->priv->bss_type));
+
+	spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+	adapter->curr_cmd = cmd_node;
+	spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+
+	cmd_code = le16_to_cpu(host_cmd->command);
+	cmd_size = le16_to_cpu(host_cmd->size);
+
+	skb_trim(cmd_node->cmd_skb, cmd_size);
+
+	do_gettimeofday(&tstamp);
+	dev_dbg(adapter->dev, "cmd: DNLD_CMD: (%lu.%lu): %#x, act %#x, len %d,"
+		" seqno %#x\n",
+		tstamp.tv_sec, tstamp.tv_usec, cmd_code,
+	       le16_to_cpu(*(__le16 *) ((u8 *) host_cmd + S_DS_GEN)), cmd_size,
+	       le16_to_cpu(host_cmd->seq_num));
+
+	skb_push(cmd_node->cmd_skb, INTF_HEADER_LEN);
+
+	ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD,
+					     cmd_node->cmd_skb->data,
+					     cmd_node->cmd_skb->len, NULL);
+
+	if (ret == -1) {
+		dev_err(adapter->dev, "DNLD_CMD: host to card failed\n");
+		if (wait_queue)
+			wait_queue->status = MWIFIEX_ERROR_CMD_DNLD_FAIL;
+		mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
+
+		spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+		adapter->curr_cmd = NULL;
+		spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+
+		adapter->dbg.num_cmd_host_to_card_failure++;
+		return -1;
+	}
+
+	/* Save the last command id and action to debug log */
+	adapter->dbg.last_cmd_index =
+		(adapter->dbg.last_cmd_index + 1) % DBG_CMD_NUM;
+	adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index] = cmd_code;
+	adapter->dbg.last_cmd_act[adapter->dbg.last_cmd_index] =
+		le16_to_cpu(*(__le16 *) ((u8 *) host_cmd + S_DS_GEN));
+
+	/* Clear BSS_NO_BITS from HostCmd */
+	cmd_code &= HostCmd_CMD_ID_MASK;
+
+	/* Setup the timer after transmit command */
+	mod_timer(&adapter->cmd_timer,
+		jiffies + (MWIFIEX_TIMER_10S * HZ) / 1000);
+
+	return 0;
+}
+
+/*
+ * This function downloads a sleep confirm command to the firmware.
+ *
+ * The function performs sanity tests, sets the command sequence
+ * number and size, converts the header fields to CPU format before
+ * sending.
+ *
+ * No responses are needed for sleep confirm command.
+ */
+static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter)
+{
+	int ret = 0;
+	u16 cmd_len = 0;
+	struct mwifiex_private *priv;
+	struct mwifiex_opt_sleep_confirm_buffer *sleep_cfm_buf =
+				(struct mwifiex_opt_sleep_confirm_buffer *)
+				adapter->sleep_cfm->data;
+	cmd_len = sizeof(struct mwifiex_opt_sleep_confirm);
+	priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
+
+	sleep_cfm_buf->ps_cfm_sleep.seq_num =
+		cpu_to_le16((HostCmd_SET_SEQ_NO_BSS_INFO
+					(adapter->seq_num, priv->bss_num,
+					 priv->bss_type)));
+	adapter->seq_num++;
+
+	ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD,
+					     adapter->sleep_cfm->data,
+					     adapter->sleep_cfm->len +
+					     INTF_HEADER_LEN, NULL);
+
+	if (ret == -1) {
+		dev_err(adapter->dev, "SLEEP_CFM: failed\n");
+		adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure++;
+		return -1;
+	}
+	if (GET_BSS_ROLE(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY))
+			== MWIFIEX_BSS_ROLE_STA) {
+		if (!sleep_cfm_buf->ps_cfm_sleep.resp_ctrl)
+			/* Response is not needed for sleep
+			   confirm command */
+			adapter->ps_state = PS_STATE_SLEEP;
+		else
+			adapter->ps_state = PS_STATE_SLEEP_CFM;
+
+		if (!sleep_cfm_buf->ps_cfm_sleep.resp_ctrl
+				&& (adapter->is_hs_configured
+					&& !adapter->sleep_period.period)) {
+			adapter->pm_wakeup_card_req = true;
+			mwifiex_hs_activated_event(mwifiex_get_priv(adapter,
+						MWIFIEX_BSS_ROLE_STA), true);
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * This function allocates the command buffers and links them to
+ * the command free queue.
+ *
+ * The driver uses a pre allocated number of command buffers, which
+ * are created at driver initializations and freed at driver cleanup.
+ * Every command needs to obtain a command buffer from this pool before
+ * it can be issued. The command free queue lists the command buffers
+ * currently free to use, while the command pending queue lists the
+ * command buffers already in use and awaiting handling. Command buffers
+ * are returned to the free queue after use.
+ */
+int mwifiex_alloc_cmd_buffer(struct mwifiex_adapter *adapter)
+{
+	struct cmd_ctrl_node *cmd_array;
+	u32 buf_size;
+	u32 i;
+
+	/* Allocate and initialize struct cmd_ctrl_node */
+	buf_size = sizeof(struct cmd_ctrl_node) * MWIFIEX_NUM_OF_CMD_BUFFER;
+	cmd_array = kzalloc(buf_size, GFP_KERNEL);
+	if (!cmd_array) {
+		dev_err(adapter->dev, "%s: failed to alloc cmd_array\n",
+				__func__);
+		return -1;
+	}
+
+	adapter->cmd_pool = cmd_array;
+	memset(adapter->cmd_pool, 0, buf_size);
+
+	/* Allocate and initialize command buffers */
+	for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++) {
+		cmd_array[i].skb = dev_alloc_skb(MWIFIEX_SIZE_OF_CMD_BUFFER);
+		if (!cmd_array[i].skb) {
+			dev_err(adapter->dev, "ALLOC_CMD_BUF: out of memory\n");
+			return -1;
+		}
+	}
+
+	for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++)
+		mwifiex_insert_cmd_to_free_q(adapter, &cmd_array[i]);
+
+	return 0;
+}
+
+/*
+ * This function frees the command buffers.
+ *
+ * The function calls the completion callback for all the command
+ * buffers that still have response buffers associated with them.
+ */
+int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter)
+{
+	struct cmd_ctrl_node *cmd_array;
+	u32 i;
+
+	/* Need to check if cmd pool is allocated or not */
+	if (!adapter->cmd_pool) {
+		dev_dbg(adapter->dev, "info: FREE_CMD_BUF: cmd_pool is null\n");
+		return 0;
+	}
+
+	cmd_array = adapter->cmd_pool;
+
+	/* Release shared memory buffers */
+	for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++) {
+		if (cmd_array[i].skb) {
+			dev_dbg(adapter->dev, "cmd: free cmd buffer %d\n", i);
+			dev_kfree_skb_any(cmd_array[i].skb);
+		}
+		if (!cmd_array[i].resp_skb)
+			continue;
+		mwifiex_recv_complete(adapter, cmd_array[i].resp_skb, 0);
+	}
+	/* Release struct cmd_ctrl_node */
+	if (adapter->cmd_pool) {
+		dev_dbg(adapter->dev, "cmd: free cmd pool\n");
+		kfree(adapter->cmd_pool);
+		adapter->cmd_pool = NULL;
+	}
+
+	return 0;
+}
+
+/*
+ * This function handles events generated by firmware.
+ *
+ * Event body of events received from firmware are not used (though they are
+ * saved), only the event ID is used. Some events are re-invoked by
+ * the driver, with a new event body.
+ *
+ * After processing, the function calls the completion callback
+ * for cleanup.
+ */
+int mwifiex_process_event(struct mwifiex_adapter *adapter)
+{
+	int ret = 0;
+	struct mwifiex_private *priv =
+		mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
+	struct sk_buff *skb = adapter->event_skb;
+	u32 eventcause = adapter->event_cause;
+	struct timeval tstamp;
+	struct mwifiex_rxinfo *rx_info = NULL;
+
+	/* Save the last event to debug log */
+	adapter->dbg.last_event_index =
+		(adapter->dbg.last_event_index + 1) % DBG_CMD_NUM;
+	adapter->dbg.last_event[adapter->dbg.last_event_index] =
+		(u16) eventcause;
+
+	/* Get BSS number and corresponding priv */
+	priv = mwifiex_get_priv_by_id(adapter, EVENT_GET_BSS_NUM(eventcause),
+				      EVENT_GET_BSS_TYPE(eventcause));
+	if (!priv)
+		priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
+	/* Clear BSS_NO_BITS from event */
+	eventcause &= EVENT_ID_MASK;
+	adapter->event_cause = eventcause;
+
+	if (skb) {
+		rx_info = MWIFIEX_SKB_RXCB(skb);
+		rx_info->bss_index = priv->bss_index;
+	}
+
+	if (eventcause != EVENT_PS_SLEEP && eventcause != EVENT_PS_AWAKE) {
+		do_gettimeofday(&tstamp);
+		dev_dbg(adapter->dev, "event: %lu.%lu: cause: %#x\n",
+		       tstamp.tv_sec, tstamp.tv_usec, eventcause);
+	}
+
+	ret = mwifiex_process_sta_event(priv);
+
+	adapter->event_cause = 0;
+	adapter->event_skb = NULL;
+
+	mwifiex_recv_complete(adapter, skb, 0);
+
+	return ret;
+}
+
+/*
+ * This function prepares a command before sending it to the firmware.
+ *
+ * Preparation includes -
+ *      - Sanity tests to make sure the card is still present or the FW
+ *        is not reset
+ *      - Getting a new command node from the command free queue
+ *      - Initializing the command node for default parameters
+ *      - Fill up the non-default parameters and buffer pointers
+ *      - Add the command to pending queue
+ */
+int mwifiex_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
+			u16 cmd_action, u32 cmd_oid,
+			void *wait_queue, void *data_buf)
+{
+	int ret = 0;
+	struct mwifiex_adapter *adapter = priv->adapter;
+	struct cmd_ctrl_node *cmd_node = NULL;
+	struct host_cmd_ds_command *cmd_ptr = NULL;
+
+	if (!adapter) {
+		pr_err("PREP_CMD: adapter is NULL\n");
+		return -1;
+	}
+
+	if (adapter->is_suspended) {
+		dev_err(adapter->dev, "PREP_CMD: device in suspended state\n");
+		return -1;
+	}
+
+	if (adapter->surprise_removed) {
+		dev_err(adapter->dev, "PREP_CMD: card is removed\n");
+		return -1;
+	}
+
+	if (adapter->hw_status == MWIFIEX_HW_STATUS_RESET) {
+		if (cmd_no != HostCmd_CMD_FUNC_INIT) {
+			dev_err(adapter->dev, "PREP_CMD: FW in reset state\n");
+			return -1;
+		}
+	}
+
+	/* Get a new command node */
+	cmd_node = mwifiex_get_cmd_node(adapter);
+
+	if (!cmd_node) {
+		dev_err(adapter->dev, "PREP_CMD: no free cmd node\n");
+		return -1;
+	}
+
+	/* Initialize the command node */
+	mwifiex_init_cmd_node(priv, cmd_node, cmd_oid, wait_queue, data_buf);
+
+	if (!cmd_node->cmd_skb) {
+		dev_err(adapter->dev, "PREP_CMD: no free cmd buf\n");
+		return -1;
+	}
+
+	memset(skb_put(cmd_node->cmd_skb, sizeof(struct host_cmd_ds_command)),
+	       0, sizeof(struct host_cmd_ds_command));
+
+	cmd_ptr = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data);
+	cmd_ptr->command = cpu_to_le16(cmd_no);
+	cmd_ptr->result = 0;
+
+	/* Prepare command */
+	if (cmd_no) {
+		ret = mwifiex_sta_prepare_cmd(priv, cmd_no, cmd_action,
+					      cmd_oid, data_buf, cmd_ptr);
+	} else {
+		ret = mwifiex_cmd_host_cmd(priv, cmd_ptr, data_buf);
+		cmd_node->cmd_flag |= CMD_F_HOSTCMD;
+	}
+
+	/* Return error, since the command preparation failed */
+	if (ret) {
+		dev_err(adapter->dev, "PREP_CMD: cmd %#x preparation failed\n",
+							cmd_no);
+		mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+		return -1;
+	}
+
+	/* Send command */
+	if (cmd_no == HostCmd_CMD_802_11_SCAN)
+		mwifiex_queue_scan_cmd(priv, cmd_node);
+	else
+		mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true);
+
+	return ret;
+}
+
+/*
+ * This function returns a command to the command free queue.
+ *
+ * The function also calls the completion callback if required, before
+ * cleaning the command node and re-inserting it into the free queue.
+ */
+void
+mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter,
+			     struct cmd_ctrl_node *cmd_node)
+{
+	struct mwifiex_wait_queue *wait_queue = NULL;
+	unsigned long flags;
+
+	if (cmd_node == NULL)
+		return;
+	if (cmd_node->wq_buf) {
+		wait_queue = (struct mwifiex_wait_queue *) cmd_node->wq_buf;
+		if (wait_queue->status != MWIFIEX_ERROR_NO_ERROR)
+			mwifiex_ioctl_complete(adapter, wait_queue, -1);
+		else
+			mwifiex_ioctl_complete(adapter, wait_queue, 0);
+	}
+	/* Clean the node */
+	mwifiex_clean_cmd_node(adapter, cmd_node);
+
+	/* Insert node into cmd_free_q */
+	spin_lock_irqsave(&adapter->cmd_free_q_lock, flags);
+	list_add_tail(&cmd_node->list, &adapter->cmd_free_q);
+	spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags);
+
+	return;
+}
+
+/*
+ * This function queues a command to the command pending queue.
+ *
+ * This in effect adds the command to the command list to be executed.
+ * Exit PS command is handled specially, by placing it always to the
+ * front of the command queue.
+ */
+void
+mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter,
+				struct cmd_ctrl_node *cmd_node, u32 add_tail)
+{
+	struct host_cmd_ds_command *host_cmd = NULL;
+	u16 command;
+	unsigned long flags;
+
+	host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data);
+	if (!host_cmd) {
+		dev_err(adapter->dev, "QUEUE_CMD: host_cmd is NULL\n");
+		return;
+	}
+
+	command = le16_to_cpu(host_cmd->command);
+
+	/* Exit_PS command needs to be queued in the header always. */
+	if (command == HostCmd_CMD_802_11_PS_MODE_ENH) {
+		struct host_cmd_ds_802_11_ps_mode_enh *pm =
+			&host_cmd->params.psmode_enh;
+		if ((le16_to_cpu(pm->action) == DIS_PS)
+		    || (le16_to_cpu(pm->action) == DIS_AUTO_PS)) {
+			if (adapter->ps_state != PS_STATE_AWAKE)
+				add_tail = false;
+		}
+	}
+
+	spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
+	if (add_tail)
+		list_add_tail(&cmd_node->list, &adapter->cmd_pending_q);
+	else
+		list_add(&cmd_node->list, &adapter->cmd_pending_q);
+	spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
+
+	dev_dbg(adapter->dev, "cmd: QUEUE_CMD: cmd=%#x is queued\n", command);
+
+	return;
+}
+
+/*
+ * This function executes the next command in command pending queue.
+ *
+ * This function will fail if a command is already in processing stage,
+ * otherwise it will dequeue the first command from the command pending
+ * queue and send to the firmware.
+ *
+ * If the device is currently in host sleep mode, any commands, except the
+ * host sleep configuration command will de-activate the host sleep. For PS
+ * mode, the function will put the firmware back to sleep if applicable.
+ */
+int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter)
+{
+	struct mwifiex_private *priv = NULL;
+	struct cmd_ctrl_node *cmd_node = NULL;
+	int ret = 0;
+	struct host_cmd_ds_command *host_cmd;
+	unsigned long cmd_flags;
+	unsigned long cmd_pending_q_flags;
+
+	/* Check if already in processing */
+	if (adapter->curr_cmd) {
+		dev_err(adapter->dev, "EXEC_NEXT_CMD: cmd in processing\n");
+		return -1;
+	}
+
+	spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
+	/* Check if any command is pending */
+	spin_lock_irqsave(&adapter->cmd_pending_q_lock, cmd_pending_q_flags);
+	if (list_empty(&adapter->cmd_pending_q)) {
+		spin_unlock_irqrestore(&adapter->cmd_pending_q_lock,
+				       cmd_pending_q_flags);
+		spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
+		return 0;
+	}
+	cmd_node = list_first_entry(&adapter->cmd_pending_q,
+				    struct cmd_ctrl_node, list);
+	spin_unlock_irqrestore(&adapter->cmd_pending_q_lock,
+			       cmd_pending_q_flags);
+
+	host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data);
+	priv = cmd_node->priv;
+
+	if (adapter->ps_state != PS_STATE_AWAKE) {
+		dev_err(adapter->dev, "%s: cannot send cmd in sleep state,"
+				" this should not happen\n", __func__);
+		spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
+		return ret;
+	}
+
+	spin_lock_irqsave(&adapter->cmd_pending_q_lock, cmd_pending_q_flags);
+	list_del(&cmd_node->list);
+	spin_unlock_irqrestore(&adapter->cmd_pending_q_lock,
+			       cmd_pending_q_flags);
+
+	spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
+	ret = mwifiex_dnld_cmd_to_fw(priv, cmd_node);
+	priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
+	/* Any command sent to the firmware when host is in sleep
+	 * mode should de-configure host sleep. We should skip the
+	 * host sleep configuration command itself though
+	 */
+	if (priv && (host_cmd->command !=
+	     cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH))) {
+		if (adapter->hs_activated) {
+			adapter->is_hs_configured = false;
+			mwifiex_hs_activated_event(priv, false);
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * This function handles the command response.
+ *
+ * After processing, the function cleans the command node and puts
+ * it back to the command free queue.
+ */
+int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
+{
+	struct host_cmd_ds_command *resp = NULL;
+	struct mwifiex_private *priv =
+		mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
+	int ret = 0;
+	uint16_t orig_cmdresp_no;
+	uint16_t cmdresp_no;
+	uint16_t cmdresp_result;
+	struct mwifiex_wait_queue *wait_queue = NULL;
+	struct timeval tstamp;
+	unsigned long flags;
+
+	/* Now we got response from FW, cancel the command timer */
+	del_timer(&adapter->cmd_timer);
+
+	if (!adapter->curr_cmd || !adapter->curr_cmd->resp_skb) {
+		resp = (struct host_cmd_ds_command *) adapter->upld_buf;
+		dev_err(adapter->dev, "CMD_RESP: NULL curr_cmd, %#x\n",
+		       le16_to_cpu(resp->command));
+		return -1;
+	}
+
+	if (adapter->curr_cmd->wq_buf)
+		wait_queue = (struct mwifiex_wait_queue *)
+				adapter->curr_cmd->wq_buf;
+
+	adapter->num_cmd_timeout = 0;
+
+	resp = (struct host_cmd_ds_command *) adapter->curr_cmd->resp_skb->data;
+	if (adapter->curr_cmd->cmd_flag & CMD_F_CANCELED) {
+		dev_err(adapter->dev, "CMD_RESP: %#x been canceled\n",
+				le16_to_cpu(resp->command));
+		mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
+		spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+		adapter->curr_cmd = NULL;
+		spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+		return -1;
+	}
+
+	if (adapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) {
+		/* Copy original response back to response buffer */
+		struct mwifiex_ds_misc_cmd *hostcmd = NULL;
+		uint16_t size = le16_to_cpu(resp->size);
+		dev_dbg(adapter->dev, "info: host cmd resp size = %d\n", size);
+		size = min_t(u16, size, MWIFIEX_SIZE_OF_CMD_BUFFER);
+		if (adapter->curr_cmd->data_buf) {
+			hostcmd = (struct mwifiex_ds_misc_cmd *)
+						adapter->curr_cmd->data_buf;
+			hostcmd->len = size;
+			memcpy(hostcmd->cmd, (void *) resp, size);
+		}
+	}
+	orig_cmdresp_no = le16_to_cpu(resp->command);
+
+	/* Get BSS number and corresponding priv */
+	priv = mwifiex_get_priv_by_id(adapter,
+			HostCmd_GET_BSS_NO(le16_to_cpu(resp->seq_num)),
+			HostCmd_GET_BSS_TYPE(le16_to_cpu(resp->seq_num)));
+	if (!priv)
+		priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
+	/* Clear RET_BIT from HostCmd */
+	resp->command = cpu_to_le16(orig_cmdresp_no & HostCmd_CMD_ID_MASK);
+
+	cmdresp_no = le16_to_cpu(resp->command);
+	cmdresp_result = le16_to_cpu(resp->result);
+
+	/* Save the last command response to debug log */
+	adapter->dbg.last_cmd_resp_index =
+		(adapter->dbg.last_cmd_resp_index + 1) % DBG_CMD_NUM;
+	adapter->dbg.last_cmd_resp_id[adapter->dbg.last_cmd_resp_index] =
+		orig_cmdresp_no;
+
+	do_gettimeofday(&tstamp);
+	dev_dbg(adapter->dev, "cmd: CMD_RESP: (%lu.%lu): 0x%x, result %d,"
+		" len %d, seqno 0x%x\n",
+	       tstamp.tv_sec, tstamp.tv_usec, orig_cmdresp_no, cmdresp_result,
+	       le16_to_cpu(resp->size), le16_to_cpu(resp->seq_num));
+
+	if (!(orig_cmdresp_no & HostCmd_RET_BIT)) {
+		dev_err(adapter->dev, "CMD_RESP: invalid cmd resp\n");
+		if (wait_queue)
+			wait_queue->status = MWIFIEX_ERROR_FW_CMDRESP;
+
+		mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
+		spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+		adapter->curr_cmd = NULL;
+		spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+		return -1;
+	}
+
+	if (adapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) {
+		adapter->curr_cmd->cmd_flag &= ~CMD_F_HOSTCMD;
+		if ((cmdresp_result == HostCmd_RESULT_OK)
+		    && (cmdresp_no == HostCmd_CMD_802_11_HS_CFG_ENH))
+			ret = mwifiex_ret_802_11_hs_cfg(priv, resp);
+	} else {
+		/* handle response */
+		ret = mwifiex_process_sta_cmdresp(priv, cmdresp_no, resp,
+						  wait_queue);
+	}
+
+	/* Check init command response */
+	if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) {
+		if (ret == -1) {
+			dev_err(adapter->dev, "%s: cmd %#x failed during "
+				"initialization\n", __func__, cmdresp_no);
+			mwifiex_init_fw_complete(adapter);
+			return -1;
+		} else if (adapter->last_init_cmd == cmdresp_no)
+			adapter->hw_status = MWIFIEX_HW_STATUS_INIT_DONE;
+	}
+
+	if (adapter->curr_cmd) {
+		if (wait_queue && (!ret))
+			wait_queue->status = MWIFIEX_ERROR_NO_ERROR;
+		else if (wait_queue && (ret == -1))
+			wait_queue->status = MWIFIEX_ERROR_CMD_RESP_FAIL;
+
+		/* Clean up and put current command back to cmd_free_q */
+		mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
+
+		spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+		adapter->curr_cmd = NULL;
+		spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+	}
+
+	return ret;
+}
+
+/*
+ * This function handles the timeout of command sending.
+ *
+ * It will re-send the same command again.
+ */
+void
+mwifiex_cmd_timeout_func(unsigned long function_context)
+{
+	struct mwifiex_adapter *adapter =
+		(struct mwifiex_adapter *) function_context;
+	struct cmd_ctrl_node *cmd_node = NULL;
+	struct mwifiex_wait_queue *wait_queue = NULL;
+	struct timeval tstamp;
+
+	adapter->num_cmd_timeout++;
+	adapter->dbg.num_cmd_timeout++;
+	if (!adapter->curr_cmd) {
+		dev_dbg(adapter->dev, "cmd: empty curr_cmd\n");
+		return;
+	}
+	cmd_node = adapter->curr_cmd;
+	if (cmd_node->wq_buf) {
+		wait_queue = (struct mwifiex_wait_queue *) cmd_node->wq_buf;
+		wait_queue->status = MWIFIEX_ERROR_CMD_TIMEOUT;
+	}
+
+	if (cmd_node) {
+		adapter->dbg.timeout_cmd_id =
+			adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index];
+		adapter->dbg.timeout_cmd_act =
+			adapter->dbg.last_cmd_act[adapter->dbg.last_cmd_index];
+		do_gettimeofday(&tstamp);
+		dev_err(adapter->dev, "%s: Timeout cmd id (%lu.%lu) = %#x,"
+			" act = %#x\n", __func__,
+		       tstamp.tv_sec, tstamp.tv_usec,
+		       adapter->dbg.timeout_cmd_id,
+		       adapter->dbg.timeout_cmd_act);
+
+		dev_err(adapter->dev, "num_data_h2c_failure = %d\n",
+		       adapter->dbg.num_tx_host_to_card_failure);
+		dev_err(adapter->dev, "num_cmd_h2c_failure = %d\n",
+		       adapter->dbg.num_cmd_host_to_card_failure);
+
+		dev_err(adapter->dev, "num_cmd_timeout = %d\n",
+		       adapter->dbg.num_cmd_timeout);
+		dev_err(adapter->dev, "num_tx_timeout = %d\n",
+		       adapter->dbg.num_tx_timeout);
+
+		dev_err(adapter->dev, "last_cmd_index = %d\n",
+		       adapter->dbg.last_cmd_index);
+		print_hex_dump_bytes("last_cmd_id: ", DUMP_PREFIX_OFFSET,
+				adapter->dbg.last_cmd_id, DBG_CMD_NUM);
+		print_hex_dump_bytes("last_cmd_act: ", DUMP_PREFIX_OFFSET,
+				adapter->dbg.last_cmd_act, DBG_CMD_NUM);
+
+		dev_err(adapter->dev, "last_cmd_resp_index = %d\n",
+		       adapter->dbg.last_cmd_resp_index);
+		print_hex_dump_bytes("last_cmd_resp_id: ", DUMP_PREFIX_OFFSET,
+				adapter->dbg.last_cmd_resp_id, DBG_CMD_NUM);
+
+		dev_err(adapter->dev, "last_event_index = %d\n",
+		       adapter->dbg.last_event_index);
+		print_hex_dump_bytes("last_event: ", DUMP_PREFIX_OFFSET,
+				adapter->dbg.last_event, DBG_CMD_NUM);
+
+		dev_err(adapter->dev, "data_sent=%d cmd_sent=%d\n",
+		       adapter->data_sent, adapter->cmd_sent);
+
+		dev_err(adapter->dev, "ps_mode=%d ps_state=%d\n",
+				adapter->ps_mode, adapter->ps_state);
+	}
+	if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING)
+		mwifiex_init_fw_complete(adapter);
+
+	return;
+}
+
+/*
+ * This function cancels all the pending commands.
+ *
+ * The current command, all commands in command pending queue and all scan
+ * commands in scan pending queue are cancelled. All the completion callbacks
+ * are called with failure status to ensure cleanup.
+ */
+void
+mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
+{
+	struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL;
+	struct mwifiex_wait_queue *wait_queue = NULL;
+	unsigned long flags;
+
+	/* Cancel current cmd */
+	if ((adapter->curr_cmd) && (adapter->curr_cmd->wq_buf)) {
+		wait_queue =
+			(struct mwifiex_wait_queue *) adapter->curr_cmd->wq_buf;
+		spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+		adapter->curr_cmd->wq_buf = NULL;
+		spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+		wait_queue->status = MWIFIEX_ERROR_CMD_CANCEL;
+		mwifiex_ioctl_complete(adapter, wait_queue, -1);
+	}
+	/* Cancel all pending command */
+	spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
+	list_for_each_entry_safe(cmd_node, tmp_node,
+				 &adapter->cmd_pending_q, list) {
+		list_del(&cmd_node->list);
+		spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
+
+		if (cmd_node->wq_buf) {
+			wait_queue =
+				(struct mwifiex_wait_queue *) cmd_node->wq_buf;
+			wait_queue->status = MWIFIEX_ERROR_CMD_CANCEL;
+			mwifiex_ioctl_complete(adapter, wait_queue, -1);
+			cmd_node->wq_buf = NULL;
+		}
+		mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+		spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
+	}
+	spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
+
+	/* Cancel all pending scan command */
+	spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+	list_for_each_entry_safe(cmd_node, tmp_node,
+				 &adapter->scan_pending_q, list) {
+		list_del(&cmd_node->list);
+		spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+
+		cmd_node->wq_buf = NULL;
+		mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+		spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+	}
+	spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+
+	spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+	adapter->scan_processing = false;
+	spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+}
+
+/*
+ * This function cancels all pending commands that matches with
+ * the given IOCTL request.
+ *
+ * Both the current command buffer and the pending command queue are
+ * searched for matching IOCTL request. The completion callback of
+ * the matched command is called with failure status to ensure cleanup.
+ * In case of scan commands, all pending commands in scan pending queue
+ * are cancelled.
+ */
+void
+mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter,
+			     struct mwifiex_wait_queue *wait_queue)
+{
+	struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL;
+	unsigned long cmd_flags;
+	unsigned long cmd_pending_q_flags;
+	unsigned long scan_pending_q_flags;
+	uint16_t cancel_scan_cmd = false;
+
+	if ((adapter->curr_cmd) &&
+	    (adapter->curr_cmd->wq_buf == wait_queue)) {
+		spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
+		cmd_node = adapter->curr_cmd;
+		cmd_node->wq_buf = NULL;
+		cmd_node->cmd_flag |= CMD_F_CANCELED;
+		spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
+	}
+
+	spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
+	while (1) {
+		cmd_node = mwifiex_get_pending_ioctl_cmd(adapter, wait_queue);
+		if (!cmd_node)
+			break;
+
+		spin_lock_irqsave(&adapter->cmd_pending_q_lock,
+				  cmd_pending_q_flags);
+		list_del(&cmd_node->list);
+		spin_unlock_irqrestore(&adapter->cmd_pending_q_lock,
+				       cmd_pending_q_flags);
+
+		cmd_node->wq_buf = NULL;
+		mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+	}
+	spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
+	/* Cancel all pending scan command */
+	spin_lock_irqsave(&adapter->scan_pending_q_lock,
+			  scan_pending_q_flags);
+	list_for_each_entry_safe(cmd_node, tmp_node,
+				 &adapter->scan_pending_q, list) {
+		if (cmd_node->wq_buf == wait_queue) {
+			list_del(&cmd_node->list);
+			spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
+					       scan_pending_q_flags);
+			cmd_node->wq_buf = NULL;
+			mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+			spin_lock_irqsave(&adapter->scan_pending_q_lock,
+					  scan_pending_q_flags);
+			cancel_scan_cmd = true;
+		}
+	}
+	spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
+			       scan_pending_q_flags);
+
+	if (cancel_scan_cmd) {
+		spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
+		adapter->scan_processing = false;
+		spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
+	}
+	wait_queue->status = MWIFIEX_ERROR_CMD_CANCEL;
+	mwifiex_ioctl_complete(adapter, wait_queue, -1);
+
+	return;
+}
+
+/*
+ * This function sends the sleep confirm command to firmware, if
+ * possible.
+ *
+ * The sleep confirm command cannot be issued if command response,
+ * data response or event response is awaiting handling, or if we
+ * are in the middle of sending a command, or expecting a command
+ * response.
+ */
+void
+mwifiex_check_ps_cond(struct mwifiex_adapter *adapter)
+{
+	if (!adapter->cmd_sent &&
+	    !adapter->curr_cmd && !IS_CARD_RX_RCVD(adapter))
+		mwifiex_dnld_sleep_confirm_cmd(adapter);
+	else
+		dev_dbg(adapter->dev,
+			"cmd: Delay Sleep Confirm (%s%s%s)\n",
+		       (adapter->cmd_sent) ? "D" : "",
+		       (adapter->curr_cmd) ? "C" : "",
+		       (IS_CARD_RX_RCVD(adapter)) ? "R" : "");
+}
+
+/*
+ * This function sends a Host Sleep activated event to applications.
+ *
+ * This event is generated by the driver, with a blank event body.
+ */
+void
+mwifiex_hs_activated_event(struct mwifiex_private *priv, u8 activated)
+{
+	if (activated) {
+		if (priv->adapter->is_hs_configured) {
+			priv->adapter->hs_activated = true;
+			dev_dbg(priv->adapter->dev, "event: hs_activated\n");
+			priv->adapter->hs_activate_wait_q_woken = true;
+			wake_up_interruptible(
+				&priv->adapter->hs_activate_wait_q);
+		} else {
+			dev_dbg(priv->adapter->dev, "event: HS not configured\n");
+		}
+	} else {
+		dev_dbg(priv->adapter->dev, "event: hs_deactivated\n");
+		priv->adapter->hs_activated = false;
+	}
+}
+
+/*
+ * This function handles the command response of a Host Sleep configuration
+ * command.
+ *
+ * Handling includes changing the header fields into CPU format
+ * and setting the current host sleep activation status in driver.
+ *
+ * In case host sleep status change, the function generates an event to
+ * notify the applications.
+ */
+int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv,
+			      struct host_cmd_ds_command *resp)
+{
+	struct mwifiex_adapter *adapter = priv->adapter;
+	struct host_cmd_ds_802_11_hs_cfg_enh *phs_cfg =
+		&resp->params.opt_hs_cfg;
+	uint32_t conditions = le32_to_cpu(phs_cfg->params.hs_config.conditions);
+
+	if (phs_cfg->action == cpu_to_le16(HS_ACTIVATE)) {
+		mwifiex_hs_activated_event(priv, true);
+		return 0;
+	} else {
+		dev_dbg(adapter->dev, "cmd: CMD_RESP: HS_CFG cmd reply"
+			" result=%#x, conditions=0x%x gpio=0x%x gap=0x%x\n",
+			resp->result, conditions,
+		       phs_cfg->params.hs_config.gpio,
+		       phs_cfg->params.hs_config.gap);
+	}
+	if (conditions != HOST_SLEEP_CFG_CANCEL) {
+		adapter->is_hs_configured = true;
+	} else {
+		adapter->is_hs_configured = false;
+		if (adapter->hs_activated)
+			mwifiex_hs_activated_event(priv, false);
+	}
+
+	return 0;
+}
+
+/*
+ * This function wakes up the adapter and generates a Host Sleep
+ * cancel event on receiving the power up interrupt.
+ */
+void
+mwifiex_process_hs_config(struct mwifiex_adapter *adapter)
+{
+	dev_dbg(adapter->dev, "info: %s: auto cancelling host sleep"
+		" since there is interrupt from the firmware\n", __func__);
+
+	adapter->if_ops.wakeup(adapter);
+	adapter->hs_activated = false;
+	adapter->is_hs_configured = false;
+	mwifiex_hs_activated_event(mwifiex_get_priv(adapter,
+				   MWIFIEX_BSS_ROLE_ANY), false);
+	return;
+}
+
+/*
+ * This function handles the command response of a sleep confirm command.
+ *
+ * The function sets the card state to SLEEP if the response indicates success.
+ */
+void
+mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *adapter,
+				   u8 *pbuf, u32 upld_len)
+{
+	struct host_cmd_ds_command *cmd = (struct host_cmd_ds_command *) pbuf;
+	struct mwifiex_private *priv =
+		mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
+	uint16_t result = le16_to_cpu(cmd->result);
+	uint16_t command = le16_to_cpu(cmd->command);
+	uint16_t seq_num = le16_to_cpu(cmd->seq_num);
+
+	if (!upld_len) {
+		dev_err(adapter->dev, "%s: cmd size is 0\n", __func__);
+		return;
+	}
+
+	/* Get BSS number and corresponding priv */
+	priv = mwifiex_get_priv_by_id(adapter, HostCmd_GET_BSS_NO(seq_num),
+				      HostCmd_GET_BSS_TYPE(seq_num));
+	if (!priv)
+		priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
+
+	/* Update sequence number */
+	seq_num = HostCmd_GET_SEQ_NO(seq_num);
+	/* Clear RET_BIT from HostCmd */
+	command &= HostCmd_CMD_ID_MASK;
+
+	if (command != HostCmd_CMD_802_11_PS_MODE_ENH) {
+		dev_err(adapter->dev, "%s: received unexpected response for"
+			" cmd %x, result = %x\n", __func__, command, result);
+		return;
+	}
+
+	if (result) {
+		dev_err(adapter->dev, "%s: sleep confirm cmd failed\n",
+						__func__);
+		adapter->pm_wakeup_card_req = false;
+		adapter->ps_state = PS_STATE_AWAKE;
+		return;
+	}
+	adapter->pm_wakeup_card_req = true;
+	if (adapter->is_hs_configured)
+		mwifiex_hs_activated_event(mwifiex_get_priv(adapter,
+					   MWIFIEX_BSS_ROLE_ANY), true);
+	adapter->ps_state = PS_STATE_SLEEP;
+	cmd->command = cpu_to_le16(command);
+	cmd->seq_num = cpu_to_le16(seq_num);
+}
+EXPORT_SYMBOL_GPL(mwifiex_process_sleep_confirm_resp);
+
+/*
+ * This function prepares an enhanced power mode command.
+ *
+ * This function can be used to disable power save or to configure
+ * power save with auto PS or STA PS or auto deep sleep.
+ *
+ * Preparation includes -
+ *      - Setting command ID, action and proper size
+ *      - Setting Power Save bitmap, PS parameters TLV, PS mode TLV,
+ *        auto deep sleep TLV (as required)
+ *      - Ensuring correct endian-ness
+ */
+int mwifiex_cmd_enh_power_mode(struct mwifiex_private *priv,
+			       struct host_cmd_ds_command *cmd,
+			       u16 cmd_action, uint16_t ps_bitmap,
+			       void *data_buf)
+{
+	struct host_cmd_ds_802_11_ps_mode_enh *psmode_enh =
+		&cmd->params.psmode_enh;
+	u8 *tlv = NULL;
+	u16 cmd_size = 0;
+
+	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH);
+	if (cmd_action == DIS_AUTO_PS) {
+		psmode_enh->action = cpu_to_le16(DIS_AUTO_PS);
+		psmode_enh->params.ps_bitmap = cpu_to_le16(ps_bitmap);
+		cmd->size = cpu_to_le16(S_DS_GEN + sizeof(psmode_enh->action) +
+				sizeof(psmode_enh->params.ps_bitmap));
+	} else if (cmd_action == GET_PS) {
+		psmode_enh->action = cpu_to_le16(GET_PS);
+		psmode_enh->params.ps_bitmap = cpu_to_le16(ps_bitmap);
+		cmd->size = cpu_to_le16(S_DS_GEN + sizeof(psmode_enh->action) +
+				sizeof(psmode_enh->params.ps_bitmap));
+	} else if (cmd_action == EN_AUTO_PS) {
+		psmode_enh->action = cpu_to_le16(EN_AUTO_PS);
+		psmode_enh->params.ps_bitmap = cpu_to_le16(ps_bitmap);
+		cmd_size = S_DS_GEN + sizeof(psmode_enh->action) +
+				sizeof(psmode_enh->params.ps_bitmap);
+		tlv = (u8 *) cmd + cmd_size;
+		if (ps_bitmap & BITMAP_STA_PS) {
+			struct mwifiex_adapter *adapter = priv->adapter;
+			struct mwifiex_ie_types_ps_param *ps_tlv =
+				(struct mwifiex_ie_types_ps_param *) tlv;
+			struct mwifiex_ps_param *ps_mode = &ps_tlv->param;
+			ps_tlv->header.type = cpu_to_le16(TLV_TYPE_PS_PARAM);
+			ps_tlv->header.len = cpu_to_le16(sizeof(*ps_tlv) -
+					sizeof(struct mwifiex_ie_types_header));
+			cmd_size += sizeof(*ps_tlv);
+			tlv += sizeof(*ps_tlv);
+			dev_dbg(adapter->dev, "cmd: PS Command: Enter PS\n");
+			ps_mode->null_pkt_interval =
+				cpu_to_le16(adapter->null_pkt_interval);
+			ps_mode->multiple_dtims =
+				cpu_to_le16(adapter->multiple_dtim);
+			ps_mode->bcn_miss_timeout =
+				cpu_to_le16(adapter->bcn_miss_time_out);
+			ps_mode->local_listen_interval =
+				cpu_to_le16(adapter->local_listen_interval);
+			ps_mode->adhoc_wake_period =
+				cpu_to_le16(adapter->adhoc_awake_period);
+			ps_mode->delay_to_ps =
+				cpu_to_le16(adapter->delay_to_ps);
+			ps_mode->mode =
+				cpu_to_le16(adapter->enhanced_ps_mode);
+
+		}
+		if (ps_bitmap & BITMAP_AUTO_DS) {
+			struct mwifiex_ie_types_auto_ds_param *auto_ds_tlv =
+				(struct mwifiex_ie_types_auto_ds_param *) tlv;
+			u16 idletime = 0;
+
+			auto_ds_tlv->header.type =
+				cpu_to_le16(TLV_TYPE_AUTO_DS_PARAM);
+			auto_ds_tlv->header.len =
+				cpu_to_le16(sizeof(*auto_ds_tlv) -
+					sizeof(struct mwifiex_ie_types_header));
+			cmd_size += sizeof(*auto_ds_tlv);
+			tlv += sizeof(*auto_ds_tlv);
+			if (data_buf)
+				idletime = ((struct mwifiex_ds_auto_ds *)
+					     data_buf)->idle_time;
+			dev_dbg(priv->adapter->dev,
+					"cmd: PS Command: Enter Auto Deep Sleep\n");
+			auto_ds_tlv->deep_sleep_timeout = cpu_to_le16(idletime);
+		}
+		cmd->size = cpu_to_le16(cmd_size);
+	}
+	return 0;
+}
+
+/*
+ * This function handles the command response of an enhanced power mode
+ * command.
+ *
+ * Handling includes changing the header fields into CPU format
+ * and setting the current enhanced power mode in driver.
+ */
+int mwifiex_ret_enh_power_mode(struct mwifiex_private *priv,
+			       struct host_cmd_ds_command *resp,
+			       void *data_buf)
+{
+	struct mwifiex_adapter *adapter = priv->adapter;
+	struct host_cmd_ds_802_11_ps_mode_enh *ps_mode =
+		&resp->params.psmode_enh;
+	uint16_t action = le16_to_cpu(ps_mode->action);
+	uint16_t ps_bitmap = le16_to_cpu(ps_mode->params.ps_bitmap);
+	uint16_t auto_ps_bitmap =
+		le16_to_cpu(ps_mode->params.ps_bitmap);
+
+	dev_dbg(adapter->dev, "info: %s: PS_MODE cmd reply result=%#x action=%#X\n",
+					__func__, resp->result, action);
+	if (action == EN_AUTO_PS) {
+		if (auto_ps_bitmap & BITMAP_AUTO_DS) {
+			dev_dbg(adapter->dev, "cmd: Enabled auto deep sleep\n");
+			priv->adapter->is_deep_sleep = true;
+		}
+		if (auto_ps_bitmap & BITMAP_STA_PS) {
+			dev_dbg(adapter->dev, "cmd: Enabled STA power save\n");
+			if (adapter->sleep_period.period)
+				dev_dbg(adapter->dev, "cmd: set to uapsd/pps mode\n");
+		}
+	} else if (action == DIS_AUTO_PS) {
+		if (ps_bitmap & BITMAP_AUTO_DS) {
+			priv->adapter->is_deep_sleep = false;
+			dev_dbg(adapter->dev, "cmd: Disabled auto deep sleep\n");
+		}
+		if (ps_bitmap & BITMAP_STA_PS) {
+			dev_dbg(adapter->dev, "cmd: Disabled STA power save\n");
+			if (adapter->sleep_period.period) {
+				adapter->delay_null_pkt = false;
+				adapter->tx_lock_flag = false;
+				adapter->pps_uapsd_mode = false;
+			}
+		}
+	} else if (action == GET_PS) {
+		if (ps_bitmap & BITMAP_STA_PS)
+			adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP;
+		else
+			adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM;
+
+		dev_dbg(adapter->dev, "cmd: ps_bitmap=%#x\n", ps_bitmap);
+
+		if (data_buf) {
+			/* This section is for get power save mode */
+			struct mwifiex_ds_pm_cfg *pm_cfg =
+					(struct mwifiex_ds_pm_cfg *)data_buf;
+			if (ps_bitmap & BITMAP_STA_PS)
+				pm_cfg->param.ps_mode = 1;
+			else
+				pm_cfg->param.ps_mode = 0;
+		}
+	}
+	return 0;
+}
+
+/*
+ * This function prepares command to get hardware specifications.
+ *
+ * Preparation includes -
+ *      - Setting command ID, action and proper size
+ *      - Setting permanent address parameter
+ *      - Ensuring correct endian-ness
+ */
+int mwifiex_cmd_get_hw_spec(struct mwifiex_private *priv,
+			    struct host_cmd_ds_command *cmd)
+{
+	struct host_cmd_ds_get_hw_spec *hw_spec = &cmd->params.hw_spec;
+
+	cmd->command = cpu_to_le16(HostCmd_CMD_GET_HW_SPEC);
+	cmd->size =
+		cpu_to_le16(sizeof(struct host_cmd_ds_get_hw_spec) + S_DS_GEN);
+	memcpy(hw_spec->permanent_addr, priv->curr_addr, ETH_ALEN);
+
+	return 0;
+}
+
+/*
+ * This function handles the command response of get hardware
+ * specifications.
+ *
+ * Handling includes changing the header fields into CPU format
+ * and saving/updating the following parameters in driver -
+ *      - Firmware capability information
+ *      - Firmware band settings
+ *      - Ad-hoc start band and channel
+ *      - Ad-hoc 11n activation status
+ *      - Firmware release number
+ *      - Number of antennas
+ *      - Hardware address
+ *      - Hardware interface version
+ *      - Firmware version
+ *      - Region code
+ *      - 11n capabilities
+ *      - MCS support fields
+ *      - MP end port
+ */
+int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
+			    struct host_cmd_ds_command *resp)
+{
+	struct host_cmd_ds_get_hw_spec *hw_spec = &resp->params.hw_spec;
+	struct mwifiex_adapter *adapter = priv->adapter;
+	int i;
+
+	adapter->fw_cap_info = le32_to_cpu(hw_spec->fw_cap_info);
+
+	if (IS_SUPPORT_MULTI_BANDS(adapter))
+		adapter->fw_bands = (u8) GET_FW_DEFAULT_BANDS(adapter);
+	else
+		adapter->fw_bands = BAND_B;
+
+	adapter->config_bands = adapter->fw_bands;
+
+	if (adapter->fw_bands & BAND_A) {
+		if (adapter->fw_bands & BAND_GN) {
+			adapter->config_bands |= BAND_AN;
+			adapter->fw_bands |= BAND_AN;
+		}
+		if (adapter->fw_bands & BAND_AN) {
+			adapter->adhoc_start_band = BAND_A | BAND_AN;
+			adapter->adhoc_11n_enabled = true;
+		} else {
+			adapter->adhoc_start_band = BAND_A;
+		}
+		priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL_A;
+	} else if (adapter->fw_bands & BAND_GN) {
+		adapter->adhoc_start_band = BAND_G | BAND_B | BAND_GN;
+		priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
+		adapter->adhoc_11n_enabled = true;
+	} else if (adapter->fw_bands & BAND_G) {
+		adapter->adhoc_start_band = BAND_G | BAND_B;
+		priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
+	} else if (adapter->fw_bands & BAND_B) {
+		adapter->adhoc_start_band = BAND_B;
+		priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
+	}
+
+	adapter->fw_release_number = le32_to_cpu(hw_spec->fw_release_number);
+	adapter->number_of_antenna = le16_to_cpu(hw_spec->number_of_antenna);
+
+	dev_dbg(adapter->dev, "info: GET_HW_SPEC: fw_release_number- %#x\n",
+	       adapter->fw_release_number);
+	dev_dbg(adapter->dev, "info: GET_HW_SPEC: permanent addr: %pM\n",
+					hw_spec->permanent_addr);
+	dev_dbg(adapter->dev, "info: GET_HW_SPEC: hw_if_version=%#x  version=%#x\n",
+		le16_to_cpu(hw_spec->hw_if_version),
+	       le16_to_cpu(hw_spec->version));
+
+	if (priv->curr_addr[0] == 0xff)
+		memmove(priv->curr_addr, hw_spec->permanent_addr, ETH_ALEN);
+
+	adapter->region_code = le16_to_cpu(hw_spec->region_code);
+
+	for (i = 0; i < MWIFIEX_MAX_REGION_CODE; i++)
+		/* Use the region code to search for the index */
+		if (adapter->region_code == region_code_index[i])
+			break;
+
+	/* If it's unidentified region code, use the default (USA) */
+	if (i >= MWIFIEX_MAX_REGION_CODE) {
+		adapter->region_code = 0x10;
+		dev_dbg(adapter->dev, "cmd: unknown region code, use default (USA)\n");
+	}
+
+	adapter->hw_dot_11n_dev_cap = le32_to_cpu(hw_spec->dot_11n_dev_cap);
+	adapter->hw_dev_mcs_support = hw_spec->dev_mcs_support;
+
+	if (adapter->if_ops.update_mp_end_port)
+		adapter->if_ops.update_mp_end_port(adapter,
+					le16_to_cpu(hw_spec->mp_end_port));
+
+	return 0;
+}
diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c
new file mode 100644
index 0000000..63b0969
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/debugfs.c
@@ -0,0 +1,773 @@
+/*
+ * Marvell Wireless LAN device driver: debugfs
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include <linux/debugfs.h>
+
+#include "main.h"
+#include "11n.h"
+
+
+static struct dentry *mwifiex_dfs_dir;
+
+static char *bss_modes[] = {
+	"Unknown",
+	"Managed",
+	"Ad-hoc",
+	"Auto"
+};
+
+/* size/addr for mwifiex_debug_info */
+#define item_size(n)		(FIELD_SIZEOF(struct mwifiex_debug_info, n))
+#define item_addr(n)		(offsetof(struct mwifiex_debug_info, n))
+
+/* size/addr for struct mwifiex_adapter */
+#define adapter_item_size(n)	(FIELD_SIZEOF(struct mwifiex_adapter, n))
+#define adapter_item_addr(n)	(offsetof(struct mwifiex_adapter, n))
+
+struct mwifiex_debug_data {
+	char name[32];		/* variable/array name */
+	u32 size;		/* size of the variable/array */
+	size_t addr;		/* address of the variable/array */
+	int num;		/* number of variables in an array */
+};
+
+static struct mwifiex_debug_data items[] = {
+	{"int_counter", item_size(int_counter),
+	 item_addr(int_counter), 1},
+	{"wmm_ac_vo", item_size(packets_out[WMM_AC_VO]),
+	 item_addr(packets_out[WMM_AC_VO]), 1},
+	{"wmm_ac_vi", item_size(packets_out[WMM_AC_VI]),
+	 item_addr(packets_out[WMM_AC_VI]), 1},
+	{"wmm_ac_be", item_size(packets_out[WMM_AC_BE]),
+	 item_addr(packets_out[WMM_AC_BE]), 1},
+	{"wmm_ac_bk", item_size(packets_out[WMM_AC_BK]),
+	 item_addr(packets_out[WMM_AC_BK]), 1},
+	{"max_tx_buf_size", item_size(max_tx_buf_size),
+	 item_addr(max_tx_buf_size), 1},
+	{"tx_buf_size", item_size(tx_buf_size),
+	 item_addr(tx_buf_size), 1},
+	{"curr_tx_buf_size", item_size(curr_tx_buf_size),
+	 item_addr(curr_tx_buf_size), 1},
+	{"ps_mode", item_size(ps_mode),
+	 item_addr(ps_mode), 1},
+	{"ps_state", item_size(ps_state),
+	 item_addr(ps_state), 1},
+	{"is_deep_sleep", item_size(is_deep_sleep),
+	 item_addr(is_deep_sleep), 1},
+	{"wakeup_dev_req", item_size(pm_wakeup_card_req),
+	 item_addr(pm_wakeup_card_req), 1},
+	{"wakeup_tries", item_size(pm_wakeup_fw_try),
+	 item_addr(pm_wakeup_fw_try), 1},
+	{"hs_configured", item_size(is_hs_configured),
+	 item_addr(is_hs_configured), 1},
+	{"hs_activated", item_size(hs_activated),
+	 item_addr(hs_activated), 1},
+	{"num_tx_timeout", item_size(num_tx_timeout),
+	 item_addr(num_tx_timeout), 1},
+	{"num_cmd_timeout", item_size(num_cmd_timeout),
+	 item_addr(num_cmd_timeout), 1},
+	{"timeout_cmd_id", item_size(timeout_cmd_id),
+	 item_addr(timeout_cmd_id), 1},
+	{"timeout_cmd_act", item_size(timeout_cmd_act),
+	 item_addr(timeout_cmd_act), 1},
+	{"last_cmd_id", item_size(last_cmd_id),
+	 item_addr(last_cmd_id), DBG_CMD_NUM},
+	{"last_cmd_act", item_size(last_cmd_act),
+	 item_addr(last_cmd_act), DBG_CMD_NUM},
+	{"last_cmd_index", item_size(last_cmd_index),
+	 item_addr(last_cmd_index), 1},
+	{"last_cmd_resp_id", item_size(last_cmd_resp_id),
+	 item_addr(last_cmd_resp_id), DBG_CMD_NUM},
+	{"last_cmd_resp_index", item_size(last_cmd_resp_index),
+	 item_addr(last_cmd_resp_index), 1},
+	{"last_event", item_size(last_event),
+	 item_addr(last_event), DBG_CMD_NUM},
+	{"last_event_index", item_size(last_event_index),
+	 item_addr(last_event_index), 1},
+	{"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure),
+	 item_addr(num_cmd_host_to_card_failure), 1},
+	{"num_cmd_sleep_cfm_fail",
+	 item_size(num_cmd_sleep_cfm_host_to_card_failure),
+	 item_addr(num_cmd_sleep_cfm_host_to_card_failure), 1},
+	{"num_tx_h2c_fail", item_size(num_tx_host_to_card_failure),
+	 item_addr(num_tx_host_to_card_failure), 1},
+	{"num_evt_deauth", item_size(num_event_deauth),
+	 item_addr(num_event_deauth), 1},
+	{"num_evt_disassoc", item_size(num_event_disassoc),
+	 item_addr(num_event_disassoc), 1},
+	{"num_evt_link_lost", item_size(num_event_link_lost),
+	 item_addr(num_event_link_lost), 1},
+	{"num_cmd_deauth", item_size(num_cmd_deauth),
+	 item_addr(num_cmd_deauth), 1},
+	{"num_cmd_assoc_ok", item_size(num_cmd_assoc_success),
+	 item_addr(num_cmd_assoc_success), 1},
+	{"num_cmd_assoc_fail", item_size(num_cmd_assoc_failure),
+	 item_addr(num_cmd_assoc_failure), 1},
+	{"cmd_sent", item_size(cmd_sent),
+	 item_addr(cmd_sent), 1},
+	{"data_sent", item_size(data_sent),
+	 item_addr(data_sent), 1},
+	{"cmd_resp_received", item_size(cmd_resp_received),
+	 item_addr(cmd_resp_received), 1},
+	{"event_received", item_size(event_received),
+	 item_addr(event_received), 1},
+
+	/* variables defined in struct mwifiex_adapter */
+	{"ioctl_pending", adapter_item_size(ioctl_pending),
+	 adapter_item_addr(ioctl_pending), 1},
+	{"tx_pending", adapter_item_size(tx_pending),
+	 adapter_item_addr(tx_pending), 1},
+	{"rx_pending", adapter_item_size(rx_pending),
+	 adapter_item_addr(rx_pending), 1},
+};
+
+static int num_of_items = ARRAY_SIZE(items);
+
+/*
+ * Generic proc file open handler.
+ *
+ * This function is called every time a file is accessed for read or write.
+ */
+static int
+mwifiex_open_generic(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+/*
+ * Proc info file read handler.
+ *
+ * This function is called when the 'info' file is opened for reading.
+ * It prints the following driver related information -
+ *      - Driver name
+ *      - Driver version
+ *      - Driver extended version
+ *      - Interface name
+ *      - BSS mode
+ *      - Media state (connected or disconnected)
+ *      - MAC address
+ *      - Total number of Tx bytes
+ *      - Total number of Rx bytes
+ *      - Total number of Tx packets
+ *      - Total number of Rx packets
+ *      - Total number of dropped Tx packets
+ *      - Total number of dropped Rx packets
+ *      - Total number of corrupted Tx packets
+ *      - Total number of corrupted Rx packets
+ *      - Carrier status (on or off)
+ *      - Tx queue status (started or stopped)
+ *
+ * For STA mode drivers, it also prints the following extra -
+ *      - ESSID
+ *      - BSSID
+ *      - Channel
+ *      - Region code
+ *      - Multicast count
+ *      - Multicast addresses
+ */
+static ssize_t
+mwifiex_info_read(struct file *file, char __user *ubuf,
+		  size_t count, loff_t *ppos)
+{
+	struct mwifiex_private *priv =
+		(struct mwifiex_private *) file->private_data;
+	struct net_device *netdev = priv->netdev;
+	struct netdev_hw_addr *ha;
+	unsigned long page = get_zeroed_page(GFP_KERNEL);
+	char *p = (char *) page, fmt[64];
+	struct mwifiex_bss_info info;
+	ssize_t ret = 0;
+	int i = 0;
+
+	if (!p)
+		return -ENOMEM;
+
+	memset(&info, 0, sizeof(info));
+	ret = mwifiex_get_bss_info(priv, &info);
+	if (ret)
+		goto free_and_exit;
+
+	mwifiex_drv_get_driver_version(priv->adapter, fmt, sizeof(fmt) - 1);
+
+	if (!priv->version_str[0])
+		mwifiex_get_ver_ext(priv);
+
+	p += sprintf(p, "driver_name = " "\"mwifiex\"\n");
+	p += sprintf(p, "driver_version = %s", fmt);
+	p += sprintf(p, "\nverext = %s", priv->version_str);
+	p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name);
+	p += sprintf(p, "bss_mode=\"%s\"\n", bss_modes[info.bss_mode]);
+	p += sprintf(p, "media_state=\"%s\"\n",
+		     (!priv->media_connected ? "Disconnected" : "Connected"));
+	p += sprintf(p, "mac_address=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
+		     netdev->dev_addr[0], netdev->dev_addr[1],
+		     netdev->dev_addr[2], netdev->dev_addr[3],
+		     netdev->dev_addr[4], netdev->dev_addr[5]);
+
+	if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) {
+		p += sprintf(p, "multicast_count=\"%d\"\n",
+			     netdev_mc_count(netdev));
+		p += sprintf(p, "essid=\"%s\"\n", info.ssid.ssid);
+		p += sprintf(p, "bssid=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
+			     info.bssid[0], info.bssid[1],
+			     info.bssid[2], info.bssid[3],
+			     info.bssid[4], info.bssid[5]);
+		p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan);
+		p += sprintf(p, "region_code = \"%02x\"\n", info.region_code);
+
+		netdev_for_each_mc_addr(ha, netdev)
+			p += sprintf(p, "multicast_address[%d]="
+				     "\"%02x:%02x:%02x:%02x:%02x:%02x\"\n", i++,
+				     ha->addr[0], ha->addr[1],
+				     ha->addr[2], ha->addr[3],
+				     ha->addr[4], ha->addr[5]);
+	}
+
+	p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes);
+	p += sprintf(p, "num_rx_bytes = %lu\n", priv->stats.rx_bytes);
+	p += sprintf(p, "num_tx_pkts = %lu\n", priv->stats.tx_packets);
+	p += sprintf(p, "num_rx_pkts = %lu\n", priv->stats.rx_packets);
+	p += sprintf(p, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped);
+	p += sprintf(p, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped);
+	p += sprintf(p, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors);
+	p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors);
+	p += sprintf(p, "carrier %s\n", ((netif_carrier_ok(priv->netdev))
+					 ? "on" : "off"));
+	p += sprintf(p, "tx queue %s\n", ((netif_queue_stopped(priv->netdev))
+					  ? "stopped" : "started"));
+
+	ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
+				      (unsigned long) p - page);
+
+free_and_exit:
+	free_page(page);
+	return ret;
+}
+
+/*
+ * Proc getlog file read handler.
+ *
+ * This function is called when the 'getlog' file is opened for reading
+ * It prints the following log information -
+ *      - Number of multicast Tx frames
+ *      - Number of failed packets
+ *      - Number of Tx retries
+ *      - Number of multicast Tx retries
+ *      - Number of duplicate frames
+ *      - Number of RTS successes
+ *      - Number of RTS failures
+ *      - Number of ACK failures
+ *      - Number of fragmented Rx frames
+ *      - Number of multicast Rx frames
+ *      - Number of FCS errors
+ *      - Number of Tx frames
+ *      - WEP ICV error counts
+ */
+static ssize_t
+mwifiex_getlog_read(struct file *file, char __user *ubuf,
+		    size_t count, loff_t *ppos)
+{
+	struct mwifiex_private *priv =
+		(struct mwifiex_private *) file->private_data;
+	unsigned long page = get_zeroed_page(GFP_KERNEL);
+	char *p = (char *) page;
+	ssize_t ret = 0;
+	struct mwifiex_ds_get_stats stats;
+
+	if (!p)
+		return -ENOMEM;
+
+	memset(&stats, 0, sizeof(stats));
+	ret = mwifiex_get_stats_info(priv, &stats);
+	if (ret)
+		goto free_and_exit;
+
+	p += sprintf(p, "\n"
+		     "mcasttxframe     %u\n"
+		     "failed           %u\n"
+		     "retry            %u\n"
+		     "multiretry       %u\n"
+		     "framedup         %u\n"
+		     "rtssuccess       %u\n"
+		     "rtsfailure       %u\n"
+		     "ackfailure       %u\n"
+		     "rxfrag           %u\n"
+		     "mcastrxframe     %u\n"
+		     "fcserror         %u\n"
+		     "txframe          %u\n"
+		     "wepicverrcnt-1   %u\n"
+		     "wepicverrcnt-2   %u\n"
+		     "wepicverrcnt-3   %u\n"
+		     "wepicverrcnt-4   %u\n",
+		     stats.mcast_tx_frame,
+		     stats.failed,
+		     stats.retry,
+		     stats.multi_retry,
+		     stats.frame_dup,
+		     stats.rts_success,
+		     stats.rts_failure,
+		     stats.ack_failure,
+		     stats.rx_frag,
+		     stats.mcast_rx_frame,
+		     stats.fcs_error,
+		     stats.tx_frame,
+		     stats.wep_icv_error[0],
+		     stats.wep_icv_error[1],
+		     stats.wep_icv_error[2],
+		     stats.wep_icv_error[3]);
+
+
+	ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
+				      (unsigned long) p - page);
+
+free_and_exit:
+	free_page(page);
+	return ret;
+}
+
+static struct mwifiex_debug_info info;
+
+/*
+ * Proc debug file read handler.
+ *
+ * This function is called when the 'debug' file is opened for reading
+ * It prints the following log information -
+ *      - Interrupt count
+ *      - WMM AC VO packets count
+ *      - WMM AC VI packets count
+ *      - WMM AC BE packets count
+ *      - WMM AC BK packets count
+ *      - Maximum Tx buffer size
+ *      - Tx buffer size
+ *      - Current Tx buffer size
+ *      - Power Save mode
+ *      - Power Save state
+ *      - Deep Sleep status
+ *      - Device wakeup required status
+ *      - Number of wakeup tries
+ *      - Host Sleep configured status
+ *      - Host Sleep activated status
+ *      - Number of Tx timeouts
+ *      - Number of command timeouts
+ *      - Last timed out command ID
+ *      - Last timed out command action
+ *      - Last command ID
+ *      - Last command action
+ *      - Last command index
+ *      - Last command response ID
+ *      - Last command response index
+ *      - Last event
+ *      - Last event index
+ *      - Number of host to card command failures
+ *      - Number of sleep confirm command failures
+ *      - Number of host to card data failure
+ *      - Number of deauthentication events
+ *      - Number of disassociation events
+ *      - Number of link lost events
+ *      - Number of deauthentication commands
+ *      - Number of association success commands
+ *      - Number of association failure commands
+ *      - Number of commands sent
+ *      - Number of data packets sent
+ *      - Number of command responses received
+ *      - Number of events received
+ *      - Tx BA stream table (TID, RA)
+ *      - Rx reorder table (TID, TA, Start window, Window size, Buffer)
+ */
+static ssize_t
+mwifiex_debug_read(struct file *file, char __user *ubuf,
+		   size_t count, loff_t *ppos)
+{
+	struct mwifiex_private *priv =
+		(struct mwifiex_private *) file->private_data;
+	struct mwifiex_debug_data *d = &items[0];
+	unsigned long page = get_zeroed_page(GFP_KERNEL);
+	char *p = (char *) page;
+	ssize_t ret = 0;
+	size_t size, addr;
+	long val;
+	int i, j;
+
+	if (!p)
+		return -ENOMEM;
+
+	ret = mwifiex_get_debug_info(priv, &info);
+	if (ret)
+		goto free_and_exit;
+
+	for (i = 0; i < num_of_items; i++) {
+		p += sprintf(p, "%s=", d[i].name);
+
+		size = d[i].size / d[i].num;
+
+		if (i < (num_of_items - 3))
+			addr = d[i].addr + (size_t) &info;
+		else /* The last 3 items are struct mwifiex_adapter variables */
+			addr = d[i].addr + (size_t) priv->adapter;
+
+		for (j = 0; j < d[i].num; j++) {
+			switch (size) {
+			case 1:
+				val = *((u8 *) addr);
+				break;
+			case 2:
+				val = *((u16 *) addr);
+				break;
+			case 4:
+				val = *((u32 *) addr);
+				break;
+			case 8:
+				val = *((long long *) addr);
+				break;
+			default:
+				val = -1;
+				break;
+			}
+
+			p += sprintf(p, "%#lx ", val);
+			addr += size;
+		}
+
+		p += sprintf(p, "\n");
+	}
+
+	if (info.tx_tbl_num) {
+		p += sprintf(p, "Tx BA stream table:\n");
+		for (i = 0; i < info.tx_tbl_num; i++)
+			p += sprintf(p, "tid = %d, "
+				     "ra = %02x:%02x:%02x:%02x:%02x:%02x\n",
+				     info.tx_tbl[i].tid, info.tx_tbl[i].ra[0],
+				     info.tx_tbl[i].ra[1], info.tx_tbl[i].ra[2],
+				     info.tx_tbl[i].ra[3], info.tx_tbl[i].ra[4],
+				     info.tx_tbl[i].ra[5]);
+	}
+
+	if (info.rx_tbl_num) {
+		p += sprintf(p, "Rx reorder table:\n");
+		for (i = 0; i < info.rx_tbl_num; i++) {
+
+			p += sprintf(p, "tid = %d, "
+				     "ta = %02x:%02x:%02x:%02x:%02x:%02x, "
+				     "start_win = %d, "
+				     "win_size = %d, buffer: ",
+				     info.rx_tbl[i].tid,
+				     info.rx_tbl[i].ta[0], info.rx_tbl[i].ta[1],
+				     info.rx_tbl[i].ta[2], info.rx_tbl[i].ta[3],
+				     info.rx_tbl[i].ta[4], info.rx_tbl[i].ta[5],
+				     info.rx_tbl[i].start_win,
+				     info.rx_tbl[i].win_size);
+
+			for (j = 0; j < info.rx_tbl[i].win_size; j++)
+				p += sprintf(p, "%c ",
+					     info.rx_tbl[i].buffer[j] ?
+					     '1' : '0');
+
+			p += sprintf(p, "\n");
+		}
+	}
+
+	ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
+				      (unsigned long) p - page);
+
+free_and_exit:
+	free_page(page);
+	return ret;
+}
+
+static u32 saved_reg_type, saved_reg_offset, saved_reg_value;
+
+/*
+ * Proc regrdwr file write handler.
+ *
+ * This function is called when the 'regrdwr' file is opened for writing
+ *
+ * This function can be used to write to a register.
+ */
+static ssize_t
+mwifiex_regrdwr_write(struct file *file,
+		      const char __user *ubuf, size_t count, loff_t *ppos)
+{
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *) addr;
+	size_t buf_size = min(count, (size_t) (PAGE_SIZE - 1));
+	int ret = 0;
+	u32 reg_type = 0, reg_offset = 0, reg_value = UINT_MAX;
+
+	if (!buf)
+		return -ENOMEM;
+
+
+	if (copy_from_user(buf, ubuf, buf_size)) {
+		ret = -EFAULT;
+		goto done;
+	}
+
+	sscanf(buf, "%u %x %x", &reg_type, &reg_offset, &reg_value);
+
+	if (reg_type == 0 || reg_offset == 0) {
+		ret = -EINVAL;
+		goto done;
+	} else {
+		saved_reg_type = reg_type;
+		saved_reg_offset = reg_offset;
+		saved_reg_value = reg_value;
+		ret = count;
+	}
+done:
+	free_page(addr);
+	return ret;
+}
+
+/*
+ * Proc regrdwr file read handler.
+ *
+ * This function is called when the 'regrdwr' file is opened for reading
+ *
+ * This function can be used to read from a register.
+ */
+static ssize_t
+mwifiex_regrdwr_read(struct file *file, char __user *ubuf,
+		     size_t count, loff_t *ppos)
+{
+	struct mwifiex_private *priv =
+		(struct mwifiex_private *) file->private_data;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *) addr;
+	int pos = 0, ret = 0;
+	u32 reg_value;
+
+	if (!buf)
+		return -ENOMEM;
+
+	if (!saved_reg_type) {
+		/* No command has been given */
+		pos += snprintf(buf, PAGE_SIZE, "0");
+		goto done;
+	}
+	/* Set command has been given */
+	if (saved_reg_value != UINT_MAX) {
+		ret = mwifiex_reg_write(priv, saved_reg_type, saved_reg_offset,
+					saved_reg_value);
+
+		pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n",
+				saved_reg_type, saved_reg_offset,
+				saved_reg_value);
+
+		ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
+
+		goto done;
+	}
+	/* Get command has been given */
+	ret = mwifiex_reg_read(priv, saved_reg_type,
+			       saved_reg_offset, &reg_value);
+	if (ret) {
+		ret = -EINVAL;
+		goto done;
+	}
+
+	pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", saved_reg_type,
+			saved_reg_offset, reg_value);
+
+	ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
+
+done:
+	free_page(addr);
+	return ret;
+}
+
+static u32 saved_offset = -1, saved_bytes = -1;
+
+/*
+ * Proc rdeeprom file write handler.
+ *
+ * This function is called when the 'rdeeprom' file is opened for writing
+ *
+ * This function can be used to write to a RDEEPROM location.
+ */
+static ssize_t
+mwifiex_rdeeprom_write(struct file *file,
+		       const char __user *ubuf, size_t count, loff_t *ppos)
+{
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *) addr;
+	size_t buf_size = min(count, (size_t) (PAGE_SIZE - 1));
+	int ret = 0;
+	int offset = -1, bytes = -1;
+
+	if (!buf)
+		return -ENOMEM;
+
+
+	if (copy_from_user(buf, ubuf, buf_size)) {
+		ret = -EFAULT;
+		goto done;
+	}
+
+	sscanf(buf, "%d %d", &offset, &bytes);
+
+	if (offset == -1 || bytes == -1) {
+		ret = -EINVAL;
+		goto done;
+	} else {
+		saved_offset = offset;
+		saved_bytes = bytes;
+		ret = count;
+	}
+done:
+	free_page(addr);
+	return ret;
+}
+
+/*
+ * Proc rdeeprom read write handler.
+ *
+ * This function is called when the 'rdeeprom' file is opened for reading
+ *
+ * This function can be used to read from a RDEEPROM location.
+ */
+static ssize_t
+mwifiex_rdeeprom_read(struct file *file, char __user *ubuf,
+		      size_t count, loff_t *ppos)
+{
+	struct mwifiex_private *priv =
+		(struct mwifiex_private *) file->private_data;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *) addr;
+	int pos = 0, ret = 0, i = 0;
+	u8 value[MAX_EEPROM_DATA];
+
+	if (!buf)
+		return -ENOMEM;
+
+	if (saved_offset == -1) {
+		/* No command has been given */
+		pos += snprintf(buf, PAGE_SIZE, "0");
+		goto done;
+	}
+
+	/* Get command has been given */
+	ret = mwifiex_eeprom_read(priv, (u16) saved_offset,
+				  (u16) saved_bytes, value);
+	if (ret) {
+		ret = -EINVAL;
+		goto done;
+	}
+
+	pos += snprintf(buf, PAGE_SIZE, "%d %d ", saved_offset, saved_bytes);
+
+	for (i = 0; i < saved_bytes; i++)
+		pos += snprintf(buf + strlen(buf), PAGE_SIZE, "%d ", value[i]);
+
+	ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
+
+done:
+	free_page(addr);
+	return ret;
+}
+
+
+#define MWIFIEX_DFS_ADD_FILE(name) do {                                 \
+	if (!debugfs_create_file(#name, 0644, priv->dfs_dev_dir,        \
+			priv, &mwifiex_dfs_##name##_fops))              \
+		return;                                                 \
+} while (0);
+
+#define MWIFIEX_DFS_FILE_OPS(name)                                      \
+static const struct file_operations mwifiex_dfs_##name##_fops = {       \
+	.read = mwifiex_##name##_read,                                  \
+	.write = mwifiex_##name##_write,                                \
+	.open = mwifiex_open_generic,                                   \
+};
+
+#define MWIFIEX_DFS_FILE_READ_OPS(name)                                 \
+static const struct file_operations mwifiex_dfs_##name##_fops = {       \
+	.read = mwifiex_##name##_read,                                  \
+	.open = mwifiex_open_generic,                                   \
+};
+
+#define MWIFIEX_DFS_FILE_WRITE_OPS(name)                                \
+static const struct file_operations mwifiex_dfs_##name##_fops = {       \
+	.write = mwifiex_##name##_write,                                \
+	.open = mwifiex_open_generic,                                   \
+};
+
+
+MWIFIEX_DFS_FILE_READ_OPS(info);
+MWIFIEX_DFS_FILE_READ_OPS(debug);
+MWIFIEX_DFS_FILE_READ_OPS(getlog);
+MWIFIEX_DFS_FILE_OPS(regrdwr);
+MWIFIEX_DFS_FILE_OPS(rdeeprom);
+
+/*
+ * This function creates the debug FS directory structure and the files.
+ */
+void
+mwifiex_dev_debugfs_init(struct mwifiex_private *priv)
+{
+	if (!mwifiex_dfs_dir || !priv)
+		return;
+
+	priv->dfs_dev_dir = debugfs_create_dir(priv->netdev->name,
+					       mwifiex_dfs_dir);
+
+	if (!priv->dfs_dev_dir)
+		return;
+
+	MWIFIEX_DFS_ADD_FILE(info);
+	MWIFIEX_DFS_ADD_FILE(debug);
+	MWIFIEX_DFS_ADD_FILE(getlog);
+	MWIFIEX_DFS_ADD_FILE(regrdwr);
+	MWIFIEX_DFS_ADD_FILE(rdeeprom);
+
+	return;
+}
+
+/*
+ * This function removes the debug FS directory structure and the files.
+ */
+void
+mwifiex_dev_debugfs_remove(struct mwifiex_private *priv)
+{
+	if (!priv)
+		return;
+
+	debugfs_remove_recursive(priv->dfs_dev_dir);
+	return;
+}
+
+/*
+ * This function creates the top level proc directory.
+ */
+void
+mwifiex_debugfs_init(void)
+{
+	if (!mwifiex_dfs_dir)
+		mwifiex_dfs_dir = debugfs_create_dir("mwifiex", NULL);
+}
+
+/*
+ * This function removes the top level proc directory.
+ */
+void
+mwifiex_debugfs_remove(void)
+{
+	if (mwifiex_dfs_dir)
+		debugfs_remove(mwifiex_dfs_dir);
+}
diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h
new file mode 100644
index 0000000..c3c15f9
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/decl.h
@@ -0,0 +1,153 @@
+/*
+ * Marvell Wireless LAN device driver: generic data structures and APIs
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#ifndef _MWIFIEX_DECL_H_
+#define _MWIFIEX_DECL_H_
+
+#undef pr_fmt
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/wait.h>
+#include <linux/timer.h>
+#include <linux/ieee80211.h>
+
+
+#define MWIFIEX_MAX_BSS_NUM         (1)
+
+#define MWIFIEX_MIN_DATA_HEADER_LEN 32	/* (sizeof(mwifiex_txpd)) */
+
+#define MWIFIEX_MAX_TX_BASTREAM_SUPPORTED	2
+#define MWIFIEX_MAX_RX_BASTREAM_SUPPORTED	16
+
+#define MWIFIEX_AMPDU_DEF_TXWINSIZE        32
+#define MWIFIEX_AMPDU_DEF_RXWINSIZE        16
+#define MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT  0xffff
+
+#define MWIFIEX_RATE_INDEX_HRDSSS0 0
+#define MWIFIEX_RATE_INDEX_HRDSSS3 3
+#define MWIFIEX_RATE_INDEX_OFDM0   4
+#define MWIFIEX_RATE_INDEX_OFDM7   11
+#define MWIFIEX_RATE_INDEX_MCS0    12
+
+#define MWIFIEX_RATE_BITMAP_OFDM0  16
+#define MWIFIEX_RATE_BITMAP_OFDM7  23
+#define MWIFIEX_RATE_BITMAP_MCS0   32
+#define MWIFIEX_RATE_BITMAP_MCS127 159
+
+#define MWIFIEX_RX_DATA_BUF_SIZE     (4 * 1024)
+
+#define MWIFIEX_RTS_MIN_VALUE              (0)
+#define MWIFIEX_RTS_MAX_VALUE              (2347)
+#define MWIFIEX_FRAG_MIN_VALUE             (256)
+#define MWIFIEX_FRAG_MAX_VALUE             (2346)
+
+#define MWIFIEX_SDIO_BLOCK_SIZE            256
+
+#define MWIFIEX_BUF_FLAG_REQUEUED_PKT      BIT(0)
+
+enum mwifiex_error_code {
+	MWIFIEX_ERROR_NO_ERROR = 0,
+	MWIFIEX_ERROR_FW_NOT_READY = 0x00000001,
+	MWIFIEX_ERROR_FW_BUSY,
+	MWIFIEX_ERROR_FW_CMDRESP,
+	MWIFIEX_ERROR_PKT_SIZE_INVALID = 0x80000001,
+	MWIFIEX_ERROR_PKT_TIMEOUT,
+	MWIFIEX_ERROR_CMD_INVALID,
+	MWIFIEX_ERROR_CMD_TIMEOUT,
+	MWIFIEX_ERROR_CMD_DNLD_FAIL,
+	MWIFIEX_ERROR_CMD_CANCEL,
+	MWIFIEX_ERROR_CMD_RESP_FAIL,
+	MWIFIEX_ERROR_ASSOC_FAIL,
+	MWIFIEX_ERROR_EVENT_UNKNOWN,
+	MWIFIEX_ERROR_INVALID_PARAMETER,
+};
+
+enum mwifiex_bss_type {
+	MWIFIEX_BSS_TYPE_STA = 0,
+	MWIFIEX_BSS_TYPE_UAP = 1,
+	MWIFIEX_BSS_TYPE_ANY = 0xff,
+};
+
+enum mwifiex_bss_role {
+	MWIFIEX_BSS_ROLE_STA = 0,
+	MWIFIEX_BSS_ROLE_UAP = 1,
+	MWIFIEX_BSS_ROLE_ANY = 0xff,
+};
+
+#define BSS_ROLE_BIT_MASK    BIT(0)
+
+#define GET_BSS_ROLE(priv)   ((priv)->bss_role & BSS_ROLE_BIT_MASK)
+
+enum mwifiex_data_frame_type {
+	MWIFIEX_DATA_FRAME_TYPE_ETH_II = 0,
+	MWIFIEX_DATA_FRAME_TYPE_802_11,
+};
+
+struct mwifiex_fw_image {
+	u8 *helper_buf;
+	u32 helper_len;
+	u8 *fw_buf;
+	u32 fw_len;
+};
+
+struct mwifiex_802_11_ssid {
+	u32 ssid_len;
+	u8 ssid[IEEE80211_MAX_SSID_LEN];
+};
+
+struct mwifiex_wait_queue {
+	u32 bss_index;
+	wait_queue_head_t *wait;
+	u16 *condition;
+	u32 start_time;
+	int status;
+	u32 enabled;
+};
+
+struct mwifiex_rxinfo {
+	u8 bss_index;
+	struct sk_buff *parent;
+	u8 use_count;
+};
+
+struct mwifiex_txinfo {
+	u32 status_code;
+	u8 flags;
+	u8 bss_index;
+};
+
+struct mwifiex_bss_attr {
+	u32 bss_type;
+	u32 frame_type;
+	u32 active;
+	u32 bss_priority;
+	u32 bss_num;
+};
+
+enum mwifiex_wmm_ac_e {
+	WMM_AC_BK,
+	WMM_AC_BE,
+	WMM_AC_VI,
+	WMM_AC_VO
+} __packed;
+
+struct mwifiex_device {
+	struct mwifiex_bss_attr bss_attr[MWIFIEX_MAX_BSS_NUM];
+};
+#endif /* !_MWIFIEX_DECL_H_ */
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
new file mode 100644
index 0000000..2b93811
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -0,0 +1,1229 @@
+/*
+ * Marvell Wireless LAN device driver: Firmware specific macros & structures
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#ifndef _MWIFIEX_FW_H_
+#define _MWIFIEX_FW_H_
+
+#include <linux/if_ether.h>
+
+
+#define INTF_HEADER_LEN     4
+
+struct rfc_1042_hdr {
+	u8 llc_dsap;
+	u8 llc_ssap;
+	u8 llc_ctrl;
+	u8 snap_oui[3];
+	u16 snap_type;
+};
+
+struct rx_packet_hdr {
+	struct ethhdr eth803_hdr;
+	struct rfc_1042_hdr rfc1042_hdr;
+};
+
+struct tx_packet_hdr {
+	struct ethhdr eth803_hdr;
+	struct rfc_1042_hdr rfc1042_hdr;
+};
+
+#define B_SUPPORTED_RATES               5
+#define G_SUPPORTED_RATES               9
+#define BG_SUPPORTED_RATES              13
+#define A_SUPPORTED_RATES               9
+#define HOSTCMD_SUPPORTED_RATES         14
+#define N_SUPPORTED_RATES               3
+#define ALL_802_11_BANDS           (BAND_A | BAND_B | BAND_G | BAND_GN)
+
+#define FW_MULTI_BANDS_SUPPORT  (BIT(8) | BIT(9) | BIT(10) | BIT(11))
+#define IS_SUPPORT_MULTI_BANDS(adapter)        \
+	(adapter->fw_cap_info & FW_MULTI_BANDS_SUPPORT)
+#define GET_FW_DEFAULT_BANDS(adapter)  \
+	((adapter->fw_cap_info >> 8) & ALL_802_11_BANDS)
+
+extern u8 supported_rates_b[B_SUPPORTED_RATES];
+extern u8 supported_rates_g[G_SUPPORTED_RATES];
+extern u8 supported_rates_bg[BG_SUPPORTED_RATES];
+extern u8 supported_rates_a[A_SUPPORTED_RATES];
+extern u8 supported_rates_n[N_SUPPORTED_RATES];
+
+#define HostCmd_WEP_KEY_INDEX_MASK              0x3fff
+
+#define KEY_INFO_ENABLED        0x01
+enum KEY_TYPE_ID {
+	KEY_TYPE_ID_WEP = 0,
+	KEY_TYPE_ID_TKIP,
+	KEY_TYPE_ID_AES,
+	KEY_TYPE_ID_WAPI,
+};
+
+enum KEY_INFO_WEP {
+	KEY_INFO_WEP_MCAST = 0x01,
+	KEY_INFO_WEP_UNICAST = 0x02,
+	KEY_INFO_WEP_ENABLED = 0x04
+};
+
+enum KEY_INFO_TKIP {
+	KEY_INFO_TKIP_MCAST = 0x01,
+	KEY_INFO_TKIP_UNICAST = 0x02,
+	KEY_INFO_TKIP_ENABLED = 0x04
+};
+
+enum KEY_INFO_AES {
+	KEY_INFO_AES_MCAST = 0x01,
+	KEY_INFO_AES_UNICAST = 0x02,
+	KEY_INFO_AES_ENABLED = 0x04
+};
+
+#define WAPI_KEY_LEN			50
+
+enum KEY_INFO_WAPI {
+	KEY_INFO_WAPI_MCAST = 0x01,
+	KEY_INFO_WAPI_UNICAST = 0x02,
+	KEY_INFO_WAPI_ENABLED = 0x04
+};
+
+#define MAX_POLL_TRIES			100
+
+#define MAX_MULTI_INTERFACE_POLL_TRIES  1000
+
+#define MAX_FIRMWARE_POLL_TRIES			100
+
+#define FIRMWARE_READY				0xfedc
+
+enum MWIFIEX_802_11_PRIVACY_FILTER {
+	MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL,
+	MWIFIEX_802_11_PRIV_FILTER_8021X_WEP
+};
+
+enum MWIFIEX_802_11_WEP_STATUS {
+	MWIFIEX_802_11_WEP_ENABLED,
+	MWIFIEX_802_11_WEP_DISABLED,
+};
+
+#define CAL_SNR(RSSI, NF)		((s16)((s16)(RSSI)-(s16)(NF)))
+
+#define PROPRIETARY_TLV_BASE_ID                 0x0100
+#define TLV_TYPE_KEY_MATERIAL       (PROPRIETARY_TLV_BASE_ID + 0)
+#define TLV_TYPE_CHANLIST           (PROPRIETARY_TLV_BASE_ID + 1)
+#define TLV_TYPE_NUMPROBES          (PROPRIETARY_TLV_BASE_ID + 2)
+#define TLV_TYPE_PASSTHROUGH        (PROPRIETARY_TLV_BASE_ID + 10)
+#define TLV_TYPE_WMMQSTATUS         (PROPRIETARY_TLV_BASE_ID + 16)
+#define TLV_TYPE_WILDCARDSSID       (PROPRIETARY_TLV_BASE_ID + 18)
+#define TLV_TYPE_TSFTIMESTAMP       (PROPRIETARY_TLV_BASE_ID + 19)
+#define TLV_TYPE_AUTH_TYPE          (PROPRIETARY_TLV_BASE_ID + 31)
+#define TLV_TYPE_CHANNELBANDLIST    (PROPRIETARY_TLV_BASE_ID + 42)
+#define TLV_TYPE_RATE_DROP_CONTROL  (PROPRIETARY_TLV_BASE_ID + 82)
+#define TLV_TYPE_RATE_SCOPE         (PROPRIETARY_TLV_BASE_ID + 83)
+#define TLV_TYPE_POWER_GROUP        (PROPRIETARY_TLV_BASE_ID + 84)
+#define TLV_TYPE_WAPI_IE            (PROPRIETARY_TLV_BASE_ID + 94)
+#define TLV_TYPE_AUTO_DS_PARAM      (PROPRIETARY_TLV_BASE_ID + 113)
+#define TLV_TYPE_PS_PARAM           (PROPRIETARY_TLV_BASE_ID + 114)
+
+#define MWIFIEX_TX_DATA_BUF_SIZE_2K        2048
+
+#define SSN_MASK         0xfff0
+
+#define BA_RESULT_SUCCESS        0x0
+#define BA_RESULT_TIMEOUT        0x2
+
+#define IS_BASTREAM_SETUP(ptr)  (ptr->ba_status)
+
+#define BA_STREAM_NOT_ALLOWED   0xff
+
+#define IS_11N_ENABLED(priv) ((priv->adapter->config_bands & BAND_GN || \
+			priv->adapter->config_bands & BAND_AN) \
+			&& priv->curr_bss_params.bss_descriptor.bcn_ht_cap)
+#define INITIATOR_BIT(DelBAParamSet) (((DelBAParamSet) &\
+			BIT(DELBA_INITIATOR_POS)) >> DELBA_INITIATOR_POS)
+
+#define MWIFIEX_TX_DATA_BUF_SIZE_4K        4096
+#define MWIFIEX_TX_DATA_BUF_SIZE_8K        8192
+#define NON_GREENFIELD_STAS     0x04
+
+#define ISSUPP_11NENABLED(FwCapInfo) (FwCapInfo & BIT(11))
+
+/* dev_cap bitmap
+ * BIT
+ * 0-16		reserved
+ * 17		IEEE80211_HT_CAP_SUP_WIDTH_20_40
+ * 18-22	reserved
+ * 23		IEEE80211_HT_CAP_SGI_20
+ * 24		IEEE80211_HT_CAP_SGI_40
+ * 25		IEEE80211_HT_CAP_TX_STBC
+ * 26		IEEE80211_HT_CAP_RX_STBC
+ * 27-28	reserved
+ * 29		IEEE80211_HT_CAP_GRN_FLD
+ * 30-31	reserved
+ */
+#define ISSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap & BIT(17))
+#define ISSUPP_SHORTGI20(Dot11nDevCap) (Dot11nDevCap & BIT(23))
+#define ISSUPP_SHORTGI40(Dot11nDevCap) (Dot11nDevCap & BIT(24))
+#define ISSUPP_TXSTBC(Dot11nDevCap) (Dot11nDevCap & BIT(25))
+#define ISSUPP_RXSTBC(Dot11nDevCap) (Dot11nDevCap & BIT(26))
+#define ISSUPP_GREENFIELD(Dot11nDevCap) (Dot11nDevCap & BIT(29))
+
+#define GET_RXMCSSUPP(DevMCSSupported) (DevMCSSupported & 0x0f)
+#define RESETHT_EXTCAP_RDG(HTExtCap) (HTExtCap &= ~BIT(11))
+#define SETHT_MCS32(x) (x[4] |= 1)
+
+#define SET_SECONDARYCHAN(RadioType, SECCHAN) (RadioType |= (SECCHAN << 4))
+
+#define LLC_SNAP_LEN    8
+
+#define MOD_CLASS_HR_DSSS       0x03
+#define MOD_CLASS_OFDM          0x07
+#define MOD_CLASS_HT            0x08
+#define HT_BW_20    0
+#define HT_BW_40    1
+
+#define HostCmd_CMD_GET_HW_SPEC                       0x0003
+#define HostCmd_CMD_802_11_SCAN                       0x0006
+#define HostCmd_CMD_802_11_GET_LOG                    0x000b
+#define HostCmd_CMD_MAC_MULTICAST_ADR                 0x0010
+#define HostCmd_CMD_802_11_EEPROM_ACCESS              0x0059
+#define HostCmd_CMD_802_11_ASSOCIATE                  0x0012
+#define HostCmd_CMD_802_11_SNMP_MIB                   0x0016
+#define HostCmd_CMD_MAC_REG_ACCESS                    0x0019
+#define HostCmd_CMD_BBP_REG_ACCESS                    0x001a
+#define HostCmd_CMD_RF_REG_ACCESS                     0x001b
+#define HostCmd_CMD_PMIC_REG_ACCESS                   0x00ad
+#define HostCmd_CMD_802_11_RF_CHANNEL                 0x001d
+#define HostCmd_CMD_802_11_DEAUTHENTICATE             0x0024
+#define HostCmd_CMD_MAC_CONTROL                       0x0028
+#define HostCmd_CMD_802_11_AD_HOC_START               0x002b
+#define HostCmd_CMD_802_11_AD_HOC_JOIN                0x002c
+#define HostCmd_CMD_802_11_AD_HOC_STOP                0x0040
+#define HostCmd_CMD_802_11_MAC_ADDRESS                0x004D
+#define HostCmd_CMD_802_11D_DOMAIN_INFO               0x005b
+#define HostCmd_CMD_802_11_KEY_MATERIAL               0x005e
+#define HostCmd_CMD_802_11_BG_SCAN_QUERY              0x006c
+#define HostCmd_CMD_WMM_GET_STATUS                    0x0071
+#define HostCmd_CMD_802_11_TX_RATE_QUERY              0x007f
+#define HostCmd_CMD_802_11_IBSS_COALESCING_STATUS     0x0083
+#define HostCmd_CMD_VERSION_EXT                       0x0097
+#define HostCmd_CMD_RSSI_INFO                         0x00a4
+#define HostCmd_CMD_FUNC_INIT                         0x00a9
+#define HostCmd_CMD_FUNC_SHUTDOWN                     0x00aa
+#define HostCmd_CMD_11N_CFG                           0x00cd
+#define HostCmd_CMD_11N_ADDBA_REQ                     0x00ce
+#define HostCmd_CMD_11N_ADDBA_RSP                     0x00cf
+#define HostCmd_CMD_11N_DELBA                         0x00d0
+#define HostCmd_CMD_RECONFIGURE_TX_BUFF               0x00d9
+#define HostCmd_CMD_AMSDU_AGGR_CTRL                   0x00df
+#define HostCmd_CMD_TXPWR_CFG                         0x00d1
+#define HostCmd_CMD_TX_RATE_CFG                       0x00d6
+#define HostCmd_CMD_802_11_PS_MODE_ENH                0x00e4
+#define HostCmd_CMD_802_11_HS_CFG_ENH                 0x00e5
+#define HostCmd_CMD_CAU_REG_ACCESS                    0x00ed
+#define HostCmd_CMD_SET_BSS_MODE                      0x00f7
+
+
+enum ENH_PS_MODES {
+	EN_PS = 1,
+	DIS_PS = 2,
+	EN_AUTO_DS = 3,
+	DIS_AUTO_DS = 4,
+	SLEEP_CONFIRM = 5,
+	GET_PS = 0,
+	EN_AUTO_PS = 0xff,
+	DIS_AUTO_PS = 0xfe,
+};
+
+#define HostCmd_RET_BIT                       0x8000
+#define HostCmd_ACT_GEN_GET                   0x0000
+#define HostCmd_ACT_GEN_SET                   0x0001
+#define HostCmd_RESULT_OK                     0x0000
+
+#define HostCmd_ACT_MAC_RX_ON                 0x0001
+#define HostCmd_ACT_MAC_TX_ON                 0x0002
+#define HostCmd_ACT_MAC_WEP_ENABLE            0x0008
+#define HostCmd_ACT_MAC_ETHERNETII_ENABLE     0x0010
+#define HostCmd_ACT_MAC_PROMISCUOUS_ENABLE    0x0080
+#define HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE  0x0100
+#define HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON     0x2000
+
+#define HostCmd_BSS_MODE_IBSS               0x0002
+#define HostCmd_BSS_MODE_ANY                0x0003
+
+#define HostCmd_SCAN_RADIO_TYPE_BG          0
+#define HostCmd_SCAN_RADIO_TYPE_A           1
+
+#define HOST_SLEEP_CFG_CANCEL		0xffffffff
+#define HOST_SLEEP_CFG_COND_DEF		0x0000000f
+#define HOST_SLEEP_CFG_GPIO_DEF		0xff
+#define HOST_SLEEP_CFG_GAP_DEF		0
+
+#define CMD_F_HOSTCMD           (1 << 0)
+#define CMD_F_CANCELED          (1 << 1)
+
+#define HostCmd_CMD_ID_MASK             0x0fff
+
+#define HostCmd_SEQ_NUM_MASK            0x00ff
+
+#define HostCmd_BSS_NUM_MASK            0x0f00
+
+#define HostCmd_BSS_TYPE_MASK           0xf000
+
+#define HostCmd_SET_SEQ_NO_BSS_INFO(seq, num, type) {   \
+	(((seq) & 0x00ff) |                             \
+	 (((num) & 0x000f) << 8)) |                     \
+	(((type) & 0x000f) << 12);                  }
+
+#define HostCmd_GET_SEQ_NO(seq)       \
+	((seq) & HostCmd_SEQ_NUM_MASK)
+
+#define HostCmd_GET_BSS_NO(seq)         \
+	(((seq) & HostCmd_BSS_NUM_MASK) >> 8)
+
+#define HostCmd_GET_BSS_TYPE(seq)       \
+	(((seq) & HostCmd_BSS_TYPE_MASK) >> 12)
+
+#define EVENT_DUMMY_HOST_WAKEUP_SIGNAL  0x00000001
+#define EVENT_LINK_LOST                 0x00000003
+#define EVENT_LINK_SENSED               0x00000004
+#define EVENT_MIB_CHANGED               0x00000006
+#define EVENT_INIT_DONE                 0x00000007
+#define EVENT_DEAUTHENTICATED           0x00000008
+#define EVENT_DISASSOCIATED             0x00000009
+#define EVENT_PS_AWAKE                  0x0000000a
+#define EVENT_PS_SLEEP                  0x0000000b
+#define EVENT_MIC_ERR_MULTICAST         0x0000000d
+#define EVENT_MIC_ERR_UNICAST           0x0000000e
+#define EVENT_DEEP_SLEEP_AWAKE          0x00000010
+#define EVENT_ADHOC_BCN_LOST            0x00000011
+
+#define EVENT_WMM_STATUS_CHANGE         0x00000017
+#define EVENT_BG_SCAN_REPORT            0x00000018
+#define EVENT_RSSI_LOW                  0x00000019
+#define EVENT_SNR_LOW                   0x0000001a
+#define EVENT_MAX_FAIL                  0x0000001b
+#define EVENT_RSSI_HIGH                 0x0000001c
+#define EVENT_SNR_HIGH                  0x0000001d
+#define EVENT_IBSS_COALESCED            0x0000001e
+#define EVENT_DATA_RSSI_LOW             0x00000024
+#define EVENT_DATA_SNR_LOW              0x00000025
+#define EVENT_DATA_RSSI_HIGH            0x00000026
+#define EVENT_DATA_SNR_HIGH             0x00000027
+#define EVENT_LINK_QUALITY              0x00000028
+#define EVENT_PORT_RELEASE              0x0000002b
+#define EVENT_PRE_BEACON_LOST           0x00000031
+#define EVENT_ADDBA                     0x00000033
+#define EVENT_DELBA                     0x00000034
+#define EVENT_BA_STREAM_TIEMOUT         0x00000037
+#define EVENT_AMSDU_AGGR_CTRL           0x00000042
+#define EVENT_WEP_ICV_ERR               0x00000046
+#define EVENT_HS_ACT_REQ                0x00000047
+#define EVENT_BW_CHANGE                 0x00000048
+
+#define EVENT_HOSTWAKE_STAIE		0x0000004d
+
+#define EVENT_ID_MASK                   0xffff
+#define BSS_NUM_MASK                    0xf
+
+#define EVENT_GET_BSS_NUM(event_cause)          \
+	(((event_cause) >> 16) & BSS_NUM_MASK)
+
+#define EVENT_GET_BSS_TYPE(event_cause)         \
+	(((event_cause) >> 24) & 0x00ff)
+
+struct mwifiex_ie_types_header {
+	__le16 type;
+	__le16 len;
+} __packed;
+
+struct mwifiex_ie_types_data {
+	struct mwifiex_ie_types_header header;
+	u8 data[1];
+} __packed;
+
+#define MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET 0x01
+#define MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET 0x08
+
+struct txpd {
+	u8 bss_type;
+	u8 bss_num;
+	__le16 tx_pkt_length;
+	__le16 tx_pkt_offset;
+	__le16 tx_pkt_type;
+	__le32 tx_control;
+	u8 priority;
+	u8 flags;
+	u8 pkt_delay_2ms;
+	u8 reserved1;
+} __packed;
+
+struct rxpd {
+	u8 bss_type;
+	u8 bss_num;
+	u16 rx_pkt_length;
+	u16 rx_pkt_offset;
+	u16 rx_pkt_type;
+	u16 seq_num;
+	u8 priority;
+	u8 rx_rate;
+	s8 snr;
+	s8 nf;
+	/* Ht Info [Bit 0] RxRate format: LG=0, HT=1
+	 * [Bit 1]  HT Bandwidth: BW20 = 0, BW40 = 1
+	 * [Bit 2]  HT Guard Interval: LGI = 0, SGI = 1 */
+	u8 ht_info;
+	u8 reserved;
+} __packed;
+
+enum mwifiex_chan_scan_mode_bitmasks {
+	MWIFIEX_PASSIVE_SCAN = BIT(0),
+	MWIFIEX_DISABLE_CHAN_FILT = BIT(1),
+};
+
+#define SECOND_CHANNEL_BELOW    0x30
+#define SECOND_CHANNEL_ABOVE    0x10
+struct mwifiex_chan_scan_param_set {
+	u8 radio_type;
+	u8 chan_number;
+	u8 chan_scan_mode_bitmap;
+	__le16 min_scan_time;
+	__le16 max_scan_time;
+} __packed;
+
+struct mwifiex_ie_types_chan_list_param_set {
+	struct mwifiex_ie_types_header header;
+	struct mwifiex_chan_scan_param_set chan_scan_param[1];
+} __packed;
+
+struct chan_band_param_set {
+	u8 radio_type;
+	u8 chan_number;
+};
+
+struct mwifiex_ie_types_chan_band_list_param_set {
+	struct mwifiex_ie_types_header header;
+	struct chan_band_param_set chan_band_param[1];
+} __packed;
+
+struct mwifiex_ie_types_rates_param_set {
+	struct mwifiex_ie_types_header header;
+	u8 rates[1];
+} __packed;
+
+struct mwifiex_ie_types_ssid_param_set {
+	struct mwifiex_ie_types_header header;
+	u8 ssid[1];
+} __packed;
+
+struct mwifiex_ie_types_num_probes {
+	struct mwifiex_ie_types_header header;
+	__le16 num_probes;
+} __packed;
+
+struct mwifiex_ie_types_wildcard_ssid_params {
+	struct mwifiex_ie_types_header header;
+	u8 max_ssid_length;
+	u8 ssid[1];
+} __packed;
+
+#define TSF_DATA_SIZE            8
+struct mwifiex_ie_types_tsf_timestamp {
+	struct mwifiex_ie_types_header header;
+	u8 tsf_data[1];
+} __packed;
+
+struct mwifiex_cf_param_set {
+	u8 cfp_cnt;
+	u8 cfp_period;
+	u16 cfp_max_duration;
+	u16 cfp_duration_remaining;
+} __packed;
+
+struct mwifiex_ibss_param_set {
+	u16 atim_window;
+} __packed;
+
+struct mwifiex_ie_types_ss_param_set {
+	struct mwifiex_ie_types_header header;
+	union {
+		struct mwifiex_cf_param_set cf_param_set[1];
+		struct mwifiex_ibss_param_set ibss_param_set[1];
+	} cf_ibss;
+} __packed;
+
+struct mwifiex_fh_param_set {
+	u16 dwell_time;
+	u8 hop_set;
+	u8 hop_pattern;
+	u8 hop_index;
+} __packed;
+
+struct mwifiex_ds_param_set {
+	u8 current_chan;
+} __packed;
+
+struct mwifiex_ie_types_phy_param_set {
+	struct mwifiex_ie_types_header header;
+	union {
+		struct mwifiex_fh_param_set fh_param_set[1];
+		struct mwifiex_ds_param_set ds_param_set[1];
+	} fh_ds;
+} __packed;
+
+struct mwifiex_ie_types_auth_type {
+	struct mwifiex_ie_types_header header;
+	__le16 auth_type;
+} __packed;
+
+struct mwifiex_ie_types_vendor_param_set {
+	struct mwifiex_ie_types_header header;
+	u8 ie[MWIFIEX_MAX_VSIE_LEN];
+};
+
+struct mwifiex_ie_types_rsn_param_set {
+	struct mwifiex_ie_types_header header;
+	u8 rsn_ie[1];
+} __packed;
+
+#define KEYPARAMSET_FIXED_LEN 6
+
+struct mwifiex_ie_type_key_param_set {
+	__le16 type;
+	__le16 length;
+	__le16 key_type_id;
+	__le16 key_info;
+	__le16 key_len;
+	u8 key[50];
+} __packed;
+
+struct host_cmd_ds_802_11_key_material {
+	__le16 action;
+	struct mwifiex_ie_type_key_param_set key_param_set;
+} __packed;
+
+struct host_cmd_ds_gen {
+	u16 command;
+	u16 size;
+	u16 seq_num;
+	u16 result;
+};
+
+#define S_DS_GEN        sizeof(struct host_cmd_ds_gen)
+
+enum sleep_resp_ctrl {
+	RESP_NOT_NEEDED = 0,
+	RESP_NEEDED,
+};
+
+struct mwifiex_ps_param {
+	__le16 null_pkt_interval;
+	__le16 multiple_dtims;
+	__le16 bcn_miss_timeout;
+	__le16 local_listen_interval;
+	__le16 adhoc_wake_period;
+	__le16 mode;
+	__le16 delay_to_ps;
+};
+
+#define BITMAP_AUTO_DS         0x01
+#define BITMAP_STA_PS          0x10
+
+struct mwifiex_ie_types_auto_ds_param {
+	struct mwifiex_ie_types_header header;
+	__le16 deep_sleep_timeout;
+} __packed;
+
+struct mwifiex_ie_types_ps_param {
+	struct mwifiex_ie_types_header header;
+	struct mwifiex_ps_param param;
+} __packed;
+
+struct host_cmd_ds_802_11_ps_mode_enh {
+	__le16 action;
+
+	union {
+		struct mwifiex_ps_param opt_ps;
+		__le16 ps_bitmap;
+	} params;
+} __packed;
+
+struct host_cmd_ds_get_hw_spec {
+	__le16 hw_if_version;
+	__le16 version;
+	__le16 reserved;
+	__le16 num_of_mcast_adr;
+	u8 permanent_addr[ETH_ALEN];
+	__le16 region_code;
+	__le16 number_of_antenna;
+	__le32 fw_release_number;
+	__le32 reserved_1;
+	__le32 reserved_2;
+	__le32 reserved_3;
+	__le32 fw_cap_info;
+	__le32 dot_11n_dev_cap;
+	u8 dev_mcs_support;
+	__le16 mp_end_port;	/* SDIO only, reserved for other interfacces */
+	__le16 reserved_4;
+} __packed;
+
+struct host_cmd_ds_802_11_rssi_info {
+	__le16 action;
+	__le16 ndata;
+	__le16 nbcn;
+	__le16 reserved[9];
+	long long reserved_1;
+};
+
+struct host_cmd_ds_802_11_rssi_info_rsp {
+	__le16 action;
+	__le16 ndata;
+	__le16 nbcn;
+	__le16 data_rssi_last;
+	__le16 data_nf_last;
+	__le16 data_rssi_avg;
+	__le16 data_nf_avg;
+	__le16 bcn_rssi_last;
+	__le16 bcn_nf_last;
+	__le16 bcn_rssi_avg;
+	__le16 bcn_nf_avg;
+	long long tsf_bcn;
+};
+
+struct host_cmd_ds_802_11_mac_address {
+	__le16 action;
+	u8 mac_addr[ETH_ALEN];
+};
+
+struct host_cmd_ds_mac_control {
+	__le16 action;
+	__le16 reserved;
+};
+
+struct host_cmd_ds_mac_multicast_adr {
+	__le16 action;
+	__le16 num_of_adrs;
+	u8 mac_list[MWIFIEX_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
+} __packed;
+
+struct host_cmd_ds_802_11_deauthenticate {
+	u8 mac_addr[ETH_ALEN];
+	__le16 reason_code;
+} __packed;
+
+struct host_cmd_ds_802_11_associate {
+	u8 peer_sta_addr[ETH_ALEN];
+	__le16 cap_info_bitmap;
+	__le16 listen_interval;
+	__le16 beacon_period;
+	u8 dtim_period;
+} __packed;
+
+struct ieee_types_assoc_rsp {
+	__le16 cap_info_bitmap;
+	__le16 status_code;
+	__le16 a_id;
+	u8 ie_buffer[1];
+} __packed;
+
+struct host_cmd_ds_802_11_associate_rsp {
+	struct ieee_types_assoc_rsp assoc_rsp;
+} __packed;
+
+struct ieee_types_cf_param_set {
+	u8 element_id;
+	u8 len;
+	u8 cfp_cnt;
+	u8 cfp_period;
+	u16 cfp_max_duration;
+	u16 cfp_duration_remaining;
+} __packed;
+
+struct ieee_types_ibss_param_set {
+	u8 element_id;
+	u8 len;
+	__le16 atim_window;
+} __packed;
+
+union ieee_types_ss_param_set {
+	struct ieee_types_cf_param_set cf_param_set;
+	struct ieee_types_ibss_param_set ibss_param_set;
+} __packed;
+
+struct ieee_types_fh_param_set {
+	u8 element_id;
+	u8 len;
+	__le16 dwell_time;
+	u8 hop_set;
+	u8 hop_pattern;
+	u8 hop_index;
+} __packed;
+
+struct ieee_types_ds_param_set {
+	u8 element_id;
+	u8 len;
+	u8 current_chan;
+} __packed;
+
+union ieee_types_phy_param_set {
+	struct ieee_types_fh_param_set fh_param_set;
+	struct ieee_types_ds_param_set ds_param_set;
+} __packed;
+
+struct host_cmd_ds_802_11_ad_hoc_start {
+	u8 ssid[IEEE80211_MAX_SSID_LEN];
+	u8 bss_mode;
+	__le16 beacon_period;
+	u8 dtim_period;
+	union ieee_types_ss_param_set ss_param_set;
+	union ieee_types_phy_param_set phy_param_set;
+	u16 reserved1;
+	__le16 cap_info_bitmap;
+	u8 DataRate[HOSTCMD_SUPPORTED_RATES];
+} __packed;
+
+struct host_cmd_ds_802_11_ad_hoc_result {
+	u8 pad[3];
+	u8 bssid[ETH_ALEN];
+} __packed;
+
+struct adhoc_bss_desc {
+	u8 bssid[ETH_ALEN];
+	u8 ssid[IEEE80211_MAX_SSID_LEN];
+	u8 bss_mode;
+	__le16 beacon_period;
+	u8 dtim_period;
+	u8 time_stamp[8];
+	u8 local_time[8];
+	union ieee_types_phy_param_set phy_param_set;
+	union ieee_types_ss_param_set ss_param_set;
+	__le16 cap_info_bitmap;
+	u8 data_rates[HOSTCMD_SUPPORTED_RATES];
+
+	/*
+	 *  DO NOT ADD ANY FIELDS TO THIS STRUCTURE.
+	 *  It is used in the Adhoc join command and will cause a
+	 *  binary layout mismatch with the firmware
+	 */
+} __packed;
+
+struct host_cmd_ds_802_11_ad_hoc_join {
+	struct adhoc_bss_desc bss_descriptor;
+	u16 reserved1;
+	u16 reserved2;
+} __packed;
+
+struct host_cmd_ds_802_11_get_log {
+	__le32 mcast_tx_frame;
+	__le32 failed;
+	__le32 retry;
+	__le32 multi_retry;
+	__le32 frame_dup;
+	__le32 rts_success;
+	__le32 rts_failure;
+	__le32 ack_failure;
+	__le32 rx_frag;
+	__le32 mcast_rx_frame;
+	__le32 fcs_error;
+	__le32 tx_frame;
+	__le32 reserved;
+	__le32 wep_icv_err_cnt[4];
+};
+
+struct host_cmd_ds_tx_rate_query {
+	u8 tx_rate;
+	/* Ht Info [Bit 0] RxRate format: LG=0, HT=1
+	 * [Bit 1]  HT Bandwidth: BW20 = 0, BW40 = 1
+	 * [Bit 2]  HT Guard Interval: LGI = 0, SGI = 1 */
+	u8 ht_info;
+} __packed;
+
+enum Host_Sleep_Action {
+	HS_CONFIGURE = 0x0001,
+	HS_ACTIVATE  = 0x0002,
+};
+
+struct mwifiex_hs_config_param {
+	__le32 conditions;
+	u8 gpio;
+	u8 gap;
+} __packed;
+
+struct hs_activate_param {
+	u16 resp_ctrl;
+} __packed;
+
+struct host_cmd_ds_802_11_hs_cfg_enh {
+	__le16 action;
+
+	union {
+		struct mwifiex_hs_config_param hs_config;
+		struct hs_activate_param hs_activate;
+	} params;
+} __packed;
+
+enum SNMP_MIB_INDEX {
+	OP_RATE_SET_I = 1,
+	DTIM_PERIOD_I = 3,
+	RTS_THRESH_I = 5,
+	SHORT_RETRY_LIM_I = 6,
+	LONG_RETRY_LIM_I = 7,
+	FRAG_THRESH_I = 8,
+	DOT11D_I = 9,
+};
+
+#define MAX_SNMP_BUF_SIZE   128
+
+struct host_cmd_ds_802_11_snmp_mib {
+	__le16 query_type;
+	__le16 oid;
+	__le16 buf_size;
+	u8 value[1];
+} __packed;
+
+struct mwifiex_rate_scope {
+	__le16 type;
+	__le16 length;
+	__le16 hr_dsss_rate_bitmap;
+	__le16 ofdm_rate_bitmap;
+	__le16 ht_mcs_rate_bitmap[8];
+} __packed;
+
+struct mwifiex_rate_drop_pattern {
+	__le16 type;
+	__le16 length;
+	__le32 rate_drop_mode;
+} __packed;
+
+struct host_cmd_ds_tx_rate_cfg {
+	__le16 action;
+	__le16 cfg_index;
+} __packed;
+
+struct mwifiex_power_group {
+	u8 modulation_class;
+	u8 first_rate_code;
+	u8 last_rate_code;
+	s8 power_step;
+	s8 power_min;
+	s8 power_max;
+	u8 ht_bandwidth;
+	u8 reserved;
+} __packed;
+
+struct mwifiex_types_power_group {
+	u16 type;
+	u16 length;
+} __packed;
+
+struct host_cmd_ds_txpwr_cfg {
+	__le16 action;
+	__le16 cfg_index;
+	__le32 mode;
+} __packed;
+
+#define MWIFIEX_USER_SCAN_CHAN_MAX             50
+
+#define MWIFIEX_MAX_SSID_LIST_LENGTH         10
+
+struct mwifiex_scan_cmd_config {
+	/*
+	 *  BSS Type to be sent in the firmware command
+	 *
+	 *  Field can be used to restrict the types of networks returned in the
+	 *    scan.  Valid settings are:
+	 *
+	 *   - MWIFIEX_SCAN_MODE_BSS  (infrastructure)
+	 *   - MWIFIEX_SCAN_MODE_IBSS (adhoc)
+	 *   - MWIFIEX_SCAN_MODE_ANY  (unrestricted, adhoc and infrastructure)
+	 */
+	u8 bss_mode;
+
+	/* Specific BSSID used to filter scan results in the firmware */
+	u8 specific_bssid[ETH_ALEN];
+
+	/* Length of TLVs sent in command starting at tlvBuffer */
+	u32 tlv_buf_len;
+
+	/*
+	 *  SSID TLV(s) and ChanList TLVs to be sent in the firmware command
+	 *
+	 *  TLV_TYPE_CHANLIST, mwifiex_ie_types_chan_list_param_set
+	 *  WLAN_EID_SSID, mwifiex_ie_types_ssid_param_set
+	 */
+	u8 tlv_buf[1];	/* SSID TLV(s) and ChanList TLVs are stored
+				   here */
+} __packed;
+
+struct mwifiex_user_scan_chan {
+	u8 chan_number;
+	u8 radio_type;
+	u8 scan_type;
+	u8 reserved;
+	u32 scan_time;
+} __packed;
+
+struct mwifiex_user_scan_ssid {
+	u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
+	u8 max_len;
+} __packed;
+
+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
+	 *
+	 *  Field can be used to restrict the types of networks returned in the
+	 *    scan.  Valid settings are:
+	 *
+	 *   - MWIFIEX_SCAN_MODE_BSS  (infrastructure)
+	 *   - MWIFIEX_SCAN_MODE_IBSS (adhoc)
+	 *   - MWIFIEX_SCAN_MODE_ANY  (unrestricted, adhoc and infrastructure)
+	 */
+	u8 bss_mode;
+	/* Configure the number of probe requests for active chan scans */
+	u8 num_probes;
+	u8 reserved;
+	/* BSSID filter sent in the firmware command to limit the results */
+	u8 specific_bssid[ETH_ALEN];
+	/* SSID filter list used in the to limit the scan results */
+	struct mwifiex_user_scan_ssid ssid_list[MWIFIEX_MAX_SSID_LIST_LENGTH];
+	/* Variable number (fixed maximum) of channels to scan up */
+	struct mwifiex_user_scan_chan chan_list[MWIFIEX_USER_SCAN_CHAN_MAX];
+} __packed;
+
+struct ie_body {
+	u8 grp_key_oui[4];
+	u8 ptk_cnt[2];
+	u8 ptk_body[4];
+} __packed;
+
+struct host_cmd_ds_802_11_scan {
+	u8 bss_mode;
+	u8 bssid[ETH_ALEN];
+	u8 tlv_buffer[1];
+} __packed;
+
+struct host_cmd_ds_802_11_scan_rsp {
+	__le16 bss_descript_size;
+	u8 number_of_sets;
+	u8 bss_desc_and_tlv_buffer[1];
+} __packed;
+
+struct host_cmd_ds_802_11_bg_scan_query {
+	u8 flush;
+} __packed;
+
+struct host_cmd_ds_802_11_bg_scan_query_rsp {
+	u32 report_condition;
+	struct host_cmd_ds_802_11_scan_rsp scan_resp;
+} __packed;
+
+struct mwifiex_ietypes_domain_param_set {
+	struct mwifiex_ie_types_header header;
+	u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
+	struct ieee80211_country_ie_triplet triplet[1];
+} __packed;
+
+struct host_cmd_ds_802_11d_domain_info {
+	__le16 action;
+	struct mwifiex_ietypes_domain_param_set domain;
+} __packed;
+
+struct host_cmd_ds_802_11d_domain_info_rsp {
+	__le16 action;
+	struct mwifiex_ietypes_domain_param_set domain;
+} __packed;
+
+struct host_cmd_ds_11n_addba_req {
+	u8 add_req_result;
+	u8 peer_mac_addr[ETH_ALEN];
+	u8 dialog_token;
+	__le16 block_ack_param_set;
+	__le16 block_ack_tmo;
+	__le16 ssn;
+} __packed;
+
+struct host_cmd_ds_11n_addba_rsp {
+	u8 add_rsp_result;
+	u8 peer_mac_addr[ETH_ALEN];
+	u8 dialog_token;
+	__le16 status_code;
+	__le16 block_ack_param_set;
+	__le16 block_ack_tmo;
+	__le16 ssn;
+} __packed;
+
+struct host_cmd_ds_11n_delba {
+	u8 del_result;
+	u8 peer_mac_addr[ETH_ALEN];
+	__le16 del_ba_param_set;
+	__le16 reason_code;
+	u8 reserved;
+} __packed;
+
+struct host_cmd_ds_11n_batimeout {
+	u8 tid;
+	u8 peer_mac_addr[ETH_ALEN];
+	u8 origninator;
+} __packed;
+
+struct host_cmd_ds_11n_cfg {
+	__le16 action;
+	__le16 ht_tx_cap;
+	__le16 ht_tx_info;
+} __packed;
+
+struct host_cmd_ds_txbuf_cfg {
+	__le16 action;
+	__le16 buff_size;
+	__le16 mp_end_port;	/* SDIO only, reserved for other interfacces */
+	__le16 reserved3;
+} __packed;
+
+struct host_cmd_ds_amsdu_aggr_ctrl {
+	__le16 action;
+	__le16 enable;
+	__le16 curr_buf_size;
+} __packed;
+
+struct mwifiex_ie_types_wmm_param_set {
+	struct mwifiex_ie_types_header header;
+	u8 wmm_ie[1];
+};
+
+struct mwifiex_ie_types_wmm_queue_status {
+	struct mwifiex_ie_types_header header;
+	u8 queue_index;
+	u8 disabled;
+	u16 medium_time;
+	u8 flow_required;
+	u8 flow_created;
+	u32 reserved;
+};
+
+struct ieee_types_vendor_header {
+	u8 element_id;
+	u8 len;
+	u8 oui[3];
+	u8 oui_type;
+	u8 oui_subtype;
+	u8 version;
+} __packed;
+
+struct ieee_types_wmm_ac_parameters {
+	u8 aci_aifsn_bitmap;
+	u8 ecw_bitmap;
+	__le16 tx_op_limit;
+} __packed;
+
+struct ieee_types_wmm_parameter {
+	/*
+	 * WMM Parameter IE - Vendor Specific Header:
+	 *   element_id  [221/0xdd]
+	 *   Len         [24]
+	 *   Oui         [00:50:f2]
+	 *   OuiType     [2]
+	 *   OuiSubType  [1]
+	 *   Version     [1]
+	 */
+	struct ieee_types_vendor_header vend_hdr;
+	u8 qos_info_bitmap;
+	u8 reserved;
+	struct ieee_types_wmm_ac_parameters ac_params[IEEE80211_MAX_QUEUES];
+} __packed;
+
+struct ieee_types_wmm_info {
+
+	/*
+	 * WMM Info IE - Vendor Specific Header:
+	 *   element_id  [221/0xdd]
+	 *   Len         [7]
+	 *   Oui         [00:50:f2]
+	 *   OuiType     [2]
+	 *   OuiSubType  [0]
+	 *   Version     [1]
+	 */
+	struct ieee_types_vendor_header vend_hdr;
+
+	u8 qos_info_bitmap;
+} __packed;
+
+struct host_cmd_ds_wmm_get_status {
+	u8 queue_status_tlv[sizeof(struct mwifiex_ie_types_wmm_queue_status) *
+			      IEEE80211_MAX_QUEUES];
+	u8 wmm_param_tlv[sizeof(struct ieee_types_wmm_parameter) + 2];
+} __packed;
+
+struct mwifiex_wmm_ac_status {
+	u8 disabled;
+	u8 flow_required;
+	u8 flow_created;
+};
+
+struct mwifiex_ie_types_htcap {
+	struct mwifiex_ie_types_header header;
+	struct ieee80211_ht_cap ht_cap;
+} __packed;
+
+struct mwifiex_ie_types_htinfo {
+	struct mwifiex_ie_types_header header;
+	struct ieee80211_ht_info ht_info;
+} __packed;
+
+struct mwifiex_ie_types_2040bssco {
+	struct mwifiex_ie_types_header header;
+	u8 bss_co_2040;
+} __packed;
+
+struct mwifiex_ie_types_extcap {
+	struct mwifiex_ie_types_header header;
+	u8 ext_cap;
+} __packed;
+
+struct host_cmd_ds_mac_reg_access {
+	__le16 action;
+	__le16 offset;
+	__le32 value;
+} __packed;
+
+struct host_cmd_ds_bbp_reg_access {
+	__le16 action;
+	__le16 offset;
+	u8 value;
+	u8 reserved[3];
+} __packed;
+
+struct host_cmd_ds_rf_reg_access {
+	__le16 action;
+	__le16 offset;
+	u8 value;
+	u8 reserved[3];
+} __packed;
+
+struct host_cmd_ds_pmic_reg_access {
+	__le16 action;
+	__le16 offset;
+	u8 value;
+	u8 reserved[3];
+} __packed;
+
+struct host_cmd_ds_802_11_eeprom_access {
+	__le16 action;
+
+	__le16 offset;
+	__le16 byte_count;
+	u8 value;
+} __packed;
+
+struct host_cmd_ds_802_11_rf_channel {
+	__le16 action;
+	__le16 current_channel;
+	__le16 rf_type;
+	__le16 reserved;
+	u8 reserved_1[32];
+} __packed;
+
+struct host_cmd_ds_version_ext {
+	u8 version_str_sel;
+	char version_str[128];
+} __packed;
+
+struct host_cmd_ds_802_11_ibss_status {
+	__le16 action;
+	__le16 enable;
+	u8 bssid[ETH_ALEN];
+	__le16 beacon_interval;
+	__le16 atim_window;
+	__le16 use_g_rate_protect;
+} __packed;
+
+#define CONNECTION_TYPE_INFRA   0
+#define CONNECTION_TYPE_ADHOC   1
+
+struct host_cmd_ds_set_bss_mode {
+	u8 con_type;
+} __packed;
+
+struct host_cmd_ds_command {
+	__le16 command;
+	__le16 size;
+	__le16 seq_num;
+	__le16 result;
+	union {
+		struct host_cmd_ds_get_hw_spec hw_spec;
+		struct host_cmd_ds_mac_control mac_ctrl;
+		struct host_cmd_ds_802_11_mac_address mac_addr;
+		struct host_cmd_ds_mac_multicast_adr mc_addr;
+		struct host_cmd_ds_802_11_get_log get_log;
+		struct host_cmd_ds_802_11_rssi_info rssi_info;
+		struct host_cmd_ds_802_11_rssi_info_rsp rssi_info_rsp;
+		struct host_cmd_ds_802_11_snmp_mib smib;
+		struct host_cmd_ds_802_11_rf_channel rf_channel;
+		struct host_cmd_ds_tx_rate_query tx_rate;
+		struct host_cmd_ds_tx_rate_cfg tx_rate_cfg;
+		struct host_cmd_ds_txpwr_cfg txp_cfg;
+		struct host_cmd_ds_802_11_ps_mode_enh psmode_enh;
+		struct host_cmd_ds_802_11_hs_cfg_enh opt_hs_cfg;
+		struct host_cmd_ds_802_11_scan scan;
+		struct host_cmd_ds_802_11_scan_rsp scan_resp;
+		struct host_cmd_ds_802_11_bg_scan_query bg_scan_query;
+		struct host_cmd_ds_802_11_bg_scan_query_rsp bg_scan_query_resp;
+		struct host_cmd_ds_802_11_associate associate;
+		struct host_cmd_ds_802_11_associate_rsp associate_rsp;
+		struct host_cmd_ds_802_11_deauthenticate deauth;
+		struct host_cmd_ds_802_11_ad_hoc_start adhoc_start;
+		struct host_cmd_ds_802_11_ad_hoc_result adhoc_result;
+		struct host_cmd_ds_802_11_ad_hoc_join adhoc_join;
+		struct host_cmd_ds_802_11d_domain_info domain_info;
+		struct host_cmd_ds_802_11d_domain_info_rsp domain_info_resp;
+		struct host_cmd_ds_11n_addba_req add_ba_req;
+		struct host_cmd_ds_11n_addba_rsp add_ba_rsp;
+		struct host_cmd_ds_11n_delba del_ba;
+		struct host_cmd_ds_txbuf_cfg tx_buf;
+		struct host_cmd_ds_amsdu_aggr_ctrl amsdu_aggr_ctrl;
+		struct host_cmd_ds_11n_cfg htcfg;
+		struct host_cmd_ds_wmm_get_status get_wmm_status;
+		struct host_cmd_ds_802_11_key_material key_material;
+		struct host_cmd_ds_version_ext verext;
+		struct host_cmd_ds_802_11_ibss_status ibss_coalescing;
+		struct host_cmd_ds_mac_reg_access mac_reg;
+		struct host_cmd_ds_bbp_reg_access bbp_reg;
+		struct host_cmd_ds_rf_reg_access rf_reg;
+		struct host_cmd_ds_pmic_reg_access pmic_reg;
+		struct host_cmd_ds_set_bss_mode bss_mode;
+		struct host_cmd_ds_802_11_eeprom_access eeprom;
+	} params;
+} __packed;
+
+struct mwifiex_opt_sleep_confirm {
+	__le16 command;
+	__le16 size;
+	__le16 seq_num;
+	__le16 result;
+	__le16 action;
+	__le16 resp_ctrl;
+} __packed;
+
+struct mwifiex_opt_sleep_confirm_buffer {
+	u8 hdr[4];
+	struct mwifiex_opt_sleep_confirm ps_cfm_sleep;
+} __packed;
+#endif /* !_MWIFIEX_FW_H_ */
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
new file mode 100644
index 0000000..8189862
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -0,0 +1,662 @@
+/*
+ * Marvell Wireless LAN device driver: HW/FW Initialization
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+#include "11n.h"
+
+/*
+ * This function adds a BSS priority table to the table list.
+ *
+ * The function allocates a new BSS priority table node and adds it to
+ * the end of BSS priority table list, kept in driver memory.
+ */
+static int mwifiex_add_bss_prio_tbl(struct mwifiex_private *priv)
+{
+	struct mwifiex_adapter *adapter = priv->adapter;
+	struct mwifiex_bss_prio_node *bss_prio;
+	int status = 0;
+	unsigned long flags;
+
+	bss_prio = kzalloc(sizeof(struct mwifiex_bss_prio_node), GFP_KERNEL);
+	if (!bss_prio) {
+		dev_err(adapter->dev, "%s: failed to alloc bss_prio\n",
+						__func__);
+		return -1;
+	}
+
+	bss_prio->priv = priv;
+	INIT_LIST_HEAD(&bss_prio->list);
+	if (!adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur)
+		adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur =
+			bss_prio;
+
+	spin_lock_irqsave(&adapter->bss_prio_tbl[priv->bss_priority]
+			.bss_prio_lock, flags);
+	list_add_tail(&bss_prio->list,
+			&adapter->bss_prio_tbl[priv->bss_priority]
+			.bss_prio_head);
+	spin_unlock_irqrestore(&adapter->bss_prio_tbl[priv->bss_priority]
+			.bss_prio_lock, flags);
+
+	return status;
+}
+
+/*
+ * This function initializes the private structure and sets default
+ * values to the members.
+ *
+ * Additionally, it also initializes all the locks and sets up all the
+ * lists.
+ */
+static int mwifiex_init_priv(struct mwifiex_private *priv)
+{
+	u32 i;
+	int ret = 0;
+
+	priv->media_connected = false;
+	memset(priv->curr_addr, 0xff, ETH_ALEN);
+
+	priv->pkt_tx_ctrl = 0;
+	priv->bss_mode = NL80211_IFTYPE_STATION;
+	priv->data_rate = 0;	/* Initially indicate the rate as auto */
+	priv->is_data_rate_auto = true;
+	priv->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR;
+	priv->data_avg_factor = DEFAULT_DATA_AVG_FACTOR;
+
+	priv->sec_info.wep_status = MWIFIEX_802_11_WEP_DISABLED;
+	priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM;
+	priv->sec_info.encryption_mode = 0;
+	for (i = 0; i < ARRAY_SIZE(priv->wep_key); i++)
+		memset(&priv->wep_key[i], 0, sizeof(struct mwifiex_wep_key));
+	priv->wep_key_curr_index = 0;
+	priv->curr_pkt_filter = HostCmd_ACT_MAC_RX_ON | HostCmd_ACT_MAC_TX_ON |
+				HostCmd_ACT_MAC_ETHERNETII_ENABLE;
+
+	priv->beacon_period = 100; /* beacon interval */ ;
+	priv->attempted_bss_desc = NULL;
+	memset(&priv->curr_bss_params, 0, sizeof(priv->curr_bss_params));
+	priv->listen_interval = MWIFIEX_DEFAULT_LISTEN_INTERVAL;
+
+	memset(&priv->prev_ssid, 0, sizeof(priv->prev_ssid));
+	memset(&priv->prev_bssid, 0, sizeof(priv->prev_bssid));
+	memset(&priv->assoc_rsp_buf, 0, sizeof(priv->assoc_rsp_buf));
+	priv->assoc_rsp_size = 0;
+	priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
+	priv->atim_window = 0;
+	priv->adhoc_state = ADHOC_IDLE;
+	priv->tx_power_level = 0;
+	priv->max_tx_power_level = 0;
+	priv->min_tx_power_level = 0;
+	priv->tx_rate = 0;
+	priv->rxpd_htinfo = 0;
+	priv->rxpd_rate = 0;
+	priv->rate_bitmap = 0;
+	priv->data_rssi_last = 0;
+	priv->data_rssi_avg = 0;
+	priv->data_nf_avg = 0;
+	priv->data_nf_last = 0;
+	priv->bcn_rssi_last = 0;
+	priv->bcn_rssi_avg = 0;
+	priv->bcn_nf_avg = 0;
+	priv->bcn_nf_last = 0;
+	memset(&priv->wpa_ie, 0, sizeof(priv->wpa_ie));
+	memset(&priv->aes_key, 0, sizeof(priv->aes_key));
+	priv->wpa_ie_len = 0;
+	priv->wpa_is_gtk_set = false;
+
+	memset(&priv->assoc_tlv_buf, 0, sizeof(priv->assoc_tlv_buf));
+	priv->assoc_tlv_buf_len = 0;
+	memset(&priv->wps, 0, sizeof(priv->wps));
+	memset(&priv->gen_ie_buf, 0, sizeof(priv->gen_ie_buf));
+	priv->gen_ie_buf_len = 0;
+	memset(priv->vs_ie, 0, sizeof(priv->vs_ie));
+
+	priv->wmm_required = true;
+	priv->wmm_enabled = false;
+	priv->wmm_qosinfo = 0;
+	priv->curr_bcn_buf = NULL;
+	priv->curr_bcn_size = 0;
+
+	priv->scan_block = false;
+
+	ret = mwifiex_add_bss_prio_tbl(priv);
+
+	return ret;
+}
+
+/*
+ * This function allocates buffers for members of the adapter
+ * structure.
+ *
+ * The memory allocated includes scan table, command buffers, and
+ * sleep confirm command buffer. In addition, the queues are
+ * also initialized.
+ */
+static int mwifiex_allocate_adapter(struct mwifiex_adapter *adapter)
+{
+	int ret = 0;
+	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 -1;
+	}
+
+	adapter->scan_table = temp_scan_table;
+
+	/* Allocate command buffer */
+	ret = mwifiex_alloc_cmd_buffer(adapter);
+	if (ret) {
+		dev_err(adapter->dev, "%s: failed to alloc cmd buffer\n",
+		       __func__);
+		return -1;
+	}
+
+	adapter->sleep_cfm =
+		dev_alloc_skb(sizeof(struct mwifiex_opt_sleep_confirm_buffer)
+				+ INTF_HEADER_LEN);
+
+	if (!adapter->sleep_cfm) {
+		dev_err(adapter->dev, "%s: failed to alloc sleep cfm"
+			" cmd buffer\n", __func__);
+		return -1;
+	}
+	skb_reserve(adapter->sleep_cfm, INTF_HEADER_LEN);
+
+	return 0;
+}
+
+/*
+ * This function initializes the adapter structure and sets default
+ * values to the members of adapter.
+ *
+ * This also initializes the WMM related parameters in the driver private
+ * structures.
+ */
+static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
+{
+	struct mwifiex_opt_sleep_confirm_buffer *sleep_cfm_buf = NULL;
+
+	skb_put(adapter->sleep_cfm, sizeof(sleep_cfm_buf->ps_cfm_sleep));
+	sleep_cfm_buf = (struct mwifiex_opt_sleep_confirm_buffer *)
+						(adapter->sleep_cfm->data);
+
+	adapter->cmd_sent = false;
+	adapter->data_sent = true;
+	adapter->cmd_resp_received = false;
+	adapter->event_received = false;
+	adapter->data_received = false;
+
+	adapter->surprise_removed = false;
+
+	adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING;
+
+	adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM;
+	adapter->ps_state = PS_STATE_AWAKE;
+	adapter->need_to_wakeup = false;
+
+	adapter->scan_mode = HostCmd_BSS_MODE_ANY;
+	adapter->specific_scan_time = MWIFIEX_SPECIFIC_SCAN_CHAN_TIME;
+	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
+						   will be used */
+
+	adapter->is_deep_sleep = false;
+
+	adapter->delay_null_pkt = false;
+	adapter->delay_to_ps = 1000;
+	adapter->enhanced_ps_mode = PS_MODE_AUTO;
+
+	adapter->gen_null_pkt = false;	/* Disable NULL Pkg generation by
+					   default */
+	adapter->pps_uapsd_mode = false; /* Disable pps/uapsd mode by
+					   default */
+	adapter->pm_wakeup_card_req = false;
+
+	adapter->pm_wakeup_fw_try = false;
+
+	adapter->max_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
+	adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
+	adapter->curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
+
+	adapter->is_hs_configured = false;
+	adapter->hs_cfg.conditions = cpu_to_le32(HOST_SLEEP_CFG_COND_DEF);
+	adapter->hs_cfg.gpio = HOST_SLEEP_CFG_GPIO_DEF;
+	adapter->hs_cfg.gap = HOST_SLEEP_CFG_GAP_DEF;
+	adapter->hs_activated = false;
+
+	memset(adapter->event_body, 0, sizeof(adapter->event_body));
+	adapter->hw_dot_11n_dev_cap = 0;
+	adapter->hw_dev_mcs_support = 0;
+	adapter->chan_offset = 0;
+	adapter->adhoc_11n_enabled = false;
+
+	mwifiex_wmm_init(adapter);
+
+	if (adapter->sleep_cfm) {
+		memset(&sleep_cfm_buf->ps_cfm_sleep, 0,
+			adapter->sleep_cfm->len);
+		sleep_cfm_buf->ps_cfm_sleep.command =
+			cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH);
+		sleep_cfm_buf->ps_cfm_sleep.size =
+			cpu_to_le16(adapter->sleep_cfm->len);
+		sleep_cfm_buf->ps_cfm_sleep.result = 0;
+		sleep_cfm_buf->ps_cfm_sleep.action = cpu_to_le16(SLEEP_CONFIRM);
+		sleep_cfm_buf->ps_cfm_sleep.resp_ctrl =
+			cpu_to_le16(RESP_NEEDED);
+	}
+	memset(&adapter->sleep_params, 0, sizeof(adapter->sleep_params));
+	memset(&adapter->sleep_period, 0, sizeof(adapter->sleep_period));
+	adapter->tx_lock_flag = false;
+	adapter->null_pkt_interval = 0;
+	adapter->fw_bands = 0;
+	adapter->config_bands = 0;
+	adapter->adhoc_start_band = 0;
+	adapter->scan_channels = NULL;
+	adapter->fw_release_number = 0;
+	adapter->fw_cap_info = 0;
+	memset(&adapter->upld_buf, 0, sizeof(adapter->upld_buf));
+	adapter->event_cause = 0;
+	adapter->region_code = 0;
+	adapter->bcn_miss_time_out = DEFAULT_BCN_MISS_TIMEOUT;
+	adapter->adhoc_awake_period = 0;
+	memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter));
+	adapter->arp_filter_size = 0;
+
+	return;
+}
+
+/*
+ * This function frees the adapter structure.
+ *
+ * The freeing operation is done recursively, by canceling all
+ * pending commands, freeing the member buffers previously
+ * allocated (command buffers, scan table buffer, sleep confirm
+ * command buffer), stopping the timers and calling the cleanup
+ * routines for every interface, before the actual adapter
+ * structure is freed.
+ */
+static void
+mwifiex_free_adapter(struct mwifiex_adapter *adapter)
+{
+	if (!adapter) {
+		pr_err("%s: adapter is NULL\n", __func__);
+		return;
+	}
+
+	mwifiex_cancel_all_pending_cmd(adapter);
+
+	/* Free lock variables */
+	mwifiex_free_lock_list(adapter);
+
+	/* Free command buffer */
+	dev_dbg(adapter->dev, "info: free cmd buffer\n");
+	mwifiex_free_cmd_buffer(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);
+
+	dev_kfree_skb_any(adapter->sleep_cfm);
+
+	return;
+}
+
+/*
+ *  This function intializes the lock variables and
+ *  the list heads.
+ */
+int mwifiex_init_lock_list(struct mwifiex_adapter *adapter)
+{
+	struct mwifiex_private   *priv = NULL;
+	s32           i = 0;
+	u32           j = 0;
+
+	spin_lock_init(&adapter->mwifiex_lock);
+	spin_lock_init(&adapter->int_lock);
+	spin_lock_init(&adapter->main_proc_lock);
+	spin_lock_init(&adapter->mwifiex_cmd_lock);
+	for (i = 0; i < adapter->priv_num; i++) {
+		if (adapter->priv[i]) {
+			priv = adapter->priv[i];
+			spin_lock_init(&priv->rx_pkt_lock);
+			spin_lock_init(&priv->wmm.ra_list_spinlock);
+			spin_lock_init(&priv->curr_bcn_buf_lock);
+		}
+	}
+
+	/* Initialize cmd_free_q */
+	INIT_LIST_HEAD(&adapter->cmd_free_q);
+	/* Initialize cmd_pending_q */
+	INIT_LIST_HEAD(&adapter->cmd_pending_q);
+	/* Initialize scan_pending_q */
+	INIT_LIST_HEAD(&adapter->scan_pending_q);
+
+	spin_lock_init(&adapter->cmd_free_q_lock);
+	spin_lock_init(&adapter->cmd_pending_q_lock);
+	spin_lock_init(&adapter->scan_pending_q_lock);
+
+	for (i = 0; i < adapter->priv_num; ++i) {
+		INIT_LIST_HEAD(&adapter->bss_prio_tbl[i].bss_prio_head);
+		adapter->bss_prio_tbl[i].bss_prio_cur = NULL;
+		spin_lock_init(&adapter->bss_prio_tbl[i].bss_prio_lock);
+	}
+
+	for (i = 0; i < adapter->priv_num; i++) {
+		if (!adapter->priv[i])
+			continue;
+		priv = adapter->priv[i];
+		for (j = 0; j < MAX_NUM_TID; ++j) {
+			INIT_LIST_HEAD(&priv->wmm.tid_tbl_ptr[j].ra_list);
+			spin_lock_init(&priv->wmm.tid_tbl_ptr[j].tid_tbl_lock);
+		}
+		INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr);
+		INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr);
+
+		spin_lock_init(&priv->tx_ba_stream_tbl_lock);
+		spin_lock_init(&priv->rx_reorder_tbl_lock);
+	}
+
+	return 0;
+}
+
+/*
+ *  This function releases the lock variables and frees the locks and
+ *  associated locks.
+ */
+void mwifiex_free_lock_list(struct mwifiex_adapter *adapter)
+{
+	struct mwifiex_private *priv = NULL;
+	s32           i = 0;
+	s32           j = 0;
+
+	/* Free lists */
+	list_del(&adapter->cmd_free_q);
+	list_del(&adapter->cmd_pending_q);
+	list_del(&adapter->scan_pending_q);
+
+	for (i = 0; i < adapter->priv_num; i++)
+		list_del(&adapter->bss_prio_tbl[i].bss_prio_head);
+
+	for (i = 0; i < adapter->priv_num; i++) {
+		if (adapter->priv[i]) {
+			priv = adapter->priv[i];
+			for (j = 0; j < MAX_NUM_TID; ++j)
+				list_del(&priv->wmm.tid_tbl_ptr[j].ra_list);
+			list_del(&priv->tx_ba_stream_tbl_ptr);
+			list_del(&priv->rx_reorder_tbl_ptr);
+		}
+	}
+
+	return;
+}
+
+/*
+ * This function initializes the firmware.
+ *
+ * The following operations are performed sequentially -
+ *      - Allocate adapter structure
+ *      - Initialize the adapter structure
+ *      - Initialize the private structure
+ *      - Add BSS priority tables to the adapter structure
+ *      - For each interface, send the init commands to firmware
+ *      - Send the first command in command pending queue, if available
+ */
+int mwifiex_init_fw(struct mwifiex_adapter *adapter)
+{
+	int ret = 0;
+	struct mwifiex_private *priv = NULL;
+	u8 i = 0;
+	u8 first_sta = true;
+	int is_cmd_pend_q_empty;
+	unsigned long flags;
+
+	adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING;
+
+	/* Allocate memory for member of adapter structure */
+	ret = mwifiex_allocate_adapter(adapter);
+	if (ret)
+		return -1;
+
+	/* Initialize adapter structure */
+	mwifiex_init_adapter(adapter);
+
+	for (i = 0; i < adapter->priv_num; i++) {
+		if (adapter->priv[i]) {
+			priv = adapter->priv[i];
+
+			/* Initialize private structure */
+			ret = mwifiex_init_priv(priv);
+			if (ret)
+				return -1;
+		}
+	}
+	for (i = 0; i < adapter->priv_num; i++) {
+		if (adapter->priv[i]) {
+			ret = mwifiex_sta_init_cmd(adapter->priv[i], first_sta);
+			if (ret == -1)
+				return -1;
+
+			first_sta = false;
+		}
+	}
+
+	spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
+	is_cmd_pend_q_empty = list_empty(&adapter->cmd_pending_q);
+	spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
+	if (!is_cmd_pend_q_empty) {
+		/* Send the first command in queue and return */
+		if (mwifiex_main_process(adapter) != -1)
+			ret = -EINPROGRESS;
+	} else {
+		adapter->hw_status = MWIFIEX_HW_STATUS_READY;
+	}
+
+	return ret;
+}
+
+/*
+ * This function deletes the BSS priority tables.
+ *
+ * The function traverses through all the allocated BSS priority nodes
+ * in every BSS priority table and frees them.
+ */
+static void mwifiex_delete_bss_prio_tbl(struct mwifiex_private *priv)
+{
+	int i;
+	struct mwifiex_adapter *adapter = priv->adapter;
+	struct mwifiex_bss_prio_node *bssprio_node = NULL, *tmp_node = NULL,
+								**cur = NULL;
+	struct list_head *head;
+	spinlock_t *lock;
+	unsigned long flags;
+
+	for (i = 0; i < adapter->priv_num; ++i) {
+		head = &adapter->bss_prio_tbl[i].bss_prio_head;
+		cur = &adapter->bss_prio_tbl[i].bss_prio_cur;
+		lock = &adapter->bss_prio_tbl[i].bss_prio_lock;
+		dev_dbg(adapter->dev, "info: delete BSS priority table,"
+				" index = %d, i = %d, head = %p, cur = %p\n",
+			      priv->bss_index, i, head, *cur);
+		if (*cur) {
+			spin_lock_irqsave(lock, flags);
+			if (list_empty(head)) {
+				spin_unlock_irqrestore(lock, flags);
+				continue;
+			}
+			bssprio_node = list_first_entry(head,
+					struct mwifiex_bss_prio_node, list);
+			spin_unlock_irqrestore(lock, flags);
+
+			list_for_each_entry_safe(bssprio_node, tmp_node, head,
+						 list) {
+				if (bssprio_node->priv == priv) {
+					dev_dbg(adapter->dev, "info: Delete "
+						"node %p, next = %p\n",
+						bssprio_node, tmp_node);
+					spin_lock_irqsave(lock, flags);
+					list_del(&bssprio_node->list);
+					spin_unlock_irqrestore(lock, flags);
+					kfree(bssprio_node);
+				}
+			}
+			*cur = (struct mwifiex_bss_prio_node *)head;
+		}
+	}
+}
+
+/*
+ * This function is used to shutdown the driver.
+ *
+ * The following operations are performed sequentially -
+ *      - Check if already shut down
+ *      - Make sure the main process has stopped
+ *      - Clean up the Tx and Rx queues
+ *      - Delete BSS priority tables
+ *      - Free the adapter
+ *      - Notify completion
+ */
+int
+mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
+{
+	int ret = -EINPROGRESS;
+	struct mwifiex_private *priv = NULL;
+	s32 i = 0;
+	unsigned long flags;
+
+	/* mwifiex already shutdown */
+	if (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY)
+		return 0;
+
+	adapter->hw_status = MWIFIEX_HW_STATUS_CLOSING;
+	/* wait for mwifiex_process to complete */
+	if (adapter->mwifiex_processing) {
+		dev_warn(adapter->dev, "main process is still running\n");
+		return ret;
+	}
+
+	/* shut down mwifiex */
+	dev_dbg(adapter->dev, "info: shutdown mwifiex...\n");
+
+	/* Clean up Tx/Rx queues and delete BSS priority table */
+	for (i = 0; i < adapter->priv_num; i++) {
+		if (adapter->priv[i]) {
+			priv = adapter->priv[i];
+
+			mwifiex_clean_txrx(priv);
+			mwifiex_delete_bss_prio_tbl(priv);
+		}
+	}
+
+	spin_lock_irqsave(&adapter->mwifiex_lock, flags);
+
+	/* Free adapter structure */
+	mwifiex_free_adapter(adapter);
+
+	spin_unlock_irqrestore(&adapter->mwifiex_lock, flags);
+
+	/* Notify completion */
+	ret = mwifiex_shutdown_fw_complete(adapter);
+
+	return ret;
+}
+
+/*
+ * This function downloads the firmware to the card.
+ *
+ * The actual download is preceded by two sanity checks -
+ *      - Check if firmware is already running
+ *      - Check if the interface is the winner to download the firmware
+ *
+ * ...and followed by another -
+ *      - Check if the firmware is downloaded successfully
+ *
+ * After download is successfully completed, the host interrupts are enabled.
+ */
+int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
+		    struct mwifiex_fw_image *pmfw)
+{
+	int ret = 0;
+	u32 poll_num = 1;
+	int winner;
+
+	/* Check if firmware is already running */
+	ret = adapter->if_ops.check_fw_status(adapter, poll_num, &winner);
+	if (!ret) {
+		dev_notice(adapter->dev,
+				"WLAN FW already running! Skip FW download\n");
+		goto done;
+	}
+	poll_num = MAX_FIRMWARE_POLL_TRIES;
+
+	/* Check if we are the winner for downloading FW */
+	if (!winner) {
+		dev_notice(adapter->dev,
+				"Other interface already running!"
+				" Skip FW download\n");
+		poll_num = MAX_MULTI_INTERFACE_POLL_TRIES;
+		goto poll_fw;
+	}
+	if (pmfw) {
+		/* Download firmware with helper */
+		ret = adapter->if_ops.prog_fw(adapter, pmfw);
+		if (ret) {
+			dev_err(adapter->dev, "prog_fw failed ret=%#x\n", ret);
+			return ret;
+		}
+	}
+
+poll_fw:
+	/* Check if the firmware is downloaded successfully or not */
+	ret = adapter->if_ops.check_fw_status(adapter, poll_num, NULL);
+	if (ret) {
+		dev_err(adapter->dev, "FW failed to be active in time\n");
+		return -1;
+	}
+done:
+	/* re-enable host interrupt for mwifiex after fw dnld is successful */
+	adapter->if_ops.enable_int(adapter);
+	return ret;
+}
diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h
new file mode 100644
index 0000000..703a6d1
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/ioctl.h
@@ -0,0 +1,411 @@
+/*
+ * Marvell Wireless LAN device driver: ioctl data structures & APIs
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#ifndef _MWIFIEX_IOCTL_H_
+#define _MWIFIEX_IOCTL_H_
+
+#include <net/mac80211.h>
+
+enum {
+	MWIFIEX_SCAN_MODE_UNCHANGED = 0,
+	MWIFIEX_SCAN_MODE_BSS,
+	MWIFIEX_SCAN_MODE_IBSS,
+	MWIFIEX_SCAN_MODE_ANY
+};
+
+enum {
+	MWIFIEX_SCAN_TYPE_UNCHANGED = 0,
+	MWIFIEX_SCAN_TYPE_ACTIVE,
+	MWIFIEX_SCAN_TYPE_PASSIVE
+};
+
+struct mwifiex_get_scan_table_fixed {
+	u8 bssid[ETH_ALEN];
+	u8 channel;
+	u8 rssi;
+	long long network_tsf;
+};
+
+struct mwifiex_scan_time_params {
+	u32 specific_scan_time;
+	u32 active_scan_time;
+	u32 passive_scan_time;
+};
+
+struct mwifiex_user_scan {
+	u32 scan_cfg_len;
+	u8 scan_cfg_buf[1];
+};
+
+struct mwifiex_scan_req {
+	u32 scan_mode;
+	u32 scan_type;
+	struct mwifiex_802_11_ssid scan_ssid;
+	struct mwifiex_scan_time_params scan_time;
+	struct mwifiex_user_scan user_scan;
+};
+
+struct mwifiex_scan_resp {
+	u32 num_in_scan_table;
+	u8 *scan_table;
+};
+
+#define MWIFIEX_PROMISC_MODE            1
+#define MWIFIEX_MULTICAST_MODE		2
+#define	MWIFIEX_ALL_MULTI_MODE		4
+#define MWIFIEX_MAX_MULTICAST_LIST_SIZE	32
+
+struct mwifiex_multicast_list {
+	u32 mode;
+	u32 num_multicast_addr;
+	u8 mac_list[MWIFIEX_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
+};
+
+#define MWIFIEX_MAX_CHANNEL_NUM		128
+
+struct mwifiex_chan_freq {
+	u32 channel;
+	u32 freq;
+};
+
+struct mwifiex_chan_list {
+	u32 num_of_chan;
+	struct mwifiex_chan_freq cf[MWIFIEX_MAX_CHANNEL_NUM];
+};
+
+struct mwifiex_ssid_bssid {
+	struct mwifiex_802_11_ssid ssid;
+	u8 bssid[ETH_ALEN];
+};
+
+enum {
+	BAND_B = 1,
+	BAND_G = 2,
+	BAND_A = 4,
+	BAND_GN = 8,
+	BAND_AN = 16,
+};
+
+#define NO_SEC_CHANNEL               0
+#define SEC_CHANNEL_ABOVE            1
+#define SEC_CHANNEL_BELOW            3
+
+struct mwifiex_ds_band_cfg {
+	u32 config_bands;
+	u32 adhoc_start_band;
+	u32 adhoc_channel;
+	u32 sec_chan_offset;
+};
+
+enum {
+	ADHOC_IDLE,
+	ADHOC_STARTED,
+	ADHOC_JOINED,
+	ADHOC_COALESCED
+};
+
+struct mwifiex_ds_get_stats {
+	u32 mcast_tx_frame;
+	u32 failed;
+	u32 retry;
+	u32 multi_retry;
+	u32 frame_dup;
+	u32 rts_success;
+	u32 rts_failure;
+	u32 ack_failure;
+	u32 rx_frag;
+	u32 mcast_rx_frame;
+	u32 fcs_error;
+	u32 tx_frame;
+	u32 wep_icv_error[4];
+};
+
+#define BCN_RSSI_LAST_MASK              0x00000001
+#define BCN_RSSI_AVG_MASK               0x00000002
+#define DATA_RSSI_LAST_MASK             0x00000004
+#define DATA_RSSI_AVG_MASK              0x00000008
+#define BCN_SNR_LAST_MASK               0x00000010
+#define BCN_SNR_AVG_MASK                0x00000020
+#define DATA_SNR_LAST_MASK              0x00000040
+#define DATA_SNR_AVG_MASK               0x00000080
+#define BCN_NF_LAST_MASK                0x00000100
+#define BCN_NF_AVG_MASK                 0x00000200
+#define DATA_NF_LAST_MASK               0x00000400
+#define DATA_NF_AVG_MASK                0x00000800
+#define ALL_RSSI_INFO_MASK              0x00000fff
+
+struct mwifiex_ds_get_signal {
+	/*
+	 * Bit0:  Last Beacon RSSI,  Bit1:  Average Beacon RSSI,
+	 * Bit2:  Last Data RSSI,    Bit3:  Average Data RSSI,
+	 * Bit4:  Last Beacon SNR,   Bit5:  Average Beacon SNR,
+	 * Bit6:  Last Data SNR,     Bit7:  Average Data SNR,
+	 * Bit8:  Last Beacon NF,    Bit9:  Average Beacon NF,
+	 * Bit10: Last Data NF,      Bit11: Average Data NF
+	 */
+	u16 selector;
+	s16 bcn_rssi_last;
+	s16 bcn_rssi_avg;
+	s16 data_rssi_last;
+	s16 data_rssi_avg;
+	s16 bcn_snr_last;
+	s16 bcn_snr_avg;
+	s16 data_snr_last;
+	s16 data_snr_avg;
+	s16 bcn_nf_last;
+	s16 bcn_nf_avg;
+	s16 data_nf_last;
+	s16 data_nf_avg;
+};
+
+struct mwifiex_fw_info {
+	u32 fw_ver;
+	u8 mac_addr[ETH_ALEN];
+};
+
+#define MWIFIEX_MAX_VER_STR_LEN    128
+
+struct mwifiex_ver_ext {
+	u32 version_str_sel;
+	char version_str[MWIFIEX_MAX_VER_STR_LEN];
+};
+
+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;
+	u32 max_power_level;
+	u32 min_power_level;
+	u32 adhoc_state;
+	signed int bcn_nf_last;
+	u32 wep_status;
+	u32 is_hs_configured;
+	u32 is_deep_sleep;
+	u8 bssid[ETH_ALEN];
+};
+
+#define MAX_NUM_TID     8
+
+#define MAX_RX_WINSIZE  64
+
+struct mwifiex_ds_rx_reorder_tbl {
+	u16 tid;
+	u8 ta[ETH_ALEN];
+	u32 start_win;
+	u32 win_size;
+	u32 buffer[MAX_RX_WINSIZE];
+};
+
+struct mwifiex_ds_tx_ba_stream_tbl {
+	u16 tid;
+	u8 ra[ETH_ALEN];
+};
+
+#define DBG_CMD_NUM	5
+
+struct mwifiex_debug_info {
+	u32 int_counter;
+	u32 packets_out[MAX_NUM_TID];
+	u32 max_tx_buf_size;
+	u32 tx_buf_size;
+	u32 curr_tx_buf_size;
+	u32 tx_tbl_num;
+	struct mwifiex_ds_tx_ba_stream_tbl
+		tx_tbl[MWIFIEX_MAX_TX_BASTREAM_SUPPORTED];
+	u32 rx_tbl_num;
+	struct mwifiex_ds_rx_reorder_tbl rx_tbl
+		[MWIFIEX_MAX_RX_BASTREAM_SUPPORTED];
+	u16 ps_mode;
+	u32 ps_state;
+	u8 is_deep_sleep;
+	u8 pm_wakeup_card_req;
+	u32 pm_wakeup_fw_try;
+	u8 is_hs_configured;
+	u8 hs_activated;
+	u32 num_cmd_host_to_card_failure;
+	u32 num_cmd_sleep_cfm_host_to_card_failure;
+	u32 num_tx_host_to_card_failure;
+	u32 num_event_deauth;
+	u32 num_event_disassoc;
+	u32 num_event_link_lost;
+	u32 num_cmd_deauth;
+	u32 num_cmd_assoc_success;
+	u32 num_cmd_assoc_failure;
+	u32 num_tx_timeout;
+	u32 num_cmd_timeout;
+	u16 timeout_cmd_id;
+	u16 timeout_cmd_act;
+	u16 last_cmd_id[DBG_CMD_NUM];
+	u16 last_cmd_act[DBG_CMD_NUM];
+	u16 last_cmd_index;
+	u16 last_cmd_resp_id[DBG_CMD_NUM];
+	u16 last_cmd_resp_index;
+	u16 last_event[DBG_CMD_NUM];
+	u16 last_event_index;
+	u8 data_sent;
+	u8 cmd_sent;
+	u8 cmd_resp_received;
+	u8 event_received;
+};
+
+#define MWIFIEX_KEY_INDEX_UNICAST	0x40000000
+#define MWIFIEX_MAX_KEY_LENGTH		32
+#define WAPI_RXPN_LEN			16
+
+struct mwifiex_ds_encrypt_key {
+	u32 key_disable;
+	u32 key_index;
+	u32 key_len;
+	u8 key_material[MWIFIEX_MAX_KEY_LENGTH];
+	u8 mac_addr[ETH_ALEN];
+	u32 is_wapi_key;
+	u8 wapi_rxpn[WAPI_RXPN_LEN];
+};
+
+struct mwifiex_rate_cfg {
+	u32 action;
+	u32 is_rate_auto;
+	u32 rate;
+};
+
+struct mwifiex_data_rate {
+	u32 tx_data_rate;
+	u32 rx_data_rate;
+};
+
+struct mwifiex_power_cfg {
+	u32 is_power_auto;
+	u32 power_level;
+};
+
+struct mwifiex_ds_hs_cfg {
+	u32 is_invoke_hostcmd;
+	/*  Bit0: non-unicast data
+	 *  Bit1: unicast data
+	 *  Bit2: mac events
+	 *  Bit3: magic packet
+	 */
+	u32 conditions;
+	u32 gpio;
+	u32 gap;
+};
+
+#define DEEP_SLEEP_ON  1
+#define DEEP_SLEEP_OFF 0
+
+#define DEEP_SLEEP_IDLE_TIME	100
+
+struct mwifiex_ds_auto_ds {
+	u16 auto_ds;
+	u16 idle_time;
+};
+
+#define PS_MODE_UNCHANGED			0
+#define PS_MODE_AUTO				1
+#define PS_MODE_POLL				2
+#define PS_MODE_NULL				3
+
+
+struct mwifiex_ds_pm_cfg {
+	union {
+		u32 ps_mode;
+		struct mwifiex_ds_hs_cfg hs_cfg;
+		struct mwifiex_ds_auto_ds auto_deep_sleep;
+		u32 sleep_period;
+	} param;
+};
+
+struct mwifiex_ioctl_wmm_queue_status_ac {
+	u8 wmm_acm;
+	u8 flow_required;
+	u8 flow_created;
+	u8 disabled;
+};
+
+struct mwifiex_ds_wmm_queue_status {
+	struct mwifiex_ioctl_wmm_queue_status_ac
+		ac_status[IEEE80211_MAX_QUEUES];
+};
+
+struct mwifiex_ds_11n_tx_cfg {
+	u16 tx_htcap;
+	u16 tx_htinfo;
+};
+
+struct mwifiex_ds_11n_amsdu_aggr_ctrl {
+	u16 enable;
+	u16 curr_buf_size;
+};
+
+#define MWIFIEX_NUM_OF_CMD_BUFFER	20
+#define MWIFIEX_SIZE_OF_CMD_BUFFER	2048
+
+enum {
+	MWIFIEX_IE_TYPE_GEN_IE = 0,
+	MWIFIEX_IE_TYPE_ARP_FILTER,
+};
+
+enum {
+	MWIFIEX_REG_MAC = 1,
+	MWIFIEX_REG_BBP,
+	MWIFIEX_REG_RF,
+	MWIFIEX_REG_PMIC,
+	MWIFIEX_REG_CAU,
+};
+
+struct mwifiex_ds_reg_rw {
+	__le32 type;
+	__le32 offset;
+	__le32 value;
+};
+
+#define MAX_EEPROM_DATA 256
+
+struct mwifiex_ds_read_eeprom {
+	__le16 offset;
+	__le16 byte_count;
+	u8 value[MAX_EEPROM_DATA];
+};
+
+struct mwifiex_ds_misc_gen_ie {
+	u32 type;
+	u32 len;
+	u8 ie_data[IW_CUSTOM_MAX];
+};
+
+struct mwifiex_ds_misc_cmd {
+	u32 len;
+	u8 cmd[MWIFIEX_SIZE_OF_CMD_BUFFER];
+};
+
+#define MWIFIEX_MAX_VSIE_LEN       (256)
+#define MWIFIEX_MAX_VSIE_NUM       (8)
+#define MWIFIEX_VSIE_MASK_SCAN     0x01
+#define MWIFIEX_VSIE_MASK_ASSOC    0x02
+#define MWIFIEX_VSIE_MASK_ADHOC    0x04
+
+enum {
+	MWIFIEX_FUNC_INIT = 1,
+	MWIFIEX_FUNC_SHUTDOWN,
+};
+
+#endif /* !_MWIFIEX_IOCTL_H_ */
diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c
new file mode 100644
index 0000000..7a9e0b5
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/join.c
@@ -0,0 +1,1462 @@
+/*
+ * Marvell Wireless LAN device driver: association and ad-hoc start/join
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+#include "11n.h"
+
+#define CAPINFO_MASK    (~(BIT(15) | BIT(14) | BIT(12) | BIT(11) | BIT(9)))
+
+/*
+ * Append a generic IE as a pass through TLV to a TLV buffer.
+ *
+ * This function is called from the network join command preparation routine.
+ *
+ * If the IE buffer has been setup by the application, this routine appends
+ * the buffer as a pass through TLV type to the request.
+ */
+static int
+mwifiex_cmd_append_generic_ie(struct mwifiex_private *priv, u8 **buffer)
+{
+	int ret_len = 0;
+	struct mwifiex_ie_types_header ie_header;
+
+	/* Null Checks */
+	if (!buffer)
+		return 0;
+	if (!(*buffer))
+		return 0;
+
+	/*
+	 * If there is a generic ie buffer setup, append it to the return
+	 *   parameter buffer pointer.
+	 */
+	if (priv->gen_ie_buf_len) {
+		dev_dbg(priv->adapter->dev, "info: %s: append generic %d to %p\n",
+				__func__, priv->gen_ie_buf_len, *buffer);
+
+		/* Wrap the generic IE buffer with a pass through TLV type */
+		ie_header.type = cpu_to_le16(TLV_TYPE_PASSTHROUGH);
+		ie_header.len = cpu_to_le16(priv->gen_ie_buf_len);
+		memcpy(*buffer, &ie_header, sizeof(ie_header));
+
+		/* Increment the return size and the return buffer pointer
+		   param */
+		*buffer += sizeof(ie_header);
+		ret_len += sizeof(ie_header);
+
+		/* Copy the generic IE buffer to the output buffer, advance
+		   pointer */
+		memcpy(*buffer, priv->gen_ie_buf, priv->gen_ie_buf_len);
+
+		/* Increment the return size and the return buffer pointer
+		   param */
+		*buffer += priv->gen_ie_buf_len;
+		ret_len += priv->gen_ie_buf_len;
+
+		/* Reset the generic IE buffer */
+		priv->gen_ie_buf_len = 0;
+	}
+
+	/* return the length appended to the buffer */
+	return ret_len;
+}
+
+/*
+ * Append TSF tracking info from the scan table for the target AP.
+ *
+ * This function is called from the network join command preparation routine.
+ *
+ * The TSF table TSF sent to the firmware contains two TSF values:
+ *      - The TSF of the target AP from its previous beacon/probe response
+ *      - The TSF timestamp of our local MAC at the time we observed the
+ *        beacon/probe response.
+ *
+ * The firmware uses the timestamp values to set an initial TSF value
+ * in the MAC for the new association after a reassociation attempt.
+ */
+static int
+mwifiex_cmd_append_tsf_tlv(struct mwifiex_private *priv, u8 **buffer,
+			   struct mwifiex_bssdescriptor *bss_desc)
+{
+	struct mwifiex_ie_types_tsf_timestamp tsf_tlv;
+	long long tsf_val;
+
+	/* Null Checks */
+	if (buffer == NULL)
+		return 0;
+	if (*buffer == NULL)
+		return 0;
+
+	memset(&tsf_tlv, 0x00, sizeof(struct mwifiex_ie_types_tsf_timestamp));
+
+	tsf_tlv.header.type = cpu_to_le16(TLV_TYPE_TSFTIMESTAMP);
+	tsf_tlv.header.len = cpu_to_le16(2 * sizeof(tsf_val));
+
+	memcpy(*buffer, &tsf_tlv, sizeof(tsf_tlv.header));
+	*buffer += sizeof(tsf_tlv.header);
+
+	memcpy(*buffer, &tsf_val, sizeof(tsf_val));
+	*buffer += sizeof(tsf_val);
+
+	memcpy(&tsf_val, bss_desc->time_stamp, sizeof(tsf_val));
+
+	dev_dbg(priv->adapter->dev, "info: %s: TSF offset calc: %016llx - "
+			"%016llx\n", __func__, tsf_val, bss_desc->network_tsf);
+
+	memcpy(*buffer, &tsf_val, sizeof(tsf_val));
+	*buffer += sizeof(tsf_val);
+
+	return sizeof(tsf_tlv.header) + (2 * sizeof(tsf_val));
+}
+
+/*
+ * This function finds out the common rates between rate1 and rate2.
+ *
+ * It will fill common rates in rate1 as output if found.
+ *
+ * NOTE: Setting the MSB of the basic rates needs to be taken
+ * care of, either before or after calling this function.
+ */
+static int mwifiex_get_common_rates(struct mwifiex_private *priv, u8 *rate1,
+				    u32 rate1_size, u8 *rate2, u32 rate2_size)
+{
+	int ret = 0;
+	u8 *ptr = rate1;
+	u8 *tmp = NULL;
+	u32 i, j;
+
+	tmp = kmalloc(rate1_size, GFP_KERNEL);
+	if (!tmp) {
+		dev_err(priv->adapter->dev, "failed to alloc tmp buf\n");
+		return -ENOMEM;
+	}
+
+	memcpy(tmp, rate1, rate1_size);
+	memset(rate1, 0, rate1_size);
+
+	for (i = 0; rate2[i] && i < rate2_size; i++) {
+		for (j = 0; tmp[j] && j < rate1_size; j++) {
+			/* Check common rate, excluding the bit for
+			   basic rate */
+			if ((rate2[i] & 0x7F) == (tmp[j] & 0x7F)) {
+				*rate1++ = tmp[j];
+				break;
+			}
+		}
+	}
+
+	dev_dbg(priv->adapter->dev, "info: Tx data rate set to %#x\n",
+						priv->data_rate);
+
+	if (!priv->is_data_rate_auto) {
+		while (*ptr) {
+			if ((*ptr & 0x7f) == priv->data_rate) {
+				ret = 0;
+				goto done;
+			}
+			ptr++;
+		}
+		dev_err(priv->adapter->dev, "previously set fixed data rate %#x"
+			" is not compatible with the network\n",
+			priv->data_rate);
+
+		ret = -1;
+		goto done;
+	}
+
+	ret = 0;
+done:
+	kfree(tmp);
+	return ret;
+}
+
+/*
+ * This function creates the intersection of the rates supported by a
+ * target BSS and our adapter settings for use in an assoc/join command.
+ */
+static int
+mwifiex_setup_rates_from_bssdesc(struct mwifiex_private *priv,
+				 struct mwifiex_bssdescriptor *bss_desc,
+				 u8 *out_rates, u32 *out_rates_size)
+{
+	u8 card_rates[MWIFIEX_SUPPORTED_RATES];
+	u32 card_rates_size = 0;
+
+	/* Copy AP supported rates */
+	memcpy(out_rates, bss_desc->supported_rates, MWIFIEX_SUPPORTED_RATES);
+	/* Get the STA supported rates */
+	card_rates_size = mwifiex_get_active_data_rates(priv, card_rates);
+	/* Get the common rates between AP and STA supported rates */
+	if (mwifiex_get_common_rates(priv, out_rates, MWIFIEX_SUPPORTED_RATES,
+				     card_rates, card_rates_size)) {
+		*out_rates_size = 0;
+		dev_err(priv->adapter->dev, "%s: cannot get common rates\n",
+						__func__);
+		return -1;
+	}
+
+	*out_rates_size =
+		min_t(size_t, strlen(out_rates), MWIFIEX_SUPPORTED_RATES);
+
+	return 0;
+}
+
+/*
+ * 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.
+ *
+ * If the IE buffer has been setup by the application, this routine appends
+ * the buffer as a WAPI TLV type to the request.
+ */
+static int
+mwifiex_cmd_append_wapi_ie(struct mwifiex_private *priv, u8 **buffer)
+{
+	int retLen = 0;
+	struct mwifiex_ie_types_header ie_header;
+
+	/* Null Checks */
+	if (buffer == NULL)
+		return 0;
+	if (*buffer == NULL)
+		return 0;
+
+	/*
+	 * If there is a wapi ie buffer setup, append it to the return
+	 *   parameter buffer pointer.
+	 */
+	if (priv->wapi_ie_len) {
+		dev_dbg(priv->adapter->dev, "cmd: append wapi ie %d to %p\n",
+				priv->wapi_ie_len, *buffer);
+
+		/* Wrap the generic IE buffer with a pass through TLV type */
+		ie_header.type = cpu_to_le16(TLV_TYPE_WAPI_IE);
+		ie_header.len = cpu_to_le16(priv->wapi_ie_len);
+		memcpy(*buffer, &ie_header, sizeof(ie_header));
+
+		/* Increment the return size and the return buffer pointer
+		   param */
+		*buffer += sizeof(ie_header);
+		retLen += sizeof(ie_header);
+
+		/* Copy the wapi IE buffer to the output buffer, advance
+		   pointer */
+		memcpy(*buffer, priv->wapi_ie, priv->wapi_ie_len);
+
+		/* Increment the return size and the return buffer pointer
+		   param */
+		*buffer += priv->wapi_ie_len;
+		retLen += priv->wapi_ie_len;
+
+	}
+	/* return the length appended to the buffer */
+	return retLen;
+}
+
+/*
+ * This function appends rsn ie tlv for wpa/wpa2 security modes.
+ * It is called from the network join command preparation routine.
+ */
+static int mwifiex_append_rsn_ie_wpa_wpa2(struct mwifiex_private *priv,
+					  u8 **buffer)
+{
+	struct mwifiex_ie_types_rsn_param_set *rsn_ie_tlv;
+	int rsn_ie_len;
+
+	if (!buffer || !(*buffer))
+		return 0;
+
+	rsn_ie_tlv = (struct mwifiex_ie_types_rsn_param_set *) (*buffer);
+	rsn_ie_tlv->header.type = cpu_to_le16((u16) priv->wpa_ie[0]);
+	rsn_ie_tlv->header.type = cpu_to_le16(
+				 le16_to_cpu(rsn_ie_tlv->header.type) & 0x00FF);
+	rsn_ie_tlv->header.len = cpu_to_le16((u16) priv->wpa_ie[1]);
+	rsn_ie_tlv->header.len = cpu_to_le16(le16_to_cpu(rsn_ie_tlv->header.len)
+							& 0x00FF);
+	if (le16_to_cpu(rsn_ie_tlv->header.len) <= (sizeof(priv->wpa_ie) - 2))
+		memcpy(rsn_ie_tlv->rsn_ie, &priv->wpa_ie[2],
+					le16_to_cpu(rsn_ie_tlv->header.len));
+	else
+		return -1;
+
+	rsn_ie_len = sizeof(rsn_ie_tlv->header) +
+					le16_to_cpu(rsn_ie_tlv->header.len);
+	*buffer += rsn_ie_len;
+
+	return rsn_ie_len;
+}
+
+/*
+ * This function prepares command for association.
+ *
+ * This sets the following parameters -
+ *      - Peer MAC address
+ *      - Listen interval
+ *      - Beacon interval
+ *      - Capability information
+ *
+ * ...and the following TLVs, as required -
+ *      - SSID TLV
+ *      - PHY TLV
+ *      - SS TLV
+ *      - Rates TLV
+ *      - Authentication TLV
+ *      - Channel TLV
+ *      - WPA/WPA2 IE
+ *      - 11n TLV
+ *      - Vendor specific TLV
+ *      - WMM TLV
+ *      - WAPI IE
+ *      - Generic IE
+ *      - TSF TLV
+ *
+ * Preparation also includes -
+ *      - Setting command ID and proper size
+ *      - Ensuring correct endian-ness
+ */
+int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
+				 struct host_cmd_ds_command *cmd,
+				 void *data_buf)
+{
+	struct host_cmd_ds_802_11_associate *assoc = &cmd->params.associate;
+	struct mwifiex_bssdescriptor *bss_desc;
+	struct mwifiex_ie_types_ssid_param_set *ssid_tlv;
+	struct mwifiex_ie_types_phy_param_set *phy_tlv;
+	struct mwifiex_ie_types_ss_param_set *ss_tlv;
+	struct mwifiex_ie_types_rates_param_set *rates_tlv;
+	struct mwifiex_ie_types_auth_type *auth_tlv;
+	struct mwifiex_ie_types_chan_list_param_set *chan_tlv;
+	u8 rates[MWIFIEX_SUPPORTED_RATES];
+	u32 rates_size;
+	u16 tmp_cap;
+	u8 *pos;
+	int rsn_ie_len = 0;
+
+	bss_desc = (struct mwifiex_bssdescriptor *) data_buf;
+	pos = (u8 *) assoc;
+
+	mwifiex_cfg_tx_buf(priv, bss_desc);
+
+	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_ASSOCIATE);
+
+	/* Save so we know which BSS Desc to use in the response handler */
+	priv->attempted_bss_desc = bss_desc;
+
+	memcpy(assoc->peer_sta_addr,
+	       bss_desc->mac_address, sizeof(assoc->peer_sta_addr));
+	pos += sizeof(assoc->peer_sta_addr);
+
+	/* Set the listen interval */
+	assoc->listen_interval = cpu_to_le16(priv->listen_interval);
+	/* Set the beacon period */
+	assoc->beacon_period = cpu_to_le16(bss_desc->beacon_period);
+
+	pos += sizeof(assoc->cap_info_bitmap);
+	pos += sizeof(assoc->listen_interval);
+	pos += sizeof(assoc->beacon_period);
+	pos += sizeof(assoc->dtim_period);
+
+	ssid_tlv = (struct mwifiex_ie_types_ssid_param_set *) pos;
+	ssid_tlv->header.type = cpu_to_le16(WLAN_EID_SSID);
+	ssid_tlv->header.len = cpu_to_le16((u16) bss_desc->ssid.ssid_len);
+	memcpy(ssid_tlv->ssid, bss_desc->ssid.ssid,
+		le16_to_cpu(ssid_tlv->header.len));
+	pos += sizeof(ssid_tlv->header) + le16_to_cpu(ssid_tlv->header.len);
+
+	phy_tlv = (struct mwifiex_ie_types_phy_param_set *) pos;
+	phy_tlv->header.type = cpu_to_le16(WLAN_EID_DS_PARAMS);
+	phy_tlv->header.len = cpu_to_le16(sizeof(phy_tlv->fh_ds.ds_param_set));
+	memcpy(&phy_tlv->fh_ds.ds_param_set,
+	       &bss_desc->phy_param_set.ds_param_set.current_chan,
+	       sizeof(phy_tlv->fh_ds.ds_param_set));
+	pos += sizeof(phy_tlv->header) + le16_to_cpu(phy_tlv->header.len);
+
+	ss_tlv = (struct mwifiex_ie_types_ss_param_set *) pos;
+	ss_tlv->header.type = cpu_to_le16(WLAN_EID_CF_PARAMS);
+	ss_tlv->header.len = cpu_to_le16(sizeof(ss_tlv->cf_ibss.cf_param_set));
+	pos += sizeof(ss_tlv->header) + le16_to_cpu(ss_tlv->header.len);
+
+	/* Get the common rates supported between the driver and the BSS Desc */
+	if (mwifiex_setup_rates_from_bssdesc
+	    (priv, bss_desc, rates, &rates_size))
+		return -1;
+
+	/* Save the data rates into Current BSS state structure */
+	priv->curr_bss_params.num_of_rates = rates_size;
+	memcpy(&priv->curr_bss_params.data_rates, rates, rates_size);
+
+	/* Setup the Rates TLV in the association command */
+	rates_tlv = (struct mwifiex_ie_types_rates_param_set *) pos;
+	rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES);
+	rates_tlv->header.len = cpu_to_le16((u16) rates_size);
+	memcpy(rates_tlv->rates, rates, rates_size);
+	pos += sizeof(rates_tlv->header) + rates_size;
+	dev_dbg(priv->adapter->dev, "info: ASSOC_CMD: rates size = %d\n",
+					rates_size);
+
+	/* Add the Authentication type to be used for Auth frames */
+	auth_tlv = (struct mwifiex_ie_types_auth_type *) pos;
+	auth_tlv->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
+	auth_tlv->header.len = cpu_to_le16(sizeof(auth_tlv->auth_type));
+	if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED)
+		auth_tlv->auth_type = cpu_to_le16(
+				(u16) priv->sec_info.authentication_mode);
+	else
+		auth_tlv->auth_type = cpu_to_le16(NL80211_AUTHTYPE_OPEN_SYSTEM);
+
+	pos += sizeof(auth_tlv->header) + le16_to_cpu(auth_tlv->header.len);
+
+	if (IS_SUPPORT_MULTI_BANDS(priv->adapter)
+	    && !(ISSUPP_11NENABLED(priv->adapter->fw_cap_info)
+		&& (!bss_desc->disable_11n)
+		 && (priv->adapter->config_bands & BAND_GN
+		     || priv->adapter->config_bands & BAND_AN)
+		 && (bss_desc->bcn_ht_cap)
+	    )
+		) {
+		/* Append a channel TLV for the channel the attempted AP was
+		   found on */
+		chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos;
+		chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
+		chan_tlv->header.len =
+			cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set));
+
+		memset(chan_tlv->chan_scan_param, 0x00,
+		       sizeof(struct mwifiex_chan_scan_param_set));
+		chan_tlv->chan_scan_param[0].chan_number =
+			(bss_desc->phy_param_set.ds_param_set.current_chan);
+		dev_dbg(priv->adapter->dev, "info: Assoc: TLV Chan = %d\n",
+		       chan_tlv->chan_scan_param[0].chan_number);
+
+		chan_tlv->chan_scan_param[0].radio_type =
+			mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
+
+		dev_dbg(priv->adapter->dev, "info: Assoc: TLV Band = %d\n",
+		       chan_tlv->chan_scan_param[0].radio_type);
+		pos += sizeof(chan_tlv->header) +
+			sizeof(struct mwifiex_chan_scan_param_set);
+	}
+
+	if (!priv->wps.session_enable) {
+		if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled)
+			rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos);
+
+		if (rsn_ie_len == -1)
+			return -1;
+	}
+
+	if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info)
+		&& (!bss_desc->disable_11n)
+	    && (priv->adapter->config_bands & BAND_GN
+		|| priv->adapter->config_bands & BAND_AN))
+		mwifiex_cmd_append_11n_tlv(priv, bss_desc, &pos);
+
+	/* Append vendor specific IE TLV */
+	mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_ASSOC, &pos);
+
+	mwifiex_wmm_process_association_req(priv, &pos, &bss_desc->wmm_ie,
+					    bss_desc->bcn_ht_cap);
+	if (priv->sec_info.wapi_enabled && priv->wapi_ie_len)
+		mwifiex_cmd_append_wapi_ie(priv, &pos);
+
+
+	mwifiex_cmd_append_generic_ie(priv, &pos);
+
+	mwifiex_cmd_append_tsf_tlv(priv, &pos, bss_desc);
+
+	cmd->size = cpu_to_le16((u16) (pos - (u8 *) assoc) + S_DS_GEN);
+
+	/* Set the Capability info at last */
+	tmp_cap = bss_desc->cap_info_bitmap;
+
+	if (priv->adapter->config_bands == BAND_B)
+		tmp_cap &= ~WLAN_CAPABILITY_SHORT_SLOT_TIME;
+
+	tmp_cap &= CAPINFO_MASK;
+	dev_dbg(priv->adapter->dev, "info: ASSOC_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n",
+	       tmp_cap, CAPINFO_MASK);
+	assoc->cap_info_bitmap = cpu_to_le16(tmp_cap);
+
+	return 0;
+}
+
+/*
+ * Association firmware command response handler
+ *
+ * The response buffer for the association command has the following
+ * memory layout.
+ *
+ * For cases where an association response was not received (indicated
+ * by the CapInfo and AId field):
+ *
+ *     .------------------------------------------------------------.
+ *     |  Header(4 * sizeof(t_u16)):  Standard command response hdr |
+ *     .------------------------------------------------------------.
+ *     |  cap_info/Error Return(t_u16):                             |
+ *     |           0xFFFF(-1): Internal error                       |
+ *     |           0xFFFE(-2): Authentication unhandled message     |
+ *     |           0xFFFD(-3): Authentication refused               |
+ *     |           0xFFFC(-4): Timeout waiting for AP response      |
+ *     .------------------------------------------------------------.
+ *     |  status_code(t_u16):                                       |
+ *     |        If cap_info is -1:                                  |
+ *     |           An internal firmware failure prevented the       |
+ *     |           command from being processed.  The status_code   |
+ *     |           will be set to 1.                                |
+ *     |                                                            |
+ *     |        If cap_info is -2:                                  |
+ *     |           An authentication frame was received but was     |
+ *     |           not handled by the firmware.  IEEE Status        |
+ *     |           code for the failure is returned.                |
+ *     |                                                            |
+ *     |        If cap_info is -3:                                  |
+ *     |           An authentication frame was received and the     |
+ *     |           status_code is the IEEE Status reported in the   |
+ *     |           response.                                        |
+ *     |                                                            |
+ *     |        If cap_info is -4:                                  |
+ *     |           (1) Association response timeout                 |
+ *     |           (2) Authentication response timeout              |
+ *     .------------------------------------------------------------.
+ *     |  a_id(t_u16): 0xFFFF                                       |
+ *     .------------------------------------------------------------.
+ *
+ *
+ * For cases where an association response was received, the IEEE
+ * standard association response frame is returned:
+ *
+ *     .------------------------------------------------------------.
+ *     |  Header(4 * sizeof(t_u16)):  Standard command response hdr |
+ *     .------------------------------------------------------------.
+ *     |  cap_info(t_u16): IEEE Capability                          |
+ *     .------------------------------------------------------------.
+ *     |  status_code(t_u16): IEEE Status Code                      |
+ *     .------------------------------------------------------------.
+ *     |  a_id(t_u16): IEEE Association ID                          |
+ *     .------------------------------------------------------------.
+ *     |  IEEE IEs(variable): Any received IEs comprising the       |
+ *     |                      remaining portion of a received       |
+ *     |                      association response frame.           |
+ *     .------------------------------------------------------------.
+ *
+ * For simplistic handling, the status_code field can be used to determine
+ * an association success (0) or failure (non-zero).
+ */
+int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
+			     struct host_cmd_ds_command *resp, void *wq_buf)
+{
+	int ret = 0;
+	struct mwifiex_wait_queue *wait_queue =
+		(struct mwifiex_wait_queue *) wq_buf;
+	struct ieee_types_assoc_rsp *assoc_rsp;
+	struct mwifiex_bssdescriptor *bss_desc;
+	u8 enable_data = true;
+
+	assoc_rsp = (struct ieee_types_assoc_rsp *) &resp->params;
+
+	priv->assoc_rsp_size = min(le16_to_cpu(resp->size) - S_DS_GEN,
+				     sizeof(priv->assoc_rsp_buf));
+
+	memcpy(priv->assoc_rsp_buf, &resp->params, priv->assoc_rsp_size);
+
+	if (le16_to_cpu(assoc_rsp->status_code)) {
+		priv->adapter->dbg.num_cmd_assoc_failure++;
+		dev_err(priv->adapter->dev, "ASSOC_RESP: association failed, "
+		       "status code = %d, error = 0x%x, a_id = 0x%x\n",
+		       le16_to_cpu(assoc_rsp->status_code),
+		       le16_to_cpu(assoc_rsp->cap_info_bitmap),
+		       le16_to_cpu(assoc_rsp->a_id));
+
+		ret = -1;
+		goto done;
+	}
+
+	/* Send a Media Connected event, according to the Spec */
+	priv->media_connected = true;
+
+	priv->adapter->ps_state = PS_STATE_AWAKE;
+	priv->adapter->pps_uapsd_mode = false;
+	priv->adapter->tx_lock_flag = false;
+
+	/* Set the attempted BSSID Index to current */
+	bss_desc = priv->attempted_bss_desc;
+
+	dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: %s\n",
+						bss_desc->ssid.ssid);
+
+	/* Make a copy of current BSSID descriptor */
+	memcpy(&priv->curr_bss_params.bss_descriptor,
+	       bss_desc, sizeof(struct mwifiex_bssdescriptor));
+
+	/* Update curr_bss_params */
+	priv->curr_bss_params.bss_descriptor.channel
+		= bss_desc->phy_param_set.ds_param_set.current_chan;
+
+	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
+		priv->curr_bss_params.wmm_enabled = false;
+
+	if ((priv->wmm_required || bss_desc->bcn_ht_cap)
+			&& priv->curr_bss_params.wmm_enabled)
+		priv->wmm_enabled = true;
+	else
+		priv->wmm_enabled = false;
+
+	priv->curr_bss_params.wmm_uapsd_enabled = false;
+
+	if (priv->wmm_enabled)
+		priv->curr_bss_params.wmm_uapsd_enabled
+			= ((bss_desc->wmm_ie.qos_info_bitmap &
+				IEEE80211_WMM_IE_AP_QOSINFO_UAPSD) ? 1 : 0);
+
+	dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: curr_pkt_filter is %#x\n",
+	       priv->curr_pkt_filter);
+	if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled)
+		priv->wpa_is_gtk_set = false;
+
+	if (priv->wmm_enabled) {
+		/* Don't re-enable carrier until we get the WMM_GET_STATUS
+		   event */
+		enable_data = false;
+	} else {
+		/* Since WMM is not enabled, setup the queues with the
+		   defaults */
+		mwifiex_wmm_setup_queue_priorities(priv, NULL);
+		mwifiex_wmm_setup_ac_downgrade(priv);
+	}
+
+	if (enable_data)
+		dev_dbg(priv->adapter->dev,
+			"info: post association, re-enabling data flow\n");
+
+	/* Reset SNR/NF/RSSI values */
+	priv->data_rssi_last = 0;
+	priv->data_nf_last = 0;
+	priv->data_rssi_avg = 0;
+	priv->data_nf_avg = 0;
+	priv->bcn_rssi_last = 0;
+	priv->bcn_nf_last = 0;
+	priv->bcn_rssi_avg = 0;
+	priv->bcn_nf_avg = 0;
+	priv->rxpd_rate = 0;
+	priv->rxpd_htinfo = 0;
+
+	mwifiex_save_curr_bcn(priv);
+
+	priv->adapter->dbg.num_cmd_assoc_success++;
+
+	dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: associated\n");
+
+	/* Add the ra_list here for infra mode as there will be only 1 ra
+	   always */
+	mwifiex_ralist_add(priv,
+			   priv->curr_bss_params.bss_descriptor.mac_address);
+
+	if (!netif_carrier_ok(priv->netdev))
+		netif_carrier_on(priv->netdev);
+	if (netif_queue_stopped(priv->netdev))
+		netif_wake_queue(priv->netdev);
+
+	if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled)
+		priv->scan_block = true;
+
+done:
+	/* Need to indicate IOCTL complete */
+	if (wait_queue) {
+		if (ret) {
+			if (assoc_rsp->status_code)
+				wait_queue->status =
+					le16_to_cpu(assoc_rsp->status_code);
+			else
+				wait_queue->status = MWIFIEX_ERROR_ASSOC_FAIL;
+		} else {
+			wait_queue->status = MWIFIEX_ERROR_NO_ERROR;
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * This function prepares command for ad-hoc start.
+ *
+ * Driver will fill up SSID, BSS mode, IBSS parameters, physical
+ * parameters, probe delay, and capability information. Firmware
+ * will fill up beacon period, basic rates and operational rates.
+ *
+ * In addition, the following TLVs are added -
+ *      - Channel TLV
+ *      - Vendor specific IE
+ *      - WPA/WPA2 IE
+ *      - HT Capabilities IE
+ *      - HT Information IE
+ *
+ * Preparation also includes -
+ *      - Setting command ID and proper size
+ *      - Ensuring correct endian-ness
+ */
+int
+mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
+				struct host_cmd_ds_command *cmd, void *data_buf)
+{
+	int ret = 0, rsn_ie_len = 0;
+	struct mwifiex_adapter *adapter = priv->adapter;
+	struct host_cmd_ds_802_11_ad_hoc_start *adhoc_start =
+		&cmd->params.adhoc_start;
+	struct mwifiex_bssdescriptor *bss_desc;
+	u32 cmd_append_size = 0;
+	u32 i;
+	u16 tmp_cap;
+	uint16_t ht_cap_info;
+	struct mwifiex_ie_types_chan_list_param_set *chan_tlv;
+
+	struct mwifiex_ie_types_htcap *ht_cap;
+	struct mwifiex_ie_types_htinfo *ht_info;
+	u8 *pos = (u8 *) adhoc_start +
+			sizeof(struct host_cmd_ds_802_11_ad_hoc_start);
+
+	if (!adapter)
+		return -1;
+
+	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_START);
+
+	bss_desc = &priv->curr_bss_params.bss_descriptor;
+	priv->attempted_bss_desc = bss_desc;
+
+	/*
+	 * Fill in the parameters for 2 data structures:
+	 *   1. struct host_cmd_ds_802_11_ad_hoc_start command
+	 *   2. bss_desc
+	 * Driver will fill up SSID, bss_mode,IBSS param, Physical Param,
+	 * probe delay, and Cap info.
+	 * Firmware will fill up beacon period, Basic rates
+	 * and operational rates.
+	 */
+
+	memset(adhoc_start->ssid, 0, IEEE80211_MAX_SSID_LEN);
+
+	memcpy(adhoc_start->ssid,
+	       ((struct mwifiex_802_11_ssid *) data_buf)->ssid,
+	       ((struct mwifiex_802_11_ssid *) data_buf)->ssid_len);
+
+	dev_dbg(adapter->dev, "info: ADHOC_S_CMD: SSID = %s\n",
+				adhoc_start->ssid);
+
+	memset(bss_desc->ssid.ssid, 0, IEEE80211_MAX_SSID_LEN);
+	memcpy(bss_desc->ssid.ssid,
+	       ((struct mwifiex_802_11_ssid *) data_buf)->ssid,
+	       ((struct mwifiex_802_11_ssid *) data_buf)->ssid_len);
+
+	bss_desc->ssid.ssid_len =
+		((struct mwifiex_802_11_ssid *) data_buf)->ssid_len;
+
+	/* Set the BSS mode */
+	adhoc_start->bss_mode = HostCmd_BSS_MODE_IBSS;
+	bss_desc->bss_mode = NL80211_IFTYPE_ADHOC;
+	adhoc_start->beacon_period = cpu_to_le16(priv->beacon_period);
+	bss_desc->beacon_period = priv->beacon_period;
+
+	/* Set Physical param set */
+/* Parameter IE Id */
+#define DS_PARA_IE_ID   3
+/* Parameter IE length */
+#define DS_PARA_IE_LEN  1
+
+	adhoc_start->phy_param_set.ds_param_set.element_id = DS_PARA_IE_ID;
+	adhoc_start->phy_param_set.ds_param_set.len = DS_PARA_IE_LEN;
+
+	if (!mwifiex_get_cfp_by_band_and_channel_from_cfg80211
+			(priv, adapter->adhoc_start_band, (u16)
+				priv->adhoc_channel)) {
+		struct mwifiex_chan_freq_power *cfp;
+		cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv,
+				adapter->adhoc_start_band, FIRST_VALID_CHANNEL);
+		if (cfp)
+			priv->adhoc_channel = (u8) cfp->channel;
+	}
+
+	if (!priv->adhoc_channel) {
+		dev_err(adapter->dev, "ADHOC_S_CMD: adhoc_channel cannot be 0\n");
+		return -1;
+	}
+
+	dev_dbg(adapter->dev, "info: ADHOC_S_CMD: creating ADHOC on channel %d\n",
+				priv->adhoc_channel);
+
+	priv->curr_bss_params.bss_descriptor.channel = priv->adhoc_channel;
+	priv->curr_bss_params.band = adapter->adhoc_start_band;
+
+	bss_desc->channel = priv->adhoc_channel;
+	adhoc_start->phy_param_set.ds_param_set.current_chan =
+		priv->adhoc_channel;
+
+	memcpy(&bss_desc->phy_param_set, &adhoc_start->phy_param_set,
+	       sizeof(union ieee_types_phy_param_set));
+
+	/* Set IBSS param set */
+/* IBSS parameter IE Id */
+#define IBSS_PARA_IE_ID   6
+/* IBSS parameter IE length */
+#define IBSS_PARA_IE_LEN  2
+
+	adhoc_start->ss_param_set.ibss_param_set.element_id = IBSS_PARA_IE_ID;
+	adhoc_start->ss_param_set.ibss_param_set.len = IBSS_PARA_IE_LEN;
+	adhoc_start->ss_param_set.ibss_param_set.atim_window
+		= cpu_to_le16(priv->atim_window);
+	memcpy(&bss_desc->ss_param_set, &adhoc_start->ss_param_set,
+	       sizeof(union ieee_types_ss_param_set));
+
+	/* Set Capability info */
+	bss_desc->cap_info_bitmap |= WLAN_CAPABILITY_IBSS;
+	tmp_cap = le16_to_cpu(adhoc_start->cap_info_bitmap);
+	tmp_cap &= ~WLAN_CAPABILITY_ESS;
+	tmp_cap |= WLAN_CAPABILITY_IBSS;
+
+	/* Set up privacy in bss_desc */
+	if (priv->sec_info.encryption_mode) {
+		/* Ad-Hoc capability privacy on */
+		dev_dbg(adapter->dev,
+			"info: ADHOC_S_CMD: wep_status set privacy to WEP\n");
+		bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP;
+		tmp_cap |= WLAN_CAPABILITY_PRIVACY;
+	} else {
+		dev_dbg(adapter->dev, "info: ADHOC_S_CMD: wep_status NOT set,"
+				" setting privacy to ACCEPT ALL\n");
+		bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL;
+	}
+
+	memset(adhoc_start->DataRate, 0, sizeof(adhoc_start->DataRate));
+	mwifiex_get_active_data_rates(priv, adhoc_start->DataRate);
+	if ((adapter->adhoc_start_band & BAND_G) &&
+	    (priv->curr_pkt_filter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)) {
+		ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL,
+					  HostCmd_ACT_GEN_SET,
+					  0, NULL, &priv->curr_pkt_filter);
+
+		if (ret) {
+			dev_err(adapter->dev,
+			       "ADHOC_S_CMD: G Protection config failed\n");
+			return -1;
+		}
+	}
+	/* Find the last non zero */
+	for (i = 0; i < sizeof(adhoc_start->DataRate) &&
+			adhoc_start->DataRate[i];
+			i++)
+			;
+
+	priv->curr_bss_params.num_of_rates = i;
+
+	/* Copy the ad-hoc creating rates into Current BSS rate structure */
+	memcpy(&priv->curr_bss_params.data_rates,
+	       &adhoc_start->DataRate, priv->curr_bss_params.num_of_rates);
+
+	dev_dbg(adapter->dev, "info: ADHOC_S_CMD: rates=%02x %02x %02x %02x\n",
+	       adhoc_start->DataRate[0], adhoc_start->DataRate[1],
+	       adhoc_start->DataRate[2], adhoc_start->DataRate[3]);
+
+	dev_dbg(adapter->dev, "info: ADHOC_S_CMD: AD-HOC Start command is ready\n");
+
+	if (IS_SUPPORT_MULTI_BANDS(adapter)) {
+		/* Append a channel TLV */
+		chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos;
+		chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
+		chan_tlv->header.len =
+			cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set));
+
+		memset(chan_tlv->chan_scan_param, 0x00,
+		       sizeof(struct mwifiex_chan_scan_param_set));
+		chan_tlv->chan_scan_param[0].chan_number =
+			(u8) priv->curr_bss_params.bss_descriptor.channel;
+
+		dev_dbg(adapter->dev, "info: ADHOC_S_CMD: TLV Chan = %d\n",
+		       chan_tlv->chan_scan_param[0].chan_number);
+
+		chan_tlv->chan_scan_param[0].radio_type
+		       = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
+		if (adapter->adhoc_start_band & BAND_GN
+		    || adapter->adhoc_start_band & BAND_AN) {
+			if (adapter->chan_offset == SEC_CHANNEL_ABOVE)
+				chan_tlv->chan_scan_param[0].radio_type |=
+					SECOND_CHANNEL_ABOVE;
+			else if (adapter->chan_offset == SEC_CHANNEL_BELOW)
+				chan_tlv->chan_scan_param[0].radio_type |=
+					SECOND_CHANNEL_BELOW;
+		}
+		dev_dbg(adapter->dev, "info: ADHOC_S_CMD: TLV Band = %d\n",
+		       chan_tlv->chan_scan_param[0].radio_type);
+		pos += sizeof(chan_tlv->header) +
+			sizeof(struct mwifiex_chan_scan_param_set);
+		cmd_append_size +=
+			sizeof(chan_tlv->header) +
+			sizeof(struct mwifiex_chan_scan_param_set);
+	}
+
+	/* Append vendor specific IE TLV */
+	cmd_append_size += mwifiex_cmd_append_vsie_tlv(priv,
+				MWIFIEX_VSIE_MASK_ADHOC, &pos);
+
+	if (priv->sec_info.wpa_enabled) {
+		rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos);
+		if (rsn_ie_len == -1)
+			return -1;
+		cmd_append_size += rsn_ie_len;
+	}
+
+	if (adapter->adhoc_11n_enabled) {
+		{
+			ht_cap = (struct mwifiex_ie_types_htcap *) pos;
+			memset(ht_cap, 0,
+			       sizeof(struct mwifiex_ie_types_htcap));
+			ht_cap->header.type =
+				cpu_to_le16(WLAN_EID_HT_CAPABILITY);
+			ht_cap->header.len =
+			       cpu_to_le16(sizeof(struct ieee80211_ht_cap));
+			ht_cap_info = le16_to_cpu(ht_cap->ht_cap.cap_info);
+
+			ht_cap_info |= IEEE80211_HT_CAP_SGI_20;
+			if (adapter->chan_offset) {
+				ht_cap_info |= IEEE80211_HT_CAP_SGI_40;
+				ht_cap_info |= IEEE80211_HT_CAP_DSSSCCK40;
+				ht_cap_info |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+				SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask);
+			}
+
+			ht_cap->ht_cap.ampdu_params_info
+					= IEEE80211_HT_MAX_AMPDU_64K;
+			ht_cap->ht_cap.mcs.rx_mask[0] = 0xff;
+			pos += sizeof(struct mwifiex_ie_types_htcap);
+			cmd_append_size +=
+				sizeof(struct mwifiex_ie_types_htcap);
+		}
+		{
+			ht_info = (struct mwifiex_ie_types_htinfo *) pos;
+			memset(ht_info, 0,
+			       sizeof(struct mwifiex_ie_types_htinfo));
+			ht_info->header.type =
+				cpu_to_le16(WLAN_EID_HT_INFORMATION);
+			ht_info->header.len =
+				cpu_to_le16(sizeof(struct ieee80211_ht_info));
+			ht_info->ht_info.control_chan =
+				(u8) priv->curr_bss_params.bss_descriptor.
+				channel;
+			if (adapter->chan_offset) {
+				ht_info->ht_info.ht_param =
+					adapter->chan_offset;
+				ht_info->ht_info.ht_param |=
+					IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
+			}
+			ht_info->ht_info.operation_mode =
+				cpu_to_le16(NON_GREENFIELD_STAS);
+			ht_info->ht_info.basic_set[0] = 0xff;
+			pos += sizeof(struct mwifiex_ie_types_htinfo);
+			cmd_append_size +=
+				sizeof(struct mwifiex_ie_types_htinfo);
+		}
+	}
+
+	cmd->size = cpu_to_le16((u16)
+			    (sizeof(struct host_cmd_ds_802_11_ad_hoc_start)
+			     + S_DS_GEN + cmd_append_size));
+
+	if (adapter->adhoc_start_band == BAND_B)
+		tmp_cap &= ~WLAN_CAPABILITY_SHORT_SLOT_TIME;
+	else
+		tmp_cap |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
+
+	adhoc_start->cap_info_bitmap = cpu_to_le16(tmp_cap);
+
+	return 0;
+}
+
+/*
+ * This function prepares command for ad-hoc join.
+ *
+ * Most of the parameters are set up by copying from the target BSS descriptor
+ * from the scan response.
+ *
+ * In addition, the following TLVs are added -
+ *      - Channel TLV
+ *      - Vendor specific IE
+ *      - WPA/WPA2 IE
+ *      - 11n IE
+ *
+ * Preparation also includes -
+ *      - Setting command ID and proper size
+ *      - Ensuring correct endian-ness
+ */
+int
+mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv,
+			       struct host_cmd_ds_command *cmd, void *data_buf)
+{
+	int ret = 0, rsn_ie_len = 0;
+	struct host_cmd_ds_802_11_ad_hoc_join *adhoc_join =
+		&cmd->params.adhoc_join;
+	struct mwifiex_bssdescriptor *bss_desc =
+		(struct mwifiex_bssdescriptor *) data_buf;
+	struct mwifiex_ie_types_chan_list_param_set *chan_tlv;
+	u32 cmd_append_size = 0;
+	u16 tmp_cap;
+	u32 i, rates_size = 0;
+	u16 curr_pkt_filter;
+	u8 *pos =
+		(u8 *) adhoc_join +
+		sizeof(struct host_cmd_ds_802_11_ad_hoc_join);
+
+/* Use G protection */
+#define USE_G_PROTECTION        0x02
+	if (bss_desc->erp_flags & USE_G_PROTECTION) {
+		curr_pkt_filter =
+			priv->
+			curr_pkt_filter | HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON;
+
+		ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL,
+					  HostCmd_ACT_GEN_SET, 0, NULL,
+					  &curr_pkt_filter);
+		if (ret) {
+			dev_err(priv->adapter->dev,
+			       "ADHOC_J_CMD: G Protection config failed\n");
+			return -1;
+		}
+	}
+
+	priv->attempted_bss_desc = bss_desc;
+
+	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_JOIN);
+
+	adhoc_join->bss_descriptor.bss_mode = HostCmd_BSS_MODE_IBSS;
+
+	adhoc_join->bss_descriptor.beacon_period
+		= cpu_to_le16(bss_desc->beacon_period);
+
+	memcpy(&adhoc_join->bss_descriptor.bssid,
+	       &bss_desc->mac_address, ETH_ALEN);
+
+	memcpy(&adhoc_join->bss_descriptor.ssid,
+	       &bss_desc->ssid.ssid, bss_desc->ssid.ssid_len);
+
+	memcpy(&adhoc_join->bss_descriptor.phy_param_set,
+	       &bss_desc->phy_param_set,
+	       sizeof(union ieee_types_phy_param_set));
+
+	memcpy(&adhoc_join->bss_descriptor.ss_param_set,
+	       &bss_desc->ss_param_set, sizeof(union ieee_types_ss_param_set));
+
+	tmp_cap = bss_desc->cap_info_bitmap;
+
+	tmp_cap &= CAPINFO_MASK;
+
+	dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: tmp_cap=%4X"
+			" CAPINFO_MASK=%4lX\n", tmp_cap, CAPINFO_MASK);
+
+	/* Information on BSSID descriptor passed to FW */
+	dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: BSSID = %pM, SSID = %s\n",
+				adhoc_join->bss_descriptor.bssid,
+				adhoc_join->bss_descriptor.ssid);
+
+	for (i = 0; bss_desc->supported_rates[i] &&
+			i < MWIFIEX_SUPPORTED_RATES;
+			i++)
+			;
+	rates_size = i;
+
+	/* Copy Data Rates from the Rates recorded in scan response */
+	memset(adhoc_join->bss_descriptor.data_rates, 0,
+	       sizeof(adhoc_join->bss_descriptor.data_rates));
+	memcpy(adhoc_join->bss_descriptor.data_rates,
+	       bss_desc->supported_rates, rates_size);
+
+	/* Copy the adhoc join rates into Current BSS state structure */
+	priv->curr_bss_params.num_of_rates = rates_size;
+	memcpy(&priv->curr_bss_params.data_rates, bss_desc->supported_rates,
+	       rates_size);
+
+	/* Copy the channel information */
+	priv->curr_bss_params.bss_descriptor.channel = bss_desc->channel;
+	priv->curr_bss_params.band = (u8) bss_desc->bss_band;
+
+	if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED
+	    || priv->sec_info.wpa_enabled)
+		tmp_cap |= WLAN_CAPABILITY_PRIVACY;
+
+	if (IS_SUPPORT_MULTI_BANDS(priv->adapter)) {
+		/* Append a channel TLV */
+		chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos;
+		chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
+		chan_tlv->header.len =
+			cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set));
+
+		memset(chan_tlv->chan_scan_param, 0x00,
+		       sizeof(struct mwifiex_chan_scan_param_set));
+		chan_tlv->chan_scan_param[0].chan_number =
+			(bss_desc->phy_param_set.ds_param_set.current_chan);
+		dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: TLV Chan = %d\n",
+		       chan_tlv->chan_scan_param[0].chan_number);
+
+		chan_tlv->chan_scan_param[0].radio_type =
+			mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
+
+		dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: TLV Band = %d\n",
+		       chan_tlv->chan_scan_param[0].radio_type);
+		pos += sizeof(chan_tlv->header) +
+			sizeof(struct mwifiex_chan_scan_param_set);
+		cmd_append_size += sizeof(chan_tlv->header) +
+			sizeof(struct mwifiex_chan_scan_param_set);
+	}
+
+	if (priv->sec_info.wpa_enabled)
+		rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos);
+	if (rsn_ie_len == -1)
+		return -1;
+	cmd_append_size += rsn_ie_len;
+
+	if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info))
+		cmd_append_size += mwifiex_cmd_append_11n_tlv(priv,
+			bss_desc, &pos);
+
+	/* Append vendor specific IE TLV */
+	cmd_append_size += mwifiex_cmd_append_vsie_tlv(priv,
+			MWIFIEX_VSIE_MASK_ADHOC, &pos);
+
+	cmd->size = cpu_to_le16((u16)
+			    (sizeof(struct host_cmd_ds_802_11_ad_hoc_join)
+			     + S_DS_GEN + cmd_append_size));
+
+	adhoc_join->bss_descriptor.cap_info_bitmap = cpu_to_le16(tmp_cap);
+
+	return ret;
+}
+
+/*
+ * This function handles the command response of ad-hoc start and
+ * ad-hoc join.
+ *
+ * The function generates a device-connected event to notify
+ * the applications, in case of successful ad-hoc start/join, and
+ * saves the beacon buffer.
+ */
+int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv,
+			      struct host_cmd_ds_command *resp, void *wq_buf)
+{
+	int ret = 0;
+	struct mwifiex_wait_queue *wait_queue =
+		(struct mwifiex_wait_queue *) wq_buf;
+	struct host_cmd_ds_802_11_ad_hoc_result *adhoc_result;
+	struct mwifiex_bssdescriptor *bss_desc;
+	u16 command = le16_to_cpu(resp->command);
+	u16 result = le16_to_cpu(resp->result);
+
+	adhoc_result = &resp->params.adhoc_result;
+
+	bss_desc = priv->attempted_bss_desc;
+
+	/* Join result code 0 --> SUCCESS */
+	if (result) {
+		dev_err(priv->adapter->dev, "ADHOC_RESP: failed\n");
+		if (priv->media_connected)
+			mwifiex_reset_connect_state(priv);
+
+		memset(&priv->curr_bss_params.bss_descriptor,
+		       0x00, sizeof(struct mwifiex_bssdescriptor));
+
+		ret = -1;
+		goto done;
+	}
+
+	/* Send a Media Connected event, according to the Spec */
+	priv->media_connected = true;
+
+	if (command == HostCmd_CMD_802_11_AD_HOC_START) {
+		dev_dbg(priv->adapter->dev, "info: ADHOC_S_RESP %s\n",
+				bss_desc->ssid.ssid);
+
+		/* Update the created network descriptor with the new BSSID */
+		memcpy(bss_desc->mac_address,
+		       adhoc_result->bssid, ETH_ALEN);
+
+		priv->adhoc_state = ADHOC_STARTED;
+	} else {
+		/*
+		 * Now the join cmd should be successful.
+		 * If BSSID has changed use SSID to compare instead of BSSID
+		 */
+		dev_dbg(priv->adapter->dev, "info: ADHOC_J_RESP %s\n",
+				bss_desc->ssid.ssid);
+
+		/*
+		 * Make a copy of current BSSID descriptor, only needed for
+		 * join since the current descriptor is already being used
+		 * for adhoc start
+		 */
+		memcpy(&priv->curr_bss_params.bss_descriptor,
+		       bss_desc, sizeof(struct mwifiex_bssdescriptor));
+
+		priv->adhoc_state = ADHOC_JOINED;
+	}
+
+	dev_dbg(priv->adapter->dev, "info: ADHOC_RESP: channel = %d\n",
+				priv->adhoc_channel);
+	dev_dbg(priv->adapter->dev, "info: ADHOC_RESP: BSSID = %pM\n",
+	       priv->curr_bss_params.bss_descriptor.mac_address);
+
+	if (!netif_carrier_ok(priv->netdev))
+		netif_carrier_on(priv->netdev);
+	if (netif_queue_stopped(priv->netdev))
+		netif_wake_queue(priv->netdev);
+
+	mwifiex_save_curr_bcn(priv);
+
+done:
+	/* Need to indicate IOCTL complete */
+	if (wait_queue) {
+		if (ret)
+			wait_queue->status = MWIFIEX_ERROR_ASSOC_FAIL;
+		else
+			wait_queue->status = MWIFIEX_ERROR_NO_ERROR;
+
+	}
+
+	return ret;
+}
+
+/*
+ * This function associates to a specific BSS discovered in a scan.
+ *
+ * It clears any past association response stored for application
+ * retrieval and calls the command preparation routine to send the
+ * command to firmware.
+ */
+int mwifiex_associate(struct mwifiex_private *priv,
+		      void *wait_queue, struct mwifiex_bssdescriptor *bss_desc)
+{
+	int ret = 0;
+	u8 current_bssid[ETH_ALEN];
+
+	/* Return error if the adapter or table entry is not marked as infra */
+	if ((priv->bss_mode != NL80211_IFTYPE_STATION) ||
+	    (bss_desc->bss_mode != NL80211_IFTYPE_STATION))
+		return -1;
+
+	memcpy(&current_bssid,
+	       &priv->curr_bss_params.bss_descriptor.mac_address,
+	       sizeof(current_bssid));
+
+	/* Clear any past association response stored for application
+	   retrieval */
+	priv->assoc_rsp_size = 0;
+
+	ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_ASSOCIATE,
+				  HostCmd_ACT_GEN_SET, 0, wait_queue,
+				  bss_desc);
+
+	return ret;
+}
+
+/*
+ * This function starts an ad-hoc network.
+ *
+ * It calls the command preparation routine to send the command to firmware.
+ */
+int
+mwifiex_adhoc_start(struct mwifiex_private *priv,
+		    void *wait_queue, struct mwifiex_802_11_ssid *adhoc_ssid)
+{
+	int ret = 0;
+
+	dev_dbg(priv->adapter->dev, "info: Adhoc Channel = %d\n",
+		priv->adhoc_channel);
+	dev_dbg(priv->adapter->dev, "info: curr_bss_params.channel = %d\n",
+	       priv->curr_bss_params.bss_descriptor.channel);
+	dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %d\n",
+	       priv->curr_bss_params.band);
+
+	ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_AD_HOC_START,
+				  HostCmd_ACT_GEN_SET, 0, wait_queue,
+				  adhoc_ssid);
+
+	return ret;
+}
+
+/*
+ * This function joins an ad-hoc network found in a previous scan.
+ *
+ * It calls the command preparation routine to send the command to firmware,
+ * if already not connected to the requested SSID.
+ */
+int mwifiex_adhoc_join(struct mwifiex_private *priv,
+		       void *wait_queue, struct mwifiex_bssdescriptor *bss_desc)
+{
+	int ret = 0;
+
+	dev_dbg(priv->adapter->dev, "info: adhoc join: curr_bss ssid =%s\n",
+	       priv->curr_bss_params.bss_descriptor.ssid.ssid);
+	dev_dbg(priv->adapter->dev, "info: adhoc join: curr_bss ssid_len =%u\n",
+	       priv->curr_bss_params.bss_descriptor.ssid.ssid_len);
+	dev_dbg(priv->adapter->dev, "info: adhoc join: ssid =%s\n",
+		bss_desc->ssid.ssid);
+	dev_dbg(priv->adapter->dev, "info: adhoc join: ssid_len =%u\n",
+	       bss_desc->ssid.ssid_len);
+
+	/* Check if the requested SSID is already joined */
+	if (priv->curr_bss_params.bss_descriptor.ssid.ssid_len &&
+	    !mwifiex_ssid_cmp(&bss_desc->ssid,
+			      &priv->curr_bss_params.bss_descriptor.ssid) &&
+	    (priv->curr_bss_params.bss_descriptor.bss_mode ==
+							NL80211_IFTYPE_ADHOC)) {
+		dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: new ad-hoc SSID"
+			" is the same as current; not attempting to re-join\n");
+		return -1;
+	}
+
+	dev_dbg(priv->adapter->dev, "info: curr_bss_params.channel = %d\n",
+	       priv->curr_bss_params.bss_descriptor.channel);
+	dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %c\n",
+	       priv->curr_bss_params.band);
+
+	ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_AD_HOC_JOIN,
+				  HostCmd_ACT_GEN_SET, 0, wait_queue,
+				  bss_desc);
+
+	return ret;
+}
+
+/*
+ * This function deauthenticates/disconnects from infra network by sending
+ * deauthentication request.
+ */
+static int mwifiex_deauthenticate_infra(struct mwifiex_private *priv,
+					struct mwifiex_wait_queue *wait,
+					u8 *mac)
+{
+	u8 mac_address[ETH_ALEN];
+	int ret = 0;
+	u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+
+	if (mac) {
+		if (!memcmp(mac, zero_mac, sizeof(zero_mac)))
+			memcpy((u8 *) &mac_address,
+			       (u8 *) &priv->curr_bss_params.bss_descriptor.
+			       mac_address, ETH_ALEN);
+		else
+			memcpy((u8 *) &mac_address, (u8 *) mac, ETH_ALEN);
+	} else {
+		memcpy((u8 *) &mac_address, (u8 *) &priv->curr_bss_params.
+		       bss_descriptor.mac_address, ETH_ALEN);
+	}
+
+	ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_DEAUTHENTICATE,
+				  HostCmd_ACT_GEN_SET, 0, wait, &mac_address);
+
+	if (!ret && wait)
+		ret = -EINPROGRESS;
+
+	return ret;
+}
+
+/*
+ * This function deauthenticates/disconnects from a BSS.
+ *
+ * In case of infra made, it sends deauthentication request, and
+ * in case of ad-hoc mode, a stop network request is sent to the firmware.
+ */
+int mwifiex_deauthenticate(struct mwifiex_private *priv,
+			   struct mwifiex_wait_queue *wait, u8 *mac)
+{
+	int ret = 0;
+
+	if (priv->media_connected) {
+		if (priv->bss_mode == NL80211_IFTYPE_STATION) {
+			ret = mwifiex_deauthenticate_infra(priv, wait, mac);
+		} else if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
+			ret = mwifiex_prepare_cmd(priv,
+					HostCmd_CMD_802_11_AD_HOC_STOP,
+					HostCmd_ACT_GEN_SET, 0, wait, NULL);
+
+			if (!ret && wait)
+				ret = -EINPROGRESS;
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * This function converts band to radio type used in channel TLV.
+ */
+u8
+mwifiex_band_to_radio_type(u8 band)
+{
+	u8 ret_radio_type;
+
+	switch (band) {
+	case BAND_A:
+	case BAND_AN:
+	case BAND_A | BAND_AN:
+		ret_radio_type = HostCmd_SCAN_RADIO_TYPE_A;
+		break;
+	case BAND_B:
+	case BAND_G:
+	case BAND_B | BAND_G:
+	default:
+		ret_radio_type = HostCmd_SCAN_RADIO_TYPE_BG;
+		break;
+	}
+
+	return ret_radio_type;
+}
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
new file mode 100644
index 0000000..ed89ca4
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -0,0 +1,1102 @@
+/*
+ * Marvell Wireless LAN device driver: major functions
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "main.h"
+#include "wmm.h"
+#include "cfg80211.h"
+#include "11n.h"
+
+#define VERSION	"1.0"
+
+const char driver_version[] = "mwifiex " VERSION " (%s) ";
+
+struct mwifiex_adapter *g_adapter;
+EXPORT_SYMBOL_GPL(g_adapter);
+
+static struct mwifiex_bss_attr mwifiex_bss_sta[] = {
+	{MWIFIEX_BSS_TYPE_STA, MWIFIEX_DATA_FRAME_TYPE_ETH_II, true, 0, 0},
+};
+
+static int drv_mode = DRV_MODE_STA;
+
+static char fw_name[32] = DEFAULT_FW_NAME;
+
+/* Supported drv_mode table */
+static struct mwifiex_drv_mode mwifiex_drv_mode_tbl[] = {
+	{
+	 /* drv_mode */
+	 .drv_mode = DRV_MODE_STA,
+	 /* intf number */
+	 .intf_num = ARRAY_SIZE(mwifiex_bss_sta),
+	 /* bss_attr */
+	 .bss_attr = mwifiex_bss_sta,
+	 }
+	,
+};
+
+/*
+ * This function registers the device and performs all the necessary
+ * initializations.
+ *
+ * The following initialization operations are performed -
+ *      - Allocate adapter structure
+ *      - Save interface specific operations table in adapter
+ *      - Call interface specific initialization routine
+ *      - Allocate private structures
+ *      - Set default adapter structure parameters
+ *      - Initialize locks
+ *
+ * In case of any errors during inittialization, this function also ensures
+ * proper cleanup before exiting.
+ */
+static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops,
+			    struct mwifiex_device *mdevice, void **padapter)
+{
+	int ret = 0;
+	struct mwifiex_adapter *adapter = NULL;
+	u8 i = 0;
+
+	adapter = kzalloc(sizeof(struct mwifiex_adapter), GFP_KERNEL);
+	/* Allocate memory for adapter structure */
+	if (!adapter)
+		return -1;
+
+	g_adapter = adapter;
+	adapter->card = card;
+
+	/* Save interface specific operations in adapter */
+	memmove(&adapter->if_ops, if_ops, sizeof(struct mwifiex_if_ops));
+
+	/* card specific initialization has been deferred until now .. */
+	ret = adapter->if_ops.init_if(adapter);
+	if (ret)
+		goto error;
+
+	adapter->priv_num = 0;
+	for (i = 0; i < MWIFIEX_MAX_BSS_NUM; i++) {
+		adapter->priv[i] = NULL;
+
+		if (!mdevice->bss_attr[i].active)
+			continue;
+
+		/* For valid bss_attr,
+		   allocate memory for private structure */
+		adapter->priv[i] = kzalloc(sizeof(struct mwifiex_private),
+				GFP_KERNEL);
+		if (!adapter->priv[i]) {
+			dev_err(adapter->dev, "%s: failed to alloc priv[%d]\n",
+			       __func__, i);
+			goto error;
+		}
+
+		adapter->priv_num++;
+		memset(adapter->priv[i], 0,
+		       sizeof(struct mwifiex_private));
+		adapter->priv[i]->adapter = adapter;
+		/* Save bss_type, frame_type & bss_priority */
+		adapter->priv[i]->bss_type = (u8) mdevice->bss_attr[i].bss_type;
+		adapter->priv[i]->frame_type =
+			(u8) mdevice->bss_attr[i].frame_type;
+		adapter->priv[i]->bss_priority =
+			(u8) mdevice->bss_attr[i].bss_priority;
+		if (mdevice->bss_attr[i].bss_type == MWIFIEX_BSS_TYPE_STA)
+			adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_STA;
+		else if (mdevice->bss_attr[i].bss_type == MWIFIEX_BSS_TYPE_UAP)
+			adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_UAP;
+
+		/* Save bss_index & bss_num */
+		adapter->priv[i]->bss_index = i;
+		adapter->priv[i]->bss_num = mdevice->bss_attr[i].bss_num;
+	}
+
+	/* Initialize lock variables */
+	if (mwifiex_init_lock_list(adapter))
+		goto error;
+
+	init_timer(&adapter->cmd_timer);
+	adapter->cmd_timer.function = mwifiex_cmd_timeout_func;
+	adapter->cmd_timer.data = (unsigned long) adapter;
+
+	/* Return pointer of struct mwifiex_adapter */
+	*padapter = adapter;
+	return 0;
+
+error:
+	dev_dbg(adapter->dev, "info: leave mwifiex_register with error\n");
+
+	/* Free lock variables */
+	mwifiex_free_lock_list(adapter);
+	for (i = 0; i < MWIFIEX_MAX_BSS_NUM; i++)
+		kfree(adapter->priv[i]);
+	kfree(adapter);
+
+	return -1;
+}
+
+/*
+ * This function unregisters the device and performs all the necessary
+ * cleanups.
+ *
+ * The following cleanup operations are performed -
+ *      - Free the timers
+ *      - Free beacon buffers
+ *      - Free private structures
+ *      - Free adapter structure
+ */
+static int mwifiex_unregister(struct mwifiex_adapter *adapter)
+{
+	s32 i = 0;
+
+	del_timer(&adapter->cmd_timer);
+
+	/* Free private structures */
+	for (i = 0; i < adapter->priv_num; i++) {
+		if (adapter->priv[i]) {
+			mwifiex_free_curr_bcn(adapter->priv[i]);
+			kfree(adapter->priv[i]);
+		}
+	}
+
+	kfree(adapter);
+	return 0;
+}
+
+/*
+ * The main process.
+ *
+ * This function is the main procedure of the driver and handles various driver
+ * operations. It runs in a loop and provides the core functionalities.
+ *
+ * The main responsibilities of this function are -
+ *      - Ensure concurrency control
+ *      - Handle pending interrupts and call interrupt handlers
+ *      - Wake up the card if required
+ *      - Handle command responses and call response handlers
+ *      - Handle events and call event handlers
+ *      - Execute pending commands
+ *      - Transmit pending data packets
+ */
+int mwifiex_main_process(struct mwifiex_adapter *adapter)
+{
+	int ret = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&adapter->main_proc_lock, flags);
+
+	/* Check if already processing */
+	if (adapter->mwifiex_processing) {
+		spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
+		goto exit_main_proc;
+	} else {
+		adapter->mwifiex_processing = true;
+		spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
+	}
+process_start:
+	do {
+		if ((adapter->hw_status == MWIFIEX_HW_STATUS_CLOSING) ||
+		    (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY))
+			break;
+
+		/* Handle pending interrupt if any */
+		if (adapter->int_status) {
+			if (adapter->hs_activated)
+				mwifiex_process_hs_config(adapter);
+			adapter->if_ops.process_int_status(adapter);
+		}
+
+		/* Need to wake up the card ? */
+		if ((adapter->ps_state == PS_STATE_SLEEP) &&
+		    (adapter->pm_wakeup_card_req &&
+		     !adapter->pm_wakeup_fw_try) &&
+		    (is_command_pending(adapter)
+		     || !mwifiex_wmm_lists_empty(adapter))) {
+			adapter->pm_wakeup_fw_try = true;
+			adapter->if_ops.wakeup(adapter);
+			continue;
+		}
+		if (IS_CARD_RX_RCVD(adapter)) {
+			adapter->pm_wakeup_fw_try = false;
+			if (adapter->ps_state == PS_STATE_SLEEP)
+				adapter->ps_state = PS_STATE_AWAKE;
+		} else {
+			/* We have tried to wakeup the card already */
+			if (adapter->pm_wakeup_fw_try)
+				break;
+			if (adapter->ps_state != PS_STATE_AWAKE ||
+			    adapter->tx_lock_flag)
+				break;
+
+			if (adapter->scan_processing || adapter->data_sent
+			    || mwifiex_wmm_lists_empty(adapter)) {
+				if (adapter->cmd_sent || adapter->curr_cmd
+				    || (!is_command_pending(adapter)))
+					break;
+			}
+		}
+
+		/* Check for Cmd Resp */
+		if (adapter->cmd_resp_received) {
+			adapter->cmd_resp_received = false;
+			mwifiex_process_cmdresp(adapter);
+
+			/* call mwifiex back when init_fw is done */
+			if (adapter->hw_status == MWIFIEX_HW_STATUS_INIT_DONE) {
+				adapter->hw_status = MWIFIEX_HW_STATUS_READY;
+				mwifiex_init_fw_complete(adapter);
+			}
+		}
+
+		/* Check for event */
+		if (adapter->event_received) {
+			adapter->event_received = false;
+			mwifiex_process_event(adapter);
+		}
+
+		/* Check if we need to confirm Sleep Request
+		   received previously */
+		if (adapter->ps_state == PS_STATE_PRE_SLEEP) {
+			if (!adapter->cmd_sent && !adapter->curr_cmd)
+				mwifiex_check_ps_cond(adapter);
+		}
+
+		/* * The ps_state may have been changed during processing of
+		 * Sleep Request event.
+		 */
+		if ((adapter->ps_state == PS_STATE_SLEEP)
+		    || (adapter->ps_state == PS_STATE_PRE_SLEEP)
+		    || (adapter->ps_state == PS_STATE_SLEEP_CFM)
+		    || adapter->tx_lock_flag)
+			continue;
+
+		if (!adapter->cmd_sent && !adapter->curr_cmd) {
+			if (mwifiex_exec_next_cmd(adapter) == -1) {
+				ret = -1;
+				break;
+			}
+		}
+
+		if (!adapter->scan_processing && !adapter->data_sent &&
+		    !mwifiex_wmm_lists_empty(adapter)) {
+			mwifiex_wmm_process_tx(adapter);
+			if (adapter->hs_activated) {
+				adapter->is_hs_configured = false;
+				mwifiex_hs_activated_event
+					(mwifiex_get_priv
+					 (adapter, MWIFIEX_BSS_ROLE_ANY),
+					 false);
+			}
+		}
+
+		if (adapter->delay_null_pkt && !adapter->cmd_sent &&
+		    !adapter->curr_cmd && !is_command_pending(adapter)
+		    && mwifiex_wmm_lists_empty(adapter)) {
+			if (!mwifiex_send_null_packet
+			    (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA),
+			     MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET |
+			     MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET)) {
+				adapter->delay_null_pkt = false;
+				adapter->ps_state = PS_STATE_SLEEP;
+			}
+			break;
+		}
+	} while (true);
+
+	if ((adapter->int_status) || IS_CARD_RX_RCVD(adapter))
+		goto process_start;
+
+	spin_lock_irqsave(&adapter->main_proc_lock, flags);
+	adapter->mwifiex_processing = false;
+	spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
+
+exit_main_proc:
+	if (adapter->hw_status == MWIFIEX_HW_STATUS_CLOSING)
+		mwifiex_shutdown_drv(adapter);
+	return ret;
+}
+
+/*
+ * This function initializes the software.
+ *
+ * The main work includes allocating and initializing the adapter structure
+ * and initializing the private structures.
+ */
+static int
+mwifiex_init_sw(void *card, struct mwifiex_if_ops *if_ops, void **pmwifiex)
+{
+	int i;
+	struct mwifiex_device device;
+	struct mwifiex_drv_mode *drv_mode_ptr;
+
+	/* find mwifiex_drv_mode entry from mwifiex_drv_mode_tbl */
+	drv_mode_ptr = NULL;
+	for (i = 0; i < ARRAY_SIZE(mwifiex_drv_mode_tbl); i++) {
+		if (mwifiex_drv_mode_tbl[i].drv_mode == drv_mode) {
+			drv_mode_ptr = &mwifiex_drv_mode_tbl[i];
+			break;
+		}
+	}
+
+	if (!drv_mode_ptr) {
+		pr_err("invalid drv_mode=%d\n", drv_mode);
+		return -1;
+	}
+
+	memset(&device, 0, sizeof(struct mwifiex_device));
+
+	for (i = 0; i < drv_mode_ptr->intf_num; i++) {
+		device.bss_attr[i].bss_type =
+			drv_mode_ptr->bss_attr[i].bss_type;
+		device.bss_attr[i].frame_type =
+			drv_mode_ptr->bss_attr[i].frame_type;
+		device.bss_attr[i].active = drv_mode_ptr->bss_attr[i].active;
+		device.bss_attr[i].bss_priority =
+			drv_mode_ptr->bss_attr[i].bss_priority;
+		device.bss_attr[i].bss_num = drv_mode_ptr->bss_attr[i].bss_num;
+	}
+
+	if (mwifiex_register(card, if_ops, &device, pmwifiex))
+		return -1;
+
+	return 0;
+}
+
+/*
+ * This function frees the adapter structure.
+ *
+ * Additionally, this closes the netlink socket, frees the timers
+ * and private structures.
+ */
+static void mwifiex_free_adapter(struct mwifiex_adapter *adapter)
+{
+	if (!adapter) {
+		pr_err("%s: adapter is NULL\n", __func__);
+		return;
+	}
+
+	mwifiex_unregister(adapter);
+	pr_debug("info: %s: free adapter\n", __func__);
+}
+
+/*
+ * This function initializes the hardware and firmware.
+ *
+ * The main initialization steps followed are -
+ *      - Download the correct firmware to card
+ *      - Allocate and initialize the adapter structure
+ *      - Initialize the private structures
+ *      - Issue the init commands to firmware
+ */
+static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter)
+{
+	int ret = 0;
+	int err;
+	struct mwifiex_fw_image fw;
+
+	memset(&fw, 0, sizeof(struct mwifiex_fw_image));
+
+	switch (adapter->revision_id) {
+	case SD8787_W0:
+	case SD8787_W1:
+		strcpy(fw_name, SD8787_W1_FW_NAME);
+		break;
+	case SD8787_A0:
+	case SD8787_A1:
+		strcpy(fw_name, SD8787_AX_FW_NAME);
+		break;
+	default:
+		break;
+	}
+
+	err = request_firmware(&adapter->firmware, fw_name, adapter->dev);
+	if (err < 0) {
+		dev_err(adapter->dev, "request_firmware() returned"
+				" error code %#x\n", err);
+		ret = -1;
+		goto done;
+	}
+	fw.fw_buf = (u8 *) adapter->firmware->data;
+	fw.fw_len = adapter->firmware->size;
+
+	ret = mwifiex_dnld_fw(adapter, &fw);
+	if (ret == -1)
+		goto done;
+
+	dev_notice(adapter->dev, "WLAN FW is active\n");
+
+	adapter->init_wait_q_woken = false;
+	ret = mwifiex_init_fw(adapter);
+	if (ret == -1) {
+		goto done;
+	} else if (!ret) {
+		adapter->hw_status = MWIFIEX_HW_STATUS_READY;
+		goto done;
+	}
+	/* Wait for mwifiex_init to complete */
+	wait_event_interruptible(adapter->init_wait_q,
+				 adapter->init_wait_q_woken);
+	if (adapter->hw_status != MWIFIEX_HW_STATUS_READY) {
+		ret = -1;
+		goto done;
+	}
+	ret = 0;
+
+done:
+	if (adapter->firmware)
+		release_firmware(adapter->firmware);
+	if (ret)
+		ret = -1;
+	return ret;
+}
+
+/*
+ * This function fills a driver buffer.
+ *
+ * The function associates a given SKB with the provided driver buffer
+ * and also updates some of the SKB parameters, including IP header,
+ * priority and timestamp.
+ */
+static void
+mwifiex_fill_buffer(struct sk_buff *skb)
+{
+	struct ethhdr *eth = NULL;
+	struct iphdr *iph;
+	struct timeval tv;
+	u8 tid = 0;
+
+	eth = (struct ethhdr *) skb->data;
+	switch (eth->h_proto) {
+	case __constant_htons(ETH_P_IP):
+		iph = ip_hdr(skb);
+		tid = IPTOS_PREC(iph->tos);
+		pr_debug("data: packet type ETH_P_IP: %04x, tid=%#x prio=%#x\n",
+		       eth->h_proto, tid, skb->priority);
+		break;
+	case __constant_htons(ETH_P_ARP):
+		pr_debug("data: ARP packet: %04x\n", eth->h_proto);
+	default:
+		break;
+	}
+/* Offset for TOS field in the IP header */
+#define IPTOS_OFFSET 5
+	tid = (tid >> IPTOS_OFFSET);
+	skb->priority = tid;
+	/* Record the current time the packet was queued; used to
+	   determine the amount of time the packet was queued in
+	   the driver before it was sent to the firmware.
+	   The delay is then sent along with the packet to the
+	   firmware for aggregate delay calculation for stats and
+	   MSDU lifetime expiry.
+	 */
+	do_gettimeofday(&tv);
+	skb->tstamp = timeval_to_ktime(tv);
+	return;
+}
+
+/*
+ * CFG802.11 network device handler for open.
+ *
+ * Starts the data queue.
+ */
+static int
+mwifiex_open(struct net_device *dev)
+{
+	netif_start_queue(dev);
+	return 0;
+}
+
+/*
+ * CFG802.11 network device handler for close.
+ */
+static int
+mwifiex_close(struct net_device *dev)
+{
+	return 0;
+}
+
+/*
+ * CFG802.11 network device handler for data transmission.
+ */
+static int
+mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+	struct sk_buff *new_skb = NULL;
+	struct mwifiex_txinfo *tx_info;
+
+	dev_dbg(priv->adapter->dev, "data: %lu BSS(%d): Data <= kernel\n",
+				jiffies, priv->bss_index);
+
+	if (priv->adapter->surprise_removed) {
+		kfree(skb);
+		priv->stats.tx_dropped++;
+		return 0;
+	}
+	if (!skb->len || (skb->len > ETH_FRAME_LEN)) {
+		dev_err(priv->adapter->dev, "Tx: bad skb len %d\n", skb->len);
+		kfree(skb);
+		priv->stats.tx_dropped++;
+		return 0;
+	}
+	if (skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN) {
+		dev_dbg(priv->adapter->dev,
+			"data: Tx: insufficient skb headroom %d\n",
+		       skb_headroom(skb));
+		/* Insufficient skb headroom - allocate a new skb */
+		new_skb =
+			skb_realloc_headroom(skb, MWIFIEX_MIN_DATA_HEADER_LEN);
+		if (unlikely(!new_skb)) {
+			dev_err(priv->adapter->dev, "Tx: cannot alloca new_skb\n");
+			kfree(skb);
+			priv->stats.tx_dropped++;
+			return 0;
+		}
+		kfree_skb(skb);
+		skb = new_skb;
+		dev_dbg(priv->adapter->dev, "info: new skb headroomd %d\n",
+				skb_headroom(skb));
+	}
+
+	tx_info = MWIFIEX_SKB_TXCB(skb);
+	tx_info->bss_index = priv->bss_index;
+	mwifiex_fill_buffer(skb);
+
+	mwifiex_wmm_add_buf_txqueue(priv->adapter, skb);
+	atomic_inc(&priv->adapter->tx_pending);
+
+	if (atomic_read(&priv->adapter->tx_pending) >= MAX_TX_PENDING) {
+		netif_stop_queue(priv->netdev);
+		dev->trans_start = jiffies;
+	}
+
+	queue_work(priv->adapter->workqueue, &priv->adapter->main_work);
+
+	return 0;
+}
+
+/*
+ * CFG802.11 network device handler for setting MAC address.
+ */
+static int
+mwifiex_set_mac_address(struct net_device *dev, void *addr)
+{
+	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+	struct sockaddr *hw_addr = (struct sockaddr *) addr;
+
+	memcpy(priv->curr_addr, hw_addr->sa_data, ETH_ALEN);
+
+	if (mwifiex_request_set_mac_address(priv)) {
+		dev_err(priv->adapter->dev, "set MAC address failed\n");
+		return -EFAULT;
+	}
+	memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN);
+
+	return 0;
+}
+
+/*
+ * CFG802.11 network device handler for setting multicast list.
+ */
+static void mwifiex_set_multicast_list(struct net_device *dev)
+{
+	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+	mwifiex_request_set_multicast_list(priv, dev);
+}
+
+/*
+ * CFG802.11 network device handler for transmission timeout.
+ */
+static void
+mwifiex_tx_timeout(struct net_device *dev)
+{
+	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+
+	dev_err(priv->adapter->dev, "%lu : Tx timeout, bss_index=%d\n",
+				jiffies, priv->bss_index);
+	dev->trans_start = jiffies;
+	priv->num_tx_timeout++;
+}
+
+/*
+ * CFG802.11 network device handler for statistics retrieval.
+ */
+static struct net_device_stats *mwifiex_get_stats(struct net_device *dev)
+{
+	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+
+	return &priv->stats;
+}
+
+/* Network device handlers */
+static const struct net_device_ops mwifiex_netdev_ops = {
+	.ndo_open = mwifiex_open,
+	.ndo_stop = mwifiex_close,
+	.ndo_start_xmit = mwifiex_hard_start_xmit,
+	.ndo_set_mac_address = mwifiex_set_mac_address,
+	.ndo_tx_timeout = mwifiex_tx_timeout,
+	.ndo_get_stats = mwifiex_get_stats,
+	.ndo_set_multicast_list = mwifiex_set_multicast_list,
+};
+
+/*
+ * This function initializes the private structure parameters.
+ *
+ * The following wait queues are initialized -
+ *      - IOCTL wait queue
+ *      - Command wait queue
+ *      - Statistics wait queue
+ *
+ * ...and the following default parameters are set -
+ *      - Current key index     : Set to 0
+ *      - Rate index            : Set to auto
+ *      - Media connected       : Set to disconnected
+ *      - Adhoc link sensed     : Set to false
+ *      - Nick name             : Set to null
+ *      - Number of Tx timeout  : Set to 0
+ *      - Device address        : Set to current address
+ *
+ * In addition, the CFG80211 work queue is also created.
+ */
+static void
+mwifiex_init_priv_params(struct mwifiex_private *priv, struct net_device *dev)
+{
+	dev->netdev_ops = &mwifiex_netdev_ops;
+	/* Initialize private structure */
+	init_waitqueue_head(&priv->ioctl_wait_q);
+	init_waitqueue_head(&priv->cmd_wait_q);
+	init_waitqueue_head(&priv->w_stats_wait_q);
+	priv->current_key_index = 0;
+	priv->media_connected = false;
+	memset(&priv->nick_name, 0, sizeof(priv->nick_name));
+	priv->num_tx_timeout = 0;
+	priv->workqueue = create_singlethread_workqueue("cfg80211_wq");
+	INIT_WORK(&priv->cfg_workqueue, mwifiex_cfg80211_results);
+	memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN);
+}
+
+/*
+ * This function adds a new logical interface.
+ *
+ * It allocates, initializes and registers the interface by performing
+ * the following opearations -
+ *      - Allocate a new net device structure
+ *      - Assign device name
+ *      - Register the new device with CFG80211 subsystem
+ *      - Initialize semaphore and private structure
+ *      - Register the new device with kernel
+ *      - Create the complete debug FS structure if configured
+ */
+static struct mwifiex_private *mwifiex_add_interface(
+			struct mwifiex_adapter *adapter,
+			u8 bss_index, u8 bss_type)
+{
+	struct net_device *dev = NULL;
+	struct mwifiex_private *priv = NULL;
+	void *mdev_priv = NULL;
+
+	dev = alloc_netdev_mq(sizeof(struct mwifiex_private *), "mlan%d",
+			      ether_setup, 1);
+	if (!dev) {
+		dev_err(adapter->dev, "no memory available for netdevice\n");
+		goto error;
+	}
+	if (dev_alloc_name(dev, dev->name)) {
+		dev_err(adapter->dev, "unable to alloc name for netdevice\n");
+		goto error;
+	}
+
+	if (mwifiex_register_cfg80211(dev, adapter->priv[bss_index]->curr_addr,
+				      adapter->priv[bss_index]) != 0) {
+		dev_err(adapter->dev, "cannot register netdevice with cfg80211\n");
+		goto error;
+	}
+	/* Save the priv pointer in netdev */
+	priv = adapter->priv[bss_index];
+	mdev_priv = netdev_priv(dev);
+	*((unsigned long *) mdev_priv) = (unsigned long) priv;
+
+	priv->netdev = dev;
+
+	sema_init(&priv->async_sem, 1);
+	priv->scan_pending_on_block = false;
+
+	mwifiex_init_priv_params(priv, dev);
+
+	SET_NETDEV_DEV(dev, adapter->dev);
+
+	/* Register network device */
+	if (register_netdev(dev)) {
+		dev_err(adapter->dev, "cannot register virtual network device\n");
+		goto error;
+	}
+
+	dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name);
+#ifdef CONFIG_DEBUG_FS
+	mwifiex_dev_debugfs_init(priv);
+#endif
+	return priv;
+error:
+	if (dev)
+		free_netdev(dev);
+	return NULL;
+}
+
+/*
+ * This function removes a logical interface.
+ *
+ * It deregisters, resets and frees the interface by performing
+ * the following operations -
+ *      - Disconnect the device if connected, send wireless event to
+ *        notify applications.
+ *      - Remove the debug FS structure if configured
+ *      - Unregister the device from kernel
+ *      - Free the net device structure
+ *      - Cancel all works and destroy work queue
+ *      - Unregister and free the wireless device from CFG80211 subsystem
+ */
+static void
+mwifiex_remove_interface(struct mwifiex_adapter *adapter, u8 bss_index)
+{
+	struct net_device *dev = NULL;
+	struct mwifiex_private *priv = adapter->priv[bss_index];
+
+	if (!priv)
+		return;
+	dev = priv->netdev;
+
+	if (priv->media_connected)
+		priv->media_connected = false;
+
+#ifdef CONFIG_DEBUG_FS
+	mwifiex_dev_debugfs_remove(priv);
+#endif
+	/* Last reference is our one */
+	dev_dbg(adapter->dev, "info: %s: refcnt = %d\n",
+				dev->name, netdev_refcnt_read(dev));
+
+	if (dev->reg_state == NETREG_REGISTERED)
+		unregister_netdev(dev);
+
+	/* Clear the priv in adapter */
+	priv->netdev = NULL;
+	if (dev)
+		free_netdev(dev);
+
+	cancel_work_sync(&priv->cfg_workqueue);
+	flush_workqueue(priv->workqueue);
+	destroy_workqueue(priv->workqueue);
+	wiphy_unregister(priv->wdev->wiphy);
+	wiphy_free(priv->wdev->wiphy);
+	kfree(priv->wdev);
+
+	return;
+}
+
+/*
+ * Sends IOCTL request to shutdown firmware.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ */
+int mwifiex_shutdown_fw(struct mwifiex_private *priv, u8 wait_option)
+{
+	struct mwifiex_wait_queue *wait = NULL;
+	int status = 0;
+
+	/* Allocate an IOCTL request buffer */
+	wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
+	if (!wait)
+		return -ENOMEM;
+
+	status = mwifiex_misc_ioctl_init_shutdown(priv->adapter, wait,
+						  MWIFIEX_FUNC_SHUTDOWN);
+
+	status = mwifiex_request_ioctl(priv, wait, status, wait_option);
+
+	kfree(wait);
+	return status;
+}
+EXPORT_SYMBOL_GPL(mwifiex_shutdown_fw);
+
+/*
+ * This function check if command is pending.
+ */
+int is_command_pending(struct mwifiex_adapter *adapter)
+{
+	unsigned long flags;
+	int is_cmd_pend_q_empty;
+
+	spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
+	is_cmd_pend_q_empty = list_empty(&adapter->cmd_pending_q);
+	spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
+
+	return !is_cmd_pend_q_empty;
+}
+
+/*
+ * This function returns the correct private structure pointer based
+ * upon the BSS number.
+ */
+struct mwifiex_private *
+mwifiex_bss_index_to_priv(struct mwifiex_adapter *adapter, u8 bss_index)
+{
+	if (!adapter || (bss_index >= adapter->priv_num))
+		return NULL;
+	return adapter->priv[bss_index];
+}
+
+/*
+ * This is the main work queue function.
+ *
+ * It handles the main process, which in turn handles the complete
+ * driver operations.
+ */
+static void mwifiex_main_work_queue(struct work_struct *work)
+{
+	struct mwifiex_adapter *adapter =
+		container_of(work, struct mwifiex_adapter, main_work);
+
+	if (adapter->surprise_removed)
+		return;
+	mwifiex_main_process(adapter);
+}
+
+/*
+ * This function cancels all works in the queue and destroys
+ * the main workqueue.
+ */
+static void
+mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter)
+{
+	flush_workqueue(adapter->workqueue);
+	destroy_workqueue(adapter->workqueue);
+	adapter->workqueue = NULL;
+}
+
+/*
+ * This function adds the card.
+ *
+ * This function follows the following major steps to set up the device -
+ *      - Initialize software. This includes probing the card, registering
+ *        the interface operations table, and allocating/initializing the
+ *        adapter structure
+ *      - Set up the netlink socket
+ *      - Create and start the main work queue
+ *      - Register the device
+ *      - Initialize firmware and hardware
+ *      - Add logical interfaces
+ */
+int
+mwifiex_add_card(void *card, struct semaphore *sem,
+		 struct mwifiex_if_ops *if_ops)
+{
+	int status = 0;
+	int i;
+	struct mwifiex_adapter *adapter = NULL;
+	struct mwifiex_drv_mode *drv_mode_info = &mwifiex_drv_mode_tbl[0];
+
+	if (down_interruptible(sem))
+		goto exit_sem_err;
+
+	if (mwifiex_init_sw(card, if_ops, (void **) &adapter)) {
+		pr_err("%s: software init failed\n", __func__);
+		goto err_init_sw;
+	}
+
+	adapter->drv_mode = drv_mode_info;
+
+	adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING;
+	/* PnP and power profile */
+	adapter->surprise_removed = false;
+	init_waitqueue_head(&adapter->init_wait_q);
+	adapter->is_suspended = false;
+	adapter->hs_activated = false;
+	init_waitqueue_head(&adapter->hs_activate_wait_q);
+
+	/* Create workqueue */
+	adapter->workqueue = create_workqueue("MWIFIEX_WORK_QUEUE");
+	if (!adapter->workqueue)
+		goto err_kmalloc;
+
+	INIT_WORK(&adapter->main_work, mwifiex_main_work_queue);
+
+	/* Register the device. Fill up the private data structure with relevant
+	   information from the card and request for the required IRQ. */
+	if (adapter->if_ops.register_dev(adapter)) {
+		pr_err("%s: failed to register mwifiex device\n", __func__);
+		goto err_registerdev;
+	}
+
+	/* Init FW and HW */
+	if (mwifiex_init_hw_fw(adapter)) {
+		pr_err("%s: firmware init failed\n", __func__);
+		goto err_init_fw;
+	}
+	/* Add interfaces */
+	for (i = 0; i < drv_mode_info->intf_num; i++) {
+		if (!mwifiex_add_interface(adapter, i,
+				adapter->drv_mode->bss_attr[i].bss_type)) {
+			status = -1;
+			break;
+		}
+	}
+	if (status)
+		goto err_add_intf;
+
+	up(sem);
+
+	return 0;
+
+err_add_intf:
+	for (i = 0; i < adapter->priv_num; i++)
+		mwifiex_remove_interface(adapter, i);
+err_init_fw:
+	/* Unregister device */
+	pr_debug("info: %s: unregister device\n", __func__);
+	adapter->if_ops.unregister_dev(adapter);
+err_registerdev:
+	adapter->surprise_removed = true;
+	mwifiex_terminate_workqueue(adapter);
+err_kmalloc:
+	if ((adapter->hw_status == MWIFIEX_HW_STATUS_FW_READY) ||
+	    (adapter->hw_status == MWIFIEX_HW_STATUS_READY)) {
+		pr_debug("info: %s: shutdown mwifiex\n", __func__);
+		adapter->init_wait_q_woken = false;
+		status = mwifiex_shutdown_drv(adapter);
+		if (status == -EINPROGRESS)
+			wait_event_interruptible(adapter->init_wait_q,
+						 adapter->init_wait_q_woken);
+	}
+
+	mwifiex_free_adapter(adapter);
+
+err_init_sw:
+	up(sem);
+
+exit_sem_err:
+	return -1;
+}
+EXPORT_SYMBOL_GPL(mwifiex_add_card);
+
+/*
+ * This function removes the card.
+ *
+ * This function follows the following major steps to remove the device -
+ *      - Stop data traffic
+ *      - Shutdown firmware
+ *      - Remove the logical interfaces
+ *      - Terminate the work queue
+ *      - Unregister the device
+ *      - Free the adapter structure
+ */
+int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem)
+{
+	struct mwifiex_private *priv = NULL;
+	int status;
+	int i;
+
+	if (down_interruptible(sem))
+		goto exit_sem_err;
+
+	if (!adapter)
+		goto exit_remove;
+
+	adapter->surprise_removed = true;
+
+	/* Stop data */
+	for (i = 0; i < adapter->priv_num; i++) {
+		priv = adapter->priv[i];
+		if (priv) {
+			if (!netif_queue_stopped(priv->netdev))
+				netif_stop_queue(priv->netdev);
+			if (netif_carrier_ok(priv->netdev))
+				netif_carrier_off(priv->netdev);
+		}
+	}
+
+	dev_dbg(adapter->dev, "cmd: calling mwifiex_shutdown_drv...\n");
+	adapter->init_wait_q_woken = false;
+	status = mwifiex_shutdown_drv(adapter);
+	if (status == -EINPROGRESS)
+		wait_event_interruptible(adapter->init_wait_q,
+					 adapter->init_wait_q_woken);
+	dev_dbg(adapter->dev, "cmd: mwifiex_shutdown_drv done\n");
+	if (atomic_read(&adapter->rx_pending) ||
+	    atomic_read(&adapter->tx_pending) ||
+	    atomic_read(&adapter->ioctl_pending)) {
+		dev_err(adapter->dev, "rx_pending=%d, tx_pending=%d, "
+		       "ioctl_pending=%d\n",
+		       atomic_read(&adapter->rx_pending),
+		       atomic_read(&adapter->tx_pending),
+		       atomic_read(&adapter->ioctl_pending));
+	}
+
+	/* Remove interface */
+	for (i = 0; i < adapter->priv_num; i++)
+		mwifiex_remove_interface(adapter, i);
+
+	mwifiex_terminate_workqueue(adapter);
+
+	/* Unregister device */
+	dev_dbg(adapter->dev, "info: unregister device\n");
+	adapter->if_ops.unregister_dev(adapter);
+	/* Free adapter structure */
+	dev_dbg(adapter->dev, "info: free adapter\n");
+	mwifiex_free_adapter(adapter);
+
+exit_remove:
+	up(sem);
+exit_sem_err:
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mwifiex_remove_card);
+
+/*
+ * This function initializes the module.
+ *
+ * The debug FS is also initialized if configured.
+ */
+static int
+mwifiex_init_module(void)
+{
+#ifdef CONFIG_DEBUG_FS
+	mwifiex_debugfs_init();
+#endif
+	return 0;
+}
+
+/*
+ * This function cleans up the module.
+ *
+ * The debug FS is removed if available.
+ */
+static void
+mwifiex_cleanup_module(void)
+{
+#ifdef CONFIG_DEBUG_FS
+	mwifiex_debugfs_remove();
+#endif
+}
+
+module_init(mwifiex_init_module);
+module_exit(mwifiex_cleanup_module);
+
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_DESCRIPTION("Marvell WiFi-Ex Driver version " VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
new file mode 100644
index 0000000..43ff149
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -0,0 +1,1058 @@
+/*
+ * Marvell Wireless LAN device driver: major data structures and prototypes
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#ifndef _MWIFIEX_MAIN_H_
+#define _MWIFIEX_MAIN_H_
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/semaphore.h>
+#include <linux/ip.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <net/sock.h>
+#include <net/lib80211.h>
+#include <linux/firmware.h>
+#include <linux/ctype.h>
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+
+extern const char driver_version[];
+extern struct mwifiex_adapter *g_adapter;
+
+enum {
+	MWIFIEX_NO_WAIT,
+	MWIFIEX_IOCTL_WAIT,
+	MWIFIEX_CMD_WAIT,
+	MWIFIEX_PROC_WAIT,
+	MWIFIEX_WSTATS_WAIT
+};
+
+#define DRV_MODE_STA       0x1
+
+#define SD8787_W0   0x30
+#define SD8787_W1   0x31
+#define SD8787_A0   0x40
+#define SD8787_A1   0x41
+
+#define DEFAULT_FW_NAME "mrvl/sd8787_uapsta.bin"
+#define SD8787_W1_FW_NAME "mrvl/sd8787_uapsta_w1.bin"
+#define SD8787_AX_FW_NAME "mrvl/sd8787_uapsta.bin"
+
+struct mwifiex_drv_mode {
+	u16 drv_mode;
+	u16 intf_num;
+	struct mwifiex_bss_attr *bss_attr;
+};
+
+
+#define MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT	(5 * HZ)
+
+#define MWIFIEX_TIMER_10S			10000
+#define MWIFIEX_TIMER_1S			1000
+
+#define MAX_TX_PENDING      60
+
+#define MWIFIEX_UPLD_SIZE               (2312)
+
+#define MAX_EVENT_SIZE                  1024
+
+#define ARP_FILTER_MAX_BUF_SIZE         68
+
+#define MWIFIEX_KEY_BUFFER_SIZE			16
+#define MWIFIEX_DEFAULT_LISTEN_INTERVAL 10
+#define MWIFIEX_MAX_REGION_CODE         7
+
+#define DEFAULT_BCN_AVG_FACTOR          8
+#define DEFAULT_DATA_AVG_FACTOR         8
+
+#define FIRST_VALID_CHANNEL				0xff
+#define DEFAULT_AD_HOC_CHANNEL			6
+#define DEFAULT_AD_HOC_CHANNEL_A		36
+
+#define DEFAULT_BCN_MISS_TIMEOUT		5
+
+#define MAX_SCAN_BEACON_BUFFER			8000
+
+#define SCAN_BEACON_ENTRY_PAD			6
+
+#define MWIFIEX_PASSIVE_SCAN_CHAN_TIME	200
+#define MWIFIEX_ACTIVE_SCAN_CHAN_TIME	200
+#define MWIFIEX_SPECIFIC_SCAN_CHAN_TIME	110
+
+#define SCAN_RSSI(RSSI)					(0x100 - ((u8)(RSSI)))
+
+#define MWIFIEX_MAX_TOTAL_SCAN_TIME	(MWIFIEX_TIMER_10S - MWIFIEX_TIMER_1S)
+
+#define RSN_GTK_OUI_OFFSET				2
+
+#define MWIFIEX_OUI_NOT_PRESENT			0
+#define MWIFIEX_OUI_PRESENT				1
+
+#define IS_CARD_RX_RCVD(adapter) (adapter->cmd_resp_received || \
+					adapter->event_received || \
+					adapter->data_received)
+
+#define MWIFIEX_TYPE_CMD				1
+#define MWIFIEX_TYPE_DATA				0
+#define MWIFIEX_TYPE_EVENT				3
+
+#define DBG_CMD_NUM						5
+
+#define MAX_BITMAP_RATES_SIZE			10
+
+#define MAX_CHANNEL_BAND_BG     14
+
+#define MAX_FREQUENCY_BAND_BG   2484
+
+struct mwifiex_dbg {
+	u32 num_cmd_host_to_card_failure;
+	u32 num_cmd_sleep_cfm_host_to_card_failure;
+	u32 num_tx_host_to_card_failure;
+	u32 num_event_deauth;
+	u32 num_event_disassoc;
+	u32 num_event_link_lost;
+	u32 num_cmd_deauth;
+	u32 num_cmd_assoc_success;
+	u32 num_cmd_assoc_failure;
+	u32 num_tx_timeout;
+	u32 num_cmd_timeout;
+	u16 timeout_cmd_id;
+	u16 timeout_cmd_act;
+	u16 last_cmd_id[DBG_CMD_NUM];
+	u16 last_cmd_act[DBG_CMD_NUM];
+	u16 last_cmd_index;
+	u16 last_cmd_resp_id[DBG_CMD_NUM];
+	u16 last_cmd_resp_index;
+	u16 last_event[DBG_CMD_NUM];
+	u16 last_event_index;
+};
+
+enum MWIFIEX_HARDWARE_STATUS {
+	MWIFIEX_HW_STATUS_READY,
+	MWIFIEX_HW_STATUS_INITIALIZING,
+	MWIFIEX_HW_STATUS_FW_READY,
+	MWIFIEX_HW_STATUS_INIT_DONE,
+	MWIFIEX_HW_STATUS_RESET,
+	MWIFIEX_HW_STATUS_CLOSING,
+	MWIFIEX_HW_STATUS_NOT_READY
+};
+
+enum MWIFIEX_802_11_POWER_MODE {
+	MWIFIEX_802_11_POWER_MODE_CAM,
+	MWIFIEX_802_11_POWER_MODE_PSP
+};
+
+struct mwifiex_tx_param {
+	u32 next_pkt_len;
+};
+
+enum MWIFIEX_PS_STATE {
+	PS_STATE_AWAKE,
+	PS_STATE_PRE_SLEEP,
+	PS_STATE_SLEEP_CFM,
+	PS_STATE_SLEEP
+};
+
+struct mwifiex_add_ba_param {
+	u32 tx_win_size;
+	u32 rx_win_size;
+	u32 timeout;
+};
+
+struct mwifiex_tx_aggr {
+	u8 ampdu_user;
+	u8 ampdu_ap;
+	u8 amsdu;
+};
+
+struct mwifiex_ra_list_tbl {
+	struct list_head list;
+	struct sk_buff_head skb_head;
+	u8 ra[ETH_ALEN];
+	u32 total_pkts_size;
+	u32 is_11n_enabled;
+};
+
+struct mwifiex_tid_tbl {
+	struct list_head ra_list;
+	/* spin lock for tid table */
+	spinlock_t tid_tbl_lock;
+	struct mwifiex_ra_list_tbl *ra_list_curr;
+};
+
+#define WMM_HIGHEST_PRIORITY		7
+#define HIGH_PRIO_TID				7
+#define LOW_PRIO_TID				0
+
+struct mwifiex_wmm_desc {
+	struct mwifiex_tid_tbl tid_tbl_ptr[MAX_NUM_TID];
+	u32 packets_out[MAX_NUM_TID];
+	/* spin lock to protect ra_list */
+	spinlock_t ra_list_spinlock;
+	struct mwifiex_wmm_ac_status ac_status[IEEE80211_MAX_QUEUES];
+	enum mwifiex_wmm_ac_e ac_down_graded_vals[IEEE80211_MAX_QUEUES];
+	u32 drv_pkt_delay_max;
+	u8 queue_priority[IEEE80211_MAX_QUEUES];
+	u32 user_pri_pkt_tx_ctrl[WMM_HIGHEST_PRIORITY + 1];	/* UP: 0 to 7 */
+
+};
+
+struct mwifiex_802_11_security {
+	u8 wpa_enabled;
+	u8 wpa2_enabled;
+	u8 wapi_enabled;
+	u8 wapi_key_on;
+	enum MWIFIEX_802_11_WEP_STATUS wep_status;
+	u32 authentication_mode;
+	u32 encryption_mode;
+};
+
+struct ieee_types_header {
+	u8 element_id;
+	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)];
+} __packed;
+
+struct ieee_types_generic {
+	struct ieee_types_header ieee_hdr;
+	u8 data[IEEE_MAX_IE_SIZE - sizeof(struct ieee_types_header)];
+} __packed;
+
+struct mwifiex_bssdescriptor {
+	u8 mac_address[ETH_ALEN];
+	struct mwifiex_802_11_ssid ssid;
+	u32 privacy;
+	s32 rssi;
+	u32 channel;
+	u32 freq;
+	u16 beacon_period;
+	u8 erp_flags;
+	u32 bss_mode;
+	u8 supported_rates[MWIFIEX_SUPPORTED_RATES];
+	u8 data_rates[MWIFIEX_SUPPORTED_RATES];
+	/* Network band.
+	 * BAND_B(0x01): 'b' band
+	 * BAND_G(0x02): 'g' band
+	 * BAND_A(0X04): 'a' band
+	 */
+	u16 bss_band;
+	long long network_tsf;
+	u8 time_stamp[8];
+	union ieee_types_phy_param_set phy_param_set;
+	union ieee_types_ss_param_set ss_param_set;
+	u16 cap_info_bitmap;
+	struct ieee_types_wmm_parameter wmm_ie;
+	u8  disable_11n;
+	struct ieee80211_ht_cap *bcn_ht_cap;
+	u16 ht_cap_offset;
+	struct ieee80211_ht_info *bcn_ht_info;
+	u16 ht_info_offset;
+	u8 *bcn_bss_co_2040;
+	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;
+	u16 rsn_offset;
+	struct ieee_types_generic *bcn_wapi_ie;
+	u16 wapi_offset;
+	u8 *beacon_buf;
+	u32 beacon_buf_size;
+	u32 beacon_buf_size_max;
+
+};
+
+struct mwifiex_current_bss_params {
+	struct mwifiex_bssdescriptor bss_descriptor;
+	u8 wmm_enabled;
+	u8 wmm_uapsd_enabled;
+	u8 band;
+	u32 num_of_rates;
+	u8 data_rates[MWIFIEX_SUPPORTED_RATES];
+};
+
+struct mwifiex_sleep_params {
+	u16 sp_error;
+	u16 sp_offset;
+	u16 sp_stable_time;
+	u8 sp_cal_control;
+	u8 sp_ext_sleep_clk;
+	u16 sp_reserved;
+};
+
+struct mwifiex_sleep_period {
+	u16 period;
+	u16 reserved;
+};
+
+struct mwifiex_wep_key {
+	u32 length;
+	u32 key_index;
+	u32 key_length;
+	u8 key_material[MWIFIEX_KEY_BUFFER_SIZE];
+};
+
+#define MAX_REGION_CHANNEL_NUM  2
+
+struct mwifiex_chan_freq_power {
+	u16 channel;
+	u32 freq;
+	u16 max_tx_power;
+	u8 unsupported;
+};
+
+enum state_11d_t {
+	DISABLE_11D = 0,
+	ENABLE_11D = 1,
+};
+
+#define MWIFIEX_MAX_TRIPLET_802_11D		83
+
+struct mwifiex_802_11d_domain_reg {
+	u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
+	u8 no_of_triplet;
+	struct ieee80211_country_ie_triplet
+		triplet[MWIFIEX_MAX_TRIPLET_802_11D];
+};
+
+struct mwifiex_vendor_spec_cfg_ie {
+	u16 mask;
+	u16 flag;
+	u8 ie[MWIFIEX_MAX_VSIE_LEN];
+};
+
+struct wps {
+	u8 session_enable;
+};
+
+struct mwifiex_adapter;
+struct mwifiex_private;
+
+struct mwifiex_private {
+	struct mwifiex_adapter *adapter;
+	u8 bss_index;
+	u8 bss_type;
+	u8 bss_role;
+	u8 bss_priority;
+	u8 bss_num;
+	u8 frame_type;
+	u8 curr_addr[ETH_ALEN];
+	u8 media_connected;
+	u32 num_tx_timeout;
+	struct net_device *netdev;
+	struct net_device_stats stats;
+	u16 curr_pkt_filter;
+	u32 bss_mode;
+	u32 pkt_tx_ctrl;
+	u16 tx_power_level;
+	u8 max_tx_power_level;
+	u8 min_tx_power_level;
+	u8 tx_rate;
+	u8 tx_htinfo;
+	u8 rxpd_htinfo;
+	u8 rxpd_rate;
+	u16 rate_bitmap;
+	u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
+	u32 data_rate;
+	u8 is_data_rate_auto;
+	u16 bcn_avg_factor;
+	u16 data_avg_factor;
+	s16 data_rssi_last;
+	s16 data_nf_last;
+	s16 data_rssi_avg;
+	s16 data_nf_avg;
+	s16 bcn_rssi_last;
+	s16 bcn_nf_last;
+	s16 bcn_rssi_avg;
+	s16 bcn_nf_avg;
+	struct mwifiex_bssdescriptor *attempted_bss_desc;
+	struct mwifiex_802_11_ssid prev_ssid;
+	u8 prev_bssid[ETH_ALEN];
+	struct mwifiex_current_bss_params curr_bss_params;
+	u16 beacon_period;
+	u16 listen_interval;
+	u16 atim_window;
+	u8 adhoc_channel;
+	u8 adhoc_is_link_sensed;
+	u8 adhoc_state;
+	struct mwifiex_802_11_security sec_info;
+	struct mwifiex_wep_key wep_key[NUM_WEP_KEYS];
+	u16 wep_key_curr_index;
+	u8 wpa_ie[256];
+	u8 wpa_ie_len;
+	u8 wpa_is_gtk_set;
+	struct host_cmd_ds_802_11_key_material aes_key;
+	u8 wapi_ie[256];
+	u8 wapi_ie_len;
+	u8 wmm_required;
+	u8 wmm_enabled;
+	u8 wmm_qosinfo;
+	struct mwifiex_wmm_desc wmm;
+	struct list_head tx_ba_stream_tbl_ptr;
+	/* spin lock for tx_ba_stream_tbl_ptr queue */
+	spinlock_t tx_ba_stream_tbl_lock;
+	struct mwifiex_tx_aggr aggr_prio_tbl[MAX_NUM_TID];
+	struct mwifiex_add_ba_param add_ba_param;
+	u16 rx_seq[MAX_NUM_TID];
+	struct list_head rx_reorder_tbl_ptr;
+	/* spin lock for rx_reorder_tbl_ptr queue */
+	spinlock_t rx_reorder_tbl_lock;
+	/* spin lock for Rx packets */
+	spinlock_t rx_pkt_lock;
+
+#define MWIFIEX_ASSOC_RSP_BUF_SIZE  500
+	u8 assoc_rsp_buf[MWIFIEX_ASSOC_RSP_BUF_SIZE];
+	u32 assoc_rsp_size;
+
+#define MWIFIEX_GENIE_BUF_SIZE      256
+	u8 gen_ie_buf[MWIFIEX_GENIE_BUF_SIZE];
+	u8 gen_ie_buf_len;
+
+	struct mwifiex_vendor_spec_cfg_ie vs_ie[MWIFIEX_MAX_VSIE_NUM];
+
+#define MWIFIEX_ASSOC_TLV_BUF_SIZE  256
+	u8 assoc_tlv_buf[MWIFIEX_ASSOC_TLV_BUF_SIZE];
+	u8 assoc_tlv_buf_len;
+
+	u8 *curr_bcn_buf;
+	u32 curr_bcn_size;
+	/* spin lock for beacon buffer */
+	spinlock_t curr_bcn_buf_lock;
+	u16 ioctl_wait_q_woken;
+	wait_queue_head_t ioctl_wait_q;
+	u16 cmd_wait_q_woken;
+	wait_queue_head_t cmd_wait_q;
+	struct wireless_dev *wdev;
+	struct mwifiex_chan_freq_power cfp;
+	char version_str[128];
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dfs_dev_dir;
+#endif
+	u8 nick_name[16];
+	struct iw_statistics w_stats;
+	u16 w_stats_wait_q_woken;
+	wait_queue_head_t w_stats_wait_q;
+	u16 current_key_index;
+	struct semaphore async_sem;
+	u8 scan_pending_on_block;
+	u8 report_scan_result;
+	struct cfg80211_scan_request *scan_request;
+	int scan_result_status;
+	bool assoc_request;
+	u16 assoc_result;
+	bool ibss_join_request;
+	u16 ibss_join_result;
+	bool disconnect;
+	u8 cfg_bssid[6];
+	struct workqueue_struct *workqueue;
+	struct work_struct cfg_workqueue;
+	u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
+	struct wps wps;
+	u8 scan_block;
+};
+
+enum mwifiex_ba_status {
+	BA_STREAM_NOT_SETUP = 0,
+	BA_STREAM_SETUP_INPROGRESS,
+	BA_STREAM_SETUP_COMPLETE
+};
+
+struct mwifiex_tx_ba_stream_tbl {
+	struct list_head list;
+	int tid;
+	u8 ra[ETH_ALEN];
+	enum mwifiex_ba_status ba_status;
+};
+
+struct mwifiex_rx_reorder_tbl;
+
+struct reorder_tmr_cnxt {
+	struct timer_list timer;
+	struct mwifiex_rx_reorder_tbl *ptr;
+	struct mwifiex_private *priv;
+};
+
+struct mwifiex_rx_reorder_tbl {
+	struct list_head list;
+	int tid;
+	u8 ta[ETH_ALEN];
+	int start_win;
+	int win_size;
+	void **rx_reorder_ptr;
+	struct reorder_tmr_cnxt timer_context;
+};
+
+struct mwifiex_bss_prio_node {
+	struct list_head list;
+	struct mwifiex_private *priv;
+};
+
+struct mwifiex_bss_prio_tbl {
+	struct list_head bss_prio_head;
+	/* spin lock for bss priority  */
+	spinlock_t bss_prio_lock;
+	struct mwifiex_bss_prio_node *bss_prio_cur;
+};
+
+struct cmd_ctrl_node {
+	struct list_head list;
+	struct mwifiex_private *priv;
+	u32 cmd_oid;
+	u32 cmd_flag;
+	struct sk_buff *cmd_skb;
+	struct sk_buff *resp_skb;
+	void *data_buf;
+	void *wq_buf;
+	struct sk_buff *skb;
+};
+
+struct mwifiex_if_ops {
+	int (*init_if) (struct mwifiex_adapter *);
+	void (*cleanup_if) (struct mwifiex_adapter *);
+	int (*check_fw_status) (struct mwifiex_adapter *, u32, int *);
+	int (*prog_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *);
+	int (*register_dev) (struct mwifiex_adapter *);
+	void (*unregister_dev) (struct mwifiex_adapter *);
+	int (*enable_int) (struct mwifiex_adapter *);
+	int (*process_int_status) (struct mwifiex_adapter *);
+	int (*host_to_card) (struct mwifiex_adapter *, u8,
+			     u8 *payload, u32 pkt_len,
+			     struct mwifiex_tx_param *);
+	int (*wakeup) (struct mwifiex_adapter *);
+	int (*wakeup_complete) (struct mwifiex_adapter *);
+
+	void (*update_mp_end_port) (struct mwifiex_adapter *, u16);
+	void (*cleanup_mpa_buf) (struct mwifiex_adapter *);
+};
+
+struct mwifiex_adapter {
+	struct mwifiex_private *priv[MWIFIEX_MAX_BSS_NUM];
+	u8 priv_num;
+	struct mwifiex_drv_mode *drv_mode;
+	const struct firmware *firmware;
+	struct device *dev;
+	bool surprise_removed;
+	u32 fw_release_number;
+	u32 revision_id;
+	u16 init_wait_q_woken;
+	wait_queue_head_t init_wait_q;
+	void *card;
+	struct mwifiex_if_ops if_ops;
+	atomic_t rx_pending;
+	atomic_t tx_pending;
+	atomic_t ioctl_pending;
+	struct workqueue_struct *workqueue;
+	struct work_struct main_work;
+	struct mwifiex_bss_prio_tbl bss_prio_tbl[MWIFIEX_MAX_BSS_NUM];
+	/* spin lock for init/shutdown */
+	spinlock_t mwifiex_lock;
+	/* spin lock for main process */
+	spinlock_t main_proc_lock;
+	u32 mwifiex_processing;
+	u16 max_tx_buf_size;
+	u16 tx_buf_size;
+	u16 curr_tx_buf_size;
+	u32 ioport;
+	enum MWIFIEX_HARDWARE_STATUS hw_status;
+	u16 number_of_antenna;
+	u32 fw_cap_info;
+	/* spin lock for interrupt handling */
+	spinlock_t int_lock;
+	u8 int_status;
+	u32 event_cause;
+	struct sk_buff *event_skb;
+	u8 upld_buf[MWIFIEX_UPLD_SIZE];
+	u8 data_sent;
+	u8 cmd_sent;
+	u8 cmd_resp_received;
+	u8 event_received;
+	u8 data_received;
+	u16 seq_num;
+	struct cmd_ctrl_node *cmd_pool;
+	struct cmd_ctrl_node *curr_cmd;
+	/* spin lock for command */
+	spinlock_t mwifiex_cmd_lock;
+	u32 num_cmd_timeout;
+	u16 last_init_cmd;
+	struct timer_list cmd_timer;
+	struct list_head cmd_free_q;
+	/* spin lock for cmd_free_q */
+	spinlock_t cmd_free_q_lock;
+	struct list_head cmd_pending_q;
+	/* spin lock for cmd_pending_q */
+	spinlock_t cmd_pending_q_lock;
+	struct list_head scan_pending_q;
+	/* spin lock for scan_pending_q */
+	spinlock_t scan_pending_q_lock;
+	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;
+	struct mwifiex_chan_scan_param_set *scan_channels;
+	u8 tx_lock_flag;
+	struct mwifiex_sleep_params sleep_params;
+	struct mwifiex_sleep_period sleep_period;
+	u16 ps_mode;
+	u32 ps_state;
+	u8 need_to_wakeup;
+	u16 multiple_dtim;
+	u16 local_listen_interval;
+	u16 null_pkt_interval;
+	struct sk_buff *sleep_cfm;
+	u16 bcn_miss_time_out;
+	u16 adhoc_awake_period;
+	u8 is_deep_sleep;
+	u8 delay_null_pkt;
+	u16 delay_to_ps;
+	u16 enhanced_ps_mode;
+	u8 pm_wakeup_card_req;
+	u16 gen_null_pkt;
+	u16 pps_uapsd_mode;
+	u32 pm_wakeup_fw_try;
+	u8 is_hs_configured;
+	struct mwifiex_hs_config_param hs_cfg;
+	u8 hs_activated;
+	u16 hs_activate_wait_q_woken;
+	wait_queue_head_t hs_activate_wait_q;
+	bool is_suspended;
+	u8 event_body[MAX_EVENT_SIZE];
+	u32 hw_dot_11n_dev_cap;
+	u8 hw_dev_mcs_support;
+	u8 adhoc_11n_enabled;
+	u8 chan_offset;
+	struct mwifiex_dbg dbg;
+	u8 arp_filter[ARP_FILTER_MAX_BUF_SIZE];
+	u32 arp_filter_size;
+};
+
+int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
+void mwifiex_free_lock_list(struct mwifiex_adapter *adapter);
+
+int mwifiex_init_fw(struct mwifiex_adapter *adapter);
+
+int mwifiex_init_fw_complete(struct mwifiex_adapter *adapter);
+
+int mwifiex_shutdown_drv(struct mwifiex_adapter *adapter);
+
+int mwifiex_shutdown_fw_complete(struct mwifiex_adapter *adapter);
+
+int mwifiex_dnld_fw(struct mwifiex_adapter *, struct mwifiex_fw_image *);
+
+int mwifiex_recv_complete(struct mwifiex_adapter *,
+			  struct sk_buff *skb,
+			  int status);
+
+int mwifiex_recv_packet(struct mwifiex_adapter *, struct sk_buff *skb);
+
+int mwifiex_process_event(struct mwifiex_adapter *adapter);
+
+int mwifiex_ioctl_complete(struct mwifiex_adapter *adapter,
+			   struct mwifiex_wait_queue *ioctl_wq,
+			   int status);
+
+int mwifiex_prepare_cmd(struct mwifiex_private *priv,
+			uint16_t cmd_no,
+			u16 cmd_action,
+			u32 cmd_oid,
+			void *wait_queue, void *data_buf);
+
+void mwifiex_cmd_timeout_func(unsigned long function_context);
+
+int mwifiex_misc_ioctl_init_shutdown(struct mwifiex_adapter *adapter,
+				     struct mwifiex_wait_queue *wait_queue,
+				     u32 func_init_shutdown);
+int mwifiex_get_debug_info(struct mwifiex_private *,
+			   struct mwifiex_debug_info *);
+
+int mwifiex_alloc_cmd_buffer(struct mwifiex_adapter *adapter);
+int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter);
+void mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter);
+void mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter,
+				  struct mwifiex_wait_queue *ioctl_wq);
+
+void mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter,
+				  struct cmd_ctrl_node *cmd_node);
+
+void mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter,
+				     struct cmd_ctrl_node *cmd_node,
+				     u32 addtail);
+
+int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter);
+int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter);
+int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter,
+			     struct sk_buff *skb);
+int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
+		       struct mwifiex_tx_param *tx_param);
+int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags);
+int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
+				struct sk_buff *skb, int status);
+int mwifiex_recv_packet_complete(struct mwifiex_adapter *,
+				 struct sk_buff *skb, int status);
+void mwifiex_clean_txrx(struct mwifiex_private *priv);
+u8 mwifiex_check_last_packet_indication(struct mwifiex_private *priv);
+void mwifiex_check_ps_cond(struct mwifiex_adapter *adapter);
+void mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *, u8 *,
+					u32);
+int mwifiex_cmd_enh_power_mode(struct mwifiex_private *priv,
+			       struct host_cmd_ds_command *cmd,
+			       u16 cmd_action, uint16_t ps_bitmap,
+			       void *data_buf);
+int mwifiex_ret_enh_power_mode(struct mwifiex_private *priv,
+			       struct host_cmd_ds_command *resp,
+			       void *data_buf);
+void mwifiex_process_hs_config(struct mwifiex_adapter *adapter);
+void mwifiex_hs_activated_event(struct mwifiex_private *priv,
+					u8 activated);
+int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv,
+			      struct host_cmd_ds_command *resp);
+int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter,
+			      struct sk_buff *skb);
+int mwifiex_sta_prepare_cmd(struct mwifiex_private *, uint16_t cmd_no,
+			    u16 cmd_action, u32 cmd_oid,
+			    void *data_buf, void *cmd_buf);
+int mwifiex_process_sta_cmdresp(struct mwifiex_private *, u16 cmdresp_no,
+				void *cmd_buf, void *ioctl);
+int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *,
+				  struct sk_buff *skb);
+int mwifiex_process_sta_event(struct mwifiex_private *);
+void *mwifiex_process_sta_txpd(struct mwifiex_private *, struct sk_buff *skb);
+int mwifiex_sta_init_cmd(struct mwifiex_private *, u8 first_sta);
+int mwifiex_scan_networks(struct mwifiex_private *priv, void *wait_queue,
+			  u16 action,
+			  const struct mwifiex_user_scan_cfg
+			  *user_scan_in, struct mwifiex_scan_resp *);
+int mwifiex_cmd_802_11_scan(struct mwifiex_private *priv,
+			    struct host_cmd_ds_command *cmd,
+			    void *data_buf);
+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,
+			    void *wait_queue);
+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, void *wait_queue,
+		      struct mwifiex_bssdescriptor *bss_desc);
+int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
+				 struct host_cmd_ds_command
+				 *cmd, void *data_buf);
+int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
+				 struct host_cmd_ds_command *resp,
+				 void *wait_queue);
+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,
+			   struct mwifiex_wait_queue *wait_queue,
+			   u8 *mac);
+int mwifiex_adhoc_start(struct mwifiex_private *priv, void *wait_queue,
+			struct mwifiex_802_11_ssid *adhoc_ssid);
+int mwifiex_adhoc_join(struct mwifiex_private *priv, void *wait_queue,
+		       struct mwifiex_bssdescriptor *bss_desc);
+int mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
+				    struct host_cmd_ds_command *cmd,
+				    void *data_buf);
+int mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv,
+				   struct host_cmd_ds_command *cmd,
+				   void *data_buf);
+int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv,
+			      struct host_cmd_ds_command *resp,
+			      void *wait_queue);
+int mwifiex_cmd_802_11_bg_scan_query(struct mwifiex_private *priv,
+				     struct host_cmd_ds_command *cmd,
+				     void *data_buf);
+struct mwifiex_chan_freq_power *
+			mwifiex_get_cfp_by_band_and_channel_from_cfg80211(
+						struct mwifiex_private *priv,
+						u8 band, u16 channel);
+struct mwifiex_chan_freq_power *mwifiex_get_cfp_by_band_and_freq_from_cfg80211(
+						struct mwifiex_private *priv,
+						u8 band, u32 freq);
+u32 mwifiex_index_to_data_rate(struct mwifiex_adapter *adapter, u8 index,
+				 u8 ht_info);
+u32 mwifiex_find_freq_from_band_chan(u8, u8);
+int mwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv, u16 vsie_mask,
+				u8 **buffer);
+u32 mwifiex_index_to_data_rate(struct mwifiex_adapter *adapter, u8 index,
+				 u8 ht_info);
+u32 mwifiex_get_active_data_rates(struct mwifiex_private *priv,
+				    u8 *rates);
+u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates);
+u8 mwifiex_data_rate_to_index(struct mwifiex_adapter *adapter, u32 rate);
+u8 mwifiex_is_rate_auto(struct mwifiex_private *priv);
+int mwifiex_get_rate_index(struct mwifiex_adapter *adapter,
+			   u16 *rateBitmap, int size);
+extern u16 region_code_index[MWIFIEX_MAX_REGION_CODE];
+void mwifiex_save_curr_bcn(struct mwifiex_private *priv);
+void mwifiex_free_curr_bcn(struct mwifiex_private *priv);
+int mwifiex_cmd_get_hw_spec(struct mwifiex_private *priv,
+			    struct host_cmd_ds_command *cmd);
+int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
+			    struct host_cmd_ds_command *resp);
+int is_command_pending(struct mwifiex_adapter *adapter);
+
+/*
+ * This function checks if the queuing is RA based or not.
+ */
+static inline u8
+mwifiex_queuing_ra_based(struct mwifiex_private *priv)
+{
+	/*
+	 * Currently we assume if we are in Infra, then DA=RA. This might not be
+	 * true in the future
+	 */
+	if ((priv->bss_mode == NL80211_IFTYPE_STATION) &&
+	    (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA))
+		return false;
+
+	return true;
+}
+
+/*
+ * This function copies rates.
+ */
+static inline u32
+mwifiex_copy_rates(u8 *dest, u32 pos, u8 *src, int len)
+{
+	int i;
+
+	for (i = 0; i < len && src[i]; i++, pos++) {
+		if (pos >= MWIFIEX_SUPPORTED_RATES)
+			break;
+		dest[pos] = src[i];
+	}
+
+	return pos;
+}
+
+/*
+ * This function returns the correct private structure pointer based
+ * upon the BSS type and BSS number.
+ */
+static inline struct mwifiex_private *
+mwifiex_get_priv_by_id(struct mwifiex_adapter *adapter,
+		       u32 bss_num, u32 bss_type)
+{
+	int i;
+
+	for (i = 0; i < adapter->priv_num; i++) {
+		if (adapter->priv[i]) {
+			if ((adapter->priv[i]->bss_num == bss_num)
+			    && (adapter->priv[i]->bss_type == bss_type))
+				break;
+		}
+	}
+	return ((i < adapter->priv_num) ? adapter->priv[i] : NULL);
+}
+
+/*
+ * This function returns the first available private structure pointer
+ * based upon the BSS role.
+ */
+static inline struct mwifiex_private *
+mwifiex_get_priv(struct mwifiex_adapter *adapter,
+		 enum mwifiex_bss_role bss_role)
+{
+	int i;
+
+	for (i = 0; i < adapter->priv_num; i++) {
+		if (adapter->priv[i]) {
+			if (bss_role == MWIFIEX_BSS_ROLE_ANY ||
+			    GET_BSS_ROLE(adapter->priv[i]) == bss_role)
+				break;
+		}
+	}
+
+	return ((i < adapter->priv_num) ? adapter->priv[i] : NULL);
+}
+
+/*
+ * This function returns the driver private structure of a network device.
+ */
+static inline struct mwifiex_private *
+mwifiex_netdev_get_priv(struct net_device *dev)
+{
+	return (struct mwifiex_private *) (*(unsigned long *) netdev_priv(dev));
+}
+
+struct mwifiex_wait_queue *mwifiex_alloc_fill_wait_queue(
+				struct mwifiex_private *,
+				u8 wait_option);
+struct mwifiex_private *mwifiex_bss_index_to_priv(struct mwifiex_adapter
+						*adapter, u8 bss_index);
+int mwifiex_shutdown_fw(struct mwifiex_private *, u8);
+
+int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *);
+int mwifiex_remove_card(struct mwifiex_adapter *, struct semaphore *);
+
+void mwifiex_get_version(struct mwifiex_adapter *adapter, char *version,
+			 int maxlen);
+int mwifiex_request_set_mac_address(struct mwifiex_private *priv);
+void mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
+					struct net_device *dev);
+int mwifiex_request_ioctl(struct mwifiex_private *priv,
+			  struct mwifiex_wait_queue *req,
+			  int, u8 wait_option);
+int mwifiex_disconnect(struct mwifiex_private *, u8, u8 *);
+int mwifiex_bss_start(struct mwifiex_private *priv,
+		      u8 wait_option,
+		      struct mwifiex_ssid_bssid *ssid_bssid);
+int mwifiex_set_hs_params(struct mwifiex_private *priv,
+			      u16 action, u8 wait_option,
+			      struct mwifiex_ds_hs_cfg *hscfg);
+int mwifiex_cancel_hs(struct mwifiex_private *priv, u8 wait_option);
+int mwifiex_enable_hs(struct mwifiex_adapter *adapter);
+void mwifiex_process_ioctl_resp(struct mwifiex_private *priv,
+				struct mwifiex_wait_queue *req);
+u32 mwifiex_get_mode(struct mwifiex_private *priv, u8 wait_option);
+int mwifiex_get_signal_info(struct mwifiex_private *priv,
+			    u8 wait_option,
+			    struct mwifiex_ds_get_signal *signal);
+int mwifiex_drv_get_data_rate(struct mwifiex_private *priv,
+			      struct mwifiex_rate_cfg *rate);
+int mwifiex_get_channel_list(struct mwifiex_private *priv,
+			     u8 wait_option,
+			     struct mwifiex_chan_list *chanlist);
+int mwifiex_get_scan_table(struct mwifiex_private *priv,
+			   u8 wait_option,
+			   struct mwifiex_scan_resp *scanresp);
+int mwifiex_enable_wep_key(struct mwifiex_private *priv, u8 wait_option);
+int mwifiex_find_best_bss(struct mwifiex_private *priv, u8 wait_option,
+			  struct mwifiex_ssid_bssid *ssid_bssid);
+int mwifiex_request_scan(struct mwifiex_private *priv,
+			 u8 wait_option,
+			 struct mwifiex_802_11_ssid *req_ssid);
+int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv,
+				struct mwifiex_user_scan_cfg *scan_req);
+int mwifiex_change_adhoc_chan(struct mwifiex_private *priv, int channel);
+int mwifiex_set_radio(struct mwifiex_private *priv, u8 option);
+
+int mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel);
+
+int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key,
+		       int key_len, u8 key_index, int disable);
+
+int mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len);
+
+int mwifiex_get_ver_ext(struct mwifiex_private *priv);
+
+int mwifiex_get_stats_info(struct mwifiex_private *priv,
+			   struct mwifiex_ds_get_stats *log);
+
+int mwifiex_reg_write(struct mwifiex_private *priv, u32 reg_type,
+		      u32 reg_offset, u32 reg_value);
+
+int mwifiex_reg_read(struct mwifiex_private *priv, u32 reg_type,
+		     u32 reg_offset, u32 *value);
+
+int mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes,
+			u8 *value);
+
+int mwifiex_set_11n_httx_cfg(struct mwifiex_private *priv, int data);
+
+int mwifiex_get_11n_httx_cfg(struct mwifiex_private *priv, int *data);
+
+int mwifiex_set_tx_rate_cfg(struct mwifiex_private *priv, int tx_rate_index);
+
+int mwifiex_get_tx_rate_cfg(struct mwifiex_private *priv, int *tx_rate_index);
+
+int mwifiex_drv_set_power(struct mwifiex_private *priv, bool power_on);
+
+int mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter,
+				   char *version, int max_len);
+
+int mwifiex_set_tx_power(struct mwifiex_private *priv, int type, int dbm);
+
+int mwifiex_main_process(struct mwifiex_adapter *);
+
+int mwifiex_bss_ioctl_channel(struct mwifiex_private *,
+			      u16 action,
+			      struct mwifiex_chan_freq_power *cfp);
+int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *,
+			       struct mwifiex_wait_queue *,
+			       struct mwifiex_ssid_bssid *);
+int mwifiex_radio_ioctl_band_cfg(struct mwifiex_private *,
+				 u16 action,
+				 struct mwifiex_ds_band_cfg *);
+int mwifiex_snmp_mib_ioctl(struct mwifiex_private *,
+			   struct mwifiex_wait_queue *,
+			   u32 cmd_oid, u16 action, u32 *value);
+int mwifiex_get_bss_info(struct mwifiex_private *,
+			 struct mwifiex_bss_info *);
+
+#ifdef CONFIG_DEBUG_FS
+void mwifiex_debugfs_init(void);
+void mwifiex_debugfs_remove(void);
+
+void mwifiex_dev_debugfs_init(struct mwifiex_private *priv);
+void mwifiex_dev_debugfs_remove(struct mwifiex_private *priv);
+#endif
+#endif /* !_MWIFIEX_MAIN_H_ */
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
new file mode 100644
index 0000000..6bb52d0
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -0,0 +1,3097 @@
+/*
+ * Marvell Wireless LAN device driver: scan ioctl and command handling
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "11n.h"
+#include "cfg80211.h"
+
+/* The maximum number of channels the firmware can scan per command */
+#define MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN   14
+
+#define MWIFIEX_CHANNELS_PER_SCAN_CMD            4
+
+/* Memory needed to store a max sized Channel List TLV for a firmware scan */
+#define CHAN_TLV_MAX_SIZE  (sizeof(struct mwifiex_ie_types_header)         \
+				+ (MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN     \
+				*sizeof(struct mwifiex_chan_scan_param_set)))
+
+/* Memory needed to store supported rate */
+#define RATE_TLV_MAX_SIZE   (sizeof(struct mwifiex_ie_types_rates_param_set) \
+				+ HOSTCMD_SUPPORTED_RATES)
+
+/* Memory needed to store a max number/size WildCard SSID TLV for a firmware
+	scan */
+#define WILDCARD_SSID_TLV_MAX_SIZE  \
+	(MWIFIEX_MAX_SSID_LIST_LENGTH *					\
+		(sizeof(struct mwifiex_ie_types_wildcard_ssid_params)	\
+			+ IEEE80211_MAX_SSID_LEN))
+
+/* Maximum memory needed for a mwifiex_scan_cmd_config with all TLVs at max */
+#define MAX_SCAN_CFG_ALLOC (sizeof(struct mwifiex_scan_cmd_config)        \
+				+ sizeof(struct mwifiex_ie_types_num_probes)   \
+				+ sizeof(struct mwifiex_ie_types_htcap)       \
+				+ CHAN_TLV_MAX_SIZE                 \
+				+ RATE_TLV_MAX_SIZE                 \
+				+ WILDCARD_SSID_TLV_MAX_SIZE)
+
+
+union mwifiex_scan_cmd_config_tlv {
+	/* Scan configuration (variable length) */
+	struct mwifiex_scan_cmd_config config;
+	/* Max allocated block */
+	u8 config_alloc_buf[MAX_SCAN_CFG_ALLOC];
+};
+
+enum cipher_suite {
+	CIPHER_SUITE_TKIP,
+	CIPHER_SUITE_CCMP,
+	CIPHER_SUITE_MAX
+};
+static u8 mwifiex_wpa_oui[CIPHER_SUITE_MAX][4] = {
+	{ 0x00, 0x50, 0xf2, 0x02 },	/* TKIP */
+	{ 0x00, 0x50, 0xf2, 0x04 },	/* AES  */
+};
+static u8 mwifiex_rsn_oui[CIPHER_SUITE_MAX][4] = {
+	{ 0x00, 0x0f, 0xac, 0x02 },	/* TKIP */
+	{ 0x00, 0x0f, 0xac, 0x04 },	/* AES  */
+};
+
+/*
+ * This function parses a given IE for a given OUI.
+ *
+ * This is used to parse a WPA/RSN IE to find if it has
+ * a given oui in PTK.
+ */
+static u8
+mwifiex_search_oui_in_ie(struct ie_body *iebody, u8 *oui)
+{
+	u8 count;
+
+	count = iebody->ptk_cnt[0];
+
+	/* There could be multiple OUIs for PTK hence
+	   1) Take the length.
+	   2) Check all the OUIs for AES.
+	   3) If one of them is AES then pass success. */
+	while (count) {
+		if (!memcmp(iebody->ptk_body, oui, sizeof(iebody->ptk_body)))
+			return MWIFIEX_OUI_PRESENT;
+
+		--count;
+		if (count)
+			iebody = (struct ie_body *) ((u8 *) iebody +
+						sizeof(iebody->ptk_body));
+	}
+
+	pr_debug("info: %s: OUI is not found in PTK\n", __func__);
+	return MWIFIEX_OUI_NOT_PRESENT;
+}
+
+/*
+ * This function checks if a given OUI is present in a RSN IE.
+ *
+ * The function first checks if a RSN IE is present or not in the
+ * BSS descriptor. It tries to locate the OUI only if such an IE is
+ * present.
+ */
+static u8
+mwifiex_is_rsn_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher)
+{
+	u8 *oui = NULL;
+	struct ie_body *iebody = NULL;
+	u8 ret = MWIFIEX_OUI_NOT_PRESENT;
+
+	if (((bss_desc->bcn_rsn_ie) && ((*(bss_desc->bcn_rsn_ie)).
+					ieee_hdr.element_id == WLAN_EID_RSN))) {
+		iebody = (struct ie_body *)
+			 (((u8 *) bss_desc->bcn_rsn_ie->data) +
+			 RSN_GTK_OUI_OFFSET);
+		oui = &mwifiex_rsn_oui[cipher][0];
+		ret = mwifiex_search_oui_in_ie(iebody, oui);
+		if (ret)
+			return ret;
+	}
+	return ret;
+}
+
+/*
+ * This function checks if a given OUI is present in a WPA IE.
+ *
+ * The function first checks if a WPA IE is present or not in the
+ * BSS descriptor. It tries to locate the OUI only if such an IE is
+ * present.
+ */
+static u8
+mwifiex_is_wpa_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher)
+{
+	u8 *oui = NULL;
+	struct ie_body *iebody = NULL;
+	u8 ret = MWIFIEX_OUI_NOT_PRESENT;
+
+	if (((bss_desc->bcn_wpa_ie) && ((*(bss_desc->bcn_wpa_ie)).
+				      vend_hdr.element_id == WLAN_EID_WPA))) {
+		iebody = (struct ie_body *) bss_desc->bcn_wpa_ie->data;
+		oui = &mwifiex_wpa_oui[cipher][0];
+		ret = mwifiex_search_oui_in_ie(iebody, oui);
+		if (ret)
+			return ret;
+	}
+	return ret;
+}
+
+/*
+ * This function compares two SSIDs and checks if they match.
+ */
+s32
+mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1,
+		 struct mwifiex_802_11_ssid *ssid2)
+{
+	if (!ssid1 || !ssid2 || (ssid1->ssid_len != ssid2->ssid_len))
+		return -1;
+	return memcmp(ssid1->ssid, ssid2->ssid, ssid1->ssid_len);
+}
+
+/*
+ * 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,
+			  u8 wait_option, struct mwifiex_ssid_bssid *ssid_bssid)
+{
+	struct mwifiex_wait_queue *wait = NULL;
+	struct mwifiex_ssid_bssid tmp_ssid_bssid;
+	int ret = 0;
+	u8 *mac = NULL;
+
+	if (!ssid_bssid)
+		return -1;
+
+	/* Allocate wait request buffer */
+	wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
+	if (!wait)
+		return -ENOMEM;
+
+	memcpy(&tmp_ssid_bssid, ssid_bssid,
+	       sizeof(struct mwifiex_ssid_bssid));
+	ret = mwifiex_bss_ioctl_find_bss(priv, wait, &tmp_ssid_bssid);
+
+	if (!ret) {
+		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);
+	}
+
+	kfree(wait);
+	return ret;
+}
+
+/*
+ * Sends IOCTL request to start a scan with user configurations.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ *
+ * Upon completion, it also generates a wireless event to notify
+ * applications.
+ */
+int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv,
+				struct mwifiex_user_scan_cfg *scan_req)
+{
+	struct mwifiex_wait_queue *wait = NULL;
+	int status = 0;
+	u8 wait_option = MWIFIEX_IOCTL_WAIT;
+
+	/* Allocate an IOCTL request buffer */
+	wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
+	if (!wait)
+		return -ENOMEM;
+
+	status = mwifiex_scan_networks(priv, wait, HostCmd_ACT_GEN_SET,
+				       scan_req, NULL);
+
+	status = mwifiex_request_ioctl(priv, wait, status, wait_option);
+
+	if (wait && (status != -EINPROGRESS))
+		kfree(wait);
+	return status;
+}
+
+/*
+ * This function checks if wapi is enabled in driver and scanned network is
+ * compatible with it.
+ */
+static bool
+mwifiex_is_network_compatible_for_wapi(struct mwifiex_private *priv,
+				       struct mwifiex_bssdescriptor *bss_desc)
+{
+	if (priv->sec_info.wapi_enabled &&
+	    (bss_desc->bcn_wapi_ie &&
+	     ((*(bss_desc->bcn_wapi_ie)).ieee_hdr.element_id ==
+			WLAN_EID_BSS_AC_ACCESS_DELAY))) {
+		return true;
+	}
+	return false;
+}
+
+/*
+ * This function checks if driver is configured with no security mode and
+ * scanned network is compatible with it.
+ */
+static bool
+mwifiex_is_network_compatible_for_no_sec(struct mwifiex_private *priv,
+				       struct mwifiex_bssdescriptor *bss_desc)
+{
+	if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
+	    && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
+	    && ((!bss_desc->bcn_wpa_ie) ||
+		((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id !=
+	    WLAN_EID_WPA))
+	    && ((!bss_desc->bcn_rsn_ie) ||
+		((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id !=
+	    WLAN_EID_RSN))
+	    && !priv->sec_info.encryption_mode
+	    && !bss_desc->privacy) {
+		return true;
+	}
+	return false;
+}
+
+/*
+ * This function checks if static WEP is enabled in driver and scanned network
+ * is compatible with it.
+ */
+static bool
+mwifiex_is_network_compatible_for_static_wep(struct mwifiex_private *priv,
+				       struct mwifiex_bssdescriptor *bss_desc)
+{
+	if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED
+	    && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
+	    && bss_desc->privacy) {
+		return true;
+	}
+	return false;
+}
+
+/*
+ * This function checks if wpa is enabled in driver and scanned network is
+ * compatible with it.
+ */
+static bool
+mwifiex_is_network_compatible_for_wpa(struct mwifiex_private *priv,
+				      struct mwifiex_bssdescriptor *bss_desc,
+				      int index)
+{
+	if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
+	    && priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
+	    && ((bss_desc->bcn_wpa_ie) && ((*(bss_desc->bcn_wpa_ie)).vend_hdr.
+						element_id == WLAN_EID_WPA))
+	   /*
+	    * Privacy bit may NOT be set in some APs like
+	    * LinkSys WRT54G && bss_desc->privacy
+	    */
+	 ) {
+		dev_dbg(priv->adapter->dev, "info: %s: WPA: index=%d"
+			" wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s "
+			"EncMode=%#x privacy=%#x\n", __func__, index,
+			(bss_desc->bcn_wpa_ie) ?
+			(*(bss_desc->bcn_wpa_ie)).
+			vend_hdr.element_id : 0,
+			(bss_desc->bcn_rsn_ie) ?
+			(*(bss_desc->bcn_rsn_ie)).
+			ieee_hdr.element_id : 0,
+			(priv->sec_info.wep_status ==
+			MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d",
+			(priv->sec_info.wpa_enabled) ? "e" : "d",
+			(priv->sec_info.wpa2_enabled) ? "e" : "d",
+			priv->sec_info.encryption_mode,
+			bss_desc->privacy);
+		return true;
+	}
+	return false;
+}
+
+/*
+ * This function checks if wpa2 is enabled in driver and scanned network is
+ * compatible with it.
+ */
+static bool
+mwifiex_is_network_compatible_for_wpa2(struct mwifiex_private *priv,
+				       struct mwifiex_bssdescriptor *bss_desc,
+				       int index)
+{
+	if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
+	   && !priv->sec_info.wpa_enabled && priv->sec_info.wpa2_enabled
+	   && ((bss_desc->bcn_rsn_ie) && ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.
+						element_id == WLAN_EID_RSN))
+	   /*
+	    * Privacy bit may NOT be set in some APs like
+	    * LinkSys WRT54G && bss_desc->privacy
+	    */
+	 ) {
+		dev_dbg(priv->adapter->dev, "info: %s: WPA2: index=%d"
+			" wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s "
+			"EncMode=%#x privacy=%#x\n", __func__, index,
+			(bss_desc->bcn_wpa_ie) ?
+			(*(bss_desc->bcn_wpa_ie)).
+			vend_hdr.element_id : 0,
+			(bss_desc->bcn_rsn_ie) ?
+			(*(bss_desc->bcn_rsn_ie)).
+			ieee_hdr.element_id : 0,
+			(priv->sec_info.wep_status ==
+			MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d",
+			(priv->sec_info.wpa_enabled) ? "e" : "d",
+			(priv->sec_info.wpa2_enabled) ? "e" : "d",
+			priv->sec_info.encryption_mode,
+			bss_desc->privacy);
+		return true;
+	}
+	return false;
+}
+
+/*
+ * This function checks if adhoc AES is enabled in driver and scanned network is
+ * compatible with it.
+ */
+static bool
+mwifiex_is_network_compatible_for_adhoc_aes(struct mwifiex_private *priv,
+				       struct mwifiex_bssdescriptor *bss_desc)
+{
+	if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
+	    && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
+	    && ((!bss_desc->bcn_wpa_ie) || ((*(bss_desc->bcn_wpa_ie)).vend_hdr.
+		   element_id != WLAN_EID_WPA))
+	    && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.
+		   element_id != WLAN_EID_RSN))
+	    && !priv->sec_info.encryption_mode
+	    && bss_desc->privacy) {
+		return true;
+	}
+	return false;
+}
+
+/*
+ * This function checks if dynamic WEP is enabled in driver and scanned network
+ * is compatible with it.
+ */
+static bool
+mwifiex_is_network_compatible_for_dynamic_wep(struct mwifiex_private *priv,
+				       struct mwifiex_bssdescriptor *bss_desc,
+				       int index)
+{
+	if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
+	    && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
+	    && ((!bss_desc->bcn_wpa_ie) || ((*(bss_desc->bcn_wpa_ie)).vend_hdr.
+		   element_id != WLAN_EID_WPA))
+	    && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.
+		   element_id != WLAN_EID_RSN))
+	    && 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 "
+			"EncMode=%#x privacy=%#x\n",
+			__func__, index,
+			(bss_desc->bcn_wpa_ie) ?
+			(*(bss_desc->bcn_wpa_ie)).
+			vend_hdr.element_id : 0,
+			(bss_desc->bcn_rsn_ie) ?
+			(*(bss_desc->bcn_rsn_ie)).
+			ieee_hdr.element_id : 0,
+			priv->sec_info.encryption_mode,
+			bss_desc->privacy);
+		return true;
+	}
+	return false;
+}
+
+/*
+ * This function checks if a scanned network is compatible with the driver
+ * settings.
+ *
+ *   WEP     WPA    WPA2   ad-hoc encrypt                  Network
+ * enabled enabled enabled  AES    mode   Privacy WPA WPA2 Compatible
+ *    0       0       0      0     NONE      0     0   0   yes No security
+ *    0       1       0      0      x        1x    1   x   yes WPA (disable
+ *                                                         HT if no AES)
+ *    0       0       1      0      x        1x    x   1   yes WPA2 (disable
+ *                                                         HT if no AES)
+ *    0       0       0      1     NONE      1     0   0   yes Ad-hoc AES
+ *    1       0       0      0     NONE      1     0   0   yes Static WEP
+ *                                                         (disable HT)
+ *    0       0       0      0    !=NONE     1     0   0   yes Dynamic WEP
+ *
+ * Compatibility is not matched while roaming, except for mode.
+ */
+static s32
+mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, 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;
+
+	if (priv->wps.session_enable) {
+		dev_dbg(adapter->dev,
+			"info: return success directly in WPS period\n");
+		return index;
+	}
+
+	if (mwifiex_is_network_compatible_for_wapi(priv, bss_desc)) {
+		dev_dbg(adapter->dev, "info: return success for WAPI AP\n");
+		return index;
+	}
+
+	if (bss_desc->bss_mode == mode) {
+		if (mwifiex_is_network_compatible_for_no_sec(priv, bss_desc)) {
+			/* No security */
+			return index;
+		} 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)) {
+			/* WPA enabled */
+			if (((priv->adapter->config_bands & BAND_GN
+			      || priv->adapter->config_bands & BAND_AN)
+			      && bss_desc->bcn_ht_cap)
+			      && !mwifiex_is_wpa_oui_present(bss_desc,
+					CIPHER_SUITE_CCMP)) {
+
+				if (mwifiex_is_wpa_oui_present(bss_desc,
+					    CIPHER_SUITE_TKIP)) {
+					dev_dbg(adapter->dev,
+						"info: Disable 11n if AES "
+						"is not supported by AP\n");
+					bss_desc->disable_11n = true;
+				} else {
+					return -1;
+				}
+			}
+			return index;
+		} else if (mwifiex_is_network_compatible_for_wpa2(priv,
+							bss_desc, index)) {
+			/* WPA2 enabled */
+			if (((priv->adapter->config_bands & BAND_GN
+			      || priv->adapter->config_bands & BAND_AN)
+			      && bss_desc->bcn_ht_cap)
+			      && !mwifiex_is_rsn_oui_present(bss_desc,
+					CIPHER_SUITE_CCMP)) {
+
+				if (mwifiex_is_rsn_oui_present(bss_desc,
+					    CIPHER_SUITE_TKIP)) {
+					dev_dbg(adapter->dev,
+						"info: Disable 11n if AES "
+						"is not supported by AP\n");
+					bss_desc->disable_11n = true;
+				} else {
+					return -1;
+				}
+			}
+			return index;
+		} else if (mwifiex_is_network_compatible_for_adhoc_aes(priv,
+								bss_desc)) {
+			/* Ad-hoc AES enabled */
+			return index;
+		} else if (mwifiex_is_network_compatible_for_dynamic_wep(priv,
+							bss_desc, index)) {
+			/* Dynamic WEP enabled */
+			return index;
+		}
+
+		/* Security doesn't match */
+		dev_dbg(adapter->dev, "info: %s: failed: index=%d "
+		       "wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode"
+		       "=%#x privacy=%#x\n",
+		       __func__, index,
+		       (bss_desc->bcn_wpa_ie) ?
+		       (*(bss_desc->bcn_wpa_ie)).vend_hdr.
+		       element_id : 0,
+		       (bss_desc->bcn_rsn_ie) ?
+		       (*(bss_desc->bcn_rsn_ie)).ieee_hdr.
+		       element_id : 0,
+		       (priv->sec_info.wep_status ==
+				MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d",
+		       (priv->sec_info.wpa_enabled) ? "e" : "d",
+		       (priv->sec_info.wpa2_enabled) ? "e" : "d",
+		       priv->sec_info.encryption_mode, bss_desc->privacy);
+		return -1;
+	}
+
+	/* Mode doesn't match */
+	return -1;
+}
+
+/*
+ * 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.
+ *
+ * This routine is used for any scan that is not provided with a
+ * specific channel list to scan.
+ */
+static void
+mwifiex_scan_create_channel_list(struct mwifiex_private *priv,
+				const struct mwifiex_user_scan_cfg
+				*user_scan_in,
+				struct mwifiex_chan_scan_param_set
+				*scan_chan_list,
+				u8 filtered_scan)
+{
+	enum ieee80211_band band;
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_channel *ch;
+	struct mwifiex_adapter *adapter = priv->adapter;
+	int chan_idx = 0, i;
+	u8 scan_type;
+
+	for (band = 0; (band < IEEE80211_NUM_BANDS) ; band++) {
+
+		if (!priv->wdev->wiphy->bands[band])
+			continue;
+
+		sband = priv->wdev->wiphy->bands[band];
+
+		for (i = 0; (i < sband->n_channels) ; i++, chan_idx++) {
+			ch = &sband->channels[i];
+			if (ch->flags & IEEE80211_CHAN_DISABLED)
+				continue;
+			scan_chan_list[chan_idx].radio_type = band;
+			scan_type = ch->flags & IEEE80211_CHAN_PASSIVE_SCAN;
+			if (user_scan_in &&
+				user_scan_in->chan_list[0].scan_time)
+				scan_chan_list[chan_idx].max_scan_time =
+					cpu_to_le16((u16) user_scan_in->
+					chan_list[0].scan_time);
+			else if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE)
+				scan_chan_list[chan_idx].max_scan_time =
+					cpu_to_le16(adapter->passive_scan_time);
+			else
+				scan_chan_list[chan_idx].max_scan_time =
+					cpu_to_le16(adapter->active_scan_time);
+			if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE)
+				scan_chan_list[chan_idx].chan_scan_mode_bitmap
+					|= MWIFIEX_PASSIVE_SCAN;
+			else
+				scan_chan_list[chan_idx].chan_scan_mode_bitmap
+					&= ~MWIFIEX_PASSIVE_SCAN;
+			scan_chan_list[chan_idx].chan_number =
+							(u32) ch->hw_value;
+			if (filtered_scan) {
+				scan_chan_list[chan_idx].max_scan_time =
+				cpu_to_le16(adapter->specific_scan_time);
+				scan_chan_list[chan_idx].chan_scan_mode_bitmap
+					|= MWIFIEX_DISABLE_CHAN_FILT;
+			}
+		}
+
+	}
+}
+
+/*
+ * This function constructs and sends multiple scan config commands to
+ * the firmware.
+ *
+ * Previous routines in the code flow have created a scan command configuration
+ * with any requested TLVs.  This function splits the channel TLV into maximum
+ * channels supported per scan lists and sends the portion of the channel TLV,
+ * along with the other TLVs, to the firmware.
+ */
+static int
+mwifiex_scan_channel_list(struct mwifiex_private *priv, void *wait_buf,
+			  u32 max_chan_per_scan, u8 filtered_scan,
+			  struct mwifiex_scan_cmd_config *scan_cfg_out,
+			  struct mwifiex_ie_types_chan_list_param_set
+			  *chan_tlv_out,
+			  struct mwifiex_chan_scan_param_set *scan_chan_list)
+{
+	int ret = 0;
+	struct mwifiex_chan_scan_param_set *tmp_chan_list;
+	struct mwifiex_chan_scan_param_set *start_chan;
+
+	u32 tlv_idx;
+	u32 total_scan_time;
+	u32 done_early;
+
+	if (!scan_cfg_out || !chan_tlv_out || !scan_chan_list) {
+		dev_dbg(priv->adapter->dev,
+			"info: Scan: Null detect: %p, %p, %p\n",
+		       scan_cfg_out, chan_tlv_out, scan_chan_list);
+		return -1;
+	}
+
+	chan_tlv_out->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
+
+	/* Set the temp channel struct pointer to the start of the desired
+	   list */
+	tmp_chan_list = scan_chan_list;
+
+	/* Loop through the desired channel list, sending a new firmware scan
+	   commands for each max_chan_per_scan channels (or for 1,6,11
+	   individually if configured accordingly) */
+	while (tmp_chan_list->chan_number) {
+
+		tlv_idx = 0;
+		total_scan_time = 0;
+		chan_tlv_out->header.len = 0;
+		start_chan = tmp_chan_list;
+		done_early = false;
+
+		/*
+		 * Construct the Channel TLV for the scan command.  Continue to
+		 * insert channel TLVs until:
+		 *   - the tlv_idx hits the maximum configured per scan command
+		 *   - the next channel to insert is 0 (end of desired channel
+		 *     list)
+		 *   - done_early is set (controlling individual scanning of
+		 *     1,6,11)
+		 */
+		while (tlv_idx < max_chan_per_scan
+		       && tmp_chan_list->chan_number && !done_early) {
+
+			dev_dbg(priv->adapter->dev,
+				"info: Scan: Chan(%3d), Radio(%d),"
+				" Mode(%d, %d), Dur(%d)\n",
+			       tmp_chan_list->chan_number,
+			       tmp_chan_list->radio_type,
+			       tmp_chan_list->chan_scan_mode_bitmap
+			       & MWIFIEX_PASSIVE_SCAN,
+			       (tmp_chan_list->chan_scan_mode_bitmap
+			       & MWIFIEX_DISABLE_CHAN_FILT) >> 1,
+			       le16_to_cpu(tmp_chan_list->max_scan_time));
+
+			/* Copy the current channel TLV to the command being
+			   prepared */
+			memcpy(chan_tlv_out->chan_scan_param + tlv_idx,
+			       tmp_chan_list,
+			       sizeof(chan_tlv_out->chan_scan_param));
+
+			/* Increment the TLV header length by the size
+			   appended */
+			chan_tlv_out->header.len =
+			cpu_to_le16(le16_to_cpu(chan_tlv_out->header.len) +
+			(sizeof(chan_tlv_out->chan_scan_param)));
+
+			/*
+			 * The tlv buffer length is set to the number of bytes
+			 * of the between the channel tlv pointer and the start
+			 * of the tlv buffer.  This compensates for any TLVs
+			 * that were appended before the channel list.
+			 */
+			scan_cfg_out->tlv_buf_len = (u32) ((u8 *) chan_tlv_out -
+							scan_cfg_out->tlv_buf);
+
+			/* Add the size of the channel tlv header and the data
+			   length */
+			scan_cfg_out->tlv_buf_len +=
+				(sizeof(chan_tlv_out->header)
+				 + le16_to_cpu(chan_tlv_out->header.len));
+
+			/* Increment the index to the channel tlv we are
+			   constructing */
+			tlv_idx++;
+
+			/* Count the total scan time per command */
+			total_scan_time +=
+				le16_to_cpu(tmp_chan_list->max_scan_time);
+
+			done_early = false;
+
+			/* Stop the loop if the *current* channel is in the
+			   1,6,11 set and we are not filtering on a BSSID
+			   or SSID. */
+			if (!filtered_scan && (tmp_chan_list->chan_number == 1
+				|| tmp_chan_list->chan_number == 6
+				|| tmp_chan_list->chan_number == 11))
+				done_early = true;
+
+			/* Increment the tmp pointer to the next channel to
+			   be scanned */
+			tmp_chan_list++;
+
+			/* Stop the loop if the *next* channel is in the 1,6,11
+			   set.  This will cause it to be the only channel
+			   scanned on the next interation */
+			if (!filtered_scan && (tmp_chan_list->chan_number == 1
+				|| tmp_chan_list->chan_number == 6
+				|| tmp_chan_list->chan_number == 11))
+				done_early = true;
+		}
+
+		/* The total scan time should be less than scan command timeout
+		   value */
+		if (total_scan_time > MWIFIEX_MAX_TOTAL_SCAN_TIME) {
+			dev_err(priv->adapter->dev, "total scan time %dms"
+				" is over limit (%dms), scan skipped\n",
+				total_scan_time, MWIFIEX_MAX_TOTAL_SCAN_TIME);
+			ret = -1;
+			break;
+		}
+
+		priv->adapter->scan_channels = start_chan;
+
+		/* Send the scan command to the firmware with the specified
+		   cfg */
+		ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_SCAN,
+					  HostCmd_ACT_GEN_SET,
+					  0, wait_buf, scan_cfg_out);
+		if (ret)
+			break;
+	}
+
+	if (ret)
+		return -1;
+
+	return 0;
+}
+
+/*
+ * This function constructs a scan command configuration structure to use
+ * in scan commands.
+ *
+ * Application layer or other functions can invoke network scanning
+ * with a scan configuration supplied in a user scan configuration structure.
+ * This structure is used as the basis of one or many scan command configuration
+ * commands that are sent to the command processing module and eventually to the
+ * firmware.
+ *
+ * This function creates a scan command configuration structure  based on the
+ * following user supplied parameters (if present):
+ *      - SSID filter
+ *      - BSSID filter
+ *      - Number of Probes to be sent
+ *      - Channel list
+ *
+ * If the SSID or BSSID filter is not present, the filter is disabled/cleared.
+ * If the number of probes is not set, adapter default setting is used.
+ */
+static void
+mwifiex_scan_setup_scan_config(struct mwifiex_private *priv,
+			       const struct mwifiex_user_scan_cfg *user_scan_in,
+			       struct mwifiex_scan_cmd_config *scan_cfg_out,
+			       struct mwifiex_ie_types_chan_list_param_set
+			       **chan_list_out,
+			       struct mwifiex_chan_scan_param_set
+			       *scan_chan_list,
+			       u8 *max_chan_per_scan, u8 *filtered_scan,
+			       u8 *scan_current_only)
+{
+	struct mwifiex_adapter *adapter = priv->adapter;
+	struct mwifiex_ie_types_num_probes *num_probes_tlv;
+	struct mwifiex_ie_types_wildcard_ssid_params *wildcard_ssid_tlv;
+	struct mwifiex_ie_types_rates_param_set *rates_tlv;
+	const u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+	u8 *tlv_pos;
+	u32 num_probes;
+	u32 ssid_len;
+	u32 chan_idx;
+	u32 scan_type;
+	u16 scan_dur;
+	u8 channel;
+	u8 radio_type;
+	u32 ssid_idx;
+	u8 ssid_filter;
+	u8 rates[MWIFIEX_SUPPORTED_RATES];
+	u32 rates_size;
+	struct mwifiex_ie_types_htcap *ht_cap;
+
+	/* The tlv_buf_len is calculated for each scan command.  The TLVs added
+	   in this routine will be preserved since the routine that sends the
+	   command will append channelTLVs at *chan_list_out.  The difference
+	   between the *chan_list_out and the tlv_buf start will be used to
+	   calculate the size of anything we add in this routine. */
+	scan_cfg_out->tlv_buf_len = 0;
+
+	/* Running tlv pointer.  Assigned to chan_list_out at end of function
+	   so later routines know where channels can be added to the command
+	   buf */
+	tlv_pos = scan_cfg_out->tlv_buf;
+
+	/* Initialize the scan as un-filtered; the flag is later set to TRUE
+	   below if a SSID or BSSID filter is sent in the command */
+	*filtered_scan = false;
+
+	/* Initialize the scan as not being only on the current channel.  If
+	   the channel list is customized, only contains one channel, and is
+	   the active channel, this is set true and data flow is not halted. */
+	*scan_current_only = false;
+
+	if (user_scan_in) {
+
+		/* Default the ssid_filter flag to TRUE, set false under
+		   certain wildcard conditions and qualified by the existence
+		   of an SSID list before marking the scan as filtered */
+		ssid_filter = true;
+
+		/* Set the BSS type scan filter, use Adapter setting if
+		   unset */
+		scan_cfg_out->bss_mode =
+			(user_scan_in->bss_mode ? (u8) user_scan_in->
+			 bss_mode : (u8) adapter->scan_mode);
+
+		/* Set the number of probes to send, use Adapter setting
+		   if unset */
+		num_probes =
+			(user_scan_in->num_probes ? user_scan_in->
+			 num_probes : adapter->scan_probes);
+
+		/*
+		 * Set the BSSID filter to the incoming configuration,
+		 * if non-zero.  If not set, it will remain disabled
+		 * (all zeros).
+		 */
+		memcpy(scan_cfg_out->specific_bssid,
+		       user_scan_in->specific_bssid,
+		       sizeof(scan_cfg_out->specific_bssid));
+
+		for (ssid_idx = 0;
+		     ((ssid_idx < ARRAY_SIZE(user_scan_in->ssid_list))
+		      && (*user_scan_in->ssid_list[ssid_idx].ssid
+			  || user_scan_in->ssid_list[ssid_idx].max_len));
+		     ssid_idx++) {
+
+			ssid_len = strlen(user_scan_in->ssid_list[ssid_idx].
+					  ssid) + 1;
+
+			wildcard_ssid_tlv =
+				(struct mwifiex_ie_types_wildcard_ssid_params *)
+				tlv_pos;
+			wildcard_ssid_tlv->header.type =
+				cpu_to_le16(TLV_TYPE_WILDCARDSSID);
+			wildcard_ssid_tlv->header.len = cpu_to_le16(
+				(u16) (ssid_len + sizeof(wildcard_ssid_tlv->
+							 max_ssid_length)));
+			wildcard_ssid_tlv->max_ssid_length =
+				user_scan_in->ssid_list[ssid_idx].max_len;
+
+			memcpy(wildcard_ssid_tlv->ssid,
+			       user_scan_in->ssid_list[ssid_idx].ssid,
+			       ssid_len);
+
+			tlv_pos += (sizeof(wildcard_ssid_tlv->header)
+				+ le16_to_cpu(wildcard_ssid_tlv->header.len));
+
+			dev_dbg(adapter->dev, "info: scan: ssid_list[%d]: %s, %d\n",
+				ssid_idx, wildcard_ssid_tlv->ssid,
+				wildcard_ssid_tlv->max_ssid_length);
+
+			/* Empty wildcard ssid with a maxlen will match many or
+			   potentially all SSIDs (maxlen == 32), therefore do
+			   not treat the scan as
+			   filtered. */
+			if (!ssid_len && wildcard_ssid_tlv->max_ssid_length)
+				ssid_filter = false;
+
+		}
+
+		/*
+		 *  The default number of channels sent in the command is low to
+		 *  ensure the response buffer from the firmware does not
+		 *  truncate scan results.  That is not an issue with an SSID
+		 *  or BSSID filter applied to the scan results in the firmware.
+		 */
+		if ((ssid_idx && ssid_filter)
+		    || memcmp(scan_cfg_out->specific_bssid, &zero_mac,
+			      sizeof(zero_mac)))
+			*filtered_scan = true;
+	} else {
+		scan_cfg_out->bss_mode = (u8) adapter->scan_mode;
+		num_probes = adapter->scan_probes;
+	}
+
+	/*
+	 *  If a specific BSSID or SSID is used, the number of channels in the
+	 *  scan command will be increased to the absolute maximum.
+	 */
+	if (*filtered_scan)
+		*max_chan_per_scan = MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN;
+	else
+		*max_chan_per_scan = MWIFIEX_CHANNELS_PER_SCAN_CMD;
+
+	/* If the input config or adapter has the number of Probes set,
+	   add tlv */
+	if (num_probes) {
+
+		dev_dbg(adapter->dev, "info: scan: num_probes = %d\n",
+						num_probes);
+
+		num_probes_tlv = (struct mwifiex_ie_types_num_probes *) tlv_pos;
+		num_probes_tlv->header.type = cpu_to_le16(TLV_TYPE_NUMPROBES);
+		num_probes_tlv->header.len =
+			cpu_to_le16(sizeof(num_probes_tlv->num_probes));
+		num_probes_tlv->num_probes = cpu_to_le16((u16) num_probes);
+
+		tlv_pos += sizeof(num_probes_tlv->header) +
+			le16_to_cpu(num_probes_tlv->header.len);
+
+	}
+
+	/* Append rates tlv */
+	memset(rates, 0, sizeof(rates));
+
+	rates_size = mwifiex_get_supported_rates(priv, rates);
+
+	rates_tlv = (struct mwifiex_ie_types_rates_param_set *) tlv_pos;
+	rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES);
+	rates_tlv->header.len = cpu_to_le16((u16) rates_size);
+	memcpy(rates_tlv->rates, rates, rates_size);
+	tlv_pos += sizeof(rates_tlv->header) + rates_size;
+
+	dev_dbg(adapter->dev, "info: SCAN_CMD: Rates size = %d\n", rates_size);
+
+	if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info)
+	    && (priv->adapter->config_bands & BAND_GN
+		|| priv->adapter->config_bands & BAND_AN)) {
+		ht_cap = (struct mwifiex_ie_types_htcap *) tlv_pos;
+		memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap));
+		ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY);
+		ht_cap->header.len =
+				cpu_to_le16(sizeof(struct ieee80211_ht_cap));
+		mwifiex_fill_cap_info(priv, ht_cap);
+		tlv_pos += sizeof(struct mwifiex_ie_types_htcap);
+	}
+
+	/* Append vendor specific IE TLV */
+	mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_SCAN, &tlv_pos);
+
+	/*
+	 * Set the output for the channel TLV to the address in the tlv buffer
+	 *   past any TLVs that were added in this function (SSID, num_probes).
+	 *   Channel TLVs will be added past this for each scan command,
+	 *   preserving the TLVs that were previously added.
+	 */
+	*chan_list_out =
+		(struct mwifiex_ie_types_chan_list_param_set *) tlv_pos;
+
+	if (user_scan_in && user_scan_in->chan_list[0].chan_number) {
+
+		dev_dbg(adapter->dev, "info: Scan: Using supplied channel list\n");
+
+		for (chan_idx = 0;
+		     chan_idx < MWIFIEX_USER_SCAN_CHAN_MAX
+		     && user_scan_in->chan_list[chan_idx].chan_number;
+		     chan_idx++) {
+
+			channel = user_scan_in->chan_list[chan_idx].chan_number;
+			(scan_chan_list + chan_idx)->chan_number = channel;
+
+			radio_type =
+				user_scan_in->chan_list[chan_idx].radio_type;
+			(scan_chan_list + chan_idx)->radio_type = radio_type;
+
+			scan_type = user_scan_in->chan_list[chan_idx].scan_type;
+
+			if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE)
+				(scan_chan_list +
+				 chan_idx)->chan_scan_mode_bitmap
+					|= MWIFIEX_PASSIVE_SCAN;
+			else
+				(scan_chan_list +
+				 chan_idx)->chan_scan_mode_bitmap
+					&= ~MWIFIEX_PASSIVE_SCAN;
+
+			if (user_scan_in->chan_list[chan_idx].scan_time) {
+				scan_dur = (u16) user_scan_in->
+					chan_list[chan_idx].scan_time;
+			} else {
+				if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE)
+					scan_dur = adapter->passive_scan_time;
+				else if (*filtered_scan)
+					scan_dur = adapter->specific_scan_time;
+				else
+					scan_dur = adapter->active_scan_time;
+			}
+
+			(scan_chan_list + chan_idx)->min_scan_time =
+				cpu_to_le16(scan_dur);
+			(scan_chan_list + chan_idx)->max_scan_time =
+				cpu_to_le16(scan_dur);
+		}
+
+		/* Check if we are only scanning the current channel */
+		if ((chan_idx == 1)
+		    && (user_scan_in->chan_list[0].chan_number
+			== priv->curr_bss_params.bss_descriptor.channel)) {
+			*scan_current_only = true;
+			dev_dbg(adapter->dev,
+				"info: Scan: Scanning current channel only\n");
+		}
+
+	} else {
+		dev_dbg(adapter->dev,
+				"info: Scan: Creating full region channel list\n");
+		mwifiex_scan_create_channel_list(priv, user_scan_in,
+						 scan_chan_list,
+						 *filtered_scan);
+	}
+}
+
+/*
+ * This function inspects the scan response buffer for pointers to
+ * expected TLVs.
+ *
+ * TLVs can be included at the end of the scan response BSS information.
+ *
+ * Data in the buffer is parsed pointers to TLVs that can potentially
+ * be passed back in the response.
+ */
+static void
+mwifiex_ret_802_11_scan_get_tlv_ptrs(struct mwifiex_adapter *adapter,
+				     struct mwifiex_ie_types_data *tlv,
+				     u32 tlv_buf_size, u32 req_tlv_type,
+				     struct mwifiex_ie_types_data **tlv_data)
+{
+	struct mwifiex_ie_types_data *current_tlv;
+	u32 tlv_buf_left;
+	u32 tlv_type;
+	u32 tlv_len;
+
+	current_tlv = tlv;
+	tlv_buf_left = tlv_buf_size;
+	*tlv_data = NULL;
+
+	dev_dbg(adapter->dev, "info: SCAN_RESP: tlv_buf_size = %d\n",
+						tlv_buf_size);
+
+	while (tlv_buf_left >= sizeof(struct mwifiex_ie_types_header)) {
+
+		tlv_type = le16_to_cpu(current_tlv->header.type);
+		tlv_len = le16_to_cpu(current_tlv->header.len);
+
+		if (sizeof(tlv->header) + tlv_len > tlv_buf_left) {
+			dev_err(adapter->dev, "SCAN_RESP: TLV buffer corrupt\n");
+			break;
+		}
+
+		if (req_tlv_type == tlv_type) {
+			switch (tlv_type) {
+			case TLV_TYPE_TSFTIMESTAMP:
+				dev_dbg(adapter->dev, "info: SCAN_RESP: TSF "
+					"timestamp TLV, len = %d\n", tlv_len);
+				*tlv_data = (struct mwifiex_ie_types_data *)
+					current_tlv;
+				break;
+			case TLV_TYPE_CHANNELBANDLIST:
+				dev_dbg(adapter->dev, "info: SCAN_RESP: channel"
+					" band list TLV, len = %d\n", tlv_len);
+				*tlv_data = (struct mwifiex_ie_types_data *)
+					current_tlv;
+				break;
+			default:
+				dev_err(adapter->dev,
+					"SCAN_RESP: unhandled TLV = %d\n",
+				       tlv_type);
+				/* Give up, this seems corrupted */
+				return;
+			}
+		}
+
+		if (*tlv_data)
+			break;
+
+
+		tlv_buf_left -= (sizeof(tlv->header) + tlv_len);
+		current_tlv =
+			(struct mwifiex_ie_types_data *) (current_tlv->data +
+							  tlv_len);
+
+	}			/* while */
+}
+
+/*
+ * 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
+ */
+static int
+mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter,
+				   struct mwifiex_bssdescriptor *bss_entry,
+				   u8 **beacon_info, u32 *bytes_left)
+{
+	int ret = 0;
+	u8 element_id;
+	struct ieee_types_fh_param_set *fh_param_set;
+	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;
+	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;
+
+
+	/* Process variable IE */
+	while (bytes_left_for_current_beacon >= 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) {
+			dev_err(adapter->dev, "err: InterpretIE: in processing"
+				" IE, bytes left < IE length\n");
+			bytes_left_for_current_beacon = 0;
+			ret = -1;
+			continue;
+		}
+		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);
+			break;
+
+		case WLAN_EID_SUPP_RATES:
+			memcpy(bss_entry->data_rates, current_ptr + 2,
+			       element_len);
+			memcpy(bss_entry->supported_rates, current_ptr + 2,
+			       element_len);
+			rate_size = element_len;
+			found_data_rate_ie = true;
+			break;
+
+		case WLAN_EID_FH_PARAMS:
+			fh_param_set =
+				(struct ieee_types_fh_param_set *) current_ptr;
+			memcpy(&bss_entry->phy_param_set.fh_param_set,
+			       fh_param_set,
+			       sizeof(struct ieee_types_fh_param_set));
+			break;
+
+		case WLAN_EID_DS_PARAMS:
+			ds_param_set =
+				(struct ieee_types_ds_param_set *) current_ptr;
+
+			bss_entry->channel = ds_param_set->current_chan;
+
+			memcpy(&bss_entry->phy_param_set.ds_param_set,
+			       ds_param_set,
+			       sizeof(struct ieee_types_ds_param_set));
+			break;
+
+		case WLAN_EID_CF_PARAMS:
+			cf_param_set =
+				(struct ieee_types_cf_param_set *) current_ptr;
+			memcpy(&bss_entry->ss_param_set.cf_param_set,
+			       cf_param_set,
+			       sizeof(struct ieee_types_cf_param_set));
+			break;
+
+		case WLAN_EID_IBSS_PARAMS:
+			ibss_param_set =
+				(struct ieee_types_ibss_param_set *)
+				current_ptr;
+			memcpy(&bss_entry->ss_param_set.ibss_param_set,
+			       ibss_param_set,
+			       sizeof(struct ieee_types_ibss_param_set));
+			break;
+
+		case WLAN_EID_ERP_INFO:
+			bss_entry->erp_flags = *(current_ptr + 2);
+			break;
+
+		case WLAN_EID_EXT_SUPP_RATES:
+			/*
+			 * Only process extended supported rate
+			 * if data rate is already found.
+			 * Data rate IE should come before
+			 * extended supported rate IE
+			 */
+			if (found_data_rate_ie) {
+				if ((element_len + rate_size) >
+				    MWIFIEX_SUPPORTED_RATES)
+					bytes_to_copy =
+						(MWIFIEX_SUPPORTED_RATES -
+						 rate_size);
+				else
+					bytes_to_copy = element_len;
+
+				rate = (u8 *) bss_entry->data_rates;
+				rate += rate_size;
+				memcpy(rate, current_ptr + 2, bytes_to_copy);
+
+				rate = (u8 *) bss_entry->supported_rates;
+				rate += rate_size;
+				memcpy(rate, current_ptr + 2, bytes_to_copy);
+			}
+			break;
+
+		case WLAN_EID_VENDOR_SPECIFIC:
+			vendor_ie = (struct ieee_types_vendor_specific *)
+					current_ptr;
+
+			if (!memcmp
+			    (vendor_ie->vend_hdr.oui, wpa_oui,
+			     sizeof(wpa_oui))) {
+				bss_entry->bcn_wpa_ie =
+					(struct ieee_types_vendor_specific *)
+					current_ptr;
+				bss_entry->wpa_offset = (u16) (current_ptr -
+							bss_entry->beacon_buf);
+			} else if (!memcmp(vendor_ie->vend_hdr.oui, wmm_oui,
+				    sizeof(wmm_oui))) {
+				if (total_ie_len ==
+				    sizeof(struct ieee_types_wmm_parameter)
+				    || total_ie_len ==
+				    sizeof(struct ieee_types_wmm_info))
+					/*
+					 * Only accept and copy the WMM IE if
+					 * it matches the size expected for the
+					 * WMM Info IE or the WMM Parameter IE.
+					 */
+					memcpy((u8 *) &bss_entry->wmm_ie,
+					       current_ptr, total_ie_len);
+			}
+			break;
+		case WLAN_EID_RSN:
+			bss_entry->bcn_rsn_ie =
+				(struct ieee_types_generic *) current_ptr;
+			bss_entry->rsn_offset = (u16) (current_ptr -
+							bss_entry->beacon_buf);
+			break;
+		case WLAN_EID_BSS_AC_ACCESS_DELAY:
+			bss_entry->bcn_wapi_ie =
+				(struct ieee_types_generic *) current_ptr;
+			bss_entry->wapi_offset = (u16) (current_ptr -
+							bss_entry->beacon_buf);
+			break;
+		case WLAN_EID_HT_CAPABILITY:
+			bss_entry->bcn_ht_cap = (struct ieee80211_ht_cap *)
+					(current_ptr +
+					sizeof(struct ieee_types_header));
+			bss_entry->ht_cap_offset = (u16) (current_ptr +
+					sizeof(struct ieee_types_header) -
+					bss_entry->beacon_buf);
+			break;
+		case WLAN_EID_HT_INFORMATION:
+			bss_entry->bcn_ht_info = (struct ieee80211_ht_info *)
+					(current_ptr +
+					sizeof(struct ieee_types_header));
+			bss_entry->ht_info_offset = (u16) (current_ptr +
+					sizeof(struct ieee_types_header) -
+					bss_entry->beacon_buf);
+			break;
+		case WLAN_EID_BSS_COEX_2040:
+			bss_entry->bcn_bss_co_2040 = (u8 *) (current_ptr +
+					sizeof(struct ieee_types_header));
+			bss_entry->bss_co_2040_offset = (u16) (current_ptr +
+					sizeof(struct ieee_types_header) -
+						bss_entry->beacon_buf);
+			break;
+		case WLAN_EID_EXT_CAPABILITY:
+			bss_entry->bcn_ext_cap = (u8 *) (current_ptr +
+					sizeof(struct ieee_types_header));
+			bss_entry->ext_cap_offset = (u16) (current_ptr +
+					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;
+		}
+
+		current_ptr += element_len + 2;
+
+		/* Need to account for IE ID and IE Len */
+		bytes_left_for_current_beacon -= (element_len + 2);
+
+	}	/* while (bytes_left_for_current_beacon > 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.
+ */
+static u8
+mwifiex_radio_type_to_band(u8 radio_type)
+{
+	u8 ret_band;
+
+	switch (radio_type) {
+	case HostCmd_SCAN_RADIO_TYPE_A:
+		ret_band = BAND_A;
+		break;
+	case HostCmd_SCAN_RADIO_TYPE_BG:
+	default:
+		ret_band = BAND_G;
+		break;
+	}
+
+	return ret_band;
+}
+
+/*
+ * 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)
+{
+	int ret = -1;
+	s32 table_idx;
+
+	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);
+		ret = 0;
+		mwifiex_scan_delete_table_entry(priv, table_idx);
+	}
+
+	return ret;
+}
+
+/*
+ * This is an internal function used to start a scan based on an input
+ * configuration.
+ *
+ * This uses the input user scan configuration information when provided in
+ * order to send the appropriate scan commands to firmware to populate or
+ * update the internal driver scan table.
+ */
+int mwifiex_scan_networks(struct mwifiex_private *priv,
+			  void *wait_buf, u16 action,
+			  const struct mwifiex_user_scan_cfg *user_scan_in,
+			  struct mwifiex_scan_resp *scan_resp)
+{
+	int ret = 0;
+	struct mwifiex_adapter *adapter = priv->adapter;
+	struct cmd_ctrl_node *cmd_node = NULL;
+	union mwifiex_scan_cmd_config_tlv *scan_cfg_out = NULL;
+	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;
+	unsigned long flags;
+
+	if (action == HostCmd_ACT_GEN_GET) {
+		if (scan_resp) {
+			scan_resp->scan_table = (u8 *) adapter->scan_table;
+			scan_resp->num_in_scan_table =
+				adapter->num_in_scan_table;
+		} else {
+			ret = -1;
+		}
+		return ret;
+	}
+
+	if (adapter->scan_processing && action == HostCmd_ACT_GEN_SET) {
+		dev_dbg(adapter->dev, "cmd: Scan already in process...\n");
+		return ret;
+	}
+
+	spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+	adapter->scan_processing = true;
+	spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+
+	if (priv->scan_block && action == HostCmd_ACT_GEN_SET) {
+		dev_dbg(adapter->dev,
+			"cmd: Scan is blocked during association...\n");
+		return ret;
+	}
+
+	scan_cfg_out = kzalloc(sizeof(union mwifiex_scan_cmd_config_tlv),
+					GFP_KERNEL);
+	if (!scan_cfg_out) {
+		dev_err(adapter->dev, "failed to alloc scan_cfg_out\n");
+		return -1;
+	}
+
+	buf_size = sizeof(struct mwifiex_chan_scan_param_set) *
+			MWIFIEX_USER_SCAN_CHAN_MAX;
+	scan_chan_list = kzalloc(buf_size, GFP_KERNEL);
+	if (!scan_chan_list) {
+		dev_err(adapter->dev, "failed to alloc scan_chan_list\n");
+		kfree(scan_cfg_out);
+		return -1;
+	}
+
+	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, wait_buf, max_chan_per_scan,
+					filtered_scan, &scan_cfg_out->config,
+					chan_list_out, scan_chan_list);
+
+	/* Get scan command from scan_pending_q and put to cmd_pending_q */
+	if (!ret) {
+		spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+		if (!list_empty(&adapter->scan_pending_q)) {
+			cmd_node = list_first_entry(&adapter->scan_pending_q,
+						struct cmd_ctrl_node, list);
+			list_del(&cmd_node->list);
+			spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
+									flags);
+			mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
+							true);
+		} else {
+			spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
+					       flags);
+		}
+		ret = -EINPROGRESS;
+	} else {
+		spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+		adapter->scan_processing = true;
+		spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+	}
+
+	kfree(scan_cfg_out);
+	kfree(scan_chan_list);
+	return ret;
+}
+
+/*
+ * This function prepares a scan command to be sent to the firmware.
+ *
+ * This uses the scan command configuration sent to the command processing
+ * module in command preparation stage to configure a scan command structure
+ * to send to firmware.
+ *
+ * The fixed fields specifying the BSS type and BSSID filters as well as a
+ * variable number/length of TLVs are sent in the command to firmware.
+ *
+ * Preparation also includes -
+ *      - Setting command ID, and proper size
+ *      - Ensuring correct endian-ness
+ */
+int mwifiex_cmd_802_11_scan(struct mwifiex_private *priv,
+			    struct host_cmd_ds_command *cmd, void *data_buf)
+{
+	struct host_cmd_ds_802_11_scan *scan_cmd = &cmd->params.scan;
+	struct mwifiex_scan_cmd_config *scan_cfg;
+
+	scan_cfg = (struct mwifiex_scan_cmd_config *) data_buf;
+
+	/* Set fixed field variables in scan command */
+	scan_cmd->bss_mode = scan_cfg->bss_mode;
+	memcpy(scan_cmd->bssid, scan_cfg->specific_bssid,
+	       sizeof(scan_cmd->bssid));
+	memcpy(scan_cmd->tlv_buffer, scan_cfg->tlv_buf, scan_cfg->tlv_buf_len);
+
+	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SCAN);
+
+	/* Size is equal to the sizeof(fixed portions) + the TLV len + header */
+	cmd->size = cpu_to_le16((u16) (sizeof(scan_cmd->bss_mode)
+					  + sizeof(scan_cmd->bssid)
+					  + scan_cfg->tlv_buf_len + S_DS_GEN));
+
+	return 0;
+}
+
+/*
+ * This function handles the command response of scan.
+ *
+ * The response buffer for the scan command has the following
+ * memory layout:
+ *
+ *      .-------------------------------------------------------------.
+ *      |  Header (4 * sizeof(t_u16)):  Standard command response hdr |
+ *      .-------------------------------------------------------------.
+ *      |  BufSize (t_u16) : sizeof the BSS Description data          |
+ *      .-------------------------------------------------------------.
+ *      |  NumOfSet (t_u8) : Number of BSS Descs returned             |
+ *      .-------------------------------------------------------------.
+ *      |  BSSDescription data (variable, size given in BufSize)      |
+ *      .-------------------------------------------------------------.
+ *      |  TLV data (variable, size calculated using Header->Size,    |
+ *      |            BufSize and sizeof the fixed fields above)       |
+ *      .-------------------------------------------------------------.
+ */
+int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
+			    struct host_cmd_ds_command *resp, void *wq_buf)
+{
+	int ret = 0;
+	struct mwifiex_adapter *adapter = priv->adapter;
+	struct mwifiex_wait_queue *wait_queue = NULL;
+	struct cmd_ctrl_node *cmd_node = NULL;
+	struct host_cmd_ds_802_11_scan_rsp *scan_rsp = NULL;
+	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;
+
+	is_bgscan_resp = (le16_to_cpu(resp->command)
+		== HostCmd_CMD_802_11_BG_SCAN_QUERY);
+	if (is_bgscan_resp)
+		scan_rsp = &resp->params.bg_scan_query_resp.scan_resp;
+	else
+		scan_rsp = &resp->params.scan_resp;
+
+
+	if (scan_rsp->number_of_sets > IW_MAX_AP) {
+		dev_err(adapter->dev, "SCAN_RESP: too many AP returned (%d)\n",
+		       scan_rsp->number_of_sets);
+		ret = -1;
+		goto done;
+	}
+
+	bytes_left = le16_to_cpu(scan_rsp->bss_descript_size);
+	dev_dbg(adapter->dev, "info: SCAN_RESP: bss_descript_size %d\n",
+						bytes_left);
+
+	scan_resp_size = le16_to_cpu(resp->size);
+
+	dev_dbg(adapter->dev,
+		"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;
+
+	/*
+	 * The size of the TLV buffer is equal to the entire command response
+	 *   size (scan_resp_size) minus the fixed fields (sizeof()'s), the
+	 *   BSS Descriptions (bss_descript_size as bytesLef) and the command
+	 *   response header (S_DS_GEN)
+	 */
+	tlv_buf_size = scan_resp_size - (bytes_left
+					 + sizeof(scan_rsp->bss_descript_size)
+					 + sizeof(scan_rsp->number_of_sets)
+					 + S_DS_GEN);
+
+	tlv_data = (struct mwifiex_ie_types_data *) (scan_rsp->
+						 bss_desc_and_tlv_buffer +
+						 bytes_left);
+
+	/* Search the TLV buffer space in the scan response for any valid
+	   TLVs */
+	mwifiex_ret_802_11_scan_get_tlv_ptrs(adapter, tlv_data, tlv_buf_size,
+					     TLV_TYPE_TSFTIMESTAMP,
+					     (struct mwifiex_ie_types_data **)
+					     &tsf_tlv);
+
+	/* Search the TLV buffer space in the scan response for any valid
+	   TLVs */
+	mwifiex_ret_802_11_scan_get_tlv_ptrs(adapter, tlv_data, tlv_buf_size,
+					     TLV_TYPE_CHANNELBANDLIST,
+					     (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 -1;
+	}
+
+	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;
+		}
+
+		/* 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);
+
+		/* 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;
+			}
+			/*
+			 * 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);
+				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++;
+		}
+
+		/*
+		 * 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 (cfp)
+			bss_new_entry->freq = cfp->freq;
+		else
+			bss_new_entry->freq = 0;
+
+		/* 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]));
+
+	}
+
+	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);
+
+	/* Update the total number of BSSIDs in the scan table */
+	adapter->num_in_scan_table = num_in_table;
+
+	spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+	if (list_empty(&adapter->scan_pending_q)) {
+		spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+		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 */
+		wait_queue = (struct mwifiex_wait_queue *) wq_buf;
+		if (wait_queue) {
+			wait_queue->status = MWIFIEX_ERROR_NO_ERROR;
+
+			/* Indicate ioctl complete */
+			mwifiex_ioctl_complete(adapter,
+			       (struct mwifiex_wait_queue *) wait_queue, 0);
+		}
+		if (priv->report_scan_result)
+			priv->report_scan_result = false;
+		if (priv->scan_pending_on_block) {
+			priv->scan_pending_on_block = false;
+			up(&priv->async_sem);
+		}
+
+	} else {
+		/* Get scan command from scan_pending_q and put to
+		   cmd_pending_q */
+		cmd_node = list_first_entry(&adapter->scan_pending_q,
+					    struct cmd_ctrl_node, list);
+		list_del(&cmd_node->list);
+		spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+
+		mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true);
+	}
+
+done:
+	kfree((u8 *) bss_new_entry);
+	return ret;
+}
+
+/*
+ * This function prepares command for background scan query.
+ *
+ * Preparation includes -
+ *      - Setting command ID and proper size
+ *      - Setting background scan flush parameter
+ *      - Ensuring correct endian-ness
+ */
+int mwifiex_cmd_802_11_bg_scan_query(struct mwifiex_private *priv,
+				     struct host_cmd_ds_command *cmd,
+				     void *data_buf)
+{
+	struct host_cmd_ds_802_11_bg_scan_query *bg_query =
+		&cmd->params.bg_scan_query;
+
+	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_QUERY);
+	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_bg_scan_query)
+				+ S_DS_GEN);
+
+	bg_query->flush = 1;
+
+	return 0;
+}
+
+/*
+ * 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
+mwifiex_queue_scan_cmd(struct mwifiex_private *priv,
+		       struct cmd_ctrl_node *cmd_node)
+{
+	struct mwifiex_adapter *adapter = priv->adapter;
+	unsigned long flags;
+
+	spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+	list_add_tail(&cmd_node->list, &adapter->scan_pending_q);
+	spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+}
+
+/*
+ * 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.
+ */
+static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv,
+				      void *wait_buf, u16 action,
+				      struct mwifiex_802_11_ssid *req_ssid,
+				      struct mwifiex_scan_resp *scan_resp)
+{
+	struct mwifiex_adapter *adapter = priv->adapter;
+	int ret = 0;
+	struct mwifiex_user_scan_cfg *scan_cfg;
+
+	if (!req_ssid)
+		return -1;
+
+	if (action == HostCmd_ACT_GEN_GET) {
+		if (scan_resp) {
+			scan_resp->scan_table =
+				(u8 *) &priv->curr_bss_params.bss_descriptor;
+			scan_resp->num_in_scan_table =
+				adapter->num_in_scan_table;
+		} else {
+			ret = -1;
+		}
+		return ret;
+	}
+
+	if (adapter->scan_processing && action == HostCmd_ACT_GEN_SET) {
+		dev_dbg(adapter->dev, "cmd: Scan already in process...\n");
+		return ret;
+	}
+
+	if (priv->scan_block && action == HostCmd_ACT_GEN_SET) {
+		dev_dbg(adapter->dev,
+			"cmd: Scan is blocked during association...\n");
+		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");
+		return -1;
+	}
+
+	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, wait_buf, action, scan_cfg, NULL);
+
+	kfree(scan_cfg);
+	return ret;
+}
+
+/*
+ * Sends IOCTL request to start a scan.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ *
+ * Scan command can be issued for both normal scan and specific SSID
+ * scan, depending upon whether an SSID is provided or not.
+ */
+int mwifiex_request_scan(struct mwifiex_private *priv, u8 wait_option,
+			 struct mwifiex_802_11_ssid *req_ssid)
+{
+	int ret = 0;
+	struct mwifiex_wait_queue *wait = NULL;
+	int status = 0;
+
+	if (down_interruptible(&priv->async_sem)) {
+		dev_err(priv->adapter->dev, "%s: acquire semaphore\n",
+						__func__);
+		return -1;
+	}
+	priv->scan_pending_on_block = true;
+
+	/* Allocate wait request buffer */
+	wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
+	if (!wait) {
+		ret = -1;
+		goto done;
+	}
+
+	if (req_ssid && req_ssid->ssid_len != 0)
+		/* Specific SSID scan */
+		status = mwifiex_scan_specific_ssid(priv, wait,
+						    HostCmd_ACT_GEN_SET,
+						    req_ssid, NULL);
+	else
+		/* Normal scan */
+		status = mwifiex_scan_networks(priv, wait, HostCmd_ACT_GEN_SET,
+					       NULL, NULL);
+	status = mwifiex_request_ioctl(priv, wait, status, wait_option);
+	if (status == -1)
+		ret = -1;
+done:
+	if ((wait) && (status != -EINPROGRESS))
+		kfree(wait);
+	if (ret == -1) {
+		priv->scan_pending_on_block = false;
+		up(&priv->async_sem);
+	}
+	return ret;
+}
+
+/*
+ * This function appends the vendor specific IE TLV to a buffer.
+ */
+int
+mwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv,
+			    u16 vsie_mask, u8 **buffer)
+{
+	int id, ret_len = 0;
+	struct mwifiex_ie_types_vendor_param_set *vs_param_set;
+
+	if (!buffer)
+		return 0;
+	if (!(*buffer))
+		return 0;
+
+	/*
+	 * Traverse through the saved vendor specific IE array and append
+	 * the selected(scan/assoc/adhoc) IE as TLV to the command
+	 */
+	for (id = 0; id < MWIFIEX_MAX_VSIE_NUM; id++) {
+		if (priv->vs_ie[id].mask & vsie_mask) {
+			vs_param_set =
+				(struct mwifiex_ie_types_vendor_param_set *)
+				*buffer;
+			vs_param_set->header.type =
+				cpu_to_le16(TLV_TYPE_PASSTHROUGH);
+			vs_param_set->header.len =
+				cpu_to_le16((((u16) priv->vs_ie[id].ie[1])
+				& 0x00FF) + 2);
+			memcpy(vs_param_set->ie, priv->vs_ie[id].ie,
+			       le16_to_cpu(vs_param_set->header.len));
+			*buffer += le16_to_cpu(vs_param_set->header.len) +
+				   sizeof(struct mwifiex_ie_types_header);
+			ret_len += le16_to_cpu(vs_param_set->header.len) +
+				   sizeof(struct mwifiex_ie_types_header);
+		}
+	}
+	return ret_len;
+}
+
+/*
+ * This function saves a beacon buffer of the current BSS descriptor.
+ *
+ * The current beacon buffer is saved so that it can be restored in the
+ * following cases that makes the beacon buffer not to contain the current
+ * ssid's beacon buffer.
+ *      - The current ssid was not found somehow in the last scan.
+ *      - The current ssid was the last entry of the scan table and overloaded.
+ */
+void
+mwifiex_save_curr_bcn(struct mwifiex_private *priv)
+{
+	struct mwifiex_bssdescriptor *curr_bss =
+		&priv->curr_bss_params.bss_descriptor;
+
+	/* save the beacon buffer if it is not saved or updated */
+	if ((priv->curr_bcn_buf == NULL) ||
+	    (priv->curr_bcn_size != curr_bss->beacon_buf_size) ||
+	    (memcmp(priv->curr_bcn_buf, curr_bss->beacon_buf,
+		    curr_bss->beacon_buf_size))) {
+
+		kfree(priv->curr_bcn_buf);
+		priv->curr_bcn_buf = NULL;
+
+		priv->curr_bcn_size = curr_bss->beacon_buf_size;
+		if (!priv->curr_bcn_size)
+			return;
+
+		priv->curr_bcn_buf = kzalloc(curr_bss->beacon_buf_size,
+						GFP_KERNEL);
+		if (!priv->curr_bcn_buf) {
+			dev_err(priv->adapter->dev,
+					"failed to alloc curr_bcn_buf\n");
+		} else {
+			memcpy(priv->curr_bcn_buf, curr_bss->beacon_buf,
+			       curr_bss->beacon_buf_size);
+			dev_dbg(priv->adapter->dev,
+				"info: current beacon saved %d\n",
+			       priv->curr_bcn_size);
+		}
+	}
+}
+
+/*
+ * This function frees the current BSS descriptor beacon buffer.
+ */
+void
+mwifiex_free_curr_bcn(struct mwifiex_private *priv)
+{
+	kfree(priv->curr_bcn_buf);
+	priv->curr_bcn_buf = NULL;
+}
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c
new file mode 100644
index 0000000..f21e5cd
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/sdio.c
@@ -0,0 +1,1770 @@
+/*
+ * Marvell Wireless LAN device driver: SDIO specific handling
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include <linux/firmware.h>
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+#include "11n.h"
+#include "sdio.h"
+
+
+#define SDIO_VERSION	"1.0"
+
+static struct mwifiex_if_ops sdio_ops;
+
+static struct semaphore add_remove_card_sem;
+
+/*
+ * SDIO probe.
+ *
+ * This function probes an mwifiex device and registers it. It allocates
+ * the card structure, enables SDIO function number and initiates the
+ * device registration and initialization procedure by adding a logical
+ * interface.
+ */
+static int
+mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
+{
+	int ret = 0;
+	struct sdio_mmc_card *card = NULL;
+
+	pr_debug("info: vendor=0x%4.04X device=0x%4.04X class=%d function=%d\n",
+	       func->vendor, func->device, func->class, func->num);
+
+	card = kzalloc(sizeof(struct sdio_mmc_card), GFP_KERNEL);
+	if (!card) {
+		pr_err("%s: failed to alloc memory\n", __func__);
+		return -ENOMEM;
+	}
+
+	card->func = func;
+
+	func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
+
+	sdio_claim_host(func);
+	ret = sdio_enable_func(func);
+	sdio_release_host(func);
+
+	if (ret) {
+		pr_err("%s: failed to enable function\n", __func__);
+		return -EIO;
+	}
+
+	if (mwifiex_add_card(card, &add_remove_card_sem, &sdio_ops)) {
+		pr_err("%s: add card failed\n", __func__);
+		kfree(card);
+		sdio_claim_host(func);
+		ret = sdio_disable_func(func);
+		sdio_release_host(func);
+		ret = -1;
+	}
+
+	return ret;
+}
+
+/*
+ * SDIO remove.
+ *
+ * This function removes the interface and frees up the card structure.
+ */
+static void
+mwifiex_sdio_remove(struct sdio_func *func)
+{
+	struct sdio_mmc_card *card;
+
+	pr_debug("info: SDIO func num=%d\n", func->num);
+
+	if (func) {
+		card = sdio_get_drvdata(func);
+		if (card) {
+			mwifiex_remove_card(card->adapter,
+					&add_remove_card_sem);
+			kfree(card);
+		}
+	}
+}
+
+/*
+ * SDIO suspend.
+ *
+ * Kernel needs to suspend all functions separately. Therefore all
+ * registered functions must have drivers with suspend and resume
+ * methods. Failing that the kernel simply removes the whole card.
+ *
+ * If already not suspended, this function allocates and sends a host
+ * sleep activate request to the firmware and turns off the traffic.
+ */
+static int mwifiex_sdio_suspend(struct device *dev)
+{
+	struct sdio_func *func = dev_to_sdio_func(dev);
+	struct sdio_mmc_card *card;
+	struct mwifiex_adapter *adapter = NULL;
+	mmc_pm_flag_t pm_flag = 0;
+	int hs_actived = 0;
+	int i;
+	int ret = 0;
+
+	if (func) {
+		pm_flag = sdio_get_host_pm_caps(func);
+		pr_debug("cmd: %s: suspend: PM flag = 0x%x\n",
+		       sdio_func_id(func), pm_flag);
+		if (!(pm_flag & MMC_PM_KEEP_POWER)) {
+			pr_err("%s: cannot remain alive while host is"
+				" suspended\n", sdio_func_id(func));
+			return -ENOSYS;
+		}
+
+		card = sdio_get_drvdata(func);
+		if (!card || !card->adapter) {
+			pr_err("suspend: invalid card or adapter\n");
+			return 0;
+		}
+	} else {
+		pr_err("suspend: sdio_func is not specified\n");
+		return 0;
+	}
+
+	adapter = card->adapter;
+
+	/* Enable the Host Sleep */
+	hs_actived = mwifiex_enable_hs(adapter);
+	if (hs_actived) {
+		pr_debug("cmd: suspend with MMC_PM_KEEP_POWER\n");
+		ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
+	}
+
+	/* Indicate device suspended */
+	adapter->is_suspended = true;
+
+	for (i = 0; i < adapter->priv_num; i++)
+		netif_carrier_off(adapter->priv[i]->netdev);
+
+	return ret;
+}
+
+/*
+ * SDIO resume.
+ *
+ * Kernel needs to suspend all functions separately. Therefore all
+ * registered functions must have drivers with suspend and resume
+ * methods. Failing that the kernel simply removes the whole card.
+ *
+ * If already not resumed, this function turns on the traffic and
+ * sends a host sleep cancel request to the firmware.
+ */
+static int mwifiex_sdio_resume(struct device *dev)
+{
+	struct sdio_func *func = dev_to_sdio_func(dev);
+	struct sdio_mmc_card *card;
+	struct mwifiex_adapter *adapter = NULL;
+	mmc_pm_flag_t pm_flag = 0;
+	int i;
+
+	if (func) {
+		pm_flag = sdio_get_host_pm_caps(func);
+		card = sdio_get_drvdata(func);
+		if (!card || !card->adapter) {
+			pr_err("resume: invalid card or adapter\n");
+			return 0;
+		}
+	} else {
+		pr_err("resume: sdio_func is not specified\n");
+		return 0;
+	}
+
+	adapter = card->adapter;
+
+	if (!adapter->is_suspended) {
+		dev_warn(adapter->dev, "device already resumed\n");
+		return 0;
+	}
+
+	adapter->is_suspended = false;
+
+	for (i = 0; i < adapter->priv_num; i++)
+		if (adapter->priv[i]->media_connected)
+			netif_carrier_on(adapter->priv[i]->netdev);
+
+	/* Disable Host Sleep */
+	mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA),
+			      MWIFIEX_NO_WAIT);
+
+	return 0;
+}
+
+/* Device ID for SD8787 */
+#define SDIO_DEVICE_ID_MARVELL_8787   (0x9119)
+
+/* WLAN IDs */
+static const struct sdio_device_id mwifiex_ids[] = {
+	{SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8787)},
+	{},
+};
+
+MODULE_DEVICE_TABLE(sdio, mwifiex_ids);
+
+static const struct dev_pm_ops mwifiex_sdio_pm_ops = {
+	.suspend = mwifiex_sdio_suspend,
+	.resume = mwifiex_sdio_resume,
+};
+
+static struct sdio_driver mwifiex_sdio = {
+	.name = "mwifiex_sdio",
+	.id_table = mwifiex_ids,
+	.probe = mwifiex_sdio_probe,
+	.remove = mwifiex_sdio_remove,
+	.drv = {
+		.owner = THIS_MODULE,
+		.pm = &mwifiex_sdio_pm_ops,
+	}
+};
+
+/*
+ * This function writes data into SDIO card register.
+ */
+static int
+mwifiex_write_reg(struct mwifiex_adapter *adapter, u32 reg, u32 data)
+{
+	struct sdio_mmc_card *card = adapter->card;
+	int ret = -1;
+
+	sdio_claim_host(card->func);
+	sdio_writeb(card->func, (u8) data, reg, &ret);
+	sdio_release_host(card->func);
+
+	return ret;
+}
+
+/*
+ * This function reads data from SDIO card register.
+ */
+static int
+mwifiex_read_reg(struct mwifiex_adapter *adapter, u32 reg, u32 *data)
+{
+	struct sdio_mmc_card *card = adapter->card;
+	int ret = -1;
+	u8 val;
+
+	sdio_claim_host(card->func);
+	val = sdio_readb(card->func, reg, &ret);
+	sdio_release_host(card->func);
+
+	*data = val;
+
+	return ret;
+}
+
+/*
+ * This function writes multiple data into SDIO card memory.
+ *
+ * This does not work in suspended mode.
+ */
+static int
+mwifiex_write_data_sync(struct mwifiex_adapter *adapter,
+			u8 *buffer, u32 pkt_len, u32 port, u32 timeout)
+{
+	struct sdio_mmc_card *card = adapter->card;
+	int ret = -1;
+	u8 blk_mode =
+		(port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE;
+	u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1;
+	u32 blk_cnt =
+		(blk_mode ==
+		 BLOCK_MODE) ? (pkt_len /
+				MWIFIEX_SDIO_BLOCK_SIZE) : pkt_len;
+	u32 ioport = (port & MWIFIEX_SDIO_IO_PORT_MASK);
+
+	if (adapter->is_suspended) {
+		dev_err(adapter->dev,
+			"%s: not allowed while suspended\n", __func__);
+		return -1;
+	}
+
+	sdio_claim_host(card->func);
+
+	if (!sdio_writesb(card->func, ioport, buffer, blk_cnt * blk_size))
+		ret = 0;
+
+	sdio_release_host(card->func);
+
+	return ret;
+}
+
+/*
+ * This function reads multiple data from SDIO card memory.
+ */
+static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter,
+				  u8 *buffer, u32 len,
+		       u32 port, u32 timeout, u8 claim)
+{
+	struct sdio_mmc_card *card = adapter->card;
+	int ret = -1;
+	u8 blk_mode =
+		(port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE;
+	u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1;
+	u32 blk_cnt =
+		(blk_mode ==
+		 BLOCK_MODE) ? (len / MWIFIEX_SDIO_BLOCK_SIZE) : len;
+	u32 ioport = (port & MWIFIEX_SDIO_IO_PORT_MASK);
+
+	if (claim)
+		sdio_claim_host(card->func);
+
+	if (!sdio_readsb(card->func, buffer, ioport, blk_cnt * blk_size))
+		ret = 0;
+
+	if (claim)
+		sdio_release_host(card->func);
+
+	return ret;
+}
+
+/*
+ * This function wakes up the card.
+ *
+ * A host power up command is written to the card configuration
+ * register to wake up the card.
+ */
+static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
+{
+	int ret;
+
+	dev_dbg(adapter->dev, "event: wakeup device...\n");
+	ret = mwifiex_write_reg(adapter, CONFIGURATION_REG, HOST_POWER_UP);
+
+	return ret;
+}
+
+/*
+ * This function is called after the card has woken up.
+ *
+ * The card configuration register is reset.
+ */
+static int mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter)
+{
+	int ret;
+
+	dev_dbg(adapter->dev, "cmd: wakeup device completed\n");
+	ret = mwifiex_write_reg(adapter, CONFIGURATION_REG, 0);
+
+	return ret;
+}
+
+/*
+ * This function initializes the IO ports.
+ *
+ * The following operations are performed -
+ *      - Read the IO ports (0, 1 and 2)
+ *      - Set host interrupt Reset-To-Read to clear
+ *      - Set auto re-enable interrupt
+ */
+static int mwifiex_init_sdio_ioport(struct mwifiex_adapter *adapter)
+{
+	u32 reg;
+
+	adapter->ioport = 0;
+
+	/* Read the IO port */
+	if (!mwifiex_read_reg(adapter, IO_PORT_0_REG, &reg))
+		adapter->ioport |= (reg & 0xff);
+	else
+		return -1;
+
+	if (!mwifiex_read_reg(adapter, IO_PORT_1_REG, &reg))
+		adapter->ioport |= ((reg & 0xff) << 8);
+	else
+		return -1;
+
+	if (!mwifiex_read_reg(adapter, IO_PORT_2_REG, &reg))
+		adapter->ioport |= ((reg & 0xff) << 16);
+	else
+		return -1;
+
+	pr_debug("info: SDIO FUNC1 IO port: %#x\n", adapter->ioport);
+
+	/* Set Host interrupt reset to read to clear */
+	if (!mwifiex_read_reg(adapter, HOST_INT_RSR_REG, &reg))
+		mwifiex_write_reg(adapter, HOST_INT_RSR_REG,
+				  reg | SDIO_INT_MASK);
+	else
+		return -1;
+
+	/* Dnld/Upld ready set to auto reset */
+	if (!mwifiex_read_reg(adapter, CARD_MISC_CFG_REG, &reg))
+		mwifiex_write_reg(adapter, CARD_MISC_CFG_REG,
+				  reg | AUTO_RE_ENABLE_INT);
+	else
+		return -1;
+
+	return 0;
+}
+
+/*
+ * This function sends data to the card.
+ */
+static int mwifiex_write_data_to_card(struct mwifiex_adapter *adapter,
+				      u8 *payload, u32 pkt_len, u32 port)
+{
+	u32 i = 0;
+	int ret = 0;
+
+	do {
+		ret = mwifiex_write_data_sync(adapter, payload, pkt_len,
+								port, 0);
+		if (ret) {
+			i++;
+			dev_err(adapter->dev, "host_to_card, write iomem"
+					" (%d) failed: %d\n", i, ret);
+			if (mwifiex_write_reg(adapter,
+					CONFIGURATION_REG, 0x04))
+				dev_err(adapter->dev, "write CFG reg failed\n");
+
+			ret = -1;
+			if (i > MAX_WRITE_IOMEM_RETRY)
+				return ret;
+		}
+	} while (ret == -1);
+
+	return ret;
+}
+
+/*
+ * This function gets the read port.
+ *
+ * If control port bit is set in MP read bitmap, the control port
+ * is returned, otherwise the current read port is returned and
+ * the value is increased (provided it does not reach the maximum
+ * limit, in which case it is reset to 1)
+ */
+static int mwifiex_get_rd_port(struct mwifiex_adapter *adapter, u8 *port)
+{
+	struct sdio_mmc_card *card = adapter->card;
+	u16 rd_bitmap = card->mp_rd_bitmap;
+
+	dev_dbg(adapter->dev, "data: mp_rd_bitmap=0x%04x\n", rd_bitmap);
+
+	if (!(rd_bitmap & (CTRL_PORT_MASK | DATA_PORT_MASK)))
+		return -1;
+
+	if (card->mp_rd_bitmap & CTRL_PORT_MASK) {
+		card->mp_rd_bitmap &= (u16) (~CTRL_PORT_MASK);
+		*port = CTRL_PORT;
+		dev_dbg(adapter->dev, "data: port=%d mp_rd_bitmap=0x%04x\n",
+		       *port, card->mp_rd_bitmap);
+	} else {
+		if (card->mp_rd_bitmap & (1 << card->curr_rd_port)) {
+			card->mp_rd_bitmap &=
+				(u16) (~(1 << card->curr_rd_port));
+			*port = card->curr_rd_port;
+
+			if (++card->curr_rd_port == MAX_PORT)
+				card->curr_rd_port = 1;
+		} else {
+			return -1;
+		}
+
+		dev_dbg(adapter->dev,
+			"data: port=%d mp_rd_bitmap=0x%04x -> 0x%04x\n",
+		       *port, rd_bitmap, card->mp_rd_bitmap);
+	}
+	return 0;
+}
+
+/*
+ * This function gets the write port for data.
+ *
+ * The current write port is returned if available and the value is
+ * increased (provided it does not reach the maximum limit, in which
+ * case it is reset to 1)
+ */
+static int mwifiex_get_wr_port_data(struct mwifiex_adapter *adapter, u8 *port)
+{
+	struct sdio_mmc_card *card = adapter->card;
+	u16 wr_bitmap = card->mp_wr_bitmap;
+
+	dev_dbg(adapter->dev, "data: mp_wr_bitmap=0x%04x\n", wr_bitmap);
+
+	if (!(wr_bitmap & card->mp_data_port_mask))
+		return -1;
+
+	if (card->mp_wr_bitmap & (1 << card->curr_wr_port)) {
+		card->mp_wr_bitmap &= (u16) (~(1 << card->curr_wr_port));
+		*port = card->curr_wr_port;
+		if (++card->curr_wr_port == card->mp_end_port)
+			card->curr_wr_port = 1;
+	} else {
+		adapter->data_sent = true;
+		return -EBUSY;
+	}
+
+	if (*port == CTRL_PORT) {
+		dev_err(adapter->dev, "invalid data port=%d cur port=%d"
+				" mp_wr_bitmap=0x%04x -> 0x%04x\n",
+				*port, card->curr_wr_port, wr_bitmap,
+				card->mp_wr_bitmap);
+		return -1;
+	}
+
+	dev_dbg(adapter->dev, "data: port=%d mp_wr_bitmap=0x%04x -> 0x%04x\n",
+	       *port, wr_bitmap, card->mp_wr_bitmap);
+
+	return 0;
+}
+
+/*
+ * This function polls the card status.
+ */
+static int
+mwifiex_sdio_poll_card_status(struct mwifiex_adapter *adapter, u8 bits)
+{
+	u32 tries;
+	u32 cs = 0;
+
+	for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
+		if (mwifiex_read_reg(adapter, CARD_STATUS_REG, &cs))
+			break;
+		else if ((cs & bits) == bits)
+			return 0;
+
+		udelay(10);
+	}
+
+	dev_err(adapter->dev, "poll card status failed, tries = %d\n",
+	       tries);
+	return -1;
+}
+
+/*
+ * This function reads the firmware status.
+ */
+static int
+mwifiex_sdio_read_fw_status(struct mwifiex_adapter *adapter, u16 *dat)
+{
+	u32 fws0 = 0, fws1 = 0;
+
+	if (mwifiex_read_reg(adapter, CARD_FW_STATUS0_REG, &fws0))
+		return -1;
+
+	if (mwifiex_read_reg(adapter, CARD_FW_STATUS1_REG, &fws1))
+		return -1;
+
+	*dat = (u16) ((fws1 << 8) | fws0);
+
+	return 0;
+}
+
+/*
+ * This function disables the host interrupt.
+ *
+ * The host interrupt mask is read, the disable bit is reset and
+ * written back to the card host interrupt mask register.
+ */
+static int mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter)
+{
+	u32 host_int_mask = 0;
+
+	/* Read back the host_int_mask register */
+	if (mwifiex_read_reg(adapter, HOST_INT_MASK_REG, &host_int_mask))
+		return -1;
+
+	/* Update with the mask and write back to the register */
+	host_int_mask &= ~HOST_INT_DISABLE;
+
+	if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, host_int_mask)) {
+		dev_err(adapter->dev, "disable host interrupt failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * This function enables the host interrupt.
+ *
+ * The host interrupt enable mask is written to the card
+ * host interrupt mask register.
+ */
+static int mwifiex_sdio_enable_host_int(struct mwifiex_adapter *adapter)
+{
+	/* Simply write the mask to the register */
+	if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, HOST_INT_ENABLE)) {
+		dev_err(adapter->dev, "enable host interrupt failed\n");
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ * This function sends a data buffer to the card.
+ */
+static int mwifiex_sdio_card_to_host(struct mwifiex_adapter *adapter,
+				     u32 *type, u8 *buffer,
+				     u32 npayload, u32 ioport)
+{
+	int ret = 0;
+	u32 nb;
+
+	if (!buffer) {
+		dev_err(adapter->dev, "%s: buffer is NULL\n", __func__);
+		return -1;
+	}
+
+	ret = mwifiex_read_data_sync(adapter, buffer, npayload, ioport, 0, 1);
+
+	if (ret) {
+		dev_err(adapter->dev, "%s: read iomem failed: %d\n", __func__,
+				ret);
+		return -1;
+	}
+
+	nb = le16_to_cpu(*(__le16 *) (buffer));
+	if (nb > npayload) {
+		dev_err(adapter->dev, "%s: invalid packet, nb=%d, npayload=%d\n",
+				__func__, nb, npayload);
+		return -1;
+	}
+
+	*type = le16_to_cpu(*(__le16 *) (buffer + 2));
+
+	return ret;
+}
+
+/*
+ * This function downloads the firmware to the card.
+ *
+ * Firmware is downloaded to the card in blocks. Every block download
+ * is tested for CRC errors, and retried a number of times before
+ * returning failure.
+ */
+static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
+				    struct mwifiex_fw_image *fw)
+{
+	int ret = 0;
+	u8 *firmware = fw->fw_buf;
+	u32 firmware_len = fw->fw_len;
+	u32 offset = 0;
+	u32 base0, base1;
+	u8 *fwbuf;
+	u16 len = 0;
+	u32 txlen = 0, tx_blocks = 0, tries = 0;
+	u32 i = 0;
+
+	if (!firmware_len) {
+		dev_err(adapter->dev, "firmware image not found!"
+				" Terminating download\n");
+		return -1;
+	}
+
+	dev_dbg(adapter->dev, "info: downloading FW image (%d bytes)\n",
+			firmware_len);
+
+	/* Assume that the allocated buffer is 8-byte aligned */
+	fwbuf = kzalloc(MWIFIEX_UPLD_SIZE, GFP_KERNEL);
+	if (!fwbuf) {
+		dev_err(adapter->dev, "unable to alloc buffer for firmware."
+				" Terminating download\n");
+		return -1;
+	}
+
+	/* Perform firmware data transfer */
+	do {
+		/* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY
+		   bits */
+		ret = mwifiex_sdio_poll_card_status(adapter, CARD_IO_READY |
+						    DN_LD_CARD_RDY);
+		if (ret) {
+			dev_err(adapter->dev, "FW download with helper:"
+					" poll status timeout @ %d\n", offset);
+			goto done;
+		}
+
+		/* More data? */
+		if (offset >= firmware_len)
+			break;
+
+		for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
+			ret = mwifiex_read_reg(adapter, HOST_F1_RD_BASE_0,
+					       &base0);
+			if (ret) {
+				dev_err(adapter->dev, "dev BASE0 register read"
+					" failed: base0=0x%04X(%d). Terminating "
+				       "download\n", base0, base0);
+				goto done;
+			}
+			ret = mwifiex_read_reg(adapter, HOST_F1_RD_BASE_1,
+					       &base1);
+			if (ret) {
+				dev_err(adapter->dev, "dev BASE1 register read"
+					" failed: base1=0x%04X(%d). Terminating "
+				       "download\n", base1, base1);
+				goto done;
+			}
+			len = (u16) (((base1 & 0xff) << 8) | (base0 & 0xff));
+
+			if (len)
+				break;
+
+			udelay(10);
+		}
+
+		if (!len) {
+			break;
+		} else if (len > MWIFIEX_UPLD_SIZE) {
+			dev_err(adapter->dev, "FW download failed @ %d,"
+				" invalid length %d\n", offset, len);
+			ret = -1;
+			goto done;
+		}
+
+		txlen = len;
+
+		if (len & BIT(0)) {
+			i++;
+			if (i > MAX_WRITE_IOMEM_RETRY) {
+				dev_err(adapter->dev, "FW download failed @"
+					" %d, over max retry count\n", offset);
+				ret = -1;
+				goto done;
+			}
+			dev_err(adapter->dev, "CRC indicated by the helper:"
+			       " len = 0x%04X, txlen = %d\n", len, txlen);
+			len &= ~BIT(0);
+			/* Setting this to 0 to resend from same offset */
+			txlen = 0;
+		} else {
+			i = 0;
+
+			/* Set blocksize to transfer - checking for last
+			   block */
+			if (firmware_len - offset < txlen)
+				txlen = firmware_len - offset;
+
+			tx_blocks = (txlen + MWIFIEX_SDIO_BLOCK_SIZE -
+					1) / MWIFIEX_SDIO_BLOCK_SIZE;
+
+			/* Copy payload to buffer */
+			memmove(fwbuf, &firmware[offset], txlen);
+		}
+
+		ret = mwifiex_write_data_sync(adapter, fwbuf, tx_blocks *
+					      MWIFIEX_SDIO_BLOCK_SIZE,
+					      adapter->ioport, 0);
+		if (ret) {
+			dev_err(adapter->dev, "FW download, write iomem (%d)"
+					" failed @ %d\n", i, offset);
+			if (mwifiex_write_reg(adapter, CONFIGURATION_REG, 0x04))
+				dev_err(adapter->dev, "write CFG reg failed\n");
+
+			ret = -1;
+			goto done;
+		}
+
+		offset += txlen;
+	} while (true);
+
+	dev_dbg(adapter->dev, "info: FW download over, size %d bytes\n",
+						offset);
+
+	ret = 0;
+done:
+	kfree(fwbuf);
+	return ret;
+}
+
+/*
+ * This function checks the firmware status in card.
+ *
+ * The winner interface is also determined by this function.
+ */
+static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter,
+				   u32 poll_num, int *winner)
+{
+	int ret = 0;
+	u16 firmware_stat;
+	u32 tries;
+	u32 winner_status;
+
+	/* Wait for firmware initialization event */
+	for (tries = 0; tries < poll_num; tries++) {
+		ret = mwifiex_sdio_read_fw_status(adapter, &firmware_stat);
+		if (ret)
+			continue;
+		if (firmware_stat == FIRMWARE_READY) {
+			ret = 0;
+			break;
+		} else {
+			mdelay(100);
+			ret = -1;
+		}
+	}
+
+	if (winner && ret) {
+		if (mwifiex_read_reg
+		    (adapter, CARD_FW_STATUS0_REG, &winner_status))
+			winner_status = 0;
+
+		if (winner_status)
+			*winner = 0;
+		else
+			*winner = 1;
+	}
+	return ret;
+}
+
+/*
+ * This function reads the interrupt status from card.
+ */
+static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
+{
+	struct sdio_mmc_card *card = adapter->card;
+	u32 sdio_ireg = 0;
+	unsigned long flags;
+
+	if (mwifiex_read_data_sync(adapter, card->mp_regs, MAX_MP_REGS,
+				   REG_PORT | MWIFIEX_SDIO_BYTE_MODE_MASK, 0,
+				   0)) {
+		dev_err(adapter->dev, "read mp_regs failed\n");
+		return;
+	}
+
+	sdio_ireg = card->mp_regs[HOST_INTSTATUS_REG];
+	if (sdio_ireg) {
+		/*
+		 * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
+		 * Clear the interrupt status register
+		 */
+		dev_dbg(adapter->dev, "int: sdio_ireg = %#x\n", sdio_ireg);
+		spin_lock_irqsave(&adapter->int_lock, flags);
+		adapter->int_status |= sdio_ireg;
+		spin_unlock_irqrestore(&adapter->int_lock, flags);
+	}
+
+	return;
+}
+
+/*
+ * SDIO interrupt handler.
+ *
+ * This function reads the interrupt status from firmware and assigns
+ * the main process in workqueue which will handle the interrupt.
+ */
+static void
+mwifiex_sdio_interrupt(struct sdio_func *func)
+{
+	struct mwifiex_adapter *adapter;
+	struct sdio_mmc_card *card;
+
+	card = sdio_get_drvdata(func);
+	if (!card || !card->adapter) {
+		pr_debug("int: func=%p card=%p adapter=%p\n",
+		       func, card, card ? card->adapter : NULL);
+		return;
+	}
+	adapter = card->adapter;
+
+	if (adapter->surprise_removed)
+		return;
+
+	if (!adapter->pps_uapsd_mode && adapter->ps_state == PS_STATE_SLEEP)
+		adapter->ps_state = PS_STATE_AWAKE;
+
+	mwifiex_interrupt_status(adapter);
+	queue_work(adapter->workqueue, &adapter->main_work);
+
+	return;
+}
+
+/*
+ * This function decodes a received packet.
+ *
+ * Based on the type, the packet is treated as either a data, or
+ * a command response, or an event, and the correct handler
+ * function is invoked.
+ */
+static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter,
+				    struct sk_buff *skb, u32 upld_typ)
+{
+	u8 *cmd_buf;
+
+	skb_pull(skb, INTF_HEADER_LEN);
+
+	switch (upld_typ) {
+	case MWIFIEX_TYPE_DATA:
+		dev_dbg(adapter->dev, "info: --- Rx: Data packet ---\n");
+		mwifiex_handle_rx_packet(adapter, skb);
+		break;
+
+	case MWIFIEX_TYPE_CMD:
+		dev_dbg(adapter->dev, "info: --- Rx: Cmd Response ---\n");
+		/* take care of curr_cmd = NULL case */
+		if (!adapter->curr_cmd) {
+			cmd_buf = adapter->upld_buf;
+
+			if (adapter->ps_state == PS_STATE_SLEEP_CFM)
+				mwifiex_process_sleep_confirm_resp(adapter,
+							skb->data, skb->len);
+
+			memcpy(cmd_buf, skb->data, min_t(u32,
+				       MWIFIEX_SIZE_OF_CMD_BUFFER, skb->len));
+
+			dev_kfree_skb_any(skb);
+		} else {
+			adapter->cmd_resp_received = true;
+			adapter->curr_cmd->resp_skb = skb;
+		}
+		break;
+
+	case MWIFIEX_TYPE_EVENT:
+		dev_dbg(adapter->dev, "info: --- Rx: Event ---\n");
+		adapter->event_cause = *(u32 *) skb->data;
+
+		skb_pull(skb, MWIFIEX_EVENT_HEADER_LEN);
+
+		if ((skb->len > 0) && (skb->len  < MAX_EVENT_SIZE))
+			memcpy(adapter->event_body, skb->data, skb->len);
+
+		/* event cause has been saved to adapter->event_cause */
+		adapter->event_received = true;
+		adapter->event_skb = skb;
+
+		break;
+
+	default:
+		dev_err(adapter->dev, "unknown upload type %#x\n", upld_typ);
+		dev_kfree_skb_any(skb);
+		break;
+	}
+
+	return 0;
+}
+
+/*
+ * This function transfers received packets from card to driver, performing
+ * aggregation if required.
+ *
+ * For data received on control port, or if aggregation is disabled, the
+ * received buffers are uploaded as separate packets. However, if aggregation
+ * is enabled and required, the buffers are copied onto an aggregation buffer,
+ * provided there is space left, processed and finally uploaded.
+ */
+static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter,
+					     struct sk_buff *skb, u8 port)
+{
+	struct sdio_mmc_card *card = adapter->card;
+	s32 f_do_rx_aggr = 0;
+	s32 f_do_rx_cur = 0;
+	s32 f_aggr_cur = 0;
+	struct sk_buff *skb_deaggr;
+	u32 pind = 0;
+	u32 pkt_len, pkt_type = 0;
+	u8 *curr_ptr;
+	u32 rx_len = skb->len;
+
+	if (port == CTRL_PORT) {
+		/* Read the command Resp without aggr */
+		dev_dbg(adapter->dev, "info: %s: no aggregation for cmd "
+				"response\n", __func__);
+
+		f_do_rx_cur = 1;
+		goto rx_curr_single;
+	}
+
+	if (!card->mpa_rx.enabled) {
+		dev_dbg(adapter->dev, "info: %s: rx aggregation disabled\n",
+						__func__);
+
+		f_do_rx_cur = 1;
+		goto rx_curr_single;
+	}
+
+	if (card->mp_rd_bitmap & (~((u16) CTRL_PORT_MASK))) {
+		/* Some more data RX pending */
+		dev_dbg(adapter->dev, "info: %s: not last packet\n", __func__);
+
+		if (MP_RX_AGGR_IN_PROGRESS(card)) {
+			if (MP_RX_AGGR_BUF_HAS_ROOM(card, skb->len)) {
+				f_aggr_cur = 1;
+			} else {
+				/* No room in Aggr buf, do rx aggr now */
+				f_do_rx_aggr = 1;
+				f_do_rx_cur = 1;
+			}
+		} else {
+			/* Rx aggr not in progress */
+			f_aggr_cur = 1;
+		}
+
+	} else {
+		/* No more data RX pending */
+		dev_dbg(adapter->dev, "info: %s: last packet\n", __func__);
+
+		if (MP_RX_AGGR_IN_PROGRESS(card)) {
+			f_do_rx_aggr = 1;
+			if (MP_RX_AGGR_BUF_HAS_ROOM(card, skb->len))
+				f_aggr_cur = 1;
+			else
+				/* No room in Aggr buf, do rx aggr now */
+				f_do_rx_cur = 1;
+		} else {
+			f_do_rx_cur = 1;
+		}
+	}
+
+	if (f_aggr_cur) {
+		dev_dbg(adapter->dev, "info: current packet aggregation\n");
+		/* Curr pkt can be aggregated */
+		MP_RX_AGGR_SETUP(card, skb, port);
+
+		if (MP_RX_AGGR_PKT_LIMIT_REACHED(card) ||
+		    MP_RX_AGGR_PORT_LIMIT_REACHED(card)) {
+			dev_dbg(adapter->dev, "info: %s: aggregated packet "
+					"limit reached\n", __func__);
+			/* No more pkts allowed in Aggr buf, rx it */
+			f_do_rx_aggr = 1;
+		}
+	}
+
+	if (f_do_rx_aggr) {
+		/* do aggr RX now */
+		dev_dbg(adapter->dev, "info: do_rx_aggr: num of packets: %d\n",
+		       card->mpa_rx.pkt_cnt);
+
+		if (mwifiex_read_data_sync(adapter, card->mpa_rx.buf,
+					   card->mpa_rx.buf_len,
+					   (adapter->ioport | 0x1000 |
+					    (card->mpa_rx.ports << 4)) +
+					   card->mpa_rx.start_port, 0, 1))
+			return -1;
+
+		curr_ptr = card->mpa_rx.buf;
+
+		for (pind = 0; pind < card->mpa_rx.pkt_cnt; pind++) {
+
+			/* get curr PKT len & type */
+			pkt_len = *(u16 *) &curr_ptr[0];
+			pkt_type = *(u16 *) &curr_ptr[2];
+
+			/* copy pkt to deaggr buf */
+			skb_deaggr = card->mpa_rx.skb_arr[pind];
+
+			if ((pkt_type == MWIFIEX_TYPE_DATA) && (pkt_len <=
+					 card->mpa_rx.len_arr[pind])) {
+
+				memcpy(skb_deaggr->data, curr_ptr, pkt_len);
+
+				skb_trim(skb_deaggr, pkt_len);
+
+				/* Process de-aggr packet */
+				mwifiex_decode_rx_packet(adapter, skb_deaggr,
+							 pkt_type);
+			} else {
+				dev_err(adapter->dev, "wrong aggr pkt:"
+					" type=%d len=%d max_len=%d\n",
+					pkt_type, pkt_len,
+					card->mpa_rx.len_arr[pind]);
+				dev_kfree_skb_any(skb_deaggr);
+			}
+			curr_ptr += card->mpa_rx.len_arr[pind];
+		}
+		MP_RX_AGGR_BUF_RESET(card);
+	}
+
+rx_curr_single:
+	if (f_do_rx_cur) {
+		dev_dbg(adapter->dev, "info: RX: port: %d, rx_len: %d\n",
+			port, rx_len);
+
+		if (mwifiex_sdio_card_to_host(adapter, &pkt_type,
+					      skb->data, skb->len,
+					      adapter->ioport + port))
+			return -1;
+
+		mwifiex_decode_rx_packet(adapter, skb, pkt_type);
+	}
+
+	return 0;
+}
+
+/*
+ * This function checks the current interrupt status.
+ *
+ * The following interrupts are checked and handled by this function -
+ *      - Data sent
+ *      - Command sent
+ *      - Packets received
+ *
+ * Since the firmware does not generate download ready interrupt if the
+ * port updated is command port only, command sent interrupt checking
+ * should be done manually, and for every SDIO interrupt.
+ *
+ * In case of Rx packets received, the packets are uploaded from card to
+ * host and processed accordingly.
+ */
+static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
+{
+	struct sdio_mmc_card *card = adapter->card;
+	int ret = 0;
+	u8 sdio_ireg;
+	struct sk_buff *skb = NULL;
+	u8 port = CTRL_PORT;
+	u32 len_reg_l, len_reg_u;
+	u32 rx_blocks;
+	u16 rx_len;
+	unsigned long flags;
+
+	spin_lock_irqsave(&adapter->int_lock, flags);
+	sdio_ireg = adapter->int_status;
+	adapter->int_status = 0;
+	spin_unlock_irqrestore(&adapter->int_lock, flags);
+
+	if (!sdio_ireg)
+		return ret;
+
+	if (sdio_ireg & DN_LD_HOST_INT_STATUS) {
+		card->mp_wr_bitmap = ((u16) card->mp_regs[WR_BITMAP_U]) << 8;
+		card->mp_wr_bitmap |= (u16) card->mp_regs[WR_BITMAP_L];
+		dev_dbg(adapter->dev, "int: DNLD: wr_bitmap=0x%04x\n",
+				card->mp_wr_bitmap);
+		if (adapter->data_sent &&
+		    (card->mp_wr_bitmap & card->mp_data_port_mask)) {
+			dev_dbg(adapter->dev,
+				"info:  <--- Tx DONE Interrupt --->\n");
+			adapter->data_sent = false;
+		}
+	}
+
+	/* As firmware will not generate download ready interrupt if the port
+	   updated is command port only, cmd_sent should be done for any SDIO
+	   interrupt. */
+	if (adapter->cmd_sent) {
+		/* Check if firmware has attach buffer at command port and
+		   update just that in wr_bit_map. */
+		card->mp_wr_bitmap |=
+			(u16) card->mp_regs[WR_BITMAP_L] & CTRL_PORT_MASK;
+		if (card->mp_wr_bitmap & CTRL_PORT_MASK)
+			adapter->cmd_sent = false;
+	}
+
+	dev_dbg(adapter->dev, "info: cmd_sent=%d data_sent=%d\n",
+	       adapter->cmd_sent, adapter->data_sent);
+	if (sdio_ireg & UP_LD_HOST_INT_STATUS) {
+		card->mp_rd_bitmap = ((u16) card->mp_regs[RD_BITMAP_U]) << 8;
+		card->mp_rd_bitmap |= (u16) card->mp_regs[RD_BITMAP_L];
+		dev_dbg(adapter->dev, "int: UPLD: rd_bitmap=0x%04x\n",
+				card->mp_rd_bitmap);
+
+		while (true) {
+			ret = mwifiex_get_rd_port(adapter, &port);
+			if (ret) {
+				dev_dbg(adapter->dev,
+					"info: no more rd_port available\n");
+				break;
+			}
+			len_reg_l = RD_LEN_P0_L + (port << 1);
+			len_reg_u = RD_LEN_P0_U + (port << 1);
+			rx_len = ((u16) card->mp_regs[len_reg_u]) << 8;
+			rx_len |= (u16) card->mp_regs[len_reg_l];
+			dev_dbg(adapter->dev, "info: RX: port=%d rx_len=%u\n",
+					port, rx_len);
+			rx_blocks =
+				(rx_len + MWIFIEX_SDIO_BLOCK_SIZE -
+				 1) / MWIFIEX_SDIO_BLOCK_SIZE;
+			if (rx_len <= INTF_HEADER_LEN
+			    || (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE) >
+			    MWIFIEX_RX_DATA_BUF_SIZE) {
+				dev_err(adapter->dev, "invalid rx_len=%d\n",
+						rx_len);
+				return -1;
+			}
+			rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE);
+
+			skb = dev_alloc_skb(rx_len);
+
+			if (!skb) {
+				dev_err(adapter->dev, "%s: failed to alloc skb",
+								__func__);
+				return -1;
+			}
+
+			skb_put(skb, rx_len);
+
+			dev_dbg(adapter->dev, "info: rx_len = %d skb->len = %d\n",
+					rx_len, skb->len);
+
+			if (mwifiex_sdio_card_to_host_mp_aggr(adapter, skb,
+							      port)) {
+				u32 cr = 0;
+
+				dev_err(adapter->dev, "card_to_host_mpa failed:"
+						" int status=%#x\n", sdio_ireg);
+				if (mwifiex_read_reg(adapter,
+						     CONFIGURATION_REG, &cr))
+					dev_err(adapter->dev,
+							"read CFG reg failed\n");
+
+				dev_dbg(adapter->dev,
+						"info: CFG reg val = %d\n", cr);
+				if (mwifiex_write_reg(adapter,
+						      CONFIGURATION_REG,
+						      (cr | 0x04)))
+					dev_err(adapter->dev,
+							"write CFG reg failed\n");
+
+				dev_dbg(adapter->dev, "info: write success\n");
+				if (mwifiex_read_reg(adapter,
+						     CONFIGURATION_REG, &cr))
+					dev_err(adapter->dev,
+							"read CFG reg failed\n");
+
+				dev_dbg(adapter->dev,
+						"info: CFG reg val =%x\n", cr);
+				dev_kfree_skb_any(skb);
+				return -1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * This function aggregates transmission buffers in driver and downloads
+ * the aggregated packet to card.
+ *
+ * The individual packets are aggregated by copying into an aggregation
+ * buffer and then downloaded to the card. Previous unsent packets in the
+ * aggregation buffer are pre-copied first before new packets are added.
+ * Aggregation is done till there is space left in the aggregation buffer,
+ * or till new packets are available.
+ *
+ * The function will only download the packet to the card when aggregation
+ * stops, otherwise it will just aggregate the packet in aggregation buffer
+ * and return.
+ */
+static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter,
+					u8 *payload, u32 pkt_len, u8 port,
+					u32 next_pkt_len)
+{
+	struct sdio_mmc_card *card = adapter->card;
+	int ret = 0;
+	s32 f_send_aggr_buf = 0;
+	s32 f_send_cur_buf = 0;
+	s32 f_precopy_cur_buf = 0;
+	s32 f_postcopy_cur_buf = 0;
+
+	if ((!card->mpa_tx.enabled) || (port == CTRL_PORT)) {
+		dev_dbg(adapter->dev, "info: %s: tx aggregation disabled\n",
+						__func__);
+
+		f_send_cur_buf = 1;
+		goto tx_curr_single;
+	}
+
+	if (next_pkt_len) {
+		/* More pkt in TX queue */
+		dev_dbg(adapter->dev, "info: %s: more packets in queue.\n",
+						__func__);
+
+		if (MP_TX_AGGR_IN_PROGRESS(card)) {
+			if (!MP_TX_AGGR_PORT_LIMIT_REACHED(card) &&
+			    MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) {
+				f_precopy_cur_buf = 1;
+
+				if (!(card->mp_wr_bitmap &
+						(1 << card->curr_wr_port))
+						|| !MP_TX_AGGR_BUF_HAS_ROOM(
+							card, next_pkt_len))
+					f_send_aggr_buf = 1;
+			} else {
+				/* No room in Aggr buf, send it */
+				f_send_aggr_buf = 1;
+
+				if (MP_TX_AGGR_PORT_LIMIT_REACHED(card) ||
+				    !(card->mp_wr_bitmap &
+				      (1 << card->curr_wr_port)))
+					f_send_cur_buf = 1;
+				else
+					f_postcopy_cur_buf = 1;
+			}
+		} else {
+			if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)
+			    && (card->mp_wr_bitmap & (1 << card->curr_wr_port)))
+				f_precopy_cur_buf = 1;
+			else
+				f_send_cur_buf = 1;
+		}
+	} else {
+		/* Last pkt in TX queue */
+		dev_dbg(adapter->dev, "info: %s: Last packet in Tx Queue.\n",
+						__func__);
+
+		if (MP_TX_AGGR_IN_PROGRESS(card)) {
+			/* some packs in Aggr buf already */
+			f_send_aggr_buf = 1;
+
+			if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len))
+				f_precopy_cur_buf = 1;
+			else
+				/* No room in Aggr buf, send it */
+				f_send_cur_buf = 1;
+		} else {
+			f_send_cur_buf = 1;
+		}
+	}
+
+	if (f_precopy_cur_buf) {
+		dev_dbg(adapter->dev, "data: %s: precopy current buffer\n",
+						__func__);
+		MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port);
+
+		if (MP_TX_AGGR_PKT_LIMIT_REACHED(card) ||
+		    MP_TX_AGGR_PORT_LIMIT_REACHED(card))
+			/* No more pkts allowed in Aggr buf, send it */
+			f_send_aggr_buf = 1;
+	}
+
+	if (f_send_aggr_buf) {
+		dev_dbg(adapter->dev, "data: %s: send aggr buffer: %d %d\n",
+				__func__,
+				card->mpa_tx.start_port, card->mpa_tx.ports);
+		ret = mwifiex_write_data_to_card(adapter, card->mpa_tx.buf,
+						 card->mpa_tx.buf_len,
+						 (adapter->ioport | 0x1000 |
+						 (card->mpa_tx.ports << 4)) +
+						  card->mpa_tx.start_port);
+
+		MP_TX_AGGR_BUF_RESET(card);
+	}
+
+tx_curr_single:
+	if (f_send_cur_buf) {
+		dev_dbg(adapter->dev, "data: %s: send current buffer %d\n",
+						__func__, port);
+		ret = mwifiex_write_data_to_card(adapter, payload, pkt_len,
+						 adapter->ioport + port);
+	}
+
+	if (f_postcopy_cur_buf) {
+		dev_dbg(adapter->dev, "data: %s: postcopy current buffer\n",
+						__func__);
+		MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port);
+	}
+
+	return ret;
+}
+
+/*
+ * This function downloads data from driver to card.
+ *
+ * Both commands and data packets are transferred to the card by this
+ * function.
+ *
+ * This function adds the SDIO specific header to the front of the buffer
+ * before transferring. The header contains the length of the packet and
+ * the type. The firmware handles the packets based upon this set type.
+ */
+static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter,
+				     u8 type, u8 *payload, u32 pkt_len,
+				     struct mwifiex_tx_param *tx_param)
+{
+	struct sdio_mmc_card *card = adapter->card;
+	int ret = 0;
+	u32 buf_block_len;
+	u32 blk_size;
+	u8 port = CTRL_PORT;
+
+	/* Allocate buffer and copy payload */
+	blk_size = MWIFIEX_SDIO_BLOCK_SIZE;
+	buf_block_len = (pkt_len + blk_size - 1) / blk_size;
+	*(u16 *) &payload[0] = (u16) pkt_len;
+	*(u16 *) &payload[2] = type;
+
+	/*
+	 * This is SDIO specific header
+	 *  u16 length,
+	 *  u16 type (MWIFIEX_TYPE_DATA = 0, MWIFIEX_TYPE_CMD = 1,
+	 *  MWIFIEX_TYPE_EVENT = 3)
+	 */
+	if (type == MWIFIEX_TYPE_DATA) {
+		ret = mwifiex_get_wr_port_data(adapter, &port);
+		if (ret) {
+			dev_err(adapter->dev, "%s: no wr_port available\n",
+						__func__);
+			return ret;
+		}
+	} else {
+		adapter->cmd_sent = true;
+		/* Type must be MWIFIEX_TYPE_CMD */
+
+		if (pkt_len <= INTF_HEADER_LEN ||
+		    pkt_len > MWIFIEX_UPLD_SIZE)
+			dev_err(adapter->dev, "%s: payload=%p, nb=%d\n",
+					__func__, payload, pkt_len);
+	}
+
+	/* Transfer data to card */
+	pkt_len = buf_block_len * blk_size;
+
+	if (tx_param)
+		ret = mwifiex_host_to_card_mp_aggr(adapter, payload, pkt_len,
+				port, tx_param->next_pkt_len);
+	else
+		ret = mwifiex_host_to_card_mp_aggr(adapter, payload, pkt_len,
+				port, 0);
+
+	if (ret) {
+		if (type == MWIFIEX_TYPE_CMD)
+			adapter->cmd_sent = false;
+		if (type == MWIFIEX_TYPE_DATA)
+			adapter->data_sent = false;
+	} else {
+		if (type == MWIFIEX_TYPE_DATA) {
+			if (!(card->mp_wr_bitmap & (1 << card->curr_wr_port)))
+				adapter->data_sent = true;
+			else
+				adapter->data_sent = false;
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * This function allocates the MPA Tx and Rx buffers.
+ */
+static int mwifiex_alloc_sdio_mpa_buffers(struct mwifiex_adapter *adapter,
+				   u32 mpa_tx_buf_size, u32 mpa_rx_buf_size)
+{
+	struct sdio_mmc_card *card = adapter->card;
+	int ret = 0;
+
+	card->mpa_tx.buf = kzalloc(mpa_tx_buf_size, GFP_KERNEL);
+	if (!card->mpa_tx.buf) {
+		dev_err(adapter->dev, "could not alloc buffer for MP-A TX\n");
+		ret = -1;
+		goto error;
+	}
+
+	card->mpa_tx.buf_size = mpa_tx_buf_size;
+
+	card->mpa_rx.buf = kzalloc(mpa_rx_buf_size, GFP_KERNEL);
+	if (!card->mpa_rx.buf) {
+		dev_err(adapter->dev, "could not alloc buffer for MP-A RX\n");
+		ret = -1;
+		goto error;
+	}
+
+	card->mpa_rx.buf_size = mpa_rx_buf_size;
+
+error:
+	if (ret) {
+		kfree(card->mpa_tx.buf);
+		kfree(card->mpa_rx.buf);
+	}
+
+	return ret;
+}
+
+/*
+ * This function unregisters the SDIO device.
+ *
+ * The SDIO IRQ is released, the function is disabled and driver
+ * data is set to null.
+ */
+static void
+mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
+{
+	struct sdio_mmc_card *card = adapter->card;
+
+	if (adapter->card) {
+		/* Release the SDIO IRQ */
+		sdio_claim_host(card->func);
+		sdio_release_irq(card->func);
+		sdio_disable_func(card->func);
+		sdio_release_host(card->func);
+		sdio_set_drvdata(card->func, NULL);
+	}
+}
+
+/*
+ * This function registers the SDIO device.
+ *
+ * SDIO IRQ is claimed, block size is set and driver data is initialized.
+ */
+static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
+{
+	int ret = 0;
+	struct sdio_mmc_card *card = adapter->card;
+	struct sdio_func *func = card->func;
+
+	/* save adapter pointer in card */
+	card->adapter = adapter;
+
+	sdio_claim_host(func);
+
+	/* Request the SDIO IRQ */
+	ret = sdio_claim_irq(func, mwifiex_sdio_interrupt);
+	if (ret) {
+		pr_err("claim irq failed: ret=%d\n", ret);
+		goto disable_func;
+	}
+
+	/* Set block size */
+	ret = sdio_set_block_size(card->func, MWIFIEX_SDIO_BLOCK_SIZE);
+	if (ret) {
+		pr_err("cannot set SDIO block size\n");
+		ret = -1;
+		goto release_irq;
+	}
+
+	sdio_release_host(func);
+	sdio_set_drvdata(func, card);
+
+	adapter->dev = &func->dev;
+
+	return 0;
+
+release_irq:
+	sdio_release_irq(func);
+disable_func:
+	sdio_disable_func(func);
+	sdio_release_host(func);
+	adapter->card = NULL;
+
+	return -1;
+}
+
+/*
+ * This function initializes the SDIO driver.
+ *
+ * The following initializations steps are followed -
+ *      - Read the Host interrupt status register to acknowledge
+ *        the first interrupt got from bootloader
+ *      - Disable host interrupt mask register
+ *      - Get SDIO port
+ *      - Get revision ID
+ *      - Initialize SDIO variables in card
+ *      - Allocate MP registers
+ *      - Allocate MPA Tx and Rx buffers
+ */
+static int mwifiex_init_sdio(struct mwifiex_adapter *adapter)
+{
+	struct sdio_mmc_card *card = adapter->card;
+	int ret;
+	u32 sdio_ireg = 0;
+
+	/*
+	 * Read the HOST_INT_STATUS_REG for ACK the first interrupt got
+	 * from the bootloader. If we don't do this we get a interrupt
+	 * as soon as we register the irq.
+	 */
+	mwifiex_read_reg(adapter, HOST_INTSTATUS_REG, &sdio_ireg);
+
+	/* Disable host interrupt mask register for SDIO */
+	mwifiex_sdio_disable_host_int(adapter);
+
+	/* Get SDIO ioport */
+	mwifiex_init_sdio_ioport(adapter);
+
+	/* Get revision ID */
+#define REV_ID_REG	0x5c
+	mwifiex_read_reg(adapter, REV_ID_REG, &adapter->revision_id);
+
+	/* Initialize SDIO variables in card */
+	card->mp_rd_bitmap = 0;
+	card->mp_wr_bitmap = 0;
+	card->curr_rd_port = 1;
+	card->curr_wr_port = 1;
+
+	card->mp_data_port_mask = DATA_PORT_MASK;
+
+	card->mpa_tx.buf_len = 0;
+	card->mpa_tx.pkt_cnt = 0;
+	card->mpa_tx.start_port = 0;
+
+	card->mpa_tx.enabled = 0;
+	card->mpa_tx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
+
+	card->mpa_rx.buf_len = 0;
+	card->mpa_rx.pkt_cnt = 0;
+	card->mpa_rx.start_port = 0;
+
+	card->mpa_rx.enabled = 0;
+	card->mpa_rx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
+
+	/* Allocate buffers for SDIO MP-A */
+	card->mp_regs = kzalloc(MAX_MP_REGS, GFP_KERNEL);
+	if (!card->mp_regs) {
+		dev_err(adapter->dev, "failed to alloc mp_regs\n");
+		return -1;
+	}
+
+	ret = mwifiex_alloc_sdio_mpa_buffers(adapter,
+					     SDIO_MP_TX_AGGR_DEF_BUF_SIZE,
+					     SDIO_MP_RX_AGGR_DEF_BUF_SIZE);
+	if (ret) {
+		dev_err(adapter->dev, "failed to alloc sdio mp-a buffers\n");
+		kfree(card->mp_regs);
+		return -1;
+	}
+
+	return ret;
+}
+
+/*
+ * This function resets the MPA Tx and Rx buffers.
+ */
+static void mwifiex_cleanup_mpa_buf(struct mwifiex_adapter *adapter)
+{
+	struct sdio_mmc_card *card = adapter->card;
+
+	MP_TX_AGGR_BUF_RESET(card);
+	MP_RX_AGGR_BUF_RESET(card);
+}
+
+/*
+ * This function cleans up the allocated card buffers.
+ *
+ * The following are freed by this function -
+ *      - MP registers
+ *      - MPA Tx buffer
+ *      - MPA Rx buffer
+ */
+static void mwifiex_cleanup_sdio(struct mwifiex_adapter *adapter)
+{
+	struct sdio_mmc_card *card = adapter->card;
+
+	kfree(card->mp_regs);
+	kfree(card->mpa_tx.buf);
+	kfree(card->mpa_rx.buf);
+}
+
+/*
+ * This function updates the MP end port in card.
+ */
+static void
+mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port)
+{
+	struct sdio_mmc_card *card = adapter->card;
+	int i;
+
+	card->mp_end_port = port;
+
+	card->mp_data_port_mask = DATA_PORT_MASK;
+
+	for (i = 1; i <= MAX_PORT - card->mp_end_port; i++)
+		card->mp_data_port_mask &= ~(1 << (MAX_PORT - i));
+
+	card->curr_wr_port = 1;
+
+	dev_dbg(adapter->dev, "cmd: mp_end_port %d, data port mask 0x%x\n",
+	       port, card->mp_data_port_mask);
+}
+
+static struct mwifiex_if_ops sdio_ops = {
+	.init_if = mwifiex_init_sdio,
+	.cleanup_if = mwifiex_cleanup_sdio,
+	.check_fw_status = mwifiex_check_fw_status,
+	.prog_fw = mwifiex_prog_fw_w_helper,
+	.register_dev = mwifiex_register_dev,
+	.unregister_dev = mwifiex_unregister_dev,
+	.enable_int = mwifiex_sdio_enable_host_int,
+	.process_int_status = mwifiex_process_int_status,
+	.host_to_card = mwifiex_sdio_host_to_card,
+	.wakeup = mwifiex_pm_wakeup_card,
+	.wakeup_complete = mwifiex_pm_wakeup_card_complete,
+
+	/* SDIO specific */
+	.update_mp_end_port = mwifiex_update_mp_end_port,
+	.cleanup_mpa_buf = mwifiex_cleanup_mpa_buf,
+};
+
+/*
+ * This function initializes the SDIO driver.
+ *
+ * This initiates the semaphore and registers the device with
+ * SDIO bus.
+ */
+static int
+mwifiex_sdio_init_module(void)
+{
+	int ret;
+
+	sema_init(&add_remove_card_sem, 1);
+
+	ret = sdio_register_driver(&mwifiex_sdio);
+
+	return ret;
+}
+
+/*
+ * This function cleans up the SDIO driver.
+ *
+ * The following major steps are followed for cleanup -
+ *      - Resume the device if its suspended
+ *      - Disconnect the device if connected
+ *      - Shutdown the firmware
+ *      - Unregister the device from SDIO bus.
+ */
+static void
+mwifiex_sdio_cleanup_module(void)
+{
+	struct mwifiex_adapter *adapter = g_adapter;
+	int i;
+
+	if (down_interruptible(&add_remove_card_sem))
+		goto exit_sem_err;
+
+	if (!adapter || !adapter->priv_num)
+		goto exit;
+
+	if (adapter->is_suspended)
+		mwifiex_sdio_resume(adapter->dev);
+
+	for (i = 0; i < adapter->priv_num; i++)
+		if ((GET_BSS_ROLE(adapter->priv[i]) == MWIFIEX_BSS_ROLE_STA) &&
+		    adapter->priv[i]->media_connected)
+			mwifiex_disconnect(adapter->priv[i], MWIFIEX_CMD_WAIT,
+					   NULL);
+
+	if (!adapter->surprise_removed)
+		mwifiex_shutdown_fw(mwifiex_get_priv
+				    (adapter, MWIFIEX_BSS_ROLE_ANY),
+				    MWIFIEX_CMD_WAIT);
+
+exit:
+	up(&add_remove_card_sem);
+
+exit_sem_err:
+	sdio_unregister_driver(&mwifiex_sdio);
+}
+
+module_init(mwifiex_sdio_init_module);
+module_exit(mwifiex_sdio_cleanup_module);
+
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_DESCRIPTION("Marvell WiFi-Ex SDIO Driver version " SDIO_VERSION);
+MODULE_VERSION(SDIO_VERSION);
+MODULE_LICENSE("GPL v2");
+MODULE_FIRMWARE("sd8787.bin");
diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h
new file mode 100644
index 0000000..a0e9bc5
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/sdio.h
@@ -0,0 +1,305 @@
+/*
+ * Marvell Wireless LAN device driver: SDIO specific definitions
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#ifndef	_MWIFIEX_SDIO_H
+#define	_MWIFIEX_SDIO_H
+
+
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/card.h>
+
+#include "main.h"
+
+#define BLOCK_MODE	1
+#define BYTE_MODE	0
+
+#define REG_PORT			0
+#define RD_BITMAP_L			0x04
+#define RD_BITMAP_U			0x05
+#define WR_BITMAP_L			0x06
+#define WR_BITMAP_U			0x07
+#define RD_LEN_P0_L			0x08
+#define RD_LEN_P0_U			0x09
+
+#define MWIFIEX_SDIO_IO_PORT_MASK		0xfffff
+
+#define MWIFIEX_SDIO_BYTE_MODE_MASK	0x80000000
+
+#define CTRL_PORT			0
+#define CTRL_PORT_MASK			0x0001
+#define DATA_PORT_MASK			0xfffe
+
+#define MAX_MP_REGS			64
+#define MAX_PORT			16
+
+#define SDIO_MP_AGGR_DEF_PKT_LIMIT	8
+
+#define SDIO_MP_TX_AGGR_DEF_BUF_SIZE        (4096)	/* 4K */
+
+/* Multi port RX aggregation buffer size */
+#define SDIO_MP_RX_AGGR_DEF_BUF_SIZE        (4096)	/* 4K */
+
+/* Misc. Config Register : Auto Re-enable interrupts */
+#define AUTO_RE_ENABLE_INT              BIT(4)
+
+/* Host Control Registers */
+/* Host Control Registers : I/O port 0 */
+#define IO_PORT_0_REG			0x78
+/* Host Control Registers : I/O port 1 */
+#define IO_PORT_1_REG			0x79
+/* Host Control Registers : I/O port 2 */
+#define IO_PORT_2_REG			0x7A
+
+/* Host Control Registers : Configuration */
+#define CONFIGURATION_REG		0x00
+/* Host Control Registers : Host without Command 53 finish host*/
+#define HOST_TO_CARD_EVENT       (0x1U << 3)
+/* Host Control Registers : Host without Command 53 finish host */
+#define HOST_WO_CMD53_FINISH_HOST	(0x1U << 2)
+/* Host Control Registers : Host power up */
+#define HOST_POWER_UP			(0x1U << 1)
+/* Host Control Registers : Host power down */
+#define HOST_POWER_DOWN			(0x1U << 0)
+
+/* Host Control Registers : Host interrupt mask */
+#define HOST_INT_MASK_REG		0x02
+/* Host Control Registers : Upload host interrupt mask */
+#define UP_LD_HOST_INT_MASK		(0x1U)
+/* Host Control Registers : Download host interrupt mask */
+#define DN_LD_HOST_INT_MASK		(0x2U)
+/* Enable Host interrupt mask */
+#define HOST_INT_ENABLE	(UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK)
+/* Disable Host interrupt mask */
+#define	HOST_INT_DISABLE		0xff
+
+/* Host Control Registers : Host interrupt status */
+#define HOST_INTSTATUS_REG		0x03
+/* Host Control Registers : Upload host interrupt status */
+#define UP_LD_HOST_INT_STATUS		(0x1U)
+/* Host Control Registers : Download host interrupt status */
+#define DN_LD_HOST_INT_STATUS		(0x2U)
+
+/* Host Control Registers : Host interrupt RSR */
+#define HOST_INT_RSR_REG		0x01
+/* Host Control Registers : Upload host interrupt RSR */
+#define UP_LD_HOST_INT_RSR		(0x1U)
+#define SDIO_INT_MASK			0x3F
+
+/* Host Control Registers : Host interrupt status */
+#define HOST_INT_STATUS_REG		0x28
+/* Host Control Registers : Upload CRC error */
+#define UP_LD_CRC_ERR			(0x1U << 2)
+/* Host Control Registers : Upload restart */
+#define UP_LD_RESTART                   (0x1U << 1)
+/* Host Control Registers : Download restart */
+#define DN_LD_RESTART                   (0x1U << 0)
+
+/* Card Control Registers : Card status register */
+#define CARD_STATUS_REG                 0x30
+/* Card Control Registers : Card I/O ready */
+#define CARD_IO_READY                   (0x1U << 3)
+/* Card Control Registers : CIS card ready */
+#define CIS_CARD_RDY                    (0x1U << 2)
+/* Card Control Registers : Upload card ready */
+#define UP_LD_CARD_RDY                  (0x1U << 1)
+/* Card Control Registers : Download card ready */
+#define DN_LD_CARD_RDY                  (0x1U << 0)
+
+/* Card Control Registers : Host interrupt mask register */
+#define HOST_INTERRUPT_MASK_REG         0x34
+/* Card Control Registers : Host power interrupt mask */
+#define HOST_POWER_INT_MASK             (0x1U << 3)
+/* Card Control Registers : Abort card interrupt mask */
+#define ABORT_CARD_INT_MASK             (0x1U << 2)
+/* Card Control Registers : Upload card interrupt mask */
+#define UP_LD_CARD_INT_MASK             (0x1U << 1)
+/* Card Control Registers : Download card interrupt mask */
+#define DN_LD_CARD_INT_MASK             (0x1U << 0)
+
+/* Card Control Registers : Card interrupt status register */
+#define CARD_INTERRUPT_STATUS_REG       0x38
+/* Card Control Registers : Power up interrupt */
+#define POWER_UP_INT                    (0x1U << 4)
+/* Card Control Registers : Power down interrupt */
+#define POWER_DOWN_INT                  (0x1U << 3)
+
+/* Card Control Registers : Card interrupt RSR register */
+#define CARD_INTERRUPT_RSR_REG          0x3c
+/* Card Control Registers : Power up RSR */
+#define POWER_UP_RSR                    (0x1U << 4)
+/* Card Control Registers : Power down RSR */
+#define POWER_DOWN_RSR                  (0x1U << 3)
+
+/* Card Control Registers : Miscellaneous Configuration Register */
+#define CARD_MISC_CFG_REG               0x6C
+
+/* Host F1 read base 0 */
+#define HOST_F1_RD_BASE_0		0x0040
+/* Host F1 read base 1 */
+#define HOST_F1_RD_BASE_1		0x0041
+/* Host F1 card ready */
+#define HOST_F1_CARD_RDY		0x0020
+
+/* Firmware status 0 register */
+#define CARD_FW_STATUS0_REG		0x60
+/* Firmware status 1 register */
+#define CARD_FW_STATUS1_REG		0x61
+/* Rx length register */
+#define CARD_RX_LEN_REG			0x62
+/* Rx unit register */
+#define CARD_RX_UNIT_REG		0x63
+
+/* Event header Len*/
+#define MWIFIEX_EVENT_HEADER_LEN           8
+
+/* Max retry number of CMD53 write */
+#define MAX_WRITE_IOMEM_RETRY		2
+
+/* SDIO Tx aggregation in progress ? */
+#define MP_TX_AGGR_IN_PROGRESS(a) (a->mpa_tx.pkt_cnt > 0)
+
+/* SDIO Tx aggregation buffer room for next packet ? */
+#define MP_TX_AGGR_BUF_HAS_ROOM(a, len) ((a->mpa_tx.buf_len+len)	\
+						<= a->mpa_tx.buf_size)
+
+/* Copy current packet (SDIO Tx aggregation buffer) to SDIO buffer */
+#define MP_TX_AGGR_BUF_PUT(a, payload, pkt_len, port) do {		\
+	memmove(&a->mpa_tx.buf[a->mpa_tx.buf_len],			\
+			payload, pkt_len);				\
+	a->mpa_tx.buf_len += pkt_len;					\
+	if (!a->mpa_tx.pkt_cnt)						\
+		a->mpa_tx.start_port = port;				\
+	if (a->mpa_tx.start_port <= port)				\
+		a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt));		\
+	else								\
+		a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt+1+(MAX_PORT -	\
+						a->mp_end_port)));	\
+	a->mpa_tx.pkt_cnt++;						\
+} while (0);
+
+/* SDIO Tx aggregation limit ? */
+#define MP_TX_AGGR_PKT_LIMIT_REACHED(a)					\
+			(a->mpa_tx.pkt_cnt == a->mpa_tx.pkt_aggr_limit)
+
+/* SDIO Tx aggregation port limit ? */
+#define MP_TX_AGGR_PORT_LIMIT_REACHED(a) ((a->curr_wr_port <		\
+			a->mpa_tx.start_port) && (((MAX_PORT -		\
+			a->mpa_tx.start_port) + a->curr_wr_port) >=	\
+				SDIO_MP_AGGR_DEF_PKT_LIMIT))
+
+/* Reset SDIO Tx aggregation buffer parameters */
+#define MP_TX_AGGR_BUF_RESET(a) do {					\
+	a->mpa_tx.pkt_cnt = 0;						\
+	a->mpa_tx.buf_len = 0;						\
+	a->mpa_tx.ports = 0;						\
+	a->mpa_tx.start_port = 0;					\
+} while (0);
+
+/* SDIO Rx aggregation limit ? */
+#define MP_RX_AGGR_PKT_LIMIT_REACHED(a)					\
+			(a->mpa_rx.pkt_cnt == a->mpa_rx.pkt_aggr_limit)
+
+/* SDIO Tx aggregation port limit ? */
+#define MP_RX_AGGR_PORT_LIMIT_REACHED(a) ((a->curr_rd_port <		\
+			a->mpa_rx.start_port) && (((MAX_PORT -		\
+			a->mpa_rx.start_port) + a->curr_rd_port) >=	\
+			SDIO_MP_AGGR_DEF_PKT_LIMIT))
+
+/* SDIO Rx aggregation in progress ? */
+#define MP_RX_AGGR_IN_PROGRESS(a) (a->mpa_rx.pkt_cnt > 0)
+
+/* SDIO Rx aggregation buffer room for next packet ? */
+#define MP_RX_AGGR_BUF_HAS_ROOM(a, rx_len)				\
+			((a->mpa_rx.buf_len+rx_len) <= a->mpa_rx.buf_size)
+
+/* Prepare to copy current packet from card to SDIO Rx aggregation buffer */
+#define MP_RX_AGGR_SETUP(a, skb, port) do {				\
+	a->mpa_rx.buf_len += skb->len;					\
+	if (!a->mpa_rx.pkt_cnt)						\
+		a->mpa_rx.start_port = port;				\
+	if (a->mpa_rx.start_port <= port)				\
+		a->mpa_rx.ports |= (1<<(a->mpa_rx.pkt_cnt));		\
+	else								\
+		a->mpa_rx.ports |= (1<<(a->mpa_rx.pkt_cnt+1));		\
+	a->mpa_rx.skb_arr[a->mpa_rx.pkt_cnt] = skb;			\
+	a->mpa_rx.len_arr[a->mpa_rx.pkt_cnt] = skb->len;		\
+	a->mpa_rx.pkt_cnt++;						\
+} while (0);
+
+/* Reset SDIO Rx aggregation buffer parameters */
+#define MP_RX_AGGR_BUF_RESET(a) do {					\
+	a->mpa_rx.pkt_cnt = 0;						\
+	a->mpa_rx.buf_len = 0;						\
+	a->mpa_rx.ports = 0;						\
+	a->mpa_rx.start_port = 0;					\
+} while (0);
+
+
+/* data structure for SDIO MPA TX */
+struct mwifiex_sdio_mpa_tx {
+	/* multiport tx aggregation buffer pointer */
+	u8 *buf;
+	u32 buf_len;
+	u32 pkt_cnt;
+	u16 ports;
+	u16 start_port;
+	u8 enabled;
+	u32 buf_size;
+	u32 pkt_aggr_limit;
+};
+
+struct mwifiex_sdio_mpa_rx {
+	u8 *buf;
+	u32 buf_len;
+	u32 pkt_cnt;
+	u16 ports;
+	u16 start_port;
+
+	struct sk_buff *skb_arr[SDIO_MP_AGGR_DEF_PKT_LIMIT];
+	u32 len_arr[SDIO_MP_AGGR_DEF_PKT_LIMIT];
+
+	u8 enabled;
+	u32 buf_size;
+	u32 pkt_aggr_limit;
+};
+
+int mwifiex_bus_register(void);
+void mwifiex_bus_unregister(void);
+
+struct sdio_mmc_card {
+	struct sdio_func *func;
+	struct mwifiex_adapter *adapter;
+
+	u16 mp_rd_bitmap;
+	u16 mp_wr_bitmap;
+
+	u16 mp_end_port;
+	u16 mp_data_port_mask;
+
+	u8 curr_rd_port;
+	u8 curr_wr_port;
+
+	u8 *mp_regs;
+
+	struct mwifiex_sdio_mpa_tx mpa_tx;
+	struct mwifiex_sdio_mpa_rx mpa_rx;
+};
+#endif /* _MWIFIEX_SDIO_H */
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c
new file mode 100644
index 0000000..6fff261
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -0,0 +1,1226 @@
+/*
+ * Marvell Wireless LAN device driver: station command handling
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+#include "11n.h"
+
+/*
+ * This function prepares command to set/get RSSI information.
+ *
+ * Preparation includes -
+ *      - Setting command ID, action and proper size
+ *      - Setting data/beacon average factors
+ *      - Resetting SNR/NF/RSSI values in private structure
+ *      - Ensuring correct endian-ness
+ */
+static int
+mwifiex_cmd_802_11_rssi_info(struct mwifiex_private *priv,
+			     struct host_cmd_ds_command *cmd, u16 cmd_action)
+{
+	cmd->command = cpu_to_le16(HostCmd_CMD_RSSI_INFO);
+	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_rssi_info) +
+				S_DS_GEN);
+	cmd->params.rssi_info.action = cpu_to_le16(cmd_action);
+	cmd->params.rssi_info.ndata = cpu_to_le16(priv->data_avg_factor);
+	cmd->params.rssi_info.nbcn = cpu_to_le16(priv->bcn_avg_factor);
+
+	/* Reset SNR/NF/RSSI values in private structure */
+	priv->data_rssi_last = 0;
+	priv->data_nf_last = 0;
+	priv->data_rssi_avg = 0;
+	priv->data_nf_avg = 0;
+	priv->bcn_rssi_last = 0;
+	priv->bcn_nf_last = 0;
+	priv->bcn_rssi_avg = 0;
+	priv->bcn_nf_avg = 0;
+
+	return 0;
+}
+
+/*
+ * This function prepares command to set MAC control.
+ *
+ * Preparation includes -
+ *      - Setting command ID, action and proper size
+ *      - Ensuring correct endian-ness
+ */
+static int mwifiex_cmd_mac_control(struct mwifiex_private *priv,
+				   struct host_cmd_ds_command *cmd,
+				   u16 cmd_action, void *data_buf)
+{
+	struct host_cmd_ds_mac_control *mac_ctrl = &cmd->params.mac_ctrl;
+	u16 action = *((u16 *) data_buf);
+
+	if (cmd_action != HostCmd_ACT_GEN_SET) {
+		dev_err(priv->adapter->dev,
+			"mac_control: only support set cmd\n");
+		return -1;
+	}
+
+	cmd->command = cpu_to_le16(HostCmd_CMD_MAC_CONTROL);
+	cmd->size =
+		cpu_to_le16(sizeof(struct host_cmd_ds_mac_control) + S_DS_GEN);
+	mac_ctrl->action = cpu_to_le16(action);
+
+	return 0;
+}
+
+/*
+ * This function prepares command to set/get SNMP MIB.
+ *
+ * Preparation includes -
+ *      - Setting command ID, action and proper size
+ *      - Setting SNMP MIB OID number and value
+ *        (as required)
+ *      - Ensuring correct endian-ness
+ *
+ * The following SNMP MIB OIDs are supported -
+ *      - FRAG_THRESH_I     : Fragmentation threshold
+ *      - RTS_THRESH_I      : RTS threshold
+ *      - SHORT_RETRY_LIM_I : Short retry limit
+ *      - DOT11D_I          : 11d support
+ */
+static int mwifiex_cmd_802_11_snmp_mib(struct mwifiex_private *priv,
+				       struct host_cmd_ds_command *cmd,
+				       u16 cmd_action, u32 cmd_oid,
+				       void *data_buf)
+{
+	struct host_cmd_ds_802_11_snmp_mib *snmp_mib = &cmd->params.smib;
+	u32 ul_temp;
+
+	dev_dbg(priv->adapter->dev, "cmd: SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
+	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SNMP_MIB);
+	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_snmp_mib)
+		- 1 + S_DS_GEN);
+
+	if (cmd_action == HostCmd_ACT_GEN_GET) {
+		snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_GET);
+		snmp_mib->buf_size = cpu_to_le16(MAX_SNMP_BUF_SIZE);
+		cmd->size = cpu_to_le16(le16_to_cpu(cmd->size)
+			+ MAX_SNMP_BUF_SIZE);
+	}
+
+	switch (cmd_oid) {
+	case FRAG_THRESH_I:
+		snmp_mib->oid = cpu_to_le16((u16) FRAG_THRESH_I);
+		if (cmd_action == HostCmd_ACT_GEN_SET) {
+			snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET);
+			snmp_mib->buf_size = cpu_to_le16(sizeof(u16));
+			ul_temp = *((u32 *) data_buf);
+			*((__le16 *) (snmp_mib->value)) =
+				cpu_to_le16((u16) ul_temp);
+			cmd->size = cpu_to_le16(le16_to_cpu(cmd->size)
+				+ sizeof(u16));
+		}
+		break;
+	case RTS_THRESH_I:
+		snmp_mib->oid = cpu_to_le16((u16) RTS_THRESH_I);
+		if (cmd_action == HostCmd_ACT_GEN_SET) {
+			snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET);
+			snmp_mib->buf_size = cpu_to_le16(sizeof(u16));
+			ul_temp = *((u32 *) data_buf);
+			*(__le16 *) (snmp_mib->value) =
+				cpu_to_le16((u16) ul_temp);
+			cmd->size = cpu_to_le16(le16_to_cpu(cmd->size)
+				+ sizeof(u16));
+		}
+		break;
+
+	case SHORT_RETRY_LIM_I:
+		snmp_mib->oid = cpu_to_le16((u16) SHORT_RETRY_LIM_I);
+		if (cmd_action == HostCmd_ACT_GEN_SET) {
+			snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET);
+			snmp_mib->buf_size = cpu_to_le16(sizeof(u16));
+			ul_temp = (*(u32 *) data_buf);
+			*((__le16 *) (snmp_mib->value)) =
+				cpu_to_le16((u16) ul_temp);
+			cmd->size = cpu_to_le16(le16_to_cpu(cmd->size)
+				+ sizeof(u16));
+		}
+		break;
+	case DOT11D_I:
+		snmp_mib->oid = cpu_to_le16((u16) DOT11D_I);
+		if (cmd_action == HostCmd_ACT_GEN_SET) {
+			snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET);
+			snmp_mib->buf_size = cpu_to_le16(sizeof(u16));
+			ul_temp = *(u32 *) data_buf;
+			*((__le16 *) (snmp_mib->value)) =
+				cpu_to_le16((u16) ul_temp);
+			cmd->size = cpu_to_le16(le16_to_cpu(cmd->size)
+				+ sizeof(u16));
+		}
+		break;
+	default:
+		break;
+	}
+	dev_dbg(priv->adapter->dev,
+		"cmd: SNMP_CMD: Action=0x%x, OID=0x%x, OIDSize=0x%x,"
+		" Value=0x%x\n",
+	       cmd_action, cmd_oid, le16_to_cpu(snmp_mib->buf_size),
+	       le16_to_cpu(*(__le16 *) snmp_mib->value));
+	return 0;
+}
+
+/*
+ * This function prepares command to get log.
+ *
+ * Preparation includes -
+ *      - Setting command ID and proper size
+ *      - Ensuring correct endian-ness
+ */
+static int
+mwifiex_cmd_802_11_get_log(struct mwifiex_private *priv,
+			   struct host_cmd_ds_command *cmd)
+{
+	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_GET_LOG);
+	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_get_log) +
+				S_DS_GEN);
+	return 0;
+}
+
+/*
+ * This function prepares command to set/get Tx data rate configuration.
+ *
+ * Preparation includes -
+ *      - Setting command ID, action and proper size
+ *      - Setting configuration index, rate scope and rate drop pattern
+ *        parameters (as required)
+ *      - Ensuring correct endian-ness
+ */
+static int mwifiex_cmd_tx_rate_cfg(struct mwifiex_private *priv,
+				   struct host_cmd_ds_command *cmd,
+				   u16 cmd_action, void *data_buf)
+{
+	struct host_cmd_ds_tx_rate_cfg *rate_cfg = &cmd->params.tx_rate_cfg;
+	struct mwifiex_rate_scope *rate_scope;
+	struct mwifiex_rate_drop_pattern *rate_drop;
+	u16 *pbitmap_rates = (u16 *) data_buf;
+
+	u32 i;
+
+	cmd->command = cpu_to_le16(HostCmd_CMD_TX_RATE_CFG);
+
+	rate_cfg->action = cpu_to_le16(cmd_action);
+	rate_cfg->cfg_index = 0;
+
+	rate_scope = (struct mwifiex_rate_scope *) ((u8 *) rate_cfg +
+		      sizeof(struct host_cmd_ds_tx_rate_cfg));
+	rate_scope->type = cpu_to_le16(TLV_TYPE_RATE_SCOPE);
+	rate_scope->length = cpu_to_le16(sizeof(struct mwifiex_rate_scope) -
+			sizeof(struct mwifiex_ie_types_header));
+	if (pbitmap_rates != NULL) {
+		rate_scope->hr_dsss_rate_bitmap = cpu_to_le16(pbitmap_rates[0]);
+		rate_scope->ofdm_rate_bitmap = cpu_to_le16(pbitmap_rates[1]);
+		for (i = 0;
+		     i < sizeof(rate_scope->ht_mcs_rate_bitmap) / sizeof(u16);
+		     i++)
+			rate_scope->ht_mcs_rate_bitmap[i] =
+				cpu_to_le16(pbitmap_rates[2 + i]);
+	} else {
+		rate_scope->hr_dsss_rate_bitmap =
+			cpu_to_le16(priv->bitmap_rates[0]);
+		rate_scope->ofdm_rate_bitmap =
+			cpu_to_le16(priv->bitmap_rates[1]);
+		for (i = 0;
+		     i < sizeof(rate_scope->ht_mcs_rate_bitmap) / sizeof(u16);
+		     i++)
+			rate_scope->ht_mcs_rate_bitmap[i] =
+				cpu_to_le16(priv->bitmap_rates[2 + i]);
+	}
+
+	rate_drop = (struct mwifiex_rate_drop_pattern *) ((u8 *) rate_scope +
+			sizeof(struct mwifiex_rate_scope));
+	rate_drop->type = cpu_to_le16(TLV_TYPE_RATE_DROP_CONTROL);
+	rate_drop->length = cpu_to_le16(sizeof(rate_drop->rate_drop_mode));
+	rate_drop->rate_drop_mode = 0;
+
+	cmd->size =
+		cpu_to_le16(S_DS_GEN + sizeof(struct host_cmd_ds_tx_rate_cfg) +
+			    sizeof(struct mwifiex_rate_scope) +
+			    sizeof(struct mwifiex_rate_drop_pattern));
+
+	return 0;
+}
+
+/*
+ * This function prepares command to set/get Tx power configuration.
+ *
+ * Preparation includes -
+ *      - Setting command ID, action and proper size
+ *      - Setting Tx power mode, power group TLV
+ *        (as required)
+ *      - Ensuring correct endian-ness
+ */
+static int mwifiex_cmd_tx_power_cfg(struct mwifiex_private *priv,
+				    struct host_cmd_ds_command *cmd,
+				    u16 cmd_action, void *data_buf)
+{
+	struct mwifiex_types_power_group *pg_tlv = NULL;
+	struct host_cmd_ds_txpwr_cfg *txp = NULL;
+	struct host_cmd_ds_txpwr_cfg *cmd_txp_cfg = &cmd->params.txp_cfg;
+
+	cmd->command = cpu_to_le16(HostCmd_CMD_TXPWR_CFG);
+	cmd->size =
+		cpu_to_le16(S_DS_GEN + sizeof(struct host_cmd_ds_txpwr_cfg));
+	switch (cmd_action) {
+	case HostCmd_ACT_GEN_SET:
+		txp = (struct host_cmd_ds_txpwr_cfg *) data_buf;
+		if (txp->mode) {
+			pg_tlv = (struct mwifiex_types_power_group
+				  *) ((unsigned long) data_buf +
+				     sizeof(struct host_cmd_ds_txpwr_cfg));
+			memmove(cmd_txp_cfg, data_buf,
+				sizeof(struct host_cmd_ds_txpwr_cfg) +
+				sizeof(struct mwifiex_types_power_group) +
+				pg_tlv->length);
+
+			pg_tlv = (struct mwifiex_types_power_group *) ((u8 *)
+				  cmd_txp_cfg +
+				  sizeof(struct host_cmd_ds_txpwr_cfg));
+			cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) +
+				  sizeof(struct mwifiex_types_power_group) +
+				  pg_tlv->length);
+		} else {
+			memmove(cmd_txp_cfg, data_buf,
+				sizeof(struct host_cmd_ds_txpwr_cfg));
+		}
+		cmd_txp_cfg->action = cpu_to_le16(cmd_action);
+		break;
+	case HostCmd_ACT_GEN_GET:
+		cmd_txp_cfg->action = cpu_to_le16(cmd_action);
+		break;
+	}
+
+	return 0;
+}
+
+/*
+ * This function prepares command to set Host Sleep configuration.
+ *
+ * Preparation includes -
+ *      - Setting command ID and proper size
+ *      - Setting Host Sleep action, conditions, ARP filters
+ *        (as required)
+ *      - Ensuring correct endian-ness
+ */
+static int mwifiex_cmd_802_11_hs_cfg(struct mwifiex_private *priv,
+				     struct host_cmd_ds_command *cmd,
+				     u16 cmd_action,
+				     struct mwifiex_hs_config_param *data_buf)
+{
+	struct mwifiex_adapter *adapter = priv->adapter;
+	struct host_cmd_ds_802_11_hs_cfg_enh *hs_cfg = &cmd->params.opt_hs_cfg;
+	u16 hs_activate = false;
+
+	if (data_buf == NULL)
+		/* New Activate command */
+		hs_activate = true;
+	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH);
+
+	if (!hs_activate &&
+	    (data_buf->conditions
+	    != cpu_to_le32(HOST_SLEEP_CFG_CANCEL))
+	    && ((adapter->arp_filter_size > 0)
+		&& (adapter->arp_filter_size <= ARP_FILTER_MAX_BUF_SIZE))) {
+		dev_dbg(adapter->dev,
+			"cmd: Attach %d bytes ArpFilter to HSCfg cmd\n",
+		       adapter->arp_filter_size);
+		memcpy(((u8 *) hs_cfg) +
+		       sizeof(struct host_cmd_ds_802_11_hs_cfg_enh),
+		       adapter->arp_filter, adapter->arp_filter_size);
+		cmd->size = cpu_to_le16(adapter->arp_filter_size +
+				    sizeof(struct host_cmd_ds_802_11_hs_cfg_enh)
+				    + S_DS_GEN);
+	} else {
+		cmd->size = cpu_to_le16(S_DS_GEN + sizeof(struct
+					   host_cmd_ds_802_11_hs_cfg_enh));
+	}
+	if (hs_activate) {
+		hs_cfg->action = cpu_to_le16(HS_ACTIVATE);
+		hs_cfg->params.hs_activate.resp_ctrl = RESP_NEEDED;
+	} else {
+		hs_cfg->action = cpu_to_le16(HS_CONFIGURE);
+		hs_cfg->params.hs_config.conditions = data_buf->conditions;
+		hs_cfg->params.hs_config.gpio = data_buf->gpio;
+		hs_cfg->params.hs_config.gap = data_buf->gap;
+		dev_dbg(adapter->dev,
+			"cmd: HS_CFG_CMD: condition:0x%x gpio:0x%x gap:0x%x\n",
+		       hs_cfg->params.hs_config.conditions,
+		       hs_cfg->params.hs_config.gpio,
+		       hs_cfg->params.hs_config.gap);
+	}
+
+	return 0;
+}
+
+/*
+ * This function prepares command to set/get MAC address.
+ *
+ * Preparation includes -
+ *      - Setting command ID, action and proper size
+ *      - Setting MAC address (for SET only)
+ *      - Ensuring correct endian-ness
+ */
+static int mwifiex_cmd_802_11_mac_address(struct mwifiex_private *priv,
+					  struct host_cmd_ds_command *cmd,
+					  u16 cmd_action)
+{
+	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_MAC_ADDRESS);
+	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_mac_address) +
+				S_DS_GEN);
+	cmd->result = 0;
+
+	cmd->params.mac_addr.action = cpu_to_le16(cmd_action);
+
+	if (cmd_action == HostCmd_ACT_GEN_SET)
+		memcpy(cmd->params.mac_addr.mac_addr, priv->curr_addr,
+		       ETH_ALEN);
+	return 0;
+}
+
+/*
+ * This function prepares command to set MAC multicast address.
+ *
+ * Preparation includes -
+ *      - Setting command ID, action and proper size
+ *      - Setting MAC multicast address
+ *      - Ensuring correct endian-ness
+ */
+static int mwifiex_cmd_mac_multicast_adr(struct mwifiex_private *priv,
+					 struct host_cmd_ds_command *cmd,
+					 u16 cmd_action, void *data_buf)
+{
+	struct mwifiex_multicast_list *mcast_list =
+		(struct mwifiex_multicast_list *) data_buf;
+	struct host_cmd_ds_mac_multicast_adr *mcast_addr = &cmd->params.mc_addr;
+
+	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_mac_multicast_adr) +
+				S_DS_GEN);
+	cmd->command = cpu_to_le16(HostCmd_CMD_MAC_MULTICAST_ADR);
+
+	mcast_addr->action = cpu_to_le16(cmd_action);
+	mcast_addr->num_of_adrs =
+		cpu_to_le16((u16) mcast_list->num_multicast_addr);
+	memcpy(mcast_addr->mac_list, mcast_list->mac_list,
+	       mcast_list->num_multicast_addr * ETH_ALEN);
+
+	return 0;
+}
+
+/*
+ * This function prepares command to deauthenticate.
+ *
+ * Preparation includes -
+ *      - Setting command ID and proper size
+ *      - Setting AP MAC address and reason code
+ *      - Ensuring correct endian-ness
+ */
+static int mwifiex_cmd_802_11_deauthenticate(struct mwifiex_private *priv,
+					     struct host_cmd_ds_command *cmd,
+					     void *data_buf)
+{
+	struct host_cmd_ds_802_11_deauthenticate *deauth = &cmd->params.deauth;
+
+	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_DEAUTHENTICATE);
+	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_deauthenticate)
+				+ S_DS_GEN);
+
+	/* Set AP MAC address */
+	memcpy(deauth->mac_addr, (u8 *) data_buf, ETH_ALEN);
+
+	dev_dbg(priv->adapter->dev, "cmd: Deauth: %pM\n", deauth->mac_addr);
+
+	deauth->reason_code = cpu_to_le16(WLAN_REASON_DEAUTH_LEAVING);
+
+	return 0;
+}
+
+/*
+ * This function prepares command to stop Ad-Hoc network.
+ *
+ * Preparation includes -
+ *      - Setting command ID and proper size
+ *      - Ensuring correct endian-ness
+ */
+static int mwifiex_cmd_802_11_ad_hoc_stop(struct mwifiex_private *priv,
+					  struct host_cmd_ds_command *cmd)
+{
+	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_STOP);
+	cmd->size = cpu_to_le16(S_DS_GEN);
+	return 0;
+}
+
+/*
+ * This function sets WEP key(s) to key parameter TLV(s).
+ *
+ * Multi-key parameter TLVs are supported, so we can send multiple
+ * WEP keys in a single buffer.
+ */
+static int
+mwifiex_set_keyparamset_wep(struct mwifiex_private *priv,
+			    struct mwifiex_ie_type_key_param_set *key_param_set,
+			    u16 *key_param_len)
+{
+	int cur_key_param_len = 0;
+	u8 i;
+
+	/* Multi-key_param_set TLV is supported */
+	for (i = 0; i < NUM_WEP_KEYS; i++) {
+		if ((priv->wep_key[i].key_length == WLAN_KEY_LEN_WEP40) ||
+		    (priv->wep_key[i].key_length == WLAN_KEY_LEN_WEP104)) {
+			key_param_set->type =
+				cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+/* Key_param_set WEP fixed length */
+#define KEYPARAMSET_WEP_FIXED_LEN 8
+			key_param_set->length = cpu_to_le16((u16)
+					(priv->wep_key[i].
+					 key_length +
+					 KEYPARAMSET_WEP_FIXED_LEN));
+			key_param_set->key_type_id =
+				cpu_to_le16(KEY_TYPE_ID_WEP);
+			key_param_set->key_info =
+				cpu_to_le16(KEY_INFO_WEP_ENABLED |
+					    KEY_INFO_WEP_UNICAST |
+					    KEY_INFO_WEP_MCAST);
+			key_param_set->key_len =
+				cpu_to_le16(priv->wep_key[i].key_length);
+			/* Set WEP key index */
+			key_param_set->key[0] = i;
+			/* Set default Tx key flag */
+			if (i ==
+			    (priv->
+			     wep_key_curr_index & HostCmd_WEP_KEY_INDEX_MASK))
+				key_param_set->key[1] = 1;
+			else
+				key_param_set->key[1] = 0;
+			memmove(&key_param_set->key[2],
+				priv->wep_key[i].key_material,
+				priv->wep_key[i].key_length);
+
+			cur_key_param_len = priv->wep_key[i].key_length +
+				KEYPARAMSET_WEP_FIXED_LEN +
+				sizeof(struct mwifiex_ie_types_header);
+			*key_param_len += (u16) cur_key_param_len;
+			key_param_set =
+				(struct mwifiex_ie_type_key_param_set *)
+						((u8 *)key_param_set +
+						cur_key_param_len);
+		} else if (!priv->wep_key[i].key_length) {
+			continue;
+		} else {
+			dev_err(priv->adapter->dev,
+				"key%d Length = %d is incorrect\n",
+			       (i + 1), priv->wep_key[i].key_length);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * This function prepares command to set/get/reset network key(s).
+ *
+ * Preparation includes -
+ *      - Setting command ID, action and proper size
+ *      - Setting WEP keys, WAPI keys or WPA keys along with required
+ *        encryption (TKIP, AES) (as required)
+ *      - Ensuring correct endian-ness
+ */
+static int mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
+					   struct host_cmd_ds_command *cmd,
+					   u16 cmd_action,
+					   u32 cmd_oid, void *data_buf)
+{
+	struct host_cmd_ds_802_11_key_material *key_material =
+		&cmd->params.key_material;
+	struct mwifiex_ds_encrypt_key *enc_key =
+		(struct mwifiex_ds_encrypt_key *) data_buf;
+	u16 key_param_len = 0;
+	int ret = 0;
+	const u8 bc_mac[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_KEY_MATERIAL);
+	key_material->action = cpu_to_le16(cmd_action);
+
+	if (cmd_action == HostCmd_ACT_GEN_GET) {
+		cmd->size =
+			cpu_to_le16(sizeof(key_material->action) + S_DS_GEN);
+		return ret;
+	}
+
+	if (!enc_key) {
+		memset(&key_material->key_param_set, 0,
+		       (NUM_WEP_KEYS *
+			sizeof(struct mwifiex_ie_type_key_param_set)));
+		ret = mwifiex_set_keyparamset_wep(priv,
+						  &key_material->key_param_set,
+						  &key_param_len);
+		cmd->size = cpu_to_le16(key_param_len +
+				    sizeof(key_material->action) + S_DS_GEN);
+		return ret;
+	} else
+		memset(&key_material->key_param_set, 0,
+		       sizeof(struct mwifiex_ie_type_key_param_set));
+	if (enc_key->is_wapi_key) {
+		dev_dbg(priv->adapter->dev, "info: Set WAPI Key\n");
+		key_material->key_param_set.key_type_id =
+			cpu_to_le16(KEY_TYPE_ID_WAPI);
+		if (cmd_oid == KEY_INFO_ENABLED)
+			key_material->key_param_set.key_info =
+				cpu_to_le16(KEY_INFO_WAPI_ENABLED);
+		else
+			key_material->key_param_set.key_info =
+				cpu_to_le16(!KEY_INFO_WAPI_ENABLED);
+
+		key_material->key_param_set.key[0] = enc_key->key_index;
+		if (!priv->sec_info.wapi_key_on)
+			key_material->key_param_set.key[1] = 1;
+		else
+			/* set 0 when re-key */
+			key_material->key_param_set.key[1] = 0;
+
+		if (0 != memcmp(enc_key->mac_addr, bc_mac, sizeof(bc_mac))) {
+			/* WAPI pairwise key: unicast */
+			key_material->key_param_set.key_info |=
+				cpu_to_le16(KEY_INFO_WAPI_UNICAST);
+		} else {	/* WAPI group key: multicast */
+			key_material->key_param_set.key_info |=
+				cpu_to_le16(KEY_INFO_WAPI_MCAST);
+			priv->sec_info.wapi_key_on = true;
+		}
+
+		key_material->key_param_set.type =
+			cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+		key_material->key_param_set.key_len =
+			cpu_to_le16(WAPI_KEY_LEN);
+		memcpy(&key_material->key_param_set.key[2],
+		       enc_key->key_material, enc_key->key_len);
+		memcpy(&key_material->key_param_set.key[2 + enc_key->key_len],
+		       enc_key->wapi_rxpn, WAPI_RXPN_LEN);
+		key_material->key_param_set.length =
+			cpu_to_le16(WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN);
+
+		key_param_len = (WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN) +
+				 sizeof(struct mwifiex_ie_types_header);
+		cmd->size = cpu_to_le16(key_param_len +
+				sizeof(key_material->action) + S_DS_GEN);
+		return ret;
+	}
+	if (enc_key->key_len == WLAN_KEY_LEN_CCMP) {
+		dev_dbg(priv->adapter->dev, "cmd: WPA_AES\n");
+		key_material->key_param_set.key_type_id =
+			cpu_to_le16(KEY_TYPE_ID_AES);
+		if (cmd_oid == KEY_INFO_ENABLED)
+			key_material->key_param_set.key_info =
+				cpu_to_le16(KEY_INFO_AES_ENABLED);
+		else
+			key_material->key_param_set.key_info =
+				cpu_to_le16(!KEY_INFO_AES_ENABLED);
+
+		if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST)
+				/* AES pairwise key: unicast */
+			key_material->key_param_set.key_info |=
+				cpu_to_le16(KEY_INFO_AES_UNICAST);
+		else		/* AES group key: multicast */
+			key_material->key_param_set.key_info |=
+				cpu_to_le16(KEY_INFO_AES_MCAST);
+	} else if (enc_key->key_len == WLAN_KEY_LEN_TKIP) {
+		dev_dbg(priv->adapter->dev, "cmd: WPA_TKIP\n");
+		key_material->key_param_set.key_type_id =
+			cpu_to_le16(KEY_TYPE_ID_TKIP);
+		key_material->key_param_set.key_info =
+			cpu_to_le16(KEY_INFO_TKIP_ENABLED);
+
+		if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST)
+				/* TKIP pairwise key: unicast */
+			key_material->key_param_set.key_info |=
+				cpu_to_le16(KEY_INFO_TKIP_UNICAST);
+		else		/* TKIP group key: multicast */
+			key_material->key_param_set.key_info |=
+				cpu_to_le16(KEY_INFO_TKIP_MCAST);
+	}
+
+	if (key_material->key_param_set.key_type_id) {
+		key_material->key_param_set.type =
+			cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+		key_material->key_param_set.key_len =
+			cpu_to_le16((u16) enc_key->key_len);
+		memcpy(key_material->key_param_set.key, enc_key->key_material,
+		       enc_key->key_len);
+		key_material->key_param_set.length =
+			cpu_to_le16((u16) enc_key->key_len +
+				    KEYPARAMSET_FIXED_LEN);
+
+		key_param_len = (u16) (enc_key->key_len + KEYPARAMSET_FIXED_LEN)
+				      + sizeof(struct mwifiex_ie_types_header);
+
+		cmd->size = cpu_to_le16(key_param_len +
+				    sizeof(key_material->action) + S_DS_GEN);
+	}
+
+	return ret;
+}
+
+/*
+ * This function prepares command to set/get 11d domain information.
+ *
+ * Preparation includes -
+ *      - Setting command ID, action and proper size
+ *      - Setting domain information fields (for SET only)
+ *      - Ensuring correct endian-ness
+ */
+static int mwifiex_cmd_802_11d_domain_info(struct mwifiex_private *priv,
+					   struct host_cmd_ds_command *cmd,
+					   u16 cmd_action)
+{
+	struct mwifiex_adapter *adapter = priv->adapter;
+	struct host_cmd_ds_802_11d_domain_info *domain_info =
+		&cmd->params.domain_info;
+	struct mwifiex_ietypes_domain_param_set *domain =
+		&domain_info->domain;
+	u8 no_of_triplet = adapter->domain_reg.no_of_triplet;
+
+	dev_dbg(adapter->dev, "info: 11D: no_of_triplet=0x%x\n", no_of_triplet);
+
+	cmd->command = cpu_to_le16(HostCmd_CMD_802_11D_DOMAIN_INFO);
+	domain_info->action = cpu_to_le16(cmd_action);
+	if (cmd_action == HostCmd_ACT_GEN_GET) {
+		cmd->size = cpu_to_le16(sizeof(domain_info->action) + S_DS_GEN);
+		return 0;
+	}
+
+	/* Set domain info fields */
+	domain->header.type = cpu_to_le16(WLAN_EID_COUNTRY);
+	memcpy(domain->country_code, adapter->domain_reg.country_code,
+			sizeof(domain->country_code));
+
+	domain->header.len = cpu_to_le16((no_of_triplet *
+				sizeof(struct ieee80211_country_ie_triplet)) +
+				sizeof(domain->country_code));
+
+	if (no_of_triplet) {
+		memcpy(domain->triplet, adapter->domain_reg.triplet,
+				no_of_triplet *
+				sizeof(struct ieee80211_country_ie_triplet));
+
+		cmd->size = cpu_to_le16(sizeof(domain_info->action) +
+				le16_to_cpu(domain->header.len) +
+				sizeof(struct mwifiex_ie_types_header)
+				+ S_DS_GEN);
+	} else {
+		cmd->size = cpu_to_le16(sizeof(domain_info->action) + S_DS_GEN);
+	}
+
+	return 0;
+}
+
+/*
+ * This function prepares command to set/get RF channel.
+ *
+ * Preparation includes -
+ *      - Setting command ID, action and proper size
+ *      - Setting RF type and current RF channel (for SET only)
+ *      - Ensuring correct endian-ness
+ */
+static int mwifiex_cmd_802_11_rf_channel(struct mwifiex_private *priv,
+					 struct host_cmd_ds_command *cmd,
+					 u16 cmd_action, void *data_buf)
+{
+	struct host_cmd_ds_802_11_rf_channel *rf_chan =
+		&cmd->params.rf_channel;
+	uint16_t rf_type = le16_to_cpu(rf_chan->rf_type);
+
+	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_RF_CHANNEL);
+	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_rf_channel)
+				+ S_DS_GEN);
+
+	if (cmd_action == HostCmd_ACT_GEN_SET) {
+		if ((priv->adapter->adhoc_start_band & BAND_A)
+		    || (priv->adapter->adhoc_start_band & BAND_AN))
+			rf_chan->rf_type =
+				cpu_to_le16(HostCmd_SCAN_RADIO_TYPE_A);
+
+		rf_type = le16_to_cpu(rf_chan->rf_type);
+		SET_SECONDARYCHAN(rf_type, priv->adapter->chan_offset);
+		rf_chan->current_channel = cpu_to_le16(*((u16 *) data_buf));
+	}
+	rf_chan->action = cpu_to_le16(cmd_action);
+	return 0;
+}
+
+/*
+ * This function prepares command to set/get IBSS coalescing status.
+ *
+ * Preparation includes -
+ *      - Setting command ID, action and proper size
+ *      - Setting status to enable or disable (for SET only)
+ *      - Ensuring correct endian-ness
+ */
+static int mwifiex_cmd_ibss_coalescing_status(struct mwifiex_private *priv,
+					      struct host_cmd_ds_command *cmd,
+					      u16 cmd_action, void *data_buf)
+{
+	struct host_cmd_ds_802_11_ibss_status *ibss_coal =
+		&(cmd->params.ibss_coalescing);
+	u16 enable = 0;
+
+	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_IBSS_COALESCING_STATUS);
+	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_ibss_status) +
+				S_DS_GEN);
+	cmd->result = 0;
+	ibss_coal->action = cpu_to_le16(cmd_action);
+
+	switch (cmd_action) {
+	case HostCmd_ACT_GEN_SET:
+		if (data_buf != NULL)
+			enable = *(u16 *) data_buf;
+		ibss_coal->enable = cpu_to_le16(enable);
+		break;
+
+		/* In other case.. Nothing to do */
+	case HostCmd_ACT_GEN_GET:
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+/*
+ * This function prepares command to set/get register value.
+ *
+ * Preparation includes -
+ *      - Setting command ID, action and proper size
+ *      - Setting register offset (for both GET and SET) and
+ *        register value (for SET only)
+ *      - Ensuring correct endian-ness
+ *
+ * The following type of registers can be accessed with this function -
+ *      - MAC register
+ *      - BBP register
+ *      - RF register
+ *      - PMIC register
+ *      - CAU register
+ *      - EEPROM
+ */
+static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd,
+				  u16 cmd_action, void *data_buf)
+{
+	struct mwifiex_ds_reg_rw *reg_rw;
+
+	reg_rw = (struct mwifiex_ds_reg_rw *) data_buf;
+	switch (le16_to_cpu(cmd->command)) {
+	case HostCmd_CMD_MAC_REG_ACCESS:
+	{
+		struct host_cmd_ds_mac_reg_access *mac_reg;
+
+		cmd->size = cpu_to_le16(sizeof(*mac_reg) + S_DS_GEN);
+		mac_reg = (struct host_cmd_ds_mac_reg_access *) &cmd->
+			params.mac_reg;
+		mac_reg->action = cpu_to_le16(cmd_action);
+		mac_reg->offset =
+			cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
+		mac_reg->value = reg_rw->value;
+		break;
+	}
+	case HostCmd_CMD_BBP_REG_ACCESS:
+	{
+		struct host_cmd_ds_bbp_reg_access *bbp_reg;
+
+		cmd->size = cpu_to_le16(sizeof(*bbp_reg) + S_DS_GEN);
+		bbp_reg = (struct host_cmd_ds_bbp_reg_access *) &cmd->
+			params.bbp_reg;
+		bbp_reg->action = cpu_to_le16(cmd_action);
+		bbp_reg->offset =
+			cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
+		bbp_reg->value = (u8) le32_to_cpu(reg_rw->value);
+		break;
+	}
+	case HostCmd_CMD_RF_REG_ACCESS:
+	{
+		struct host_cmd_ds_rf_reg_access *rf_reg;
+
+		cmd->size = cpu_to_le16(sizeof(*rf_reg) + S_DS_GEN);
+		rf_reg = (struct host_cmd_ds_rf_reg_access *) &cmd->
+			params.rf_reg;
+		rf_reg->action = cpu_to_le16(cmd_action);
+		rf_reg->offset =
+			cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
+		rf_reg->value = (u8) le32_to_cpu(reg_rw->value);
+		break;
+	}
+	case HostCmd_CMD_PMIC_REG_ACCESS:
+	{
+		struct host_cmd_ds_pmic_reg_access *pmic_reg;
+
+		cmd->size = cpu_to_le16(sizeof(*pmic_reg) + S_DS_GEN);
+		pmic_reg = (struct host_cmd_ds_pmic_reg_access *) &cmd->
+				params.pmic_reg;
+		pmic_reg->action = cpu_to_le16(cmd_action);
+		pmic_reg->offset =
+			cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
+		pmic_reg->value = (u8) le32_to_cpu(reg_rw->value);
+		break;
+	}
+	case HostCmd_CMD_CAU_REG_ACCESS:
+	{
+		struct host_cmd_ds_rf_reg_access *cau_reg;
+
+		cmd->size = cpu_to_le16(sizeof(*cau_reg) + S_DS_GEN);
+		cau_reg = (struct host_cmd_ds_rf_reg_access *) &cmd->
+				params.rf_reg;
+		cau_reg->action = cpu_to_le16(cmd_action);
+		cau_reg->offset =
+			cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
+		cau_reg->value = (u8) le32_to_cpu(reg_rw->value);
+		break;
+	}
+	case HostCmd_CMD_802_11_EEPROM_ACCESS:
+	{
+		struct mwifiex_ds_read_eeprom *rd_eeprom =
+			(struct mwifiex_ds_read_eeprom *) data_buf;
+		struct host_cmd_ds_802_11_eeprom_access *cmd_eeprom =
+			(struct host_cmd_ds_802_11_eeprom_access *)
+			&cmd->params.eeprom;
+
+		cmd->size = cpu_to_le16(sizeof(*cmd_eeprom) + S_DS_GEN);
+		cmd_eeprom->action = cpu_to_le16(cmd_action);
+		cmd_eeprom->offset = rd_eeprom->offset;
+		cmd_eeprom->byte_count = rd_eeprom->byte_count;
+		cmd_eeprom->value = 0;
+		break;
+	}
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * This function prepares the commands before sending them to the firmware.
+ *
+ * This is a generic function which calls specific command preparation
+ * routines based upon the command number.
+ */
+int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
+			    u16 cmd_action, u32 cmd_oid,
+			    void *data_buf, void *cmd_buf)
+{
+	struct host_cmd_ds_command *cmd_ptr =
+		(struct host_cmd_ds_command *) cmd_buf;
+	int ret = 0;
+
+	/* Prepare command */
+	switch (cmd_no) {
+	case HostCmd_CMD_GET_HW_SPEC:
+		ret = mwifiex_cmd_get_hw_spec(priv, cmd_ptr);
+		break;
+	case HostCmd_CMD_MAC_CONTROL:
+		ret = mwifiex_cmd_mac_control(priv, cmd_ptr, cmd_action,
+					      data_buf);
+		break;
+	case HostCmd_CMD_802_11_MAC_ADDRESS:
+		ret = mwifiex_cmd_802_11_mac_address(priv, cmd_ptr,
+						     cmd_action);
+		break;
+	case HostCmd_CMD_MAC_MULTICAST_ADR:
+		ret = mwifiex_cmd_mac_multicast_adr(priv, cmd_ptr, cmd_action,
+						    data_buf);
+		break;
+	case HostCmd_CMD_TX_RATE_CFG:
+		ret = mwifiex_cmd_tx_rate_cfg(priv, cmd_ptr, cmd_action,
+					      data_buf);
+		break;
+	case HostCmd_CMD_TXPWR_CFG:
+		ret = mwifiex_cmd_tx_power_cfg(priv, cmd_ptr, cmd_action,
+					       data_buf);
+		break;
+	case HostCmd_CMD_802_11_PS_MODE_ENH:
+		ret = mwifiex_cmd_enh_power_mode(priv, cmd_ptr, cmd_action,
+						 (uint16_t)cmd_oid, data_buf);
+		break;
+	case HostCmd_CMD_802_11_HS_CFG_ENH:
+		ret = mwifiex_cmd_802_11_hs_cfg(priv, cmd_ptr, cmd_action,
+				(struct mwifiex_hs_config_param *) data_buf);
+		break;
+	case HostCmd_CMD_802_11_SCAN:
+		ret = mwifiex_cmd_802_11_scan(priv, cmd_ptr, data_buf);
+		break;
+	case HostCmd_CMD_802_11_BG_SCAN_QUERY:
+		ret = mwifiex_cmd_802_11_bg_scan_query(priv, cmd_ptr,
+						       data_buf);
+		break;
+	case HostCmd_CMD_802_11_ASSOCIATE:
+		ret = mwifiex_cmd_802_11_associate(priv, cmd_ptr, data_buf);
+		break;
+	case HostCmd_CMD_802_11_DEAUTHENTICATE:
+		ret = mwifiex_cmd_802_11_deauthenticate(priv, cmd_ptr,
+							data_buf);
+		break;
+	case HostCmd_CMD_802_11_AD_HOC_START:
+		ret = mwifiex_cmd_802_11_ad_hoc_start(priv, cmd_ptr,
+						      data_buf);
+		break;
+	case HostCmd_CMD_802_11_GET_LOG:
+		ret = mwifiex_cmd_802_11_get_log(priv, cmd_ptr);
+		break;
+	case HostCmd_CMD_802_11_AD_HOC_JOIN:
+		ret = mwifiex_cmd_802_11_ad_hoc_join(priv, cmd_ptr,
+						     data_buf);
+		break;
+	case HostCmd_CMD_802_11_AD_HOC_STOP:
+		ret = mwifiex_cmd_802_11_ad_hoc_stop(priv, cmd_ptr);
+		break;
+	case HostCmd_CMD_RSSI_INFO:
+		ret = mwifiex_cmd_802_11_rssi_info(priv, cmd_ptr, cmd_action);
+		break;
+	case HostCmd_CMD_802_11_SNMP_MIB:
+		ret = mwifiex_cmd_802_11_snmp_mib(priv, cmd_ptr, cmd_action,
+						  cmd_oid, data_buf);
+		break;
+	case HostCmd_CMD_802_11_TX_RATE_QUERY:
+		cmd_ptr->command =
+			cpu_to_le16(HostCmd_CMD_802_11_TX_RATE_QUERY);
+		cmd_ptr->size =
+			cpu_to_le16(sizeof(struct host_cmd_ds_tx_rate_query) +
+				    S_DS_GEN);
+		priv->tx_rate = 0;
+		ret = 0;
+		break;
+	case HostCmd_CMD_VERSION_EXT:
+		cmd_ptr->command = cpu_to_le16(cmd_no);
+		cmd_ptr->params.verext.version_str_sel =
+			(u8) (*((u32 *) data_buf));
+		memcpy(&cmd_ptr->params, data_buf,
+		       sizeof(struct host_cmd_ds_version_ext));
+		cmd_ptr->size =
+			cpu_to_le16(sizeof(struct host_cmd_ds_version_ext) +
+				    S_DS_GEN);
+		ret = 0;
+		break;
+	case HostCmd_CMD_802_11_RF_CHANNEL:
+		ret = mwifiex_cmd_802_11_rf_channel(priv, cmd_ptr, cmd_action,
+						    data_buf);
+		break;
+	case HostCmd_CMD_FUNC_INIT:
+		if (priv->adapter->hw_status == MWIFIEX_HW_STATUS_RESET)
+			priv->adapter->hw_status = MWIFIEX_HW_STATUS_READY;
+		cmd_ptr->command = cpu_to_le16(cmd_no);
+		cmd_ptr->size = cpu_to_le16(S_DS_GEN);
+		break;
+	case HostCmd_CMD_FUNC_SHUTDOWN:
+		priv->adapter->hw_status = MWIFIEX_HW_STATUS_RESET;
+		cmd_ptr->command = cpu_to_le16(cmd_no);
+		cmd_ptr->size = cpu_to_le16(S_DS_GEN);
+		break;
+	case HostCmd_CMD_11N_ADDBA_REQ:
+		ret = mwifiex_cmd_11n_addba_req(priv, cmd_ptr, data_buf);
+		break;
+	case HostCmd_CMD_11N_DELBA:
+		ret = mwifiex_cmd_11n_delba(priv, cmd_ptr, data_buf);
+		break;
+	case HostCmd_CMD_11N_ADDBA_RSP:
+		ret = mwifiex_cmd_11n_addba_rsp_gen(priv, cmd_ptr, data_buf);
+		break;
+	case HostCmd_CMD_802_11_KEY_MATERIAL:
+		ret = mwifiex_cmd_802_11_key_material(priv, cmd_ptr,
+						cmd_action, cmd_oid,
+						data_buf);
+		break;
+	case HostCmd_CMD_802_11D_DOMAIN_INFO:
+		ret = mwifiex_cmd_802_11d_domain_info(priv, cmd_ptr,
+						cmd_action);
+		break;
+	case HostCmd_CMD_RECONFIGURE_TX_BUFF:
+		ret = mwifiex_cmd_recfg_tx_buf(priv, cmd_ptr, cmd_action,
+					       data_buf);
+		break;
+	case HostCmd_CMD_AMSDU_AGGR_CTRL:
+		ret = mwifiex_cmd_amsdu_aggr_ctrl(priv, cmd_ptr, cmd_action,
+						  data_buf);
+		break;
+	case HostCmd_CMD_11N_CFG:
+		ret = mwifiex_cmd_11n_cfg(priv, cmd_ptr, cmd_action,
+					  data_buf);
+		break;
+	case HostCmd_CMD_WMM_GET_STATUS:
+		dev_dbg(priv->adapter->dev,
+			"cmd: WMM: WMM_GET_STATUS cmd sent\n");
+		cmd_ptr->command = cpu_to_le16(HostCmd_CMD_WMM_GET_STATUS);
+		cmd_ptr->size =
+			cpu_to_le16(sizeof(struct host_cmd_ds_wmm_get_status) +
+				    S_DS_GEN);
+		ret = 0;
+		break;
+	case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:
+		ret = mwifiex_cmd_ibss_coalescing_status(priv, cmd_ptr,
+							 cmd_action, data_buf);
+		break;
+	case HostCmd_CMD_MAC_REG_ACCESS:
+	case HostCmd_CMD_BBP_REG_ACCESS:
+	case HostCmd_CMD_RF_REG_ACCESS:
+	case HostCmd_CMD_PMIC_REG_ACCESS:
+	case HostCmd_CMD_CAU_REG_ACCESS:
+	case HostCmd_CMD_802_11_EEPROM_ACCESS:
+		ret = mwifiex_cmd_reg_access(cmd_ptr, cmd_action, data_buf);
+		break;
+	case HostCmd_CMD_SET_BSS_MODE:
+		cmd_ptr->command = cpu_to_le16(cmd_no);
+		if (priv->bss_mode == NL80211_IFTYPE_ADHOC)
+			cmd_ptr->params.bss_mode.con_type =
+				CONNECTION_TYPE_ADHOC;
+		else if (priv->bss_mode == NL80211_IFTYPE_STATION)
+			cmd_ptr->params.bss_mode.con_type =
+				CONNECTION_TYPE_INFRA;
+		cmd_ptr->size = cpu_to_le16(sizeof(struct
+				host_cmd_ds_set_bss_mode) + S_DS_GEN);
+		ret = 0;
+		break;
+	default:
+		dev_err(priv->adapter->dev,
+			"PREP_CMD: unknown cmd- %#x\n", cmd_no);
+		ret = -1;
+		break;
+	}
+	return ret;
+}
+
+/*
+ * This function issues commands to initialize firmware.
+ *
+ * This is called after firmware download to bring the card to
+ * working state.
+ *
+ * The following commands are issued sequentially -
+ *      - Function init (for first interface only)
+ *      - Read MAC address (for first interface only)
+ *      - Reconfigure Tx buffer size (for first interface only)
+ *      - Enable auto deep sleep (for first interface only)
+ *      - Get Tx rate
+ *      - Get Tx power
+ *      - Set IBSS coalescing status
+ *      - Set AMSDU aggregation control
+ *      - Set 11d control
+ *      - Set MAC control (this must be the last command to initialize firmware)
+ */
+int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
+{
+	int ret = 0;
+	u16 enable = true;
+	struct mwifiex_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl;
+	struct mwifiex_ds_auto_ds auto_ds;
+	enum state_11d_t state_11d;
+
+	if (first_sta) {
+
+		ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_FUNC_INIT,
+					  HostCmd_ACT_GEN_SET, 0, NULL, NULL);
+		if (ret)
+			return -1;
+		/* Read MAC address from HW */
+		ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_GET_HW_SPEC,
+					  HostCmd_ACT_GEN_GET, 0, NULL, NULL);
+		if (ret)
+			return -1;
+
+		/* Reconfigure tx buf size */
+		ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF,
+					  HostCmd_ACT_GEN_SET, 0, NULL,
+					  &priv->adapter->tx_buf_size);
+		if (ret)
+			return -1;
+
+		/* Enable IEEE PS by default */
+		priv->adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP;
+		ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
+					  EN_AUTO_PS, BITMAP_STA_PS, NULL,
+					  NULL);
+		if (ret)
+			return -1;
+	}
+
+	/* get tx rate */
+	ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_TX_RATE_CFG,
+				  HostCmd_ACT_GEN_GET, 0, NULL, NULL);
+	if (ret)
+		return -1;
+	priv->data_rate = 0;
+
+	/* get tx power */
+	ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_TXPWR_CFG,
+				  HostCmd_ACT_GEN_GET, 0, NULL, NULL);
+	if (ret)
+		return -1;
+
+	/* set ibss coalescing_status */
+	ret = mwifiex_prepare_cmd(priv,
+				  HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
+				  HostCmd_ACT_GEN_SET, 0, NULL, &enable);
+	if (ret)
+		return -1;
+
+	memset(&amsdu_aggr_ctrl, 0, sizeof(amsdu_aggr_ctrl));
+	amsdu_aggr_ctrl.enable = true;
+	/* Send request to firmware */
+	ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_AMSDU_AGGR_CTRL,
+				  HostCmd_ACT_GEN_SET, 0, NULL,
+				  (void *) &amsdu_aggr_ctrl);
+	if (ret)
+		return -1;
+	/* MAC Control must be the last command in init_fw */
+	/* set MAC Control */
+	ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL,
+				  HostCmd_ACT_GEN_SET, 0, NULL,
+				  &priv->curr_pkt_filter);
+	if (ret)
+		return -1;
+
+	if (first_sta) {
+		/* Enable auto deep sleep */
+		auto_ds.auto_ds = DEEP_SLEEP_ON;
+		auto_ds.idle_time = DEEP_SLEEP_IDLE_TIME;
+		ret = mwifiex_prepare_cmd(priv,
+				HostCmd_CMD_802_11_PS_MODE_ENH,
+				EN_AUTO_PS, BITMAP_AUTO_DS, NULL,
+				&auto_ds);
+		if (ret)
+			return -1;
+	}
+
+	/* Send cmd to FW to enable/disable 11D function */
+	state_11d = ENABLE_11D;
+	ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
+				  HostCmd_ACT_GEN_SET, DOT11D_I,
+				  NULL, &state_11d);
+	if (ret)
+		dev_err(priv->adapter->dev, "11D: failed to enable 11D\n");
+
+	/* set last_init_cmd */
+	priv->adapter->last_init_cmd = HostCmd_CMD_802_11_SNMP_MIB;
+	ret = -EINPROGRESS;
+
+	return ret;
+}
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c
new file mode 100644
index 0000000..74add45
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c
@@ -0,0 +1,983 @@
+/*
+ * Marvell Wireless LAN device driver: station command response handling
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+#include "11n.h"
+
+
+/*
+ * This function handles the command response error case.
+ *
+ * For scan response error, the function cancels all the pending
+ * scan commands and generates an event to inform the applications
+ * of the scan completion.
+ *
+ * For Power Save command failure, we do not retry enter PS
+ * command in case of Ad-hoc mode.
+ *
+ * For all other response errors, the current command buffer is freed
+ * and returned to the free command queue.
+ */
+static void
+mwifiex_process_cmdresp_error(struct mwifiex_private *priv,
+			      struct host_cmd_ds_command *resp,
+			      struct mwifiex_wait_queue *wq_buf)
+{
+	struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL;
+	struct mwifiex_adapter *adapter = priv->adapter;
+	struct host_cmd_ds_802_11_ps_mode_enh *pm;
+	unsigned long flags;
+
+	dev_err(adapter->dev, "CMD_RESP: cmd %#x error, result=%#x\n",
+			resp->command, resp->result);
+	if (wq_buf)
+		wq_buf->status = MWIFIEX_ERROR_FW_CMDRESP;
+
+	switch (le16_to_cpu(resp->command)) {
+	case HostCmd_CMD_802_11_PS_MODE_ENH:
+		pm = &resp->params.psmode_enh;
+		dev_err(adapter->dev, "PS_MODE_ENH cmd failed: "
+					"result=0x%x action=0x%X\n",
+				resp->result, le16_to_cpu(pm->action));
+		/* We do not re-try enter-ps command in ad-hoc mode. */
+		if (le16_to_cpu(pm->action) == EN_AUTO_PS &&
+			(le16_to_cpu(pm->params.ps_bitmap) & BITMAP_STA_PS) &&
+				priv->bss_mode == NL80211_IFTYPE_ADHOC)
+			adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM;
+
+		break;
+	case HostCmd_CMD_802_11_SCAN:
+		/* Cancel all pending scan command */
+		spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+		list_for_each_entry_safe(cmd_node, tmp_node,
+					 &adapter->scan_pending_q, list) {
+			list_del(&cmd_node->list);
+			spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
+					       flags);
+			mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+			spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+		}
+		spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+
+		spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+		adapter->scan_processing = false;
+		spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+		if (priv->report_scan_result)
+			priv->report_scan_result = false;
+		if (priv->scan_pending_on_block) {
+			priv->scan_pending_on_block = false;
+			up(&priv->async_sem);
+		}
+		break;
+
+	case HostCmd_CMD_MAC_CONTROL:
+		break;
+
+	default:
+		break;
+	}
+	/* Handling errors here */
+	mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
+
+	spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+	adapter->curr_cmd = NULL;
+	spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+
+	return;
+}
+
+/*
+ * This function handles the command response of get RSSI info.
+ *
+ * Handling includes changing the header fields into CPU format
+ * and saving the following parameters in driver -
+ *      - Last data and beacon RSSI value
+ *      - Average data and beacon RSSI value
+ *      - Last data and beacon NF value
+ *      - Average data and beacon NF value
+ *
+ * The parameters are send to the application as well, along with
+ * calculated SNR values.
+ */
+static int mwifiex_ret_802_11_rssi_info(struct mwifiex_private *priv,
+					struct host_cmd_ds_command *resp,
+					void *data_buf)
+{
+	struct host_cmd_ds_802_11_rssi_info_rsp *rssi_info_rsp =
+		&resp->params.rssi_info_rsp;
+	struct mwifiex_ds_get_signal *signal = NULL;
+
+	priv->data_rssi_last = le16_to_cpu(rssi_info_rsp->data_rssi_last);
+	priv->data_nf_last = le16_to_cpu(rssi_info_rsp->data_nf_last);
+
+	priv->data_rssi_avg = le16_to_cpu(rssi_info_rsp->data_rssi_avg);
+	priv->data_nf_avg = le16_to_cpu(rssi_info_rsp->data_nf_avg);
+
+	priv->bcn_rssi_last = le16_to_cpu(rssi_info_rsp->bcn_rssi_last);
+	priv->bcn_nf_last = le16_to_cpu(rssi_info_rsp->bcn_nf_last);
+
+	priv->bcn_rssi_avg = le16_to_cpu(rssi_info_rsp->bcn_rssi_avg);
+	priv->bcn_nf_avg = le16_to_cpu(rssi_info_rsp->bcn_nf_avg);
+
+	/* Need to indicate IOCTL complete */
+	if (data_buf) {
+		signal = (struct mwifiex_ds_get_signal *) data_buf;
+		memset(signal, 0, sizeof(struct mwifiex_ds_get_signal));
+
+		signal->selector = ALL_RSSI_INFO_MASK;
+
+		/* RSSI */
+		signal->bcn_rssi_last = priv->bcn_rssi_last;
+		signal->bcn_rssi_avg = priv->bcn_rssi_avg;
+		signal->data_rssi_last = priv->data_rssi_last;
+		signal->data_rssi_avg = priv->data_rssi_avg;
+
+		/* SNR */
+		signal->bcn_snr_last =
+			CAL_SNR(priv->bcn_rssi_last, priv->bcn_nf_last);
+		signal->bcn_snr_avg =
+			CAL_SNR(priv->bcn_rssi_avg, priv->bcn_nf_avg);
+		signal->data_snr_last =
+			CAL_SNR(priv->data_rssi_last, priv->data_nf_last);
+		signal->data_snr_avg =
+			CAL_SNR(priv->data_rssi_avg, priv->data_nf_avg);
+
+		/* NF */
+		signal->bcn_nf_last = priv->bcn_nf_last;
+		signal->bcn_nf_avg = priv->bcn_nf_avg;
+		signal->data_nf_last = priv->data_nf_last;
+		signal->data_nf_avg = priv->data_nf_avg;
+	}
+
+	return 0;
+}
+
+/*
+ * This function handles the command response of set/get SNMP
+ * MIB parameters.
+ *
+ * Handling includes changing the header fields into CPU format
+ * and saving the parameter in driver.
+ *
+ * The following parameters are supported -
+ *      - Fragmentation threshold
+ *      - RTS threshold
+ *      - Short retry limit
+ */
+static int mwifiex_ret_802_11_snmp_mib(struct mwifiex_private *priv,
+				       struct host_cmd_ds_command *resp,
+				       void *data_buf)
+{
+	struct host_cmd_ds_802_11_snmp_mib *smib = &resp->params.smib;
+	u16 oid = le16_to_cpu(smib->oid);
+	u16 query_type = le16_to_cpu(smib->query_type);
+	u32 ul_temp;
+
+	dev_dbg(priv->adapter->dev, "info: SNMP_RESP: oid value = %#x,"
+			" query_type = %#x, buf size = %#x\n",
+			oid, query_type, le16_to_cpu(smib->buf_size));
+	if (query_type == HostCmd_ACT_GEN_GET) {
+		ul_temp = le16_to_cpu(*((__le16 *) (smib->value)));
+		if (data_buf)
+			*(u32 *)data_buf = ul_temp;
+		switch (oid) {
+		case FRAG_THRESH_I:
+			dev_dbg(priv->adapter->dev,
+				"info: SNMP_RESP: FragThsd =%u\n", ul_temp);
+			break;
+		case RTS_THRESH_I:
+			dev_dbg(priv->adapter->dev,
+				"info: SNMP_RESP: RTSThsd =%u\n", ul_temp);
+			break;
+		case SHORT_RETRY_LIM_I:
+			dev_dbg(priv->adapter->dev,
+				"info: SNMP_RESP: TxRetryCount=%u\n", ul_temp);
+			break;
+		default:
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * This function handles the command response of get log request
+ *
+ * Handling includes changing the header fields into CPU format
+ * and sending the received parameters to application.
+ */
+static int mwifiex_ret_get_log(struct mwifiex_private *priv,
+			       struct host_cmd_ds_command *resp,
+			       void *data_buf)
+{
+	struct host_cmd_ds_802_11_get_log *get_log =
+		(struct host_cmd_ds_802_11_get_log *) &resp->params.get_log;
+	struct mwifiex_ds_get_stats *stats = NULL;
+
+	if (data_buf) {
+		stats = (struct mwifiex_ds_get_stats *) data_buf;
+		stats->mcast_tx_frame = le32_to_cpu(get_log->mcast_tx_frame);
+		stats->failed = le32_to_cpu(get_log->failed);
+		stats->retry = le32_to_cpu(get_log->retry);
+		stats->multi_retry = le32_to_cpu(get_log->multi_retry);
+		stats->frame_dup = le32_to_cpu(get_log->frame_dup);
+		stats->rts_success = le32_to_cpu(get_log->rts_success);
+		stats->rts_failure = le32_to_cpu(get_log->rts_failure);
+		stats->ack_failure = le32_to_cpu(get_log->ack_failure);
+		stats->rx_frag = le32_to_cpu(get_log->rx_frag);
+		stats->mcast_rx_frame = le32_to_cpu(get_log->mcast_rx_frame);
+		stats->fcs_error = le32_to_cpu(get_log->fcs_error);
+		stats->tx_frame = le32_to_cpu(get_log->tx_frame);
+		stats->wep_icv_error[0] =
+			le32_to_cpu(get_log->wep_icv_err_cnt[0]);
+		stats->wep_icv_error[1] =
+			le32_to_cpu(get_log->wep_icv_err_cnt[1]);
+		stats->wep_icv_error[2] =
+			le32_to_cpu(get_log->wep_icv_err_cnt[2]);
+		stats->wep_icv_error[3] =
+			le32_to_cpu(get_log->wep_icv_err_cnt[3]);
+	}
+
+	return 0;
+}
+
+/*
+ * This function handles the command response of set/get Tx rate
+ * configurations.
+ *
+ * Handling includes changing the header fields into CPU format
+ * and saving the following parameters in driver -
+ *      - DSSS rate bitmap
+ *      - OFDM rate bitmap
+ *      - HT MCS rate bitmaps
+ *
+ * Based on the new rate bitmaps, the function re-evaluates if
+ * auto data rate has been activated. If not, it sends another
+ * query to the firmware to get the current Tx data rate and updates
+ * the driver value.
+ */
+static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv,
+				   struct host_cmd_ds_command *resp,
+				   void *data_buf)
+{
+	struct mwifiex_adapter *adapter = priv->adapter;
+	struct mwifiex_rate_cfg *ds_rate = NULL;
+	struct host_cmd_ds_tx_rate_cfg *rate_cfg = &resp->params.tx_rate_cfg;
+	struct mwifiex_rate_scope *rate_scope;
+	struct mwifiex_ie_types_header *head = NULL;
+	u16 tlv, tlv_buf_len;
+	u8 *tlv_buf;
+	u32 i;
+	int ret = 0;
+
+	tlv_buf = (u8 *) ((u8 *) rate_cfg) +
+			sizeof(struct host_cmd_ds_tx_rate_cfg);
+	tlv_buf_len = *(u16 *) (tlv_buf + sizeof(u16));
+
+	while (tlv_buf && tlv_buf_len > 0) {
+		tlv = (*tlv_buf);
+		tlv = tlv | (*(tlv_buf + 1) << 8);
+
+		switch (tlv) {
+		case TLV_TYPE_RATE_SCOPE:
+			rate_scope = (struct mwifiex_rate_scope *) tlv_buf;
+			priv->bitmap_rates[0] =
+				le16_to_cpu(rate_scope->hr_dsss_rate_bitmap);
+			priv->bitmap_rates[1] =
+				le16_to_cpu(rate_scope->ofdm_rate_bitmap);
+			for (i = 0;
+			     i <
+			     sizeof(rate_scope->ht_mcs_rate_bitmap) /
+			     sizeof(u16); i++)
+				priv->bitmap_rates[2 + i] =
+					le16_to_cpu(rate_scope->
+						    ht_mcs_rate_bitmap[i]);
+			break;
+			/* Add RATE_DROP tlv here */
+		}
+
+		head = (struct mwifiex_ie_types_header *) tlv_buf;
+		tlv_buf += le16_to_cpu(head->len) + sizeof(*head);
+		tlv_buf_len -= le16_to_cpu(head->len);
+	}
+
+	priv->is_data_rate_auto = mwifiex_is_rate_auto(priv);
+
+	if (priv->is_data_rate_auto)
+		priv->data_rate = 0;
+	else
+		ret = mwifiex_prepare_cmd(priv,
+					  HostCmd_CMD_802_11_TX_RATE_QUERY,
+					  HostCmd_ACT_GEN_GET, 0, NULL, NULL);
+
+	if (data_buf) {
+		ds_rate = (struct mwifiex_rate_cfg *) data_buf;
+		if (le16_to_cpu(rate_cfg->action) == HostCmd_ACT_GEN_GET) {
+			if (priv->is_data_rate_auto) {
+				ds_rate->is_rate_auto = 1;
+			} else {
+				ds_rate->rate =
+					mwifiex_get_rate_index(adapter,
+							       priv->
+							       bitmap_rates,
+							       sizeof(priv->
+							       bitmap_rates));
+				if (ds_rate->rate >=
+				    MWIFIEX_RATE_BITMAP_OFDM0
+				    && ds_rate->rate <=
+				    MWIFIEX_RATE_BITMAP_OFDM7)
+					ds_rate->rate -=
+						(MWIFIEX_RATE_BITMAP_OFDM0 -
+						 MWIFIEX_RATE_INDEX_OFDM0);
+				if (ds_rate->rate >=
+				    MWIFIEX_RATE_BITMAP_MCS0
+				    && ds_rate->rate <=
+				    MWIFIEX_RATE_BITMAP_MCS127)
+					ds_rate->rate -=
+						(MWIFIEX_RATE_BITMAP_MCS0 -
+						 MWIFIEX_RATE_INDEX_MCS0);
+			}
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * This function handles the command response of get Tx power level.
+ *
+ * Handling includes saving the maximum and minimum Tx power levels
+ * in driver, as well as sending the values to user.
+ */
+static int mwifiex_get_power_level(struct mwifiex_private *priv, void *data_buf)
+{
+	int length = -1, max_power = -1, min_power = -1;
+	struct mwifiex_types_power_group *pg_tlv_hdr = NULL;
+	struct mwifiex_power_group *pg = NULL;
+
+	if (data_buf) {
+		pg_tlv_hdr =
+			(struct mwifiex_types_power_group *) ((u8 *) data_buf
+					+ sizeof(struct host_cmd_ds_txpwr_cfg));
+		pg = (struct mwifiex_power_group *) ((u8 *) pg_tlv_hdr +
+				sizeof(struct mwifiex_types_power_group));
+		length = pg_tlv_hdr->length;
+		if (length > 0) {
+			max_power = pg->power_max;
+			min_power = pg->power_min;
+			length -= sizeof(struct mwifiex_power_group);
+		}
+		while (length) {
+			pg++;
+			if (max_power < pg->power_max)
+				max_power = pg->power_max;
+
+			if (min_power > pg->power_min)
+				min_power = pg->power_min;
+
+			length -= sizeof(struct mwifiex_power_group);
+		}
+		if (pg_tlv_hdr->length > 0) {
+			priv->min_tx_power_level = (u8) min_power;
+			priv->max_tx_power_level = (u8) max_power;
+		}
+	} else {
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * This function handles the command response of set/get Tx power
+ * configurations.
+ *
+ * Handling includes changing the header fields into CPU format
+ * and saving the current Tx power level in driver.
+ */
+static int mwifiex_ret_tx_power_cfg(struct mwifiex_private *priv,
+				    struct host_cmd_ds_command *resp,
+				    void *data_buf)
+{
+	struct mwifiex_adapter *adapter = priv->adapter;
+	struct host_cmd_ds_txpwr_cfg *txp_cfg = &resp->params.txp_cfg;
+	struct mwifiex_types_power_group *pg_tlv_hdr = NULL;
+	struct mwifiex_power_group *pg = NULL;
+	u16 action = le16_to_cpu(txp_cfg->action);
+
+	switch (action) {
+	case HostCmd_ACT_GEN_GET:
+		{
+			pg_tlv_hdr =
+				(struct mwifiex_types_power_group *) ((u8 *)
+						txp_cfg +
+						sizeof
+						(struct
+						 host_cmd_ds_txpwr_cfg));
+			pg = (struct mwifiex_power_group *) ((u8 *)
+						pg_tlv_hdr +
+						sizeof(struct
+						mwifiex_types_power_group));
+			if (adapter->hw_status ==
+			    MWIFIEX_HW_STATUS_INITIALIZING)
+				mwifiex_get_power_level(priv, txp_cfg);
+			priv->tx_power_level = (u16) pg->power_min;
+			break;
+		}
+	case HostCmd_ACT_GEN_SET:
+		if (le32_to_cpu(txp_cfg->mode)) {
+			pg_tlv_hdr =
+				(struct mwifiex_types_power_group *) ((u8 *)
+						txp_cfg +
+						sizeof
+						(struct
+						 host_cmd_ds_txpwr_cfg));
+			pg = (struct mwifiex_power_group *) ((u8 *) pg_tlv_hdr
+						+
+						sizeof(struct
+						mwifiex_types_power_group));
+			if (pg->power_max == pg->power_min)
+				priv->tx_power_level = (u16) pg->power_min;
+		}
+		break;
+	default:
+		dev_err(adapter->dev, "CMD_RESP: unknown cmd action %d\n",
+				action);
+		return 0;
+	}
+	dev_dbg(adapter->dev,
+		"info: Current TxPower Level = %d, Max Power=%d, Min Power=%d\n",
+	       priv->tx_power_level, priv->max_tx_power_level,
+	       priv->min_tx_power_level);
+
+	return 0;
+}
+
+/*
+ * This function handles the command response of set/get MAC address.
+ *
+ * Handling includes saving the MAC address in driver.
+ */
+static int mwifiex_ret_802_11_mac_address(struct mwifiex_private *priv,
+					  struct host_cmd_ds_command *resp)
+{
+	struct host_cmd_ds_802_11_mac_address *cmd_mac_addr =
+		&resp->params.mac_addr;
+
+	memcpy(priv->curr_addr, cmd_mac_addr->mac_addr, ETH_ALEN);
+
+	dev_dbg(priv->adapter->dev,
+		"info: set mac address: %pM\n", priv->curr_addr);
+
+	return 0;
+}
+
+/*
+ * This function handles the command response of set/get MAC multicast
+ * address.
+ */
+static int mwifiex_ret_mac_multicast_adr(struct mwifiex_private *priv,
+					 struct host_cmd_ds_command *resp)
+{
+	return 0;
+}
+
+/*
+ * This function handles the command response of get Tx rate query.
+ *
+ * Handling includes changing the header fields into CPU format
+ * and saving the Tx rate and HT information parameters in driver.
+ *
+ * Both rate configuration and current data rate can be retrieved
+ * with this request.
+ */
+static int mwifiex_ret_802_11_tx_rate_query(struct mwifiex_private *priv,
+					    struct host_cmd_ds_command *resp)
+{
+	struct mwifiex_adapter *adapter = priv->adapter;
+
+	priv->tx_rate = resp->params.tx_rate.tx_rate;
+	priv->tx_htinfo = resp->params.tx_rate.ht_info;
+	if (!priv->is_data_rate_auto)
+		priv->data_rate =
+			mwifiex_index_to_data_rate(adapter, priv->tx_rate,
+						   priv->tx_htinfo);
+
+	return 0;
+}
+
+/*
+ * This function handles the command response of a deauthenticate
+ * command.
+ *
+ * If the deauthenticated MAC matches the current BSS MAC, the connection
+ * state is reset.
+ */
+static int mwifiex_ret_802_11_deauthenticate(struct mwifiex_private *priv,
+					     struct host_cmd_ds_command *resp)
+{
+	struct mwifiex_adapter *adapter = priv->adapter;
+
+	adapter->dbg.num_cmd_deauth++;
+	if (!memcmp(resp->params.deauth.mac_addr,
+		    &priv->curr_bss_params.bss_descriptor.mac_address,
+		    sizeof(resp->params.deauth.mac_addr)))
+		mwifiex_reset_connect_state(priv);
+
+	return 0;
+}
+
+/*
+ * This function handles the command response of ad-hoc stop.
+ *
+ * The function resets the connection state in driver.
+ */
+static int mwifiex_ret_802_11_ad_hoc_stop(struct mwifiex_private *priv,
+					  struct host_cmd_ds_command *resp)
+{
+	mwifiex_reset_connect_state(priv);
+	return 0;
+}
+
+/*
+ * This function handles the command response of set/get key material.
+ *
+ * Handling includes updating the driver parameters to reflect the
+ * changes.
+ */
+static int mwifiex_ret_802_11_key_material(struct mwifiex_private *priv,
+					   struct host_cmd_ds_command *resp)
+{
+	struct host_cmd_ds_802_11_key_material *key =
+		&resp->params.key_material;
+
+	if (le16_to_cpu(key->action) == HostCmd_ACT_GEN_SET) {
+		if ((le16_to_cpu(key->key_param_set.key_info) &
+		     KEY_INFO_TKIP_MCAST)) {
+			dev_dbg(priv->adapter->dev, "info: key: GTK is set\n");
+			priv->wpa_is_gtk_set = true;
+			priv->scan_block = false;
+		}
+	}
+
+	memset(priv->aes_key.key_param_set.key, 0,
+	       sizeof(key->key_param_set.key));
+	priv->aes_key.key_param_set.key_len = key->key_param_set.key_len;
+	memcpy(priv->aes_key.key_param_set.key, key->key_param_set.key,
+	       le16_to_cpu(priv->aes_key.key_param_set.key_len));
+
+	return 0;
+}
+
+/*
+ * This function handles the command response of get 11d domain information.
+ */
+static int mwifiex_ret_802_11d_domain_info(struct mwifiex_private *priv,
+					   struct host_cmd_ds_command *resp)
+{
+	struct host_cmd_ds_802_11d_domain_info_rsp *domain_info =
+		&resp->params.domain_info_resp;
+	struct mwifiex_ietypes_domain_param_set *domain = &domain_info->domain;
+	u16 action = le16_to_cpu(domain_info->action);
+	u8 no_of_triplet = 0;
+
+	no_of_triplet = (u8) ((le16_to_cpu(domain->header.len) -
+					IEEE80211_COUNTRY_STRING_LEN) /
+				sizeof(struct ieee80211_country_ie_triplet));
+
+	dev_dbg(priv->adapter->dev, "info: 11D Domain Info Resp:"
+			" no_of_triplet=%d\n", no_of_triplet);
+
+	if (no_of_triplet > MWIFIEX_MAX_TRIPLET_802_11D) {
+		dev_warn(priv->adapter->dev,
+			"11D: invalid number of triplets %d "
+			"returned!!\n", no_of_triplet);
+		return -1;
+	}
+
+	switch (action) {
+	case HostCmd_ACT_GEN_SET:  /* Proc Set Action */
+		break;
+	case HostCmd_ACT_GEN_GET:
+		break;
+	default:
+		dev_err(priv->adapter->dev,
+			"11D: invalid action:%d\n", domain_info->action);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * This function handles the command response of get RF channel.
+ *
+ * Handling includes changing the header fields into CPU format
+ * and saving the new channel in driver.
+ */
+static int mwifiex_ret_802_11_rf_channel(struct mwifiex_private *priv,
+					 struct host_cmd_ds_command *resp,
+					 void *data_buf)
+{
+	struct host_cmd_ds_802_11_rf_channel *rf_channel =
+		&resp->params.rf_channel;
+	u16 new_channel = le16_to_cpu(rf_channel->current_channel);
+
+	if (priv->curr_bss_params.bss_descriptor.channel != new_channel) {
+		dev_dbg(priv->adapter->dev, "cmd: Channel Switch: %d to %d\n",
+		       priv->curr_bss_params.bss_descriptor.channel,
+		       new_channel);
+		/* Update the channel again */
+		priv->curr_bss_params.bss_descriptor.channel = new_channel;
+	}
+	if (data_buf)
+		*((u16 *)data_buf) = new_channel;
+
+	return 0;
+}
+
+/*
+ * This function handles the command response of get extended version.
+ *
+ * Handling includes forming the extended version string and sending it
+ * to application.
+ */
+static int mwifiex_ret_ver_ext(struct mwifiex_private *priv,
+			       struct host_cmd_ds_command *resp,
+			       void *data_buf)
+{
+	struct host_cmd_ds_version_ext *ver_ext = &resp->params.verext;
+	struct host_cmd_ds_version_ext *version_ext = NULL;
+
+	if (data_buf) {
+		version_ext = (struct host_cmd_ds_version_ext *)data_buf;
+		version_ext->version_str_sel = ver_ext->version_str_sel;
+		memcpy(version_ext->version_str, ver_ext->version_str,
+		       sizeof(char) * 128);
+		memcpy(priv->version_str, ver_ext->version_str, 128);
+	}
+	return 0;
+}
+
+/*
+ * This function handles the command response of register access.
+ *
+ * The register value and offset are returned to the user. For EEPROM
+ * access, the byte count is also returned.
+ */
+static int mwifiex_ret_reg_access(u16 type, struct host_cmd_ds_command *resp,
+				  void *data_buf)
+{
+	struct mwifiex_ds_reg_rw *reg_rw = NULL;
+	struct mwifiex_ds_read_eeprom *eeprom = NULL;
+
+	if (data_buf) {
+		reg_rw = (struct mwifiex_ds_reg_rw *) data_buf;
+		eeprom = (struct mwifiex_ds_read_eeprom *) data_buf;
+		switch (type) {
+		case HostCmd_CMD_MAC_REG_ACCESS:
+			{
+				struct host_cmd_ds_mac_reg_access *reg;
+				reg = (struct host_cmd_ds_mac_reg_access *)
+					&resp->params.mac_reg;
+				reg_rw->offset = cpu_to_le32(
+					(u32) le16_to_cpu(reg->offset));
+				reg_rw->value = reg->value;
+				break;
+			}
+		case HostCmd_CMD_BBP_REG_ACCESS:
+			{
+				struct host_cmd_ds_bbp_reg_access *reg;
+				reg = (struct host_cmd_ds_bbp_reg_access *)
+					&resp->params.bbp_reg;
+				reg_rw->offset = cpu_to_le32(
+					(u32) le16_to_cpu(reg->offset));
+				reg_rw->value = cpu_to_le32((u32) reg->value);
+				break;
+			}
+
+		case HostCmd_CMD_RF_REG_ACCESS:
+			{
+				struct host_cmd_ds_rf_reg_access *reg;
+				reg = (struct host_cmd_ds_rf_reg_access *)
+					&resp->params.rf_reg;
+				reg_rw->offset = cpu_to_le32(
+					(u32) le16_to_cpu(reg->offset));
+				reg_rw->value = cpu_to_le32((u32) reg->value);
+				break;
+			}
+		case HostCmd_CMD_PMIC_REG_ACCESS:
+			{
+				struct host_cmd_ds_pmic_reg_access *reg;
+				reg = (struct host_cmd_ds_pmic_reg_access *)
+					&resp->params.pmic_reg;
+				reg_rw->offset = cpu_to_le32(
+					(u32) le16_to_cpu(reg->offset));
+				reg_rw->value = cpu_to_le32((u32) reg->value);
+				break;
+			}
+		case HostCmd_CMD_CAU_REG_ACCESS:
+			{
+				struct host_cmd_ds_rf_reg_access *reg;
+				reg = (struct host_cmd_ds_rf_reg_access *)
+					&resp->params.rf_reg;
+				reg_rw->offset = cpu_to_le32(
+					(u32) le16_to_cpu(reg->offset));
+				reg_rw->value = cpu_to_le32((u32) reg->value);
+				break;
+			}
+		case HostCmd_CMD_802_11_EEPROM_ACCESS:
+			{
+				struct host_cmd_ds_802_11_eeprom_access
+					*cmd_eeprom =
+					(struct host_cmd_ds_802_11_eeprom_access
+					 *) &resp->params.eeprom;
+				pr_debug("info: EEPROM read len=%x\n",
+				       cmd_eeprom->byte_count);
+				if (le16_to_cpu(eeprom->byte_count) <
+						le16_to_cpu(
+						cmd_eeprom->byte_count)) {
+					eeprom->byte_count = cpu_to_le16(0);
+					pr_debug("info: EEPROM read "
+							"length is too big\n");
+					return -1;
+				}
+				eeprom->offset = cmd_eeprom->offset;
+				eeprom->byte_count = cmd_eeprom->byte_count;
+				if (le16_to_cpu(eeprom->byte_count) > 0)
+					memcpy(&eeprom->value,
+					       &cmd_eeprom->value,
+					       le16_to_cpu(eeprom->byte_count));
+
+				break;
+			}
+		default:
+			return -1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * This function handles the command response of get IBSS coalescing status.
+ *
+ * If the received BSSID is different than the current one, the current BSSID,
+ * beacon interval, ATIM window and ERP information are updated, along with
+ * changing the ad-hoc state accordingly.
+ */
+static int mwifiex_ret_ibss_coalescing_status(struct mwifiex_private *priv,
+					      struct host_cmd_ds_command *resp)
+{
+	struct host_cmd_ds_802_11_ibss_status *ibss_coal_resp =
+		&(resp->params.ibss_coalescing);
+	u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+
+	if (le16_to_cpu(ibss_coal_resp->action) == HostCmd_ACT_GEN_SET)
+		return 0;
+
+	dev_dbg(priv->adapter->dev,
+		"info: new BSSID %pM\n", ibss_coal_resp->bssid);
+
+	/* If rsp has NULL BSSID, Just return..... No Action */
+	if (!memcmp(ibss_coal_resp->bssid, zero_mac, ETH_ALEN)) {
+		dev_warn(priv->adapter->dev, "new BSSID is NULL\n");
+		return 0;
+	}
+
+	/* If BSSID is diff, modify current BSS parameters */
+	if (memcmp(priv->curr_bss_params.bss_descriptor.mac_address,
+		   ibss_coal_resp->bssid, ETH_ALEN)) {
+		/* BSSID */
+		memcpy(priv->curr_bss_params.bss_descriptor.mac_address,
+		       ibss_coal_resp->bssid, ETH_ALEN);
+
+		/* Beacon Interval */
+		priv->curr_bss_params.bss_descriptor.beacon_period
+			= le16_to_cpu(ibss_coal_resp->beacon_interval);
+
+		/* ERP Information */
+		priv->curr_bss_params.bss_descriptor.erp_flags =
+			(u8) le16_to_cpu(ibss_coal_resp->use_g_rate_protect);
+
+		priv->adhoc_state = ADHOC_COALESCED;
+	}
+
+	return 0;
+}
+
+/*
+ * This function handles the command responses.
+ *
+ * This is a generic function, which calls command specific
+ * response handlers based on the command ID.
+ */
+int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv,
+				u16 cmdresp_no, void *cmd_buf, void *wq_buf)
+{
+	int ret = 0;
+	struct mwifiex_adapter *adapter = priv->adapter;
+	struct host_cmd_ds_command *resp =
+		(struct host_cmd_ds_command *) cmd_buf;
+	struct mwifiex_wait_queue *wait_queue =
+		(struct mwifiex_wait_queue *) wq_buf;
+	void *data_buf = adapter->curr_cmd->data_buf;
+
+	/* If the command is not successful, cleanup and return failure */
+	if (resp->result != HostCmd_RESULT_OK) {
+		mwifiex_process_cmdresp_error(priv, resp, wait_queue);
+		return -1;
+	}
+	/* Command successful, handle response */
+	switch (cmdresp_no) {
+	case HostCmd_CMD_GET_HW_SPEC:
+		ret = mwifiex_ret_get_hw_spec(priv, resp);
+		break;
+	case HostCmd_CMD_MAC_CONTROL:
+		break;
+	case HostCmd_CMD_802_11_MAC_ADDRESS:
+		ret = mwifiex_ret_802_11_mac_address(priv, resp);
+		break;
+	case HostCmd_CMD_MAC_MULTICAST_ADR:
+		ret = mwifiex_ret_mac_multicast_adr(priv, resp);
+		break;
+	case HostCmd_CMD_TX_RATE_CFG:
+		ret = mwifiex_ret_tx_rate_cfg(priv, resp, data_buf);
+		break;
+	case HostCmd_CMD_802_11_SCAN:
+		ret = mwifiex_ret_802_11_scan(priv, resp, wait_queue);
+		wait_queue = NULL;
+		adapter->curr_cmd->wq_buf = NULL;
+		break;
+	case HostCmd_CMD_802_11_BG_SCAN_QUERY:
+		ret = mwifiex_ret_802_11_scan(priv, resp, wait_queue);
+		dev_dbg(adapter->dev,
+			"info: CMD_RESP: BG_SCAN result is ready!\n");
+		break;
+	case HostCmd_CMD_TXPWR_CFG:
+		ret = mwifiex_ret_tx_power_cfg(priv, resp, data_buf);
+		break;
+	case HostCmd_CMD_802_11_PS_MODE_ENH:
+		ret = mwifiex_ret_enh_power_mode(priv, resp, data_buf);
+		break;
+	case HostCmd_CMD_802_11_HS_CFG_ENH:
+		ret = mwifiex_ret_802_11_hs_cfg(priv, resp);
+		break;
+	case HostCmd_CMD_802_11_ASSOCIATE:
+		ret = mwifiex_ret_802_11_associate(priv, resp, wait_queue);
+		break;
+	case HostCmd_CMD_802_11_DEAUTHENTICATE:
+		ret = mwifiex_ret_802_11_deauthenticate(priv, resp);
+		break;
+	case HostCmd_CMD_802_11_AD_HOC_START:
+	case HostCmd_CMD_802_11_AD_HOC_JOIN:
+		ret = mwifiex_ret_802_11_ad_hoc(priv, resp, wait_queue);
+		break;
+	case HostCmd_CMD_802_11_AD_HOC_STOP:
+		ret = mwifiex_ret_802_11_ad_hoc_stop(priv, resp);
+		break;
+	case HostCmd_CMD_802_11_GET_LOG:
+		ret = mwifiex_ret_get_log(priv, resp, data_buf);
+		break;
+	case HostCmd_CMD_RSSI_INFO:
+		ret = mwifiex_ret_802_11_rssi_info(priv, resp, data_buf);
+		break;
+	case HostCmd_CMD_802_11_SNMP_MIB:
+		ret = mwifiex_ret_802_11_snmp_mib(priv, resp, data_buf);
+		break;
+	case HostCmd_CMD_802_11_TX_RATE_QUERY:
+		ret = mwifiex_ret_802_11_tx_rate_query(priv, resp);
+		break;
+	case HostCmd_CMD_802_11_RF_CHANNEL:
+		ret = mwifiex_ret_802_11_rf_channel(priv, resp, data_buf);
+		break;
+	case HostCmd_CMD_VERSION_EXT:
+		ret = mwifiex_ret_ver_ext(priv, resp, data_buf);
+		break;
+	case HostCmd_CMD_FUNC_INIT:
+	case HostCmd_CMD_FUNC_SHUTDOWN:
+		break;
+	case HostCmd_CMD_802_11_KEY_MATERIAL:
+		ret = mwifiex_ret_802_11_key_material(priv, resp);
+		break;
+	case HostCmd_CMD_802_11D_DOMAIN_INFO:
+		ret = mwifiex_ret_802_11d_domain_info(priv, resp);
+		break;
+	case HostCmd_CMD_11N_ADDBA_REQ:
+		ret = mwifiex_ret_11n_addba_req(priv, resp);
+		break;
+	case HostCmd_CMD_11N_DELBA:
+		ret = mwifiex_ret_11n_delba(priv, resp);
+		break;
+	case HostCmd_CMD_11N_ADDBA_RSP:
+		ret = mwifiex_ret_11n_addba_resp(priv, resp);
+		break;
+	case HostCmd_CMD_RECONFIGURE_TX_BUFF:
+		adapter->tx_buf_size = (u16) le16_to_cpu(resp->params.
+							     tx_buf.buff_size);
+		adapter->tx_buf_size = (adapter->tx_buf_size /
+						MWIFIEX_SDIO_BLOCK_SIZE) *
+						MWIFIEX_SDIO_BLOCK_SIZE;
+		adapter->curr_tx_buf_size = adapter->tx_buf_size;
+		dev_dbg(adapter->dev,
+			"cmd: max_tx_buf_size=%d, tx_buf_size=%d\n",
+		       adapter->max_tx_buf_size, adapter->tx_buf_size);
+
+		if (adapter->if_ops.update_mp_end_port)
+			adapter->if_ops.update_mp_end_port(adapter,
+					le16_to_cpu(resp->
+						params.
+						tx_buf.
+						mp_end_port));
+		break;
+	case HostCmd_CMD_AMSDU_AGGR_CTRL:
+		ret = mwifiex_ret_amsdu_aggr_ctrl(priv, resp, data_buf);
+		break;
+	case HostCmd_CMD_WMM_GET_STATUS:
+		ret = mwifiex_ret_wmm_get_status(priv, resp);
+		break;
+	case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:
+		ret = mwifiex_ret_ibss_coalescing_status(priv, resp);
+		break;
+	case HostCmd_CMD_MAC_REG_ACCESS:
+	case HostCmd_CMD_BBP_REG_ACCESS:
+	case HostCmd_CMD_RF_REG_ACCESS:
+	case HostCmd_CMD_PMIC_REG_ACCESS:
+	case HostCmd_CMD_CAU_REG_ACCESS:
+	case HostCmd_CMD_802_11_EEPROM_ACCESS:
+		ret = mwifiex_ret_reg_access(cmdresp_no, resp, data_buf);
+		break;
+	case HostCmd_CMD_SET_BSS_MODE:
+		break;
+	case HostCmd_CMD_11N_CFG:
+		ret = mwifiex_ret_11n_cfg(priv, resp, data_buf);
+		break;
+	default:
+		dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n",
+		       resp->command);
+		break;
+	}
+
+	return ret;
+}
diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c
new file mode 100644
index 0000000..936d7c1
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/sta_event.c
@@ -0,0 +1,405 @@
+/*
+ * Marvell Wireless LAN device driver: station event handling
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+#include "11n.h"
+
+/*
+ * This function resets the connection state.
+ *
+ * The function is invoked after receiving a disconnect event from firmware,
+ * and performs the following actions -
+ *      - Set media status to disconnected
+ *      - Clean up Tx and Rx packets
+ *      - Resets SNR/NF/RSSI value in driver
+ *      - Resets security configurations in driver
+ *      - Enables auto data rate
+ *      - Saves the previous SSID and BSSID so that they can
+ *        be used for re-association, if required
+ *      - Erases current SSID and BSSID information
+ *      - Sends a disconnect event to upper layers/applications.
+ */
+void
+mwifiex_reset_connect_state(struct mwifiex_private *priv)
+{
+	struct mwifiex_adapter *adapter = priv->adapter;
+
+	if (!priv->media_connected)
+		return;
+
+	dev_dbg(adapter->dev, "info: handles disconnect event\n");
+
+	priv->media_connected = false;
+
+	priv->scan_block = false;
+
+	/* Free Tx and Rx packets, report disconnect to upper layer */
+	mwifiex_clean_txrx(priv);
+
+	/* Reset SNR/NF/RSSI values */
+	priv->data_rssi_last = 0;
+	priv->data_nf_last = 0;
+	priv->data_rssi_avg = 0;
+	priv->data_nf_avg = 0;
+	priv->bcn_rssi_last = 0;
+	priv->bcn_nf_last = 0;
+	priv->bcn_rssi_avg = 0;
+	priv->bcn_nf_avg = 0;
+	priv->rxpd_rate = 0;
+	priv->rxpd_htinfo = 0;
+	priv->sec_info.wpa_enabled = false;
+	priv->sec_info.wpa2_enabled = false;
+	priv->wpa_ie_len = 0;
+
+	priv->sec_info.wapi_enabled = false;
+	priv->wapi_ie_len = 0;
+	priv->sec_info.wapi_key_on = false;
+
+	priv->sec_info.encryption_mode = 0;
+
+	/* Enable auto data rate */
+	priv->is_data_rate_auto = true;
+	priv->data_rate = 0;
+
+	if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
+		priv->adhoc_state = ADHOC_IDLE;
+		priv->adhoc_is_link_sensed = false;
+	}
+
+	/*
+	 * Memorize the previous SSID and BSSID so
+	 * it could be used for re-assoc
+	 */
+
+	dev_dbg(adapter->dev, "info: previous SSID=%s, SSID len=%u\n",
+	       priv->prev_ssid.ssid, priv->prev_ssid.ssid_len);
+
+	dev_dbg(adapter->dev, "info: current SSID=%s, SSID len=%u\n",
+	       priv->curr_bss_params.bss_descriptor.ssid.ssid,
+	       priv->curr_bss_params.bss_descriptor.ssid.ssid_len);
+
+	memcpy(&priv->prev_ssid,
+	       &priv->curr_bss_params.bss_descriptor.ssid,
+	       sizeof(struct mwifiex_802_11_ssid));
+
+	memcpy(priv->prev_bssid,
+	       priv->curr_bss_params.bss_descriptor.mac_address, ETH_ALEN);
+
+	/* Need to erase the current SSID and BSSID info */
+	memset(&priv->curr_bss_params, 0x00, sizeof(priv->curr_bss_params));
+
+	adapter->tx_lock_flag = false;
+	adapter->pps_uapsd_mode = false;
+
+	if (adapter->num_cmd_timeout && adapter->curr_cmd)
+		return;
+	priv->media_connected = false;
+	if (!priv->disconnect) {
+		priv->disconnect = 1;
+		dev_dbg(adapter->dev, "info: successfully disconnected from"
+				" %pM: reason code %d\n", priv->cfg_bssid,
+				WLAN_REASON_DEAUTH_LEAVING);
+		cfg80211_disconnected(priv->netdev,
+				WLAN_REASON_DEAUTH_LEAVING, NULL, 0,
+				GFP_KERNEL);
+		queue_work(priv->workqueue, &priv->cfg_workqueue);
+	}
+	if (!netif_queue_stopped(priv->netdev))
+		netif_stop_queue(priv->netdev);
+	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;
+}
+
+/*
+ * This function handles events generated by firmware.
+ *
+ * This is a generic function and handles all events.
+ *
+ * Event specific routines are called by this function based
+ * upon the generated event cause.
+ *
+ * For the following events, the function just forwards them to upper
+ * layers, optionally recording the change -
+ *      - EVENT_LINK_SENSED
+ *      - EVENT_MIC_ERR_UNICAST
+ *      - EVENT_MIC_ERR_MULTICAST
+ *      - EVENT_PORT_RELEASE
+ *      - EVENT_RSSI_LOW
+ *      - EVENT_SNR_LOW
+ *      - EVENT_MAX_FAIL
+ *      - EVENT_RSSI_HIGH
+ *      - EVENT_SNR_HIGH
+ *      - EVENT_DATA_RSSI_LOW
+ *      - EVENT_DATA_SNR_LOW
+ *      - EVENT_DATA_RSSI_HIGH
+ *      - EVENT_DATA_SNR_HIGH
+ *      - EVENT_LINK_QUALITY
+ *      - EVENT_PRE_BEACON_LOST
+ *      - EVENT_IBSS_COALESCED
+ *      - EVENT_WEP_ICV_ERR
+ *      - EVENT_BW_CHANGE
+ *      - EVENT_HOSTWAKE_STAIE
+  *
+ * For the following events, no action is taken -
+ *      - EVENT_MIB_CHANGED
+ *      - EVENT_INIT_DONE
+ *      - EVENT_DUMMY_HOST_WAKEUP_SIGNAL
+ *
+ * Rest of the supported events requires driver handling -
+ *      - EVENT_DEAUTHENTICATED
+ *      - EVENT_DISASSOCIATED
+ *      - EVENT_LINK_LOST
+ *      - EVENT_PS_SLEEP
+ *      - EVENT_PS_AWAKE
+ *      - EVENT_DEEP_SLEEP_AWAKE
+ *      - EVENT_HS_ACT_REQ
+ *      - EVENT_ADHOC_BCN_LOST
+ *      - EVENT_BG_SCAN_REPORT
+ *      - EVENT_WMM_STATUS_CHANGE
+ *      - EVENT_ADDBA
+ *      - EVENT_DELBA
+ *      - EVENT_BA_STREAM_TIEMOUT
+ *      - EVENT_AMSDU_AGGR_CTRL
+ */
+int mwifiex_process_sta_event(struct mwifiex_private *priv)
+{
+	struct mwifiex_adapter *adapter = priv->adapter;
+	int ret = 0;
+	u32 eventcause = adapter->event_cause;
+
+	switch (eventcause) {
+	case EVENT_DUMMY_HOST_WAKEUP_SIGNAL:
+		dev_err(adapter->dev, "invalid EVENT: DUMMY_HOST_WAKEUP_SIGNAL,"
+				" ignoring it\n");
+		break;
+	case EVENT_LINK_SENSED:
+		dev_dbg(adapter->dev, "event: LINK_SENSED\n");
+		if (!netif_carrier_ok(priv->netdev))
+			netif_carrier_on(priv->netdev);
+		if (netif_queue_stopped(priv->netdev))
+			netif_wake_queue(priv->netdev);
+		break;
+
+	case EVENT_DEAUTHENTICATED:
+		dev_dbg(adapter->dev, "event: Deauthenticated\n");
+		adapter->dbg.num_event_deauth++;
+		if (priv->media_connected)
+			mwifiex_reset_connect_state(priv);
+		break;
+
+	case EVENT_DISASSOCIATED:
+		dev_dbg(adapter->dev, "event: Disassociated\n");
+		adapter->dbg.num_event_disassoc++;
+		if (priv->media_connected)
+			mwifiex_reset_connect_state(priv);
+		break;
+
+	case EVENT_LINK_LOST:
+		dev_dbg(adapter->dev, "event: Link lost\n");
+		adapter->dbg.num_event_link_lost++;
+		if (priv->media_connected)
+			mwifiex_reset_connect_state(priv);
+		break;
+
+	case EVENT_PS_SLEEP:
+		dev_dbg(adapter->dev, "info: EVENT: SLEEP\n");
+
+		adapter->ps_state = PS_STATE_PRE_SLEEP;
+
+		mwifiex_check_ps_cond(adapter);
+		break;
+
+	case EVENT_PS_AWAKE:
+		dev_dbg(adapter->dev, "info: EVENT: AWAKE\n");
+		if (!adapter->pps_uapsd_mode &&
+			priv->media_connected &&
+			adapter->sleep_period.period) {
+				adapter->pps_uapsd_mode = true;
+				dev_dbg(adapter->dev,
+					"event: PPS/UAPSD mode activated\n");
+		}
+		adapter->tx_lock_flag = false;
+		if (adapter->pps_uapsd_mode && adapter->gen_null_pkt) {
+			if (mwifiex_check_last_packet_indication(priv)) {
+				if (!adapter->data_sent) {
+					if (!mwifiex_send_null_packet(priv,
+					MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET
+					|
+					MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET))
+						adapter->ps_state =
+							PS_STATE_SLEEP;
+					return 0;
+				}
+			}
+		}
+		adapter->ps_state = PS_STATE_AWAKE;
+		adapter->pm_wakeup_card_req = false;
+		adapter->pm_wakeup_fw_try = false;
+
+		break;
+
+	case EVENT_DEEP_SLEEP_AWAKE:
+		adapter->if_ops.wakeup_complete(adapter);
+		dev_dbg(adapter->dev, "event: DS_AWAKE\n");
+		if (adapter->is_deep_sleep)
+			adapter->is_deep_sleep = false;
+		break;
+
+	case EVENT_HS_ACT_REQ:
+		dev_dbg(adapter->dev, "event: HS_ACT_REQ\n");
+		ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_HS_CFG_ENH,
+					  0, 0, NULL, NULL);
+		break;
+
+	case EVENT_MIC_ERR_UNICAST:
+		dev_dbg(adapter->dev, "event: UNICAST MIC ERROR\n");
+		break;
+
+	case EVENT_MIC_ERR_MULTICAST:
+		dev_dbg(adapter->dev, "event: MULTICAST MIC ERROR\n");
+		break;
+	case EVENT_MIB_CHANGED:
+	case EVENT_INIT_DONE:
+		break;
+
+	case EVENT_ADHOC_BCN_LOST:
+		dev_dbg(adapter->dev, "event: ADHOC_BCN_LOST\n");
+		priv->adhoc_is_link_sensed = false;
+		mwifiex_clean_txrx(priv);
+		if (!netif_queue_stopped(priv->netdev))
+			netif_stop_queue(priv->netdev);
+		if (netif_carrier_ok(priv->netdev))
+			netif_carrier_off(priv->netdev);
+		break;
+
+	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_prepare_cmd(priv,
+					  HostCmd_CMD_802_11_BG_SCAN_QUERY,
+					  HostCmd_ACT_GEN_GET, 0, NULL, NULL);
+		break;
+
+	case EVENT_PORT_RELEASE:
+		dev_dbg(adapter->dev, "event: PORT RELEASE\n");
+		break;
+
+	case EVENT_WMM_STATUS_CHANGE:
+		dev_dbg(adapter->dev, "event: WMM status changed\n");
+		ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_WMM_GET_STATUS,
+					  0, 0, NULL, NULL);
+		break;
+
+	case EVENT_RSSI_LOW:
+		dev_dbg(adapter->dev, "event: Beacon RSSI_LOW\n");
+		break;
+	case EVENT_SNR_LOW:
+		dev_dbg(adapter->dev, "event: Beacon SNR_LOW\n");
+		break;
+	case EVENT_MAX_FAIL:
+		dev_dbg(adapter->dev, "event: MAX_FAIL\n");
+		break;
+	case EVENT_RSSI_HIGH:
+		dev_dbg(adapter->dev, "event: Beacon RSSI_HIGH\n");
+		break;
+	case EVENT_SNR_HIGH:
+		dev_dbg(adapter->dev, "event: Beacon SNR_HIGH\n");
+		break;
+	case EVENT_DATA_RSSI_LOW:
+		dev_dbg(adapter->dev, "event: Data RSSI_LOW\n");
+		break;
+	case EVENT_DATA_SNR_LOW:
+		dev_dbg(adapter->dev, "event: Data SNR_LOW\n");
+		break;
+	case EVENT_DATA_RSSI_HIGH:
+		dev_dbg(adapter->dev, "event: Data RSSI_HIGH\n");
+		break;
+	case EVENT_DATA_SNR_HIGH:
+		dev_dbg(adapter->dev, "event: Data SNR_HIGH\n");
+		break;
+	case EVENT_LINK_QUALITY:
+		dev_dbg(adapter->dev, "event: Link Quality\n");
+		break;
+	case EVENT_PRE_BEACON_LOST:
+		dev_dbg(adapter->dev, "event: Pre-Beacon Lost\n");
+		break;
+	case EVENT_IBSS_COALESCED:
+		dev_dbg(adapter->dev, "event: IBSS_COALESCED\n");
+		ret = mwifiex_prepare_cmd(priv,
+				HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
+				HostCmd_ACT_GEN_GET, 0, NULL, NULL);
+		break;
+	case EVENT_ADDBA:
+		dev_dbg(adapter->dev, "event: ADDBA Request\n");
+		mwifiex_prepare_cmd(priv, HostCmd_CMD_11N_ADDBA_RSP,
+				    HostCmd_ACT_GEN_SET, 0, NULL,
+				    adapter->event_body);
+		break;
+	case EVENT_DELBA:
+		dev_dbg(adapter->dev, "event: DELBA Request\n");
+		mwifiex_11n_delete_ba_stream(priv, adapter->event_body);
+		break;
+	case EVENT_BA_STREAM_TIEMOUT:
+		dev_dbg(adapter->dev, "event:  BA Stream timeout\n");
+		mwifiex_11n_ba_stream_timeout(priv,
+					      (struct host_cmd_ds_11n_batimeout
+					       *)
+					      adapter->event_body);
+		break;
+	case EVENT_AMSDU_AGGR_CTRL:
+		dev_dbg(adapter->dev, "event:  AMSDU_AGGR_CTRL %d\n",
+		       *(u16 *) adapter->event_body);
+		adapter->tx_buf_size =
+			min(adapter->curr_tx_buf_size,
+			    le16_to_cpu(*(__le16 *) adapter->event_body));
+		dev_dbg(adapter->dev, "event: tx_buf_size %d\n",
+				adapter->tx_buf_size);
+		break;
+
+	case EVENT_WEP_ICV_ERR:
+		dev_dbg(adapter->dev, "event: WEP ICV error\n");
+		break;
+
+	case EVENT_BW_CHANGE:
+		dev_dbg(adapter->dev, "event: BW Change\n");
+		break;
+
+	case EVENT_HOSTWAKE_STAIE:
+		dev_dbg(adapter->dev, "event: HOSTWAKE_STAIE %d\n", eventcause);
+		break;
+	default:
+		dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
+						eventcause);
+		break;
+	}
+
+	return ret;
+}
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
new file mode 100644
index 0000000..b163507
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -0,0 +1,2360 @@
+/*
+ * Marvell Wireless LAN device driver: functions for station ioctl
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+#include "11n.h"
+#include "cfg80211.h"
+
+/*
+ * Copies the multicast address list from device to driver.
+ *
+ * This function does not validate the destination memory for
+ * size, and the calling function must ensure enough memory is
+ * available.
+ */
+static int
+mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist,
+			struct net_device *dev)
+{
+	int i = 0;
+	struct netdev_hw_addr *ha;
+
+	netdev_for_each_mc_addr(ha, dev)
+		memcpy(&mlist->mac_list[i++], ha->addr, ETH_ALEN);
+
+	return i;
+}
+
+/*
+ * Allocate and fills a wait queue with proper parameters.
+ *
+ * This function needs to be called before an IOCTL request can be made.
+ * It can handle the following wait options:
+ *      MWIFIEX_NO_WAIT     - Waiting is disabled
+ *      MWIFIEX_IOCTL_WAIT  - Waiting is done on IOCTL wait queue
+ *      MWIFIEX_CMD_WAIT    - Waiting is done on command wait queue
+ *      MWIFIEX_WSTATS_WAIT - Waiting is done on stats wait queue
+ */
+struct mwifiex_wait_queue *
+mwifiex_alloc_fill_wait_queue(struct mwifiex_private *priv,
+			      u8 wait_option)
+{
+	struct mwifiex_wait_queue *wait = NULL;
+
+	wait = (struct mwifiex_wait_queue *)
+		kzalloc(sizeof(struct mwifiex_wait_queue), GFP_ATOMIC);
+	if (!wait) {
+		dev_err(priv->adapter->dev, "%s: fail to alloc buffer\n",
+						__func__);
+		return wait;
+	}
+
+	wait->bss_index = priv->bss_index;
+
+	switch (wait_option) {
+	case MWIFIEX_NO_WAIT:
+		wait->enabled = 0;
+		break;
+	case MWIFIEX_IOCTL_WAIT:
+		priv->ioctl_wait_q_woken = false;
+		wait->start_time = jiffies;
+		wait->wait = &priv->ioctl_wait_q;
+		wait->condition = &priv->ioctl_wait_q_woken;
+		wait->enabled = 1;
+		break;
+	case MWIFIEX_CMD_WAIT:
+		priv->cmd_wait_q_woken = false;
+		wait->start_time = jiffies;
+		wait->wait = &priv->cmd_wait_q;
+		wait->condition = &priv->cmd_wait_q_woken;
+		wait->enabled = 1;
+		break;
+	case MWIFIEX_WSTATS_WAIT:
+		priv->w_stats_wait_q_woken = false;
+		wait->start_time = jiffies;
+		wait->wait = &priv->w_stats_wait_q;
+		wait->condition = &priv->w_stats_wait_q_woken;
+		wait->enabled = 1;
+		break;
+	}
+
+	return wait;
+}
+
+/*
+ * Wait queue completion handler.
+ *
+ * This function waits on a particular wait queue.
+ * For NO_WAIT option, it returns immediately. It also cancels the
+ * pending IOCTL request after waking up, in case of errors.
+ */
+static void
+mwifiex_wait_ioctl_complete(struct mwifiex_private *priv,
+			    struct mwifiex_wait_queue *wait,
+			    u8 wait_option)
+{
+	bool cancel_flag = false;
+
+	switch (wait_option) {
+	case MWIFIEX_NO_WAIT:
+		break;
+	case MWIFIEX_IOCTL_WAIT:
+		wait_event_interruptible(priv->ioctl_wait_q,
+					 priv->ioctl_wait_q_woken);
+		if (!priv->ioctl_wait_q_woken)
+			cancel_flag = true;
+		break;
+	case MWIFIEX_CMD_WAIT:
+		wait_event_interruptible(priv->cmd_wait_q,
+					 priv->cmd_wait_q_woken);
+		if (!priv->cmd_wait_q_woken)
+			cancel_flag = true;
+		break;
+	case MWIFIEX_WSTATS_WAIT:
+		wait_event_interruptible(priv->w_stats_wait_q,
+					 priv->w_stats_wait_q_woken);
+		if (!priv->w_stats_wait_q_woken)
+			cancel_flag = true;
+		break;
+	}
+	if (cancel_flag) {
+		mwifiex_cancel_pending_ioctl(priv->adapter, wait);
+		dev_dbg(priv->adapter->dev, "cmd: IOCTL cancel: wait=%p, wait_option=%d\n",
+			wait, wait_option);
+	}
+
+	return;
+}
+
+/*
+ * The function waits for the request to complete and issues the
+ * completion handler, if required.
+ */
+int mwifiex_request_ioctl(struct mwifiex_private *priv,
+			  struct mwifiex_wait_queue *wait,
+			  int status, u8 wait_option)
+{
+	switch (status) {
+	case -EINPROGRESS:
+		dev_dbg(priv->adapter->dev, "cmd: IOCTL pending: wait=%p, wait_option=%d\n",
+				wait, wait_option);
+		atomic_inc(&priv->adapter->ioctl_pending);
+		/* Status pending, wake up main process */
+		queue_work(priv->adapter->workqueue, &priv->adapter->main_work);
+
+		/* Wait for completion */
+		if (wait_option) {
+			mwifiex_wait_ioctl_complete(priv, wait, wait_option);
+			status = wait->status;
+		}
+		break;
+	case 0:
+	case -1:
+	case -EBUSY:
+	default:
+		break;
+	}
+	return status;
+}
+EXPORT_SYMBOL_GPL(mwifiex_request_ioctl);
+
+/*
+ * IOCTL request handler to set/get MAC address.
+ *
+ * This function prepares the correct firmware command and
+ * issues it to get the extended version information.
+ */
+static int mwifiex_bss_ioctl_mac_address(struct mwifiex_private *priv,
+					 struct mwifiex_wait_queue *wait,
+					 u8 action, u8 *mac)
+{
+	int ret = 0;
+
+	if ((action == HostCmd_ACT_GEN_GET) && mac) {
+		memcpy(mac, priv->curr_addr, ETH_ALEN);
+		return 0;
+	}
+
+	/* Send request to firmware */
+	ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_MAC_ADDRESS,
+				  action, 0, wait, mac);
+	if (!ret)
+		ret = -EINPROGRESS;
+
+	return ret;
+}
+
+/*
+ * Sends IOCTL request to set MAC address.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ */
+int mwifiex_request_set_mac_address(struct mwifiex_private *priv)
+{
+	struct mwifiex_wait_queue *wait = NULL;
+	int status = 0;
+	u8 wait_option = MWIFIEX_CMD_WAIT;
+
+	/* Allocate wait buffer */
+	wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
+	if (!wait)
+		return -ENOMEM;
+
+	status = mwifiex_bss_ioctl_mac_address(priv, wait, HostCmd_ACT_GEN_SET,
+					       NULL);
+
+	status = mwifiex_request_ioctl(priv, wait, status, wait_option);
+	if (!status)
+		memcpy(priv->netdev->dev_addr, priv->curr_addr, ETH_ALEN);
+	else
+		dev_err(priv->adapter->dev, "set mac address failed: status=%d"
+				" error_code=%#x\n", status, wait->status);
+
+	kfree(wait);
+	return status;
+}
+
+/*
+ * IOCTL request handler to set multicast list.
+ *
+ * This function prepares the correct firmware command and
+ * issues it to set the multicast list.
+ *
+ * This function can be used to enable promiscuous mode, or enable all
+ * multicast packets, or to enable selective multicast.
+ */
+static int
+mwifiex_bss_ioctl_multicast_list(struct mwifiex_private *priv,
+				 struct mwifiex_wait_queue *wait,
+				 u16 action,
+				 struct mwifiex_multicast_list *mcast_list)
+{
+	int ret = 0;
+	u16 old_pkt_filter;
+
+	old_pkt_filter = priv->curr_pkt_filter;
+	if (action == HostCmd_ACT_GEN_GET)
+		return -1;
+
+	if (mcast_list->mode == MWIFIEX_PROMISC_MODE) {
+		dev_dbg(priv->adapter->dev, "info: Enable Promiscuous mode\n");
+		priv->curr_pkt_filter |= HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
+		priv->curr_pkt_filter &=
+			~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
+	} else {
+		/* Multicast */
+		priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
+		if (mcast_list->mode == MWIFIEX_MULTICAST_MODE) {
+			dev_dbg(priv->adapter->dev,
+				"info: Enabling All Multicast!\n");
+			priv->curr_pkt_filter |=
+				HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
+		} else {
+			priv->curr_pkt_filter &=
+				~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
+			if (mcast_list->num_multicast_addr) {
+				dev_dbg(priv->adapter->dev,
+					"info: Set multicast list=%d\n",
+				       mcast_list->num_multicast_addr);
+				/* Set multicast addresses to firmware */
+				if (old_pkt_filter == priv->curr_pkt_filter) {
+					/* Send request to firmware */
+					ret = mwifiex_prepare_cmd(priv,
+						HostCmd_CMD_MAC_MULTICAST_ADR,
+						action, 0, wait, mcast_list);
+					if (!ret)
+						ret = -EINPROGRESS;
+				} else {
+					/* Send request to firmware */
+					ret = mwifiex_prepare_cmd(priv,
+						HostCmd_CMD_MAC_MULTICAST_ADR,
+						action, 0, NULL,
+						mcast_list);
+				}
+			}
+		}
+	}
+	dev_dbg(priv->adapter->dev,
+		"info: old_pkt_filter=%#x, curr_pkt_filter=%#x\n",
+	       old_pkt_filter, priv->curr_pkt_filter);
+	if (old_pkt_filter != priv->curr_pkt_filter) {
+		ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL, action,
+					  0, wait, &priv->curr_pkt_filter);
+		if (!ret)
+			ret = -EINPROGRESS;
+	}
+
+	return ret;
+}
+
+/*
+ * Sends IOCTL request to set multicast list.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ */
+void
+mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
+				   struct net_device *dev)
+{
+	struct mwifiex_wait_queue *wait = NULL;
+	struct mwifiex_multicast_list mcast_list;
+	u8 wait_option = MWIFIEX_NO_WAIT;
+	int status = 0;
+
+	/* Allocate wait buffer */
+	wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
+	if (!wait)
+		return;
+
+	if (dev->flags & IFF_PROMISC) {
+		mcast_list.mode = MWIFIEX_PROMISC_MODE;
+	} else if (dev->flags & IFF_ALLMULTI ||
+		   netdev_mc_count(dev) > MWIFIEX_MAX_MULTICAST_LIST_SIZE) {
+		mcast_list.mode = MWIFIEX_ALL_MULTI_MODE;
+	} else {
+		mcast_list.mode = MWIFIEX_MULTICAST_MODE;
+		if (netdev_mc_count(dev))
+			mcast_list.num_multicast_addr =
+				mwifiex_copy_mcast_addr(&mcast_list, dev);
+	}
+	status = mwifiex_bss_ioctl_multicast_list(priv, wait,
+						  HostCmd_ACT_GEN_SET,
+						  &mcast_list);
+
+	status = mwifiex_request_ioctl(priv, wait, status, wait_option);
+	if (wait && status != -EINPROGRESS)
+		kfree(wait);
+
+	return;
+}
+
+/*
+ * IOCTL request handler to disconnect from a BSS/IBSS.
+ */
+static int mwifiex_bss_ioctl_stop(struct mwifiex_private *priv,
+				  struct mwifiex_wait_queue *wait, u8 *mac)
+{
+	return mwifiex_deauthenticate(priv, wait, mac);
+}
+
+/*
+ * Sends IOCTL request to disconnect from a BSS.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ */
+int mwifiex_disconnect(struct mwifiex_private *priv, u8 wait_option, u8 *mac)
+{
+	struct mwifiex_wait_queue *wait = NULL;
+	int status = 0;
+
+	/* Allocate wait buffer */
+	wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
+	if (!wait)
+		return -ENOMEM;
+
+	status = mwifiex_bss_ioctl_stop(priv, wait, mac);
+
+	status = mwifiex_request_ioctl(priv, wait, status, wait_option);
+
+	kfree(wait);
+	return status;
+}
+EXPORT_SYMBOL_GPL(mwifiex_disconnect);
+
+/*
+ * IOCTL request handler to join a BSS/IBSS.
+ *
+ * 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.
+ */
+static int mwifiex_bss_ioctl_start(struct mwifiex_private *priv,
+				   struct mwifiex_wait_queue *wait,
+				   struct mwifiex_ssid_bssid *ssid_bssid)
+{
+	int ret = 0;
+	struct mwifiex_adapter *adapter = priv->adapter;
+	s32 i = -1;
+
+	priv->scan_block = false;
+	if (!ssid_bssid)
+		return -1;
+
+	if (priv->bss_mode == NL80211_IFTYPE_STATION) {
+		/* Infra mode */
+		ret = mwifiex_deauthenticate(priv, NULL, NULL);
+		if (ret)
+			return ret;
+
+		/* 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;
+
+		dev_dbg(adapter->dev,
+			"info: SSID found in scan list ... associating...\n");
+
+		/* Clear any past association response stored for
+		 * application retrieval */
+		priv->assoc_rsp_size = 0;
+		ret = mwifiex_associate(priv, wait, &adapter->scan_table[i]);
+		if (ret)
+			return ret;
+	} else {
+		/* Adhoc mode */
+		/* If the requested SSID matches current SSID, return */
+		if (ssid_bssid->ssid.ssid_len &&
+		    (!mwifiex_ssid_cmp
+		     (&priv->curr_bss_params.bss_descriptor.ssid,
+		      &ssid_bssid->ssid)))
+			return 0;
+
+		/* Exit Adhoc mode first */
+		dev_dbg(adapter->dev, "info: Sending Adhoc Stop\n");
+		ret = mwifiex_deauthenticate(priv, NULL, NULL);
+		if (ret)
+			return ret;
+
+		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) {
+			dev_dbg(adapter->dev, "info: network found in scan"
+							" list. Joining...\n");
+			ret = mwifiex_adhoc_join(priv, wait,
+						 &adapter->scan_table[i]);
+			if (ret)
+				return ret;
+		} else {	/* i >= 0 */
+			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, wait,
+						  &ssid_bssid->ssid);
+			if (ret)
+				return ret;
+		}
+	}
+
+	if (!ret)
+		ret = -EINPROGRESS;
+
+	return ret;
+}
+
+/*
+ * Sends IOCTL request to connect with a BSS.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ */
+int mwifiex_bss_start(struct mwifiex_private *priv, u8 wait_option,
+		      struct mwifiex_ssid_bssid *ssid_bssid)
+{
+	struct mwifiex_wait_queue *wait = NULL;
+	struct mwifiex_ssid_bssid tmp_ssid_bssid;
+	int status = 0;
+
+	/* Stop the O.S. TX queue if needed */
+	if (!netif_queue_stopped(priv->netdev))
+		netif_stop_queue(priv->netdev);
+
+	/* Allocate wait buffer */
+	wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
+	if (!wait)
+		return -ENOMEM;
+
+	if (ssid_bssid)
+		memcpy(&tmp_ssid_bssid, ssid_bssid,
+		       sizeof(struct mwifiex_ssid_bssid));
+	status = mwifiex_bss_ioctl_start(priv, wait, &tmp_ssid_bssid);
+
+	status = mwifiex_request_ioctl(priv, wait, status, wait_option);
+
+	kfree(wait);
+	return status;
+}
+
+/*
+ * IOCTL request handler to set host sleep configuration.
+ *
+ * This function prepares the correct firmware command and
+ * issues it.
+ */
+static int
+mwifiex_pm_ioctl_hs_cfg(struct mwifiex_private *priv,
+			struct mwifiex_wait_queue *wait,
+			u16 action, struct mwifiex_ds_hs_cfg *hs_cfg)
+{
+	struct mwifiex_adapter *adapter = priv->adapter;
+	int status = 0;
+	u32 prev_cond = 0;
+
+	switch (action) {
+	case HostCmd_ACT_GEN_SET:
+		if (adapter->pps_uapsd_mode) {
+			dev_dbg(adapter->dev, "info: Host Sleep IOCTL"
+				" is blocked in UAPSD/PPS mode\n");
+			status = -1;
+			break;
+		}
+		if (hs_cfg->is_invoke_hostcmd) {
+			if (hs_cfg->conditions == HOST_SLEEP_CFG_CANCEL) {
+				if (!adapter->is_hs_configured)
+					/* Already cancelled */
+					break;
+				/* Save previous condition */
+				prev_cond = le32_to_cpu(adapter->hs_cfg
+							.conditions);
+				adapter->hs_cfg.conditions =
+						cpu_to_le32(hs_cfg->conditions);
+			} else if (hs_cfg->conditions) {
+				adapter->hs_cfg.conditions =
+						cpu_to_le32(hs_cfg->conditions);
+				adapter->hs_cfg.gpio = (u8)hs_cfg->gpio;
+				if (hs_cfg->gap)
+					adapter->hs_cfg.gap = (u8)hs_cfg->gap;
+			} else if (adapter->hs_cfg.conditions ==
+						cpu_to_le32(
+						HOST_SLEEP_CFG_CANCEL)) {
+				/* Return failure if no parameters for HS
+				   enable */
+				status = -1;
+				break;
+			}
+			status = mwifiex_prepare_cmd(priv,
+					HostCmd_CMD_802_11_HS_CFG_ENH,
+					HostCmd_ACT_GEN_SET,
+					0, wait, &adapter->hs_cfg);
+			if (!status)
+				status = -EINPROGRESS;
+			if (hs_cfg->conditions == HOST_SLEEP_CFG_CANCEL)
+				/* Restore previous condition */
+				adapter->hs_cfg.conditions =
+						cpu_to_le32(prev_cond);
+		} else {
+			adapter->hs_cfg.conditions =
+				cpu_to_le32(hs_cfg->conditions);
+			adapter->hs_cfg.gpio = (u8)hs_cfg->gpio;
+			adapter->hs_cfg.gap = (u8)hs_cfg->gap;
+		}
+		break;
+	case HostCmd_ACT_GEN_GET:
+		hs_cfg->conditions = le32_to_cpu(adapter->hs_cfg.conditions);
+		hs_cfg->gpio = adapter->hs_cfg.gpio;
+		hs_cfg->gap = adapter->hs_cfg.gap;
+		break;
+	default:
+		status = -1;
+		break;
+	}
+
+	return status;
+}
+
+/*
+ * Sends IOCTL request to set Host Sleep parameters.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ */
+int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action,
+			      u8 wait_option,
+			      struct mwifiex_ds_hs_cfg *hscfg)
+{
+	int ret = 0;
+	struct mwifiex_wait_queue *wait = NULL;
+
+	if (!hscfg)
+		return -ENOMEM;
+
+	/* Allocate wait buffer */
+	wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
+	if (!wait)
+		return -ENOMEM;
+
+	ret = mwifiex_pm_ioctl_hs_cfg(priv, wait, action, hscfg);
+
+	ret = mwifiex_request_ioctl(priv, wait, ret, wait_option);
+
+	if (wait && (ret != -EINPROGRESS))
+		kfree(wait);
+	return ret;
+}
+
+/*
+ * Sends IOCTL request to cancel the existing Host Sleep configuration.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ */
+int mwifiex_cancel_hs(struct mwifiex_private *priv, u8 wait_option)
+{
+	int ret = 0;
+	struct mwifiex_ds_hs_cfg hscfg;
+
+	/* Cancel Host Sleep */
+	hscfg.conditions = HOST_SLEEP_CFG_CANCEL;
+	hscfg.is_invoke_hostcmd = true;
+	ret = mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET,
+					wait_option, &hscfg);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(mwifiex_cancel_hs);
+
+/*
+ * Sends IOCTL request to cancel the existing Host Sleep configuration.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ */
+int mwifiex_enable_hs(struct mwifiex_adapter *adapter)
+{
+	struct mwifiex_ds_hs_cfg hscfg;
+
+	if (adapter->hs_activated) {
+		dev_dbg(adapter->dev, "cmd: HS Already actived\n");
+		return true;
+	}
+
+	/* Enable Host Sleep */
+	adapter->hs_activate_wait_q_woken = false;
+
+	memset(&hscfg, 0, sizeof(struct mwifiex_hs_config_param));
+	hscfg.is_invoke_hostcmd = true;
+
+	if (mwifiex_set_hs_params(mwifiex_get_priv(adapter,
+						       MWIFIEX_BSS_ROLE_STA),
+				      HostCmd_ACT_GEN_SET,
+				      MWIFIEX_IOCTL_WAIT, &hscfg)) {
+		dev_err(adapter->dev, "IOCTL request HS enable failed\n");
+		return false;
+	}
+
+	wait_event_interruptible(adapter->hs_activate_wait_q,
+			adapter->hs_activate_wait_q_woken);
+
+	return true;
+}
+EXPORT_SYMBOL_GPL(mwifiex_enable_hs);
+
+/*
+ * IOCTL request handler to get signal information.
+ *
+ * This function prepares the correct firmware command and
+ * issues it to get the signal (RSSI) information.
+ *
+ * This only works in the connected mode.
+ */
+static int mwifiex_get_info_signal(struct mwifiex_private *priv,
+				   struct mwifiex_wait_queue *wait,
+				   struct mwifiex_ds_get_signal *signal)
+{
+	int ret = 0;
+
+	if (!wait) {
+		dev_err(priv->adapter->dev, "WAIT information is not present\n");
+		return -1;
+	}
+
+	/* Signal info can be obtained only if connected */
+	if (!priv->media_connected) {
+		dev_dbg(priv->adapter->dev,
+			"info: Can not get signal in disconnected state\n");
+		return -1;
+	}
+
+	/* Send request to firmware */
+	ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_RSSI_INFO,
+				  HostCmd_ACT_GEN_GET, 0, wait, signal);
+
+	if (!ret)
+		ret = -EINPROGRESS;
+
+	return ret;
+}
+
+/*
+ * IOCTL request handler to get statistics.
+ *
+ * This function prepares the correct firmware command and
+ * issues it to get the statistics (RSSI) information.
+ */
+static int mwifiex_get_info_stats(struct mwifiex_private *priv,
+			   struct mwifiex_wait_queue *wait,
+			   struct mwifiex_ds_get_stats *log)
+{
+	int ret = 0;
+
+	if (!wait) {
+		dev_err(priv->adapter->dev, "MWIFIEX IOCTL information is not present\n");
+		return -1;
+	}
+
+	/* Send request to firmware */
+	ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_GET_LOG,
+				  HostCmd_ACT_GEN_GET, 0, wait, log);
+
+	if (!ret)
+		ret = -EINPROGRESS;
+
+	return ret;
+}
+
+/*
+ * IOCTL request handler to get BSS information.
+ *
+ * This function collates the information from different driver structures
+ * to send to the user.
+ */
+int mwifiex_get_bss_info(struct mwifiex_private *priv,
+			 struct mwifiex_bss_info *info)
+{
+	struct mwifiex_adapter *adapter = priv->adapter;
+	struct mwifiex_bssdescriptor *bss_desc;
+	s32 tbl_idx = 0;
+
+	if (!info)
+		return -1;
+
+	/* Get current BSS info */
+	bss_desc = &priv->curr_bss_params.bss_descriptor;
+
+	/* BSS mode */
+	info->bss_mode = priv->bss_mode;
+
+	/* SSID */
+	memcpy(&info->ssid, &bss_desc->ssid,
+	       sizeof(struct mwifiex_802_11_ssid));
+
+	/* BSSID */
+	memcpy(&info->bssid, &bss_desc->mac_address, ETH_ALEN);
+
+	/* Channel */
+	info->bss_chan = bss_desc->channel;
+
+	/* Region code */
+	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;
+	}
+
+	/* Connection status */
+	info->media_connected = priv->media_connected;
+
+	/* Tx power information */
+	info->max_power_level = priv->max_tx_power_level;
+	info->min_power_level = priv->min_tx_power_level;
+
+	/* AdHoc state */
+	info->adhoc_state = priv->adhoc_state;
+
+	/* Last beacon NF */
+	info->bcn_nf_last = priv->bcn_nf_last;
+
+	/* wep status */
+	if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED)
+		info->wep_status = true;
+	else
+		info->wep_status = false;
+
+	info->is_hs_configured = adapter->is_hs_configured;
+	info->is_deep_sleep = adapter->is_deep_sleep;
+
+	return 0;
+}
+
+/*
+ * IOCTL request handler to get extended version information.
+ *
+ * This function prepares the correct firmware command and
+ * issues it to get the extended version information.
+ */
+static int mwifiex_get_info_ver_ext(struct mwifiex_private *priv,
+				    struct mwifiex_wait_queue *wait,
+				    struct mwifiex_ver_ext *ver_ext)
+{
+	int ret = 0;
+
+	/* Send request to firmware */
+	ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_VERSION_EXT,
+				  HostCmd_ACT_GEN_GET, 0, wait, ver_ext);
+	if (!ret)
+		ret = -EINPROGRESS;
+
+	return ret;
+}
+
+/*
+ * IOCTL request handler to set/get SNMP MIB parameters.
+ *
+ * This function prepares the correct firmware command and
+ * issues it.
+ *
+ * Currently the following parameters are supported -
+ *      Set/get RTS Threshold
+ *      Set/get fragmentation threshold
+ *      Set/get retry count
+ */
+int mwifiex_snmp_mib_ioctl(struct mwifiex_private *priv,
+			   struct mwifiex_wait_queue *wait,
+			   u32 cmd_oid, u16 action, u32 *value)
+{
+	int ret = 0;
+
+	if (!value)
+		return -1;
+
+	/* Send request to firmware */
+	ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
+				  action, cmd_oid, wait, value);
+
+	if (!ret)
+		ret = -EINPROGRESS;
+
+	return ret;
+}
+
+/*
+ * IOCTL request handler to set/get band configurations.
+ *
+ * For SET operation, it performs extra checks to make sure the Ad-Hoc
+ * band and channel are compatible. Otherwise it returns an error.
+ *
+ * For GET operation, this function retrieves the following information -
+ *      - Infra bands
+ *      - Ad-hoc band
+ *      - Ad-hoc channel
+ *      - Secondary channel offset
+ */
+int mwifiex_radio_ioctl_band_cfg(struct mwifiex_private *priv,
+				 u16 action,
+				 struct mwifiex_ds_band_cfg *radio_cfg)
+{
+	struct mwifiex_adapter *adapter = priv->adapter;
+	u8 infra_band = 0;
+	u8 adhoc_band = 0;
+	u32 adhoc_channel = 0;
+
+	if (action == HostCmd_ACT_GEN_GET) {
+		/* Infra Bands */
+		radio_cfg->config_bands = adapter->config_bands;
+		/* Adhoc Band */
+		radio_cfg->adhoc_start_band = adapter->adhoc_start_band;
+		/* Adhoc channel */
+		radio_cfg->adhoc_channel = priv->adhoc_channel;
+		/* Secondary channel offset */
+		radio_cfg->sec_chan_offset = adapter->chan_offset;
+		return 0;
+	}
+
+	/* For action = SET */
+	infra_band = (u8) radio_cfg->config_bands;
+	adhoc_band = (u8) radio_cfg->adhoc_start_band;
+	adhoc_channel = radio_cfg->adhoc_channel;
+
+	/* SET Infra band */
+	if ((infra_band | adapter->fw_bands) & ~adapter->fw_bands)
+		return -1;
+
+	adapter->config_bands = infra_band;
+
+	/* SET Ad-hoc Band */
+	if ((adhoc_band | adapter->fw_bands) & ~adapter->fw_bands)
+		return -1;
+
+	if (adhoc_band)
+		adapter->adhoc_start_band = adhoc_band;
+	adapter->chan_offset = (u8) radio_cfg->sec_chan_offset;
+	/*
+	 * If no adhoc_channel is supplied verify if the existing adhoc
+	 * channel compiles with new adhoc_band
+	 */
+	if (!adhoc_channel) {
+		if (!mwifiex_get_cfp_by_band_and_channel_from_cfg80211
+		     (priv, adapter->adhoc_start_band,
+		     priv->adhoc_channel)) {
+			/* Pass back the default channel */
+			radio_cfg->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
+			if ((adapter->adhoc_start_band & BAND_A)
+			    || (adapter->adhoc_start_band & BAND_AN))
+				radio_cfg->adhoc_channel =
+					DEFAULT_AD_HOC_CHANNEL_A;
+		}
+	} else {	/* Retrurn error if adhoc_band and
+			   adhoc_channel combination is invalid */
+		if (!mwifiex_get_cfp_by_band_and_channel_from_cfg80211
+		    (priv, adapter->adhoc_start_band, (u16) adhoc_channel))
+			return -1;
+		priv->adhoc_channel = (u8) adhoc_channel;
+	}
+	if ((adhoc_band & BAND_GN) || (adhoc_band & BAND_AN))
+		adapter->adhoc_11n_enabled = true;
+	else
+		adapter->adhoc_11n_enabled = false;
+
+	return 0;
+}
+
+/*
+ * IOCTL request handler to set/get active channel.
+ *
+ * This function performs validity checking on channel/frequency
+ * compatibility and returns failure if not valid.
+ */
+int mwifiex_bss_ioctl_channel(struct mwifiex_private *priv, u16 action,
+			      struct mwifiex_chan_freq_power *chan)
+{
+	struct mwifiex_adapter *adapter = priv->adapter;
+	struct mwifiex_chan_freq_power *cfp = NULL;
+
+	if (!chan)
+		return -1;
+
+	if (action == HostCmd_ACT_GEN_GET) {
+		cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv,
+				priv->curr_bss_params.band,
+				(u16) priv->curr_bss_params.bss_descriptor.
+					channel);
+		chan->channel = cfp->channel;
+		chan->freq = cfp->freq;
+
+		return 0;
+	}
+	if (!chan->channel && !chan->freq)
+		return -1;
+	if (adapter->adhoc_start_band & BAND_AN)
+		adapter->adhoc_start_band = BAND_G | BAND_B | BAND_GN;
+	else if (adapter->adhoc_start_band & BAND_A)
+		adapter->adhoc_start_band = BAND_G | BAND_B;
+	if (chan->channel) {
+		if (chan->channel <= MAX_CHANNEL_BAND_BG)
+			cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211
+					(priv, 0, (u16) chan->channel);
+		if (!cfp) {
+			cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211
+					(priv, BAND_A, (u16) chan->channel);
+			if (cfp) {
+				if (adapter->adhoc_11n_enabled)
+					adapter->adhoc_start_band = BAND_A
+						| BAND_AN;
+				else
+					adapter->adhoc_start_band = BAND_A;
+			}
+		}
+	} else {
+		if (chan->freq <= MAX_FREQUENCY_BAND_BG)
+			cfp = mwifiex_get_cfp_by_band_and_freq_from_cfg80211(
+							priv, 0, chan->freq);
+		if (!cfp) {
+			cfp = mwifiex_get_cfp_by_band_and_freq_from_cfg80211
+						  (priv, BAND_A, chan->freq);
+			if (cfp) {
+				if (adapter->adhoc_11n_enabled)
+					adapter->adhoc_start_band = BAND_A
+						| BAND_AN;
+				else
+					adapter->adhoc_start_band = BAND_A;
+			}
+		}
+	}
+	if (!cfp || !cfp->channel) {
+		dev_err(adapter->dev, "invalid channel/freq\n");
+		return -1;
+	}
+	priv->adhoc_channel = (u8) cfp->channel;
+	chan->channel = cfp->channel;
+	chan->freq = cfp->freq;
+
+	return 0;
+}
+
+/*
+ * IOCTL request handler to set/get Ad-Hoc channel.
+ *
+ * This function prepares the correct firmware command and
+ * issues it to set or get the ad-hoc channel.
+ */
+static int mwifiex_bss_ioctl_ibss_channel(struct mwifiex_private *priv,
+					  struct mwifiex_wait_queue *wait,
+					  u16 action, u16 *channel)
+{
+	int ret = 0;
+
+	if (action == HostCmd_ACT_GEN_GET) {
+		if (!priv->media_connected) {
+			*channel = priv->adhoc_channel;
+			return ret;
+		}
+	} else {
+		priv->adhoc_channel = (u8) *channel;
+	}
+
+	/* Send request to firmware */
+	ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_RF_CHANNEL,
+				  action, 0, wait, channel);
+	if (!ret)
+		ret = -EINPROGRESS;
+
+	return ret;
+}
+
+/*
+ * 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_wait_queue *wait,
+			       struct mwifiex_ssid_bssid *ssid_bssid)
+{
+	struct mwifiex_adapter *adapter = priv->adapter;
+	int ret = 0;
+	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 {
+		ret = mwifiex_find_best_network(priv, ssid_bssid);
+	}
+
+	return ret;
+}
+
+/*
+ * IOCTL request handler to change Ad-Hoc channel.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ *
+ * The function follows the following steps to perform the change -
+ *      - Get current IBSS information
+ *      - Get current channel
+ *      - If no change is required, return
+ *      - If not connected, change channel and return
+ *      - If connected,
+ *          - Disconnect
+ *          - Change channel
+ *          - Perform specific SSID scan with same SSID
+ *          - Start/Join the IBSS
+ */
+int
+mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel)
+{
+	int ret = 0;
+	int status = 0;
+	struct mwifiex_bss_info bss_info;
+	struct mwifiex_wait_queue *wait = NULL;
+	u8 wait_option = MWIFIEX_IOCTL_WAIT;
+	struct mwifiex_ssid_bssid ssid_bssid;
+	u16 curr_chan = 0;
+
+	memset(&bss_info, 0, sizeof(bss_info));
+
+	/* Get BSS information */
+	if (mwifiex_get_bss_info(priv, &bss_info))
+		return -1;
+
+	/* Allocate wait buffer */
+	wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
+	if (!wait)
+		return -ENOMEM;
+
+	/* Get current channel */
+	status = mwifiex_bss_ioctl_ibss_channel(priv, wait, HostCmd_ACT_GEN_GET,
+						&curr_chan);
+
+	if (mwifiex_request_ioctl(priv, wait, status, wait_option)) {
+		ret = -1;
+		goto done;
+	}
+	if (curr_chan == channel) {
+		ret = 0;
+		goto done;
+	}
+	dev_dbg(priv->adapter->dev, "cmd: updating channel from %d to %d\n",
+			curr_chan, channel);
+
+	if (!bss_info.media_connected) {
+		ret = 0;
+		goto done;
+	}
+
+	/* Do disonnect */
+	memset(&ssid_bssid, 0, ETH_ALEN);
+	status = mwifiex_bss_ioctl_stop(priv, wait, ssid_bssid.bssid);
+
+	if (mwifiex_request_ioctl(priv, wait, status, wait_option)) {
+		ret = -1;
+		goto done;
+	}
+
+	status = mwifiex_bss_ioctl_ibss_channel(priv, wait, HostCmd_ACT_GEN_SET,
+						(u16 *) &channel);
+
+	if (mwifiex_request_ioctl(priv, wait, status, wait_option)) {
+		ret = -1;
+		goto done;
+	}
+
+	/* Do specific SSID scanning */
+	if (mwifiex_request_scan(priv, wait_option, &bss_info.ssid)) {
+		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));
+
+	status = mwifiex_bss_ioctl_start(priv, wait, &ssid_bssid);
+
+	if (mwifiex_request_ioctl(priv, wait, status, wait_option))
+		ret = -1;
+
+done:
+	kfree(wait);
+	return ret;
+}
+
+/*
+ * IOCTL request handler to get rate.
+ *
+ * This function prepares the correct firmware command and
+ * issues it to get the current rate if it is connected,
+ * otherwise, the function returns the lowest supported rate
+ * for the band.
+ */
+static int mwifiex_rate_ioctl_get_rate_value(struct mwifiex_private *priv,
+					     struct mwifiex_wait_queue *wait,
+					     struct mwifiex_rate_cfg *rate_cfg)
+{
+	struct mwifiex_adapter *adapter = priv->adapter;
+	int ret = 0;
+
+	rate_cfg->is_rate_auto = priv->is_data_rate_auto;
+	if (!priv->media_connected) {
+		switch (adapter->config_bands) {
+		case BAND_B:
+			/* Return the lowest supported rate for B band */
+			rate_cfg->rate = supported_rates_b[0] & 0x7f;
+			break;
+		case BAND_G:
+		case BAND_G | BAND_GN:
+			/* Return the lowest supported rate for G band */
+			rate_cfg->rate = supported_rates_g[0] & 0x7f;
+			break;
+		case BAND_B | BAND_G:
+		case BAND_A | BAND_B | BAND_G:
+		case BAND_A | BAND_B:
+		case BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN:
+		case BAND_B | BAND_G | BAND_GN:
+			/* Return the lowest supported rate for BG band */
+			rate_cfg->rate = supported_rates_bg[0] & 0x7f;
+			break;
+		case BAND_A:
+		case BAND_A | BAND_G:
+		case BAND_A | BAND_G | BAND_AN | BAND_GN:
+		case BAND_A | BAND_AN:
+			/* Return the lowest supported rate for A band */
+			rate_cfg->rate = supported_rates_a[0] & 0x7f;
+			break;
+		case BAND_GN:
+			/* Return the lowest supported rate for N band */
+			rate_cfg->rate = supported_rates_n[0] & 0x7f;
+			break;
+		default:
+			dev_warn(adapter->dev, "invalid band %#x\n",
+			       adapter->config_bands);
+			break;
+		}
+	} else {
+		/* Send request to firmware */
+		ret = mwifiex_prepare_cmd(priv,
+					  HostCmd_CMD_802_11_TX_RATE_QUERY,
+					  HostCmd_ACT_GEN_GET, 0, wait, NULL);
+		if (!ret)
+			ret = -EINPROGRESS;
+	}
+
+	return ret;
+}
+
+/*
+ * IOCTL request handler to set rate.
+ *
+ * This function prepares the correct firmware command and
+ * issues it to set the current rate.
+ *
+ * The function also performs validation checking on the supplied value.
+ */
+static int mwifiex_rate_ioctl_set_rate_value(struct mwifiex_private *priv,
+					     struct mwifiex_wait_queue *wait,
+					     struct mwifiex_rate_cfg *rate_cfg)
+{
+	u8 rates[MWIFIEX_SUPPORTED_RATES];
+	u8 *rate = NULL;
+	int rate_index = 0;
+	u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
+	u32 i = 0;
+	int ret = 0;
+	struct mwifiex_adapter *adapter = priv->adapter;
+
+	if (rate_cfg->is_rate_auto) {
+		memset(bitmap_rates, 0, sizeof(bitmap_rates));
+		/* Support all HR/DSSS rates */
+		bitmap_rates[0] = 0x000F;
+		/* Support all OFDM rates */
+		bitmap_rates[1] = 0x00FF;
+		/* Support all HT-MCSs rate */
+		for (i = 0; i < ARRAY_SIZE(priv->bitmap_rates) - 3; i++)
+			bitmap_rates[i + 2] = 0xFFFF;
+		bitmap_rates[9] = 0x3FFF;
+	} else {
+		memset(rates, 0, sizeof(rates));
+		mwifiex_get_active_data_rates(priv, rates);
+		rate = rates;
+		for (i = 0; (rate[i] && i < MWIFIEX_SUPPORTED_RATES); i++) {
+			dev_dbg(adapter->dev, "info: rate=%#x wanted=%#x\n",
+				rate[i], rate_cfg->rate);
+			if ((rate[i] & 0x7f) == (rate_cfg->rate & 0x7f))
+				break;
+		}
+		if (!rate[i] || (i == MWIFIEX_SUPPORTED_RATES)) {
+			dev_err(adapter->dev, "fixed data rate %#x is out "
+			       "of range\n", rate_cfg->rate);
+			return -1;
+		}
+		memset(bitmap_rates, 0, sizeof(bitmap_rates));
+
+		rate_index =
+			mwifiex_data_rate_to_index(adapter, rate_cfg->rate);
+
+		/* Only allow b/g rates to be set */
+		if (rate_index >= MWIFIEX_RATE_INDEX_HRDSSS0 &&
+		    rate_index <= MWIFIEX_RATE_INDEX_HRDSSS3) {
+			bitmap_rates[0] = 1 << rate_index;
+		} else {
+			rate_index -= 1; /* There is a 0x00 in the table */
+			if (rate_index >= MWIFIEX_RATE_INDEX_OFDM0 &&
+			    rate_index <= MWIFIEX_RATE_INDEX_OFDM7)
+				bitmap_rates[1] = 1 << (rate_index -
+						   MWIFIEX_RATE_INDEX_OFDM0);
+		}
+	}
+
+	/* Send request to firmware */
+	ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_TX_RATE_CFG,
+				  HostCmd_ACT_GEN_SET, 0, wait, bitmap_rates);
+	if (!ret)
+		ret = -EINPROGRESS;
+
+	return ret;
+}
+
+/*
+ * IOCTL request handler to set/get rate.
+ *
+ * This function can be used to set/get either the rate value or the
+ * rate index.
+ */
+static int mwifiex_rate_ioctl_cfg(struct mwifiex_private *priv,
+				  struct mwifiex_wait_queue *wait,
+				  struct mwifiex_rate_cfg *rate_cfg)
+{
+	int status = 0;
+
+	if (!rate_cfg)
+		return -1;
+
+	if (rate_cfg->action == HostCmd_ACT_GEN_GET)
+		status = mwifiex_rate_ioctl_get_rate_value(
+				priv, wait, rate_cfg);
+	else
+		status = mwifiex_rate_ioctl_set_rate_value(
+				priv, wait, rate_cfg);
+
+	return status;
+}
+
+/*
+ * Sends IOCTL request to get the data rate.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ */
+int mwifiex_drv_get_data_rate(struct mwifiex_private *priv,
+			      struct mwifiex_rate_cfg *rate)
+{
+	int ret = 0;
+	struct mwifiex_wait_queue *wait = NULL;
+	u8 wait_option = MWIFIEX_IOCTL_WAIT;
+
+	/* Allocate wait buffer */
+	wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
+	if (!wait)
+		return -ENOMEM;
+
+	memset(rate, 0, sizeof(struct mwifiex_rate_cfg));
+	rate->action = HostCmd_ACT_GEN_GET;
+	ret = mwifiex_rate_ioctl_cfg(priv, wait, rate);
+
+	ret = mwifiex_request_ioctl(priv, wait, ret, wait_option);
+	if (!ret) {
+		if (rate && rate->is_rate_auto)
+			rate->rate = mwifiex_index_to_data_rate(priv->adapter,
+					priv->tx_rate, priv->tx_htinfo);
+		else if (rate)
+			rate->rate = priv->data_rate;
+	} else {
+		ret = -1;
+	}
+
+	kfree(wait);
+	return ret;
+}
+
+/*
+ * IOCTL request handler to set tx power configuration.
+ *
+ * This function prepares the correct firmware command and
+ * issues it.
+ *
+ * For non-auto power mode, all the following power groups are set -
+ *      - Modulation class HR/DSSS
+ *      - Modulation class OFDM
+ *      - Modulation class HTBW20
+ *      - Modulation class HTBW40
+ */
+static int mwifiex_power_ioctl_set_power(struct mwifiex_private *priv,
+					 struct mwifiex_wait_queue *wait,
+					 struct mwifiex_power_cfg *power_cfg)
+{
+	int ret = 0;
+	struct host_cmd_ds_txpwr_cfg *txp_cfg = NULL;
+	struct mwifiex_types_power_group *pg_tlv = NULL;
+	struct mwifiex_power_group *pg = NULL;
+	u8 *buf = NULL;
+	u16 dbm = 0;
+
+	if (!power_cfg->is_power_auto) {
+		dbm = (u16) power_cfg->power_level;
+		if ((dbm < priv->min_tx_power_level) ||
+		    (dbm > priv->max_tx_power_level)) {
+			dev_err(priv->adapter->dev, "txpower value %d dBm"
+					" is out of range (%d dBm-%d dBm)\n",
+					dbm, priv->min_tx_power_level,
+					priv->max_tx_power_level);
+			return -1;
+		}
+	}
+	buf = kzalloc(MWIFIEX_SIZE_OF_CMD_BUFFER, GFP_KERNEL);
+	if (!buf) {
+		dev_err(priv->adapter->dev, "%s: failed to alloc cmd buffer\n",
+				__func__);
+		return -1;
+	}
+
+	txp_cfg = (struct host_cmd_ds_txpwr_cfg *) buf;
+	txp_cfg->action = cpu_to_le16(HostCmd_ACT_GEN_SET);
+	if (!power_cfg->is_power_auto) {
+		txp_cfg->mode = cpu_to_le32(1);
+		pg_tlv = (struct mwifiex_types_power_group *) (buf +
+				sizeof(struct host_cmd_ds_txpwr_cfg));
+		pg_tlv->type = TLV_TYPE_POWER_GROUP;
+		pg_tlv->length = 4 * sizeof(struct mwifiex_power_group);
+		pg = (struct mwifiex_power_group *) (buf +
+				sizeof(struct host_cmd_ds_txpwr_cfg) +
+				sizeof(struct mwifiex_types_power_group));
+		/* Power group for modulation class HR/DSSS */
+		pg->first_rate_code = 0x00;
+		pg->last_rate_code = 0x03;
+		pg->modulation_class = MOD_CLASS_HR_DSSS;
+		pg->power_step = 0;
+		pg->power_min = (s8) dbm;
+		pg->power_max = (s8) dbm;
+		pg++;
+		/* Power group for modulation class OFDM */
+		pg->first_rate_code = 0x00;
+		pg->last_rate_code = 0x07;
+		pg->modulation_class = MOD_CLASS_OFDM;
+		pg->power_step = 0;
+		pg->power_min = (s8) dbm;
+		pg->power_max = (s8) dbm;
+		pg++;
+		/* Power group for modulation class HTBW20 */
+		pg->first_rate_code = 0x00;
+		pg->last_rate_code = 0x20;
+		pg->modulation_class = MOD_CLASS_HT;
+		pg->power_step = 0;
+		pg->power_min = (s8) dbm;
+		pg->power_max = (s8) dbm;
+		pg->ht_bandwidth = HT_BW_20;
+		pg++;
+		/* Power group for modulation class HTBW40 */
+		pg->first_rate_code = 0x00;
+		pg->last_rate_code = 0x20;
+		pg->modulation_class = MOD_CLASS_HT;
+		pg->power_step = 0;
+		pg->power_min = (s8) dbm;
+		pg->power_max = (s8) dbm;
+		pg->ht_bandwidth = HT_BW_40;
+	}
+	/* Send request to firmware */
+	ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_TXPWR_CFG,
+				  HostCmd_ACT_GEN_SET, 0, wait, buf);
+	if (!ret)
+		ret = -EINPROGRESS;
+	kfree(buf);
+
+	return ret;
+}
+
+/*
+ * IOCTL request handler to get power save mode.
+ *
+ * This function prepares the correct firmware command and
+ * issues it.
+ */
+static int mwifiex_pm_ioctl_ps_mode(struct mwifiex_private *priv,
+				    struct mwifiex_wait_queue *wait,
+				    u32 *ps_mode, u16 action)
+{
+	int ret = 0;
+	struct mwifiex_adapter *adapter = priv->adapter;
+	u16 sub_cmd;
+
+	if (action == HostCmd_ACT_GEN_SET) {
+		if (*ps_mode)
+			adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP;
+		else
+			adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM;
+		sub_cmd = (*ps_mode) ? EN_AUTO_PS : DIS_AUTO_PS;
+		ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
+					  sub_cmd, BITMAP_STA_PS, wait, NULL);
+		if ((!ret) && (sub_cmd == DIS_AUTO_PS))
+			ret = mwifiex_prepare_cmd(priv,
+					HostCmd_CMD_802_11_PS_MODE_ENH, GET_PS,
+					0, NULL, NULL);
+	} else {
+		ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
+					  GET_PS, 0, wait, NULL);
+	}
+
+	if (!ret)
+		ret = -EINPROGRESS;
+
+	return ret;
+}
+
+/*
+ * IOCTL request handler to set/reset WPA IE.
+ *
+ * The supplied WPA IE is treated as a opaque buffer. Only the first field
+ * is checked to determine WPA version. If buffer length is zero, the existing
+ * WPA IE is reset.
+ */
+static int mwifiex_set_wpa_ie_helper(struct mwifiex_private *priv,
+				     u8 *ie_data_ptr, u16 ie_len)
+{
+	if (ie_len) {
+		if (ie_len > sizeof(priv->wpa_ie)) {
+			dev_err(priv->adapter->dev,
+				"failed to copy WPA IE, too big\n");
+			return -1;
+		}
+		memcpy(priv->wpa_ie, ie_data_ptr, ie_len);
+		priv->wpa_ie_len = (u8) ie_len;
+		dev_dbg(priv->adapter->dev, "cmd: Set Wpa_ie_len=%d IE=%#x\n",
+				priv->wpa_ie_len, priv->wpa_ie[0]);
+
+		if (priv->wpa_ie[0] == WLAN_EID_WPA) {
+			priv->sec_info.wpa_enabled = true;
+		} else if (priv->wpa_ie[0] == WLAN_EID_RSN) {
+			priv->sec_info.wpa2_enabled = true;
+		} else {
+			priv->sec_info.wpa_enabled = false;
+			priv->sec_info.wpa2_enabled = false;
+		}
+	} else {
+		memset(priv->wpa_ie, 0, sizeof(priv->wpa_ie));
+		priv->wpa_ie_len = 0;
+		dev_dbg(priv->adapter->dev, "info: reset wpa_ie_len=%d IE=%#x\n",
+			priv->wpa_ie_len, priv->wpa_ie[0]);
+		priv->sec_info.wpa_enabled = false;
+		priv->sec_info.wpa2_enabled = false;
+	}
+
+	return 0;
+}
+
+/*
+ * IOCTL request handler to set/reset WAPI IE.
+ *
+ * The supplied WAPI IE is treated as a opaque buffer. Only the first field
+ * is checked to internally enable WAPI. If buffer length is zero, the existing
+ * WAPI IE is reset.
+ */
+static int mwifiex_set_wapi_ie(struct mwifiex_private *priv,
+			       u8 *ie_data_ptr, u16 ie_len)
+{
+	if (ie_len) {
+		if (ie_len > sizeof(priv->wapi_ie)) {
+			dev_dbg(priv->adapter->dev,
+				"info: failed to copy WAPI IE, too big\n");
+			return -1;
+		}
+		memcpy(priv->wapi_ie, ie_data_ptr, ie_len);
+		priv->wapi_ie_len = ie_len;
+		dev_dbg(priv->adapter->dev, "cmd: Set wapi_ie_len=%d IE=%#x\n",
+				priv->wapi_ie_len, priv->wapi_ie[0]);
+
+		if (priv->wapi_ie[0] == WLAN_EID_BSS_AC_ACCESS_DELAY)
+			priv->sec_info.wapi_enabled = true;
+	} else {
+		memset(priv->wapi_ie, 0, sizeof(priv->wapi_ie));
+		priv->wapi_ie_len = ie_len;
+		dev_dbg(priv->adapter->dev,
+			"info: Reset wapi_ie_len=%d IE=%#x\n",
+		       priv->wapi_ie_len, priv->wapi_ie[0]);
+		priv->sec_info.wapi_enabled = false;
+	}
+	return 0;
+}
+
+/*
+ * IOCTL request handler to set WAPI key.
+ *
+ * This function prepares the correct firmware command and
+ * issues it.
+ */
+static int mwifiex_sec_ioctl_set_wapi_key(struct mwifiex_adapter *adapter,
+			       struct mwifiex_wait_queue *wait,
+			       struct mwifiex_ds_encrypt_key *encrypt_key)
+{
+	int ret = 0;
+	struct mwifiex_private *priv = adapter->priv[wait->bss_index];
+
+	ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
+				  HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED,
+				  wait, encrypt_key);
+	if (!ret)
+		ret = -EINPROGRESS;
+
+	return ret;
+}
+
+/*
+ * IOCTL request handler to set WEP network key.
+ *
+ * This function prepares the correct firmware command and
+ * issues it, after validation checks.
+ */
+static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_adapter *adapter,
+			      struct mwifiex_wait_queue *wait,
+			      struct mwifiex_ds_encrypt_key *encrypt_key)
+{
+	int ret = 0;
+	struct mwifiex_private *priv = adapter->priv[wait->bss_index];
+	struct mwifiex_wep_key *wep_key = NULL;
+	int index;
+
+	if (priv->wep_key_curr_index >= NUM_WEP_KEYS)
+		priv->wep_key_curr_index = 0;
+	wep_key = &priv->wep_key[priv->wep_key_curr_index];
+	index = encrypt_key->key_index;
+	if (encrypt_key->key_disable) {
+		priv->sec_info.wep_status = MWIFIEX_802_11_WEP_DISABLED;
+	} else if (!encrypt_key->key_len) {
+		/* Copy the required key as the current key */
+		wep_key = &priv->wep_key[index];
+		if (!wep_key->key_length) {
+			dev_err(adapter->dev,
+				"key not set, so cannot enable it\n");
+			return -1;
+		}
+		priv->wep_key_curr_index = (u16) index;
+		priv->sec_info.wep_status = MWIFIEX_802_11_WEP_ENABLED;
+	} else {
+		wep_key = &priv->wep_key[index];
+		/* Cleanup */
+		memset(wep_key, 0, sizeof(struct mwifiex_wep_key));
+		/* Copy the key in the driver */
+		memcpy(wep_key->key_material,
+		       encrypt_key->key_material,
+		       encrypt_key->key_len);
+		wep_key->key_index = index;
+		wep_key->key_length = encrypt_key->key_len;
+		priv->sec_info.wep_status = MWIFIEX_802_11_WEP_ENABLED;
+	}
+	if (wep_key->key_length) {
+		/* Send request to firmware */
+		ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
+					  HostCmd_ACT_GEN_SET, 0, NULL, NULL);
+		if (ret)
+			return ret;
+	}
+	if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED)
+		priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE;
+	else
+		priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE;
+
+	/* Send request to firmware */
+	ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL,
+				  HostCmd_ACT_GEN_SET, 0, wait,
+				  &priv->curr_pkt_filter);
+	if (!ret)
+		ret = -EINPROGRESS;
+
+	return ret;
+}
+
+/*
+ * IOCTL request handler to set WPA key.
+ *
+ * This function prepares the correct firmware command and
+ * issues it, after validation checks.
+ *
+ * Current driver only supports key length of up to 32 bytes.
+ *
+ * This function can also be used to disable a currently set key.
+ */
+static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_adapter *adapter,
+			      struct mwifiex_wait_queue *wait,
+			      struct mwifiex_ds_encrypt_key *encrypt_key)
+{
+	int ret = 0;
+	struct mwifiex_private *priv = adapter->priv[wait->bss_index];
+	u8 remove_key = false;
+	struct host_cmd_ds_802_11_key_material *ibss_key;
+
+	/* Current driver only supports key length of up to 32 bytes */
+	if (encrypt_key->key_len > MWIFIEX_MAX_KEY_LENGTH) {
+		dev_err(adapter->dev, "key length too long\n");
+		return -1;
+	}
+
+	if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
+		/*
+		 * IBSS/WPA-None uses only one key (Group) for both receiving
+		 * and sending unicast and multicast packets.
+		 */
+		/* Send the key as PTK to firmware */
+		encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST;
+		ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
+					  HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED,
+					  NULL, encrypt_key);
+		if (ret)
+			return ret;
+
+		ibss_key = &priv->aes_key;
+		memset(ibss_key, 0,
+		       sizeof(struct host_cmd_ds_802_11_key_material));
+		/* Copy the key in the driver */
+		memcpy(ibss_key->key_param_set.key, encrypt_key->key_material,
+		       encrypt_key->key_len);
+		memcpy(&ibss_key->key_param_set.key_len, &encrypt_key->key_len,
+		       sizeof(ibss_key->key_param_set.key_len));
+		ibss_key->key_param_set.key_type_id
+			= cpu_to_le16(KEY_TYPE_ID_TKIP);
+		ibss_key->key_param_set.key_info
+			= cpu_to_le16(KEY_INFO_TKIP_ENABLED);
+
+		/* Send the key as GTK to firmware */
+		encrypt_key->key_index = ~MWIFIEX_KEY_INDEX_UNICAST;
+	}
+
+	if (!encrypt_key->key_index)
+		encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST;
+
+	if (remove_key)
+		/* Send request to firmware */
+		ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
+					  HostCmd_ACT_GEN_SET,
+					  !(KEY_INFO_ENABLED),
+					  wait, encrypt_key);
+	else
+		/* Send request to firmware */
+		ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
+					  HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED,
+					  wait, encrypt_key);
+
+	if (!ret)
+		ret = -EINPROGRESS;
+
+	return ret;
+}
+
+/*
+ * IOCTL request handler to set/get network keys.
+ *
+ * This is a generic key handling function which supports WEP, WPA
+ * and WAPI.
+ */
+static int
+mwifiex_sec_ioctl_encrypt_key(struct mwifiex_private *priv,
+			      struct mwifiex_wait_queue *wait,
+			      struct mwifiex_ds_encrypt_key *encrypt_key)
+{
+	int status = 0;
+	struct mwifiex_adapter *adapter = priv->adapter;
+
+	if (encrypt_key->is_wapi_key)
+		status = mwifiex_sec_ioctl_set_wapi_key(adapter, wait,
+							encrypt_key);
+	else if (encrypt_key->key_len > WLAN_KEY_LEN_WEP104)
+		status = mwifiex_sec_ioctl_set_wpa_key(adapter, wait,
+						       encrypt_key);
+	else
+		status = mwifiex_sec_ioctl_set_wep_key(adapter, wait,
+						       encrypt_key);
+	return status;
+}
+
+/*
+ * This function returns the driver version.
+ */
+int
+mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, char *version,
+			       int max_len)
+{
+	union {
+		u32 l;
+		u8 c[4];
+	} ver;
+	char fw_ver[32];
+
+	ver.l = adapter->fw_release_number;
+	sprintf(fw_ver, "%u.%u.%u.p%u", ver.c[2], ver.c[1], ver.c[0], ver.c[3]);
+
+	snprintf(version, max_len, driver_version, fw_ver);
+
+	dev_dbg(adapter->dev, "info: MWIFIEX VERSION: %s\n", version);
+
+	return 0;
+}
+
+/*
+ * Sends IOCTL request to set Tx power. It can be set to either auto
+ * or a fixed value.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ */
+int
+mwifiex_set_tx_power(struct mwifiex_private *priv, int type, int dbm)
+{
+	struct mwifiex_power_cfg power_cfg;
+	struct mwifiex_wait_queue *wait = NULL;
+	int status = 0;
+	int ret = 0;
+
+	wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT);
+	if (!wait)
+		return -ENOMEM;
+
+	if (type == NL80211_TX_POWER_FIXED) {
+		power_cfg.is_power_auto = 0;
+		power_cfg.power_level = dbm;
+	} else {
+		power_cfg.is_power_auto = 1;
+	}
+	status = mwifiex_power_ioctl_set_power(priv, wait, &power_cfg);
+
+	ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT);
+
+	kfree(wait);
+	return ret;
+}
+
+/*
+ * Sends IOCTL request to get scan table.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ */
+int mwifiex_get_scan_table(struct mwifiex_private *priv, u8 wait_option,
+			   struct mwifiex_scan_resp *scan_resp)
+{
+	struct mwifiex_wait_queue *wait = NULL;
+	struct mwifiex_scan_resp scan;
+	int status = 0;
+
+	/* Allocate wait buffer */
+	wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
+	if (!wait)
+		return -ENOMEM;
+
+	status = mwifiex_scan_networks(priv, wait, HostCmd_ACT_GEN_GET,
+				       NULL, &scan);
+
+	status = mwifiex_request_ioctl(priv, wait, status, wait_option);
+	if (!status) {
+		if (scan_resp)
+			memcpy(scan_resp, &scan,
+			       sizeof(struct mwifiex_scan_resp));
+	}
+
+	if (wait && (status != -EINPROGRESS))
+		kfree(wait);
+	return status;
+}
+
+/*
+ * Sends IOCTL request to get signal information.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ */
+int mwifiex_get_signal_info(struct mwifiex_private *priv, u8 wait_option,
+			    struct mwifiex_ds_get_signal *signal)
+{
+	struct mwifiex_ds_get_signal info;
+	struct mwifiex_wait_queue *wait = NULL;
+	int status = 0;
+
+	/* Allocate wait buffer */
+	wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
+	if (!wait)
+		return -ENOMEM;
+
+	info.selector = ALL_RSSI_INFO_MASK;
+
+	status = mwifiex_get_info_signal(priv, wait, &info);
+
+	status = mwifiex_request_ioctl(priv, wait, status, wait_option);
+	if (!status) {
+		if (signal)
+			memcpy(signal, &info,
+			       sizeof(struct mwifiex_ds_get_signal));
+		if (info.selector & BCN_RSSI_AVG_MASK)
+			priv->w_stats.qual.level = info.bcn_rssi_avg;
+		if (info.selector & BCN_NF_AVG_MASK)
+			priv->w_stats.qual.noise = info.bcn_nf_avg;
+	}
+
+	if (wait && (status != -EINPROGRESS))
+		kfree(wait);
+	return status;
+}
+
+/*
+ * Sends IOCTL request to set encoding parameters.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ */
+int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key,
+			int key_len, u8 key_index, int disable)
+{
+	struct mwifiex_wait_queue *wait = NULL;
+	struct mwifiex_ds_encrypt_key encrypt_key;
+	int status = 0;
+	int ret = 0;
+
+	wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT);
+	if (!wait)
+		return -ENOMEM;
+
+	memset(&encrypt_key, 0, sizeof(struct mwifiex_ds_encrypt_key));
+	encrypt_key.key_len = key_len;
+	if (!disable) {
+		encrypt_key.key_index = key_index;
+		if (key_len)
+			memcpy(encrypt_key.key_material, key, key_len);
+	} else {
+		encrypt_key.key_disable = true;
+	}
+
+	status = mwifiex_sec_ioctl_encrypt_key(priv, wait, &encrypt_key);
+
+	if (mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT))
+		ret = -EFAULT;
+
+	kfree(wait);
+	return ret;
+}
+
+/*
+ * Sends IOCTL request to set power management parameters.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ */
+int
+mwifiex_drv_set_power(struct mwifiex_private *priv, bool power_on)
+{
+	int ret = 0;
+	int status = 0;
+	struct mwifiex_wait_queue *wait = NULL;
+	u32 ps_mode;
+
+	wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT);
+	if (!wait)
+		return -ENOMEM;
+
+	ps_mode = power_on;
+	status = mwifiex_pm_ioctl_ps_mode(priv, wait, &ps_mode,
+					  HostCmd_ACT_GEN_SET);
+
+	ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT);
+
+	kfree(wait);
+	return ret;
+}
+
+/*
+ * Sends IOCTL request to get extended version.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ */
+int
+mwifiex_get_ver_ext(struct mwifiex_private *priv)
+{
+	struct mwifiex_ver_ext ver_ext;
+	struct mwifiex_wait_queue *wait = NULL;
+	int status = 0;
+	int ret = 0;
+	u8 wait_option = MWIFIEX_IOCTL_WAIT;
+
+	/* Allocate wait buffer */
+	wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
+	if (!wait)
+		return -ENOMEM;
+
+	/* get fw version */
+	memset(&ver_ext, 0, sizeof(struct host_cmd_ds_version_ext));
+	status = mwifiex_get_info_ver_ext(priv, wait, &ver_ext);
+
+	ret = mwifiex_request_ioctl(priv, wait, status, wait_option);
+
+	if (ret)
+		ret = -1;
+
+	kfree(wait);
+	return ret;
+}
+
+/*
+ * Sends IOCTL request to get statistics information.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ */
+int
+mwifiex_get_stats_info(struct mwifiex_private *priv,
+		       struct mwifiex_ds_get_stats *log)
+{
+	int ret = 0;
+	int status = 0;
+	struct mwifiex_wait_queue *wait = NULL;
+	struct mwifiex_ds_get_stats get_log;
+	u8 wait_option = MWIFIEX_IOCTL_WAIT;
+
+	/* Allocate wait buffer */
+	wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
+	if (!wait)
+		return -ENOMEM;
+
+	memset(&get_log, 0, sizeof(struct mwifiex_ds_get_stats));
+	status = mwifiex_get_info_stats(priv, wait, &get_log);
+
+	/* Send IOCTL request to MWIFIEX */
+	ret = mwifiex_request_ioctl(priv, wait, status, wait_option);
+	if (!ret) {
+		if (log)
+			memcpy(log, &get_log, sizeof(struct
+					mwifiex_ds_get_stats));
+		priv->w_stats.discard.fragment = get_log.fcs_error;
+		priv->w_stats.discard.retries = get_log.retry;
+		priv->w_stats.discard.misc = get_log.ack_failure;
+	}
+
+	kfree(wait);
+	return ret;
+}
+
+/*
+ * IOCTL request handler to read/write register.
+ *
+ * This function prepares the correct firmware command and
+ * issues it.
+ *
+ * Access to the following registers are supported -
+ *      - MAC
+ *      - BBP
+ *      - RF
+ *      - PMIC
+ *      - CAU
+ */
+static int mwifiex_reg_mem_ioctl_reg_rw(struct mwifiex_private *priv,
+					struct mwifiex_wait_queue *wait,
+					struct mwifiex_ds_reg_rw *reg_rw,
+					u16 action)
+{
+	int ret = 0;
+	u16 cmd_no;
+
+	switch (le32_to_cpu(reg_rw->type)) {
+	case MWIFIEX_REG_MAC:
+		cmd_no = HostCmd_CMD_MAC_REG_ACCESS;
+		break;
+	case MWIFIEX_REG_BBP:
+		cmd_no = HostCmd_CMD_BBP_REG_ACCESS;
+		break;
+	case MWIFIEX_REG_RF:
+		cmd_no = HostCmd_CMD_RF_REG_ACCESS;
+		break;
+	case MWIFIEX_REG_PMIC:
+		cmd_no = HostCmd_CMD_PMIC_REG_ACCESS;
+		break;
+	case MWIFIEX_REG_CAU:
+		cmd_no = HostCmd_CMD_CAU_REG_ACCESS;
+		break;
+	default:
+		return -1;
+	}
+
+	/* Send request to firmware */
+	ret = mwifiex_prepare_cmd(priv, cmd_no, action, 0, wait, reg_rw);
+
+	if (!ret)
+		ret = -EINPROGRESS;
+
+	return ret;
+}
+
+/*
+ * Sends IOCTL request to write to a register.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ */
+int
+mwifiex_reg_write(struct mwifiex_private *priv, u32 reg_type,
+		  u32 reg_offset, u32 reg_value)
+{
+	int ret = 0;
+	int status = 0;
+	struct mwifiex_wait_queue *wait = NULL;
+	struct mwifiex_ds_reg_rw reg_rw;
+
+	wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT);
+	if (!wait)
+		return -ENOMEM;
+
+	reg_rw.type = cpu_to_le32(reg_type);
+	reg_rw.offset = cpu_to_le32(reg_offset);
+	reg_rw.value = cpu_to_le32(reg_value);
+	status = mwifiex_reg_mem_ioctl_reg_rw(priv, wait, &reg_rw,
+					      HostCmd_ACT_GEN_SET);
+
+	ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT);
+
+	kfree(wait);
+	return ret;
+}
+
+/*
+ * Sends IOCTL request to read from a register.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ */
+int
+mwifiex_reg_read(struct mwifiex_private *priv, u32 reg_type,
+		 u32 reg_offset, u32 *value)
+{
+	int ret = 0;
+	int status = 0;
+	struct mwifiex_wait_queue *wait = NULL;
+	struct mwifiex_ds_reg_rw reg_rw;
+
+	wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT);
+	if (!wait)
+		return -ENOMEM;
+
+	reg_rw.type = cpu_to_le32(reg_type);
+	reg_rw.offset = cpu_to_le32(reg_offset);
+	status = mwifiex_reg_mem_ioctl_reg_rw(priv, wait, &reg_rw,
+					      HostCmd_ACT_GEN_GET);
+
+	ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT);
+	if (ret)
+		goto done;
+
+	*value = le32_to_cpu(reg_rw.value);
+
+done:
+	kfree(wait);
+	return ret;
+}
+
+/*
+ * IOCTL request handler to read EEPROM.
+ *
+ * This function prepares the correct firmware command and
+ * issues it.
+ */
+static int
+mwifiex_reg_mem_ioctl_read_eeprom(struct mwifiex_private *priv,
+				  struct mwifiex_wait_queue *wait,
+				  struct mwifiex_ds_read_eeprom *rd_eeprom)
+{
+	int ret = 0;
+
+	/* Send request to firmware */
+	ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_EEPROM_ACCESS,
+				  HostCmd_ACT_GEN_GET, 0, wait, rd_eeprom);
+
+	if (!ret)
+		ret = -EINPROGRESS;
+
+	return ret;
+}
+
+/*
+ * Sends IOCTL request to read from EEPROM.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ */
+int
+mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes,
+		    u8 *value)
+{
+	int ret = 0;
+	int status = 0;
+	struct mwifiex_wait_queue *wait = NULL;
+	struct mwifiex_ds_read_eeprom rd_eeprom;
+
+	wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT);
+	if (!wait)
+		return -ENOMEM;
+
+	rd_eeprom.offset = cpu_to_le16((u16) offset);
+	rd_eeprom.byte_count = cpu_to_le16((u16) bytes);
+	status = mwifiex_reg_mem_ioctl_read_eeprom(priv, wait, &rd_eeprom);
+
+	ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT);
+	if (ret)
+		goto done;
+
+	memcpy(value, rd_eeprom.value, MAX_EEPROM_DATA);
+done:
+	kfree(wait);
+	return ret;
+}
+
+/*
+ * This function sets a generic IE. In addition to generic IE, it can
+ * also handle WPA, WPA2 and WAPI IEs.
+ */
+static int
+mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr,
+			  u16 ie_len)
+{
+	int ret = 0;
+	struct ieee_types_vendor_header *pvendor_ie;
+	const u8 wpa_oui[] = { 0x00, 0x50, 0xf2, 0x01 };
+	const u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 };
+
+	/* If the passed length is zero, reset the buffer */
+	if (!ie_len) {
+		priv->gen_ie_buf_len = 0;
+		priv->wps.session_enable = false;
+
+		return 0;
+	} else if (!ie_data_ptr) {
+		return -1;
+	}
+	pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr;
+	/* Test to see if it is a WPA IE, if not, then it is a gen IE */
+	if (((pvendor_ie->element_id == WLAN_EID_WPA)
+	     && (!memcmp(pvendor_ie->oui, wpa_oui, sizeof(wpa_oui))))
+			|| (pvendor_ie->element_id == WLAN_EID_RSN)) {
+
+		/* IE is a WPA/WPA2 IE so call set_wpa function */
+		ret = mwifiex_set_wpa_ie_helper(priv, ie_data_ptr, ie_len);
+		priv->wps.session_enable = false;
+
+		return ret;
+	} else if (pvendor_ie->element_id == WLAN_EID_BSS_AC_ACCESS_DELAY) {
+		/* IE is a WAPI IE so call set_wapi function */
+		ret = mwifiex_set_wapi_ie(priv, ie_data_ptr, ie_len);
+
+		return ret;
+	}
+	/*
+	 * Verify that the passed length is not larger than the
+	 * available space remaining in the buffer
+	 */
+	if (ie_len < (sizeof(priv->gen_ie_buf) - priv->gen_ie_buf_len)) {
+
+		/* Test to see if it is a WPS IE, if so, enable
+		 * wps session flag
+		 */
+		pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr;
+		if ((pvendor_ie->element_id == WLAN_EID_VENDOR_SPECIFIC)
+				&& (!memcmp(pvendor_ie->oui, wps_oui,
+						sizeof(wps_oui)))) {
+			priv->wps.session_enable = true;
+			dev_dbg(priv->adapter->dev,
+				"info: WPS Session Enabled.\n");
+		}
+
+		/* Append the passed data to the end of the
+		   genIeBuffer */
+		memcpy(priv->gen_ie_buf + priv->gen_ie_buf_len, ie_data_ptr,
+									ie_len);
+		/* Increment the stored buffer length by the
+		   size passed */
+		priv->gen_ie_buf_len += ie_len;
+	} else {
+		/* Passed data does not fit in the remaining
+		   buffer space */
+		ret = -1;
+	}
+
+	/* Return 0, or -1 for error case */
+	return ret;
+}
+
+/*
+ * IOCTL request handler to set/get generic IE.
+ *
+ * In addition to various generic IEs, this function can also be
+ * used to set the ARP filter.
+ */
+static int mwifiex_misc_ioctl_gen_ie(struct mwifiex_private *priv,
+				     struct mwifiex_ds_misc_gen_ie *gen_ie,
+				     u16 action)
+{
+	struct mwifiex_adapter *adapter = priv->adapter;
+
+	switch (gen_ie->type) {
+	case MWIFIEX_IE_TYPE_GEN_IE:
+		if (action == HostCmd_ACT_GEN_GET) {
+			gen_ie->len = priv->wpa_ie_len;
+			memcpy(gen_ie->ie_data, priv->wpa_ie, gen_ie->len);
+		} else {
+			mwifiex_set_gen_ie_helper(priv, gen_ie->ie_data,
+						  (u16) gen_ie->len);
+		}
+		break;
+	case MWIFIEX_IE_TYPE_ARP_FILTER:
+		memset(adapter->arp_filter, 0, sizeof(adapter->arp_filter));
+		if (gen_ie->len > ARP_FILTER_MAX_BUF_SIZE) {
+			adapter->arp_filter_size = 0;
+			dev_err(adapter->dev, "invalid ARP filter size\n");
+			return -1;
+		} else {
+			memcpy(adapter->arp_filter, gen_ie->ie_data,
+								gen_ie->len);
+			adapter->arp_filter_size = gen_ie->len;
+		}
+		break;
+	default:
+		dev_err(adapter->dev, "invalid IE type\n");
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ * Sends IOCTL request to set a generic IE.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ */
+int
+mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len)
+{
+	struct mwifiex_ds_misc_gen_ie gen_ie;
+	int status = 0;
+
+	if (ie_len > IW_CUSTOM_MAX)
+		return -EFAULT;
+
+	gen_ie.type = MWIFIEX_IE_TYPE_GEN_IE;
+	gen_ie.len = ie_len;
+	memcpy(gen_ie.ie_data, ie, ie_len);
+	status = mwifiex_misc_ioctl_gen_ie(priv, &gen_ie, HostCmd_ACT_GEN_SET);
+	if (status)
+		return -EFAULT;
+
+	return 0;
+}
diff --git a/drivers/net/wireless/mwifiex/sta_rx.c b/drivers/net/wireless/mwifiex/sta_rx.c
new file mode 100644
index 0000000..8282679
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/sta_rx.c
@@ -0,0 +1,182 @@
+/*
+ * Marvell Wireless LAN device driver: station RX data handling
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "11n_aggr.h"
+#include "11n_rxreorder.h"
+
+/*
+ * This function processes the received packet and forwards it
+ * to kernel/upper layer.
+ *
+ * This function parses through the received packet and determines
+ * if it is a debug packet or normal packet.
+ *
+ * For non-debug packets, the function chops off unnecessary leading
+ * header bytes, reconstructs the packet as an ethernet frame or
+ * 802.2/llc/snap frame as required, and sends it to kernel/upper layer.
+ *
+ * The completion callback is called after processing in complete.
+ */
+int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter,
+			      struct sk_buff *skb)
+{
+	int ret = 0;
+	struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
+	struct mwifiex_private *priv = adapter->priv[rx_info->bss_index];
+	struct rx_packet_hdr *rx_pkt_hdr;
+	struct rxpd *local_rx_pd;
+	int hdr_chop;
+	struct ethhdr *eth_hdr;
+	u8 rfc1042_eth_hdr[ETH_ALEN] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+	local_rx_pd = (struct rxpd *) (skb->data);
+
+	rx_pkt_hdr = (struct rx_packet_hdr *) ((u8 *) local_rx_pd +
+				local_rx_pd->rx_pkt_offset);
+
+	if (!memcmp(&rx_pkt_hdr->rfc1042_hdr,
+		    rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr))) {
+		/*
+		 *  Replace the 803 header and rfc1042 header (llc/snap) with an
+		 *    EthernetII header, keep the src/dst and snap_type
+		 *    (ethertype).
+		 *  The firmware only passes up SNAP frames converting
+		 *    all RX Data from 802.11 to 802.2/LLC/SNAP frames.
+		 *  To create the Ethernet II, just move the src, dst address
+		 *    right before the snap_type.
+		 */
+		eth_hdr = (struct ethhdr *)
+			((u8 *) &rx_pkt_hdr->eth803_hdr
+			 + sizeof(rx_pkt_hdr->eth803_hdr) +
+			 sizeof(rx_pkt_hdr->rfc1042_hdr)
+			 - sizeof(rx_pkt_hdr->eth803_hdr.h_dest)
+			 - sizeof(rx_pkt_hdr->eth803_hdr.h_source)
+			 - sizeof(rx_pkt_hdr->rfc1042_hdr.snap_type));
+
+		memcpy(eth_hdr->h_source, rx_pkt_hdr->eth803_hdr.h_source,
+		       sizeof(eth_hdr->h_source));
+		memcpy(eth_hdr->h_dest, rx_pkt_hdr->eth803_hdr.h_dest,
+		       sizeof(eth_hdr->h_dest));
+
+		/* Chop off the rxpd + the excess memory from the 802.2/llc/snap
+		   header that was removed. */
+		hdr_chop = (u8 *) eth_hdr - (u8 *) local_rx_pd;
+	} else {
+		/* Chop off the rxpd */
+		hdr_chop = (u8 *) &rx_pkt_hdr->eth803_hdr -
+			(u8 *) local_rx_pd;
+	}
+
+	/* Chop off the leading header bytes so the it points to the start of
+	   either the reconstructed EthII frame or the 802.2/llc/snap frame */
+	skb_pull(skb, hdr_chop);
+
+	priv->rxpd_rate = local_rx_pd->rx_rate;
+
+	priv->rxpd_htinfo = local_rx_pd->ht_info;
+
+	ret = mwifiex_recv_packet(adapter, skb);
+	if (ret == -1)
+		dev_err(adapter->dev, "recv packet failed\n");
+
+	return ret;
+}
+
+/*
+ * This function processes the received buffer.
+ *
+ * The function looks into the RxPD and performs sanity tests on the
+ * received buffer to ensure its a valid packet, before processing it
+ * further. If the packet is determined to be aggregated, it is
+ * de-aggregated accordingly. Non-unicast packets are sent directly to
+ * the kernel/upper layers. Unicast packets are handed over to the
+ * Rx reordering routine if 11n is enabled.
+ *
+ * The completion callback is called after processing in complete.
+ */
+int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter,
+				  struct sk_buff *skb)
+{
+	int ret = 0;
+	struct rxpd *local_rx_pd;
+	struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
+	struct rx_packet_hdr *rx_pkt_hdr;
+	u8 ta[ETH_ALEN];
+	u16 rx_pkt_type = 0;
+	struct mwifiex_private *priv = adapter->priv[rx_info->bss_index];
+
+	local_rx_pd = (struct rxpd *) (skb->data);
+	rx_pkt_type = local_rx_pd->rx_pkt_type;
+
+	rx_pkt_hdr = (struct rx_packet_hdr *) ((u8 *) local_rx_pd +
+					local_rx_pd->rx_pkt_offset);
+
+	if ((local_rx_pd->rx_pkt_offset + local_rx_pd->rx_pkt_length) >
+	    (u16) skb->len) {
+		dev_err(adapter->dev, "wrong rx packet: len=%d,"
+			" rx_pkt_offset=%d, rx_pkt_length=%d\n", skb->len,
+		       local_rx_pd->rx_pkt_offset, local_rx_pd->rx_pkt_length);
+		priv->stats.rx_dropped++;
+		dev_kfree_skb_any(skb);
+		return ret;
+	}
+	if (local_rx_pd->rx_pkt_type == PKT_TYPE_AMSDU) {
+		mwifiex_11n_deaggregate_pkt(priv, skb);
+		return ret;
+	}
+	/*
+	 * If the packet is not an unicast packet then send the packet
+	 * directly to os. Don't pass thru rx reordering
+	 */
+	if (!IS_11N_ENABLED(priv) ||
+	    memcmp(priv->curr_addr, rx_pkt_hdr->eth803_hdr.h_dest, ETH_ALEN)) {
+		mwifiex_process_rx_packet(adapter, skb);
+		return ret;
+	}
+
+	if (mwifiex_queuing_ra_based(priv)) {
+		memcpy(ta, rx_pkt_hdr->eth803_hdr.h_source, ETH_ALEN);
+	} else {
+		if (rx_pkt_type != PKT_TYPE_BAR)
+			priv->rx_seq[local_rx_pd->priority] =
+						local_rx_pd->seq_num;
+		memcpy(ta, priv->curr_bss_params.bss_descriptor.mac_address,
+		       ETH_ALEN);
+	}
+
+	/* Reorder and send to OS */
+	ret = mwifiex_11n_rx_reorder_pkt(priv, local_rx_pd->seq_num,
+					     local_rx_pd->priority, ta,
+					     (u8) local_rx_pd->rx_pkt_type,
+						(void *) skb);
+
+	if (ret || (rx_pkt_type == PKT_TYPE_BAR)) {
+		if (priv && (ret == -1))
+			priv->stats.rx_dropped++;
+
+		dev_kfree_skb_any(skb);
+	}
+
+	return ret;
+}
diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c
new file mode 100644
index 0000000..e8db6bd
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/sta_tx.c
@@ -0,0 +1,202 @@
+/*
+ * Marvell Wireless LAN device driver: station TX data handling
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+
+/*
+ * This function fills the TxPD for tx packets.
+ *
+ * The Tx buffer received by this function should already have the
+ * header space allocated for TxPD.
+ *
+ * This function inserts the TxPD in between interface header and actual
+ * data and adjusts the buffer pointers accordingly.
+ *
+ * The following TxPD fields are set by this function, as required -
+ *      - BSS number
+ *      - Tx packet length and offset
+ *      - Priority
+ *      - Packet delay
+ *      - Priority specific Tx control
+ *      - Flags
+ */
+void *mwifiex_process_sta_txpd(struct mwifiex_private *priv,
+				struct sk_buff *skb)
+{
+	struct mwifiex_adapter *adapter = priv->adapter;
+	struct txpd *local_tx_pd;
+	struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb);
+
+	if (!skb->len) {
+		dev_err(adapter->dev, "Tx: bad packet length: %d\n",
+		       skb->len);
+		tx_info->status_code = MWIFIEX_ERROR_PKT_SIZE_INVALID;
+		return skb->data;
+	}
+
+	BUG_ON(skb_headroom(skb) < (sizeof(*local_tx_pd) + INTF_HEADER_LEN));
+	skb_push(skb, sizeof(*local_tx_pd));
+
+	local_tx_pd = (struct txpd *) skb->data;
+	memset(local_tx_pd, 0, sizeof(struct txpd));
+	local_tx_pd->bss_num = priv->bss_num;
+	local_tx_pd->bss_type = priv->bss_type;
+	local_tx_pd->tx_pkt_length = cpu_to_le16((u16) (skb->len -
+							sizeof(struct txpd)));
+
+	local_tx_pd->priority = (u8) skb->priority;
+	local_tx_pd->pkt_delay_2ms =
+		mwifiex_wmm_compute_drv_pkt_delay(priv, skb);
+
+	if (local_tx_pd->priority <
+	    ARRAY_SIZE(priv->wmm.user_pri_pkt_tx_ctrl))
+		/*
+		 * Set the priority specific tx_control field, setting of 0 will
+		 *   cause the default value to be used later in this function
+		 */
+		local_tx_pd->tx_control =
+			cpu_to_le32(priv->wmm.user_pri_pkt_tx_ctrl[local_tx_pd->
+							 priority]);
+
+	if (adapter->pps_uapsd_mode) {
+		if (mwifiex_check_last_packet_indication(priv)) {
+			adapter->tx_lock_flag = true;
+			local_tx_pd->flags =
+				MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET;
+		}
+	}
+
+	/* Offset of actual data */
+	local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd));
+
+	/* make space for INTF_HEADER_LEN */
+	skb_push(skb, INTF_HEADER_LEN);
+
+	if (!local_tx_pd->tx_control)
+		/* TxCtrl set by user or default */
+		local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl);
+
+	return skb->data;
+}
+
+/*
+ * This function tells firmware to send a NULL data packet.
+ *
+ * The function creates a NULL data packet with TxPD and sends to the
+ * firmware for transmission, with highest priority setting.
+ */
+int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags)
+{
+	struct mwifiex_adapter *adapter = priv->adapter;
+	struct txpd *local_tx_pd;
+/* sizeof(struct txpd) + Interface specific header */
+#define NULL_PACKET_HDR 64
+	u32 data_len = NULL_PACKET_HDR;
+	struct sk_buff *skb = NULL;
+	int ret = 0;
+	struct mwifiex_txinfo *tx_info = NULL;
+
+	if (adapter->surprise_removed)
+		return -1;
+
+	if (!priv->media_connected)
+		return -1;
+
+	if (adapter->data_sent)
+		return -1;
+
+	skb = dev_alloc_skb(data_len);
+	if (!skb)
+		return -1;
+
+	tx_info = MWIFIEX_SKB_TXCB(skb);
+	tx_info->bss_index = priv->bss_index;
+	skb_reserve(skb, sizeof(struct txpd) + INTF_HEADER_LEN);
+	skb_push(skb, sizeof(struct txpd));
+
+	local_tx_pd = (struct txpd *) skb->data;
+	local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl);
+	local_tx_pd->flags = flags;
+	local_tx_pd->priority = WMM_HIGHEST_PRIORITY;
+	local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd));
+	local_tx_pd->bss_num = priv->bss_num;
+	local_tx_pd->bss_type = priv->bss_type;
+
+	skb_push(skb, INTF_HEADER_LEN);
+
+	ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
+					     skb->data, skb->len, NULL);
+	switch (ret) {
+	case -EBUSY:
+		adapter->data_sent = true;
+		/* Fall through FAILURE handling */
+	case -1:
+		dev_kfree_skb_any(skb);
+		dev_err(adapter->dev, "%s: host_to_card failed: ret=%d\n",
+						__func__, ret);
+		adapter->dbg.num_tx_host_to_card_failure++;
+		break;
+	case 0:
+		dev_kfree_skb_any(skb);
+		dev_dbg(adapter->dev, "data: %s: host_to_card succeeded\n",
+						__func__);
+		adapter->tx_lock_flag = true;
+		break;
+	case -EINPROGRESS:
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+/*
+ * This function checks if we need to send last packet indication.
+ */
+u8
+mwifiex_check_last_packet_indication(struct mwifiex_private *priv)
+{
+	struct mwifiex_adapter *adapter = priv->adapter;
+	u8 ret = false;
+	u8 prop_ps = true;
+
+	if (!adapter->sleep_period.period)
+		return ret;
+	if (mwifiex_wmm_lists_empty(adapter)) {
+		if ((priv->curr_bss_params.wmm_uapsd_enabled &&
+		     priv->wmm_qosinfo) || prop_ps)
+			ret = true;
+	}
+
+	if (ret && !adapter->cmd_sent && !adapter->curr_cmd
+	    && !is_command_pending(adapter)) {
+		adapter->delay_null_pkt = false;
+		ret = true;
+	} else {
+		ret = false;
+		adapter->delay_null_pkt = true;
+	}
+	return ret;
+}
diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c
new file mode 100644
index 0000000..f06923c
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/txrx.c
@@ -0,0 +1,202 @@
+/*
+ * Marvell Wireless LAN device driver: generic TX/RX data handling
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+
+/*
+ * This function processes the received buffer.
+ *
+ * Main responsibility of this function is to parse the RxPD to
+ * identify the correct interface this packet is headed for and
+ * forwarding it to the associated handling function, where the
+ * packet will be further processed and sent to kernel/upper layer
+ * if required.
+ */
+int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter,
+			     struct sk_buff *skb)
+{
+	int ret = 0;
+	struct mwifiex_private *priv =
+		mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
+	struct rxpd *local_rx_pd;
+	struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
+
+	local_rx_pd = (struct rxpd *) (skb->data);
+	/* Get the BSS number from rxpd, get corresponding priv */
+	priv = mwifiex_get_priv_by_id(adapter, local_rx_pd->bss_num &
+				      BSS_NUM_MASK, local_rx_pd->bss_type);
+	if (!priv)
+		priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
+
+	rx_info->bss_index = priv->bss_index;
+	ret = mwifiex_process_sta_rx_packet(adapter, skb);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(mwifiex_handle_rx_packet);
+
+/*
+ * This function sends a packet to device.
+ *
+ * It processes the packet to add the TxPD, checks condition and
+ * sends the processed packet to firmware for transmission.
+ *
+ * On successful completion, the function calls the completion callback
+ * and logs the time.
+ */
+int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
+		       struct mwifiex_tx_param *tx_param)
+{
+	int ret = -1;
+	struct mwifiex_adapter *adapter = priv->adapter;
+	u8 *head_ptr = NULL;
+	struct txpd *local_tx_pd = NULL;
+
+	head_ptr = (u8 *) mwifiex_process_sta_txpd(priv, skb);
+	if (head_ptr) {
+		if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA)
+			local_tx_pd =
+				(struct txpd *) (head_ptr + INTF_HEADER_LEN);
+
+		ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
+					     skb->data, skb->len, tx_param);
+	}
+
+	switch (ret) {
+	case -EBUSY:
+		if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
+			(adapter->pps_uapsd_mode) &&
+			(adapter->tx_lock_flag)) {
+				priv->adapter->tx_lock_flag = false;
+				local_tx_pd->flags = 0;
+		}
+		dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
+		break;
+	case -1:
+		adapter->data_sent = false;
+		dev_err(adapter->dev, "mwifiex_write_data_async failed: 0x%X\n",
+		       ret);
+		adapter->dbg.num_tx_host_to_card_failure++;
+		mwifiex_write_data_complete(adapter, skb, ret);
+		break;
+	case -EINPROGRESS:
+		adapter->data_sent = false;
+		break;
+	case 0:
+		mwifiex_write_data_complete(adapter, skb, ret);
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+/*
+ * Packet send completion callback handler.
+ *
+ * It either frees the buffer directly or forwards it to another
+ * completion callback which checks conditions, updates statistics,
+ * wakes up stalled traffic queue if required, and then frees the buffer.
+ */
+int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
+				struct sk_buff *skb, int status)
+{
+	struct mwifiex_private *priv = NULL, *tpriv = NULL;
+	struct mwifiex_txinfo *tx_info = NULL;
+	int i;
+
+	if (!skb)
+		return 0;
+
+	tx_info = MWIFIEX_SKB_TXCB(skb);
+	priv = mwifiex_bss_index_to_priv(adapter, tx_info->bss_index);
+	if (!priv)
+		goto done;
+
+	priv->netdev->trans_start = jiffies;
+	if (!status) {
+		priv->stats.tx_packets++;
+		priv->stats.tx_bytes += skb->len;
+	} else {
+		priv->stats.tx_errors++;
+	}
+	atomic_dec(&adapter->tx_pending);
+
+	for (i = 0; i < adapter->priv_num; i++) {
+
+		tpriv = adapter->priv[i];
+
+		if ((GET_BSS_ROLE(tpriv) == MWIFIEX_BSS_ROLE_STA)
+				&& (tpriv->media_connected)) {
+			if (netif_queue_stopped(tpriv->netdev))
+				netif_wake_queue(tpriv->netdev);
+		}
+	}
+done:
+	dev_kfree_skb_any(skb);
+
+	return 0;
+}
+
+/*
+ * Packet receive completion callback handler.
+ *
+ * This function calls another completion callback handler which
+ * updates the statistics, and optionally updates the parent buffer
+ * use count before freeing the received packet.
+ */
+int mwifiex_recv_packet_complete(struct mwifiex_adapter *adapter,
+				 struct sk_buff *skb, int status)
+{
+	struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
+	struct mwifiex_rxinfo *rx_info_parent = NULL;
+	struct mwifiex_private *priv;
+	struct sk_buff *skb_parent = NULL;
+	unsigned long flags;
+
+	priv = adapter->priv[rx_info->bss_index];
+
+	if (priv && (status == -1))
+		priv->stats.rx_dropped++;
+
+	if (rx_info->parent) {
+		skb_parent = rx_info->parent;
+		rx_info_parent = MWIFIEX_SKB_RXCB(skb_parent);
+
+		spin_lock_irqsave(&priv->rx_pkt_lock, flags);
+		--rx_info_parent->use_count;
+
+		if (!rx_info_parent->use_count) {
+			spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
+			dev_kfree_skb_any(skb_parent);
+		} else {
+			spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
+		}
+	} else {
+		dev_kfree_skb_any(skb);
+	}
+
+	return 0;
+}
diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c
new file mode 100644
index 0000000..205022a
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/util.c
@@ -0,0 +1,252 @@
+/*
+ * Marvell Wireless LAN device driver: utility functions
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+#include "11n.h"
+
+/*
+ * Firmware initialization complete callback handler.
+ *
+ * This function wakes up the function waiting on the init
+ * wait queue for the firmware initialization to complete.
+ */
+int mwifiex_init_fw_complete(struct mwifiex_adapter *adapter)
+{
+
+	adapter->init_wait_q_woken = true;
+	wake_up_interruptible(&adapter->init_wait_q);
+	return 0;
+}
+
+/*
+ * Firmware shutdown complete callback handler.
+ *
+ * This function sets the hardware status to not ready and wakes up
+ * the function waiting on the init wait queue for the firmware
+ * shutdown to complete.
+ */
+int mwifiex_shutdown_fw_complete(struct mwifiex_adapter *adapter)
+{
+	adapter->hw_status = MWIFIEX_HW_STATUS_NOT_READY;
+	adapter->init_wait_q_woken = true;
+	wake_up_interruptible(&adapter->init_wait_q);
+	return 0;
+}
+
+/*
+ * IOCTL request handler to send function init/shutdown command
+ * to firmware.
+ *
+ * This function prepares the correct firmware command and
+ * issues it.
+ */
+int mwifiex_misc_ioctl_init_shutdown(struct mwifiex_adapter *adapter,
+				     struct mwifiex_wait_queue *wait,
+				     u32 func_init_shutdown)
+{
+	struct mwifiex_private *priv = adapter->priv[wait->bss_index];
+	int ret;
+	u16 cmd;
+
+	if (func_init_shutdown == MWIFIEX_FUNC_INIT) {
+		cmd = HostCmd_CMD_FUNC_INIT;
+	} else if (func_init_shutdown == MWIFIEX_FUNC_SHUTDOWN) {
+		cmd = HostCmd_CMD_FUNC_SHUTDOWN;
+	} else {
+		dev_err(adapter->dev, "unsupported parameter\n");
+		return -1;
+	}
+
+	/* Send command to firmware */
+	ret = mwifiex_prepare_cmd(priv, cmd, HostCmd_ACT_GEN_SET,
+				  0, wait, NULL);
+
+	if (!ret)
+		ret = -EINPROGRESS;
+
+	return ret;
+}
+
+/*
+ * IOCTL request handler to set/get debug information.
+ *
+ * This function collates/sets the information from/to different driver
+ * structures.
+ */
+int mwifiex_get_debug_info(struct mwifiex_private *priv,
+			   struct mwifiex_debug_info *info)
+{
+	struct mwifiex_adapter *adapter = priv->adapter;
+
+	if (info) {
+		memcpy(info->packets_out,
+		       priv->wmm.packets_out,
+		       sizeof(priv->wmm.packets_out));
+		info->max_tx_buf_size = (u32) adapter->max_tx_buf_size;
+		info->tx_buf_size = (u32) adapter->tx_buf_size;
+		info->rx_tbl_num = mwifiex_get_rx_reorder_tbl(
+					priv, info->rx_tbl);
+		info->tx_tbl_num = mwifiex_get_tx_ba_stream_tbl(
+					priv, info->tx_tbl);
+		info->ps_mode = adapter->ps_mode;
+		info->ps_state = adapter->ps_state;
+		info->is_deep_sleep = adapter->is_deep_sleep;
+		info->pm_wakeup_card_req = adapter->pm_wakeup_card_req;
+		info->pm_wakeup_fw_try = adapter->pm_wakeup_fw_try;
+		info->is_hs_configured = adapter->is_hs_configured;
+		info->hs_activated = adapter->hs_activated;
+		info->num_cmd_host_to_card_failure
+			= adapter->dbg.num_cmd_host_to_card_failure;
+		info->num_cmd_sleep_cfm_host_to_card_failure
+			= adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure;
+		info->num_tx_host_to_card_failure
+			= adapter->dbg.num_tx_host_to_card_failure;
+		info->num_event_deauth = adapter->dbg.num_event_deauth;
+		info->num_event_disassoc = adapter->dbg.num_event_disassoc;
+		info->num_event_link_lost = adapter->dbg.num_event_link_lost;
+		info->num_cmd_deauth = adapter->dbg.num_cmd_deauth;
+		info->num_cmd_assoc_success =
+			adapter->dbg.num_cmd_assoc_success;
+		info->num_cmd_assoc_failure =
+			adapter->dbg.num_cmd_assoc_failure;
+		info->num_tx_timeout = adapter->dbg.num_tx_timeout;
+		info->num_cmd_timeout = adapter->dbg.num_cmd_timeout;
+		info->timeout_cmd_id = adapter->dbg.timeout_cmd_id;
+		info->timeout_cmd_act = adapter->dbg.timeout_cmd_act;
+		memcpy(info->last_cmd_id, adapter->dbg.last_cmd_id,
+		       sizeof(adapter->dbg.last_cmd_id));
+		memcpy(info->last_cmd_act, adapter->dbg.last_cmd_act,
+		       sizeof(adapter->dbg.last_cmd_act));
+		info->last_cmd_index = adapter->dbg.last_cmd_index;
+		memcpy(info->last_cmd_resp_id, adapter->dbg.last_cmd_resp_id,
+		       sizeof(adapter->dbg.last_cmd_resp_id));
+		info->last_cmd_resp_index = adapter->dbg.last_cmd_resp_index;
+		memcpy(info->last_event, adapter->dbg.last_event,
+		       sizeof(adapter->dbg.last_event));
+		info->last_event_index = adapter->dbg.last_event_index;
+		info->data_sent = adapter->data_sent;
+		info->cmd_sent = adapter->cmd_sent;
+		info->cmd_resp_received = adapter->cmd_resp_received;
+	}
+
+	return 0;
+}
+
+/*
+ * This function processes the received packet before sending it to the
+ * kernel.
+ *
+ * It extracts the SKB from the received buffer and sends it to kernel.
+ * In case the received buffer does not contain the data in SKB format,
+ * the function creates a blank SKB, fills it with the data from the
+ * received buffer and then sends this new SKB to the kernel.
+ */
+int mwifiex_recv_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb)
+{
+	struct mwifiex_rxinfo *rx_info = NULL;
+	struct mwifiex_private *priv = NULL;
+
+	if (!skb)
+		return -1;
+
+	rx_info = MWIFIEX_SKB_RXCB(skb);
+	priv = mwifiex_bss_index_to_priv(adapter, rx_info->bss_index);
+	if (!priv)
+		return -1;
+
+	skb->dev = priv->netdev;
+	skb->protocol = eth_type_trans(skb, priv->netdev);
+	skb->ip_summed = CHECKSUM_NONE;
+	priv->stats.rx_bytes += skb->len;
+	priv->stats.rx_packets++;
+	if (in_interrupt())
+		netif_rx(skb);
+	else
+		netif_rx_ni(skb);
+
+	return 0;
+}
+
+/*
+ * Receive packet completion callback handler.
+ *
+ * This function updates the statistics and frees the buffer SKB.
+ */
+int mwifiex_recv_complete(struct mwifiex_adapter *adapter,
+			  struct sk_buff *skb, int status)
+{
+	struct mwifiex_private *priv = NULL;
+	struct mwifiex_rxinfo *rx_info = NULL;
+
+	if (!skb)
+		return 0;
+
+	rx_info = MWIFIEX_SKB_RXCB(skb);
+	priv = mwifiex_bss_index_to_priv(adapter, rx_info->bss_index);
+
+	if (priv && (status == -1))
+		priv->stats.rx_dropped++;
+
+	dev_kfree_skb_any(skb);
+
+	return 0;
+}
+
+/*
+ * IOCTL completion callback handler.
+ *
+ * This function is called when a pending IOCTL is completed.
+ *
+ * If work queue support is enabled, the function wakes up the
+ * corresponding waiting function. Otherwise, it processes the
+ * IOCTL response and frees the response buffer.
+ */
+int mwifiex_ioctl_complete(struct mwifiex_adapter *adapter,
+			   struct mwifiex_wait_queue *wait_queue,
+			   int status)
+{
+	enum mwifiex_error_code status_code =
+		(enum mwifiex_error_code) wait_queue->status;
+
+	atomic_dec(&adapter->ioctl_pending);
+
+	dev_dbg(adapter->dev, "cmd: IOCTL completed: status=%d,"
+			" status_code=%#x\n", status, status_code);
+
+	if (wait_queue->enabled) {
+		*wait_queue->condition = true;
+		wait_queue->status = status;
+		if (status && (status_code == MWIFIEX_ERROR_CMD_TIMEOUT))
+			dev_err(adapter->dev, "cmd timeout\n");
+		else
+			wake_up_interruptible(wait_queue->wait);
+	} else {
+		if (status)
+			dev_err(adapter->dev, "cmd failed: status_code=%#x\n",
+			       status_code);
+		kfree(wait_queue);
+	}
+
+	return 0;
+}
diff --git a/drivers/net/wireless/mwifiex/util.h b/drivers/net/wireless/mwifiex/util.h
new file mode 100644
index 0000000..9506afc
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/util.h
@@ -0,0 +1,32 @@
+/*
+ * Marvell Wireless LAN device driver: utility functions
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#ifndef _MWIFIEX_UTIL_H_
+#define _MWIFIEX_UTIL_H_
+
+static inline struct mwifiex_rxinfo *MWIFIEX_SKB_RXCB(struct sk_buff *skb)
+{
+	return (struct mwifiex_rxinfo *)skb->cb;
+}
+
+static inline struct mwifiex_txinfo *MWIFIEX_SKB_TXCB(struct sk_buff *skb)
+{
+	return (struct mwifiex_txinfo *)skb->cb;
+}
+#endif /* !_MWIFIEX_UTIL_H_ */
diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c
new file mode 100644
index 0000000..1cfbc6b
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/wmm.c
@@ -0,0 +1,1237 @@
+/*
+ * Marvell Wireless LAN device driver: WMM
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+#include "11n.h"
+
+
+/* Maximum value FW can accept for driver delay in packet transmission */
+#define DRV_PKT_DELAY_TO_FW_MAX   512
+
+
+#define WMM_QUEUED_PACKET_LOWER_LIMIT   180
+
+#define WMM_QUEUED_PACKET_UPPER_LIMIT   200
+
+/* Offset for TOS field in the IP header */
+#define IPTOS_OFFSET 5
+
+/* WMM information IE */
+static const u8 wmm_info_ie[] = { WLAN_EID_VENDOR_SPECIFIC, 0x07,
+	0x00, 0x50, 0xf2, 0x02,
+	0x00, 0x01, 0x00
+};
+
+static const u8 wmm_aci_to_qidx_map[] = { WMM_AC_BE,
+	WMM_AC_BK,
+	WMM_AC_VI,
+	WMM_AC_VO
+};
+
+static u8 tos_to_tid[] = {
+	/* TID DSCP_P2 DSCP_P1 DSCP_P0 WMM_AC */
+	0x01,			/* 0 1 0 AC_BK */
+	0x02,			/* 0 0 0 AC_BK */
+	0x00,			/* 0 0 1 AC_BE */
+	0x03,			/* 0 1 1 AC_BE */
+	0x04,			/* 1 0 0 AC_VI */
+	0x05,			/* 1 0 1 AC_VI */
+	0x06,			/* 1 1 0 AC_VO */
+	0x07			/* 1 1 1 AC_VO */
+};
+
+/*
+ * This table inverses the tos_to_tid operation to get a priority
+ * which is in sequential order, and can be compared.
+ * Use this to compare the priority of two different TIDs.
+ */
+static u8 tos_to_tid_inv[] = {
+	0x02,  /* from tos_to_tid[2] = 0 */
+	0x00,  /* from tos_to_tid[0] = 1 */
+	0x01,  /* from tos_to_tid[1] = 2 */
+	0x03,
+	0x04,
+	0x05,
+	0x06,
+	0x07};
+
+static u8 ac_to_tid[4][2] = { {1, 2}, {0, 3}, {4, 5}, {6, 7} };
+
+/*
+ * This function debug prints the priority parameters for a WMM AC.
+ */
+static void
+mwifiex_wmm_ac_debug_print(const struct ieee_types_wmm_ac_parameters *ac_param)
+{
+	const char *ac_str[] = { "BK", "BE", "VI", "VO" };
+
+	pr_debug("info: WMM AC_%s: ACI=%d, ACM=%d, Aifsn=%d, "
+	       "EcwMin=%d, EcwMax=%d, TxopLimit=%d\n",
+	       ac_str[wmm_aci_to_qidx_map[(ac_param->aci_aifsn_bitmap
+	       & MWIFIEX_ACI) >> 5]],
+	       (ac_param->aci_aifsn_bitmap & MWIFIEX_ACI) >> 5,
+	       (ac_param->aci_aifsn_bitmap & MWIFIEX_ACM) >> 4,
+	       ac_param->aci_aifsn_bitmap & MWIFIEX_AIFSN,
+	       ac_param->ecw_bitmap & MWIFIEX_ECW_MIN,
+	       (ac_param->ecw_bitmap & MWIFIEX_ECW_MAX) >> 4,
+	       le16_to_cpu(ac_param->tx_op_limit));
+}
+
+/*
+ * This function allocates a route address list.
+ *
+ * The function also initializes the list with the provided RA.
+ */
+static struct mwifiex_ra_list_tbl *
+mwifiex_wmm_allocate_ralist_node(struct mwifiex_adapter *adapter, u8 *ra)
+{
+	struct mwifiex_ra_list_tbl *ra_list;
+
+	ra_list = kzalloc(sizeof(struct mwifiex_ra_list_tbl), GFP_ATOMIC);
+
+	if (!ra_list) {
+		dev_err(adapter->dev, "%s: failed to alloc ra_list\n",
+						__func__);
+		return NULL;
+	}
+	INIT_LIST_HEAD(&ra_list->list);
+	skb_queue_head_init(&ra_list->skb_head);
+
+	memcpy(ra_list->ra, ra, ETH_ALEN);
+
+	ra_list->total_pkts_size = 0;
+
+	dev_dbg(adapter->dev, "info: allocated ra_list %p\n", ra_list);
+
+	return ra_list;
+}
+
+/*
+ * This function allocates and adds a RA list for all TIDs
+ * with the given RA.
+ */
+void
+mwifiex_ralist_add(struct mwifiex_private *priv, u8 *ra)
+{
+	int i;
+	struct mwifiex_ra_list_tbl *ra_list;
+	struct mwifiex_adapter *adapter = priv->adapter;
+
+	for (i = 0; i < MAX_NUM_TID; ++i) {
+		ra_list = mwifiex_wmm_allocate_ralist_node(adapter, ra);
+		dev_dbg(adapter->dev, "info: created ra_list %p\n", ra_list);
+
+		if (!ra_list)
+			break;
+
+		if (!mwifiex_queuing_ra_based(priv))
+			ra_list->is_11n_enabled = IS_11N_ENABLED(priv);
+		else
+			ra_list->is_11n_enabled = false;
+
+		dev_dbg(adapter->dev, "data: ralist %p: is_11n_enabled=%d\n",
+			ra_list, ra_list->is_11n_enabled);
+
+		list_add_tail(&ra_list->list,
+				&priv->wmm.tid_tbl_ptr[i].ra_list);
+
+		if (!priv->wmm.tid_tbl_ptr[i].ra_list_curr)
+			priv->wmm.tid_tbl_ptr[i].ra_list_curr = ra_list;
+	}
+}
+
+/*
+ * This function sets the WMM queue priorities to their default values.
+ */
+static void mwifiex_wmm_default_queue_priorities(struct mwifiex_private *priv)
+{
+	/* Default queue priorities: VO->VI->BE->BK */
+	priv->wmm.queue_priority[0] = WMM_AC_VO;
+	priv->wmm.queue_priority[1] = WMM_AC_VI;
+	priv->wmm.queue_priority[2] = WMM_AC_BE;
+	priv->wmm.queue_priority[3] = WMM_AC_BK;
+}
+
+/*
+ * This function map ACs to TIDs.
+ */
+static void
+mwifiex_wmm_queue_priorities_tid(struct mwifiex_private *priv,
+				 u8 queue_priority[])
+{
+	int i;
+
+	for (i = 0; i < 4; ++i) {
+		tos_to_tid[7 - (i * 2)] = ac_to_tid[queue_priority[i]][1];
+		tos_to_tid[6 - (i * 2)] = ac_to_tid[queue_priority[i]][0];
+	}
+}
+
+/*
+ * This function initializes WMM priority queues.
+ */
+void
+mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv,
+				   struct ieee_types_wmm_parameter *wmm_ie)
+{
+	u16 cw_min, avg_back_off, tmp[4];
+	u32 i, j, num_ac;
+	u8 ac_idx;
+
+	if (!wmm_ie || !priv->wmm_enabled) {
+		/* WMM is not enabled, just set the defaults and return */
+		mwifiex_wmm_default_queue_priorities(priv);
+		return;
+	}
+
+	dev_dbg(priv->adapter->dev, "info: WMM Parameter IE: version=%d, "
+		"qos_info Parameter Set Count=%d, Reserved=%#x\n",
+		wmm_ie->vend_hdr.version, wmm_ie->qos_info_bitmap &
+		IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK,
+		wmm_ie->reserved);
+
+	for (num_ac = 0; num_ac < ARRAY_SIZE(wmm_ie->ac_params); num_ac++) {
+		cw_min = (1 << (wmm_ie->ac_params[num_ac].ecw_bitmap &
+			MWIFIEX_ECW_MIN)) - 1;
+		avg_back_off = (cw_min >> 1) +
+			(wmm_ie->ac_params[num_ac].aci_aifsn_bitmap &
+			MWIFIEX_AIFSN);
+
+		ac_idx = wmm_aci_to_qidx_map[(wmm_ie->ac_params[num_ac].
+					     aci_aifsn_bitmap &
+					     MWIFIEX_ACI) >> 5];
+		priv->wmm.queue_priority[ac_idx] = ac_idx;
+		tmp[ac_idx] = avg_back_off;
+
+		dev_dbg(priv->adapter->dev, "info: WMM: CWmax=%d CWmin=%d Avg Back-off=%d\n",
+		       (1 << ((wmm_ie->ac_params[num_ac].ecw_bitmap &
+		       MWIFIEX_ECW_MAX) >> 4)) - 1,
+		       cw_min, avg_back_off);
+		mwifiex_wmm_ac_debug_print(&wmm_ie->ac_params[num_ac]);
+	}
+
+	/* Bubble sort */
+	for (i = 0; i < num_ac; i++) {
+		for (j = 1; j < num_ac - i; j++) {
+			if (tmp[j - 1] > tmp[j]) {
+				swap(tmp[j - 1], tmp[j]);
+				swap(priv->wmm.queue_priority[j - 1],
+				     priv->wmm.queue_priority[j]);
+			} else if (tmp[j - 1] == tmp[j]) {
+				if (priv->wmm.queue_priority[j - 1]
+				    < priv->wmm.queue_priority[j])
+					swap(priv->wmm.queue_priority[j - 1],
+					     priv->wmm.queue_priority[j]);
+			}
+		}
+	}
+
+	mwifiex_wmm_queue_priorities_tid(priv, priv->wmm.queue_priority);
+}
+
+/*
+ * This function evaluates whether or not an AC is to be downgraded.
+ *
+ * In case the AC is not enabled, the highest AC is returned that is
+ * enabled and does not require admission control.
+ */
+static enum mwifiex_wmm_ac_e
+mwifiex_wmm_eval_downgrade_ac(struct mwifiex_private *priv,
+			      enum mwifiex_wmm_ac_e eval_ac)
+{
+	int down_ac;
+	enum mwifiex_wmm_ac_e ret_ac;
+	struct mwifiex_wmm_ac_status *ac_status;
+
+	ac_status = &priv->wmm.ac_status[eval_ac];
+
+	if (!ac_status->disabled)
+		/* Okay to use this AC, its enabled */
+		return eval_ac;
+
+	/* Setup a default return value of the lowest priority */
+	ret_ac = WMM_AC_BK;
+
+	/*
+	 *  Find the highest AC that is enabled and does not require
+	 *  admission control. The spec disallows downgrading to an AC,
+	 *  which is enabled due to a completed admission control.
+	 *  Unadmitted traffic is not to be sent on an AC with admitted
+	 *  traffic.
+	 */
+	for (down_ac = WMM_AC_BK; down_ac < eval_ac; down_ac++) {
+		ac_status = &priv->wmm.ac_status[down_ac];
+
+		if (!ac_status->disabled && !ac_status->flow_required)
+			/* AC is enabled and does not require admission
+			   control */
+			ret_ac = (enum mwifiex_wmm_ac_e) down_ac;
+	}
+
+	return ret_ac;
+}
+
+/*
+ * This function downgrades WMM priority queue.
+ */
+void
+mwifiex_wmm_setup_ac_downgrade(struct mwifiex_private *priv)
+{
+	int ac_val;
+
+	dev_dbg(priv->adapter->dev, "info: WMM: AC Priorities:"
+			"BK(0), BE(1), VI(2), VO(3)\n");
+
+	if (!priv->wmm_enabled) {
+		/* WMM is not enabled, default priorities */
+		for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++)
+			priv->wmm.ac_down_graded_vals[ac_val] =
+				(enum mwifiex_wmm_ac_e) ac_val;
+	} else {
+		for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++) {
+			priv->wmm.ac_down_graded_vals[ac_val]
+				= mwifiex_wmm_eval_downgrade_ac(priv,
+						(enum mwifiex_wmm_ac_e) ac_val);
+			dev_dbg(priv->adapter->dev, "info: WMM: AC PRIO %d maps to %d\n",
+				ac_val, priv->wmm.ac_down_graded_vals[ac_val]);
+		}
+	}
+}
+
+/*
+ * This function converts the IP TOS field to an WMM AC
+ * Queue assignment.
+ */
+static enum mwifiex_wmm_ac_e
+mwifiex_wmm_convert_tos_to_ac(struct mwifiex_adapter *adapter, u32 tos)
+{
+	/* Map of TOS UP values to WMM AC */
+	const enum mwifiex_wmm_ac_e tos_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
+	};
+
+	if (tos >= ARRAY_SIZE(tos_to_ac))
+		return WMM_AC_BE;
+
+	return tos_to_ac[tos];
+}
+
+/*
+ * This function evaluates a given TID and downgrades it to a lower
+ * TID if the WMM Parameter IE received from the AP indicates that the
+ * AP is disabled (due to call admission control (ACM bit). Mapping
+ * of TID to AC is taken care of internally.
+ */
+static u8
+mwifiex_wmm_downgrade_tid(struct mwifiex_private *priv, u32 tid)
+{
+	enum mwifiex_wmm_ac_e ac, ac_down;
+	u8 new_tid;
+
+	ac = mwifiex_wmm_convert_tos_to_ac(priv->adapter, tid);
+	ac_down = priv->wmm.ac_down_graded_vals[ac];
+
+	/* Send the index to tid array, picking from the array will be
+	 * taken care by dequeuing function
+	 */
+	new_tid = ac_to_tid[ac_down][tid % 2];
+
+	return new_tid;
+}
+
+/*
+ * This function initializes the WMM state information and the
+ * WMM data path queues.
+ */
+void
+mwifiex_wmm_init(struct mwifiex_adapter *adapter)
+{
+	int i, j;
+	struct mwifiex_private *priv;
+
+	for (j = 0; j < adapter->priv_num; ++j) {
+		priv = adapter->priv[j];
+		if (!priv)
+			continue;
+
+		for (i = 0; i < MAX_NUM_TID; ++i) {
+			priv->aggr_prio_tbl[i].amsdu = tos_to_tid_inv[i];
+			priv->aggr_prio_tbl[i].ampdu_ap = tos_to_tid_inv[i];
+			priv->aggr_prio_tbl[i].ampdu_user = tos_to_tid_inv[i];
+			priv->wmm.tid_tbl_ptr[i].ra_list_curr = NULL;
+		}
+
+		priv->aggr_prio_tbl[6].amsdu
+			= priv->aggr_prio_tbl[6].ampdu_ap
+			= priv->aggr_prio_tbl[6].ampdu_user
+			= BA_STREAM_NOT_ALLOWED;
+
+		priv->aggr_prio_tbl[7].amsdu = priv->aggr_prio_tbl[7].ampdu_ap
+			= priv->aggr_prio_tbl[7].ampdu_user
+			= BA_STREAM_NOT_ALLOWED;
+
+		priv->add_ba_param.timeout = MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT;
+		priv->add_ba_param.tx_win_size = MWIFIEX_AMPDU_DEF_TXWINSIZE;
+		priv->add_ba_param.rx_win_size = MWIFIEX_AMPDU_DEF_RXWINSIZE;
+	}
+}
+
+/*
+ * This function checks if WMM Tx queue is empty.
+ */
+int
+mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter)
+{
+	int i, j;
+	struct mwifiex_private *priv;
+
+	for (j = 0; j < adapter->priv_num; ++j) {
+		priv = adapter->priv[j];
+		if (priv) {
+			for (i = 0; i < MAX_NUM_TID; i++)
+				if (!mwifiex_wmm_is_ra_list_empty(adapter,
+					     &priv->wmm.tid_tbl_ptr[i].ra_list))
+					return false;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * This function deletes all packets in an RA list node.
+ *
+ * The packet sent completion callback handler are called with
+ * status failure, after they are dequeued to ensure proper
+ * cleanup. The RA list node itself is freed at the end.
+ */
+static void
+mwifiex_wmm_del_pkts_in_ralist_node(struct mwifiex_private *priv,
+				    struct mwifiex_ra_list_tbl *ra_list)
+{
+	struct mwifiex_adapter *adapter = priv->adapter;
+	struct sk_buff *skb, *tmp;
+
+	skb_queue_walk_safe(&ra_list->skb_head, skb, tmp)
+		mwifiex_write_data_complete(adapter, skb, -1);
+}
+
+/*
+ * This function deletes all packets in an RA list.
+ *
+ * Each nodes in the RA list are freed individually first, and then
+ * the RA list itself is freed.
+ */
+static void
+mwifiex_wmm_del_pkts_in_ralist(struct mwifiex_private *priv,
+			       struct list_head *ra_list_head)
+{
+	struct mwifiex_ra_list_tbl *ra_list;
+
+	list_for_each_entry(ra_list, ra_list_head, list)
+		mwifiex_wmm_del_pkts_in_ralist_node(priv, ra_list);
+}
+
+/*
+ * This function deletes all packets in all RA lists.
+ */
+static void mwifiex_wmm_cleanup_queues(struct mwifiex_private *priv)
+{
+	int i;
+
+	for (i = 0; i < MAX_NUM_TID; i++)
+		mwifiex_wmm_del_pkts_in_ralist(priv, &priv->wmm.tid_tbl_ptr[i].
+						     ra_list);
+}
+
+/*
+ * This function deletes all route addresses from all RA lists.
+ */
+static void mwifiex_wmm_delete_all_ralist(struct mwifiex_private *priv)
+{
+	struct mwifiex_ra_list_tbl *ra_list, *tmp_node;
+	int i;
+
+	for (i = 0; i < MAX_NUM_TID; ++i) {
+		dev_dbg(priv->adapter->dev,
+				"info: ra_list: freeing buf for tid %d\n", i);
+		list_for_each_entry_safe(ra_list, tmp_node,
+				&priv->wmm.tid_tbl_ptr[i].ra_list, list) {
+			list_del(&ra_list->list);
+			kfree(ra_list);
+		}
+
+		INIT_LIST_HEAD(&priv->wmm.tid_tbl_ptr[i].ra_list);
+
+		priv->wmm.tid_tbl_ptr[i].ra_list_curr = NULL;
+	}
+}
+
+/*
+ * This function cleans up the Tx and Rx queues.
+ *
+ * Cleanup includes -
+ *      - All packets in RA lists
+ *      - All entries in Rx reorder table
+ *      - All entries in Tx BA stream table
+ *      - MPA buffer (if required)
+ *      - All RA lists
+ */
+void
+mwifiex_clean_txrx(struct mwifiex_private *priv)
+{
+	unsigned long flags;
+
+	mwifiex_11n_cleanup_reorder_tbl(priv);
+	spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
+
+	mwifiex_wmm_cleanup_queues(priv);
+	mwifiex_11n_delete_all_tx_ba_stream_tbl(priv);
+
+	if (priv->adapter->if_ops.cleanup_mpa_buf)
+		priv->adapter->if_ops.cleanup_mpa_buf(priv->adapter);
+
+	mwifiex_wmm_delete_all_ralist(priv);
+	memcpy(tos_to_tid, ac_to_tid, sizeof(tos_to_tid));
+
+	spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
+}
+
+/*
+ * This function retrieves a particular RA list node, matching with the
+ * given TID and RA address.
+ */
+static struct mwifiex_ra_list_tbl *
+mwifiex_wmm_get_ralist_node(struct mwifiex_private *priv, u8 tid,
+			    u8 *ra_addr)
+{
+	struct mwifiex_ra_list_tbl *ra_list;
+
+	list_for_each_entry(ra_list, &priv->wmm.tid_tbl_ptr[tid].ra_list,
+			    list) {
+		if (!memcmp(ra_list->ra, ra_addr, ETH_ALEN))
+			return ra_list;
+	}
+
+	return NULL;
+}
+
+/*
+ * This function retrieves an RA list node for a given TID and
+ * RA address pair.
+ *
+ * If no such node is found, a new node is added first and then
+ * retrieved.
+ */
+static struct mwifiex_ra_list_tbl *
+mwifiex_wmm_get_queue_raptr(struct mwifiex_private *priv, u8 tid, u8 *ra_addr)
+{
+	struct mwifiex_ra_list_tbl *ra_list;
+
+	ra_list = mwifiex_wmm_get_ralist_node(priv, tid, ra_addr);
+	if (ra_list)
+		return ra_list;
+	mwifiex_ralist_add(priv, ra_addr);
+
+	return mwifiex_wmm_get_ralist_node(priv, tid, ra_addr);
+}
+
+/*
+ * This function checks if a particular RA list node exists in a given TID
+ * table index.
+ */
+int
+mwifiex_is_ralist_valid(struct mwifiex_private *priv,
+			struct mwifiex_ra_list_tbl *ra_list, int ptr_index)
+{
+	struct mwifiex_ra_list_tbl *rlist;
+
+	list_for_each_entry(rlist, &priv->wmm.tid_tbl_ptr[ptr_index].ra_list,
+			    list) {
+		if (rlist == ra_list)
+			return true;
+	}
+
+	return false;
+}
+
+/*
+ * This function adds a packet to WMM queue.
+ *
+ * In disconnected state the packet is immediately dropped and the
+ * packet send completion callback is called with status failure.
+ *
+ * Otherwise, the correct RA list node is located and the packet
+ * is queued at the list tail.
+ */
+void
+mwifiex_wmm_add_buf_txqueue(struct mwifiex_adapter *adapter,
+			    struct sk_buff *skb)
+{
+	struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb);
+	struct mwifiex_private *priv = adapter->priv[tx_info->bss_index];
+	u32 tid;
+	struct mwifiex_ra_list_tbl *ra_list;
+	u8 ra[ETH_ALEN], tid_down;
+	unsigned long flags;
+
+	if (!priv->media_connected) {
+		dev_dbg(adapter->dev, "data: drop packet in disconnect\n");
+		mwifiex_write_data_complete(adapter, skb, -1);
+		return;
+	}
+
+	tid = skb->priority;
+
+	spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
+
+	tid_down = mwifiex_wmm_downgrade_tid(priv, tid);
+
+	/* In case of infra as we have already created the list during
+	   association we just don't have to call get_queue_raptr, we will
+	   have only 1 raptr for a tid in case of infra */
+	if (!mwifiex_queuing_ra_based(priv)) {
+		if (!list_empty(&priv->wmm.tid_tbl_ptr[tid_down].ra_list))
+			ra_list = list_first_entry(
+				&priv->wmm.tid_tbl_ptr[tid_down].ra_list,
+				struct mwifiex_ra_list_tbl, list);
+		else
+			ra_list = NULL;
+	} else {
+		memcpy(ra, skb->data, ETH_ALEN);
+		ra_list = mwifiex_wmm_get_queue_raptr(priv, tid_down, ra);
+	}
+
+	if (!ra_list) {
+		spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
+		mwifiex_write_data_complete(adapter, skb, -1);
+		return;
+	}
+
+	skb_queue_tail(&ra_list->skb_head, skb);
+
+	ra_list->total_pkts_size += skb->len;
+
+	spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
+}
+
+/*
+ * This function processes the get WMM status command response from firmware.
+ *
+ * The response may contain multiple TLVs -
+ *      - AC Queue status TLVs
+ *      - Current WMM Parameter IE TLV
+ *      - Admission Control action frame TLVs
+ *
+ * This function parses the TLVs and then calls further specific functions
+ * to process any changes in the queue prioritize or state.
+ */
+int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv,
+			       const struct host_cmd_ds_command *resp)
+{
+	u8 *curr = (u8 *) &resp->params.get_wmm_status;
+	uint16_t resp_len = le16_to_cpu(resp->size), tlv_len;
+	int valid = true;
+
+	struct mwifiex_ie_types_data *tlv_hdr;
+	struct mwifiex_ie_types_wmm_queue_status *tlv_wmm_qstatus;
+	struct ieee_types_wmm_parameter *wmm_param_ie = NULL;
+	struct mwifiex_wmm_ac_status *ac_status;
+
+	dev_dbg(priv->adapter->dev, "info: WMM: WMM_GET_STATUS cmdresp received: %d\n",
+			resp_len);
+
+	while ((resp_len >= sizeof(tlv_hdr->header)) && valid) {
+		tlv_hdr = (struct mwifiex_ie_types_data *) curr;
+		tlv_len = le16_to_cpu(tlv_hdr->header.len);
+
+		switch (le16_to_cpu(tlv_hdr->header.type)) {
+		case TLV_TYPE_WMMQSTATUS:
+			tlv_wmm_qstatus =
+				(struct mwifiex_ie_types_wmm_queue_status *)
+				tlv_hdr;
+			dev_dbg(priv->adapter->dev,
+				"info: CMD_RESP: WMM_GET_STATUS:"
+				" QSTATUS TLV: %d, %d, %d\n",
+			       tlv_wmm_qstatus->queue_index,
+			       tlv_wmm_qstatus->flow_required,
+			       tlv_wmm_qstatus->disabled);
+
+			ac_status = &priv->wmm.ac_status[tlv_wmm_qstatus->
+							 queue_index];
+			ac_status->disabled = tlv_wmm_qstatus->disabled;
+			ac_status->flow_required =
+				tlv_wmm_qstatus->flow_required;
+			ac_status->flow_created = tlv_wmm_qstatus->flow_created;
+			break;
+
+		case WLAN_EID_VENDOR_SPECIFIC:
+			/*
+			 * Point the regular IEEE IE 2 bytes into the Marvell IE
+			 *   and setup the IEEE IE type and length byte fields
+			 */
+
+			wmm_param_ie =
+				(struct ieee_types_wmm_parameter *) (curr +
+								    2);
+			wmm_param_ie->vend_hdr.len = (u8) tlv_len;
+			wmm_param_ie->vend_hdr.element_id =
+						WLAN_EID_VENDOR_SPECIFIC;
+
+			dev_dbg(priv->adapter->dev,
+				"info: CMD_RESP: WMM_GET_STATUS:"
+				" WMM Parameter Set Count: %d\n",
+				wmm_param_ie->qos_info_bitmap &
+				IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK);
+
+			memcpy((u8 *) &priv->curr_bss_params.bss_descriptor.
+			       wmm_ie, wmm_param_ie,
+			       wmm_param_ie->vend_hdr.len + 2);
+
+			break;
+
+		default:
+			valid = false;
+			break;
+		}
+
+		curr += (tlv_len + sizeof(tlv_hdr->header));
+		resp_len -= (tlv_len + sizeof(tlv_hdr->header));
+	}
+
+	mwifiex_wmm_setup_queue_priorities(priv, wmm_param_ie);
+	mwifiex_wmm_setup_ac_downgrade(priv);
+
+	return 0;
+}
+
+/*
+ * Callback handler from the command module to allow insertion of a WMM TLV.
+ *
+ * If the BSS we are associating to supports WMM, this function adds the
+ * required WMM Information IE to the association request command buffer in
+ * the form of a Marvell extended IEEE IE.
+ */
+u32
+mwifiex_wmm_process_association_req(struct mwifiex_private *priv,
+				    u8 **assoc_buf,
+				    struct ieee_types_wmm_parameter *wmm_ie,
+				    struct ieee80211_ht_cap *ht_cap)
+{
+	struct mwifiex_ie_types_wmm_param_set *wmm_tlv;
+	u32 ret_len = 0;
+
+	/* Null checks */
+	if (!assoc_buf)
+		return 0;
+	if (!(*assoc_buf))
+		return 0;
+
+	if (!wmm_ie)
+		return 0;
+
+	dev_dbg(priv->adapter->dev, "info: WMM: process assoc req:"
+			"bss->wmmIe=0x%x\n",
+			wmm_ie->vend_hdr.element_id);
+
+	if ((priv->wmm_required
+	     || (ht_cap && (priv->adapter->config_bands & BAND_GN
+		     || priv->adapter->config_bands & BAND_AN))
+	    )
+	    && wmm_ie->vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC) {
+		wmm_tlv = (struct mwifiex_ie_types_wmm_param_set *) *assoc_buf;
+		wmm_tlv->header.type = cpu_to_le16((u16) wmm_info_ie[0]);
+		wmm_tlv->header.len = cpu_to_le16((u16) wmm_info_ie[1]);
+		memcpy(wmm_tlv->wmm_ie, &wmm_info_ie[2],
+			le16_to_cpu(wmm_tlv->header.len));
+		if (wmm_ie->qos_info_bitmap & IEEE80211_WMM_IE_AP_QOSINFO_UAPSD)
+			memcpy((u8 *) (wmm_tlv->wmm_ie
+					+ le16_to_cpu(wmm_tlv->header.len)
+					 - sizeof(priv->wmm_qosinfo)),
+					&priv->wmm_qosinfo,
+					sizeof(priv->wmm_qosinfo));
+
+		ret_len = sizeof(wmm_tlv->header)
+			+ le16_to_cpu(wmm_tlv->header.len);
+
+		*assoc_buf += ret_len;
+	}
+
+	return ret_len;
+}
+
+/*
+ * This function computes the time delay in the driver queues for a
+ * given packet.
+ *
+ * When the packet is received at the OS/Driver interface, the current
+ * time is set in the packet structure. The difference between the present
+ * time and that received time is computed in this function and limited
+ * based on pre-compiled limits in the driver.
+ */
+u8
+mwifiex_wmm_compute_drv_pkt_delay(struct mwifiex_private *priv,
+					const struct sk_buff *skb)
+{
+	u8 ret_val = 0;
+	struct timeval out_tstamp, in_tstamp;
+	u32 queue_delay;
+
+	do_gettimeofday(&out_tstamp);
+	in_tstamp = ktime_to_timeval(skb->tstamp);
+
+	queue_delay = (out_tstamp.tv_sec - in_tstamp.tv_sec) * 1000;
+	queue_delay += (out_tstamp.tv_usec - in_tstamp.tv_usec) / 1000;
+
+	/*
+	 * Queue delay is passed as a uint8 in units of 2ms (ms shifted
+	 *  by 1). Min value (other than 0) is therefore 2ms, max is 510ms.
+	 *
+	 * Pass max value if queue_delay is beyond the uint8 range
+	 */
+	ret_val = (u8) (min(queue_delay, priv->wmm.drv_pkt_delay_max) >> 1);
+
+	dev_dbg(priv->adapter->dev, "data: WMM: Pkt Delay: %d ms,"
+				" %d ms sent to FW\n", queue_delay, ret_val);
+
+	return ret_val;
+}
+
+/*
+ * This function retrieves the highest priority RA list table pointer.
+ */
+static struct mwifiex_ra_list_tbl *
+mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
+				     struct mwifiex_private **priv, int *tid)
+{
+	struct mwifiex_private *priv_tmp;
+	struct mwifiex_ra_list_tbl *ptr, *head;
+	struct mwifiex_bss_prio_node *bssprio_node, *bssprio_head;
+	struct mwifiex_tid_tbl *tid_ptr;
+	int is_list_empty;
+	unsigned long flags;
+	int i, j;
+
+	for (j = adapter->priv_num - 1; j >= 0; --j) {
+		spin_lock_irqsave(&adapter->bss_prio_tbl[j].bss_prio_lock,
+				flags);
+		is_list_empty = list_empty(&adapter->bss_prio_tbl[j]
+				.bss_prio_head);
+		spin_unlock_irqrestore(&adapter->bss_prio_tbl[j].bss_prio_lock,
+				flags);
+		if (is_list_empty)
+			continue;
+
+		if (adapter->bss_prio_tbl[j].bss_prio_cur ==
+		    (struct mwifiex_bss_prio_node *)
+		    &adapter->bss_prio_tbl[j].bss_prio_head) {
+			bssprio_node =
+				list_first_entry(&adapter->bss_prio_tbl[j]
+						 .bss_prio_head,
+						 struct mwifiex_bss_prio_node,
+						 list);
+			bssprio_head = bssprio_node;
+		} else {
+			bssprio_node = adapter->bss_prio_tbl[j].bss_prio_cur;
+			bssprio_head = bssprio_node;
+		}
+
+		do {
+			priv_tmp = bssprio_node->priv;
+
+			for (i = HIGH_PRIO_TID; i >= LOW_PRIO_TID; --i) {
+
+				tid_ptr = &(priv_tmp)->wmm.
+					tid_tbl_ptr[tos_to_tid[i]];
+
+				spin_lock_irqsave(&tid_ptr->tid_tbl_lock,
+						  flags);
+				is_list_empty =
+					list_empty(&adapter->bss_prio_tbl[j]
+						   .bss_prio_head);
+				spin_unlock_irqrestore(&tid_ptr->tid_tbl_lock,
+						       flags);
+				if (is_list_empty)
+					continue;
+
+				/*
+				 * Always choose the next ra we transmitted
+				 * last time, this way we pick the ra's in
+				 * round robin fashion.
+				 */
+				ptr = list_first_entry(
+						&tid_ptr->ra_list_curr->list,
+						struct mwifiex_ra_list_tbl,
+						list);
+
+				head = ptr;
+				if (ptr == (struct mwifiex_ra_list_tbl *)
+						&tid_ptr->ra_list) {
+					/* Get next ra */
+					ptr = list_first_entry(&ptr->list,
+					    struct mwifiex_ra_list_tbl, list);
+					head = ptr;
+				}
+
+				do {
+					is_list_empty =
+						skb_queue_empty(&ptr->skb_head);
+					if (!is_list_empty) {
+						*priv = priv_tmp;
+						*tid = tos_to_tid[i];
+						return ptr;
+					}
+					/* Get next ra */
+					ptr = list_first_entry(&ptr->list,
+						 struct mwifiex_ra_list_tbl,
+						 list);
+					if (ptr ==
+					    (struct mwifiex_ra_list_tbl *)
+					    &tid_ptr->ra_list)
+						ptr = list_first_entry(
+						    &ptr->list,
+						    struct mwifiex_ra_list_tbl,
+						    list);
+				} while (ptr != head);
+			}
+
+			/* Get next bss priority node */
+			bssprio_node = list_first_entry(&bssprio_node->list,
+						struct mwifiex_bss_prio_node,
+						list);
+
+			if (bssprio_node ==
+			    (struct mwifiex_bss_prio_node *)
+			    &adapter->bss_prio_tbl[j].bss_prio_head)
+				/* Get next bss priority node */
+				bssprio_node = list_first_entry(
+						&bssprio_node->list,
+						struct mwifiex_bss_prio_node,
+						list);
+		} while (bssprio_node != bssprio_head);
+	}
+	return NULL;
+}
+
+/*
+ * This function gets the number of packets in the Tx queue of a
+ * particular RA list.
+ */
+static int
+mwifiex_num_pkts_in_txq(struct mwifiex_private *priv,
+			struct mwifiex_ra_list_tbl *ptr, int max_buf_size)
+{
+	int count = 0, total_size = 0;
+	struct sk_buff *skb, *tmp;
+
+	skb_queue_walk_safe(&ptr->skb_head, skb, tmp) {
+		total_size += skb->len;
+		if (total_size < max_buf_size)
+			++count;
+		else
+			break;
+	}
+
+	return count;
+}
+
+/*
+ * This function sends a single packet to firmware for transmission.
+ */
+static void
+mwifiex_send_single_packet(struct mwifiex_private *priv,
+			   struct mwifiex_ra_list_tbl *ptr, int ptr_index,
+			   unsigned long ra_list_flags)
+			   __releases(&priv->wmm.ra_list_spinlock)
+{
+	struct sk_buff *skb, *skb_next;
+	struct mwifiex_tx_param tx_param;
+	struct mwifiex_adapter *adapter = priv->adapter;
+	int status = 0;
+	struct mwifiex_txinfo *tx_info;
+
+	if (skb_queue_empty(&ptr->skb_head)) {
+		spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+				       ra_list_flags);
+		dev_dbg(adapter->dev, "data: nothing to send\n");
+		return;
+	}
+
+	skb = skb_dequeue(&ptr->skb_head);
+
+	tx_info = MWIFIEX_SKB_TXCB(skb);
+	dev_dbg(adapter->dev, "data: dequeuing the packet %p %p\n", ptr, skb);
+
+	ptr->total_pkts_size -= skb->len;
+
+	if (!skb_queue_empty(&ptr->skb_head))
+		skb_next = skb_peek(&ptr->skb_head);
+	else
+		skb_next = NULL;
+
+	spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags);
+
+	tx_param.next_pkt_len = ((skb_next) ? skb_next->len +
+				sizeof(struct txpd) : 0);
+
+	status = mwifiex_process_tx(priv, skb, &tx_param);
+
+	if (status == -EBUSY) {
+		/* Queue the packet back at the head */
+		spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
+
+		if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {
+			spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+					       ra_list_flags);
+			mwifiex_write_data_complete(adapter, skb, -1);
+			return;
+		}
+
+		skb_queue_tail(&ptr->skb_head, skb);
+
+		ptr->total_pkts_size += skb->len;
+		tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT;
+		spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+				       ra_list_flags);
+	} else {
+		spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
+		if (mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {
+			priv->wmm.packets_out[ptr_index]++;
+			priv->wmm.tid_tbl_ptr[ptr_index].ra_list_curr = ptr;
+		}
+		adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur =
+			list_first_entry(
+				&adapter->bss_prio_tbl[priv->bss_priority]
+				.bss_prio_cur->list,
+				struct mwifiex_bss_prio_node,
+				list);
+		spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+				       ra_list_flags);
+	}
+}
+
+/*
+ * This function checks if the first packet in the given RA list
+ * is already processed or not.
+ */
+static int
+mwifiex_is_ptr_processed(struct mwifiex_private *priv,
+			 struct mwifiex_ra_list_tbl *ptr)
+{
+	struct sk_buff *skb;
+	struct mwifiex_txinfo *tx_info;
+
+	if (skb_queue_empty(&ptr->skb_head))
+		return false;
+
+	skb = skb_peek(&ptr->skb_head);
+
+	tx_info = MWIFIEX_SKB_TXCB(skb);
+	if (tx_info->flags & MWIFIEX_BUF_FLAG_REQUEUED_PKT)
+		return true;
+
+	return false;
+}
+
+/*
+ * This function sends a single processed packet to firmware for
+ * transmission.
+ */
+static void
+mwifiex_send_processed_packet(struct mwifiex_private *priv,
+			      struct mwifiex_ra_list_tbl *ptr, int ptr_index,
+			      unsigned long ra_list_flags)
+				__releases(&priv->wmm.ra_list_spinlock)
+{
+	struct mwifiex_tx_param tx_param;
+	struct mwifiex_adapter *adapter = priv->adapter;
+	int ret = -1;
+	struct sk_buff *skb, *skb_next;
+	struct mwifiex_txinfo *tx_info;
+
+	if (skb_queue_empty(&ptr->skb_head)) {
+		spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+				       ra_list_flags);
+		return;
+	}
+
+	skb = skb_dequeue(&ptr->skb_head);
+
+	if (!skb_queue_empty(&ptr->skb_head))
+		skb_next = skb_peek(&ptr->skb_head);
+	else
+		skb_next = NULL;
+
+	tx_info = MWIFIEX_SKB_TXCB(skb);
+
+	spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags);
+	tx_param.next_pkt_len =
+		((skb_next) ? skb_next->len +
+		 sizeof(struct txpd) : 0);
+	ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
+					   skb->data, skb->len, &tx_param);
+	switch (ret) {
+	case -EBUSY:
+		dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
+		spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
+
+		if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {
+			spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+					       ra_list_flags);
+			mwifiex_write_data_complete(adapter, skb, -1);
+			return;
+		}
+
+		skb_queue_tail(&ptr->skb_head, skb);
+
+		tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT;
+		spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+				       ra_list_flags);
+		break;
+	case -1:
+		adapter->data_sent = false;
+		dev_err(adapter->dev, "host_to_card failed: %#x\n", ret);
+		adapter->dbg.num_tx_host_to_card_failure++;
+		mwifiex_write_data_complete(adapter, skb, ret);
+		break;
+	case -EINPROGRESS:
+		adapter->data_sent = false;
+	default:
+		break;
+	}
+	if (ret != -EBUSY) {
+		spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
+		if (mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {
+			priv->wmm.packets_out[ptr_index]++;
+			priv->wmm.tid_tbl_ptr[ptr_index].ra_list_curr = ptr;
+		}
+		adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur =
+			list_first_entry(
+				&adapter->bss_prio_tbl[priv->bss_priority]
+				.bss_prio_cur->list,
+				struct mwifiex_bss_prio_node,
+				list);
+		spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+				       ra_list_flags);
+	}
+}
+
+/*
+ * This function dequeues a packet from the highest priority list
+ * and transmits it.
+ */
+static int
+mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter)
+{
+	struct mwifiex_ra_list_tbl *ptr;
+	struct mwifiex_private *priv = NULL;
+	int ptr_index = 0;
+	u8 ra[ETH_ALEN];
+	int tid_del = 0, tid = 0;
+	unsigned long flags;
+
+	ptr = mwifiex_wmm_get_highest_priolist_ptr(adapter, &priv, &ptr_index);
+	if (!ptr)
+		return -1;
+
+	tid = mwifiex_get_tid(priv->adapter, ptr);
+
+	dev_dbg(adapter->dev, "data: tid=%d\n", tid);
+
+	spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
+	if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {
+		spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
+		return -1;
+	}
+
+	if (mwifiex_is_ptr_processed(priv, ptr)) {
+		mwifiex_send_processed_packet(priv, ptr, ptr_index, flags);
+		/* ra_list_spinlock has been freed in
+		   mwifiex_send_processed_packet() */
+		return 0;
+	}
+
+	if (!ptr->is_11n_enabled || mwifiex_is_ba_stream_setup(priv, ptr, tid)
+	    || ((priv->sec_info.wpa_enabled
+		  || priv->sec_info.wpa2_enabled) && !priv->wpa_is_gtk_set)
+		) {
+		mwifiex_send_single_packet(priv, ptr, ptr_index, flags);
+		/* ra_list_spinlock has been freed in
+		   mwifiex_send_single_packet() */
+	} else {
+		if (mwifiex_is_ampdu_allowed(priv, ptr, tid)) {
+			if (mwifiex_is_ba_stream_avail(priv)) {
+				mwifiex_11n_create_tx_ba_stream_tbl(priv,
+						ptr->ra, tid,
+						BA_STREAM_SETUP_INPROGRESS);
+				mwifiex_send_addba(priv, tid, ptr->ra);
+			} else if (mwifiex_find_stream_to_delete
+				   (priv, ptr, tid, &tid_del, ra)) {
+				mwifiex_11n_create_tx_ba_stream_tbl(priv,
+						ptr->ra, tid,
+						BA_STREAM_SETUP_INPROGRESS);
+				mwifiex_send_delba(priv, tid_del, ra, 1);
+			}
+		}
+/* Minimum number of AMSDU */
+#define MIN_NUM_AMSDU 2
+		if (mwifiex_is_amsdu_allowed(priv, ptr, tid) &&
+		    (mwifiex_num_pkts_in_txq(priv, ptr, adapter->tx_buf_size) >=
+		     MIN_NUM_AMSDU))
+			mwifiex_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN,
+						  ptr_index, flags);
+			/* ra_list_spinlock has been freed in
+			   mwifiex_11n_aggregate_pkt() */
+		else
+			mwifiex_send_single_packet(priv, ptr, ptr_index, flags);
+			/* ra_list_spinlock has been freed in
+			   mwifiex_send_single_packet() */
+	}
+	return 0;
+}
+
+/*
+ * This function transmits the highest priority packet awaiting in the
+ * WMM Queues.
+ */
+void
+mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter)
+{
+	do {
+		/* Check if busy */
+		if (adapter->data_sent || adapter->tx_lock_flag)
+			break;
+
+		if (mwifiex_dequeue_tx_packet(adapter))
+			break;
+	} while (true);
+
+	return;
+}
diff --git a/drivers/net/wireless/mwifiex/wmm.h b/drivers/net/wireless/mwifiex/wmm.h
new file mode 100644
index 0000000..241f1b0
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/wmm.h
@@ -0,0 +1,112 @@
+/*
+ * Marvell Wireless LAN device driver: WMM
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#ifndef _MWIFIEX_WMM_H_
+#define _MWIFIEX_WMM_H_
+
+enum ieee_types_wmm_aciaifsn_bitmasks {
+	MWIFIEX_AIFSN = (BIT(0) | BIT(1) | BIT(2) | BIT(3)),
+	MWIFIEX_ACM = BIT(4),
+	MWIFIEX_ACI = (BIT(5) | BIT(6)),
+};
+
+enum ieee_types_wmm_ecw_bitmasks {
+	MWIFIEX_ECW_MIN = (BIT(0) | BIT(1) | BIT(2) | BIT(3)),
+	MWIFIEX_ECW_MAX = (BIT(4) | BIT(5) | BIT(6) | BIT(7)),
+};
+
+/*
+ * This function retrieves the TID of the given RA list.
+ */
+static inline int
+mwifiex_get_tid(struct mwifiex_adapter *adapter,
+		struct mwifiex_ra_list_tbl *ptr)
+{
+	struct sk_buff *skb;
+
+	if (skb_queue_empty(&ptr->skb_head))
+		return 0;
+
+	skb = skb_peek(&ptr->skb_head);
+
+	return skb->priority;
+}
+
+/*
+ * This function gets the length of a list.
+ */
+static inline int
+mwifiex_wmm_list_len(struct mwifiex_adapter *adapter, struct list_head *head)
+{
+	struct list_head *pos;
+	int count = 0;
+
+	list_for_each(pos, head)
+		++count;
+
+	return count;
+}
+
+/*
+ * This function checks if a RA list is empty or not.
+ */
+static inline u8
+mwifiex_wmm_is_ra_list_empty(struct mwifiex_adapter *adapter,
+			     struct list_head *ra_list_hhead)
+{
+	struct mwifiex_ra_list_tbl *ra_list;
+	int is_list_empty;
+
+	list_for_each_entry(ra_list, ra_list_hhead, list) {
+		is_list_empty = skb_queue_empty(&ra_list->skb_head);
+		if (!is_list_empty)
+			return false;
+	}
+
+	return true;
+}
+
+void mwifiex_wmm_add_buf_txqueue(struct mwifiex_adapter *adapter,
+				 struct sk_buff *skb);
+void mwifiex_ralist_add(struct mwifiex_private *priv, u8 *ra);
+
+int mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter);
+void mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter);
+int mwifiex_is_ralist_valid(struct mwifiex_private *priv,
+			    struct mwifiex_ra_list_tbl *ra_list, int tid);
+
+u8 mwifiex_wmm_compute_drv_pkt_delay(struct mwifiex_private *priv,
+					     const struct sk_buff *skb);
+void mwifiex_wmm_init(struct mwifiex_adapter *adapter);
+
+extern u32 mwifiex_wmm_process_association_req(struct mwifiex_private *priv,
+						 u8 **assoc_buf,
+						 struct ieee_types_wmm_parameter
+						 *wmmie,
+						 struct ieee80211_ht_cap
+						 *htcap);
+
+void mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv,
+					struct ieee_types_wmm_parameter
+					*wmm_ie);
+void mwifiex_wmm_setup_ac_downgrade(struct mwifiex_private *priv);
+extern int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv,
+				      const struct host_cmd_ds_command *resp);
+
+#endif /* !_MWIFIEX_WMM_H_ */
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index c1ceb4b..8913180 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -63,6 +63,7 @@
 #define MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL	0x00000c38
 #define MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK	0x00000c3c
 #define  MWL8K_A2H_INT_DUMMY			 (1 << 20)
+#define  MWL8K_A2H_INT_BA_WATCHDOG		 (1 << 14)
 #define  MWL8K_A2H_INT_CHNL_SWITCHED		 (1 << 11)
 #define  MWL8K_A2H_INT_QUEUE_EMPTY		 (1 << 10)
 #define  MWL8K_A2H_INT_RADAR_DETECT		 (1 << 7)
@@ -82,10 +83,14 @@
 				 MWL8K_A2H_INT_MAC_EVENT | \
 				 MWL8K_A2H_INT_OPC_DONE | \
 				 MWL8K_A2H_INT_RX_READY | \
-				 MWL8K_A2H_INT_TX_DONE)
+				 MWL8K_A2H_INT_TX_DONE | \
+				 MWL8K_A2H_INT_BA_WATCHDOG)
 
 #define MWL8K_RX_QUEUES		1
-#define MWL8K_TX_QUEUES		4
+#define MWL8K_TX_WMM_QUEUES	4
+#define MWL8K_MAX_AMPDU_QUEUES	8
+#define MWL8K_MAX_TX_QUEUES	(MWL8K_TX_WMM_QUEUES + MWL8K_MAX_AMPDU_QUEUES)
+#define mwl8k_tx_queues(priv)	(MWL8K_TX_WMM_QUEUES + (priv)->num_ampdu_queues)
 
 struct rxd_ops {
 	int rxd_size;
@@ -134,6 +139,21 @@
 	struct sk_buff **skb;
 };
 
+enum {
+	AMPDU_NO_STREAM,
+	AMPDU_STREAM_NEW,
+	AMPDU_STREAM_IN_PROGRESS,
+	AMPDU_STREAM_ACTIVE,
+};
+
+struct mwl8k_ampdu_stream {
+	struct ieee80211_sta *sta;
+	u8 tid;
+	u8 state;
+	u8 idx;
+	u8 txq_idx; /* index of this stream in priv->txq */
+};
+
 struct mwl8k_priv {
 	struct ieee80211_hw *hw;
 	struct pci_dev *pdev;
@@ -160,6 +180,12 @@
 	u32 ap_macids_supported;
 	u32 sta_macids_supported;
 
+	/* Ampdu stream information */
+	u8 num_ampdu_queues;
+	spinlock_t stream_lock;
+	struct mwl8k_ampdu_stream ampdu[MWL8K_MAX_AMPDU_QUEUES];
+	struct work_struct watchdog_ba_handle;
+
 	/* firmware access */
 	struct mutex fw_mutex;
 	struct task_struct *fw_mutex_owner;
@@ -191,7 +217,8 @@
 	int pending_tx_pkts;
 
 	struct mwl8k_rx_queue rxq[MWL8K_RX_QUEUES];
-	struct mwl8k_tx_queue txq[MWL8K_TX_QUEUES];
+	struct mwl8k_tx_queue txq[MWL8K_MAX_TX_QUEUES];
+	u32 txq_offset[MWL8K_MAX_TX_QUEUES];
 
 	bool radio_on;
 	bool radio_short_preamble;
@@ -224,7 +251,7 @@
 	 * preserve the queue configurations so they can be restored if/when
 	 * the firmware image is swapped.
 	 */
-	struct ieee80211_tx_queue_params wmm_params[MWL8K_TX_QUEUES];
+	struct ieee80211_tx_queue_params wmm_params[MWL8K_TX_WMM_QUEUES];
 
 	/* async firmware loading state */
 	unsigned fw_state;
@@ -265,6 +292,7 @@
 struct mwl8k_sta {
 	/* Index into station database. Returned by UPDATE_STADB.  */
 	u8 peer_id;
+	u8 is_ampdu_allowed;
 };
 #define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv))
 
@@ -352,10 +380,12 @@
 #define MWL8K_CMD_ENABLE_SNIFFER	0x0150
 #define MWL8K_CMD_SET_MAC_ADDR		0x0202		/* per-vif */
 #define MWL8K_CMD_SET_RATEADAPT_MODE	0x0203
+#define MWL8K_CMD_GET_WATCHDOG_BITMAP	0x0205
 #define MWL8K_CMD_BSS_START		0x1100		/* per-vif */
 #define MWL8K_CMD_SET_NEW_STN		0x1111		/* per-vif */
 #define MWL8K_CMD_UPDATE_ENCRYPTION	0x1122		/* per-vif */
 #define MWL8K_CMD_UPDATE_STADB		0x1123
+#define MWL8K_CMD_BASTREAM		0x1125
 
 static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize)
 {
@@ -395,6 +425,8 @@
 		MWL8K_CMDNAME(SET_NEW_STN);
 		MWL8K_CMDNAME(UPDATE_ENCRYPTION);
 		MWL8K_CMDNAME(UPDATE_STADB);
+		MWL8K_CMDNAME(BASTREAM);
+		MWL8K_CMDNAME(GET_WATCHDOG_BITMAP);
 	default:
 		snprintf(buf, bufsize, "0x%x", cmd);
 	}
@@ -1127,6 +1159,9 @@
 	struct mwl8k_rx_queue *rxq = priv->rxq + index;
 	int i;
 
+	if (rxq->rxd == NULL)
+		return;
+
 	for (i = 0; i < MWL8K_RX_DESCS; i++) {
 		if (rxq->buf[i].skb != NULL) {
 			pci_unmap_single(priv->pdev,
@@ -1319,7 +1354,7 @@
 	__le16 pkt_len;
 	__u8 dest_MAC_addr[ETH_ALEN];
 	__le32 next_txd_phys_addr;
-	__le32 reserved;
+	__le32 timestamp;
 	__le16 rate_info;
 	__u8 peer_id;
 	__u8 tx_frag_cnt;
@@ -1383,7 +1418,7 @@
 	struct mwl8k_priv *priv = hw->priv;
 	int i;
 
-	for (i = 0; i < MWL8K_TX_QUEUES; i++) {
+	for (i = 0; i < mwl8k_tx_queues(priv); i++) {
 		struct mwl8k_tx_queue *txq = priv->txq + i;
 		int fw_owned = 0;
 		int drv_owned = 0;
@@ -1484,6 +1519,54 @@
 		     MWL8K_TXD_STATUS_OK_RETRY |		\
 		     MWL8K_TXD_STATUS_OK_MORE_RETRY))
 
+static int mwl8k_tid_queue_mapping(u8 tid)
+{
+	BUG_ON(tid > 7);
+
+	switch (tid) {
+	case 0:
+	case 3:
+		return IEEE80211_AC_BE;
+		break;
+	case 1:
+	case 2:
+		return IEEE80211_AC_BK;
+		break;
+	case 4:
+	case 5:
+		return IEEE80211_AC_VI;
+		break;
+	case 6:
+	case 7:
+		return IEEE80211_AC_VO;
+		break;
+	default:
+		return -1;
+		break;
+	}
+}
+
+/* The firmware will fill in the rate information
+ * for each packet that gets queued in the hardware
+ * in this structure
+ */
+
+struct rateinfo {
+	__le16  format:1;
+	__le16  short_gi:1;
+	__le16  band_width:1;
+	__le16  rate_id_mcs:6;
+	__le16  adv_coding:2;
+	__le16  antenna:2;
+	__le16  act_sub_chan:2;
+	__le16  preamble_type:1;
+	__le16  power_id:4;
+	__le16  antenna2:1;
+	__le16  reserved:1;
+	__le16  tx_bf_frame:1;
+	__le16  green_field:1;
+} __packed;
+
 static int
 mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force)
 {
@@ -1500,6 +1583,11 @@
 		struct sk_buff *skb;
 		struct ieee80211_tx_info *info;
 		u32 status;
+		struct ieee80211_sta *sta;
+		struct mwl8k_sta *sta_info = NULL;
+		u16 rate_info;
+		struct rateinfo *rate;
+		struct ieee80211_hdr *wh;
 
 		tx = txq->head;
 		tx_desc = txq->txd + tx;
@@ -1528,11 +1616,34 @@
 
 		mwl8k_remove_dma_header(skb, tx_desc->qos_control);
 
+		wh = (struct ieee80211_hdr *) skb->data;
+
 		/* Mark descriptor as unused */
 		tx_desc->pkt_phys_addr = 0;
 		tx_desc->pkt_len = 0;
 
 		info = IEEE80211_SKB_CB(skb);
+		if (ieee80211_is_data(wh->frame_control)) {
+			sta = info->control.sta;
+			if (sta) {
+				sta_info = MWL8K_STA(sta);
+				BUG_ON(sta_info == NULL);
+				rate_info = le16_to_cpu(tx_desc->rate_info);
+				rate = (struct rateinfo *)&rate_info;
+				/* If rate is < 6.5 Mpbs for an ht station
+				 * do not form an ampdu. If the station is a
+				 * legacy station (format = 0), do not form an
+				 * ampdu
+				 */
+				if (rate->rate_id_mcs < 1 ||
+				    rate->format == 0) {
+					sta_info->is_ampdu_allowed = false;
+				} else {
+					sta_info->is_ampdu_allowed = true;
+				}
+			}
+		}
+
 		ieee80211_tx_info_clear_status(info);
 
 		/* Rate control is happening in the firmware.
@@ -1549,7 +1660,8 @@
 		processed++;
 	}
 
-	if (processed && priv->radio_on && !mutex_is_locked(&priv->fw_mutex))
+	if (index < MWL8K_TX_WMM_QUEUES && processed && priv->radio_on &&
+	    !mutex_is_locked(&priv->fw_mutex))
 		ieee80211_wake_queue(hw, index);
 
 	return processed;
@@ -1561,6 +1673,9 @@
 	struct mwl8k_priv *priv = hw->priv;
 	struct mwl8k_tx_queue *txq = priv->txq + index;
 
+	if (txq->txd == NULL)
+		return;
+
 	mwl8k_txq_reclaim(hw, index, INT_MAX, 1);
 
 	kfree(txq->skb);
@@ -1572,12 +1687,81 @@
 	txq->txd = NULL;
 }
 
+/* caller must hold priv->stream_lock when calling the stream functions */
+struct mwl8k_ampdu_stream *
+mwl8k_add_stream(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u8 tid)
+{
+	struct mwl8k_ampdu_stream *stream;
+	struct mwl8k_priv *priv = hw->priv;
+	int i;
+
+	for (i = 0; i < priv->num_ampdu_queues; i++) {
+		stream = &priv->ampdu[i];
+		if (stream->state == AMPDU_NO_STREAM) {
+			stream->sta = sta;
+			stream->state = AMPDU_STREAM_NEW;
+			stream->tid = tid;
+			stream->idx = i;
+			stream->txq_idx = MWL8K_TX_WMM_QUEUES + i;
+			wiphy_debug(hw->wiphy, "Added a new stream for %pM %d",
+				    sta->addr, tid);
+			return stream;
+		}
+	}
+	return NULL;
+}
+
+static int
+mwl8k_start_stream(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream)
+{
+	int ret;
+
+	/* if the stream has already been started, don't start it again */
+	if (stream->state != AMPDU_STREAM_NEW)
+		return 0;
+	ret = ieee80211_start_tx_ba_session(stream->sta, stream->tid, 0);
+	if (ret)
+		wiphy_debug(hw->wiphy, "Failed to start stream for %pM %d: "
+			    "%d\n", stream->sta->addr, stream->tid, ret);
+	else
+		wiphy_debug(hw->wiphy, "Started stream for %pM %d\n",
+			    stream->sta->addr, stream->tid);
+	return ret;
+}
+
+static void
+mwl8k_remove_stream(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream)
+{
+	wiphy_debug(hw->wiphy, "Remove stream for %pM %d\n", stream->sta->addr,
+		    stream->tid);
+	memset(stream, 0, sizeof(*stream));
+}
+
+static struct mwl8k_ampdu_stream *
+mwl8k_lookup_stream(struct ieee80211_hw *hw, u8 *addr, u8 tid)
+{
+	struct mwl8k_priv *priv = hw->priv;
+	int i;
+
+	for (i = 0 ; i < priv->num_ampdu_queues; i++) {
+		struct mwl8k_ampdu_stream *stream;
+		stream = &priv->ampdu[i];
+		if (stream->state == AMPDU_NO_STREAM)
+			continue;
+		if (!memcmp(stream->sta->addr, addr, ETH_ALEN) &&
+		    stream->tid == tid)
+			return stream;
+	}
+	return NULL;
+}
+
 static void
 mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
 {
 	struct mwl8k_priv *priv = hw->priv;
 	struct ieee80211_tx_info *tx_info;
 	struct mwl8k_vif *mwl8k_vif;
+	struct ieee80211_sta *sta;
 	struct ieee80211_hdr *wh;
 	struct mwl8k_tx_queue *txq;
 	struct mwl8k_tx_desc *tx;
@@ -1585,6 +1769,11 @@
 	u32 txstatus;
 	u8 txdatarate;
 	u16 qos;
+	int txpriority;
+	u8 tid = 0;
+	struct mwl8k_ampdu_stream *stream = NULL;
+	bool start_ba_session = false;
+	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
 
 	wh = (struct ieee80211_hdr *)skb->data;
 	if (ieee80211_is_data_qos(wh->frame_control))
@@ -1600,6 +1789,7 @@
 	wh = &((struct mwl8k_dma_data *)skb->data)->wh;
 
 	tx_info = IEEE80211_SKB_CB(skb);
+	sta = tx_info->control.sta;
 	mwl8k_vif = MWL8K_VIF(tx_info->control.vif);
 
 	if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
@@ -1627,12 +1817,90 @@
 			qos |= MWL8K_QOS_ACK_POLICY_NORMAL;
 	}
 
+	/* Queue ADDBA request in the respective data queue.  While setting up
+	 * the ampdu stream, mac80211 queues further packets for that
+	 * particular ra/tid pair.  However, packets piled up in the hardware
+	 * for that ra/tid pair will still go out. ADDBA request and the
+	 * related data packets going out from different queues asynchronously
+	 * will cause a shift in the receiver window which might result in
+	 * ampdu packets getting dropped at the receiver after the stream has
+	 * been setup.
+	 */
+	if (unlikely(ieee80211_is_action(wh->frame_control) &&
+	    mgmt->u.action.category == WLAN_CATEGORY_BACK &&
+	    mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ &&
+	    priv->ap_fw)) {
+		u16 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
+		tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
+		index = mwl8k_tid_queue_mapping(tid);
+	}
+
+	txpriority = index;
+
+	if (ieee80211_is_data_qos(wh->frame_control) &&
+	    skb->protocol != cpu_to_be16(ETH_P_PAE) &&
+	    sta->ht_cap.ht_supported && priv->ap_fw) {
+		tid = qos & 0xf;
+		spin_lock(&priv->stream_lock);
+		stream = mwl8k_lookup_stream(hw, sta->addr, tid);
+		if (stream != NULL) {
+			if (stream->state == AMPDU_STREAM_ACTIVE) {
+				txpriority = stream->txq_idx;
+				index = stream->txq_idx;
+			} else if (stream->state == AMPDU_STREAM_NEW) {
+				/* We get here if the driver sends us packets
+				 * after we've initiated a stream, but before
+				 * our ampdu_action routine has been called
+				 * with IEEE80211_AMPDU_TX_START to get the SSN
+				 * for the ADDBA request.  So this packet can
+				 * go out with no risk of sequence number
+				 * mismatch.  No special handling is required.
+				 */
+			} else {
+				/* Drop packets that would go out after the
+				 * ADDBA request was sent but before the ADDBA
+				 * response is received.  If we don't do this,
+				 * the recipient would probably receive it
+				 * after the ADDBA request with SSN 0.  This
+				 * will cause the recipient's BA receive window
+				 * to shift, which would cause the subsequent
+				 * packets in the BA stream to be discarded.
+				 * mac80211 queues our packets for us in this
+				 * case, so this is really just a safety check.
+				 */
+				wiphy_warn(hw->wiphy,
+					   "Cannot send packet while ADDBA "
+					   "dialog is underway.\n");
+				spin_unlock(&priv->stream_lock);
+				dev_kfree_skb(skb);
+				return;
+			}
+		} else {
+			/* Defer calling mwl8k_start_stream so that the current
+			 * skb can go out before the ADDBA request.  This
+			 * prevents sequence number mismatch at the recepient
+			 * as described above.
+			 */
+			if (MWL8K_STA(sta)->is_ampdu_allowed) {
+				stream = mwl8k_add_stream(hw, sta, tid);
+				if (stream != NULL)
+					start_ba_session = true;
+			}
+		}
+		spin_unlock(&priv->stream_lock);
+	}
+
 	dma = pci_map_single(priv->pdev, skb->data,
 				skb->len, PCI_DMA_TODEVICE);
 
 	if (pci_dma_mapping_error(priv->pdev, dma)) {
 		wiphy_debug(hw->wiphy,
 			    "failed to dma map skb, dropping TX frame.\n");
+		if (start_ba_session) {
+			spin_lock(&priv->stream_lock);
+			mwl8k_remove_stream(hw, stream);
+			spin_unlock(&priv->stream_lock);
+		}
 		dev_kfree_skb(skb);
 		return;
 	}
@@ -1641,12 +1909,22 @@
 
 	txq = priv->txq + index;
 
+	if (index >= MWL8K_TX_WMM_QUEUES && txq->len >= MWL8K_TX_DESCS) {
+		/* This is the case in which the tx packet is destined for an
+		 * AMPDU queue and that AMPDU queue is full.  Because we don't
+		 * start and stop the AMPDU queues, we must drop these packets.
+		 */
+		dev_kfree_skb(skb);
+		spin_unlock_bh(&priv->tx_lock);
+		return;
+	}
+
 	BUG_ON(txq->skb[txq->tail] != NULL);
 	txq->skb[txq->tail] = skb;
 
 	tx = txq->txd + txq->tail;
 	tx->data_rate = txdatarate;
-	tx->tx_priority = index;
+	tx->tx_priority = txpriority;
 	tx->qos_control = cpu_to_le16(qos);
 	tx->pkt_phys_addr = cpu_to_le32(dma);
 	tx->pkt_len = cpu_to_le16(skb->len);
@@ -1665,12 +1943,20 @@
 	if (txq->tail == MWL8K_TX_DESCS)
 		txq->tail = 0;
 
-	if (txq->head == txq->tail)
+	if (txq->head == txq->tail && index < MWL8K_TX_WMM_QUEUES)
 		ieee80211_stop_queue(hw, index);
 
 	mwl8k_tx_start(priv);
 
 	spin_unlock_bh(&priv->tx_lock);
+
+	/* Initiate the ampdu session here */
+	if (start_ba_session) {
+		spin_lock(&priv->stream_lock);
+		if (mwl8k_start_stream(hw, stream))
+			mwl8k_remove_stream(hw, stream);
+		spin_unlock(&priv->stream_lock);
+	}
 }
 
 
@@ -1868,7 +2154,7 @@
 	__u8 mcs_bitmap[16];
 	__le32 rx_queue_ptr;
 	__le32 num_tx_queues;
-	__le32 tx_queue_ptrs[MWL8K_TX_QUEUES];
+	__le32 tx_queue_ptrs[MWL8K_TX_WMM_QUEUES];
 	__le32 caps2;
 	__le32 num_tx_desc_per_queue;
 	__le32 total_rxd;
@@ -1974,8 +2260,8 @@
 	memset(cmd->perm_addr, 0xff, sizeof(cmd->perm_addr));
 	cmd->ps_cookie = cpu_to_le32(priv->cookie_dma);
 	cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma);
-	cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES);
-	for (i = 0; i < MWL8K_TX_QUEUES; i++)
+	cmd->num_tx_queues = cpu_to_le32(mwl8k_tx_queues(priv));
+	for (i = 0; i < mwl8k_tx_queues(priv); i++)
 		cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].txd_dma);
 	cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS);
 	cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS);
@@ -2017,13 +2303,16 @@
 	__le32 wcbbase2;
 	__le32 wcbbase3;
 	__le32 fw_api_version;
+	__le32 caps;
+	__le32 num_of_ampdu_queues;
+	__le32 wcbbase_ampdu[MWL8K_MAX_AMPDU_QUEUES];
 } __packed;
 
 static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw)
 {
 	struct mwl8k_priv *priv = hw->priv;
 	struct mwl8k_cmd_get_hw_spec_ap *cmd;
-	int rc;
+	int rc, i;
 	u32 api_version;
 
 	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
@@ -2055,27 +2344,31 @@
 		priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs);
 		priv->fw_rev = le32_to_cpu(cmd->fw_rev);
 		priv->hw_rev = cmd->hw_rev;
-		mwl8k_setup_2ghz_band(hw);
+		mwl8k_set_caps(hw, le32_to_cpu(cmd->caps));
 		priv->ap_macids_supported = 0x000000ff;
 		priv->sta_macids_supported = 0x00000000;
-
-		off = le32_to_cpu(cmd->wcbbase0) & 0xffff;
-		iowrite32(priv->txq[0].txd_dma, priv->sram + off);
-
+		priv->num_ampdu_queues = le32_to_cpu(cmd->num_of_ampdu_queues);
+		if (priv->num_ampdu_queues > MWL8K_MAX_AMPDU_QUEUES) {
+			wiphy_warn(hw->wiphy, "fw reported %d ampdu queues"
+				   " but we only support %d.\n",
+				   priv->num_ampdu_queues,
+				   MWL8K_MAX_AMPDU_QUEUES);
+			priv->num_ampdu_queues = MWL8K_MAX_AMPDU_QUEUES;
+		}
 		off = le32_to_cpu(cmd->rxwrptr) & 0xffff;
 		iowrite32(priv->rxq[0].rxd_dma, priv->sram + off);
 
 		off = le32_to_cpu(cmd->rxrdptr) & 0xffff;
 		iowrite32(priv->rxq[0].rxd_dma, priv->sram + off);
 
-		off = le32_to_cpu(cmd->wcbbase1) & 0xffff;
-		iowrite32(priv->txq[1].txd_dma, priv->sram + off);
+		priv->txq_offset[0] = le32_to_cpu(cmd->wcbbase0) & 0xffff;
+		priv->txq_offset[1] = le32_to_cpu(cmd->wcbbase1) & 0xffff;
+		priv->txq_offset[2] = le32_to_cpu(cmd->wcbbase2) & 0xffff;
+		priv->txq_offset[3] = le32_to_cpu(cmd->wcbbase3) & 0xffff;
 
-		off = le32_to_cpu(cmd->wcbbase2) & 0xffff;
-		iowrite32(priv->txq[2].txd_dma, priv->sram + off);
-
-		off = le32_to_cpu(cmd->wcbbase3) & 0xffff;
-		iowrite32(priv->txq[3].txd_dma, priv->sram + off);
+		for (i = 0; i < priv->num_ampdu_queues; i++)
+			priv->txq_offset[i + MWL8K_TX_WMM_QUEUES] =
+				le32_to_cpu(cmd->wcbbase_ampdu[i]) & 0xffff;
 	}
 
 done:
@@ -2098,12 +2391,20 @@
 	__le32 caps;
 	__le32 rx_queue_ptr;
 	__le32 num_tx_queues;
-	__le32 tx_queue_ptrs[MWL8K_TX_QUEUES];
+	__le32 tx_queue_ptrs[MWL8K_MAX_TX_QUEUES];
 	__le32 flags;
 	__le32 num_tx_desc_per_queue;
 	__le32 total_rxd;
 } __packed;
 
+/* If enabled, MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY will cause
+ * packets to expire 500 ms after the timestamp in the tx descriptor.  That is,
+ * the packets that are queued for more than 500ms, will be dropped in the
+ * hardware. This helps minimizing the issues caused due to head-of-line
+ * blocking where a slow client can hog the bandwidth and affect traffic to a
+ * faster client.
+ */
+#define MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY	0x00000400
 #define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT		0x00000080
 #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP	0x00000020
 #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON		0x00000010
@@ -2124,7 +2425,7 @@
 
 	cmd->ps_cookie = cpu_to_le32(priv->cookie_dma);
 	cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma);
-	cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES);
+	cmd->num_tx_queues = cpu_to_le32(mwl8k_tx_queues(priv));
 
 	/*
 	 * Mac80211 stack has Q0 as highest priority and Q3 as lowest in
@@ -2132,8 +2433,8 @@
 	 * in that order. Map Q3 of mac80211 to Q0 of firmware so that the
 	 * priority is interpreted the right way in firmware.
 	 */
-	for (i = 0; i < MWL8K_TX_QUEUES; i++) {
-		int j = MWL8K_TX_QUEUES - 1 - i;
+	for (i = 0; i < mwl8k_tx_queues(priv); i++) {
+		int j = mwl8k_tx_queues(priv) - 1 - i;
 		cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[j].txd_dma);
 	}
 
@@ -3123,6 +3424,65 @@
 }
 
 /*
+ * CMD_GET_WATCHDOG_BITMAP.
+ */
+struct mwl8k_cmd_get_watchdog_bitmap {
+	struct mwl8k_cmd_pkt header;
+	u8	bitmap;
+} __packed;
+
+static int mwl8k_cmd_get_watchdog_bitmap(struct ieee80211_hw *hw, u8 *bitmap)
+{
+	struct mwl8k_cmd_get_watchdog_bitmap *cmd;
+	int rc;
+
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	if (cmd == NULL)
+		return -ENOMEM;
+
+	cmd->header.code = cpu_to_le16(MWL8K_CMD_GET_WATCHDOG_BITMAP);
+	cmd->header.length = cpu_to_le16(sizeof(*cmd));
+
+	rc = mwl8k_post_cmd(hw, &cmd->header);
+	if (!rc)
+		*bitmap = cmd->bitmap;
+
+	kfree(cmd);
+
+	return rc;
+}
+
+#define INVALID_BA	0xAA
+static void mwl8k_watchdog_ba_events(struct work_struct *work)
+{
+	int rc;
+	u8 bitmap = 0, stream_index;
+	struct mwl8k_ampdu_stream *streams;
+	struct mwl8k_priv *priv =
+		container_of(work, struct mwl8k_priv, watchdog_ba_handle);
+
+	rc = mwl8k_cmd_get_watchdog_bitmap(priv->hw, &bitmap);
+	if (rc)
+		return;
+
+	if (bitmap == INVALID_BA)
+		return;
+
+	/* the bitmap is the hw queue number.  Map it to the ampdu queue. */
+	stream_index = bitmap - MWL8K_TX_WMM_QUEUES;
+
+	BUG_ON(stream_index >= priv->num_ampdu_queues);
+
+	streams = &priv->ampdu[stream_index];
+
+	if (streams->state == AMPDU_STREAM_ACTIVE)
+		ieee80211_stop_tx_ba_session(streams->sta, streams->tid);
+
+	return;
+}
+
+
+/*
  * CMD_BSS_START.
  */
 struct mwl8k_cmd_bss_start {
@@ -3151,6 +3511,152 @@
 }
 
 /*
+ * CMD_BASTREAM.
+ */
+
+/*
+ * UPSTREAM is tx direction
+ */
+#define BASTREAM_FLAG_DIRECTION_UPSTREAM	0x00
+#define BASTREAM_FLAG_IMMEDIATE_TYPE		0x01
+
+enum {
+	MWL8K_BA_CREATE,
+	MWL8K_BA_UPDATE,
+	MWL8K_BA_DESTROY,
+	MWL8K_BA_FLUSH,
+	MWL8K_BA_CHECK,
+} ba_stream_action_type;
+
+
+struct mwl8k_create_ba_stream {
+	__le32	flags;
+	__le32	idle_thrs;
+	__le32	bar_thrs;
+	__le32	window_size;
+	u8	peer_mac_addr[6];
+	u8	dialog_token;
+	u8	tid;
+	u8	queue_id;
+	u8	param_info;
+	__le32	ba_context;
+	u8	reset_seq_no_flag;
+	__le16	curr_seq_no;
+	u8	sta_src_mac_addr[6];
+} __packed;
+
+struct mwl8k_destroy_ba_stream {
+	__le32	flags;
+	__le32	ba_context;
+} __packed;
+
+struct mwl8k_cmd_bastream {
+	struct mwl8k_cmd_pkt	header;
+	__le32	action;
+	union {
+		struct mwl8k_create_ba_stream	create_params;
+		struct mwl8k_destroy_ba_stream	destroy_params;
+	};
+} __packed;
+
+static int
+mwl8k_check_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream)
+{
+	struct mwl8k_cmd_bastream *cmd;
+	int rc;
+
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	if (cmd == NULL)
+		return -ENOMEM;
+
+	cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM);
+	cmd->header.length = cpu_to_le16(sizeof(*cmd));
+
+	cmd->action = cpu_to_le32(MWL8K_BA_CHECK);
+
+	cmd->create_params.queue_id = stream->idx;
+	memcpy(&cmd->create_params.peer_mac_addr[0], stream->sta->addr,
+	       ETH_ALEN);
+	cmd->create_params.tid = stream->tid;
+
+	cmd->create_params.flags =
+		cpu_to_le32(BASTREAM_FLAG_IMMEDIATE_TYPE) |
+		cpu_to_le32(BASTREAM_FLAG_DIRECTION_UPSTREAM);
+
+	rc = mwl8k_post_cmd(hw, &cmd->header);
+
+	kfree(cmd);
+
+	return rc;
+}
+
+static int
+mwl8k_create_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream,
+		u8 buf_size)
+{
+	struct mwl8k_cmd_bastream *cmd;
+	int rc;
+
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	if (cmd == NULL)
+		return -ENOMEM;
+
+
+	cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM);
+	cmd->header.length = cpu_to_le16(sizeof(*cmd));
+
+	cmd->action = cpu_to_le32(MWL8K_BA_CREATE);
+
+	cmd->create_params.bar_thrs = cpu_to_le32((u32)buf_size);
+	cmd->create_params.window_size = cpu_to_le32((u32)buf_size);
+	cmd->create_params.queue_id = stream->idx;
+
+	memcpy(cmd->create_params.peer_mac_addr, stream->sta->addr, ETH_ALEN);
+	cmd->create_params.tid = stream->tid;
+	cmd->create_params.curr_seq_no = cpu_to_le16(0);
+	cmd->create_params.reset_seq_no_flag = 1;
+
+	cmd->create_params.param_info =
+		(stream->sta->ht_cap.ampdu_factor &
+		 IEEE80211_HT_AMPDU_PARM_FACTOR) |
+		((stream->sta->ht_cap.ampdu_density << 2) &
+		 IEEE80211_HT_AMPDU_PARM_DENSITY);
+
+	cmd->create_params.flags =
+		cpu_to_le32(BASTREAM_FLAG_IMMEDIATE_TYPE |
+					BASTREAM_FLAG_DIRECTION_UPSTREAM);
+
+	rc = mwl8k_post_cmd(hw, &cmd->header);
+
+	wiphy_debug(hw->wiphy, "Created a BA stream for %pM : tid %d\n",
+		stream->sta->addr, stream->tid);
+	kfree(cmd);
+
+	return rc;
+}
+
+static void mwl8k_destroy_ba(struct ieee80211_hw *hw,
+			     struct mwl8k_ampdu_stream *stream)
+{
+	struct mwl8k_cmd_bastream *cmd;
+
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	if (cmd == NULL)
+		return;
+
+	cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM);
+	cmd->header.length = cpu_to_le16(sizeof(*cmd));
+	cmd->action = cpu_to_le32(MWL8K_BA_DESTROY);
+
+	cmd->destroy_params.ba_context = cpu_to_le32(stream->idx);
+	mwl8k_post_cmd(hw, &cmd->header);
+
+	wiphy_debug(hw->wiphy, "Deleted BA stream index %d\n", stream->idx);
+
+	kfree(cmd);
+}
+
+/*
  * CMD_SET_NEW_STN.
  */
 struct mwl8k_cmd_set_new_stn {
@@ -3671,6 +4177,11 @@
 		tasklet_schedule(&priv->poll_rx_task);
 	}
 
+	if (status & MWL8K_A2H_INT_BA_WATCHDOG) {
+		status &= ~MWL8K_A2H_INT_BA_WATCHDOG;
+		ieee80211_queue_work(hw, &priv->watchdog_ba_handle);
+	}
+
 	if (status)
 		iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
 
@@ -3699,7 +4210,7 @@
 
 	spin_lock_bh(&priv->tx_lock);
 
-	for (i = 0; i < MWL8K_TX_QUEUES; i++)
+	for (i = 0; i < mwl8k_tx_queues(priv); i++)
 		limit -= mwl8k_txq_reclaim(hw, i, limit, 0);
 
 	if (!priv->pending_tx_pkts && priv->tx_wait != NULL) {
@@ -3829,6 +4340,7 @@
 
 	/* Stop finalize join worker */
 	cancel_work_sync(&priv->finalize_join_worker);
+	cancel_work_sync(&priv->watchdog_ba_handle);
 	if (priv->beacon_skb != NULL)
 		dev_kfree_skb(priv->beacon_skb);
 
@@ -3837,7 +4349,7 @@
 	tasklet_disable(&priv->poll_rx_task);
 
 	/* Return all skbs to mac80211 */
-	for (i = 0; i < MWL8K_TX_QUEUES; i++)
+	for (i = 0; i < mwl8k_tx_queues(priv); i++)
 		mwl8k_txq_reclaim(hw, i, INT_MAX, 1);
 }
 
@@ -3958,9 +4470,12 @@
 		conf->power_level = 18;
 
 	if (priv->ap_fw) {
-		rc = mwl8k_cmd_tx_power(hw, conf, conf->power_level);
-		if (rc)
-			goto out;
+
+		if (conf->flags & IEEE80211_CONF_CHANGE_POWER) {
+			rc = mwl8k_cmd_tx_power(hw, conf, conf->power_level);
+			if (rc)
+				goto out;
+		}
 
 		rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_RX, 0x3);
 		if (rc)
@@ -4312,6 +4827,8 @@
 		ret = mwl8k_cmd_update_stadb_add(hw, vif, sta);
 		if (ret >= 0) {
 			MWL8K_STA(sta)->peer_id = ret;
+			if (sta->ht_cap.ht_supported)
+				MWL8K_STA(sta)->is_ampdu_allowed = true;
 			ret = 0;
 		}
 
@@ -4335,14 +4852,14 @@
 
 	rc = mwl8k_fw_lock(hw);
 	if (!rc) {
-		BUG_ON(queue > MWL8K_TX_QUEUES - 1);
+		BUG_ON(queue > MWL8K_TX_WMM_QUEUES - 1);
 		memcpy(&priv->wmm_params[queue], params, sizeof(*params));
 
 		if (!priv->wmm_enabled)
 			rc = mwl8k_cmd_set_wmm_mode(hw, 1);
 
 		if (!rc) {
-			int q = MWL8K_TX_QUEUES - 1 - queue;
+			int q = MWL8K_TX_WMM_QUEUES - 1 - queue;
 			rc = mwl8k_cmd_set_edca_params(hw, q,
 						       params->cw_min,
 						       params->cw_max,
@@ -4378,21 +4895,118 @@
 	return 0;
 }
 
+#define MAX_AMPDU_ATTEMPTS 5
+
 static int
 mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 		   enum ieee80211_ampdu_mlme_action action,
 		   struct ieee80211_sta *sta, u16 tid, u16 *ssn,
 		   u8 buf_size)
 {
+
+	int i, rc = 0;
+	struct mwl8k_priv *priv = hw->priv;
+	struct mwl8k_ampdu_stream *stream;
+	u8 *addr = sta->addr;
+
+	if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION))
+		return -ENOTSUPP;
+
+	spin_lock(&priv->stream_lock);
+	stream = mwl8k_lookup_stream(hw, addr, tid);
+
 	switch (action) {
 	case IEEE80211_AMPDU_RX_START:
 	case IEEE80211_AMPDU_RX_STOP:
-		if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION))
-			return -ENOTSUPP;
-		return 0;
+		break;
+	case IEEE80211_AMPDU_TX_START:
+		/* By the time we get here the hw queues may contain outgoing
+		 * packets for this RA/TID that are not part of this BA
+		 * session.  The hw will assign sequence numbers to these
+		 * packets as they go out.  So if we query the hw for its next
+		 * sequence number and use that for the SSN here, it may end up
+		 * being wrong, which will lead to sequence number mismatch at
+		 * the recipient.  To avoid this, we reset the sequence number
+		 * to O for the first MPDU in this BA stream.
+		 */
+		*ssn = 0;
+		if (stream == NULL) {
+			/* This means that somebody outside this driver called
+			 * ieee80211_start_tx_ba_session.  This is unexpected
+			 * because we do our own rate control.  Just warn and
+			 * move on.
+			 */
+			wiphy_warn(hw->wiphy, "Unexpected call to %s.  "
+				   "Proceeding anyway.\n", __func__);
+			stream = mwl8k_add_stream(hw, sta, tid);
+		}
+		if (stream == NULL) {
+			wiphy_debug(hw->wiphy, "no free AMPDU streams\n");
+			rc = -EBUSY;
+			break;
+		}
+		stream->state = AMPDU_STREAM_IN_PROGRESS;
+
+		/* Release the lock before we do the time consuming stuff */
+		spin_unlock(&priv->stream_lock);
+		for (i = 0; i < MAX_AMPDU_ATTEMPTS; i++) {
+			rc = mwl8k_check_ba(hw, stream);
+
+			if (!rc)
+				break;
+			/*
+			 * HW queues take time to be flushed, give them
+			 * sufficient time
+			 */
+
+			msleep(1000);
+		}
+		spin_lock(&priv->stream_lock);
+		if (rc) {
+			wiphy_err(hw->wiphy, "Stream for tid %d busy after %d"
+				" attempts\n", tid, MAX_AMPDU_ATTEMPTS);
+			mwl8k_remove_stream(hw, stream);
+			rc = -EBUSY;
+			break;
+		}
+		ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid);
+		break;
+	case IEEE80211_AMPDU_TX_STOP:
+		if (stream == NULL)
+			break;
+		if (stream->state == AMPDU_STREAM_ACTIVE) {
+			spin_unlock(&priv->stream_lock);
+			mwl8k_destroy_ba(hw, stream);
+			spin_lock(&priv->stream_lock);
+		}
+		mwl8k_remove_stream(hw, stream);
+		ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid);
+		break;
+	case IEEE80211_AMPDU_TX_OPERATIONAL:
+		BUG_ON(stream == NULL);
+		BUG_ON(stream->state != AMPDU_STREAM_IN_PROGRESS);
+		spin_unlock(&priv->stream_lock);
+		rc = mwl8k_create_ba(hw, stream, buf_size);
+		spin_lock(&priv->stream_lock);
+		if (!rc)
+			stream->state = AMPDU_STREAM_ACTIVE;
+		else {
+			spin_unlock(&priv->stream_lock);
+			mwl8k_destroy_ba(hw, stream);
+			spin_lock(&priv->stream_lock);
+			wiphy_debug(hw->wiphy,
+				"Failed adding stream for sta %pM tid %d\n",
+				addr, tid);
+			mwl8k_remove_stream(hw, stream);
+		}
+		break;
+
 	default:
-		return -ENOTSUPP;
+		rc = -ENOTSUPP;
 	}
+
+	spin_unlock(&priv->stream_lock);
+	return rc;
 }
 
 static const struct ieee80211_ops mwl8k_ops = {
@@ -4441,7 +5055,7 @@
 	MWL8366,
 };
 
-#define MWL8K_8366_AP_FW_API 1
+#define MWL8K_8366_AP_FW_API 2
 #define _MWL8K_8366_AP_FW(api) "mwl8k/fmimage_8366_ap-" #api ".fw"
 #define MWL8K_8366_AP_FW(api) _MWL8K_8366_AP_FW(api)
 
@@ -4607,6 +5221,23 @@
 	return rc;
 }
 
+static int mwl8k_init_txqs(struct ieee80211_hw *hw)
+{
+	struct mwl8k_priv *priv = hw->priv;
+	int rc = 0;
+	int i;
+
+	for (i = 0; i < mwl8k_tx_queues(priv); i++) {
+		rc = mwl8k_txq_init(hw, i);
+		if (rc)
+			break;
+		if (priv->ap_fw)
+			iowrite32(priv->txq[i].txd_dma,
+				  priv->sram + priv->txq_offset[i]);
+	}
+	return rc;
+}
+
 /* initialize hw after successfully loading a firmware image */
 static int mwl8k_probe_hw(struct ieee80211_hw *hw)
 {
@@ -4634,15 +5265,23 @@
 		goto err_stop_firmware;
 	rxq_refill(hw, 0, INT_MAX);
 
-	for (i = 0; i < MWL8K_TX_QUEUES; i++) {
-		rc = mwl8k_txq_init(hw, i);
+	/* For the sta firmware, we need to know the dma addresses of tx queues
+	 * before sending MWL8K_CMD_GET_HW_SPEC.  So we must initialize them
+	 * prior to issuing this command.  But for the AP case, we learn the
+	 * total number of queues from the result CMD_GET_HW_SPEC, so for this
+	 * case we must initialize the tx queues after.
+	 */
+	priv->num_ampdu_queues = 0;
+	if (!priv->ap_fw) {
+		rc = mwl8k_init_txqs(hw);
 		if (rc)
 			goto err_free_queues;
 	}
 
 	iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
 	iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
-	iowrite32(MWL8K_A2H_INT_TX_DONE | MWL8K_A2H_INT_RX_READY,
+	iowrite32(MWL8K_A2H_INT_TX_DONE|MWL8K_A2H_INT_RX_READY|
+		  MWL8K_A2H_INT_BA_WATCHDOG,
 		  priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL);
 	iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK);
 
@@ -4653,6 +5292,8 @@
 		goto err_free_queues;
 	}
 
+	memset(priv->ampdu, 0, sizeof(priv->ampdu));
+
 	/*
 	 * Temporarily enable interrupts.  Initial firmware host
 	 * commands use interrupts and avoid polling.  Disable
@@ -4664,6 +5305,8 @@
 	if (priv->ap_fw) {
 		rc = mwl8k_cmd_get_hw_spec_ap(hw);
 		if (!rc)
+			rc = mwl8k_init_txqs(hw);
+		if (!rc)
 			rc = mwl8k_cmd_set_hw_spec(hw);
 	} else {
 		rc = mwl8k_cmd_get_hw_spec_sta(hw);
@@ -4705,7 +5348,7 @@
 	free_irq(priv->pdev->irq, hw);
 
 err_free_queues:
-	for (i = 0; i < MWL8K_TX_QUEUES; i++)
+	for (i = 0; i < mwl8k_tx_queues(priv); i++)
 		mwl8k_txq_deinit(hw, i);
 	mwl8k_rxq_deinit(hw, 0);
 
@@ -4727,7 +5370,7 @@
 	mwl8k_stop(hw);
 	mwl8k_rxq_deinit(hw, 0);
 
-	for (i = 0; i < MWL8K_TX_QUEUES; i++)
+	for (i = 0; i < mwl8k_tx_queues(priv); i++)
 		mwl8k_txq_deinit(hw, i);
 
 	rc = mwl8k_init_firmware(hw, fw_image, false);
@@ -4746,7 +5389,7 @@
 	if (rc)
 		goto fail;
 
-	for (i = 0; i < MWL8K_TX_QUEUES; i++) {
+	for (i = 0; i < MWL8K_TX_WMM_QUEUES; i++) {
 		rc = mwl8k_conf_tx(hw, i, &priv->wmm_params[i]);
 		if (rc)
 			goto fail;
@@ -4780,7 +5423,7 @@
 
 	hw->channel_change_time = 10;
 
-	hw->queues = MWL8K_TX_QUEUES;
+	hw->queues = MWL8K_TX_WMM_QUEUES;
 
 	/* Set rssi values to dBm */
 	hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_HAS_RATE_CONTROL;
@@ -4796,6 +5439,8 @@
 
 	/* Finalize join worker */
 	INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker);
+	/* Handle watchdog ba events */
+	INIT_WORK(&priv->watchdog_ba_handle, mwl8k_watchdog_ba_events);
 
 	/* TX reclaim and RX tasklets.  */
 	tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw);
@@ -4815,6 +5460,8 @@
 
 	spin_lock_init(&priv->tx_lock);
 
+	spin_lock_init(&priv->stream_lock);
+
 	priv->tx_wait = NULL;
 
 	rc = mwl8k_probe_hw(hw);
@@ -4836,7 +5483,7 @@
 	return 0;
 
 err_unprobe_hw:
-	for (i = 0; i < MWL8K_TX_QUEUES; i++)
+	for (i = 0; i < mwl8k_tx_queues(priv); i++)
 		mwl8k_txq_deinit(hw, i);
 	mwl8k_rxq_deinit(hw, 0);
 
@@ -4995,10 +5642,10 @@
 	mwl8k_hw_reset(priv);
 
 	/* Return all skbs to mac80211 */
-	for (i = 0; i < MWL8K_TX_QUEUES; i++)
+	for (i = 0; i < mwl8k_tx_queues(priv); i++)
 		mwl8k_txq_reclaim(hw, i, INT_MAX, 1);
 
-	for (i = 0; i < MWL8K_TX_QUEUES; i++)
+	for (i = 0; i < mwl8k_tx_queues(priv); i++)
 		mwl8k_txq_deinit(hw, i);
 
 	mwl8k_rxq_deinit(hw, 0);
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 329f328..137a24e 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -1368,8 +1368,10 @@
 static void rt2400pci_rxdone_tasklet(unsigned long data)
 {
 	struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
-	rt2x00pci_rxdone(rt2x00dev);
-	rt2400pci_enable_interrupt(rt2x00dev, CSR8_RXDONE);
+	if (rt2x00pci_rxdone(rt2x00dev))
+		tasklet_schedule(&rt2x00dev->rxdone_tasklet);
+	else
+		rt2400pci_enable_interrupt(rt2x00dev, CSR8_RXDONE);
 }
 
 static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance)
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 5827787..198fc0a 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -1500,8 +1500,10 @@
 static void rt2500pci_rxdone_tasklet(unsigned long data)
 {
 	struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
-	rt2x00pci_rxdone(rt2x00dev);
-	rt2500pci_enable_interrupt(rt2x00dev, CSR8_RXDONE);
+	if (rt2x00pci_rxdone(rt2x00dev))
+		tasklet_schedule(&rt2x00dev->rxdone_tasklet);
+	else
+		rt2500pci_enable_interrupt(rt2x00dev, CSR8_RXDONE);
 }
 
 static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance)
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 979fe65..eac7881 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -1796,7 +1796,6 @@
 		__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
 		__set_bit(DRIVER_REQUIRE_COPY_IV, &rt2x00dev->flags);
 	}
-	__set_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags);
 	__set_bit(DRIVER_REQUIRE_SW_SEQNO, &rt2x00dev->flags);
 
 	/*
@@ -1910,13 +1909,10 @@
 	/* Belkin */
 	{ USB_DEVICE(0x050d, 0x7050), USB_DEVICE_DATA(&rt2500usb_ops) },
 	{ USB_DEVICE(0x050d, 0x7051), USB_DEVICE_DATA(&rt2500usb_ops) },
-	{ USB_DEVICE(0x050d, 0x705a), USB_DEVICE_DATA(&rt2500usb_ops) },
 	/* Cisco Systems */
 	{ USB_DEVICE(0x13b1, 0x000d), USB_DEVICE_DATA(&rt2500usb_ops) },
 	{ USB_DEVICE(0x13b1, 0x0011), USB_DEVICE_DATA(&rt2500usb_ops) },
 	{ USB_DEVICE(0x13b1, 0x001a), USB_DEVICE_DATA(&rt2500usb_ops) },
-	/* CNet */
-	{ USB_DEVICE(0x1371, 0x9022), USB_DEVICE_DATA(&rt2500usb_ops) },
 	/* Conceptronic */
 	{ USB_DEVICE(0x14b2, 0x3c02), USB_DEVICE_DATA(&rt2500usb_ops) },
 	/* D-LINK */
@@ -1939,7 +1935,6 @@
 	/* Ralink */
 	{ USB_DEVICE(0x148f, 0x1706), USB_DEVICE_DATA(&rt2500usb_ops) },
 	{ USB_DEVICE(0x148f, 0x2570), USB_DEVICE_DATA(&rt2500usb_ops) },
-	{ USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt2500usb_ops) },
 	{ USB_DEVICE(0x148f, 0x9020), USB_DEVICE_DATA(&rt2500usb_ops) },
 	/* Sagem */
 	{ USB_DEVICE(0x079b, 0x004b), USB_DEVICE_DATA(&rt2500usb_ops) },
diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
index 70b9abb..3b3d851 100644
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -2104,6 +2104,59 @@
 #define EEPROM_TXPOWER_BG_2		FIELD16(0xff00)
 
 /*
+ * EEPROM temperature compensation boundaries 802.11BG
+ * MINUS4: If the actual TSSI is below this boundary, tx power needs to be
+ *         reduced by (agc_step * -4)
+ * MINUS3: If the actual TSSI is below this boundary, tx power needs to be
+ *         reduced by (agc_step * -3)
+ */
+#define EEPROM_TSSI_BOUND_BG1		0x0037
+#define EEPROM_TSSI_BOUND_BG1_MINUS4	FIELD16(0x00ff)
+#define EEPROM_TSSI_BOUND_BG1_MINUS3	FIELD16(0xff00)
+
+/*
+ * EEPROM temperature compensation boundaries 802.11BG
+ * MINUS2: If the actual TSSI is below this boundary, tx power needs to be
+ *         reduced by (agc_step * -2)
+ * MINUS1: If the actual TSSI is below this boundary, tx power needs to be
+ *         reduced by (agc_step * -1)
+ */
+#define EEPROM_TSSI_BOUND_BG2		0x0038
+#define EEPROM_TSSI_BOUND_BG2_MINUS2	FIELD16(0x00ff)
+#define EEPROM_TSSI_BOUND_BG2_MINUS1	FIELD16(0xff00)
+
+/*
+ * EEPROM temperature compensation boundaries 802.11BG
+ * REF: Reference TSSI value, no tx power changes needed
+ * PLUS1: If the actual TSSI is above this boundary, tx power needs to be
+ *        increased by (agc_step * 1)
+ */
+#define EEPROM_TSSI_BOUND_BG3		0x0039
+#define EEPROM_TSSI_BOUND_BG3_REF	FIELD16(0x00ff)
+#define EEPROM_TSSI_BOUND_BG3_PLUS1	FIELD16(0xff00)
+
+/*
+ * EEPROM temperature compensation boundaries 802.11BG
+ * PLUS2: If the actual TSSI is above this boundary, tx power needs to be
+ *        increased by (agc_step * 2)
+ * PLUS3: If the actual TSSI is above this boundary, tx power needs to be
+ *        increased by (agc_step * 3)
+ */
+#define EEPROM_TSSI_BOUND_BG4		0x003a
+#define EEPROM_TSSI_BOUND_BG4_PLUS2	FIELD16(0x00ff)
+#define EEPROM_TSSI_BOUND_BG4_PLUS3	FIELD16(0xff00)
+
+/*
+ * EEPROM temperature compensation boundaries 802.11BG
+ * PLUS4: If the actual TSSI is above this boundary, tx power needs to be
+ *        increased by (agc_step * 4)
+ * AGC_STEP: Temperature compensation step.
+ */
+#define EEPROM_TSSI_BOUND_BG5		0x003b
+#define EEPROM_TSSI_BOUND_BG5_PLUS4	FIELD16(0x00ff)
+#define EEPROM_TSSI_BOUND_BG5_AGC_STEP	FIELD16(0xff00)
+
+/*
  * EEPROM TXPOWER 802.11A
  */
 #define EEPROM_TXPOWER_A1		0x003c
@@ -2113,6 +2166,59 @@
 #define EEPROM_TXPOWER_A_2		FIELD16(0xff00)
 
 /*
+ * EEPROM temperature compensation boundaries 802.11A
+ * MINUS4: If the actual TSSI is below this boundary, tx power needs to be
+ *         reduced by (agc_step * -4)
+ * MINUS3: If the actual TSSI is below this boundary, tx power needs to be
+ *         reduced by (agc_step * -3)
+ */
+#define EEPROM_TSSI_BOUND_A1		0x006a
+#define EEPROM_TSSI_BOUND_A1_MINUS4	FIELD16(0x00ff)
+#define EEPROM_TSSI_BOUND_A1_MINUS3	FIELD16(0xff00)
+
+/*
+ * EEPROM temperature compensation boundaries 802.11A
+ * MINUS2: If the actual TSSI is below this boundary, tx power needs to be
+ *         reduced by (agc_step * -2)
+ * MINUS1: If the actual TSSI is below this boundary, tx power needs to be
+ *         reduced by (agc_step * -1)
+ */
+#define EEPROM_TSSI_BOUND_A2		0x006b
+#define EEPROM_TSSI_BOUND_A2_MINUS2	FIELD16(0x00ff)
+#define EEPROM_TSSI_BOUND_A2_MINUS1	FIELD16(0xff00)
+
+/*
+ * EEPROM temperature compensation boundaries 802.11A
+ * REF: Reference TSSI value, no tx power changes needed
+ * PLUS1: If the actual TSSI is above this boundary, tx power needs to be
+ *        increased by (agc_step * 1)
+ */
+#define EEPROM_TSSI_BOUND_A3		0x006c
+#define EEPROM_TSSI_BOUND_A3_REF	FIELD16(0x00ff)
+#define EEPROM_TSSI_BOUND_A3_PLUS1	FIELD16(0xff00)
+
+/*
+ * EEPROM temperature compensation boundaries 802.11A
+ * PLUS2: If the actual TSSI is above this boundary, tx power needs to be
+ *        increased by (agc_step * 2)
+ * PLUS3: If the actual TSSI is above this boundary, tx power needs to be
+ *        increased by (agc_step * 3)
+ */
+#define EEPROM_TSSI_BOUND_A4		0x006d
+#define EEPROM_TSSI_BOUND_A4_PLUS2	FIELD16(0x00ff)
+#define EEPROM_TSSI_BOUND_A4_PLUS3	FIELD16(0xff00)
+
+/*
+ * EEPROM temperature compensation boundaries 802.11A
+ * PLUS4: If the actual TSSI is above this boundary, tx power needs to be
+ *        increased by (agc_step * 4)
+ * AGC_STEP: Temperature compensation step.
+ */
+#define EEPROM_TSSI_BOUND_A5		0x006e
+#define EEPROM_TSSI_BOUND_A5_PLUS4	FIELD16(0x00ff)
+#define EEPROM_TSSI_BOUND_A5_AGC_STEP	FIELD16(0xff00)
+
+/*
  * EEPROM TXPOWER by rate: tx power per tx rate for HT20 mode
  */
 #define EEPROM_TXPOWER_BYRATE		0x006f
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 2ee6ceb..769c05c 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -687,6 +687,9 @@
 		mcs = real_mcs;
 	}
 
+	if (aggr == 1 || ampdu == 1)
+		__set_bit(TXDONE_AMPDU, &txdesc.flags);
+
 	/*
 	 * Ralink has a retry mechanism using a global fallback
 	 * table. We setup this fallback table to try the immediate
@@ -1813,17 +1816,131 @@
 	rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC, &reg);
 }
 
+static int rt2800_get_gain_calibration_delta(struct rt2x00_dev *rt2x00dev)
+{
+	u8 tssi_bounds[9];
+	u8 current_tssi;
+	u16 eeprom;
+	u8 step;
+	int i;
+
+	/*
+	 * Read TSSI boundaries for temperature compensation from
+	 * the EEPROM.
+	 *
+	 * Array idx               0    1    2    3    4    5    6    7    8
+	 * Matching Delta value   -4   -3   -2   -1    0   +1   +2   +3   +4
+	 * Example TSSI bounds  0xF0 0xD0 0xB5 0xA0 0x88 0x45 0x25 0x15 0x00
+	 */
+	if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) {
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG1, &eeprom);
+		tssi_bounds[0] = rt2x00_get_field16(eeprom,
+					EEPROM_TSSI_BOUND_BG1_MINUS4);
+		tssi_bounds[1] = rt2x00_get_field16(eeprom,
+					EEPROM_TSSI_BOUND_BG1_MINUS3);
+
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG2, &eeprom);
+		tssi_bounds[2] = rt2x00_get_field16(eeprom,
+					EEPROM_TSSI_BOUND_BG2_MINUS2);
+		tssi_bounds[3] = rt2x00_get_field16(eeprom,
+					EEPROM_TSSI_BOUND_BG2_MINUS1);
+
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG3, &eeprom);
+		tssi_bounds[4] = rt2x00_get_field16(eeprom,
+					EEPROM_TSSI_BOUND_BG3_REF);
+		tssi_bounds[5] = rt2x00_get_field16(eeprom,
+					EEPROM_TSSI_BOUND_BG3_PLUS1);
+
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG4, &eeprom);
+		tssi_bounds[6] = rt2x00_get_field16(eeprom,
+					EEPROM_TSSI_BOUND_BG4_PLUS2);
+		tssi_bounds[7] = rt2x00_get_field16(eeprom,
+					EEPROM_TSSI_BOUND_BG4_PLUS3);
+
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG5, &eeprom);
+		tssi_bounds[8] = rt2x00_get_field16(eeprom,
+					EEPROM_TSSI_BOUND_BG5_PLUS4);
+
+		step = rt2x00_get_field16(eeprom,
+					  EEPROM_TSSI_BOUND_BG5_AGC_STEP);
+	} else {
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A1, &eeprom);
+		tssi_bounds[0] = rt2x00_get_field16(eeprom,
+					EEPROM_TSSI_BOUND_A1_MINUS4);
+		tssi_bounds[1] = rt2x00_get_field16(eeprom,
+					EEPROM_TSSI_BOUND_A1_MINUS3);
+
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A2, &eeprom);
+		tssi_bounds[2] = rt2x00_get_field16(eeprom,
+					EEPROM_TSSI_BOUND_A2_MINUS2);
+		tssi_bounds[3] = rt2x00_get_field16(eeprom,
+					EEPROM_TSSI_BOUND_A2_MINUS1);
+
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A3, &eeprom);
+		tssi_bounds[4] = rt2x00_get_field16(eeprom,
+					EEPROM_TSSI_BOUND_A3_REF);
+		tssi_bounds[5] = rt2x00_get_field16(eeprom,
+					EEPROM_TSSI_BOUND_A3_PLUS1);
+
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A4, &eeprom);
+		tssi_bounds[6] = rt2x00_get_field16(eeprom,
+					EEPROM_TSSI_BOUND_A4_PLUS2);
+		tssi_bounds[7] = rt2x00_get_field16(eeprom,
+					EEPROM_TSSI_BOUND_A4_PLUS3);
+
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A5, &eeprom);
+		tssi_bounds[8] = rt2x00_get_field16(eeprom,
+					EEPROM_TSSI_BOUND_A5_PLUS4);
+
+		step = rt2x00_get_field16(eeprom,
+					  EEPROM_TSSI_BOUND_A5_AGC_STEP);
+	}
+
+	/*
+	 * Check if temperature compensation is supported.
+	 */
+	if (tssi_bounds[4] == 0xff)
+		return 0;
+
+	/*
+	 * Read current TSSI (BBP 49).
+	 */
+	rt2800_bbp_read(rt2x00dev, 49, &current_tssi);
+
+	/*
+	 * Compare TSSI value (BBP49) with the compensation boundaries
+	 * from the EEPROM and increase or decrease tx power.
+	 */
+	for (i = 0; i <= 3; i++) {
+		if (current_tssi > tssi_bounds[i])
+			break;
+	}
+
+	if (i == 4) {
+		for (i = 8; i >= 5; i--) {
+			if (current_tssi < tssi_bounds[i])
+				break;
+		}
+	}
+
+	return (i - 4) * step;
+}
+
 static int rt2800_get_txpower_bw_comp(struct rt2x00_dev *rt2x00dev,
 				      enum ieee80211_band band)
 {
 	u16 eeprom;
 	u8 comp_en;
 	u8 comp_type;
-	int comp_value;
+	int comp_value = 0;
 
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_TXPOWER_DELTA, &eeprom);
 
-	if (eeprom == 0xffff)
+	/*
+	 * HT40 compensation not required.
+	 */
+	if (eeprom == 0xffff ||
+	    !test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags))
 		return 0;
 
 	if (band == IEEE80211_BAND_2GHZ) {
@@ -1853,11 +1970,9 @@
 	return comp_value;
 }
 
-static u8 rt2800_compesate_txpower(struct rt2x00_dev *rt2x00dev,
-				     int is_rate_b,
-				     enum ieee80211_band band,
-				     int power_level,
-				     u8 txpower)
+static u8 rt2800_compensate_txpower(struct rt2x00_dev *rt2x00dev, int is_rate_b,
+				   enum ieee80211_band band, int power_level,
+				   u8 txpower, int delta)
 {
 	u32 reg;
 	u16 eeprom;
@@ -1865,14 +1980,10 @@
 	u8 eirp_txpower;
 	u8 eirp_txpower_criterion;
 	u8 reg_limit;
-	int bw_comp = 0;
 
 	if (!((band == IEEE80211_BAND_5GHZ) && is_rate_b))
 		return txpower;
 
-	if (test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags))
-		bw_comp = rt2800_get_txpower_bw_comp(rt2x00dev, band);
-
 	if (test_bit(CONFIG_SUPPORT_POWER_LIMIT, &rt2x00dev->flags)) {
 		/*
 		 * Check if eirp txpower exceed txpower_limit.
@@ -1895,18 +2006,19 @@
 						 EEPROM_EIRP_MAX_TX_POWER_5GHZ);
 
 		eirp_txpower = eirp_txpower_criterion + (txpower - criterion) +
-				       (is_rate_b ? 4 : 0) + bw_comp;
+			       (is_rate_b ? 4 : 0) + delta;
 
 		reg_limit = (eirp_txpower > power_level) ?
 					(eirp_txpower - power_level) : 0;
 	} else
 		reg_limit = 0;
 
-	return txpower + bw_comp - reg_limit;
+	return txpower + delta - reg_limit;
 }
 
 static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
-				  struct ieee80211_conf *conf)
+				  enum ieee80211_band band,
+				  int power_level)
 {
 	u8 txpower;
 	u16 eeprom;
@@ -1914,8 +2026,17 @@
 	u32 reg;
 	u8 r1;
 	u32 offset;
-	enum ieee80211_band band = conf->channel->band;
-	int power_level = conf->power_level;
+	int delta;
+
+	/*
+	 * Calculate HT40 compensation delta
+	 */
+	delta = rt2800_get_txpower_bw_comp(rt2x00dev, band);
+
+	/*
+	 * calculate temperature compensation delta
+	 */
+	delta += rt2800_get_gain_calibration_delta(rt2x00dev);
 
 	/*
 	 * set to normal bbp tx power control mode: +/- 0dBm
@@ -1944,8 +2065,8 @@
 		 */
 		txpower = rt2x00_get_field16(eeprom,
 					     EEPROM_TXPOWER_BYRATE_RATE0);
-		txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band,
-					     power_level, txpower);
+		txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band,
+					     power_level, txpower, delta);
 		rt2x00_set_field32(&reg, TX_PWR_CFG_RATE0, txpower);
 
 		/*
@@ -1955,8 +2076,8 @@
 		 */
 		txpower = rt2x00_get_field16(eeprom,
 					     EEPROM_TXPOWER_BYRATE_RATE1);
-		txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band,
-					     power_level, txpower);
+		txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band,
+					     power_level, txpower, delta);
 		rt2x00_set_field32(&reg, TX_PWR_CFG_RATE1, txpower);
 
 		/*
@@ -1966,8 +2087,8 @@
 		 */
 		txpower = rt2x00_get_field16(eeprom,
 					     EEPROM_TXPOWER_BYRATE_RATE2);
-		txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band,
-					     power_level, txpower);
+		txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band,
+					     power_level, txpower, delta);
 		rt2x00_set_field32(&reg, TX_PWR_CFG_RATE2, txpower);
 
 		/*
@@ -1977,8 +2098,8 @@
 		 */
 		txpower = rt2x00_get_field16(eeprom,
 					     EEPROM_TXPOWER_BYRATE_RATE3);
-		txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band,
-					     power_level, txpower);
+		txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band,
+					     power_level, txpower, delta);
 		rt2x00_set_field32(&reg, TX_PWR_CFG_RATE3, txpower);
 
 		/* read the next four txpower values */
@@ -1993,8 +2114,8 @@
 		 */
 		txpower = rt2x00_get_field16(eeprom,
 					     EEPROM_TXPOWER_BYRATE_RATE0);
-		txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band,
-					     power_level, txpower);
+		txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band,
+					     power_level, txpower, delta);
 		rt2x00_set_field32(&reg, TX_PWR_CFG_RATE4, txpower);
 
 		/*
@@ -2004,8 +2125,8 @@
 		 */
 		txpower = rt2x00_get_field16(eeprom,
 					     EEPROM_TXPOWER_BYRATE_RATE1);
-		txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band,
-					     power_level, txpower);
+		txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band,
+					     power_level, txpower, delta);
 		rt2x00_set_field32(&reg, TX_PWR_CFG_RATE5, txpower);
 
 		/*
@@ -2015,8 +2136,8 @@
 		 */
 		txpower = rt2x00_get_field16(eeprom,
 					     EEPROM_TXPOWER_BYRATE_RATE2);
-		txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band,
-					     power_level, txpower);
+		txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band,
+					     power_level, txpower, delta);
 		rt2x00_set_field32(&reg, TX_PWR_CFG_RATE6, txpower);
 
 		/*
@@ -2026,8 +2147,8 @@
 		 */
 		txpower = rt2x00_get_field16(eeprom,
 					     EEPROM_TXPOWER_BYRATE_RATE3);
-		txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band,
-					     power_level, txpower);
+		txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band,
+					     power_level, txpower, delta);
 		rt2x00_set_field32(&reg, TX_PWR_CFG_RATE7, txpower);
 
 		rt2800_register_write(rt2x00dev, offset, reg);
@@ -2037,6 +2158,13 @@
 	}
 }
 
+void rt2800_gain_calibration(struct rt2x00_dev *rt2x00dev)
+{
+	rt2800_config_txpower(rt2x00dev, rt2x00dev->curr_band,
+			      rt2x00dev->tx_power);
+}
+EXPORT_SYMBOL_GPL(rt2800_gain_calibration);
+
 static void rt2800_config_retry_limit(struct rt2x00_dev *rt2x00dev,
 				      struct rt2x00lib_conf *libconf)
 {
@@ -2090,10 +2218,12 @@
 	if (flags & IEEE80211_CONF_CHANGE_CHANNEL) {
 		rt2800_config_channel(rt2x00dev, libconf->conf,
 				      &libconf->rf, &libconf->channel);
-		rt2800_config_txpower(rt2x00dev, libconf->conf);
+		rt2800_config_txpower(rt2x00dev, libconf->conf->channel->band,
+				      libconf->conf->power_level);
 	}
 	if (flags & IEEE80211_CONF_CHANGE_POWER)
-		rt2800_config_txpower(rt2x00dev, libconf->conf);
+		rt2800_config_txpower(rt2x00dev, libconf->conf->channel->band,
+				      libconf->conf->power_level);
 	if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
 		rt2800_config_retry_limit(rt2x00dev, libconf);
 	if (flags & IEEE80211_CONF_CHANGE_PS)
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h
index 0c92d86..f2d1594 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/rt2x00/rt2800lib.h
@@ -181,6 +181,7 @@
 void rt2800_reset_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual);
 void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual,
 		       const u32 count);
+void rt2800_gain_calibration(struct rt2x00_dev *rt2x00dev);
 
 int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev);
 void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev);
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index 808073a..adc3534 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -717,12 +717,13 @@
 	rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS);
 }
 
-static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
+static bool rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
 {
 	struct data_queue *queue;
 	struct queue_entry *entry;
 	u32 status;
 	u8 qid;
+	int max_tx_done = 16;
 
 	while (kfifo_get(&rt2x00dev->txstatus_fifo, &status)) {
 		qid = rt2x00_get_field32(status, TX_STA_FIFO_PID_QUEUE);
@@ -759,7 +760,12 @@
 
 		entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
 		rt2800_txdone_entry(entry, status);
+
+		if (--max_tx_done == 0)
+			break;
 	}
+
+	return !max_tx_done;
 }
 
 static void rt2800pci_enable_interrupt(struct rt2x00_dev *rt2x00dev,
@@ -780,7 +786,9 @@
 
 static void rt2800pci_txstatus_tasklet(unsigned long data)
 {
-	rt2800pci_txdone((struct rt2x00_dev *)data);
+	struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
+	if (rt2800pci_txdone(rt2x00dev))
+		tasklet_schedule(&rt2x00dev->txstatus_tasklet);
 
 	/*
 	 * No need to enable the tx status interrupt here as we always
@@ -806,8 +814,10 @@
 static void rt2800pci_rxdone_tasklet(unsigned long data)
 {
 	struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
-	rt2x00pci_rxdone(rt2x00dev);
-	rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RX_DONE);
+	if (rt2x00pci_rxdone(rt2x00dev))
+		tasklet_schedule(&rt2x00dev->rxdone_tasklet);
+	else
+		rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RX_DONE);
 }
 
 static void rt2800pci_autowake_tasklet(unsigned long data)
@@ -1043,6 +1053,7 @@
 	.link_stats		= rt2800_link_stats,
 	.reset_tuner		= rt2800_reset_tuner,
 	.link_tuner		= rt2800_link_tuner,
+	.gain_calibration	= rt2800_gain_calibration,
 	.start_queue		= rt2800pci_start_queue,
 	.kick_queue		= rt2800pci_kick_queue,
 	.stop_queue		= rt2800pci_stop_queue,
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 37509d0..6ba31a0 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -564,7 +564,6 @@
 	if (!modparam_nohwcrypt)
 		__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
 	__set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
-	__set_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags);
 	__set_bit(DRIVER_REQUIRE_HT_TX_DESC, &rt2x00dev->flags);
 
 	/*
@@ -630,6 +629,7 @@
 	.link_stats		= rt2800_link_stats,
 	.reset_tuner		= rt2800_reset_tuner,
 	.link_tuner		= rt2800_link_tuner,
+	.gain_calibration	= rt2800_gain_calibration,
 	.watchdog		= rt2800usb_watchdog,
 	.start_queue		= rt2800usb_start_queue,
 	.kick_queue		= rt2x00usb_kick_queue,
@@ -882,6 +882,7 @@
 	{ USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) },
 	/* Zyxel */
 	{ USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x0586, 0x3418), USB_DEVICE_DATA(&rt2800usb_ops) },
 #ifdef CONFIG_RT2800USB_RT33XX
 	/* Ralink */
 	{ USB_DEVICE(0x148f, 0x3370), USB_DEVICE_DATA(&rt2800usb_ops) },
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index a3940d7..dd0f66a 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -348,6 +348,11 @@
 	 * to bring the device/driver back into the desired state.
 	 */
 	struct delayed_work watchdog_work;
+
+	/*
+	 * Work structure for scheduling periodic AGC adjustments.
+	 */
+	struct delayed_work agc_work;
 };
 
 enum rt2x00_delayed_flags {
@@ -556,6 +561,7 @@
 			     struct link_qual *qual);
 	void (*link_tuner) (struct rt2x00_dev *rt2x00dev,
 			    struct link_qual *qual, const u32 count);
+	void (*gain_calibration) (struct rt2x00_dev *rt2x00dev);
 
 	/*
 	 * Data queue handlers.
@@ -674,7 +680,6 @@
 	DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL,
 	DRIVER_SUPPORT_PRE_TBTT_INTERRUPT,
 	DRIVER_SUPPORT_LINK_TUNING,
-	DRIVER_SUPPORT_WATCHDOG,
 
 	/*
 	 * Driver configuration
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c
index c92db32..66166ef 100644
--- a/drivers/net/wireless/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.c
@@ -568,7 +568,6 @@
 	blob->data = data;
 	data += sprintf(data, "driver:\t%s\n", intf->rt2x00dev->ops->name);
 	data += sprintf(data, "version:\t%s\n", DRV_VERSION);
-	data += sprintf(data, "compiled:\t%s %s\n", __DATE__, __TIME__);
 	blob->size = strlen(blob->data);
 
 	return debugfs_create_blob(name, S_IRUSR, intf->driver_folder, blob);
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 84eb6ad..9bffe84 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -27,6 +27,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/log2.h>
 
 #include "rt2x00.h"
 #include "rt2x00lib.h"
@@ -70,6 +71,7 @@
 	 */
 	rt2x00queue_start_queues(rt2x00dev);
 	rt2x00link_start_tuner(rt2x00dev);
+	rt2x00link_start_agc(rt2x00dev);
 
 	/*
 	 * Start watchdog monitoring.
@@ -92,6 +94,7 @@
 	/*
 	 * Stop all queues
 	 */
+	rt2x00link_stop_agc(rt2x00dev);
 	rt2x00link_stop_tuner(rt2x00dev);
 	rt2x00queue_stop_queues(rt2x00dev);
 	rt2x00queue_flush_queues(rt2x00dev, true);
@@ -350,10 +353,14 @@
 	 * which would allow the rc algorithm to better decide on
 	 * which rates are suitable.
 	 */
-	if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
+	if (test_bit(TXDONE_AMPDU, &txdesc->flags) ||
+	    tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
 		tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
 		tx_info->status.ampdu_len = 1;
 		tx_info->status.ampdu_ack_len = success ? 1 : 0;
+
+		if (!success)
+			tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
 	}
 
 	if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
@@ -511,8 +518,6 @@
 		 (rxdesc.size > header_length) &&
 		 (rxdesc.dev_flags & RXDONE_L2PAD))
 		rt2x00queue_remove_l2pad(entry->skb, header_length);
-	else
-		rt2x00queue_align_payload(entry->skb, header_length);
 
 	/* Trim buffer to correct size */
 	skb_trim(entry->skb, rxdesc.size);
@@ -811,13 +816,18 @@
 	 */
 	if (test_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags)) {
 		/*
-		 * Allocate txstatus fifo and tasklet, we use a size of 512
-		 * for the kfifo which is big enough to store 512/4=128 tx
-		 * status reports. In the worst case (tx status for all tx
-		 * queues gets reported before we've got a chance to handle
-		 * them) 24*4=384 tx status reports need to be cached.
+		 * Allocate the txstatus fifo. In the worst case the tx
+		 * status fifo has to hold the tx status of all entries
+		 * in all tx queues. Hence, calculate the kfifo size as
+		 * tx_queues * entry_num and round up to the nearest
+		 * power of 2.
 		 */
-		status = kfifo_alloc(&rt2x00dev->txstatus_fifo, 512,
+		int kfifo_size =
+			roundup_pow_of_two(rt2x00dev->ops->tx_queues *
+					   rt2x00dev->ops->tx->entry_num *
+					   sizeof(u32));
+
+		status = kfifo_alloc(&rt2x00dev->txstatus_fifo, kfifo_size,
 				     GFP_KERNEL);
 		if (status)
 			return status;
diff --git a/drivers/net/wireless/rt2x00/rt2x00ht.c b/drivers/net/wireless/rt2x00/rt2x00ht.c
index ae1219d..e8c0c3e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00ht.c
+++ b/drivers/net/wireless/rt2x00/rt2x00ht.c
@@ -43,8 +43,11 @@
 
 	txdesc->u.ht.ba_size = 7;	/* FIXME: What value is needed? */
 
-	txdesc->u.ht.stbc =
-	    (tx_info->flags & IEEE80211_TX_CTL_STBC) >> IEEE80211_TX_CTL_STBC_SHIFT;
+	/*
+	 * Only one STBC stream is supported for now.
+	 */
+	if (tx_info->flags & IEEE80211_TX_CTL_STBC)
+		txdesc->u.ht.stbc = 1;
 
 	/*
 	 * If IEEE80211_TX_RC_MCS is set txrate->idx just contains the
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index 2d94cba..88f2f92 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -32,6 +32,7 @@
  */
 #define WATCHDOG_INTERVAL	round_jiffies_relative(HZ)
 #define LINK_TUNE_INTERVAL	round_jiffies_relative(HZ)
+#define AGC_INTERVAL		round_jiffies_relative(4 * HZ)
 
 /*
  * rt2x00_rate: Per rate device information
@@ -119,16 +120,6 @@
 void rt2x00queue_align_frame(struct sk_buff *skb);
 
 /**
- * rt2x00queue_align_payload - Align 802.11 payload to 4-byte boundary
- * @skb: The skb to align
- * @header_length: Length of 802.11 header
- *
- * Align the 802.11 payload to a 4-byte boundary, this could
- * mean the header is not aligned properly though.
- */
-void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_length);
-
-/**
  * rt2x00queue_insert_l2pad - Align 802.11 header & payload to 4-byte boundary
  * @skb: The skb to align
  * @header_length: Length of 802.11 header
@@ -281,6 +272,18 @@
 void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev);
 
 /**
+ * rt2x00link_start_agc - Start periodic gain calibration
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ */
+void rt2x00link_start_agc(struct rt2x00_dev *rt2x00dev);
+
+/**
+ * rt2x00link_stop_agc - Stop periodic gain calibration
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ */
+void rt2x00link_stop_agc(struct rt2x00_dev *rt2x00dev);
+
+/**
  * rt2x00link_register - Initialize link tuning & watchdog functionality
  * @rt2x00dev: Pointer to &struct rt2x00_dev.
  *
diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c
index c975b0a..128b361 100644
--- a/drivers/net/wireless/rt2x00/rt2x00link.c
+++ b/drivers/net/wireless/rt2x00/rt2x00link.c
@@ -413,12 +413,11 @@
 {
 	struct link *link = &rt2x00dev->link;
 
-	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) ||
-	    !test_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags))
-		return;
-
-	ieee80211_queue_delayed_work(rt2x00dev->hw,
-				     &link->watchdog_work, WATCHDOG_INTERVAL);
+	if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
+	    rt2x00dev->ops->lib->watchdog)
+		ieee80211_queue_delayed_work(rt2x00dev->hw,
+					     &link->watchdog_work,
+					     WATCHDOG_INTERVAL);
 }
 
 void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev)
@@ -447,8 +446,46 @@
 					     WATCHDOG_INTERVAL);
 }
 
+void rt2x00link_start_agc(struct rt2x00_dev *rt2x00dev)
+{
+	struct link *link = &rt2x00dev->link;
+
+	if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
+	    rt2x00dev->ops->lib->gain_calibration)
+		ieee80211_queue_delayed_work(rt2x00dev->hw,
+					     &link->agc_work,
+					     AGC_INTERVAL);
+}
+
+void rt2x00link_stop_agc(struct rt2x00_dev *rt2x00dev)
+{
+	cancel_delayed_work_sync(&rt2x00dev->link.agc_work);
+}
+
+static void rt2x00link_agc(struct work_struct *work)
+{
+	struct rt2x00_dev *rt2x00dev =
+	    container_of(work, struct rt2x00_dev, link.agc_work.work);
+	struct link *link = &rt2x00dev->link;
+
+	/*
+	 * When the radio is shutting down we should
+	 * immediately cease the watchdog monitoring.
+	 */
+	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+		return;
+
+	rt2x00dev->ops->lib->gain_calibration(rt2x00dev);
+
+	if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
+		ieee80211_queue_delayed_work(rt2x00dev->hw,
+					     &link->agc_work,
+					     AGC_INTERVAL);
+}
+
 void rt2x00link_register(struct rt2x00_dev *rt2x00dev)
 {
+	INIT_DELAYED_WORK(&rt2x00dev->link.agc_work, rt2x00link_agc);
 	INIT_DELAYED_WORK(&rt2x00dev->link.watchdog_work, rt2x00link_watchdog);
 	INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00link_tuner);
 }
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index 4dd82b0..9649bd0 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -60,14 +60,15 @@
 }
 EXPORT_SYMBOL_GPL(rt2x00pci_regbusy_read);
 
-void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
+bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
 {
 	struct data_queue *queue = rt2x00dev->rx;
 	struct queue_entry *entry;
 	struct queue_entry_priv_pci *entry_priv;
 	struct skb_frame_desc *skbdesc;
+	int max_rx = 16;
 
-	while (1) {
+	while (--max_rx) {
 		entry = rt2x00queue_get_entry(queue, Q_INDEX);
 		entry_priv = entry->priv_data;
 
@@ -93,6 +94,8 @@
 		 */
 		rt2x00lib_rxdone(entry);
 	}
+
+	return !max_rx;
 }
 EXPORT_SYMBOL_GPL(rt2x00pci_rxdone);
 
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h
index 746ce8f..07961b8 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.h
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.h
@@ -101,8 +101,11 @@
 /**
  * rt2x00pci_rxdone - Handle RX done events
  * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ *
+ * Returns true if there are still rx frames pending and false if all
+ * pending rx frames were processed.
  */
-void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev);
+bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev);
 
 /*
  * Device initialization handlers.
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 4b3c70e..9fc4a1e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -148,19 +148,6 @@
 	skb_trim(skb, frame_length);
 }
 
-void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_length)
-{
-	unsigned int frame_length = skb->len;
-	unsigned int align = ALIGN_SIZE(skb, header_length);
-
-	if (!align)
-		return;
-
-	skb_push(skb, align);
-	memmove(skb->data, skb->data + align, frame_length);
-	skb_trim(skb, frame_length);
-}
-
 void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length)
 {
 	unsigned int payload_length = skb->len - header_length;
@@ -495,8 +482,11 @@
 	struct skb_frame_desc *skbdesc;
 	u8 rate_idx, rate_flags;
 
-	if (unlikely(rt2x00queue_full(queue)))
+	if (unlikely(rt2x00queue_full(queue))) {
+		ERROR(queue->rt2x00dev,
+		      "Dropping frame due to full tx queue %d.\n", queue->qid);
 		return -ENOBUFS;
+	}
 
 	if (unlikely(test_and_set_bit(ENTRY_OWNER_DEVICE_DATA,
 				      &entry->flags))) {
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index 0c8b0c6..6ae8200 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -217,6 +217,7 @@
 	TXDONE_FALLBACK,
 	TXDONE_FAILURE,
 	TXDONE_EXCESSIVE_RETRY,
+	TXDONE_AMPDU,
 };
 
 /**
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 77e8113..8ee1514 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -2313,8 +2313,10 @@
 static void rt61pci_rxdone_tasklet(unsigned long data)
 {
 	struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
-	rt2x00pci_rxdone(rt2x00dev);
-	rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RXDONE);
+	if (rt2x00pci_rxdone(rt2x00dev))
+		rt2x00pci_rxdone(rt2x00dev);
+	else
+		rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RXDONE);
 }
 
 static void rt61pci_autowake_tasklet(unsigned long data)
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 02f1148..6593059 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -2209,7 +2209,6 @@
 	if (!modparam_nohwcrypt)
 		__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
 	__set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
-	__set_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags);
 
 	/*
 	 * Set the rssi offset.
@@ -2407,7 +2406,6 @@
 	{ USB_DEVICE(0x0b05, 0x1723), USB_DEVICE_DATA(&rt73usb_ops) },
 	{ USB_DEVICE(0x0b05, 0x1724), USB_DEVICE_DATA(&rt73usb_ops) },
 	/* Belkin */
-	{ USB_DEVICE(0x050d, 0x7050), USB_DEVICE_DATA(&rt73usb_ops) },
 	{ USB_DEVICE(0x050d, 0x705a), USB_DEVICE_DATA(&rt73usb_ops) },
 	{ USB_DEVICE(0x050d, 0x905b), USB_DEVICE_DATA(&rt73usb_ops) },
 	{ USB_DEVICE(0x050d, 0x905c), USB_DEVICE_DATA(&rt73usb_ops) },
diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c
index bb0c781..dd5318e 100644
--- a/drivers/net/wireless/rtlwifi/base.c
+++ b/drivers/net/wireless/rtlwifi/base.c
@@ -432,7 +432,7 @@
 	}
 
 	if (rtlpriv->dm.useramask) {
-		/* TODO we will differentiate adhoc and station futrue  */
+		/* TODO adhoc and station handled differently in the future */
 		tcb_desc->mac_id = 0;
 
 		if ((mac->mode == WIRELESS_MODE_N_24G) ||
@@ -630,7 +630,7 @@
 	const struct iphdr *ip;
 
 	if (!ieee80211_is_data(fc))
-		goto end;
+		return false;
 
 	if (ieee80211_is_nullfunc(fc))
 		return true;
@@ -686,7 +686,6 @@
 		return true;
 	}
 
-end:
 	return false;
 }
 
diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c
index e4f4aee..8fed3c6 100644
--- a/drivers/net/wireless/rtlwifi/core.c
+++ b/drivers/net/wireless/rtlwifi/core.c
@@ -35,7 +35,7 @@
 /*mutex for start & stop is must here. */
 static int rtl_op_start(struct ieee80211_hw *hw)
 {
-	int err = 0;
+	int err;
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 
@@ -45,10 +45,8 @@
 		return 0;
 	mutex_lock(&rtlpriv->locks.conf_mutex);
 	err = rtlpriv->intf_ops->adapter_start(hw);
-	if (err)
-		goto out;
-	rtl_watch_dog_timer_callback((unsigned long)hw);
-out:
+	if (!err)
+		rtl_watch_dog_timer_callback((unsigned long)hw);
 	mutex_unlock(&rtlpriv->locks.conf_mutex);
 	return err;
 }
diff --git a/drivers/net/wireless/rtlwifi/efuse.c b/drivers/net/wireless/rtlwifi/efuse.c
index 590f14f..5d73c0f 100644
--- a/drivers/net/wireless/rtlwifi/efuse.c
+++ b/drivers/net/wireless/rtlwifi/efuse.c
@@ -338,11 +338,11 @@
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 	u8 section_idx, i, Base;
 	u16 words_need = 0, hdr_num = 0, totalbytes, efuse_used;
-	bool bwordchanged, bresult = true;
+	bool wordchanged, result = true;
 
 	for (section_idx = 0; section_idx < 16; section_idx++) {
 		Base = section_idx * 8;
-		bwordchanged = false;
+		wordchanged = false;
 
 		for (i = 0; i < 8; i = i + 2) {
 			if ((rtlefuse->efuse_map[EFUSE_INIT_MAP][Base + i] !=
@@ -351,11 +351,11 @@
 			     rtlefuse->efuse_map[EFUSE_MODIFY_MAP][Base + i +
 								   1])) {
 				words_need++;
-				bwordchanged = true;
+				wordchanged = true;
 			}
 		}
 
-		if (bwordchanged == true)
+		if (wordchanged == true)
 			hdr_num++;
 	}
 
@@ -364,14 +364,14 @@
 
 	if ((totalbytes + efuse_used) >=
 	    (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES))
-		bresult = false;
+		result = false;
 
 	RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD,
 		 ("efuse_shadow_update_chk(): totalbytes(%#x), "
 		  "hdr_num(%#x), words_need(%#x), efuse_used(%d)\n",
 		  totalbytes, hdr_num, words_need, efuse_used));
 
-	return bresult;
+	return result;
 }
 
 void efuse_shadow_read(struct ieee80211_hw *hw, u8 type,
@@ -394,7 +394,7 @@
 	else if (type == 2)
 		efuse_shadow_write_2byte(hw, offset, (u16) value);
 	else if (type == 4)
-		efuse_shadow_write_4byte(hw, offset, (u32) value);
+		efuse_shadow_write_4byte(hw, offset, value);
 
 }
 
@@ -572,7 +572,7 @@
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u8 tmpidx = 0;
-	int bresult;
+	int result;
 
 	rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1,
 		       (u8) (addr & 0xff));
@@ -592,19 +592,18 @@
 
 	if (tmpidx < 100) {
 		*data = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]);
-		bresult = true;
+		result = true;
 	} else {
 		*data = 0xff;
-		bresult = false;
+		result = false;
 	}
-	return bresult;
+	return result;
 }
 
 static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, u8 data)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u8 tmpidx = 0;
-	bool bresult;
 
 	RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD,
 		 ("Addr = %x Data=%x\n", addr, data));
@@ -626,11 +625,9 @@
 	}
 
 	if (tmpidx < 100)
-		bresult = true;
-	else
-		bresult = false;
+		return true;
 
-	return bresult;
+	return false;
 }
 
 static void efuse_read_all_map(struct ieee80211_hw *hw, u8 * efuse)
@@ -681,11 +678,10 @@
 {
 	u8 readstate = PG_STATE_HEADER;
 
-	bool bcontinual = true;
+	bool continual = true;
 
 	u8 efuse_data, word_cnts = 0;
 	u16 efuse_addr = 0;
-	u8 hworden = 0;
 	u8 tmpdata[8];
 
 	if (data == NULL)
@@ -696,7 +692,7 @@
 	memset(data, 0xff, PGPKT_DATA_SIZE * sizeof(u8));
 	memset(tmpdata, 0xff, PGPKT_DATA_SIZE * sizeof(u8));
 
-	while (bcontinual && (efuse_addr < EFUSE_MAX_SIZE)) {
+	while (continual && (efuse_addr < EFUSE_MAX_SIZE)) {
 		if (readstate & PG_STATE_HEADER) {
 			if (efuse_one_byte_read(hw, efuse_addr, &efuse_data)
 			    && (efuse_data != 0xFF))
@@ -705,9 +701,9 @@
 						      offset, tmpdata,
 						      &readstate);
 			else
-				bcontinual = false;
+				continual = false;
 		} else if (readstate & PG_STATE_DATA) {
-			efuse_word_enable_data_read(hworden, tmpdata, data);
+			efuse_word_enable_data_read(0, tmpdata, data);
 			efuse_addr = efuse_addr + (word_cnts * 2) + 1;
 			readstate = PG_STATE_HEADER;
 		}
@@ -725,13 +721,13 @@
 }
 
 static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
-			u8 efuse_data, u8 offset, int *bcontinual,
+			u8 efuse_data, u8 offset, int *continual,
 			u8 *write_state, struct pgpkt_struct *target_pkt,
-			int *repeat_times, int *bresult, u8 word_en)
+			int *repeat_times, int *result, u8 word_en)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct pgpkt_struct tmp_pkt;
-	int bdataempty = true;
+	bool dataempty = true;
 	u8 originaldata[8 * sizeof(u8)];
 	u8 badworden = 0x0F;
 	u8 match_word_en, tmp_word_en;
@@ -751,10 +747,10 @@
 			u16 address = *efuse_addr + 1 + tmpindex;
 			if (efuse_one_byte_read(hw, address,
 			     &efuse_data) && (efuse_data != 0xFF))
-				bdataempty = false;
+				dataempty = false;
 		}
 
-		if (bdataempty == false) {
+		if (dataempty == false) {
 			*efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1;
 			*write_state = PG_STATE_HEADER;
 		} else {
@@ -811,12 +807,12 @@
 					target_pkt->offset = offset;
 					target_pkt->word_en = tmp_word_en;
 				} else
-					*bcontinual = false;
+					*continual = false;
 				*write_state = PG_STATE_HEADER;
 				*repeat_times += 1;
 				if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) {
-					*bcontinual = false;
-					*bresult = false;
+					*continual = false;
+					*result = false;
 				}
 			} else {
 				*efuse_addr += (2 * tmp_word_cnts) + 1;
@@ -830,9 +826,9 @@
 }
 
 static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr,
-				   int *bcontinual, u8 *write_state,
+				   int *continual, u8 *write_state,
 				   struct pgpkt_struct target_pkt,
-				   int *repeat_times, int *bresult)
+				   int *repeat_times, int *result)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct pgpkt_struct tmp_pkt;
@@ -852,8 +848,8 @@
 		*write_state = PG_STATE_HEADER;
 		*repeat_times += 1;
 		if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) {
-			*bcontinual = false;
-			*bresult = false;
+			*continual = false;
+			*result = false;
 		}
 	} else {
 		tmp_pkt.offset = (tmp_header >> 4) & 0x0F;
@@ -884,8 +880,8 @@
 		*write_state = PG_STATE_HEADER;
 		*repeat_times += 1;
 		if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) {
-			*bcontinual = false;
-			*bresult = false;
+			*continual = false;
+			*result = false;
 		}
 
 		RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,
@@ -899,7 +895,7 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct pgpkt_struct target_pkt;
 	u8 write_state = PG_STATE_HEADER;
-	int bcontinual = true, bdataempty = true, bresult = true;
+	int continual = true, dataempty = true, result = true;
 	u16 efuse_addr = 0;
 	u8 efuse_data;
 	u8 target_word_cnts = 0;
@@ -923,11 +919,11 @@
 
 	RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, ("efuse Power ON\n"));
 
-	while (bcontinual && (efuse_addr <
+	while (continual && (efuse_addr <
 	       (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES))) {
 
 		if (write_state == PG_STATE_HEADER) {
-			bdataempty = true;
+			dataempty = true;
 			badworden = 0x0F;
 			RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,
 				("efuse PG_STATE_HEADER\n"));
@@ -936,32 +932,30 @@
 			    (efuse_data != 0xFF))
 				efuse_write_data_case1(hw, &efuse_addr,
 						       efuse_data, offset,
-						       &bcontinual,
+						       &continual,
 						       &write_state, &target_pkt,
-						       &repeat_times, &bresult,
+						       &repeat_times, &result,
 						       word_en);
 			else
 				efuse_write_data_case2(hw, &efuse_addr,
-						       &bcontinual,
+						       &continual,
 						       &write_state,
 						       target_pkt,
 						       &repeat_times,
-						       &bresult);
+						       &result);
 
 		} else if (write_state == PG_STATE_DATA) {
 			RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,
 				("efuse PG_STATE_DATA\n"));
-			badworden = 0x0f;
 			badworden =
 			    efuse_word_enable_data_write(hw, efuse_addr + 1,
 							 target_pkt.word_en,
 							 target_pkt.data);
 
 			if ((badworden & 0x0F) == 0x0F) {
-				bcontinual = false;
+				continual = false;
 			} else {
-				efuse_addr =
-				    efuse_addr + (2 * target_word_cnts) + 1;
+				efuse_addr += (2 * target_word_cnts) + 1;
 
 				target_pkt.offset = offset;
 				target_pkt.word_en = badworden;
@@ -971,8 +965,8 @@
 				write_state = PG_STATE_HEADER;
 				repeat_times++;
 				if (repeat_times > EFUSE_REPEAT_THRESHOLD_) {
-					bcontinual = false;
-					bresult = false;
+					continual = false;
+					result = false;
 				}
 				RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,
 					("efuse PG_STATE_HEADER-3\n"));
@@ -1072,13 +1066,13 @@
 	return badworden;
 }
 
-static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, u8 pwrstate)
+static void efuse_power_switch(struct ieee80211_hw *hw, u8 write, u8 pwrstate)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u8 tempval;
 	u16 tmpV16;
 
-	if (pwrstate == true) {
+	if (pwrstate) {
 		tmpV16 = rtl_read_word(rtlpriv,
 				       rtlpriv->cfg->maps[SYS_ISO_CTRL]);
 		if (!(tmpV16 & rtlpriv->cfg->maps[EFUSE_PWC_EV12V])) {
@@ -1106,8 +1100,8 @@
 		}
 	}
 
-	if (pwrstate == true) {
-		if (bwrite == true) {
+	if (pwrstate) {
+		if (write) {
 			tempval = rtl_read_byte(rtlpriv,
 						rtlpriv->cfg->maps[EFUSE_TEST] +
 						3);
@@ -1119,7 +1113,7 @@
 		}
 
 	} else {
-		if (bwrite == true) {
+		if (write) {
 			tempval = rtl_read_byte(rtlpriv,
 						rtlpriv->cfg->maps[EFUSE_TEST] +
 						3);
@@ -1134,12 +1128,12 @@
 
 static u16 efuse_get_current_size(struct ieee80211_hw *hw)
 {
-	int bcontinual = true;
+	int continual = true;
 	u16 efuse_addr = 0;
 	u8 hoffset, hworden;
 	u8 efuse_data, word_cnts;
 
-	while (bcontinual && efuse_one_byte_read(hw, efuse_addr, &efuse_data)
+	while (continual && efuse_one_byte_read(hw, efuse_addr, &efuse_data)
 	       && (efuse_addr < EFUSE_MAX_SIZE)) {
 		if (efuse_data != 0xFF) {
 			hoffset = (efuse_data >> 4) & 0x0F;
@@ -1147,7 +1141,7 @@
 			word_cnts = efuse_calculate_word_cnts(hworden);
 			efuse_addr = efuse_addr + (word_cnts * 2) + 1;
 		} else {
-			bcontinual = false;
+			continual = false;
 		}
 	}
 
diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c
index 9cd7703..efded43 100644
--- a/drivers/net/wireless/rtlwifi/pci.c
+++ b/drivers/net/wireless/rtlwifi/pci.c
@@ -113,32 +113,19 @@
 
 	/*Set HW definition to determine if it supports ASPM. */
 	switch (rtlpci->const_support_pciaspm) {
-	case 0:{
-			/*Not support ASPM. */
-			bool support_aspm = false;
-			ppsc->support_aspm = support_aspm;
-			break;
-		}
-	case 1:{
-			/*Support ASPM. */
-			bool support_aspm = true;
-			bool support_backdoor = true;
-			ppsc->support_aspm = support_aspm;
-
-			/*if(priv->oem_id == RT_CID_TOSHIBA &&
-			   !priv->ndis_adapter.amd_l1_patch)
-			   support_backdoor = false; */
-
-			ppsc->support_backdoor = support_backdoor;
-
-			break;
-		}
+	case 0:
+		/*Not support ASPM. */
+		ppsc->support_aspm = false;
+		break;
+	case 1:
+		/*Support ASPM. */
+		ppsc->support_aspm = true;
+		ppsc->support_backdoor = true;
+		break;
 	case 2:
 		/*ASPM value set by chipset. */
-		if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL) {
-			bool support_aspm = true;
-			ppsc->support_aspm = support_aspm;
-		}
+		if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL)
+			ppsc->support_aspm = true;
 		break;
 	default:
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
@@ -152,13 +139,11 @@
 			u8 value)
 {
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
-	bool bresult = false;
 
 	value |= 0x40;
-
 	pci_write_config_byte(rtlpci->pdev, 0x80, value);
 
-	return bresult;
+	return false;
 }
 
 /*When we set 0x01 to enable clk request. Set 0x0 to disable clk req.*/
@@ -166,14 +151,11 @@
 {
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	u8 buffer;
-	bool bresult = false;
 
 	buffer = value;
-
 	pci_write_config_byte(rtlpci->pdev, 0x81, value);
-	bresult = true;
 
-	return bresult;
+	return true;
 }
 
 /*Disable RTL8192SE ASPM & Disable Pci Bridge ASPM*/
@@ -191,6 +173,7 @@
 	u16 pcibridge_linkctrlreg = pcipriv->ndis_adapter.
 				pcibridge_linkctrlreg;
 	u16 aspmlevel = 0;
+	u8 tmp_u1b = 0;
 
 	if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) {
 		RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
@@ -204,11 +187,8 @@
 		_rtl_pci_switch_clk_req(hw, 0x0);
 	}
 
-	if (1) {
-		/*for promising device will in L0 state after an I/O. */
-		u8 tmp_u1b;
-		pci_read_config_byte(rtlpci->pdev, 0x80, &tmp_u1b);
-	}
+	/*for promising device will in L0 state after an I/O. */
+	pci_read_config_byte(rtlpci->pdev, 0x80, &tmp_u1b);
 
 	/*Set corresponding value. */
 	aspmlevel |= BIT(0) | BIT(1);
@@ -224,7 +204,6 @@
 	rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, pcibridge_linkctrlreg);
 
 	udelay(50);
-
 }
 
 /*
diff --git a/drivers/net/wireless/rtlwifi/pci.h b/drivers/net/wireless/rtlwifi/pci.h
index 0caa814..12747b9 100644
--- a/drivers/net/wireless/rtlwifi/pci.h
+++ b/drivers/net/wireless/rtlwifi/pci.h
@@ -192,8 +192,8 @@
 	u8 const_devicepci_aspm_setting;
 	/*If it supports ASPM, Offset[560h] = 0x40,
 	   otherwise Offset[560h] = 0x00. */
-	bool b_support_aspm;
-	bool b_support_backdoor;
+	bool support_aspm;
+	bool support_backdoor;
 
 	/*QOS & EDCA */
 	enum acm_method acm_method;
diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c
index 6b7e217..c8395fb 100644
--- a/drivers/net/wireless/rtlwifi/ps.c
+++ b/drivers/net/wireless/rtlwifi/ps.c
@@ -63,7 +63,6 @@
 
 bool rtl_ps_disable_nic(struct ieee80211_hw *hw)
 {
-	bool status = true;
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
 	/*<1> Stop all timer */
@@ -75,7 +74,7 @@
 	/*<3> Disable Adapter */
 	rtlpriv->cfg->ops->hw_disable(hw);
 
-	return status;
+	return true;
 }
 EXPORT_SYMBOL(rtl_ps_disable_nic);
 
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
index 28a6ce3..f107660 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
@@ -171,7 +171,6 @@
 static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	int err = -EIO;
 	u32 counter = 0;
 	u32 value32;
 
@@ -184,7 +183,7 @@
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 			 ("chksum report faill ! REG_MCUFWDL:0x%08x .\n",
 			  value32));
-		goto exit;
+		return -EIO;
 	}
 
 	RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
@@ -204,8 +203,7 @@
 				 ("Polling FW ready success!!"
 				 " REG_MCUFWDL:0x%08x .\n",
 				 value32));
-			err = 0;
-			goto exit;
+			return 0;
 		}
 
 		mdelay(FW_8192C_POLLING_DELAY);
@@ -214,9 +212,7 @@
 
 	RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 		 ("Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32));
-
-exit:
-	return err;
+	return -EIO;
 }
 
 int rtl92c_download_fw(struct ieee80211_hw *hw)
@@ -226,16 +222,14 @@
 	struct rtl92c_firmware_header *pfwheader;
 	u8 *pfwdata;
 	u32 fwsize;
-	int err;
 	enum version_8192c version = rtlhal->version;
 	const struct firmware *firmware;
 
-	printk(KERN_INFO "rtl8192cu: Loading firmware file %s\n",
+	printk(KERN_INFO "rtl8192c: Loading firmware file %s\n",
 	       rtlpriv->cfg->fw_name);
-	err = request_firmware(&firmware, rtlpriv->cfg->fw_name,
-			       rtlpriv->io.dev);
-	if (err) {
-		printk(KERN_ERR "rtl8192cu: Firmware loading failed\n");
+	if (request_firmware(&firmware, rtlpriv->cfg->fw_name,
+			    rtlpriv->io.dev)) {
+		printk(KERN_ERR "rtl8192c: Firmware loading failed\n");
 		return 1;
 	}
 
@@ -267,8 +261,7 @@
 	_rtl92c_write_fw(hw, version, pfwdata, fwsize);
 	_rtl92c_enable_fw_download(hw, false);
 
-	err = _rtl92c_fw_free_to_go(hw);
-	if (err) {
+	if (_rtl92c_fw_free_to_go(hw)) {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 			 ("Firmware is not ready to run!\n"));
 	} else {
@@ -303,7 +296,6 @@
 	u16 box_reg, box_extreg;
 	u8 u1b_tmp;
 	bool isfw_read = false;
-	u8 buf_index = 0;
 	bool bwrite_sucess = false;
 	u8 wait_h2c_limmit = 100;
 	u8 wait_writeh2c_limmit = 100;
@@ -414,7 +406,7 @@
 		case 1:
 			boxcontent[0] &= ~(BIT(7));
 			memcpy((u8 *) (boxcontent) + 1,
-			       p_cmdbuffer + buf_index, 1);
+			       p_cmdbuffer, 1);
 
 			for (idx = 0; idx < 4; idx++) {
 				rtl_write_byte(rtlpriv, box_reg + idx,
@@ -424,7 +416,7 @@
 		case 2:
 			boxcontent[0] &= ~(BIT(7));
 			memcpy((u8 *) (boxcontent) + 1,
-			       p_cmdbuffer + buf_index, 2);
+			       p_cmdbuffer, 2);
 
 			for (idx = 0; idx < 4; idx++) {
 				rtl_write_byte(rtlpriv, box_reg + idx,
@@ -434,7 +426,7 @@
 		case 3:
 			boxcontent[0] &= ~(BIT(7));
 			memcpy((u8 *) (boxcontent) + 1,
-			       p_cmdbuffer + buf_index, 3);
+			       p_cmdbuffer, 3);
 
 			for (idx = 0; idx < 4; idx++) {
 				rtl_write_byte(rtlpriv, box_reg + idx,
@@ -444,9 +436,9 @@
 		case 4:
 			boxcontent[0] |= (BIT(7));
 			memcpy((u8 *) (boxextcontent),
-			       p_cmdbuffer + buf_index, 2);
+			       p_cmdbuffer, 2);
 			memcpy((u8 *) (boxcontent) + 1,
-			       p_cmdbuffer + buf_index + 2, 2);
+			       p_cmdbuffer + 2, 2);
 
 			for (idx = 0; idx < 2; idx++) {
 				rtl_write_byte(rtlpriv, box_extreg + idx,
@@ -461,9 +453,9 @@
 		case 5:
 			boxcontent[0] |= (BIT(7));
 			memcpy((u8 *) (boxextcontent),
-			       p_cmdbuffer + buf_index, 2);
+			       p_cmdbuffer, 2);
 			memcpy((u8 *) (boxcontent) + 1,
-			       p_cmdbuffer + buf_index + 2, 3);
+			       p_cmdbuffer + 2, 3);
 
 			for (idx = 0; idx < 2; idx++) {
 				rtl_write_byte(rtlpriv, box_extreg + idx,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h
index 803adcc..b0b0b13 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h
@@ -532,9 +532,9 @@
 #define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size)	\
 do {							\
 	if (_size > TX_DESC_NEXT_DESC_OFFSET)		\
-		memset((void *)__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET);	\
+		memset(__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET);	\
 	else						\
-		memset((void *)__pdesc, 0, _size);	\
+		memset(__pdesc, 0, _size);	\
 } while (0);
 
 #define RX_HAL_IS_CCK_RATE(_pdesc)\
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
index d0b0d43..3f0cb81 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
@@ -656,7 +656,7 @@
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
 	__le16 fc = hdr->frame_control;
 
-	memset((void *)pdesc, 0, RTL_TX_HEADER_SIZE);
+	memset(pdesc, 0, RTL_TX_HEADER_SIZE);
 	if (firstseg)
 		SET_TX_DESC_OFFSET(pdesc, RTL_TX_HEADER_SIZE);
 	SET_TX_DESC_TX_RATE(pdesc, DESC92C_RATE1M);
diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h
index 01226f8..4ce4853 100644
--- a/drivers/net/wireless/rtlwifi/wifi.h
+++ b/drivers/net/wireless/rtlwifi/wifi.h
@@ -766,7 +766,7 @@
 #define IQK_MATRIX_REG_NUM	8
 #define IQK_MATRIX_SETTINGS_NUM	(1 + 24 + 21)
 struct iqk_matrix_regs {
-	bool b_iqk_done;
+	bool iqk_done;
 	long value[1][IQK_MATRIX_REG_NUM];
 };
 
@@ -1621,19 +1621,19 @@
 	u32 bt_edca_ul;
 	u32 bt_edca_dl;
 
-	bool b_init_set;
-	bool b_bt_busy_traffic;
-	bool b_bt_traffic_mode_set;
-	bool b_bt_non_traffic_mode_set;
+	bool init_set;
+	bool bt_busy_traffic;
+	bool bt_traffic_mode_set;
+	bool bt_non_traffic_mode_set;
 
-	bool b_fw_coexist_all_off;
-	bool b_sw_coexist_all_off;
+	bool fw_coexist_all_off;
+	bool sw_coexist_all_off;
 	u32 current_state;
 	u32 previous_state;
 	u8 bt_pre_rssi_state;
 
-	u8 b_reg_bt_iso;
-	u8 b_reg_bt_sco;
+	u8 reg_bt_iso;
+	u8 reg_bt_sco;
 
 };
 
diff --git a/drivers/net/wireless/wl1251/cmd.h b/drivers/net/wireless/wl1251/cmd.h
index e5c74c6..79ca527 100644
--- a/drivers/net/wireless/wl1251/cmd.h
+++ b/drivers/net/wireless/wl1251/cmd.h
@@ -313,8 +313,8 @@
 } __packed;
 
 enum wl1251_cmd_ps_mode {
-	STATION_ACTIVE_MODE,
-	STATION_POWER_SAVE_MODE
+	CHIP_ACTIVE_MODE,
+	CHIP_POWER_SAVE_MODE
 };
 
 struct wl1251_cmd_ps_params {
diff --git a/drivers/net/wireless/wl1251/event.c b/drivers/net/wireless/wl1251/event.c
index dfc4579..9f15cca 100644
--- a/drivers/net/wireless/wl1251/event.c
+++ b/drivers/net/wireless/wl1251/event.c
@@ -68,14 +68,16 @@
 	if (vector & BSS_LOSE_EVENT_ID) {
 		wl1251_debug(DEBUG_EVENT, "BSS_LOSE_EVENT");
 
-		if (wl->psm_requested && wl->psm) {
+		if (wl->psm_requested &&
+		    wl->station_mode != STATION_ACTIVE_MODE) {
 			ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE);
 			if (ret < 0)
 				return ret;
 		}
 	}
 
-	if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID && wl->psm) {
+	if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID &&
+	    wl->station_mode != STATION_ACTIVE_MODE) {
 		wl1251_debug(DEBUG_EVENT, "SYNCHRONIZATION_TIMEOUT_EVENT");
 
 		/* indicate to the stack, that beacons have been lost */
diff --git a/drivers/net/wireless/wl1251/main.c b/drivers/net/wireless/wl1251/main.c
index 12c9e63..a14a48c 100644
--- a/drivers/net/wireless/wl1251/main.c
+++ b/drivers/net/wireless/wl1251/main.c
@@ -497,7 +497,7 @@
 	wl->rx_last_id = 0;
 	wl->next_tx_complete = 0;
 	wl->elp = false;
-	wl->psm = 0;
+	wl->station_mode = STATION_ACTIVE_MODE;
 	wl->tx_queue_stopped = false;
 	wl->power_level = WL1251_DEFAULT_POWER_LEVEL;
 	wl->rssi_thold = 0;
@@ -632,13 +632,29 @@
 
 		wl->psm_requested = false;
 
-		if (wl->psm) {
+		if (wl->station_mode != STATION_ACTIVE_MODE) {
 			ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE);
 			if (ret < 0)
 				goto out_sleep;
 		}
 	}
 
+	if (changed & IEEE80211_CONF_CHANGE_IDLE) {
+		if (conf->flags & IEEE80211_CONF_IDLE) {
+			ret = wl1251_ps_set_mode(wl, STATION_IDLE);
+			if (ret < 0)
+				goto out_sleep;
+		} else {
+			ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE);
+			if (ret < 0)
+				goto out_sleep;
+			ret = wl1251_join(wl, wl->bss_type, wl->channel,
+					  wl->beacon_int, wl->dtim_period);
+			if (ret < 0)
+				goto out_sleep;
+		}
+	}
+
 	if (conf->power_level != wl->power_level) {
 		ret = wl1251_acx_tx_power(wl, conf->power_level);
 		if (ret < 0)
@@ -1384,7 +1400,7 @@
 	wl->rx_config = WL1251_DEFAULT_RX_CONFIG;
 	wl->rx_filter = WL1251_DEFAULT_RX_FILTER;
 	wl->elp = false;
-	wl->psm = 0;
+	wl->station_mode = STATION_ACTIVE_MODE;
 	wl->psm_requested = false;
 	wl->tx_queue_stopped = false;
 	wl->power_level = WL1251_DEFAULT_POWER_LEVEL;
diff --git a/drivers/net/wireless/wl1251/ps.c b/drivers/net/wireless/wl1251/ps.c
index 9cc5147..db719f7 100644
--- a/drivers/net/wireless/wl1251/ps.c
+++ b/drivers/net/wireless/wl1251/ps.c
@@ -39,7 +39,7 @@
 
 	mutex_lock(&wl->mutex);
 
-	if (wl->elp || !wl->psm)
+	if (wl->elp || wl->station_mode == STATION_ACTIVE_MODE)
 		goto out;
 
 	wl1251_debug(DEBUG_PSM, "chip to elp");
@@ -57,7 +57,7 @@
 {
 	unsigned long delay;
 
-	if (wl->psm) {
+	if (wl->station_mode != STATION_ACTIVE_MODE) {
 		delay = msecs_to_jiffies(ELP_ENTRY_DELAY);
 		ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, delay);
 	}
@@ -104,7 +104,7 @@
 	return 0;
 }
 
-int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode)
+int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_station_mode mode)
 {
 	int ret;
 
@@ -128,15 +128,24 @@
 		if (ret < 0)
 			return ret;
 
-		ret = wl1251_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE);
+		ret = wl1251_cmd_ps_mode(wl, CHIP_POWER_SAVE_MODE);
 		if (ret < 0)
 			return ret;
 
 		ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP);
 		if (ret < 0)
 			return ret;
+		break;
+	case STATION_IDLE:
+		wl1251_debug(DEBUG_PSM, "entering idle");
 
-		wl->psm = 1;
+		ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP);
+		if (ret < 0)
+			return ret;
+
+		ret = wl1251_cmd_template_set(wl, CMD_DISCONNECT, NULL, 0);
+		if (ret < 0)
+			return ret;
 		break;
 	case STATION_ACTIVE_MODE:
 	default:
@@ -163,13 +172,13 @@
 		if (ret < 0)
 			return ret;
 
-		ret = wl1251_cmd_ps_mode(wl, STATION_ACTIVE_MODE);
+		ret = wl1251_cmd_ps_mode(wl, CHIP_ACTIVE_MODE);
 		if (ret < 0)
 			return ret;
 
-		wl->psm = 0;
 		break;
 	}
+	wl->station_mode = mode;
 
 	return ret;
 }
diff --git a/drivers/net/wireless/wl1251/ps.h b/drivers/net/wireless/wl1251/ps.h
index 55c3dda..75efad2 100644
--- a/drivers/net/wireless/wl1251/ps.h
+++ b/drivers/net/wireless/wl1251/ps.h
@@ -26,7 +26,7 @@
 #include "wl1251.h"
 #include "acx.h"
 
-int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode);
+int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_station_mode mode);
 void wl1251_ps_elp_sleep(struct wl1251 *wl);
 int wl1251_ps_elp_wakeup(struct wl1251 *wl);
 void wl1251_elp_work(struct work_struct *work);
diff --git a/drivers/net/wireless/wl1251/wl1251.h b/drivers/net/wireless/wl1251/wl1251.h
index bb23cd5..a77f1bb 100644
--- a/drivers/net/wireless/wl1251/wl1251.h
+++ b/drivers/net/wireless/wl1251/wl1251.h
@@ -129,6 +129,12 @@
 	PART_TABLE_LEN
 };
 
+enum wl1251_station_mode {
+	STATION_ACTIVE_MODE,
+	STATION_POWER_SAVE_MODE,
+	STATION_IDLE,
+};
+
 struct wl1251_partition {
 	u32 size;
 	u32 start;
@@ -358,8 +364,7 @@
 
 	struct delayed_work elp_work;
 
-	/* we can be in psm, but not in elp, we have to differentiate */
-	bool psm;
+	enum wl1251_station_mode station_mode;
 
 	/* PSM mode requested */
 	bool psm_requested;
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index a73a305..ff306d7 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -557,7 +557,7 @@
 	return r;
 }
 
-/* CR157 can be optionally patched by the EEPROM for original ZD1211 */
+/* ZD_CR157 can be optionally patched by the EEPROM for original ZD1211 */
 static int patch_cr157(struct zd_chip *chip)
 {
 	int r;
@@ -571,7 +571,7 @@
 		return r;
 
 	dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value >> 8);
-	return zd_iowrite32_locked(chip, value >> 8, CR157);
+	return zd_iowrite32_locked(chip, value >> 8, ZD_CR157);
 }
 
 /*
@@ -593,8 +593,8 @@
 int zd_chip_generic_patch_6m_band(struct zd_chip *chip, int channel)
 {
 	struct zd_ioreq16 ioreqs[] = {
-		{ CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
-		{ CR47,  0x1e },
+		{ ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 },
+		{ ZD_CR47,  0x1e },
 	};
 
 	/* FIXME: Channel 11 is not the edge for all regulatory domains. */
@@ -608,69 +608,69 @@
 static int zd1211_hw_reset_phy(struct zd_chip *chip)
 {
 	static const struct zd_ioreq16 ioreqs[] = {
-		{ CR0,   0x0a }, { CR1,   0x06 }, { CR2,   0x26 },
-		{ CR3,   0x38 }, { CR4,   0x80 }, { CR9,   0xa0 },
-		{ CR10,  0x81 }, { CR11,  0x00 }, { CR12,  0x7f },
-		{ CR13,  0x8c }, { CR14,  0x80 }, { CR15,  0x3d },
-		{ CR16,  0x20 }, { CR17,  0x1e }, { CR18,  0x0a },
-		{ CR19,  0x48 }, { CR20,  0x0c }, { CR21,  0x0c },
-		{ CR22,  0x23 }, { CR23,  0x90 }, { CR24,  0x14 },
-		{ CR25,  0x40 }, { CR26,  0x10 }, { CR27,  0x19 },
-		{ CR28,  0x7f }, { CR29,  0x80 }, { CR30,  0x4b },
-		{ CR31,  0x60 }, { CR32,  0x43 }, { CR33,  0x08 },
-		{ CR34,  0x06 }, { CR35,  0x0a }, { CR36,  0x00 },
-		{ CR37,  0x00 }, { CR38,  0x38 }, { CR39,  0x0c },
-		{ CR40,  0x84 }, { CR41,  0x2a }, { CR42,  0x80 },
-		{ CR43,  0x10 }, { CR44,  0x12 }, { CR46,  0xff },
-		{ CR47,  0x1E }, { CR48,  0x26 }, { CR49,  0x5b },
-		{ CR64,  0xd0 }, { CR65,  0x04 }, { CR66,  0x58 },
-		{ CR67,  0xc9 }, { CR68,  0x88 }, { CR69,  0x41 },
-		{ CR70,  0x23 }, { CR71,  0x10 }, { CR72,  0xff },
-		{ CR73,  0x32 }, { CR74,  0x30 }, { CR75,  0x65 },
-		{ CR76,  0x41 }, { CR77,  0x1b }, { CR78,  0x30 },
-		{ CR79,  0x68 }, { CR80,  0x64 }, { CR81,  0x64 },
-		{ CR82,  0x00 }, { CR83,  0x00 }, { CR84,  0x00 },
-		{ CR85,  0x02 }, { CR86,  0x00 }, { CR87,  0x00 },
-		{ CR88,  0xff }, { CR89,  0xfc }, { CR90,  0x00 },
-		{ CR91,  0x00 }, { CR92,  0x00 }, { CR93,  0x08 },
-		{ CR94,  0x00 }, { CR95,  0x00 }, { CR96,  0xff },
-		{ CR97,  0xe7 }, { CR98,  0x00 }, { CR99,  0x00 },
-		{ CR100, 0x00 }, { CR101, 0xae }, { CR102, 0x02 },
-		{ CR103, 0x00 }, { CR104, 0x03 }, { CR105, 0x65 },
-		{ CR106, 0x04 }, { CR107, 0x00 }, { CR108, 0x0a },
-		{ CR109, 0xaa }, { CR110, 0xaa }, { CR111, 0x25 },
-		{ CR112, 0x25 }, { CR113, 0x00 }, { CR119, 0x1e },
-		{ CR125, 0x90 }, { CR126, 0x00 }, { CR127, 0x00 },
+		{ ZD_CR0,   0x0a }, { ZD_CR1,   0x06 }, { ZD_CR2,   0x26 },
+		{ ZD_CR3,   0x38 }, { ZD_CR4,   0x80 }, { ZD_CR9,   0xa0 },
+		{ ZD_CR10,  0x81 }, { ZD_CR11,  0x00 }, { ZD_CR12,  0x7f },
+		{ ZD_CR13,  0x8c }, { ZD_CR14,  0x80 }, { ZD_CR15,  0x3d },
+		{ ZD_CR16,  0x20 }, { ZD_CR17,  0x1e }, { ZD_CR18,  0x0a },
+		{ ZD_CR19,  0x48 }, { ZD_CR20,  0x0c }, { ZD_CR21,  0x0c },
+		{ ZD_CR22,  0x23 }, { ZD_CR23,  0x90 }, { ZD_CR24,  0x14 },
+		{ ZD_CR25,  0x40 }, { ZD_CR26,  0x10 }, { ZD_CR27,  0x19 },
+		{ ZD_CR28,  0x7f }, { ZD_CR29,  0x80 }, { ZD_CR30,  0x4b },
+		{ ZD_CR31,  0x60 }, { ZD_CR32,  0x43 }, { ZD_CR33,  0x08 },
+		{ ZD_CR34,  0x06 }, { ZD_CR35,  0x0a }, { ZD_CR36,  0x00 },
+		{ ZD_CR37,  0x00 }, { ZD_CR38,  0x38 }, { ZD_CR39,  0x0c },
+		{ ZD_CR40,  0x84 }, { ZD_CR41,  0x2a }, { ZD_CR42,  0x80 },
+		{ ZD_CR43,  0x10 }, { ZD_CR44,  0x12 }, { ZD_CR46,  0xff },
+		{ ZD_CR47,  0x1E }, { ZD_CR48,  0x26 }, { ZD_CR49,  0x5b },
+		{ ZD_CR64,  0xd0 }, { ZD_CR65,  0x04 }, { ZD_CR66,  0x58 },
+		{ ZD_CR67,  0xc9 }, { ZD_CR68,  0x88 }, { ZD_CR69,  0x41 },
+		{ ZD_CR70,  0x23 }, { ZD_CR71,  0x10 }, { ZD_CR72,  0xff },
+		{ ZD_CR73,  0x32 }, { ZD_CR74,  0x30 }, { ZD_CR75,  0x65 },
+		{ ZD_CR76,  0x41 }, { ZD_CR77,  0x1b }, { ZD_CR78,  0x30 },
+		{ ZD_CR79,  0x68 }, { ZD_CR80,  0x64 }, { ZD_CR81,  0x64 },
+		{ ZD_CR82,  0x00 }, { ZD_CR83,  0x00 }, { ZD_CR84,  0x00 },
+		{ ZD_CR85,  0x02 }, { ZD_CR86,  0x00 }, { ZD_CR87,  0x00 },
+		{ ZD_CR88,  0xff }, { ZD_CR89,  0xfc }, { ZD_CR90,  0x00 },
+		{ ZD_CR91,  0x00 }, { ZD_CR92,  0x00 }, { ZD_CR93,  0x08 },
+		{ ZD_CR94,  0x00 }, { ZD_CR95,  0x00 }, { ZD_CR96,  0xff },
+		{ ZD_CR97,  0xe7 }, { ZD_CR98,  0x00 }, { ZD_CR99,  0x00 },
+		{ ZD_CR100, 0x00 }, { ZD_CR101, 0xae }, { ZD_CR102, 0x02 },
+		{ ZD_CR103, 0x00 }, { ZD_CR104, 0x03 }, { ZD_CR105, 0x65 },
+		{ ZD_CR106, 0x04 }, { ZD_CR107, 0x00 }, { ZD_CR108, 0x0a },
+		{ ZD_CR109, 0xaa }, { ZD_CR110, 0xaa }, { ZD_CR111, 0x25 },
+		{ ZD_CR112, 0x25 }, { ZD_CR113, 0x00 }, { ZD_CR119, 0x1e },
+		{ ZD_CR125, 0x90 }, { ZD_CR126, 0x00 }, { ZD_CR127, 0x00 },
 		{ },
-		{ CR5,   0x00 }, { CR6,   0x00 }, { CR7,   0x00 },
-		{ CR8,   0x00 }, { CR9,   0x20 }, { CR12,  0xf0 },
-		{ CR20,  0x0e }, { CR21,  0x0e }, { CR27,  0x10 },
-		{ CR44,  0x33 }, { CR47,  0x1E }, { CR83,  0x24 },
-		{ CR84,  0x04 }, { CR85,  0x00 }, { CR86,  0x0C },
-		{ CR87,  0x12 }, { CR88,  0x0C }, { CR89,  0x00 },
-		{ CR90,  0x10 }, { CR91,  0x08 }, { CR93,  0x00 },
-		{ CR94,  0x01 }, { CR95,  0x00 }, { CR96,  0x50 },
-		{ CR97,  0x37 }, { CR98,  0x35 }, { CR101, 0x13 },
-		{ CR102, 0x27 }, { CR103, 0x27 }, { CR104, 0x18 },
-		{ CR105, 0x12 }, { CR109, 0x27 }, { CR110, 0x27 },
-		{ CR111, 0x27 }, { CR112, 0x27 }, { CR113, 0x27 },
-		{ CR114, 0x27 }, { CR115, 0x26 }, { CR116, 0x24 },
-		{ CR117, 0xfc }, { CR118, 0xfa }, { CR120, 0x4f },
-		{ CR125, 0xaa }, { CR127, 0x03 }, { CR128, 0x14 },
-		{ CR129, 0x12 }, { CR130, 0x10 }, { CR131, 0x0C },
-		{ CR136, 0xdf }, { CR137, 0x40 }, { CR138, 0xa0 },
-		{ CR139, 0xb0 }, { CR140, 0x99 }, { CR141, 0x82 },
-		{ CR142, 0x54 }, { CR143, 0x1c }, { CR144, 0x6c },
-		{ CR147, 0x07 }, { CR148, 0x4c }, { CR149, 0x50 },
-		{ CR150, 0x0e }, { CR151, 0x18 }, { CR160, 0xfe },
-		{ CR161, 0xee }, { CR162, 0xaa }, { CR163, 0xfa },
-		{ CR164, 0xfa }, { CR165, 0xea }, { CR166, 0xbe },
-		{ CR167, 0xbe }, { CR168, 0x6a }, { CR169, 0xba },
-		{ CR170, 0xba }, { CR171, 0xba },
-		/* Note: CR204 must lead the CR203 */
-		{ CR204, 0x7d },
+		{ ZD_CR5,   0x00 }, { ZD_CR6,   0x00 }, { ZD_CR7,   0x00 },
+		{ ZD_CR8,   0x00 }, { ZD_CR9,   0x20 }, { ZD_CR12,  0xf0 },
+		{ ZD_CR20,  0x0e }, { ZD_CR21,  0x0e }, { ZD_CR27,  0x10 },
+		{ ZD_CR44,  0x33 }, { ZD_CR47,  0x1E }, { ZD_CR83,  0x24 },
+		{ ZD_CR84,  0x04 }, { ZD_CR85,  0x00 }, { ZD_CR86,  0x0C },
+		{ ZD_CR87,  0x12 }, { ZD_CR88,  0x0C }, { ZD_CR89,  0x00 },
+		{ ZD_CR90,  0x10 }, { ZD_CR91,  0x08 }, { ZD_CR93,  0x00 },
+		{ ZD_CR94,  0x01 }, { ZD_CR95,  0x00 }, { ZD_CR96,  0x50 },
+		{ ZD_CR97,  0x37 }, { ZD_CR98,  0x35 }, { ZD_CR101, 0x13 },
+		{ ZD_CR102, 0x27 }, { ZD_CR103, 0x27 }, { ZD_CR104, 0x18 },
+		{ ZD_CR105, 0x12 }, { ZD_CR109, 0x27 }, { ZD_CR110, 0x27 },
+		{ ZD_CR111, 0x27 }, { ZD_CR112, 0x27 }, { ZD_CR113, 0x27 },
+		{ ZD_CR114, 0x27 }, { ZD_CR115, 0x26 }, { ZD_CR116, 0x24 },
+		{ ZD_CR117, 0xfc }, { ZD_CR118, 0xfa }, { ZD_CR120, 0x4f },
+		{ ZD_CR125, 0xaa }, { ZD_CR127, 0x03 }, { ZD_CR128, 0x14 },
+		{ ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, { ZD_CR131, 0x0C },
+		{ ZD_CR136, 0xdf }, { ZD_CR137, 0x40 }, { ZD_CR138, 0xa0 },
+		{ ZD_CR139, 0xb0 }, { ZD_CR140, 0x99 }, { ZD_CR141, 0x82 },
+		{ ZD_CR142, 0x54 }, { ZD_CR143, 0x1c }, { ZD_CR144, 0x6c },
+		{ ZD_CR147, 0x07 }, { ZD_CR148, 0x4c }, { ZD_CR149, 0x50 },
+		{ ZD_CR150, 0x0e }, { ZD_CR151, 0x18 }, { ZD_CR160, 0xfe },
+		{ ZD_CR161, 0xee }, { ZD_CR162, 0xaa }, { ZD_CR163, 0xfa },
+		{ ZD_CR164, 0xfa }, { ZD_CR165, 0xea }, { ZD_CR166, 0xbe },
+		{ ZD_CR167, 0xbe }, { ZD_CR168, 0x6a }, { ZD_CR169, 0xba },
+		{ ZD_CR170, 0xba }, { ZD_CR171, 0xba },
+		/* Note: ZD_CR204 must lead the ZD_CR203 */
+		{ ZD_CR204, 0x7d },
 		{ },
-		{ CR203, 0x30 },
+		{ ZD_CR203, 0x30 },
 	};
 
 	int r, t;
@@ -697,62 +697,62 @@
 static int zd1211b_hw_reset_phy(struct zd_chip *chip)
 {
 	static const struct zd_ioreq16 ioreqs[] = {
-		{ CR0,   0x14 }, { CR1,   0x06 }, { CR2,   0x26 },
-		{ CR3,   0x38 }, { CR4,   0x80 }, { CR9,   0xe0 },
-		{ CR10,  0x81 },
-		/* power control { { CR11,  1 << 6 }, */
-		{ CR11,  0x00 },
-		{ CR12,  0xf0 }, { CR13,  0x8c }, { CR14,  0x80 },
-		{ CR15,  0x3d }, { CR16,  0x20 }, { CR17,  0x1e },
-		{ CR18,  0x0a }, { CR19,  0x48 },
-		{ CR20,  0x10 }, /* Org:0x0E, ComTrend:RalLink AP */
-		{ CR21,  0x0e }, { CR22,  0x23 }, { CR23,  0x90 },
-		{ CR24,  0x14 }, { CR25,  0x40 }, { CR26,  0x10 },
-		{ CR27,  0x10 }, { CR28,  0x7f }, { CR29,  0x80 },
-		{ CR30,  0x4b }, /* ASIC/FWT, no jointly decoder */
-		{ CR31,  0x60 }, { CR32,  0x43 }, { CR33,  0x08 },
-		{ CR34,  0x06 }, { CR35,  0x0a }, { CR36,  0x00 },
-		{ CR37,  0x00 }, { CR38,  0x38 }, { CR39,  0x0c },
-		{ CR40,  0x84 }, { CR41,  0x2a }, { CR42,  0x80 },
-		{ CR43,  0x10 }, { CR44,  0x33 }, { CR46,  0xff },
-		{ CR47,  0x1E }, { CR48,  0x26 }, { CR49,  0x5b },
-		{ CR64,  0xd0 }, { CR65,  0x04 }, { CR66,  0x58 },
-		{ CR67,  0xc9 }, { CR68,  0x88 }, { CR69,  0x41 },
-		{ CR70,  0x23 }, { CR71,  0x10 }, { CR72,  0xff },
-		{ CR73,  0x32 }, { CR74,  0x30 }, { CR75,  0x65 },
-		{ CR76,  0x41 }, { CR77,  0x1b }, { CR78,  0x30 },
-		{ CR79,  0xf0 }, { CR80,  0x64 }, { CR81,  0x64 },
-		{ CR82,  0x00 }, { CR83,  0x24 }, { CR84,  0x04 },
-		{ CR85,  0x00 }, { CR86,  0x0c }, { CR87,  0x12 },
-		{ CR88,  0x0c }, { CR89,  0x00 }, { CR90,  0x58 },
-		{ CR91,  0x04 }, { CR92,  0x00 }, { CR93,  0x00 },
-		{ CR94,  0x01 },
-		{ CR95,  0x20 }, /* ZD1211B */
-		{ CR96,  0x50 }, { CR97,  0x37 }, { CR98,  0x35 },
-		{ CR99,  0x00 }, { CR100, 0x01 }, { CR101, 0x13 },
-		{ CR102, 0x27 }, { CR103, 0x27 }, { CR104, 0x18 },
-		{ CR105, 0x12 }, { CR106, 0x04 }, { CR107, 0x00 },
-		{ CR108, 0x0a }, { CR109, 0x27 }, { CR110, 0x27 },
-		{ CR111, 0x27 }, { CR112, 0x27 }, { CR113, 0x27 },
-		{ CR114, 0x27 }, { CR115, 0x26 }, { CR116, 0x24 },
-		{ CR117, 0xfc }, { CR118, 0xfa }, { CR119, 0x1e },
-		{ CR125, 0x90 }, { CR126, 0x00 }, { CR127, 0x00 },
-		{ CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
-		{ CR131, 0x0c }, { CR136, 0xdf }, { CR137, 0xa0 },
-		{ CR138, 0xa8 }, { CR139, 0xb4 }, { CR140, 0x98 },
-		{ CR141, 0x82 }, { CR142, 0x53 }, { CR143, 0x1c },
-		{ CR144, 0x6c }, { CR147, 0x07 }, { CR148, 0x40 },
-		{ CR149, 0x40 }, /* Org:0x50 ComTrend:RalLink AP */
-		{ CR150, 0x14 }, /* Org:0x0E ComTrend:RalLink AP */
-		{ CR151, 0x18 }, { CR159, 0x70 }, { CR160, 0xfe },
-		{ CR161, 0xee }, { CR162, 0xaa }, { CR163, 0xfa },
-		{ CR164, 0xfa }, { CR165, 0xea }, { CR166, 0xbe },
-		{ CR167, 0xbe }, { CR168, 0x6a }, { CR169, 0xba },
-		{ CR170, 0xba }, { CR171, 0xba },
-		/* Note: CR204 must lead the CR203 */
-		{ CR204, 0x7d },
+		{ ZD_CR0,   0x14 }, { ZD_CR1,   0x06 }, { ZD_CR2,   0x26 },
+		{ ZD_CR3,   0x38 }, { ZD_CR4,   0x80 }, { ZD_CR9,   0xe0 },
+		{ ZD_CR10,  0x81 },
+		/* power control { { ZD_CR11,  1 << 6 }, */
+		{ ZD_CR11,  0x00 },
+		{ ZD_CR12,  0xf0 }, { ZD_CR13,  0x8c }, { ZD_CR14,  0x80 },
+		{ ZD_CR15,  0x3d }, { ZD_CR16,  0x20 }, { ZD_CR17,  0x1e },
+		{ ZD_CR18,  0x0a }, { ZD_CR19,  0x48 },
+		{ ZD_CR20,  0x10 }, /* Org:0x0E, ComTrend:RalLink AP */
+		{ ZD_CR21,  0x0e }, { ZD_CR22,  0x23 }, { ZD_CR23,  0x90 },
+		{ ZD_CR24,  0x14 }, { ZD_CR25,  0x40 }, { ZD_CR26,  0x10 },
+		{ ZD_CR27,  0x10 }, { ZD_CR28,  0x7f }, { ZD_CR29,  0x80 },
+		{ ZD_CR30,  0x4b }, /* ASIC/FWT, no jointly decoder */
+		{ ZD_CR31,  0x60 }, { ZD_CR32,  0x43 }, { ZD_CR33,  0x08 },
+		{ ZD_CR34,  0x06 }, { ZD_CR35,  0x0a }, { ZD_CR36,  0x00 },
+		{ ZD_CR37,  0x00 }, { ZD_CR38,  0x38 }, { ZD_CR39,  0x0c },
+		{ ZD_CR40,  0x84 }, { ZD_CR41,  0x2a }, { ZD_CR42,  0x80 },
+		{ ZD_CR43,  0x10 }, { ZD_CR44,  0x33 }, { ZD_CR46,  0xff },
+		{ ZD_CR47,  0x1E }, { ZD_CR48,  0x26 }, { ZD_CR49,  0x5b },
+		{ ZD_CR64,  0xd0 }, { ZD_CR65,  0x04 }, { ZD_CR66,  0x58 },
+		{ ZD_CR67,  0xc9 }, { ZD_CR68,  0x88 }, { ZD_CR69,  0x41 },
+		{ ZD_CR70,  0x23 }, { ZD_CR71,  0x10 }, { ZD_CR72,  0xff },
+		{ ZD_CR73,  0x32 }, { ZD_CR74,  0x30 }, { ZD_CR75,  0x65 },
+		{ ZD_CR76,  0x41 }, { ZD_CR77,  0x1b }, { ZD_CR78,  0x30 },
+		{ ZD_CR79,  0xf0 }, { ZD_CR80,  0x64 }, { ZD_CR81,  0x64 },
+		{ ZD_CR82,  0x00 }, { ZD_CR83,  0x24 }, { ZD_CR84,  0x04 },
+		{ ZD_CR85,  0x00 }, { ZD_CR86,  0x0c }, { ZD_CR87,  0x12 },
+		{ ZD_CR88,  0x0c }, { ZD_CR89,  0x00 }, { ZD_CR90,  0x58 },
+		{ ZD_CR91,  0x04 }, { ZD_CR92,  0x00 }, { ZD_CR93,  0x00 },
+		{ ZD_CR94,  0x01 },
+		{ ZD_CR95,  0x20 }, /* ZD1211B */
+		{ ZD_CR96,  0x50 }, { ZD_CR97,  0x37 }, { ZD_CR98,  0x35 },
+		{ ZD_CR99,  0x00 }, { ZD_CR100, 0x01 }, { ZD_CR101, 0x13 },
+		{ ZD_CR102, 0x27 }, { ZD_CR103, 0x27 }, { ZD_CR104, 0x18 },
+		{ ZD_CR105, 0x12 }, { ZD_CR106, 0x04 }, { ZD_CR107, 0x00 },
+		{ ZD_CR108, 0x0a }, { ZD_CR109, 0x27 }, { ZD_CR110, 0x27 },
+		{ ZD_CR111, 0x27 }, { ZD_CR112, 0x27 }, { ZD_CR113, 0x27 },
+		{ ZD_CR114, 0x27 }, { ZD_CR115, 0x26 }, { ZD_CR116, 0x24 },
+		{ ZD_CR117, 0xfc }, { ZD_CR118, 0xfa }, { ZD_CR119, 0x1e },
+		{ ZD_CR125, 0x90 }, { ZD_CR126, 0x00 }, { ZD_CR127, 0x00 },
+		{ ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 },
+		{ ZD_CR131, 0x0c }, { ZD_CR136, 0xdf }, { ZD_CR137, 0xa0 },
+		{ ZD_CR138, 0xa8 }, { ZD_CR139, 0xb4 }, { ZD_CR140, 0x98 },
+		{ ZD_CR141, 0x82 }, { ZD_CR142, 0x53 }, { ZD_CR143, 0x1c },
+		{ ZD_CR144, 0x6c }, { ZD_CR147, 0x07 }, { ZD_CR148, 0x40 },
+		{ ZD_CR149, 0x40 }, /* Org:0x50 ComTrend:RalLink AP */
+		{ ZD_CR150, 0x14 }, /* Org:0x0E ComTrend:RalLink AP */
+		{ ZD_CR151, 0x18 }, { ZD_CR159, 0x70 }, { ZD_CR160, 0xfe },
+		{ ZD_CR161, 0xee }, { ZD_CR162, 0xaa }, { ZD_CR163, 0xfa },
+		{ ZD_CR164, 0xfa }, { ZD_CR165, 0xea }, { ZD_CR166, 0xbe },
+		{ ZD_CR167, 0xbe }, { ZD_CR168, 0x6a }, { ZD_CR169, 0xba },
+		{ ZD_CR170, 0xba }, { ZD_CR171, 0xba },
+		/* Note: ZD_CR204 must lead the ZD_CR203 */
+		{ ZD_CR204, 0x7d },
 		{},
-		{ CR203, 0x30 },
+		{ ZD_CR203, 0x30 },
 	};
 
 	int r, t;
@@ -1200,24 +1200,24 @@
 static int update_pwr_int(struct zd_chip *chip, u8 channel)
 {
 	u8 value = chip->pwr_int_values[channel - 1];
-	return zd_iowrite16_locked(chip, value, CR31);
+	return zd_iowrite16_locked(chip, value, ZD_CR31);
 }
 
 static int update_pwr_cal(struct zd_chip *chip, u8 channel)
 {
 	u8 value = chip->pwr_cal_values[channel-1];
-	return zd_iowrite16_locked(chip, value, CR68);
+	return zd_iowrite16_locked(chip, value, ZD_CR68);
 }
 
 static int update_ofdm_cal(struct zd_chip *chip, u8 channel)
 {
 	struct zd_ioreq16 ioreqs[3];
 
-	ioreqs[0].addr = CR67;
+	ioreqs[0].addr = ZD_CR67;
 	ioreqs[0].value = chip->ofdm_cal_values[OFDM_36M_INDEX][channel-1];
-	ioreqs[1].addr = CR66;
+	ioreqs[1].addr = ZD_CR66;
 	ioreqs[1].value = chip->ofdm_cal_values[OFDM_48M_INDEX][channel-1];
-	ioreqs[2].addr = CR65;
+	ioreqs[2].addr = ZD_CR65;
 	ioreqs[2].value = chip->ofdm_cal_values[OFDM_54M_INDEX][channel-1];
 
 	return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
@@ -1236,9 +1236,9 @@
 		return r;
 	if (zd_chip_is_zd1211b(chip)) {
 		static const struct zd_ioreq16 ioreqs[] = {
-			{ CR69, 0x28 },
+			{ ZD_CR69, 0x28 },
 			{},
-			{ CR69, 0x2a },
+			{ ZD_CR69, 0x2a },
 		};
 
 		r = update_ofdm_cal(chip, channel);
@@ -1269,7 +1269,7 @@
 	if (r)
 		return r;
 	dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value & 0xff);
-	return zd_iowrite16_locked(chip, value & 0xff, CR47);
+	return zd_iowrite16_locked(chip, value & 0xff, ZD_CR47);
 }
 
 int zd_chip_set_channel(struct zd_chip *chip, u8 channel)
@@ -1505,9 +1505,9 @@
 int zd_rfwrite_cr_locked(struct zd_chip *chip, u32 value)
 {
 	const struct zd_ioreq16 ioreqs[] = {
-		{ CR244, (value >> 16) & 0xff },
-		{ CR243, (value >>  8) & 0xff },
-		{ CR242,  value        & 0xff },
+		{ ZD_CR244, (value >> 16) & 0xff },
+		{ ZD_CR243, (value >>  8) & 0xff },
+		{ ZD_CR242,  value        & 0xff },
 	};
 	ZD_ASSERT(mutex_is_locked(&chip->mutex));
 	return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
index 14e4402..4be7c3b 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -61,277 +61,288 @@
 #define FWRAW_DATA(offset) ((zd_addr_t)(FW_START + (offset)))
 
 /* 8-bit hardware registers */
-#define CR0   CTL_REG(0x0000)
-#define CR1   CTL_REG(0x0004)
-#define CR2   CTL_REG(0x0008)
-#define CR3   CTL_REG(0x000C)
+#define ZD_CR0   CTL_REG(0x0000)
+#define ZD_CR1   CTL_REG(0x0004)
+#define ZD_CR2   CTL_REG(0x0008)
+#define ZD_CR3   CTL_REG(0x000C)
 
-#define CR5   CTL_REG(0x0010)
+#define ZD_CR5   CTL_REG(0x0010)
 /*	bit 5: if set short preamble used
  *	bit 6: filter band - Japan channel 14 on, else off
  */
-#define CR6   CTL_REG(0x0014)
-#define CR7   CTL_REG(0x0018)
-#define CR8   CTL_REG(0x001C)
+#define ZD_CR6   CTL_REG(0x0014)
+#define ZD_CR7   CTL_REG(0x0018)
+#define ZD_CR8   CTL_REG(0x001C)
 
-#define CR4   CTL_REG(0x0020)
+#define ZD_CR4   CTL_REG(0x0020)
 
-#define CR9   CTL_REG(0x0024)
-/*	bit 2: antenna switch (together with CR10) */
-#define CR10  CTL_REG(0x0028)
-/*	bit 1: antenna switch (together with CR9)
- *	RF2959 controls with CR11 radion on and off
+#define ZD_CR9   CTL_REG(0x0024)
+/*	bit 2: antenna switch (together with ZD_CR10) */
+#define ZD_CR10  CTL_REG(0x0028)
+/*	bit 1: antenna switch (together with ZD_CR9)
+ *	RF2959 controls with ZD_CR11 radion on and off
  */
-#define CR11  CTL_REG(0x002C)
+#define ZD_CR11  CTL_REG(0x002C)
 /*	bit 6:  TX power control for OFDM
- *	RF2959 controls with CR10 radio on and off
+ *	RF2959 controls with ZD_CR10 radio on and off
  */
-#define CR12  CTL_REG(0x0030)
-#define CR13  CTL_REG(0x0034)
-#define CR14  CTL_REG(0x0038)
-#define CR15  CTL_REG(0x003C)
-#define CR16  CTL_REG(0x0040)
-#define CR17  CTL_REG(0x0044)
-#define CR18  CTL_REG(0x0048)
-#define CR19  CTL_REG(0x004C)
-#define CR20  CTL_REG(0x0050)
-#define CR21  CTL_REG(0x0054)
-#define CR22  CTL_REG(0x0058)
-#define CR23  CTL_REG(0x005C)
-#define CR24  CTL_REG(0x0060)	/* CCA threshold */
-#define CR25  CTL_REG(0x0064)
-#define CR26  CTL_REG(0x0068)
-#define CR27  CTL_REG(0x006C)
-#define CR28  CTL_REG(0x0070)
-#define CR29  CTL_REG(0x0074)
-#define CR30  CTL_REG(0x0078)
-#define CR31  CTL_REG(0x007C)	/* TX power control for RF in CCK mode */
-#define CR32  CTL_REG(0x0080)
-#define CR33  CTL_REG(0x0084)
-#define CR34  CTL_REG(0x0088)
-#define CR35  CTL_REG(0x008C)
-#define CR36  CTL_REG(0x0090)
-#define CR37  CTL_REG(0x0094)
-#define CR38  CTL_REG(0x0098)
-#define CR39  CTL_REG(0x009C)
-#define CR40  CTL_REG(0x00A0)
-#define CR41  CTL_REG(0x00A4)
-#define CR42  CTL_REG(0x00A8)
-#define CR43  CTL_REG(0x00AC)
-#define CR44  CTL_REG(0x00B0)
-#define CR45  CTL_REG(0x00B4)
-#define CR46  CTL_REG(0x00B8)
-#define CR47  CTL_REG(0x00BC)	/* CCK baseband gain
-	                         * (patch value might be in EEPROM)
-				 */
-#define CR48  CTL_REG(0x00C0)
-#define CR49  CTL_REG(0x00C4)
-#define CR50  CTL_REG(0x00C8)
-#define CR51  CTL_REG(0x00CC)	/* TX power control for RF in 6-36M modes */
-#define CR52  CTL_REG(0x00D0)	/* TX power control for RF in 48M mode */
-#define CR53  CTL_REG(0x00D4)	/* TX power control for RF in 54M mode */
-#define CR54  CTL_REG(0x00D8)
-#define CR55  CTL_REG(0x00DC)
-#define CR56  CTL_REG(0x00E0)
-#define CR57  CTL_REG(0x00E4)
-#define CR58  CTL_REG(0x00E8)
-#define CR59  CTL_REG(0x00EC)
-#define CR60  CTL_REG(0x00F0)
-#define CR61  CTL_REG(0x00F4)
-#define CR62  CTL_REG(0x00F8)
-#define CR63  CTL_REG(0x00FC)
-#define CR64  CTL_REG(0x0100)
-#define CR65  CTL_REG(0x0104) /* OFDM 54M calibration */
-#define CR66  CTL_REG(0x0108) /* OFDM 48M calibration */
-#define CR67  CTL_REG(0x010C) /* OFDM 36M calibration */
-#define CR68  CTL_REG(0x0110) /* CCK calibration */
-#define CR69  CTL_REG(0x0114)
-#define CR70  CTL_REG(0x0118)
-#define CR71  CTL_REG(0x011C)
-#define CR72  CTL_REG(0x0120)
-#define CR73  CTL_REG(0x0124)
-#define CR74  CTL_REG(0x0128)
-#define CR75  CTL_REG(0x012C)
-#define CR76  CTL_REG(0x0130)
-#define CR77  CTL_REG(0x0134)
-#define CR78  CTL_REG(0x0138)
-#define CR79  CTL_REG(0x013C)
-#define CR80  CTL_REG(0x0140)
-#define CR81  CTL_REG(0x0144)
-#define CR82  CTL_REG(0x0148)
-#define CR83  CTL_REG(0x014C)
-#define CR84  CTL_REG(0x0150)
-#define CR85  CTL_REG(0x0154)
-#define CR86  CTL_REG(0x0158)
-#define CR87  CTL_REG(0x015C)
-#define CR88  CTL_REG(0x0160)
-#define CR89  CTL_REG(0x0164)
-#define CR90  CTL_REG(0x0168)
-#define CR91  CTL_REG(0x016C)
-#define CR92  CTL_REG(0x0170)
-#define CR93  CTL_REG(0x0174)
-#define CR94  CTL_REG(0x0178)
-#define CR95  CTL_REG(0x017C)
-#define CR96  CTL_REG(0x0180)
-#define CR97  CTL_REG(0x0184)
-#define CR98  CTL_REG(0x0188)
-#define CR99  CTL_REG(0x018C)
-#define CR100 CTL_REG(0x0190)
-#define CR101 CTL_REG(0x0194)
-#define CR102 CTL_REG(0x0198)
-#define CR103 CTL_REG(0x019C)
-#define CR104 CTL_REG(0x01A0)
-#define CR105 CTL_REG(0x01A4)
-#define CR106 CTL_REG(0x01A8)
-#define CR107 CTL_REG(0x01AC)
-#define CR108 CTL_REG(0x01B0)
-#define CR109 CTL_REG(0x01B4)
-#define CR110 CTL_REG(0x01B8)
-#define CR111 CTL_REG(0x01BC)
-#define CR112 CTL_REG(0x01C0)
-#define CR113 CTL_REG(0x01C4)
-#define CR114 CTL_REG(0x01C8)
-#define CR115 CTL_REG(0x01CC)
-#define CR116 CTL_REG(0x01D0)
-#define CR117 CTL_REG(0x01D4)
-#define CR118 CTL_REG(0x01D8)
-#define CR119 CTL_REG(0x01DC)
-#define CR120 CTL_REG(0x01E0)
-#define CR121 CTL_REG(0x01E4)
-#define CR122 CTL_REG(0x01E8)
-#define CR123 CTL_REG(0x01EC)
-#define CR124 CTL_REG(0x01F0)
-#define CR125 CTL_REG(0x01F4)
-#define CR126 CTL_REG(0x01F8)
-#define CR127 CTL_REG(0x01FC)
-#define CR128 CTL_REG(0x0200)
-#define CR129 CTL_REG(0x0204)
-#define CR130 CTL_REG(0x0208)
-#define CR131 CTL_REG(0x020C)
-#define CR132 CTL_REG(0x0210)
-#define CR133 CTL_REG(0x0214)
-#define CR134 CTL_REG(0x0218)
-#define CR135 CTL_REG(0x021C)
-#define CR136 CTL_REG(0x0220)
-#define CR137 CTL_REG(0x0224)
-#define CR138 CTL_REG(0x0228)
-#define CR139 CTL_REG(0x022C)
-#define CR140 CTL_REG(0x0230)
-#define CR141 CTL_REG(0x0234)
-#define CR142 CTL_REG(0x0238)
-#define CR143 CTL_REG(0x023C)
-#define CR144 CTL_REG(0x0240)
-#define CR145 CTL_REG(0x0244)
-#define CR146 CTL_REG(0x0248)
-#define CR147 CTL_REG(0x024C)
-#define CR148 CTL_REG(0x0250)
-#define CR149 CTL_REG(0x0254)
-#define CR150 CTL_REG(0x0258)
-#define CR151 CTL_REG(0x025C)
-#define CR152 CTL_REG(0x0260)
-#define CR153 CTL_REG(0x0264)
-#define CR154 CTL_REG(0x0268)
-#define CR155 CTL_REG(0x026C)
-#define CR156 CTL_REG(0x0270)
-#define CR157 CTL_REG(0x0274)
-#define CR158 CTL_REG(0x0278)
-#define CR159 CTL_REG(0x027C)
-#define CR160 CTL_REG(0x0280)
-#define CR161 CTL_REG(0x0284)
-#define CR162 CTL_REG(0x0288)
-#define CR163 CTL_REG(0x028C)
-#define CR164 CTL_REG(0x0290)
-#define CR165 CTL_REG(0x0294)
-#define CR166 CTL_REG(0x0298)
-#define CR167 CTL_REG(0x029C)
-#define CR168 CTL_REG(0x02A0)
-#define CR169 CTL_REG(0x02A4)
-#define CR170 CTL_REG(0x02A8)
-#define CR171 CTL_REG(0x02AC)
-#define CR172 CTL_REG(0x02B0)
-#define CR173 CTL_REG(0x02B4)
-#define CR174 CTL_REG(0x02B8)
-#define CR175 CTL_REG(0x02BC)
-#define CR176 CTL_REG(0x02C0)
-#define CR177 CTL_REG(0x02C4)
-#define CR178 CTL_REG(0x02C8)
-#define CR179 CTL_REG(0x02CC)
-#define CR180 CTL_REG(0x02D0)
-#define CR181 CTL_REG(0x02D4)
-#define CR182 CTL_REG(0x02D8)
-#define CR183 CTL_REG(0x02DC)
-#define CR184 CTL_REG(0x02E0)
-#define CR185 CTL_REG(0x02E4)
-#define CR186 CTL_REG(0x02E8)
-#define CR187 CTL_REG(0x02EC)
-#define CR188 CTL_REG(0x02F0)
-#define CR189 CTL_REG(0x02F4)
-#define CR190 CTL_REG(0x02F8)
-#define CR191 CTL_REG(0x02FC)
-#define CR192 CTL_REG(0x0300)
-#define CR193 CTL_REG(0x0304)
-#define CR194 CTL_REG(0x0308)
-#define CR195 CTL_REG(0x030C)
-#define CR196 CTL_REG(0x0310)
-#define CR197 CTL_REG(0x0314)
-#define CR198 CTL_REG(0x0318)
-#define CR199 CTL_REG(0x031C)
-#define CR200 CTL_REG(0x0320)
-#define CR201 CTL_REG(0x0324)
-#define CR202 CTL_REG(0x0328)
-#define CR203 CTL_REG(0x032C)	/* I2C bus template value & flash control */
-#define CR204 CTL_REG(0x0330)
-#define CR205 CTL_REG(0x0334)
-#define CR206 CTL_REG(0x0338)
-#define CR207 CTL_REG(0x033C)
-#define CR208 CTL_REG(0x0340)
-#define CR209 CTL_REG(0x0344)
-#define CR210 CTL_REG(0x0348)
-#define CR211 CTL_REG(0x034C)
-#define CR212 CTL_REG(0x0350)
-#define CR213 CTL_REG(0x0354)
-#define CR214 CTL_REG(0x0358)
-#define CR215 CTL_REG(0x035C)
-#define CR216 CTL_REG(0x0360)
-#define CR217 CTL_REG(0x0364)
-#define CR218 CTL_REG(0x0368)
-#define CR219 CTL_REG(0x036C)
-#define CR220 CTL_REG(0x0370)
-#define CR221 CTL_REG(0x0374)
-#define CR222 CTL_REG(0x0378)
-#define CR223 CTL_REG(0x037C)
-#define CR224 CTL_REG(0x0380)
-#define CR225 CTL_REG(0x0384)
-#define CR226 CTL_REG(0x0388)
-#define CR227 CTL_REG(0x038C)
-#define CR228 CTL_REG(0x0390)
-#define CR229 CTL_REG(0x0394)
-#define CR230 CTL_REG(0x0398)
-#define CR231 CTL_REG(0x039C)
-#define CR232 CTL_REG(0x03A0)
-#define CR233 CTL_REG(0x03A4)
-#define CR234 CTL_REG(0x03A8)
-#define CR235 CTL_REG(0x03AC)
-#define CR236 CTL_REG(0x03B0)
+#define ZD_CR12  CTL_REG(0x0030)
+#define ZD_CR13  CTL_REG(0x0034)
+#define ZD_CR14  CTL_REG(0x0038)
+#define ZD_CR15  CTL_REG(0x003C)
+#define ZD_CR16  CTL_REG(0x0040)
+#define ZD_CR17  CTL_REG(0x0044)
+#define ZD_CR18  CTL_REG(0x0048)
+#define ZD_CR19  CTL_REG(0x004C)
+#define ZD_CR20  CTL_REG(0x0050)
+#define ZD_CR21  CTL_REG(0x0054)
+#define ZD_CR22  CTL_REG(0x0058)
+#define ZD_CR23  CTL_REG(0x005C)
+#define ZD_CR24  CTL_REG(0x0060)	/* CCA threshold */
+#define ZD_CR25  CTL_REG(0x0064)
+#define ZD_CR26  CTL_REG(0x0068)
+#define ZD_CR27  CTL_REG(0x006C)
+#define ZD_CR28  CTL_REG(0x0070)
+#define ZD_CR29  CTL_REG(0x0074)
+#define ZD_CR30  CTL_REG(0x0078)
+#define ZD_CR31  CTL_REG(0x007C)	/* TX power control for RF in
+					 * CCK mode
+					 */
+#define ZD_CR32  CTL_REG(0x0080)
+#define ZD_CR33  CTL_REG(0x0084)
+#define ZD_CR34  CTL_REG(0x0088)
+#define ZD_CR35  CTL_REG(0x008C)
+#define ZD_CR36  CTL_REG(0x0090)
+#define ZD_CR37  CTL_REG(0x0094)
+#define ZD_CR38  CTL_REG(0x0098)
+#define ZD_CR39  CTL_REG(0x009C)
+#define ZD_CR40  CTL_REG(0x00A0)
+#define ZD_CR41  CTL_REG(0x00A4)
+#define ZD_CR42  CTL_REG(0x00A8)
+#define ZD_CR43  CTL_REG(0x00AC)
+#define ZD_CR44  CTL_REG(0x00B0)
+#define ZD_CR45  CTL_REG(0x00B4)
+#define ZD_CR46  CTL_REG(0x00B8)
+#define ZD_CR47  CTL_REG(0x00BC)	/* CCK baseband gain
+					 * (patch value might be in EEPROM)
+					 */
+#define ZD_CR48  CTL_REG(0x00C0)
+#define ZD_CR49  CTL_REG(0x00C4)
+#define ZD_CR50  CTL_REG(0x00C8)
+#define ZD_CR51  CTL_REG(0x00CC)	/* TX power control for RF in
+					 * 6-36M modes
+					 */
+#define ZD_CR52  CTL_REG(0x00D0)	/* TX power control for RF in
+					 * 48M mode
+					 */
+#define ZD_CR53  CTL_REG(0x00D4)	/* TX power control for RF in
+					 * 54M mode
+					 */
+#define ZD_CR54  CTL_REG(0x00D8)
+#define ZD_CR55  CTL_REG(0x00DC)
+#define ZD_CR56  CTL_REG(0x00E0)
+#define ZD_CR57  CTL_REG(0x00E4)
+#define ZD_CR58  CTL_REG(0x00E8)
+#define ZD_CR59  CTL_REG(0x00EC)
+#define ZD_CR60  CTL_REG(0x00F0)
+#define ZD_CR61  CTL_REG(0x00F4)
+#define ZD_CR62  CTL_REG(0x00F8)
+#define ZD_CR63  CTL_REG(0x00FC)
+#define ZD_CR64  CTL_REG(0x0100)
+#define ZD_CR65  CTL_REG(0x0104) /* OFDM 54M calibration */
+#define ZD_CR66  CTL_REG(0x0108) /* OFDM 48M calibration */
+#define ZD_CR67  CTL_REG(0x010C) /* OFDM 36M calibration */
+#define ZD_CR68  CTL_REG(0x0110) /* CCK calibration */
+#define ZD_CR69  CTL_REG(0x0114)
+#define ZD_CR70  CTL_REG(0x0118)
+#define ZD_CR71  CTL_REG(0x011C)
+#define ZD_CR72  CTL_REG(0x0120)
+#define ZD_CR73  CTL_REG(0x0124)
+#define ZD_CR74  CTL_REG(0x0128)
+#define ZD_CR75  CTL_REG(0x012C)
+#define ZD_CR76  CTL_REG(0x0130)
+#define ZD_CR77  CTL_REG(0x0134)
+#define ZD_CR78  CTL_REG(0x0138)
+#define ZD_CR79  CTL_REG(0x013C)
+#define ZD_CR80  CTL_REG(0x0140)
+#define ZD_CR81  CTL_REG(0x0144)
+#define ZD_CR82  CTL_REG(0x0148)
+#define ZD_CR83  CTL_REG(0x014C)
+#define ZD_CR84  CTL_REG(0x0150)
+#define ZD_CR85  CTL_REG(0x0154)
+#define ZD_CR86  CTL_REG(0x0158)
+#define ZD_CR87  CTL_REG(0x015C)
+#define ZD_CR88  CTL_REG(0x0160)
+#define ZD_CR89  CTL_REG(0x0164)
+#define ZD_CR90  CTL_REG(0x0168)
+#define ZD_CR91  CTL_REG(0x016C)
+#define ZD_CR92  CTL_REG(0x0170)
+#define ZD_CR93  CTL_REG(0x0174)
+#define ZD_CR94  CTL_REG(0x0178)
+#define ZD_CR95  CTL_REG(0x017C)
+#define ZD_CR96  CTL_REG(0x0180)
+#define ZD_CR97  CTL_REG(0x0184)
+#define ZD_CR98  CTL_REG(0x0188)
+#define ZD_CR99  CTL_REG(0x018C)
+#define ZD_CR100 CTL_REG(0x0190)
+#define ZD_CR101 CTL_REG(0x0194)
+#define ZD_CR102 CTL_REG(0x0198)
+#define ZD_CR103 CTL_REG(0x019C)
+#define ZD_CR104 CTL_REG(0x01A0)
+#define ZD_CR105 CTL_REG(0x01A4)
+#define ZD_CR106 CTL_REG(0x01A8)
+#define ZD_CR107 CTL_REG(0x01AC)
+#define ZD_CR108 CTL_REG(0x01B0)
+#define ZD_CR109 CTL_REG(0x01B4)
+#define ZD_CR110 CTL_REG(0x01B8)
+#define ZD_CR111 CTL_REG(0x01BC)
+#define ZD_CR112 CTL_REG(0x01C0)
+#define ZD_CR113 CTL_REG(0x01C4)
+#define ZD_CR114 CTL_REG(0x01C8)
+#define ZD_CR115 CTL_REG(0x01CC)
+#define ZD_CR116 CTL_REG(0x01D0)
+#define ZD_CR117 CTL_REG(0x01D4)
+#define ZD_CR118 CTL_REG(0x01D8)
+#define ZD_CR119 CTL_REG(0x01DC)
+#define ZD_CR120 CTL_REG(0x01E0)
+#define ZD_CR121 CTL_REG(0x01E4)
+#define ZD_CR122 CTL_REG(0x01E8)
+#define ZD_CR123 CTL_REG(0x01EC)
+#define ZD_CR124 CTL_REG(0x01F0)
+#define ZD_CR125 CTL_REG(0x01F4)
+#define ZD_CR126 CTL_REG(0x01F8)
+#define ZD_CR127 CTL_REG(0x01FC)
+#define ZD_CR128 CTL_REG(0x0200)
+#define ZD_CR129 CTL_REG(0x0204)
+#define ZD_CR130 CTL_REG(0x0208)
+#define ZD_CR131 CTL_REG(0x020C)
+#define ZD_CR132 CTL_REG(0x0210)
+#define ZD_CR133 CTL_REG(0x0214)
+#define ZD_CR134 CTL_REG(0x0218)
+#define ZD_CR135 CTL_REG(0x021C)
+#define ZD_CR136 CTL_REG(0x0220)
+#define ZD_CR137 CTL_REG(0x0224)
+#define ZD_CR138 CTL_REG(0x0228)
+#define ZD_CR139 CTL_REG(0x022C)
+#define ZD_CR140 CTL_REG(0x0230)
+#define ZD_CR141 CTL_REG(0x0234)
+#define ZD_CR142 CTL_REG(0x0238)
+#define ZD_CR143 CTL_REG(0x023C)
+#define ZD_CR144 CTL_REG(0x0240)
+#define ZD_CR145 CTL_REG(0x0244)
+#define ZD_CR146 CTL_REG(0x0248)
+#define ZD_CR147 CTL_REG(0x024C)
+#define ZD_CR148 CTL_REG(0x0250)
+#define ZD_CR149 CTL_REG(0x0254)
+#define ZD_CR150 CTL_REG(0x0258)
+#define ZD_CR151 CTL_REG(0x025C)
+#define ZD_CR152 CTL_REG(0x0260)
+#define ZD_CR153 CTL_REG(0x0264)
+#define ZD_CR154 CTL_REG(0x0268)
+#define ZD_CR155 CTL_REG(0x026C)
+#define ZD_CR156 CTL_REG(0x0270)
+#define ZD_CR157 CTL_REG(0x0274)
+#define ZD_CR158 CTL_REG(0x0278)
+#define ZD_CR159 CTL_REG(0x027C)
+#define ZD_CR160 CTL_REG(0x0280)
+#define ZD_CR161 CTL_REG(0x0284)
+#define ZD_CR162 CTL_REG(0x0288)
+#define ZD_CR163 CTL_REG(0x028C)
+#define ZD_CR164 CTL_REG(0x0290)
+#define ZD_CR165 CTL_REG(0x0294)
+#define ZD_CR166 CTL_REG(0x0298)
+#define ZD_CR167 CTL_REG(0x029C)
+#define ZD_CR168 CTL_REG(0x02A0)
+#define ZD_CR169 CTL_REG(0x02A4)
+#define ZD_CR170 CTL_REG(0x02A8)
+#define ZD_CR171 CTL_REG(0x02AC)
+#define ZD_CR172 CTL_REG(0x02B0)
+#define ZD_CR173 CTL_REG(0x02B4)
+#define ZD_CR174 CTL_REG(0x02B8)
+#define ZD_CR175 CTL_REG(0x02BC)
+#define ZD_CR176 CTL_REG(0x02C0)
+#define ZD_CR177 CTL_REG(0x02C4)
+#define ZD_CR178 CTL_REG(0x02C8)
+#define ZD_CR179 CTL_REG(0x02CC)
+#define ZD_CR180 CTL_REG(0x02D0)
+#define ZD_CR181 CTL_REG(0x02D4)
+#define ZD_CR182 CTL_REG(0x02D8)
+#define ZD_CR183 CTL_REG(0x02DC)
+#define ZD_CR184 CTL_REG(0x02E0)
+#define ZD_CR185 CTL_REG(0x02E4)
+#define ZD_CR186 CTL_REG(0x02E8)
+#define ZD_CR187 CTL_REG(0x02EC)
+#define ZD_CR188 CTL_REG(0x02F0)
+#define ZD_CR189 CTL_REG(0x02F4)
+#define ZD_CR190 CTL_REG(0x02F8)
+#define ZD_CR191 CTL_REG(0x02FC)
+#define ZD_CR192 CTL_REG(0x0300)
+#define ZD_CR193 CTL_REG(0x0304)
+#define ZD_CR194 CTL_REG(0x0308)
+#define ZD_CR195 CTL_REG(0x030C)
+#define ZD_CR196 CTL_REG(0x0310)
+#define ZD_CR197 CTL_REG(0x0314)
+#define ZD_CR198 CTL_REG(0x0318)
+#define ZD_CR199 CTL_REG(0x031C)
+#define ZD_CR200 CTL_REG(0x0320)
+#define ZD_CR201 CTL_REG(0x0324)
+#define ZD_CR202 CTL_REG(0x0328)
+#define ZD_CR203 CTL_REG(0x032C)	/* I2C bus template value & flash
+					 * control
+					 */
+#define ZD_CR204 CTL_REG(0x0330)
+#define ZD_CR205 CTL_REG(0x0334)
+#define ZD_CR206 CTL_REG(0x0338)
+#define ZD_CR207 CTL_REG(0x033C)
+#define ZD_CR208 CTL_REG(0x0340)
+#define ZD_CR209 CTL_REG(0x0344)
+#define ZD_CR210 CTL_REG(0x0348)
+#define ZD_CR211 CTL_REG(0x034C)
+#define ZD_CR212 CTL_REG(0x0350)
+#define ZD_CR213 CTL_REG(0x0354)
+#define ZD_CR214 CTL_REG(0x0358)
+#define ZD_CR215 CTL_REG(0x035C)
+#define ZD_CR216 CTL_REG(0x0360)
+#define ZD_CR217 CTL_REG(0x0364)
+#define ZD_CR218 CTL_REG(0x0368)
+#define ZD_CR219 CTL_REG(0x036C)
+#define ZD_CR220 CTL_REG(0x0370)
+#define ZD_CR221 CTL_REG(0x0374)
+#define ZD_CR222 CTL_REG(0x0378)
+#define ZD_CR223 CTL_REG(0x037C)
+#define ZD_CR224 CTL_REG(0x0380)
+#define ZD_CR225 CTL_REG(0x0384)
+#define ZD_CR226 CTL_REG(0x0388)
+#define ZD_CR227 CTL_REG(0x038C)
+#define ZD_CR228 CTL_REG(0x0390)
+#define ZD_CR229 CTL_REG(0x0394)
+#define ZD_CR230 CTL_REG(0x0398)
+#define ZD_CR231 CTL_REG(0x039C)
+#define ZD_CR232 CTL_REG(0x03A0)
+#define ZD_CR233 CTL_REG(0x03A4)
+#define ZD_CR234 CTL_REG(0x03A8)
+#define ZD_CR235 CTL_REG(0x03AC)
+#define ZD_CR236 CTL_REG(0x03B0)
 
-#define CR240 CTL_REG(0x03C0)
-/*	bit 7:  host-controlled RF register writes
- * CR241-CR245: for hardware controlled writing of RF bits, not needed for
- *              USB
+#define ZD_CR240 CTL_REG(0x03C0)
+/*             bit 7: host-controlled RF register writes
+ * ZD_CR241-ZD_CR245: for hardware controlled writing of RF bits, not needed for
+ *                    USB
  */
-#define CR241 CTL_REG(0x03C4)
-#define CR242 CTL_REG(0x03C8)
-#define CR243 CTL_REG(0x03CC)
-#define CR244 CTL_REG(0x03D0)
-#define CR245 CTL_REG(0x03D4)
+#define ZD_CR241 CTL_REG(0x03C4)
+#define ZD_CR242 CTL_REG(0x03C8)
+#define ZD_CR243 CTL_REG(0x03CC)
+#define ZD_CR244 CTL_REG(0x03D0)
+#define ZD_CR245 CTL_REG(0x03D4)
 
-#define CR251 CTL_REG(0x03EC)	/* only used for activation and deactivation of
-				 * Airoha RFs AL2230 and AL7230B
-				 */
-#define CR252 CTL_REG(0x03F0)
-#define CR253 CTL_REG(0x03F4)
-#define CR254 CTL_REG(0x03F8)
-#define CR255 CTL_REG(0x03FC)
+#define ZD_CR251 CTL_REG(0x03EC)	/* only used for activation and
+					 * deactivation of Airoha RFs AL2230
+					 * and AL7230B
+					 */
+#define ZD_CR252 CTL_REG(0x03F0)
+#define ZD_CR253 CTL_REG(0x03F4)
+#define ZD_CR254 CTL_REG(0x03F8)
+#define ZD_CR255 CTL_REG(0x03FC)
 
 #define CR_MAX_PHY_REG 255
 
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h
index 79dc103..725b7c9 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf.h
+++ b/drivers/net/wireless/zd1211rw/zd_rf.h
@@ -55,7 +55,7 @@
 	 * defaults to 1 (yes) */
 	u8 update_channel_int:1;
 
-	/* whether CR47 should be patched from the EEPROM, if the appropriate
+	/* whether ZD_CR47 should be patched from the EEPROM, if the appropriate
 	 * flag is set in the POD. The vendor driver suggests that this should
 	 * be done for all RF's, but a bug in their code prevents but their
 	 * HW_OverWritePhyRegFromE2P() routine from ever taking effect. */
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
index 74a8f7a..12babcb 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
@@ -61,31 +61,31 @@
 };
 
 static const struct zd_ioreq16 zd1211b_ioreqs_shared_1[] = {
-	{ CR240, 0x57 }, { CR9,   0xe0 },
+	{ ZD_CR240, 0x57 }, { ZD_CR9,   0xe0 },
 };
 
 static const struct zd_ioreq16 ioreqs_init_al2230s[] = {
-	{ CR47,   0x1e }, /* MARK_002 */
-	{ CR106,  0x22 },
-	{ CR107,  0x2a }, /* MARK_002 */
-	{ CR109,  0x13 }, /* MARK_002 */
-	{ CR118,  0xf8 }, /* MARK_002 */
-	{ CR119,  0x12 }, { CR122,  0xe0 },
-	{ CR128,  0x10 }, /* MARK_001 from 0xe->0x10 */
-	{ CR129,  0x0e }, /* MARK_001 from 0xd->0x0e */
-	{ CR130,  0x10 }, /* MARK_001 from 0xb->0x0d */
+	{ ZD_CR47,   0x1e }, /* MARK_002 */
+	{ ZD_CR106,  0x22 },
+	{ ZD_CR107,  0x2a }, /* MARK_002 */
+	{ ZD_CR109,  0x13 }, /* MARK_002 */
+	{ ZD_CR118,  0xf8 }, /* MARK_002 */
+	{ ZD_CR119,  0x12 }, { ZD_CR122,  0xe0 },
+	{ ZD_CR128,  0x10 }, /* MARK_001 from 0xe->0x10 */
+	{ ZD_CR129,  0x0e }, /* MARK_001 from 0xd->0x0e */
+	{ ZD_CR130,  0x10 }, /* MARK_001 from 0xb->0x0d */
 };
 
 static int zd1211b_al2230_finalize_rf(struct zd_chip *chip)
 {
 	int r;
 	static const struct zd_ioreq16 ioreqs[] = {
-		{ CR80,  0x30 }, { CR81,  0x30 }, { CR79,  0x58 },
-		{ CR12,  0xf0 }, { CR77,  0x1b }, { CR78,  0x58 },
-		{ CR203, 0x06 },
+		{ ZD_CR80,  0x30 }, { ZD_CR81,  0x30 }, { ZD_CR79,  0x58 },
+		{ ZD_CR12,  0xf0 }, { ZD_CR77,  0x1b }, { ZD_CR78,  0x58 },
+		{ ZD_CR203, 0x06 },
 		{ },
 
-		{ CR240, 0x80 },
+		{ ZD_CR240, 0x80 },
 	};
 
 	r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
@@ -94,12 +94,12 @@
 
 	/* related to antenna selection? */
 	if (chip->new_phy_layout) {
-		r = zd_iowrite16_locked(chip, 0xe1, CR9);
+		r = zd_iowrite16_locked(chip, 0xe1, ZD_CR9);
 		if (r)
 			return r;
 	}
 
-	return zd_iowrite16_locked(chip, 0x06, CR203);
+	return zd_iowrite16_locked(chip, 0x06, ZD_CR203);
 }
 
 static int zd1211_al2230_init_hw(struct zd_rf *rf)
@@ -108,40 +108,40 @@
 	struct zd_chip *chip = zd_rf_to_chip(rf);
 
 	static const struct zd_ioreq16 ioreqs_init[] = {
-		{ CR15,   0x20 }, { CR23,   0x40 }, { CR24,  0x20 },
-		{ CR26,   0x11 }, { CR28,   0x3e }, { CR29,  0x00 },
-		{ CR44,   0x33 }, { CR106,  0x2a }, { CR107, 0x1a },
-		{ CR109,  0x09 }, { CR110,  0x27 }, { CR111, 0x2b },
-		{ CR112,  0x2b }, { CR119,  0x0a }, { CR10,  0x89 },
+		{ ZD_CR15,   0x20 }, { ZD_CR23,   0x40 }, { ZD_CR24,  0x20 },
+		{ ZD_CR26,   0x11 }, { ZD_CR28,   0x3e }, { ZD_CR29,  0x00 },
+		{ ZD_CR44,   0x33 }, { ZD_CR106,  0x2a }, { ZD_CR107, 0x1a },
+		{ ZD_CR109,  0x09 }, { ZD_CR110,  0x27 }, { ZD_CR111, 0x2b },
+		{ ZD_CR112,  0x2b }, { ZD_CR119,  0x0a }, { ZD_CR10,  0x89 },
 		/* for newest (3rd cut) AL2300 */
-		{ CR17,   0x28 },
-		{ CR26,   0x93 }, { CR34,   0x30 },
+		{ ZD_CR17,   0x28 },
+		{ ZD_CR26,   0x93 }, { ZD_CR34,   0x30 },
 		/* for newest (3rd cut) AL2300 */
-		{ CR35,   0x3e },
-		{ CR41,   0x24 }, { CR44,   0x32 },
+		{ ZD_CR35,   0x3e },
+		{ ZD_CR41,   0x24 }, { ZD_CR44,   0x32 },
 		/* for newest (3rd cut) AL2300 */
-		{ CR46,   0x96 },
-		{ CR47,   0x1e }, { CR79,   0x58 }, { CR80,  0x30 },
-		{ CR81,   0x30 }, { CR87,   0x0a }, { CR89,  0x04 },
-		{ CR92,   0x0a }, { CR99,   0x28 }, { CR100, 0x00 },
-		{ CR101,  0x13 }, { CR102,  0x27 }, { CR106, 0x24 },
-		{ CR107,  0x2a }, { CR109,  0x09 }, { CR110, 0x13 },
-		{ CR111,  0x1f }, { CR112,  0x1f }, { CR113, 0x27 },
-		{ CR114,  0x27 },
+		{ ZD_CR46,   0x96 },
+		{ ZD_CR47,   0x1e }, { ZD_CR79,   0x58 }, { ZD_CR80,  0x30 },
+		{ ZD_CR81,   0x30 }, { ZD_CR87,   0x0a }, { ZD_CR89,  0x04 },
+		{ ZD_CR92,   0x0a }, { ZD_CR99,   0x28 }, { ZD_CR100, 0x00 },
+		{ ZD_CR101,  0x13 }, { ZD_CR102,  0x27 }, { ZD_CR106, 0x24 },
+		{ ZD_CR107,  0x2a }, { ZD_CR109,  0x09 }, { ZD_CR110, 0x13 },
+		{ ZD_CR111,  0x1f }, { ZD_CR112,  0x1f }, { ZD_CR113, 0x27 },
+		{ ZD_CR114,  0x27 },
 		/* for newest (3rd cut) AL2300 */
-		{ CR115,  0x24 },
-		{ CR116,  0x24 }, { CR117,  0xf4 }, { CR118, 0xfc },
-		{ CR119,  0x10 }, { CR120,  0x4f }, { CR121, 0x77 },
-		{ CR122,  0xe0 }, { CR137,  0x88 }, { CR252, 0xff },
-		{ CR253,  0xff },
+		{ ZD_CR115,  0x24 },
+		{ ZD_CR116,  0x24 }, { ZD_CR117,  0xf4 }, { ZD_CR118, 0xfc },
+		{ ZD_CR119,  0x10 }, { ZD_CR120,  0x4f }, { ZD_CR121, 0x77 },
+		{ ZD_CR122,  0xe0 }, { ZD_CR137,  0x88 }, { ZD_CR252, 0xff },
+		{ ZD_CR253,  0xff },
 	};
 
 	static const struct zd_ioreq16 ioreqs_pll[] = {
 		/* shdnb(PLL_ON)=0 */
-		{ CR251,  0x2f },
+		{ ZD_CR251,  0x2f },
 		/* shdnb(PLL_ON)=1 */
-		{ CR251,  0x3f },
-		{ CR138,  0x28 }, { CR203,  0x06 },
+		{ ZD_CR251,  0x3f },
+		{ ZD_CR138,  0x28 }, { ZD_CR203,  0x06 },
 	};
 
 	static const u32 rv1[] = {
@@ -161,7 +161,7 @@
 		0x0805b6,
 		0x011687,
 		0x000688,
-		0x0403b9, /* external control TX power (CR31) */
+		0x0403b9, /* external control TX power (ZD_CR31) */
 		0x00dbba,
 		0x00099b,
 		0x0bdffc,
@@ -221,52 +221,54 @@
 	struct zd_chip *chip = zd_rf_to_chip(rf);
 
 	static const struct zd_ioreq16 ioreqs1[] = {
-		{ CR10,  0x89 }, { CR15,  0x20 },
-		{ CR17,  0x2B }, /* for newest(3rd cut) AL2230 */
-		{ CR23,  0x40 }, { CR24,  0x20 }, { CR26,  0x93 },
-		{ CR28,  0x3e }, { CR29,  0x00 },
-		{ CR33,  0x28 }, /* 5621 */
-		{ CR34,  0x30 },
-		{ CR35,  0x3e }, /* for newest(3rd cut) AL2230 */
-		{ CR41,  0x24 }, { CR44,  0x32 },
-		{ CR46,  0x99 }, /* for newest(3rd cut) AL2230 */
-		{ CR47,  0x1e },
+		{ ZD_CR10,  0x89 }, { ZD_CR15,  0x20 },
+		{ ZD_CR17,  0x2B }, /* for newest(3rd cut) AL2230 */
+		{ ZD_CR23,  0x40 }, { ZD_CR24,  0x20 }, { ZD_CR26,  0x93 },
+		{ ZD_CR28,  0x3e }, { ZD_CR29,  0x00 },
+		{ ZD_CR33,  0x28 }, /* 5621 */
+		{ ZD_CR34,  0x30 },
+		{ ZD_CR35,  0x3e }, /* for newest(3rd cut) AL2230 */
+		{ ZD_CR41,  0x24 }, { ZD_CR44,  0x32 },
+		{ ZD_CR46,  0x99 }, /* for newest(3rd cut) AL2230 */
+		{ ZD_CR47,  0x1e },
 
 		/* ZD1211B 05.06.10 */
-		{ CR48,  0x06 }, { CR49,  0xf9 }, { CR51,  0x01 },
-		{ CR52,  0x80 }, { CR53,  0x7e }, { CR65,  0x00 },
-		{ CR66,  0x00 }, { CR67,  0x00 }, { CR68,  0x00 },
-		{ CR69,  0x28 },
+		{ ZD_CR48,  0x06 }, { ZD_CR49,  0xf9 }, { ZD_CR51,  0x01 },
+		{ ZD_CR52,  0x80 }, { ZD_CR53,  0x7e }, { ZD_CR65,  0x00 },
+		{ ZD_CR66,  0x00 }, { ZD_CR67,  0x00 }, { ZD_CR68,  0x00 },
+		{ ZD_CR69,  0x28 },
 
-		{ CR79,  0x58 }, { CR80,  0x30 }, { CR81,  0x30 },
-		{ CR87,  0x0a }, { CR89,  0x04 },
-		{ CR91,  0x00 }, /* 5621 */
-		{ CR92,  0x0a },
-		{ CR98,  0x8d }, /* 4804,  for 1212 new algorithm */
-		{ CR99,  0x00 }, /* 5621 */
-		{ CR101, 0x13 }, { CR102, 0x27 },
-		{ CR106, 0x24 }, /* for newest(3rd cut) AL2230 */
-		{ CR107, 0x2a },
-		{ CR109, 0x13 }, /* 4804, for 1212 new algorithm */
-		{ CR110, 0x1f }, /* 4804, for 1212 new algorithm */
-		{ CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 },
-		{ CR114, 0x27 },
-		{ CR115, 0x26 }, /* 24->26 at 4902 for newest(3rd cut) AL2230 */
-		{ CR116, 0x24 },
-		{ CR117, 0xfa }, /* for 1211b */
-		{ CR118, 0xfa }, /* for 1211b */
-		{ CR119, 0x10 },
-		{ CR120, 0x4f },
-		{ CR121, 0x6c }, /* for 1211b */
-		{ CR122, 0xfc }, /* E0->FC at 4902 */
-		{ CR123, 0x57 }, /* 5623 */
-		{ CR125, 0xad }, /* 4804, for 1212 new algorithm */
-		{ CR126, 0x6c }, /* 5614 */
-		{ CR127, 0x03 }, /* 4804, for 1212 new algorithm */
-		{ CR137, 0x50 }, /* 5614 */
-		{ CR138, 0xa8 },
-		{ CR144, 0xac }, /* 5621 */
-		{ CR150, 0x0d }, { CR252, 0x34 }, { CR253, 0x34 },
+		{ ZD_CR79,  0x58 }, { ZD_CR80,  0x30 }, { ZD_CR81,  0x30 },
+		{ ZD_CR87,  0x0a }, { ZD_CR89,  0x04 },
+		{ ZD_CR91,  0x00 }, /* 5621 */
+		{ ZD_CR92,  0x0a },
+		{ ZD_CR98,  0x8d }, /* 4804,  for 1212 new algorithm */
+		{ ZD_CR99,  0x00 }, /* 5621 */
+		{ ZD_CR101, 0x13 }, { ZD_CR102, 0x27 },
+		{ ZD_CR106, 0x24 }, /* for newest(3rd cut) AL2230 */
+		{ ZD_CR107, 0x2a },
+		{ ZD_CR109, 0x13 }, /* 4804, for 1212 new algorithm */
+		{ ZD_CR110, 0x1f }, /* 4804, for 1212 new algorithm */
+		{ ZD_CR111, 0x1f }, { ZD_CR112, 0x1f }, { ZD_CR113, 0x27 },
+		{ ZD_CR114, 0x27 },
+		{ ZD_CR115, 0x26 }, /* 24->26 at 4902 for newest(3rd cut)
+				     * AL2230
+				     */
+		{ ZD_CR116, 0x24 },
+		{ ZD_CR117, 0xfa }, /* for 1211b */
+		{ ZD_CR118, 0xfa }, /* for 1211b */
+		{ ZD_CR119, 0x10 },
+		{ ZD_CR120, 0x4f },
+		{ ZD_CR121, 0x6c }, /* for 1211b */
+		{ ZD_CR122, 0xfc }, /* E0->FC at 4902 */
+		{ ZD_CR123, 0x57 }, /* 5623 */
+		{ ZD_CR125, 0xad }, /* 4804, for 1212 new algorithm */
+		{ ZD_CR126, 0x6c }, /* 5614 */
+		{ ZD_CR127, 0x03 }, /* 4804, for 1212 new algorithm */
+		{ ZD_CR137, 0x50 }, /* 5614 */
+		{ ZD_CR138, 0xa8 },
+		{ ZD_CR144, 0xac }, /* 5621 */
+		{ ZD_CR150, 0x0d }, { ZD_CR252, 0x34 }, { ZD_CR253, 0x34 },
 	};
 
 	static const u32 rv1[] = {
@@ -284,7 +286,7 @@
 		0x6da010, /* Reg6 update for MP versio */
 		0xe36280, /* Modified by jxiao for Bor-Chin on 2004/08/02 */
 		0x116000,
-		0x9dc020, /* External control TX power (CR31) */
+		0x9dc020, /* External control TX power (ZD_CR31) */
 		0x5ddb00, /* RegA update for MP version */
 		0xd99000, /* RegB update for MP version */
 		0x3ffbd0, /* RegC update for MP version */
@@ -295,8 +297,8 @@
 	};
 
 	static const struct zd_ioreq16 ioreqs2[] = {
-		{ CR251, 0x2f }, /* shdnb(PLL_ON)=0 */
-		{ CR251, 0x7f }, /* shdnb(PLL_ON)=1 */
+		{ ZD_CR251, 0x2f }, /* shdnb(PLL_ON)=0 */
+		{ ZD_CR251, 0x7f }, /* shdnb(PLL_ON)=1 */
 	};
 
 	static const u32 rv3[] = {
@@ -308,7 +310,7 @@
 
 	static const struct zd_ioreq16 ioreqs3[] = {
 		/* related to 6M band edge patching, happens unconditionally */
-		{ CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
+		{ ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 },
 	};
 
 	r = zd_iowrite16a_locked(chip, zd1211b_ioreqs_shared_1,
@@ -361,8 +363,8 @@
 	const u32 *rv = zd1211_al2230_table[channel-1];
 	struct zd_chip *chip = zd_rf_to_chip(rf);
 	static const struct zd_ioreq16 ioreqs[] = {
-		{ CR138, 0x28 },
-		{ CR203, 0x06 },
+		{ ZD_CR138, 0x28 },
+		{ ZD_CR203, 0x06 },
 	};
 
 	r = zd_rfwritev_locked(chip, rv, 3, RF_RV_BITS);
@@ -393,8 +395,8 @@
 {
 	struct zd_chip *chip = zd_rf_to_chip(rf);
 	static const struct zd_ioreq16 ioreqs[] = {
-		{ CR11,  0x00 },
-		{ CR251, 0x3f },
+		{ ZD_CR11,  0x00 },
+		{ ZD_CR251, 0x3f },
 	};
 
 	return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
@@ -404,8 +406,8 @@
 {
 	struct zd_chip *chip = zd_rf_to_chip(rf);
 	static const struct zd_ioreq16 ioreqs[] = {
-		{ CR11,  0x00 },
-		{ CR251, 0x7f },
+		{ ZD_CR11,  0x00 },
+		{ ZD_CR251, 0x7f },
 	};
 
 	return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
@@ -415,8 +417,8 @@
 {
 	struct zd_chip *chip = zd_rf_to_chip(rf);
 	static const struct zd_ioreq16 ioreqs[] = {
-		{ CR11,  0x04 },
-		{ CR251, 0x2f },
+		{ ZD_CR11,  0x04 },
+		{ ZD_CR251, 0x2f },
 	};
 
 	return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
index 65095d6..385c670 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
@@ -68,19 +68,19 @@
 };
 
 static const struct zd_ioreq16 ioreqs_sw[] = {
-	{ CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
-	{ CR38,  0x38 }, { CR136, 0xdf },
+	{ ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 },
+	{ ZD_CR38,  0x38 }, { ZD_CR136, 0xdf },
 };
 
 static int zd1211b_al7230b_finalize(struct zd_chip *chip)
 {
 	int r;
 	static const struct zd_ioreq16 ioreqs[] = {
-		{ CR80,  0x30 }, { CR81,  0x30 }, { CR79,  0x58 },
-		{ CR12,  0xf0 }, { CR77,  0x1b }, { CR78,  0x58 },
-		{ CR203, 0x04 },
+		{ ZD_CR80,  0x30 }, { ZD_CR81,  0x30 }, { ZD_CR79,  0x58 },
+		{ ZD_CR12,  0xf0 }, { ZD_CR77,  0x1b }, { ZD_CR78,  0x58 },
+		{ ZD_CR203, 0x04 },
 		{ },
-		{ CR240, 0x80 },
+		{ ZD_CR240, 0x80 },
 	};
 
 	r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
@@ -89,12 +89,12 @@
 
 	if (chip->new_phy_layout) {
 		/* antenna selection? */
-		r = zd_iowrite16_locked(chip, 0xe5, CR9);
+		r = zd_iowrite16_locked(chip, 0xe5, ZD_CR9);
 		if (r)
 			return r;
 	}
 
-	return zd_iowrite16_locked(chip, 0x04, CR203);
+	return zd_iowrite16_locked(chip, 0x04, ZD_CR203);
 }
 
 static int zd1211_al7230b_init_hw(struct zd_rf *rf)
@@ -106,66 +106,66 @@
 	 * specified */
 	static const struct zd_ioreq16 ioreqs_1[] = {
 		/* This one is 7230-specific, and happens before the rest */
-		{ CR240,  0x57 },
+		{ ZD_CR240,  0x57 },
 		{ },
 
-		{ CR15,   0x20 }, { CR23,   0x40 }, { CR24,  0x20 },
-		{ CR26,   0x11 }, { CR28,   0x3e }, { CR29,  0x00 },
-		{ CR44,   0x33 },
+		{ ZD_CR15,   0x20 }, { ZD_CR23,   0x40 }, { ZD_CR24,  0x20 },
+		{ ZD_CR26,   0x11 }, { ZD_CR28,   0x3e }, { ZD_CR29,  0x00 },
+		{ ZD_CR44,   0x33 },
 		/* This value is different for 7230 (was: 0x2a) */
-		{ CR106,  0x22 },
-		{ CR107,  0x1a }, { CR109,  0x09 }, { CR110,  0x27 },
-		{ CR111,  0x2b }, { CR112,  0x2b }, { CR119,  0x0a },
+		{ ZD_CR106,  0x22 },
+		{ ZD_CR107,  0x1a }, { ZD_CR109,  0x09 }, { ZD_CR110,  0x27 },
+		{ ZD_CR111,  0x2b }, { ZD_CR112,  0x2b }, { ZD_CR119,  0x0a },
 		/* This happened further down in AL2230,
 		 * and the value changed (was: 0xe0) */
-		{ CR122,  0xfc },
-		{ CR10,   0x89 },
+		{ ZD_CR122,  0xfc },
+		{ ZD_CR10,   0x89 },
 		/* for newest (3rd cut) AL2300 */
-		{ CR17,   0x28 },
-		{ CR26,   0x93 }, { CR34,   0x30 },
+		{ ZD_CR17,   0x28 },
+		{ ZD_CR26,   0x93 }, { ZD_CR34,   0x30 },
 		/* for newest (3rd cut) AL2300 */
-		{ CR35,   0x3e },
-		{ CR41,   0x24 }, { CR44,   0x32 },
+		{ ZD_CR35,   0x3e },
+		{ ZD_CR41,   0x24 }, { ZD_CR44,   0x32 },
 		/* for newest (3rd cut) AL2300 */
-		{ CR46,   0x96 },
-		{ CR47,   0x1e }, { CR79,   0x58 }, { CR80,  0x30 },
-		{ CR81,   0x30 }, { CR87,   0x0a }, { CR89,  0x04 },
-		{ CR92,   0x0a }, { CR99,   0x28 },
+		{ ZD_CR46,   0x96 },
+		{ ZD_CR47,   0x1e }, { ZD_CR79,   0x58 }, { ZD_CR80,  0x30 },
+		{ ZD_CR81,   0x30 }, { ZD_CR87,   0x0a }, { ZD_CR89,  0x04 },
+		{ ZD_CR92,   0x0a }, { ZD_CR99,   0x28 },
 		/* This value is different for 7230 (was: 0x00) */
-		{ CR100,  0x02 },
-		{ CR101,  0x13 }, { CR102,  0x27 },
+		{ ZD_CR100,  0x02 },
+		{ ZD_CR101,  0x13 }, { ZD_CR102,  0x27 },
 		/* This value is different for 7230 (was: 0x24) */
-		{ CR106,  0x22 },
+		{ ZD_CR106,  0x22 },
 		/* This value is different for 7230 (was: 0x2a) */
-		{ CR107,  0x3f },
-		{ CR109,  0x09 },
+		{ ZD_CR107,  0x3f },
+		{ ZD_CR109,  0x09 },
 		/* This value is different for 7230 (was: 0x13) */
-		{ CR110,  0x1f },
-		{ CR111,  0x1f }, { CR112,  0x1f }, { CR113, 0x27 },
-		{ CR114,  0x27 },
+		{ ZD_CR110,  0x1f },
+		{ ZD_CR111,  0x1f }, { ZD_CR112,  0x1f }, { ZD_CR113, 0x27 },
+		{ ZD_CR114,  0x27 },
 		/* for newest (3rd cut) AL2300 */
-		{ CR115,  0x24 },
+		{ ZD_CR115,  0x24 },
 		/* This value is different for 7230 (was: 0x24) */
-		{ CR116,  0x3f },
+		{ ZD_CR116,  0x3f },
 		/* This value is different for 7230 (was: 0xf4) */
-		{ CR117,  0xfa },
-		{ CR118,  0xfc }, { CR119,  0x10 }, { CR120, 0x4f },
-		{ CR121,  0x77 }, { CR137,  0x88 },
+		{ ZD_CR117,  0xfa },
+		{ ZD_CR118,  0xfc }, { ZD_CR119,  0x10 }, { ZD_CR120, 0x4f },
+		{ ZD_CR121,  0x77 }, { ZD_CR137,  0x88 },
 		/* This one is 7230-specific */
-		{ CR138,  0xa8 },
+		{ ZD_CR138,  0xa8 },
 		/* This value is different for 7230 (was: 0xff) */
-		{ CR252,  0x34 },
+		{ ZD_CR252,  0x34 },
 		/* This value is different for 7230 (was: 0xff) */
-		{ CR253,  0x34 },
+		{ ZD_CR253,  0x34 },
 
 		/* PLL_OFF */
-		{ CR251, 0x2f },
+		{ ZD_CR251, 0x2f },
 	};
 
 	static const struct zd_ioreq16 ioreqs_2[] = {
-		{ CR251, 0x3f }, /* PLL_ON */
-		{ CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
-		{ CR38,  0x38 }, { CR136, 0xdf },
+		{ ZD_CR251, 0x3f }, /* PLL_ON */
+		{ ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 },
+		{ ZD_CR38,  0x38 }, { ZD_CR136, 0xdf },
 	};
 
 	r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1));
@@ -192,10 +192,10 @@
 	if (r)
 		return r;
 
-	r = zd_iowrite16_locked(chip, 0x06, CR203);
+	r = zd_iowrite16_locked(chip, 0x06, ZD_CR203);
 	if (r)
 		return r;
-	r = zd_iowrite16_locked(chip, 0x80, CR240);
+	r = zd_iowrite16_locked(chip, 0x80, ZD_CR240);
 	if (r)
 		return r;
 
@@ -208,79 +208,79 @@
 	struct zd_chip *chip = zd_rf_to_chip(rf);
 
 	static const struct zd_ioreq16 ioreqs_1[] = {
-		{ CR240, 0x57 }, { CR9,   0x9 },
+		{ ZD_CR240, 0x57 }, { ZD_CR9,   0x9 },
 		{ },
-		{ CR10,  0x8b }, { CR15,  0x20 },
-		{ CR17,  0x2B }, /* for newest (3rd cut) AL2230 */
-		{ CR20,  0x10 }, /* 4N25->Stone Request */
-		{ CR23,  0x40 }, { CR24,  0x20 }, { CR26,  0x93 },
-		{ CR28,  0x3e }, { CR29,  0x00 },
-		{ CR33,  0x28 }, /* 5613 */
-		{ CR34,  0x30 },
-		{ CR35,  0x3e }, /* for newest (3rd cut) AL2230 */
-		{ CR41,  0x24 }, { CR44,  0x32 },
-		{ CR46,  0x99 }, /* for newest (3rd cut) AL2230 */
-		{ CR47,  0x1e },
+		{ ZD_CR10,  0x8b }, { ZD_CR15,  0x20 },
+		{ ZD_CR17,  0x2B }, /* for newest (3rd cut) AL2230 */
+		{ ZD_CR20,  0x10 }, /* 4N25->Stone Request */
+		{ ZD_CR23,  0x40 }, { ZD_CR24,  0x20 }, { ZD_CR26,  0x93 },
+		{ ZD_CR28,  0x3e }, { ZD_CR29,  0x00 },
+		{ ZD_CR33,  0x28 }, /* 5613 */
+		{ ZD_CR34,  0x30 },
+		{ ZD_CR35,  0x3e }, /* for newest (3rd cut) AL2230 */
+		{ ZD_CR41,  0x24 }, { ZD_CR44,  0x32 },
+		{ ZD_CR46,  0x99 }, /* for newest (3rd cut) AL2230 */
+		{ ZD_CR47,  0x1e },
 
 		/* ZD1215 5610 */
-		{ CR48,  0x00 }, { CR49,  0x00 }, { CR51,  0x01 },
-		{ CR52,  0x80 }, { CR53,  0x7e }, { CR65,  0x00 },
-		{ CR66,  0x00 }, { CR67,  0x00 }, { CR68,  0x00 },
-		{ CR69,  0x28 },
+		{ ZD_CR48,  0x00 }, { ZD_CR49,  0x00 }, { ZD_CR51,  0x01 },
+		{ ZD_CR52,  0x80 }, { ZD_CR53,  0x7e }, { ZD_CR65,  0x00 },
+		{ ZD_CR66,  0x00 }, { ZD_CR67,  0x00 }, { ZD_CR68,  0x00 },
+		{ ZD_CR69,  0x28 },
 
-		{ CR79,  0x58 }, { CR80,  0x30 }, { CR81,  0x30 },
-		{ CR87,  0x0A }, { CR89,  0x04 },
-		{ CR90,  0x58 }, /* 5112 */
-		{ CR91,  0x00 }, /* 5613 */
-		{ CR92,  0x0a },
-		{ CR98,  0x8d }, /* 4804, for 1212 new algorithm */
-		{ CR99,  0x00 }, { CR100, 0x02 }, { CR101, 0x13 },
-		{ CR102, 0x27 },
-		{ CR106, 0x20 }, /* change to 0x24 for AL7230B */
-		{ CR109, 0x13 }, /* 4804, for 1212 new algorithm */
-		{ CR112, 0x1f },
+		{ ZD_CR79,  0x58 }, { ZD_CR80,  0x30 }, { ZD_CR81,  0x30 },
+		{ ZD_CR87,  0x0A }, { ZD_CR89,  0x04 },
+		{ ZD_CR90,  0x58 }, /* 5112 */
+		{ ZD_CR91,  0x00 }, /* 5613 */
+		{ ZD_CR92,  0x0a },
+		{ ZD_CR98,  0x8d }, /* 4804, for 1212 new algorithm */
+		{ ZD_CR99,  0x00 }, { ZD_CR100, 0x02 }, { ZD_CR101, 0x13 },
+		{ ZD_CR102, 0x27 },
+		{ ZD_CR106, 0x20 }, /* change to 0x24 for AL7230B */
+		{ ZD_CR109, 0x13 }, /* 4804, for 1212 new algorithm */
+		{ ZD_CR112, 0x1f },
 	};
 
 	static const struct zd_ioreq16 ioreqs_new_phy[] = {
-		{ CR107, 0x28 },
-		{ CR110, 0x1f }, /* 5127, 0x13->0x1f */
-		{ CR111, 0x1f }, /* 0x13 to 0x1f for AL7230B */
-		{ CR116, 0x2a }, { CR118, 0xfa }, { CR119, 0x12 },
-		{ CR121, 0x6c }, /* 5613 */
+		{ ZD_CR107, 0x28 },
+		{ ZD_CR110, 0x1f }, /* 5127, 0x13->0x1f */
+		{ ZD_CR111, 0x1f }, /* 0x13 to 0x1f for AL7230B */
+		{ ZD_CR116, 0x2a }, { ZD_CR118, 0xfa }, { ZD_CR119, 0x12 },
+		{ ZD_CR121, 0x6c }, /* 5613 */
 	};
 
 	static const struct zd_ioreq16 ioreqs_old_phy[] = {
-		{ CR107, 0x24 },
-		{ CR110, 0x13 }, /* 5127, 0x13->0x1f */
-		{ CR111, 0x13 }, /* 0x13 to 0x1f for AL7230B */
-		{ CR116, 0x24 }, { CR118, 0xfc }, { CR119, 0x11 },
-		{ CR121, 0x6a }, /* 5613 */
+		{ ZD_CR107, 0x24 },
+		{ ZD_CR110, 0x13 }, /* 5127, 0x13->0x1f */
+		{ ZD_CR111, 0x13 }, /* 0x13 to 0x1f for AL7230B */
+		{ ZD_CR116, 0x24 }, { ZD_CR118, 0xfc }, { ZD_CR119, 0x11 },
+		{ ZD_CR121, 0x6a }, /* 5613 */
 	};
 
 	static const struct zd_ioreq16 ioreqs_2[] = {
-		{ CR113, 0x27 }, { CR114, 0x27 }, { CR115, 0x24 },
-		{ CR117, 0xfa }, { CR120, 0x4f },
-		{ CR122, 0xfc }, /* E0->FCh at 4901 */
-		{ CR123, 0x57 }, /* 5613 */
-		{ CR125, 0xad }, /* 4804, for 1212 new algorithm */
-		{ CR126, 0x6c }, /* 5613 */
-		{ CR127, 0x03 }, /* 4804, for 1212 new algorithm */
-		{ CR130, 0x10 },
-		{ CR131, 0x00 }, /* 5112 */
-		{ CR137, 0x50 }, /* 5613 */
-		{ CR138, 0xa8 }, /* 5112 */
-		{ CR144, 0xac }, /* 5613 */
-		{ CR148, 0x40 }, /* 5112 */
-		{ CR149, 0x40 }, /* 4O07, 50->40 */
-		{ CR150, 0x1a }, /* 5112, 0C->1A */
-		{ CR252, 0x34 }, { CR253, 0x34 },
-		{ CR251, 0x2f }, /* PLL_OFF */
+		{ ZD_CR113, 0x27 }, { ZD_CR114, 0x27 }, { ZD_CR115, 0x24 },
+		{ ZD_CR117, 0xfa }, { ZD_CR120, 0x4f },
+		{ ZD_CR122, 0xfc }, /* E0->FCh at 4901 */
+		{ ZD_CR123, 0x57 }, /* 5613 */
+		{ ZD_CR125, 0xad }, /* 4804, for 1212 new algorithm */
+		{ ZD_CR126, 0x6c }, /* 5613 */
+		{ ZD_CR127, 0x03 }, /* 4804, for 1212 new algorithm */
+		{ ZD_CR130, 0x10 },
+		{ ZD_CR131, 0x00 }, /* 5112 */
+		{ ZD_CR137, 0x50 }, /* 5613 */
+		{ ZD_CR138, 0xa8 }, /* 5112 */
+		{ ZD_CR144, 0xac }, /* 5613 */
+		{ ZD_CR148, 0x40 }, /* 5112 */
+		{ ZD_CR149, 0x40 }, /* 4O07, 50->40 */
+		{ ZD_CR150, 0x1a }, /* 5112, 0C->1A */
+		{ ZD_CR252, 0x34 }, { ZD_CR253, 0x34 },
+		{ ZD_CR251, 0x2f }, /* PLL_OFF */
 	};
 
 	static const struct zd_ioreq16 ioreqs_3[] = {
-		{ CR251, 0x7f }, /* PLL_ON */
-		{ CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
-		{ CR38,  0x38 }, { CR136, 0xdf },
+		{ ZD_CR251, 0x7f }, /* PLL_ON */
+		{ ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 },
+		{ ZD_CR38,  0x38 }, { ZD_CR136, 0xdf },
 	};
 
 	r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1));
@@ -331,16 +331,16 @@
 
 	static const struct zd_ioreq16 ioreqs[] = {
 		/* PLL_ON */
-		{ CR251, 0x3f },
-		{ CR203, 0x06 }, { CR240, 0x08 },
+		{ ZD_CR251, 0x3f },
+		{ ZD_CR203, 0x06 }, { ZD_CR240, 0x08 },
 	};
 
-	r = zd_iowrite16_locked(chip, 0x57, CR240);
+	r = zd_iowrite16_locked(chip, 0x57, ZD_CR240);
 	if (r)
 		return r;
 
 	/* PLL_OFF */
-	r = zd_iowrite16_locked(chip, 0x2f, CR251);
+	r = zd_iowrite16_locked(chip, 0x2f, ZD_CR251);
 	if (r)
 		return r;
 
@@ -376,15 +376,15 @@
 	const u32 *rv = chan_rv[channel-1];
 	struct zd_chip *chip = zd_rf_to_chip(rf);
 
-	r = zd_iowrite16_locked(chip, 0x57, CR240);
+	r = zd_iowrite16_locked(chip, 0x57, ZD_CR240);
 	if (r)
 		return r;
-	r = zd_iowrite16_locked(chip, 0xe4, CR9);
+	r = zd_iowrite16_locked(chip, 0xe4, ZD_CR9);
 	if (r)
 		return r;
 
 	/* PLL_OFF */
-	r = zd_iowrite16_locked(chip, 0x2f, CR251);
+	r = zd_iowrite16_locked(chip, 0x2f, ZD_CR251);
 	if (r)
 		return r;
 	r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv));
@@ -410,7 +410,7 @@
 	if (r)
 		return r;
 
-	r = zd_iowrite16_locked(chip, 0x7f, CR251);
+	r = zd_iowrite16_locked(chip, 0x7f, ZD_CR251);
 	if (r)
 		return r;
 
@@ -421,8 +421,8 @@
 {
 	struct zd_chip *chip = zd_rf_to_chip(rf);
 	static const struct zd_ioreq16 ioreqs[] = {
-		{ CR11,  0x00 },
-		{ CR251, 0x3f },
+		{ ZD_CR11,  0x00 },
+		{ ZD_CR251, 0x3f },
 	};
 
 	return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
@@ -432,8 +432,8 @@
 {
 	struct zd_chip *chip = zd_rf_to_chip(rf);
 	static const struct zd_ioreq16 ioreqs[] = {
-		{ CR11,  0x00 },
-		{ CR251, 0x7f },
+		{ ZD_CR11,  0x00 },
+		{ ZD_CR251, 0x7f },
 	};
 
 	return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
@@ -443,8 +443,8 @@
 {
 	struct zd_chip *chip = zd_rf_to_chip(rf);
 	static const struct zd_ioreq16 ioreqs[] = {
-		{ CR11,  0x04 },
-		{ CR251, 0x2f },
+		{ ZD_CR11,  0x04 },
+		{ ZD_CR251, 0x2f },
 	};
 
 	return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
@@ -456,7 +456,7 @@
 {
 	struct zd_chip *chip = zd_rf_to_chip(rf);
 	struct zd_ioreq16 ioreqs[] = {
-		{ CR128, 0x14 }, { CR129, 0x12 },
+		{ ZD_CR128, 0x14 }, { ZD_CR129, 0x12 },
 	};
 
 	/* FIXME: Channel 11 is not the edge for all regulatory domains. */
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
index 0597d86..0325426 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
@@ -152,44 +152,44 @@
 	struct zd_chip *chip = zd_rf_to_chip(rf);
 
 	static const struct zd_ioreq16 ioreqs[] = {
-		{ CR2,   0x1E }, { CR9,   0x20 }, { CR10,  0x89 },
-		{ CR11,  0x00 }, { CR15,  0xD0 }, { CR17,  0x68 },
-		{ CR19,  0x4a }, { CR20,  0x0c }, { CR21,  0x0E },
-		{ CR23,  0x48 },
+		{ ZD_CR2,   0x1E }, { ZD_CR9,   0x20 }, { ZD_CR10,  0x89 },
+		{ ZD_CR11,  0x00 }, { ZD_CR15,  0xD0 }, { ZD_CR17,  0x68 },
+		{ ZD_CR19,  0x4a }, { ZD_CR20,  0x0c }, { ZD_CR21,  0x0E },
+		{ ZD_CR23,  0x48 },
 		/* normal size for cca threshold */
-		{ CR24,  0x14 },
-		/* { CR24,  0x20 }, */
-		{ CR26,  0x90 }, { CR27,  0x30 }, { CR29,  0x20 },
-		{ CR31,  0xb2 }, { CR32,  0x43 }, { CR33,  0x28 },
-		{ CR38,  0x30 }, { CR34,  0x0f }, { CR35,  0xF0 },
-		{ CR41,  0x2a }, { CR46,  0x7F }, { CR47,  0x1E },
-		{ CR51,  0xc5 }, { CR52,  0xc5 }, { CR53,  0xc5 },
-		{ CR79,  0x58 }, { CR80,  0x30 }, { CR81,  0x30 },
-		{ CR82,  0x00 }, { CR83,  0x24 }, { CR84,  0x04 },
-		{ CR85,  0x00 }, { CR86,  0x10 }, { CR87,  0x2A },
-		{ CR88,  0x10 }, { CR89,  0x24 }, { CR90,  0x18 },
-		/* { CR91,  0x18 }, */
+		{ ZD_CR24,  0x14 },
+		/* { ZD_CR24,  0x20 }, */
+		{ ZD_CR26,  0x90 }, { ZD_CR27,  0x30 }, { ZD_CR29,  0x20 },
+		{ ZD_CR31,  0xb2 }, { ZD_CR32,  0x43 }, { ZD_CR33,  0x28 },
+		{ ZD_CR38,  0x30 }, { ZD_CR34,  0x0f }, { ZD_CR35,  0xF0 },
+		{ ZD_CR41,  0x2a }, { ZD_CR46,  0x7F }, { ZD_CR47,  0x1E },
+		{ ZD_CR51,  0xc5 }, { ZD_CR52,  0xc5 }, { ZD_CR53,  0xc5 },
+		{ ZD_CR79,  0x58 }, { ZD_CR80,  0x30 }, { ZD_CR81,  0x30 },
+		{ ZD_CR82,  0x00 }, { ZD_CR83,  0x24 }, { ZD_CR84,  0x04 },
+		{ ZD_CR85,  0x00 }, { ZD_CR86,  0x10 }, { ZD_CR87,  0x2A },
+		{ ZD_CR88,  0x10 }, { ZD_CR89,  0x24 }, { ZD_CR90,  0x18 },
+		/* { ZD_CR91,  0x18 }, */
 		/* should solve continous CTS frame problems */
-		{ CR91,  0x00 },
-		{ CR92,  0x0a }, { CR93,  0x00 }, { CR94,  0x01 },
-		{ CR95,  0x00 }, { CR96,  0x40 }, { CR97,  0x37 },
-		{ CR98,  0x05 }, { CR99,  0x28 }, { CR100, 0x00 },
-		{ CR101, 0x13 }, { CR102, 0x27 }, { CR103, 0x27 },
-		{ CR104, 0x18 }, { CR105, 0x12 },
+		{ ZD_CR91,  0x00 },
+		{ ZD_CR92,  0x0a }, { ZD_CR93,  0x00 }, { ZD_CR94,  0x01 },
+		{ ZD_CR95,  0x00 }, { ZD_CR96,  0x40 }, { ZD_CR97,  0x37 },
+		{ ZD_CR98,  0x05 }, { ZD_CR99,  0x28 }, { ZD_CR100, 0x00 },
+		{ ZD_CR101, 0x13 }, { ZD_CR102, 0x27 }, { ZD_CR103, 0x27 },
+		{ ZD_CR104, 0x18 }, { ZD_CR105, 0x12 },
 		/* normal size */
-		{ CR106, 0x1a },
-		/* { CR106, 0x22 }, */
-		{ CR107, 0x24 }, { CR108, 0x0a }, { CR109, 0x13 },
-		{ CR110, 0x2F }, { CR111, 0x27 }, { CR112, 0x27 },
-		{ CR113, 0x27 }, { CR114, 0x27 }, { CR115, 0x40 },
-		{ CR116, 0x40 }, { CR117, 0xF0 }, { CR118, 0xF0 },
-		{ CR119, 0x16 },
+		{ ZD_CR106, 0x1a },
+		/* { ZD_CR106, 0x22 }, */
+		{ ZD_CR107, 0x24 }, { ZD_CR108, 0x0a }, { ZD_CR109, 0x13 },
+		{ ZD_CR110, 0x2F }, { ZD_CR111, 0x27 }, { ZD_CR112, 0x27 },
+		{ ZD_CR113, 0x27 }, { ZD_CR114, 0x27 }, { ZD_CR115, 0x40 },
+		{ ZD_CR116, 0x40 }, { ZD_CR117, 0xF0 }, { ZD_CR118, 0xF0 },
+		{ ZD_CR119, 0x16 },
 		/* no TX continuation */
-		{ CR122, 0x00 },
-		/* { CR122, 0xff }, */
-		{ CR127, 0x03 }, { CR131, 0x08 }, { CR138, 0x28 },
-		{ CR148, 0x44 }, { CR150, 0x10 }, { CR169, 0xBB },
-		{ CR170, 0xBB },
+		{ ZD_CR122, 0x00 },
+		/* { ZD_CR122, 0xff }, */
+		{ ZD_CR127, 0x03 }, { ZD_CR131, 0x08 }, { ZD_CR138, 0x28 },
+		{ ZD_CR148, 0x44 }, { ZD_CR150, 0x10 }, { ZD_CR169, 0xBB },
+		{ ZD_CR170, 0xBB },
 	};
 
 	static const u32 rv[] = {
@@ -210,7 +210,7 @@
 		 */
 		0x294128, /* internal power */
 		/* 0x28252c, */ /* External control TX power */
-		/* CR31_CCK, CR51_6-36M, CR52_48M, CR53_54M */
+		/* ZD_CR31_CCK, ZD_CR51_6-36M, ZD_CR52_48M, ZD_CR53_54M */
 		0x2c0000,
 		0x300000,
 		0x340000,  /* REG13(0xD) */
@@ -245,8 +245,8 @@
 static int rf2959_switch_radio_on(struct zd_rf *rf)
 {
 	static const struct zd_ioreq16 ioreqs[] = {
-		{ CR10, 0x89 },
-		{ CR11, 0x00 },
+		{ ZD_CR10, 0x89 },
+		{ ZD_CR11, 0x00 },
 	};
 	struct zd_chip *chip = zd_rf_to_chip(rf);
 
@@ -256,8 +256,8 @@
 static int rf2959_switch_radio_off(struct zd_rf *rf)
 {
 	static const struct zd_ioreq16 ioreqs[] = {
-		{ CR10, 0x15 },
-		{ CR11, 0x81 },
+		{ ZD_CR10, 0x15 },
+		{ ZD_CR11, 0x81 },
 	};
 	struct zd_chip *chip = zd_rf_to_chip(rf);
 
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c
index 9e74eb1..860b0af 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c
@@ -314,42 +314,44 @@
 	struct zd_chip *chip = zd_rf_to_chip(rf);
 
 	static const struct zd_ioreq16 ioreqs[] = {
-		{ CR10,  0x89 }, { CR15,  0x20 },
-		{ CR17,  0x28 }, /* 6112 no change */
-		{ CR23,  0x38 }, { CR24,  0x20 }, { CR26,  0x93 },
-		{ CR27,  0x15 }, { CR28,  0x3e }, { CR29,  0x00 },
-		{ CR33,  0x28 }, { CR34,  0x30 },
-		{ CR35,  0x43 }, /* 6112 3e->43 */
-		{ CR41,  0x24 }, { CR44,  0x32 },
-		{ CR46,  0x92 }, /* 6112 96->92 */
-		{ CR47,  0x1e },
-		{ CR48,  0x04 }, /* 5602 Roger */
-		{ CR49,  0xfa }, { CR79,  0x58 }, { CR80,  0x30 },
-		{ CR81,  0x30 }, { CR87,  0x0a }, { CR89,  0x04 },
-		{ CR91,  0x00 }, { CR92,  0x0a }, { CR98,  0x8d },
-		{ CR99,  0x28 }, { CR100, 0x02 },
-		{ CR101, 0x09 }, /* 6112 13->1f 6220 1f->13 6407 13->9 */
-		{ CR102, 0x27 },
-		{ CR106, 0x1c }, /* 5d07 5112 1f->1c 6220 1c->1f 6221 1f->1c */
-		{ CR107, 0x1c }, /* 6220 1c->1a 5221 1a->1c */
-		{ CR109, 0x13 },
-		{ CR110, 0x1f }, /* 6112 13->1f 6221 1f->13 6407 13->0x09 */
-		{ CR111, 0x13 }, { CR112, 0x1f }, { CR113, 0x27 },
-		{ CR114, 0x23 }, /* 6221 27->23 */
-		{ CR115, 0x24 }, /* 6112 24->1c 6220 1c->24 */
-		{ CR116, 0x24 }, /* 6220 1c->24 */
-		{ CR117, 0xfa }, /* 6112 fa->f8 6220 f8->f4 6220 f4->fa */
-		{ CR118, 0xf0 }, /* 5d07 6112 f0->f2 6220 f2->f0 */
-		{ CR119, 0x1a }, /* 6112 1a->10 6220 10->14 6220 14->1a */
-		{ CR120, 0x4f },
-		{ CR121, 0x1f }, /* 6220 4f->1f */
-		{ CR122, 0xf0 }, { CR123, 0x57 }, { CR125, 0xad },
-		{ CR126, 0x6c }, { CR127, 0x03 },
-		{ CR128, 0x14 }, /* 6302 12->11 */
-		{ CR129, 0x12 }, /* 6301 10->0f */
-		{ CR130, 0x10 }, { CR137, 0x50 }, { CR138, 0xa8 },
-		{ CR144, 0xac }, { CR146, 0x20 }, { CR252, 0xff },
-		{ CR253, 0xff },
+		{ ZD_CR10,  0x89 }, { ZD_CR15,  0x20 },
+		{ ZD_CR17,  0x28 }, /* 6112 no change */
+		{ ZD_CR23,  0x38 }, { ZD_CR24,  0x20 }, { ZD_CR26,  0x93 },
+		{ ZD_CR27,  0x15 }, { ZD_CR28,  0x3e }, { ZD_CR29,  0x00 },
+		{ ZD_CR33,  0x28 }, { ZD_CR34,  0x30 },
+		{ ZD_CR35,  0x43 }, /* 6112 3e->43 */
+		{ ZD_CR41,  0x24 }, { ZD_CR44,  0x32 },
+		{ ZD_CR46,  0x92 }, /* 6112 96->92 */
+		{ ZD_CR47,  0x1e },
+		{ ZD_CR48,  0x04 }, /* 5602 Roger */
+		{ ZD_CR49,  0xfa }, { ZD_CR79,  0x58 }, { ZD_CR80,  0x30 },
+		{ ZD_CR81,  0x30 }, { ZD_CR87,  0x0a }, { ZD_CR89,  0x04 },
+		{ ZD_CR91,  0x00 }, { ZD_CR92,  0x0a }, { ZD_CR98,  0x8d },
+		{ ZD_CR99,  0x28 }, { ZD_CR100, 0x02 },
+		{ ZD_CR101, 0x09 }, /* 6112 13->1f 6220 1f->13 6407 13->9 */
+		{ ZD_CR102, 0x27 },
+		{ ZD_CR106, 0x1c }, /* 5d07 5112 1f->1c 6220 1c->1f
+				     * 6221 1f->1c
+				     */
+		{ ZD_CR107, 0x1c }, /* 6220 1c->1a 5221 1a->1c */
+		{ ZD_CR109, 0x13 },
+		{ ZD_CR110, 0x1f }, /* 6112 13->1f 6221 1f->13 6407 13->0x09 */
+		{ ZD_CR111, 0x13 }, { ZD_CR112, 0x1f }, { ZD_CR113, 0x27 },
+		{ ZD_CR114, 0x23 }, /* 6221 27->23 */
+		{ ZD_CR115, 0x24 }, /* 6112 24->1c 6220 1c->24 */
+		{ ZD_CR116, 0x24 }, /* 6220 1c->24 */
+		{ ZD_CR117, 0xfa }, /* 6112 fa->f8 6220 f8->f4 6220 f4->fa */
+		{ ZD_CR118, 0xf0 }, /* 5d07 6112 f0->f2 6220 f2->f0 */
+		{ ZD_CR119, 0x1a }, /* 6112 1a->10 6220 10->14 6220 14->1a */
+		{ ZD_CR120, 0x4f },
+		{ ZD_CR121, 0x1f }, /* 6220 4f->1f */
+		{ ZD_CR122, 0xf0 }, { ZD_CR123, 0x57 }, { ZD_CR125, 0xad },
+		{ ZD_CR126, 0x6c }, { ZD_CR127, 0x03 },
+		{ ZD_CR128, 0x14 }, /* 6302 12->11 */
+		{ ZD_CR129, 0x12 }, /* 6301 10->0f */
+		{ ZD_CR130, 0x10 }, { ZD_CR137, 0x50 }, { ZD_CR138, 0xa8 },
+		{ ZD_CR144, 0xac }, { ZD_CR146, 0x20 }, { ZD_CR252, 0xff },
+		{ ZD_CR253, 0xff },
 	};
 
 	static const u32 rv[] = {
@@ -433,7 +435,7 @@
 	 * the one that produced a lock. */
 	UW2453_PRIV(rf)->config = found_config + 1;
 
-	return zd_iowrite16_locked(chip, 0x06, CR203);
+	return zd_iowrite16_locked(chip, 0x06, ZD_CR203);
 }
 
 static int uw2453_set_channel(struct zd_rf *rf, u8 channel)
@@ -445,8 +447,8 @@
 	struct zd_chip *chip = zd_rf_to_chip(rf);
 
 	static const struct zd_ioreq16 ioreqs[] = {
-		{ CR80,  0x30 }, { CR81,  0x30 }, { CR79,  0x58 },
-		{ CR12,  0xf0 }, { CR77,  0x1b }, { CR78,  0x58 },
+		{ ZD_CR80,  0x30 }, { ZD_CR81,  0x30 }, { ZD_CR79,  0x58 },
+		{ ZD_CR12,  0xf0 }, { ZD_CR77,  0x1b }, { ZD_CR78,  0x58 },
 	};
 
 	r = uw2453_synth_set_channel(chip, channel, autocal);
@@ -474,7 +476,7 @@
 	if (r)
 		return r;
 
-	return zd_iowrite16_locked(chip, 0x06, CR203);
+	return zd_iowrite16_locked(chip, 0x06, ZD_CR203);
 }
 
 static int uw2453_switch_radio_on(struct zd_rf *rf)
@@ -482,7 +484,7 @@
 	int r;
 	struct zd_chip *chip = zd_rf_to_chip(rf);
 	struct zd_ioreq16 ioreqs[] = {
-		{ CR11,  0x00 }, { CR251, 0x3f },
+		{ ZD_CR11,  0x00 }, { ZD_CR251, 0x3f },
 	};
 
 	/* enter RXTX mode */
@@ -501,7 +503,7 @@
 	int r;
 	struct zd_chip *chip = zd_rf_to_chip(rf);
 	static const struct zd_ioreq16 ioreqs[] = {
-		{ CR11,  0x04 }, { CR251, 0x2f },
+		{ ZD_CR11,  0x04 }, { ZD_CR251, 0x2f },
 	};
 
 	/* enter IDLE mode */
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index ab607bb..0e81994 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -1893,10 +1893,10 @@
 
 	dev_dbg_f(zd_usb_dev(usb), "value %#09x bits %d\n", value, bits);
 
-	r = zd_usb_ioread16(usb, &bit_value_template, CR203);
+	r = zd_usb_ioread16(usb, &bit_value_template, ZD_CR203);
 	if (r) {
 		dev_dbg_f(zd_usb_dev(usb),
-			"error %d: Couldn't read CR203\n", r);
+			"error %d: Couldn't read ZD_CR203\n", r);
 		return r;
 	}
 	bit_value_template &= ~(RF_IF_LE|RF_CLK|RF_DATA);
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h
index 325d0f9..bf94284 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.h
+++ b/drivers/net/wireless/zd1211rw/zd_usb.h
@@ -109,7 +109,7 @@
 	__le16 bits;
 	/* RF2595: 24 */
 	__le16 bit_values[0];
-	/* (CR203 & ~(RF_IF_LE | RF_CLK | RF_DATA)) | (bit ? RF_DATA : 0) */
+	/* (ZD_CR203 & ~(RF_IF_LE | RF_CLK | RF_DATA)) | (bit ? RF_DATA : 0) */
 } __packed;
 
 /* USB interrupt */
diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c
index 0e8d352..1ba9f0e 100644
--- a/drivers/ssb/driver_pcicore.c
+++ b/drivers/ssb/driver_pcicore.c
@@ -15,6 +15,11 @@
 
 #include "ssb_private.h"
 
+static u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address);
+static void ssb_pcie_write(struct ssb_pcicore *pc, u32 address, u32 data);
+static u16 ssb_pcie_mdio_read(struct ssb_pcicore *pc, u8 device, u8 address);
+static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device,
+				u8 address, u16 data);
 
 static inline
 u32 pcicore_read32(struct ssb_pcicore *pc, u16 offset)
@@ -403,6 +408,27 @@
 }
 #endif /* CONFIG_SSB_PCICORE_HOSTMODE */
 
+/**************************************************
+ * Workarounds.
+ **************************************************/
+
+static u8 ssb_pcicore_polarity_workaround(struct ssb_pcicore *pc)
+{
+	return (ssb_pcie_read(pc, 0x204) & 0x10) ? 0xC0 : 0x80;
+}
+
+static void ssb_pcicore_serdes_workaround(struct ssb_pcicore *pc)
+{
+	const u8 serdes_pll_device = 0x1D;
+	const u8 serdes_rx_device = 0x1F;
+	u16 tmp;
+
+	ssb_pcie_mdio_write(pc, serdes_rx_device, 1 /* Control */,
+			    ssb_pcicore_polarity_workaround(pc));
+	tmp = ssb_pcie_mdio_read(pc, serdes_pll_device, 1 /* Control */);
+	if (tmp & 0x4000)
+		ssb_pcie_mdio_write(pc, serdes_pll_device, 1, tmp & ~0x4000);
+}
 
 /**************************************************
  * Generic and Clientmode operation code.
@@ -417,11 +443,9 @@
 void ssb_pcicore_init(struct ssb_pcicore *pc)
 {
 	struct ssb_device *dev = pc->dev;
-	struct ssb_bus *bus;
 
 	if (!dev)
 		return;
-	bus = dev->bus;
 	if (!ssb_device_is_enabled(dev))
 		ssb_device_enable(dev, 0);
 
@@ -432,6 +456,8 @@
 #endif /* CONFIG_SSB_PCICORE_HOSTMODE */
 	if (!pc->hostmode)
 		ssb_pcicore_init_clientmode(pc);
+
+	ssb_pcicore_serdes_workaround(pc);
 }
 
 static u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address)
@@ -446,28 +472,98 @@
 	pcicore_write32(pc, 0x134, data);
 }
 
-static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device,
-				u8 address, u16 data)
+static void ssb_pcie_mdio_set_phy(struct ssb_pcicore *pc, u8 phy)
 {
 	const u16 mdio_control = 0x128;
 	const u16 mdio_data = 0x12C;
 	u32 v;
 	int i;
 
+	v = (1 << 30); /* Start of Transaction */
+	v |= (1 << 28); /* Write Transaction */
+	v |= (1 << 17); /* Turnaround */
+	v |= (0x1F << 18);
+	v |= (phy << 4);
+	pcicore_write32(pc, mdio_data, v);
+
+	udelay(10);
+	for (i = 0; i < 200; i++) {
+		v = pcicore_read32(pc, mdio_control);
+		if (v & 0x100 /* Trans complete */)
+			break;
+		msleep(1);
+	}
+}
+
+static u16 ssb_pcie_mdio_read(struct ssb_pcicore *pc, u8 device, u8 address)
+{
+	const u16 mdio_control = 0x128;
+	const u16 mdio_data = 0x12C;
+	int max_retries = 10;
+	u16 ret = 0;
+	u32 v;
+	int i;
+
 	v = 0x80; /* Enable Preamble Sequence */
 	v |= 0x2; /* MDIO Clock Divisor */
 	pcicore_write32(pc, mdio_control, v);
 
+	if (pc->dev->id.revision >= 10) {
+		max_retries = 200;
+		ssb_pcie_mdio_set_phy(pc, device);
+	}
+
+	v = (1 << 30); /* Start of Transaction */
+	v |= (1 << 29); /* Read Transaction */
+	v |= (1 << 17); /* Turnaround */
+	if (pc->dev->id.revision < 10)
+		v |= (u32)device << 22;
+	v |= (u32)address << 18;
+	pcicore_write32(pc, mdio_data, v);
+	/* Wait for the device to complete the transaction */
+	udelay(10);
+	for (i = 0; i < 200; i++) {
+		v = pcicore_read32(pc, mdio_control);
+		if (v & 0x100 /* Trans complete */) {
+			udelay(10);
+			ret = pcicore_read32(pc, mdio_data);
+			break;
+		}
+		msleep(1);
+	}
+	pcicore_write32(pc, mdio_control, 0);
+	return ret;
+}
+
+static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device,
+				u8 address, u16 data)
+{
+	const u16 mdio_control = 0x128;
+	const u16 mdio_data = 0x12C;
+	int max_retries = 10;
+	u32 v;
+	int i;
+
+	v = 0x80; /* Enable Preamble Sequence */
+	v |= 0x2; /* MDIO Clock Divisor */
+	pcicore_write32(pc, mdio_control, v);
+
+	if (pc->dev->id.revision >= 10) {
+		max_retries = 200;
+		ssb_pcie_mdio_set_phy(pc, device);
+	}
+
 	v = (1 << 30); /* Start of Transaction */
 	v |= (1 << 28); /* Write Transaction */
 	v |= (1 << 17); /* Turnaround */
-	v |= (u32)device << 22;
+	if (pc->dev->id.revision < 10)
+		v |= (u32)device << 22;
 	v |= (u32)address << 18;
 	v |= data;
 	pcicore_write32(pc, mdio_data, v);
 	/* Wait for the device to complete the transaction */
 	udelay(10);
-	for (i = 0; i < 10; i++) {
+	for (i = 0; i < max_retries; i++) {
 		v = pcicore_read32(pc, mdio_control);
 		if (v & 0x100 /* Trans complete */)
 			break;
diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c
index 29884c0..7dca719 100644
--- a/drivers/ssb/scan.c
+++ b/drivers/ssb/scan.c
@@ -307,7 +307,7 @@
 	} else {
 		if (bus->bustype == SSB_BUSTYPE_PCI) {
 			bus->chip_id = pcidev_to_chipid(bus->host_pci);
-			pci_read_config_word(bus->host_pci, PCI_REVISION_ID,
+			pci_read_config_byte(bus->host_pci, PCI_REVISION_ID,
 					     &bus->chip_rev);
 			bus->chip_package = 0;
 		} else {
diff --git a/include/linux/ath9k_platform.h b/include/linux/ath9k_platform.h
index b847fc7..020387a 100644
--- a/include/linux/ath9k_platform.h
+++ b/include/linux/ath9k_platform.h
@@ -23,6 +23,11 @@
 
 struct ath9k_platform_data {
 	u16 eeprom_data[ATH9K_PLAT_EEP_MAX_WORDS];
+	u8 *macaddr;
+
+	int led_pin;
+	u32 gpio_mask;
+	u32 gpio_val;
 };
 
 #endif /* _LINUX_ATH9K_PLATFORM_H */
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 2d1c611..79690b7 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -884,6 +884,15 @@
 #define IEEE80211_HT_CAP_40MHZ_INTOLERANT	0x4000
 #define IEEE80211_HT_CAP_LSIG_TXOP_PROT		0x8000
 
+/* 802.11n HT extended capabilities masks (for extended_ht_cap_info) */
+#define IEEE80211_HT_EXT_CAP_PCO		0x0001
+#define IEEE80211_HT_EXT_CAP_PCO_TIME		0x0006
+#define		IEEE80211_HT_EXT_CAP_PCO_TIME_SHIFT	1
+#define IEEE80211_HT_EXT_CAP_MCS_FB		0x0300
+#define		IEEE80211_HT_EXT_CAP_MCS_FB_SHIFT	8
+#define IEEE80211_HT_EXT_CAP_HTC_SUP		0x0400
+#define IEEE80211_HT_EXT_CAP_RD_RESPONDER	0x0800
+
 /* 802.11n HT capability AMPDU settings (for ampdu_params_info) */
 #define IEEE80211_HT_AMPDU_PARM_FACTOR		0x03
 #define IEEE80211_HT_AMPDU_PARM_DENSITY		0x1C
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 3002218..16eea72 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1222,6 +1222,36 @@
 };
 
 /**
+ * enum nl80211_sta_bss_param - BSS information collected by STA
+ *
+ * These attribute types are used with %NL80211_STA_INFO_BSS_PARAM
+ * when getting information about the bitrate of a station.
+ *
+ * @__NL80211_STA_BSS_PARAM_INVALID: attribute number 0 is reserved
+ * @NL80211_STA_BSS_PARAM_CTS_PROT: whether CTS protection is enabled (flag)
+ * @NL80211_STA_BSS_PARAM_SHORT_PREAMBLE:  whether short preamble is enabled
+ *	(flag)
+ * @NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME:  whether short slot time is enabled
+ *	(flag)
+ * @NL80211_STA_BSS_PARAM_DTIM_PERIOD: DTIM period for beaconing (u8)
+ * @NL80211_STA_BSS_PARAM_BEACON_INTERVAL: Beacon interval (u16)
+ * @NL80211_STA_BSS_PARAM_MAX: highest sta_bss_param number currently defined
+ * @__NL80211_STA_BSS_PARAM_AFTER_LAST: internal use
+ */
+enum nl80211_sta_bss_param {
+	__NL80211_STA_BSS_PARAM_INVALID,
+	NL80211_STA_BSS_PARAM_CTS_PROT,
+	NL80211_STA_BSS_PARAM_SHORT_PREAMBLE,
+	NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME,
+	NL80211_STA_BSS_PARAM_DTIM_PERIOD,
+	NL80211_STA_BSS_PARAM_BEACON_INTERVAL,
+
+	/* keep last */
+	__NL80211_STA_BSS_PARAM_AFTER_LAST,
+	NL80211_STA_BSS_PARAM_MAX = __NL80211_STA_BSS_PARAM_AFTER_LAST - 1
+};
+
+/**
  * enum nl80211_sta_info - station information
  *
  * These attribute types are used with %NL80211_ATTR_STA_INFO
@@ -1233,7 +1263,7 @@
  * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station)
  * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm)
  * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute
- * 	containing info as possible, see &enum nl80211_sta_info_txrate.
+ * 	containing info as possible, see &enum nl80211_rate_info
  * @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station)
  * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (u32, to this
  *	station)
@@ -1245,6 +1275,8 @@
  * @NL80211_STA_INFO_PLINK_STATE: peer link state for the station
  * @NL80211_STA_INFO_RX_BITRATE: last unicast data frame rx rate, nested
  *	attribute, like NL80211_STA_INFO_TX_BITRATE.
+ * @NL80211_STA_INFO_BSS_PARAM: current station's view of BSS, nested attribute
+ *     containing info as possible, see &enum nl80211_sta_bss_param
  * @__NL80211_STA_INFO_AFTER_LAST: internal
  * @NL80211_STA_INFO_MAX: highest possible station info attribute
  */
@@ -1264,6 +1296,7 @@
 	NL80211_STA_INFO_TX_FAILED,
 	NL80211_STA_INFO_SIGNAL_AVG,
 	NL80211_STA_INFO_RX_BITRATE,
+	NL80211_STA_INFO_BSS_PARAM,
 
 	/* keep last */
 	__NL80211_STA_INFO_AFTER_LAST,
diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h
index 9659eff..7e99b34 100644
--- a/include/linux/ssb/ssb.h
+++ b/include/linux/ssb/ssb.h
@@ -308,7 +308,7 @@
 
 	/* ID information about the Chip. */
 	u16 chip_id;
-	u16 chip_rev;
+	u8 chip_rev;
 	u16 sprom_offset;
 	u16 sprom_size;		/* number of words in sprom */
 	u8 chip_package;
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 2c0d309..6138e31 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -428,6 +428,18 @@
 
 #define HCI_OP_USER_CONFIRM_NEG_REPLY	0x042d
 
+#define HCI_OP_REMOTE_OOB_DATA_REPLY	0x0430
+struct hci_cp_remote_oob_data_reply {
+	bdaddr_t bdaddr;
+	__u8     hash[16];
+	__u8     randomizer[16];
+} __packed;
+
+#define HCI_OP_REMOTE_OOB_DATA_NEG_REPLY	0x0433
+struct hci_cp_remote_oob_data_neg_reply {
+	bdaddr_t bdaddr;
+} __packed;
+
 #define HCI_OP_IO_CAPABILITY_NEG_REPLY	0x0434
 struct hci_cp_io_capability_neg_reply {
 	bdaddr_t bdaddr;
@@ -537,15 +549,17 @@
 	__u8     delete_all;
 } __packed;
 
+#define HCI_MAX_NAME_LENGTH		248
+
 #define HCI_OP_WRITE_LOCAL_NAME		0x0c13
 struct hci_cp_write_local_name {
-	__u8     name[248];
+	__u8     name[HCI_MAX_NAME_LENGTH];
 } __packed;
 
 #define HCI_OP_READ_LOCAL_NAME		0x0c14
 struct hci_rp_read_local_name {
 	__u8     status;
-	__u8     name[248];
+	__u8     name[HCI_MAX_NAME_LENGTH];
 } __packed;
 
 #define HCI_OP_WRITE_CA_TIMEOUT		0x0c16
@@ -602,6 +616,14 @@
 
 #define HCI_OP_WRITE_INQUIRY_MODE	0x0c45
 
+#define HCI_MAX_EIR_LENGTH		240
+
+#define HCI_OP_WRITE_EIR		0x0c52
+struct hci_cp_write_eir {
+	uint8_t		fec;
+	uint8_t		data[HCI_MAX_EIR_LENGTH];
+} __packed;
+
 #define HCI_OP_READ_SSP_MODE		0x0c55
 struct hci_rp_read_ssp_mode {
 	__u8     status;
@@ -613,6 +635,13 @@
 	__u8     mode;
 } __packed;
 
+#define HCI_OP_READ_LOCAL_OOB_DATA		0x0c57
+struct hci_rp_read_local_oob_data {
+	__u8     status;
+	__u8     hash[16];
+	__u8     randomizer[16];
+} __packed;
+
 #define HCI_OP_READ_INQ_RSP_TX_POWER	0x0c58
 
 #define HCI_OP_READ_LOCAL_VERSION	0x1001
@@ -747,7 +776,7 @@
 struct hci_ev_remote_name {
 	__u8     status;
 	bdaddr_t bdaddr;
-	__u8     name[248];
+	__u8     name[HCI_MAX_NAME_LENGTH];
 } __packed;
 
 #define HCI_EV_ENCRYPT_CHANGE		0x08
@@ -955,6 +984,11 @@
 	__le32		passkey;
 } __packed;
 
+#define HCI_EV_REMOTE_OOB_DATA_REQUEST	0x35
+struct hci_ev_remote_oob_data_request {
+	bdaddr_t bdaddr;
+} __packed;
+
 #define HCI_EV_SIMPLE_PAIR_COMPLETE	0x36
 struct hci_ev_simple_pair_complete {
 	__u8     status;
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 441dadb..4093133 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -82,6 +82,13 @@
 	u8 pin_len;
 };
 
+struct oob_data {
+	struct list_head list;
+	bdaddr_t bdaddr;
+	u8 hash[16];
+	u8 randomizer[16];
+};
+
 #define NUM_REASSEMBLY 4
 struct hci_dev {
 	struct list_head list;
@@ -94,7 +101,8 @@
 	__u8		bus;
 	__u8		dev_type;
 	bdaddr_t	bdaddr;
-	__u8		dev_name[248];
+	__u8		dev_name[HCI_MAX_NAME_LENGTH];
+	__u8		eir[HCI_MAX_EIR_LENGTH];
 	__u8		dev_class[3];
 	__u8		major_class;
 	__u8		minor_class;
@@ -169,6 +177,8 @@
 
 	struct list_head	link_keys;
 
+	struct list_head	remote_oob_data;
+
 	struct hci_dev_stats	stat;
 
 	struct sk_buff_head	driver_init;
@@ -505,6 +515,13 @@
 						u8 *key, u8 type, u8 pin_len);
 int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
 
+int hci_remote_oob_data_clear(struct hci_dev *hdev);
+struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev,
+							bdaddr_t *bdaddr);
+int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
+								u8 *randomizer);
+int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr);
+
 void hci_del_off_timer(struct hci_dev *hdev);
 
 void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
@@ -767,6 +784,12 @@
 int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr,
 								u8 status);
 int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status);
+int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status);
+int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
+								u8 status);
+int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
+								u8 *eir);
+int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name);
 
 /* HCI info for socket */
 #define hci_pi(sk) ((struct hci_pinfo *) sk)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 4f4bff1..2b9ca0d 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -280,7 +280,6 @@
 struct l2cap_chan_list {
 	struct sock	*head;
 	rwlock_t	lock;
-	long		num;
 };
 
 struct l2cap_conn {
@@ -302,7 +301,6 @@
 
 	struct sk_buff *rx_skb;
 	__u32		rx_len;
-	__u8		rx_ident;
 	__u8		tx_ident;
 
 	__u8		disc_reason;
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 5fabfa8..6b6ff92 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -41,6 +41,10 @@
 	__le16 index[0];
 } __packed;
 
+/* Reserve one extra byte for names in management messages so that they
+ * are always guaranteed to be nul-terminated */
+#define MGMT_MAX_NAME_LENGTH		(HCI_MAX_NAME_LENGTH + 1)
+
 #define MGMT_OP_READ_INFO		0x0004
 struct mgmt_rp_read_info {
 	__u8 type;
@@ -55,6 +59,7 @@
 	__u16 manufacturer;
 	__u8 hci_ver;
 	__u16 hci_rev;
+	__u8 name[MGMT_MAX_NAME_LENGTH];
 } __packed;
 
 struct mgmt_mode {
@@ -167,6 +172,29 @@
 
 #define MGMT_OP_USER_CONFIRM_NEG_REPLY	0x0016
 
+#define MGMT_OP_SET_LOCAL_NAME		0x0017
+struct mgmt_cp_set_local_name {
+	__u8 name[MGMT_MAX_NAME_LENGTH];
+} __packed;
+
+#define MGMT_OP_READ_LOCAL_OOB_DATA	0x0018
+struct mgmt_rp_read_local_oob_data {
+	__u8 hash[16];
+	__u8 randomizer[16];
+} __packed;
+
+#define MGMT_OP_ADD_REMOTE_OOB_DATA	0x0019
+struct mgmt_cp_add_remote_oob_data {
+	bdaddr_t bdaddr;
+	__u8 hash[16];
+	__u8 randomizer[16];
+} __packed;
+
+#define MGMT_OP_REMOVE_REMOTE_OOB_DATA	0x001A
+struct mgmt_cp_remove_remote_oob_data {
+	bdaddr_t bdaddr;
+} __packed;
+
 #define MGMT_EV_CMD_COMPLETE		0x0001
 struct mgmt_ev_cmd_complete {
 	__le16 opcode;
@@ -234,3 +262,22 @@
 	bdaddr_t bdaddr;
 	__u8 status;
 } __packed;
+
+#define MGMT_EV_LOCAL_NAME_CHANGED	0x0011
+struct mgmt_ev_local_name_changed {
+	__u8 name[MGMT_MAX_NAME_LENGTH];
+} __packed;
+
+#define MGMT_EV_DEVICE_FOUND		0x0012
+struct mgmt_ev_device_found {
+	bdaddr_t bdaddr;
+	__u8 dev_class[3];
+	__s8 rssi;
+	__u8 eir[HCI_MAX_EIR_LENGTH];
+} __packed;
+
+#define MGMT_EV_REMOTE_NAME		0x0013
+struct mgmt_ev_remote_name {
+	bdaddr_t bdaddr;
+	__u8 name[MGMT_MAX_NAME_LENGTH];
+} __packed;
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index b2b9d28..ba7384a 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -422,6 +422,7 @@
  * @STATION_INFO_RX_DROP_MISC: @rx_dropped_misc filled
  * @STATION_INFO_SIGNAL_AVG: @signal_avg filled
  * @STATION_INFO_RX_BITRATE: @rxrate fields are filled
+ * @STATION_INFO_BSS_PARAM: @bss_param filled
  */
 enum station_info_flags {
 	STATION_INFO_INACTIVE_TIME	= 1<<0,
@@ -439,6 +440,7 @@
 	STATION_INFO_RX_DROP_MISC	= 1<<12,
 	STATION_INFO_SIGNAL_AVG		= 1<<13,
 	STATION_INFO_RX_BITRATE		= 1<<14,
+	STATION_INFO_BSS_PARAM          = 1<<15,
 };
 
 /**
@@ -473,6 +475,37 @@
 };
 
 /**
+ * enum station_info_rate_flags - bitrate info flags
+ *
+ * Used by the driver to indicate the specific rate transmission
+ * type for 802.11n transmissions.
+ *
+ * @BSS_PARAM_FLAGS_CTS_PROT: whether CTS protection is enabled
+ * @BSS_PARAM_FLAGS_SHORT_PREAMBLE: whether short preamble is enabled
+ * @BSS_PARAM_FLAGS_SHORT_SLOT_TIME: whether short slot time is enabled
+ */
+enum bss_param_flags {
+	BSS_PARAM_FLAGS_CTS_PROT	= 1<<0,
+	BSS_PARAM_FLAGS_SHORT_PREAMBLE	= 1<<1,
+	BSS_PARAM_FLAGS_SHORT_SLOT_TIME	= 1<<2,
+};
+
+/**
+ * struct sta_bss_parameters - BSS parameters for the attached station
+ *
+ * Information about the currently associated BSS
+ *
+ * @flags: bitflag of flags from &enum bss_param_flags
+ * @dtim_period: DTIM period for the BSS
+ * @beacon_interval: beacon interval
+ */
+struct sta_bss_parameters {
+	u8 flags;
+	u8 dtim_period;
+	u16 beacon_interval;
+};
+
+/**
  * struct station_info - station information
  *
  * Station information filled by driver for get_station() and dump_station.
@@ -515,6 +548,7 @@
 	u32 tx_retries;
 	u32 tx_failed;
 	u32 rx_dropped_misc;
+	struct sta_bss_parameters bss_param;
 
 	int generation;
 };
@@ -2667,6 +2701,15 @@
 		      struct station_info *sinfo, gfp_t gfp);
 
 /**
+ * cfg80211_del_sta - notify userspace about deletion of a station
+ *
+ * @dev: the netdev
+ * @mac_addr: the station's address
+ * @gfp: allocation flags
+ */
+void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp);
+
+/**
  * cfg80211_rx_mgmt - notification of received, unprocessed management frame
  * @dev: network device
  * @freq: Frequency on which the frame was received in MHz
diff --git a/net/bluetooth/bnep/bnep.h b/net/bluetooth/bnep/bnep.h
index 70672544..8e6c061 100644
--- a/net/bluetooth/bnep/bnep.h
+++ b/net/bluetooth/bnep/bnep.h
@@ -23,88 +23,88 @@
 #include <linux/crc32.h>
 #include <net/bluetooth/bluetooth.h>
 
-// Limits
-#define BNEP_MAX_PROTO_FILTERS     5
-#define BNEP_MAX_MULTICAST_FILTERS 20
+/* Limits */
+#define BNEP_MAX_PROTO_FILTERS		5
+#define BNEP_MAX_MULTICAST_FILTERS	20
 
-// UUIDs
-#define BNEP_BASE_UUID 0x0000000000001000800000805F9B34FB
-#define BNEP_UUID16    0x02
-#define BNEP_UUID32    0x04
-#define BNEP_UUID128   0x16
+/* UUIDs */
+#define BNEP_BASE_UUID	0x0000000000001000800000805F9B34FB
+#define BNEP_UUID16	0x02
+#define BNEP_UUID32	0x04
+#define BNEP_UUID128	0x16
 
-#define BNEP_SVC_PANU  0x1115
-#define BNEP_SVC_NAP   0x1116
-#define BNEP_SVC_GN    0x1117
+#define BNEP_SVC_PANU	0x1115
+#define BNEP_SVC_NAP	0x1116
+#define BNEP_SVC_GN	0x1117
 
-// Packet types
-#define BNEP_GENERAL               0x00
-#define BNEP_CONTROL               0x01
-#define BNEP_COMPRESSED            0x02
-#define BNEP_COMPRESSED_SRC_ONLY   0x03
-#define BNEP_COMPRESSED_DST_ONLY   0x04
+/* Packet types */
+#define BNEP_GENERAL			0x00
+#define BNEP_CONTROL			0x01
+#define BNEP_COMPRESSED			0x02
+#define BNEP_COMPRESSED_SRC_ONLY	0x03
+#define BNEP_COMPRESSED_DST_ONLY	0x04
 
-// Control types
-#define BNEP_CMD_NOT_UNDERSTOOD    0x00
-#define BNEP_SETUP_CONN_REQ        0x01
-#define BNEP_SETUP_CONN_RSP        0x02
-#define BNEP_FILTER_NET_TYPE_SET   0x03
-#define BNEP_FILTER_NET_TYPE_RSP   0x04
-#define BNEP_FILTER_MULTI_ADDR_SET 0x05
-#define BNEP_FILTER_MULTI_ADDR_RSP 0x06
+/* Control types */
+#define BNEP_CMD_NOT_UNDERSTOOD		0x00
+#define BNEP_SETUP_CONN_REQ		0x01
+#define BNEP_SETUP_CONN_RSP		0x02
+#define BNEP_FILTER_NET_TYPE_SET	0x03
+#define BNEP_FILTER_NET_TYPE_RSP	0x04
+#define BNEP_FILTER_MULTI_ADDR_SET	0x05
+#define BNEP_FILTER_MULTI_ADDR_RSP	0x06
 
-// Extension types
-#define BNEP_EXT_CONTROL           0x00
+/* Extension types */
+#define BNEP_EXT_CONTROL 0x00
 
-// Response messages
-#define BNEP_SUCCESS               0x00
+/* Response messages */
+#define BNEP_SUCCESS 0x00
 
-#define BNEP_CONN_INVALID_DST      0x01
-#define BNEP_CONN_INVALID_SRC      0x02
-#define BNEP_CONN_INVALID_SVC      0x03
-#define BNEP_CONN_NOT_ALLOWED      0x04
+#define BNEP_CONN_INVALID_DST 0x01
+#define BNEP_CONN_INVALID_SRC 0x02
+#define BNEP_CONN_INVALID_SVC 0x03
+#define BNEP_CONN_NOT_ALLOWED 0x04
 
-#define BNEP_FILTER_UNSUPPORTED_REQ    0x01
-#define BNEP_FILTER_INVALID_RANGE      0x02
-#define BNEP_FILTER_INVALID_MCADDR     0x02
-#define BNEP_FILTER_LIMIT_REACHED      0x03
-#define BNEP_FILTER_DENIED_SECURITY    0x04
+#define BNEP_FILTER_UNSUPPORTED_REQ	0x01
+#define BNEP_FILTER_INVALID_RANGE	0x02
+#define BNEP_FILTER_INVALID_MCADDR	0x02
+#define BNEP_FILTER_LIMIT_REACHED	0x03
+#define BNEP_FILTER_DENIED_SECURITY	0x04
 
-// L2CAP settings
-#define BNEP_MTU         1691
-#define BNEP_PSM	 0x0f
-#define BNEP_FLUSH_TO    0xffff
-#define BNEP_CONNECT_TO  15
-#define BNEP_FILTER_TO   15
+/* L2CAP settings */
+#define BNEP_MTU	1691
+#define BNEP_PSM	0x0f
+#define BNEP_FLUSH_TO	0xffff
+#define BNEP_CONNECT_TO	15
+#define BNEP_FILTER_TO	15
 
-// Headers
-#define BNEP_TYPE_MASK	 0x7f
-#define BNEP_EXT_HEADER	 0x80
+/* Headers */
+#define BNEP_TYPE_MASK	0x7f
+#define BNEP_EXT_HEADER	0x80
 
 struct bnep_setup_conn_req {
-	__u8  type;
-	__u8  ctrl;
-	__u8  uuid_size;
-	__u8  service[0];
+	__u8 type;
+	__u8 ctrl;
+	__u8 uuid_size;
+	__u8 service[0];
 } __packed;
 
 struct bnep_set_filter_req {
-	__u8  type;
-	__u8  ctrl;
+	__u8 type;
+	__u8 ctrl;
 	__be16 len;
-	__u8  list[0];
+	__u8 list[0];
 } __packed;
 
 struct bnep_control_rsp {
-	__u8  type;
-	__u8  ctrl;
+	__u8 type;
+	__u8 ctrl;
 	__be16 resp;
 } __packed;
 
 struct bnep_ext_hdr {
-	__u8  type;
-	__u8  len;
-	__u8  data[0];
+	__u8 type;
+	__u8 len;
+	__u8 data[0];
 } __packed;
 
 /* BNEP ioctl defines */
@@ -114,10 +114,10 @@
 #define BNEPGETCONNINFO	_IOR('B', 211, int)
 
 struct bnep_connadd_req {
-	int   sock;       // Connected socket
+	int   sock;		/* Connected socket */
 	__u32 flags;
 	__u16 role;
-	char  device[16]; // Name of the Ethernet device
+	char  device[16];	/* Name of the Ethernet device */
 };
 
 struct bnep_conndel_req {
@@ -148,14 +148,14 @@
 int bnep_get_connlist(struct bnep_connlist_req *req);
 int bnep_get_conninfo(struct bnep_conninfo *ci);
 
-// BNEP sessions
+/* BNEP sessions */
 struct bnep_session {
 	struct list_head list;
 
 	unsigned int  role;
 	unsigned long state;
 	unsigned long flags;
-	atomic_t      killed;
+	struct task_struct *task;
 
 	struct ethhdr eh;
 	struct msghdr msg;
@@ -173,7 +173,7 @@
 
 static inline int bnep_mc_hash(__u8 *addr)
 {
-	return (crc32_be(~0, addr, ETH_ALEN) >> 26);
+	return crc32_be(~0, addr, ETH_ALEN) >> 26;
 }
 
 #endif
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
index 03d4d12..ca39fcf 100644
--- a/net/bluetooth/bnep/core.c
+++ b/net/bluetooth/bnep/core.c
@@ -36,6 +36,7 @@
 #include <linux/errno.h>
 #include <linux/net.h>
 #include <linux/slab.h>
+#include <linux/kthread.h>
 #include <net/sock.h>
 
 #include <linux/socket.h>
@@ -131,7 +132,8 @@
 		return -EILSEQ;
 
 	n = get_unaligned_be16(data);
-	data++; len -= 2;
+	data++;
+	len -= 2;
 
 	if (len < n)
 		return -EILSEQ;
@@ -176,7 +178,8 @@
 		return -EILSEQ;
 
 	n = get_unaligned_be16(data);
-	data += 2; len -= 2;
+	data += 2;
+	len -= 2;
 
 	if (len < n)
 		return -EILSEQ;
@@ -187,6 +190,8 @@
 	n /= (ETH_ALEN * 2);
 
 	if (n > 0) {
+		int i;
+
 		s->mc_filter = 0;
 
 		/* Always send broadcast */
@@ -196,18 +201,22 @@
 		for (; n > 0; n--) {
 			u8 a1[6], *a2;
 
-			memcpy(a1, data, ETH_ALEN); data += ETH_ALEN;
-			a2 = data; data += ETH_ALEN;
+			memcpy(a1, data, ETH_ALEN);
+			data += ETH_ALEN;
+			a2 = data;
+			data += ETH_ALEN;
 
 			BT_DBG("mc filter %s -> %s",
 				batostr((void *) a1), batostr((void *) a2));
 
-			#define INCA(a) { int i = 5; while (i >=0 && ++a[i--] == 0); }
-
 			/* Iterate from a1 to a2 */
 			set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter);
 			while (memcmp(a1, a2, 6) < 0 && s->mc_filter != ~0LL) {
-				INCA(a1);
+				/* Increment a1 */
+				i = 5;
+				while (i >= 0 && ++a1[i--] == 0)
+					;
+
 				set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter);
 			}
 		}
@@ -227,7 +236,8 @@
 	u8  cmd = *(u8 *)data;
 	int err = 0;
 
-	data++; len--;
+	data++;
+	len--;
 
 	switch (cmd) {
 	case BNEP_CMD_NOT_UNDERSTOOD:
@@ -302,7 +312,6 @@
 	ETH_ALEN + 2, /* BNEP_COMPRESSED_SRC_ONLY */
 	ETH_ALEN + 2  /* BNEP_COMPRESSED_DST_ONLY */
 };
-#define BNEP_RX_TYPES	(sizeof(__bnep_rx_hlen) - 1)
 
 static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
 {
@@ -312,9 +321,10 @@
 
 	dev->stats.rx_bytes += skb->len;
 
-	type = *(u8 *) skb->data; skb_pull(skb, 1);
+	type = *(u8 *) skb->data;
+	skb_pull(skb, 1);
 
-	if ((type & BNEP_TYPE_MASK) > BNEP_RX_TYPES)
+	if ((type & BNEP_TYPE_MASK) >= sizeof(__bnep_rx_hlen))
 		goto badframe;
 
 	if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) {
@@ -367,14 +377,14 @@
 
 	case BNEP_COMPRESSED_DST_ONLY:
 		memcpy(__skb_put(nskb, ETH_ALEN), skb_mac_header(skb),
-		       ETH_ALEN);
+								ETH_ALEN);
 		memcpy(__skb_put(nskb, ETH_ALEN + 2), s->eh.h_source,
-		       ETH_ALEN + 2);
+								ETH_ALEN + 2);
 		break;
 
 	case BNEP_GENERAL:
 		memcpy(__skb_put(nskb, ETH_ALEN * 2), skb_mac_header(skb),
-		       ETH_ALEN * 2);
+								ETH_ALEN * 2);
 		put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2));
 		break;
 	}
@@ -470,15 +480,14 @@
 
 	BT_DBG("");
 
-	daemonize("kbnepd %s", dev->name);
 	set_user_nice(current, -15);
 
 	init_waitqueue_entry(&wait, current);
 	add_wait_queue(sk_sleep(sk), &wait);
-	while (!atomic_read(&s->killed)) {
+	while (!kthread_should_stop()) {
 		set_current_state(TASK_INTERRUPTIBLE);
 
-		// RX
+		/* RX */
 		while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
 			skb_orphan(skb);
 			bnep_rx_frame(s, skb);
@@ -487,7 +496,7 @@
 		if (sk->sk_state != BT_CONNECTED)
 			break;
 
-		// TX
+		/* TX */
 		while ((skb = skb_dequeue(&sk->sk_write_queue)))
 			if (bnep_tx_frame(s, skb))
 				break;
@@ -555,8 +564,8 @@
 
 	/* session struct allocated as private part of net_device */
 	dev = alloc_netdev(sizeof(struct bnep_session),
-			   (*req->device) ? req->device : "bnep%d",
-			   bnep_net_setup);
+				(*req->device) ? req->device : "bnep%d",
+				bnep_net_setup);
 	if (!dev)
 		return -ENOMEM;
 
@@ -571,7 +580,7 @@
 	s = netdev_priv(dev);
 
 	/* This is rx header therefore addresses are swapped.
-	 * ie eh.h_dest is our local address. */
+	 * ie. eh.h_dest is our local address. */
 	memcpy(s->eh.h_dest,   &src, ETH_ALEN);
 	memcpy(s->eh.h_source, &dst, ETH_ALEN);
 	memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN);
@@ -597,17 +606,17 @@
 	SET_NETDEV_DEVTYPE(dev, &bnep_type);
 
 	err = register_netdev(dev);
-	if (err) {
+	if (err)
 		goto failed;
-	}
 
 	__bnep_link_session(s);
 
-	err = kernel_thread(bnep_session, s, CLONE_KERNEL);
-	if (err < 0) {
+	s->task = kthread_run(bnep_session, s, "kbnepd %s", dev->name);
+	if (IS_ERR(s->task)) {
 		/* Session thread start failed, gotta cleanup. */
 		unregister_netdev(dev);
 		__bnep_unlink_session(s);
+		err = PTR_ERR(s->task);
 		goto failed;
 	}
 
@@ -631,15 +640,9 @@
 	down_read(&bnep_session_sem);
 
 	s = __bnep_get_session(req->dst);
-	if (s) {
-		/* Wakeup user-space which is polling for socket errors.
-		 * This is temporary hack until we have shutdown in L2CAP */
-		s->sock->sk->sk_err = EUNATCH;
-
-		/* Kill session thread */
-		atomic_inc(&s->killed);
-		wake_up_interruptible(sk_sleep(s->sock->sk));
-	} else
+	if (s)
+		kthread_stop(s->task);
+	else
 		err = -ENOENT;
 
 	up_read(&bnep_session_sem);
diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c
index d935da7..17800b1 100644
--- a/net/bluetooth/bnep/sock.c
+++ b/net/bluetooth/bnep/sock.c
@@ -39,10 +39,10 @@
 #include <linux/init.h>
 #include <linux/compat.h>
 #include <linux/gfp.h>
+#include <linux/uaccess.h>
 #include <net/sock.h>
 
 #include <asm/system.h>
-#include <asm/uaccess.h>
 
 #include "bnep.h"
 
diff --git a/net/bluetooth/cmtp/capi.c b/net/bluetooth/cmtp/capi.c
index 67cff810..744233c 100644
--- a/net/bluetooth/cmtp/capi.c
+++ b/net/bluetooth/cmtp/capi.c
@@ -35,6 +35,7 @@
 #include <linux/ioctl.h>
 #include <linux/file.h>
 #include <linux/wait.h>
+#include <linux/kthread.h>
 #include <net/sock.h>
 
 #include <linux/isdn/capilli.h>
@@ -143,7 +144,7 @@
 
 	skb_queue_tail(&session->transmit, skb);
 
-	cmtp_schedule(session);
+	wake_up_interruptible(sk_sleep(session->sock->sk));
 }
 
 static void cmtp_send_interopmsg(struct cmtp_session *session,
@@ -386,8 +387,7 @@
 
 	capi_ctr_down(ctrl);
 
-	atomic_inc(&session->terminate);
-	cmtp_schedule(session);
+	kthread_stop(session->task);
 }
 
 static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
diff --git a/net/bluetooth/cmtp/cmtp.h b/net/bluetooth/cmtp/cmtp.h
index 785e79e..db43b54 100644
--- a/net/bluetooth/cmtp/cmtp.h
+++ b/net/bluetooth/cmtp/cmtp.h
@@ -37,7 +37,7 @@
 #define CMTP_LOOPBACK	0
 
 struct cmtp_connadd_req {
-	int   sock;	// Connected socket
+	int   sock;	/* Connected socket */
 	__u32 flags;
 };
 
@@ -81,7 +81,7 @@
 
 	char name[BTNAMSIZ];
 
-	atomic_t terminate;
+	struct task_struct *task;
 
 	wait_queue_head_t wait;
 
@@ -121,13 +121,6 @@
 
 void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb);
 
-static inline void cmtp_schedule(struct cmtp_session *session)
-{
-	struct sock *sk = session->sock->sk;
-
-	wake_up_interruptible(sk_sleep(sk));
-}
-
 /* CMTP init defines */
 int cmtp_init_sockets(void);
 void cmtp_cleanup_sockets(void);
diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c
index 964ea91..cce99b0 100644
--- a/net/bluetooth/cmtp/core.c
+++ b/net/bluetooth/cmtp/core.c
@@ -35,6 +35,7 @@
 #include <linux/ioctl.h>
 #include <linux/file.h>
 #include <linux/init.h>
+#include <linux/kthread.h>
 #include <net/sock.h>
 
 #include <linux/isdn/capilli.h>
@@ -235,9 +236,12 @@
 
 		size = min_t(uint, ((tail < 258) ? (tail - 2) : (tail - 3)), skb->len);
 
-		if ((scb->id < 0) && ((scb->id = cmtp_alloc_block_id(session)) < 0)) {
-			skb_queue_head(&session->transmit, skb);
-			break;
+		if (scb->id < 0) {
+			scb->id = cmtp_alloc_block_id(session);
+			if (scb->id < 0) {
+				skb_queue_head(&session->transmit, skb);
+				break;
+			}
 		}
 
 		if (size < 256) {
@@ -284,12 +288,11 @@
 
 	BT_DBG("session %p", session);
 
-	daemonize("kcmtpd_ctr_%d", session->num);
 	set_user_nice(current, -15);
 
 	init_waitqueue_entry(&wait, current);
 	add_wait_queue(sk_sleep(sk), &wait);
-	while (!atomic_read(&session->terminate)) {
+	while (!kthread_should_stop()) {
 		set_current_state(TASK_INTERRUPTIBLE);
 
 		if (sk->sk_state != BT_CONNECTED)
@@ -367,9 +370,12 @@
 
 	__cmtp_link_session(session);
 
-	err = kernel_thread(cmtp_session, session, CLONE_KERNEL);
-	if (err < 0)
+	session->task = kthread_run(cmtp_session, session, "kcmtpd_ctr_%d",
+								session->num);
+	if (IS_ERR(session->task)) {
+		err = PTR_ERR(session->task);
 		goto unlink;
+	}
 
 	if (!(session->flags & (1 << CMTP_LOOPBACK))) {
 		err = cmtp_attach_device(session);
@@ -406,9 +412,8 @@
 		/* Flush the transmit queue */
 		skb_queue_purge(&session->transmit);
 
-		/* Kill session thread */
-		atomic_inc(&session->terminate);
-		cmtp_schedule(session);
+		/* Stop session thread */
+		kthread_stop(session->task);
 	} else
 		err = -ENOENT;
 
diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c
index 7ea1979..3f2dd5c 100644
--- a/net/bluetooth/cmtp/sock.c
+++ b/net/bluetooth/cmtp/sock.c
@@ -34,12 +34,12 @@
 #include <linux/file.h>
 #include <linux/compat.h>
 #include <linux/gfp.h>
+#include <linux/uaccess.h>
 #include <net/sock.h>
 
 #include <linux/isdn/capilli.h>
 
 #include <asm/system.h>
-#include <asm/uaccess.h>
 
 #include "cmtp.h"
 
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 2216620..a80bc1c 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -56,7 +56,6 @@
 static void hci_cmd_task(unsigned long arg);
 static void hci_rx_task(unsigned long arg);
 static void hci_tx_task(unsigned long arg);
-static void hci_notify(struct hci_dev *hdev, int event);
 
 static DEFINE_RWLOCK(hci_task_lock);
 
@@ -1083,6 +1082,70 @@
 	tasklet_schedule(&hdev->cmd_task);
 }
 
+struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev,
+							bdaddr_t *bdaddr)
+{
+	struct oob_data *data;
+
+	list_for_each_entry(data, &hdev->remote_oob_data, list)
+		if (bacmp(bdaddr, &data->bdaddr) == 0)
+			return data;
+
+	return NULL;
+}
+
+int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr)
+{
+	struct oob_data *data;
+
+	data = hci_find_remote_oob_data(hdev, bdaddr);
+	if (!data)
+		return -ENOENT;
+
+	BT_DBG("%s removing %s", hdev->name, batostr(bdaddr));
+
+	list_del(&data->list);
+	kfree(data);
+
+	return 0;
+}
+
+int hci_remote_oob_data_clear(struct hci_dev *hdev)
+{
+	struct oob_data *data, *n;
+
+	list_for_each_entry_safe(data, n, &hdev->remote_oob_data, list) {
+		list_del(&data->list);
+		kfree(data);
+	}
+
+	return 0;
+}
+
+int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
+								u8 *randomizer)
+{
+	struct oob_data *data;
+
+	data = hci_find_remote_oob_data(hdev, bdaddr);
+
+	if (!data) {
+		data = kmalloc(sizeof(*data), GFP_ATOMIC);
+		if (!data)
+			return -ENOMEM;
+
+		bacpy(&data->bdaddr, bdaddr);
+		list_add(&data->list, &hdev->remote_oob_data);
+	}
+
+	memcpy(data->hash, hash, sizeof(data->hash));
+	memcpy(data->randomizer, randomizer, sizeof(data->randomizer));
+
+	BT_DBG("%s for %s", hdev->name, batostr(bdaddr));
+
+	return 0;
+}
+
 /* Register HCI device */
 int hci_register_dev(struct hci_dev *hdev)
 {
@@ -1147,6 +1210,8 @@
 
 	INIT_LIST_HEAD(&hdev->link_keys);
 
+	INIT_LIST_HEAD(&hdev->remote_oob_data);
+
 	INIT_WORK(&hdev->power_on, hci_power_on);
 	INIT_WORK(&hdev->power_off, hci_power_off);
 	setup_timer(&hdev->off_timer, hci_auto_off, (unsigned long) hdev);
@@ -1226,6 +1291,7 @@
 	hci_blacklist_clear(hdev);
 	hci_uuids_clear(hdev);
 	hci_link_keys_clear(hdev);
+	hci_remote_oob_data_clear(hdev);
 	hci_dev_unlock_bh(hdev);
 
 	__hci_dev_put(hdev);
@@ -1275,7 +1341,7 @@
 EXPORT_SYMBOL(hci_recv_frame);
 
 static int hci_reassembly(struct hci_dev *hdev, int type, void *data,
-			  int count, __u8 index, gfp_t gfp_mask)
+						  int count, __u8 index)
 {
 	int len = 0;
 	int hlen = 0;
@@ -1305,7 +1371,7 @@
 			break;
 		}
 
-		skb = bt_skb_alloc(len, gfp_mask);
+		skb = bt_skb_alloc(len, GFP_ATOMIC);
 		if (!skb)
 			return -ENOMEM;
 
@@ -1391,8 +1457,7 @@
 		return -EILSEQ;
 
 	while (count) {
-		rem = hci_reassembly(hdev, type, data, count,
-						type - 1, GFP_ATOMIC);
+		rem = hci_reassembly(hdev, type, data, count, type - 1);
 		if (rem < 0)
 			return rem;
 
@@ -1426,8 +1491,8 @@
 		} else
 			type = bt_cb(skb)->pkt_type;
 
-		rem = hci_reassembly(hdev, type, data,
-					count, STREAM_REASSEMBLY, GFP_ATOMIC);
+		rem = hci_reassembly(hdev, type, data, count,
+							STREAM_REASSEMBLY);
 		if (rem < 0)
 			return rem;
 
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index cebe7588..7a3398d 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -195,14 +195,17 @@
 
 	BT_DBG("%s status 0x%x", hdev->name, status);
 
-	if (status)
-		return;
-
 	sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LOCAL_NAME);
 	if (!sent)
 		return;
 
-	memcpy(hdev->dev_name, sent, 248);
+	if (test_bit(HCI_MGMT, &hdev->flags))
+		mgmt_set_local_name_complete(hdev->id, sent, status);
+
+	if (status)
+		return;
+
+	memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH);
 }
 
 static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
@@ -214,7 +217,7 @@
 	if (rp->status)
 		return;
 
-	memcpy(hdev->dev_name, rp->name, 248);
+	memcpy(hdev->dev_name, rp->name, HCI_MAX_NAME_LENGTH);
 }
 
 static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb)
@@ -821,6 +824,17 @@
 								rp->status);
 }
 
+static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
+							struct sk_buff *skb)
+{
+	struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
+
+	BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+	mgmt_read_local_oob_data_reply_complete(hdev->id, rp->hash,
+						rp->randomizer, rp->status);
+}
+
 static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
 {
 	BT_DBG("%s status 0x%x", hdev->name, status);
@@ -1214,7 +1228,7 @@
 
 	hci_dev_lock(hdev);
 
-	for (; num_rsp; num_rsp--) {
+	for (; num_rsp; num_rsp--, info++) {
 		bacpy(&data.bdaddr, &info->bdaddr);
 		data.pscan_rep_mode	= info->pscan_rep_mode;
 		data.pscan_period_mode	= info->pscan_period_mode;
@@ -1223,8 +1237,9 @@
 		data.clock_offset	= info->clock_offset;
 		data.rssi		= 0x00;
 		data.ssp_mode		= 0x00;
-		info++;
 		hci_inquiry_cache_update(hdev, &data);
+		mgmt_device_found(hdev->id, &info->bdaddr, info->dev_class, 0,
+									NULL);
 	}
 
 	hci_dev_unlock(hdev);
@@ -1482,6 +1497,9 @@
 
 	hci_dev_lock(hdev);
 
+	if (ev->status == 0 && test_bit(HCI_MGMT, &hdev->flags))
+		mgmt_remote_name(hdev->id, &ev->bdaddr, ev->name);
+
 	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
 	if (conn && hci_outgoing_auth_needed(hdev, conn)) {
 		struct hci_cp_auth_requested cp;
@@ -1751,6 +1769,10 @@
 		hci_cc_pin_code_neg_reply(hdev, skb);
 		break;
 
+	case HCI_OP_READ_LOCAL_OOB_DATA:
+		hci_cc_read_local_oob_data_reply(hdev, skb);
+		break;
+
 	case HCI_OP_LE_READ_BUFFER_SIZE:
 		hci_cc_le_read_buffer_size(hdev, skb);
 		break;
@@ -2140,7 +2162,7 @@
 		struct inquiry_info_with_rssi_and_pscan_mode *info;
 		info = (void *) (skb->data + 1);
 
-		for (; num_rsp; num_rsp--) {
+		for (; num_rsp; num_rsp--, info++) {
 			bacpy(&data.bdaddr, &info->bdaddr);
 			data.pscan_rep_mode	= info->pscan_rep_mode;
 			data.pscan_period_mode	= info->pscan_period_mode;
@@ -2149,13 +2171,15 @@
 			data.clock_offset	= info->clock_offset;
 			data.rssi		= info->rssi;
 			data.ssp_mode		= 0x00;
-			info++;
 			hci_inquiry_cache_update(hdev, &data);
+			mgmt_device_found(hdev->id, &info->bdaddr,
+						info->dev_class, info->rssi,
+						NULL);
 		}
 	} else {
 		struct inquiry_info_with_rssi *info = (void *) (skb->data + 1);
 
-		for (; num_rsp; num_rsp--) {
+		for (; num_rsp; num_rsp--, info++) {
 			bacpy(&data.bdaddr, &info->bdaddr);
 			data.pscan_rep_mode	= info->pscan_rep_mode;
 			data.pscan_period_mode	= info->pscan_period_mode;
@@ -2164,8 +2188,10 @@
 			data.clock_offset	= info->clock_offset;
 			data.rssi		= info->rssi;
 			data.ssp_mode		= 0x00;
-			info++;
 			hci_inquiry_cache_update(hdev, &data);
+			mgmt_device_found(hdev->id, &info->bdaddr,
+						info->dev_class, info->rssi,
+						NULL);
 		}
 	}
 
@@ -2296,7 +2322,7 @@
 
 	hci_dev_lock(hdev);
 
-	for (; num_rsp; num_rsp--) {
+	for (; num_rsp; num_rsp--, info++) {
 		bacpy(&data.bdaddr, &info->bdaddr);
 		data.pscan_rep_mode	= info->pscan_rep_mode;
 		data.pscan_period_mode	= info->pscan_period_mode;
@@ -2305,8 +2331,9 @@
 		data.clock_offset	= info->clock_offset;
 		data.rssi		= info->rssi;
 		data.ssp_mode		= 0x01;
-		info++;
 		hci_inquiry_cache_update(hdev, &data);
+		mgmt_device_found(hdev->id, &info->bdaddr, info->dev_class,
+						info->rssi, info->data);
 	}
 
 	hci_dev_unlock(hdev);
@@ -2355,9 +2382,14 @@
 
 		bacpy(&cp.bdaddr, &ev->bdaddr);
 		cp.capability = conn->io_capability;
-		cp.oob_data = 0;
 		cp.authentication = hci_get_auth_req(conn);
 
+		if ((conn->out == 0x01 || conn->remote_oob == 0x01) &&
+				hci_find_remote_oob_data(hdev, &conn->dst))
+			cp.oob_data = 0x01;
+		else
+			cp.oob_data = 0x00;
+
 		hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_REPLY,
 							sizeof(cp), &cp);
 	} else {
@@ -2455,6 +2487,37 @@
 	hci_dev_unlock(hdev);
 }
 
+static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
+							struct sk_buff *skb)
+{
+	struct hci_ev_remote_oob_data_request *ev = (void *) skb->data;
+	struct oob_data *data;
+
+	BT_DBG("%s", hdev->name);
+
+	hci_dev_lock(hdev);
+
+	data = hci_find_remote_oob_data(hdev, &ev->bdaddr);
+	if (data) {
+		struct hci_cp_remote_oob_data_reply cp;
+
+		bacpy(&cp.bdaddr, &ev->bdaddr);
+		memcpy(cp.hash, data->hash, sizeof(cp.hash));
+		memcpy(cp.randomizer, data->randomizer, sizeof(cp.randomizer));
+
+		hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_REPLY, sizeof(cp),
+									&cp);
+	} else {
+		struct hci_cp_remote_oob_data_neg_reply cp;
+
+		bacpy(&cp.bdaddr, &ev->bdaddr);
+		hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_NEG_REPLY, sizeof(cp),
+									&cp);
+	}
+
+	hci_dev_unlock(hdev);
+}
+
 static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_le_conn_complete *ev = (void *) skb->data;
@@ -2657,6 +2720,10 @@
 		hci_le_meta_evt(hdev, skb);
 		break;
 
+	case HCI_EV_REMOTE_OOB_DATA_REQUEST:
+		hci_remote_oob_data_request_evt(hdev, skb);
+		break;
+
 	default:
 		BT_DBG("%s event 0x%x", hdev->name, event);
 		break;
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 3c838a6..8775933 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -216,13 +216,13 @@
 static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct hci_dev *hdev = dev_get_drvdata(dev);
-	char name[249];
+	char name[HCI_MAX_NAME_LENGTH + 1];
 	int i;
 
-	for (i = 0; i < 248; i++)
+	for (i = 0; i < HCI_MAX_NAME_LENGTH; i++)
 		name[i] = hdev->dev_name[i];
 
-	name[248] = '\0';
+	name[HCI_MAX_NAME_LENGTH] = '\0';
 	return sprintf(buf, "%s\n", name);
 }
 
@@ -277,10 +277,12 @@
 static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
 	struct hci_dev *hdev = dev_get_drvdata(dev);
-	unsigned long val;
+	unsigned int val;
+	int rv;
 
-	if (strict_strtoul(buf, 0, &val) < 0)
-		return -EINVAL;
+	rv = kstrtouint(buf, 0, &val);
+	if (rv < 0)
+		return rv;
 
 	if (val != 0 && (val < 500 || val > 3600000))
 		return -EINVAL;
@@ -299,15 +301,14 @@
 static ssize_t store_sniff_max_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
 	struct hci_dev *hdev = dev_get_drvdata(dev);
-	unsigned long val;
+	u16 val;
+	int rv;
 
-	if (strict_strtoul(buf, 0, &val) < 0)
-		return -EINVAL;
+	rv = kstrtou16(buf, 0, &val);
+	if (rv < 0)
+		return rv;
 
-	if (val < 0x0002 || val > 0xFFFE || val % 2)
-		return -EINVAL;
-
-	if (val < hdev->sniff_min_interval)
+	if (val == 0 || val % 2 || val < hdev->sniff_min_interval)
 		return -EINVAL;
 
 	hdev->sniff_max_interval = val;
@@ -324,15 +325,14 @@
 static ssize_t store_sniff_min_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
 	struct hci_dev *hdev = dev_get_drvdata(dev);
-	unsigned long val;
+	u16 val;
+	int rv;
 
-	if (strict_strtoul(buf, 0, &val) < 0)
-		return -EINVAL;
+	rv = kstrtou16(buf, 0, &val);
+	if (rv < 0)
+		return rv;
 
-	if (val < 0x0002 || val > 0xFFFE || val % 2)
-		return -EINVAL;
-
-	if (val > hdev->sniff_max_interval)
+	if (val == 0 || val % 2 || val > hdev->sniff_max_interval)
 		return -EINVAL;
 
 	hdev->sniff_min_interval = val;
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index 5ec1297..ae6ebc6 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -37,6 +37,7 @@
 #include <linux/init.h>
 #include <linux/wait.h>
 #include <linux/mutex.h>
+#include <linux/kthread.h>
 #include <net/sock.h>
 
 #include <linux/input.h>
@@ -55,22 +56,24 @@
 static LIST_HEAD(hidp_session_list);
 
 static unsigned char hidp_keycode[256] = {
-	  0,  0,  0,  0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
-	 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44,  2,  3,
-	  4,  5,  6,  7,  8,  9, 10, 11, 28,  1, 14, 15, 57, 12, 13, 26,
-	 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
-	 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
-	105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
-	 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
-	191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
-	115,114,  0,  0,  0,121,  0, 89, 93,124, 92, 94, 95,  0,  0,  0,
-	122,123, 90, 91, 85,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
-	150,158,159,128,136,177,178,176,142,152,173,140
+	  0,   0,   0,   0,  30,  48,  46,  32,  18,  33,  34,  35,  23,  36,
+	 37,  38,  50,  49,  24,  25,  16,  19,  31,  20,  22,  47,  17,  45,
+	 21,  44,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  28,   1,
+	 14,  15,  57,  12,  13,  26,  27,  43,  43,  39,  40,  41,  51,  52,
+	 53,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  87,  88,
+	 99,  70, 119, 110, 102, 104, 111, 107, 109, 106, 105, 108, 103,  69,
+	 98,  55,  74,  78,  96,  79,  80,  81,  75,  76,  77,  71,  72,  73,
+	 82,  83,  86, 127, 116, 117, 183, 184, 185, 186, 187, 188, 189, 190,
+	191, 192, 193, 194, 134, 138, 130, 132, 128, 129, 131, 137, 133, 135,
+	136, 113, 115, 114,   0,   0,   0, 121,   0,  89,  93, 124,  92,  94,
+	 95,   0,   0,   0, 122, 123,  90,  91,  85,   0,   0,   0,   0,   0,
+	  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+	 29,  42,  56, 125,  97,  54, 100, 126, 164, 166, 165, 163, 161, 115,
+	114, 113, 150, 158, 159, 128, 136, 177, 178, 176, 142, 152, 173, 140
 };
 
 static unsigned char hidp_mkeyspat[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
@@ -461,8 +464,7 @@
 {
 	struct hidp_session *session = (struct hidp_session *) arg;
 
-	atomic_inc(&session->terminate);
-	hidp_schedule(session);
+	kthread_stop(session->task);
 }
 
 static void hidp_set_timer(struct hidp_session *session)
@@ -533,9 +535,7 @@
 		skb_queue_purge(&session->ctrl_transmit);
 		skb_queue_purge(&session->intr_transmit);
 
-		/* Kill session thread */
-		atomic_inc(&session->terminate);
-		hidp_schedule(session);
+		kthread_stop(session->task);
 	}
 }
 
@@ -694,22 +694,10 @@
 	struct sock *ctrl_sk = session->ctrl_sock->sk;
 	struct sock *intr_sk = session->intr_sock->sk;
 	struct sk_buff *skb;
-	int vendor = 0x0000, product = 0x0000;
 	wait_queue_t ctrl_wait, intr_wait;
 
 	BT_DBG("session %p", session);
 
-	if (session->input) {
-		vendor  = session->input->id.vendor;
-		product = session->input->id.product;
-	}
-
-	if (session->hid) {
-		vendor  = session->hid->vendor;
-		product = session->hid->product;
-	}
-
-	daemonize("khidpd_%04x%04x", vendor, product);
 	set_user_nice(current, -15);
 
 	init_waitqueue_entry(&ctrl_wait, current);
@@ -718,10 +706,11 @@
 	add_wait_queue(sk_sleep(intr_sk), &intr_wait);
 	session->waiting_for_startup = 0;
 	wake_up_interruptible(&session->startup_queue);
-	while (!atomic_read(&session->terminate)) {
+	while (!kthread_should_stop()) {
 		set_current_state(TASK_INTERRUPTIBLE);
 
-		if (ctrl_sk->sk_state != BT_CONNECTED || intr_sk->sk_state != BT_CONNECTED)
+		if (ctrl_sk->sk_state != BT_CONNECTED ||
+				intr_sk->sk_state != BT_CONNECTED)
 			break;
 
 		while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
@@ -965,6 +954,7 @@
 int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock)
 {
 	struct hidp_session *session, *s;
+	int vendor, product;
 	int err;
 
 	BT_DBG("");
@@ -1026,9 +1016,24 @@
 
 	hidp_set_timer(session);
 
-	err = kernel_thread(hidp_session, session, CLONE_KERNEL);
-	if (err < 0)
+	if (session->hid) {
+		vendor  = session->hid->vendor;
+		product = session->hid->product;
+	} else if (session->input) {
+		vendor  = session->input->id.vendor;
+		product = session->input->id.product;
+	} else {
+		vendor = 0x0000;
+		product = 0x0000;
+	}
+
+	session->task = kthread_run(hidp_session, session, "khidpd_%04x%04x",
+							vendor, product);
+	if (IS_ERR(session->task)) {
+		err = PTR_ERR(session->task);
 		goto unlink;
+	}
+
 	while (session->waiting_for_startup) {
 		wait_event_interruptible(session->startup_queue,
 			!session->waiting_for_startup);
@@ -1053,8 +1058,7 @@
 err_add_device:
 	hid_destroy_device(session->hid);
 	session->hid = NULL;
-	atomic_inc(&session->terminate);
-	hidp_schedule(session);
+	kthread_stop(session->task);
 
 unlink:
 	hidp_del_timer(session);
@@ -1105,13 +1109,7 @@
 			skb_queue_purge(&session->ctrl_transmit);
 			skb_queue_purge(&session->intr_transmit);
 
-			/* Wakeup user-space polling for socket errors */
-			session->intr_sock->sk->sk_err = EUNATCH;
-			session->ctrl_sock->sk->sk_err = EUNATCH;
-
-			/* Kill session thread */
-			atomic_inc(&session->terminate);
-			hidp_schedule(session);
+			kthread_stop(session->task);
 		}
 	} else
 		err = -ENOENT;
diff --git a/net/bluetooth/hidp/hidp.h b/net/bluetooth/hidp/hidp.h
index 13de5fa..12822cd 100644
--- a/net/bluetooth/hidp/hidp.h
+++ b/net/bluetooth/hidp/hidp.h
@@ -84,8 +84,8 @@
 #define HIDP_WAITING_FOR_SEND_ACK	11
 
 struct hidp_connadd_req {
-	int   ctrl_sock;	// Connected control socket
-	int   intr_sock;	// Connteted interrupt socket
+	int   ctrl_sock;	/* Connected control socket */
+	int   intr_sock;	/* Connected interrupt socket */
 	__u16 parser;
 	__u16 rd_size;
 	__u8 __user *rd_data;
@@ -142,7 +142,7 @@
 	uint ctrl_mtu;
 	uint intr_mtu;
 
-	atomic_t terminate;
+	struct task_struct *task;
 
 	unsigned char keys[8];
 	unsigned char leds;
diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c
index 250dfd4..178ac7f 100644
--- a/net/bluetooth/hidp/sock.c
+++ b/net/bluetooth/hidp/sock.c
@@ -85,7 +85,8 @@
 			return err;
 		}
 
-		if (csock->sk->sk_state != BT_CONNECTED || isock->sk->sk_state != BT_CONNECTED) {
+		if (csock->sk->sk_state != BT_CONNECTED ||
+				isock->sk->sk_state != BT_CONNECTED) {
 			sockfd_put(csock);
 			sockfd_put(isock);
 			return -EBADFD;
@@ -140,8 +141,8 @@
 
 #ifdef CONFIG_COMPAT
 struct compat_hidp_connadd_req {
-	int   ctrl_sock;	// Connected control socket
-	int   intr_sock;	// Connteted interrupt socket
+	int   ctrl_sock;	/* Connected control socket */
+	int   intr_sock;	/* Connected interrupt socket */
 	__u16 parser;
 	__u16 rd_size;
 	compat_uptr_t rd_data;
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index ca27f3a..c3cebed 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -169,7 +169,7 @@
 	__sock_put(sk);
 }
 
-static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
+static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk)
 {
 	struct l2cap_chan_list *l = &conn->chan_list;
 
@@ -204,9 +204,6 @@
 	}
 
 	__l2cap_chan_link(l, sk);
-
-	if (parent)
-		bt_accept_enqueue(parent, sk);
 }
 
 /* Delete channel.
@@ -652,7 +649,9 @@
 	bacpy(&bt_sk(sk)->src, conn->src);
 	bacpy(&bt_sk(sk)->dst, conn->dst);
 
-	__l2cap_chan_add(conn, sk, parent);
+	bt_accept_enqueue(parent, sk);
+
+	__l2cap_chan_add(conn, sk);
 
 	l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
 
@@ -793,11 +792,11 @@
 	kfree(conn);
 }
 
-static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
+static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk)
 {
 	struct l2cap_chan_list *l = &conn->chan_list;
 	write_lock_bh(&l->lock);
-	__l2cap_chan_add(conn, sk, parent);
+	__l2cap_chan_add(conn, sk);
 	write_unlock_bh(&l->lock);
 }
 
@@ -876,7 +875,7 @@
 	/* Update source addr of the socket */
 	bacpy(src, conn->src);
 
-	l2cap_chan_add(conn, sk, NULL);
+	l2cap_chan_add(conn, sk);
 
 	sk->sk_state = BT_CONNECT;
 	l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
@@ -2032,7 +2031,9 @@
 	l2cap_pi(sk)->psm  = psm;
 	l2cap_pi(sk)->dcid = scid;
 
-	__l2cap_chan_add(conn, sk, parent);
+	bt_accept_enqueue(parent, sk);
+
+	__l2cap_chan_add(conn, sk);
 	dcid = l2cap_pi(sk)->scid;
 
 	l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
@@ -2462,6 +2463,11 @@
 
 	BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
 
+	/* L2CAP Info req/rsp are unbound to channels, add extra checks */
+	if (cmd->ident != conn->info_ident ||
+			conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
+		return 0;
+
 	del_timer(&conn->info_timer);
 
 	if (result != L2CAP_IR_SUCCESS) {
@@ -2672,7 +2678,8 @@
 
 		if (err) {
 			struct l2cap_cmd_rej rej;
-			BT_DBG("error %d", err);
+
+			BT_ERR("Wrong link type (%d)", err);
 
 			/* FIXME: Map err to a valid reason */
 			rej.reason = cpu_to_le16(0);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 4476d8e..c304688 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -36,7 +36,7 @@
 	struct list_head list;
 	__u16 opcode;
 	int index;
-	void *cmd;
+	void *param;
 	struct sock *sk;
 	void *user_data;
 };
@@ -179,10 +179,12 @@
 
 	hci_del_off_timer(hdev);
 
-	hci_dev_lock_bh(hdev);
+	hci_dev_lock(hdev);
 
 	set_bit(HCI_MGMT, &hdev->flags);
 
+	memset(&rp, 0, sizeof(rp));
+
 	rp.type = hdev->dev_type;
 
 	rp.powered = test_bit(HCI_UP, &hdev->flags);
@@ -204,7 +206,9 @@
 	rp.hci_ver = hdev->hci_ver;
 	put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
 
-	hci_dev_unlock_bh(hdev);
+	memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
+
+	hci_dev_unlock(hdev);
 	hci_dev_put(hdev);
 
 	return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
@@ -213,7 +217,7 @@
 static void mgmt_pending_free(struct pending_cmd *cmd)
 {
 	sock_put(cmd->sk);
-	kfree(cmd->cmd);
+	kfree(cmd->param);
 	kfree(cmd);
 }
 
@@ -229,13 +233,14 @@
 	cmd->opcode = opcode;
 	cmd->index = index;
 
-	cmd->cmd = kmalloc(len, GFP_ATOMIC);
-	if (!cmd->cmd) {
+	cmd->param = kmalloc(len, GFP_ATOMIC);
+	if (!cmd->param) {
 		kfree(cmd);
 		return NULL;
 	}
 
-	memcpy(cmd->cmd, data, len);
+	if (data)
+		memcpy(cmd->param, data, len);
 
 	cmd->sk = sk;
 	sock_hold(sk);
@@ -311,7 +316,7 @@
 	if (!hdev)
 		return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
 
-	hci_dev_lock_bh(hdev);
+	hci_dev_lock(hdev);
 
 	up = test_bit(HCI_UP, &hdev->flags);
 	if ((cp->val && up) || (!cp->val && !up)) {
@@ -338,7 +343,7 @@
 	err = 0;
 
 failed:
-	hci_dev_unlock_bh(hdev);
+	hci_dev_unlock(hdev);
 	hci_dev_put(hdev);
 	return err;
 }
@@ -363,7 +368,7 @@
 	if (!hdev)
 		return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
 
-	hci_dev_lock_bh(hdev);
+	hci_dev_lock(hdev);
 
 	if (!test_bit(HCI_UP, &hdev->flags)) {
 		err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
@@ -398,7 +403,7 @@
 		mgmt_pending_remove(cmd);
 
 failed:
-	hci_dev_unlock_bh(hdev);
+	hci_dev_unlock(hdev);
 	hci_dev_put(hdev);
 
 	return err;
@@ -424,7 +429,7 @@
 	if (!hdev)
 		return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
 
-	hci_dev_lock_bh(hdev);
+	hci_dev_lock(hdev);
 
 	if (!test_bit(HCI_UP, &hdev->flags)) {
 		err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
@@ -458,7 +463,7 @@
 		mgmt_pending_remove(cmd);
 
 failed:
-	hci_dev_unlock_bh(hdev);
+	hci_dev_unlock(hdev);
 	hci_dev_put(hdev);
 
 	return err;
@@ -517,7 +522,7 @@
 	if (!hdev)
 		return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
 
-	hci_dev_lock_bh(hdev);
+	hci_dev_lock(hdev);
 
 	if (cp->val)
 		set_bit(HCI_PAIRABLE, &hdev->flags);
@@ -533,12 +538,156 @@
 	err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
 
 failed:
-	hci_dev_unlock_bh(hdev);
+	hci_dev_unlock(hdev);
 	hci_dev_put(hdev);
 
 	return err;
 }
 
+#define EIR_FLAGS		0x01 /* flags */
+#define EIR_UUID16_SOME		0x02 /* 16-bit UUID, more available */
+#define EIR_UUID16_ALL		0x03 /* 16-bit UUID, all listed */
+#define EIR_UUID32_SOME		0x04 /* 32-bit UUID, more available */
+#define EIR_UUID32_ALL		0x05 /* 32-bit UUID, all listed */
+#define EIR_UUID128_SOME	0x06 /* 128-bit UUID, more available */
+#define EIR_UUID128_ALL		0x07 /* 128-bit UUID, all listed */
+#define EIR_NAME_SHORT		0x08 /* shortened local name */
+#define EIR_NAME_COMPLETE	0x09 /* complete local name */
+#define EIR_TX_POWER		0x0A /* transmit power level */
+#define EIR_DEVICE_ID		0x10 /* device ID */
+
+#define PNP_INFO_SVCLASS_ID		0x1200
+
+static u8 bluetooth_base_uuid[] = {
+			0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
+			0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static u16 get_uuid16(u8 *uuid128)
+{
+	u32 val;
+	int i;
+
+	for (i = 0; i < 12; i++) {
+		if (bluetooth_base_uuid[i] != uuid128[i])
+			return 0;
+	}
+
+	memcpy(&val, &uuid128[12], 4);
+
+	val = le32_to_cpu(val);
+	if (val > 0xffff)
+		return 0;
+
+	return (u16) val;
+}
+
+static void create_eir(struct hci_dev *hdev, u8 *data)
+{
+	u8 *ptr = data;
+	u16 eir_len = 0;
+	u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
+	int i, truncated = 0;
+	struct list_head *p;
+	size_t name_len;
+
+	name_len = strlen(hdev->dev_name);
+
+	if (name_len > 0) {
+		/* EIR Data type */
+		if (name_len > 48) {
+			name_len = 48;
+			ptr[1] = EIR_NAME_SHORT;
+		} else
+			ptr[1] = EIR_NAME_COMPLETE;
+
+		/* EIR Data length */
+		ptr[0] = name_len + 1;
+
+		memcpy(ptr + 2, hdev->dev_name, name_len);
+
+		eir_len += (name_len + 2);
+		ptr += (name_len + 2);
+	}
+
+	memset(uuid16_list, 0, sizeof(uuid16_list));
+
+	/* Group all UUID16 types */
+	list_for_each(p, &hdev->uuids) {
+		struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
+		u16 uuid16;
+
+		uuid16 = get_uuid16(uuid->uuid);
+		if (uuid16 == 0)
+			return;
+
+		if (uuid16 < 0x1100)
+			continue;
+
+		if (uuid16 == PNP_INFO_SVCLASS_ID)
+			continue;
+
+		/* Stop if not enough space to put next UUID */
+		if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
+			truncated = 1;
+			break;
+		}
+
+		/* Check for duplicates */
+		for (i = 0; uuid16_list[i] != 0; i++)
+			if (uuid16_list[i] == uuid16)
+				break;
+
+		if (uuid16_list[i] == 0) {
+			uuid16_list[i] = uuid16;
+			eir_len += sizeof(u16);
+		}
+	}
+
+	if (uuid16_list[0] != 0) {
+		u8 *length = ptr;
+
+		/* EIR Data type */
+		ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
+
+		ptr += 2;
+		eir_len += 2;
+
+		for (i = 0; uuid16_list[i] != 0; i++) {
+			*ptr++ = (uuid16_list[i] & 0x00ff);
+			*ptr++ = (uuid16_list[i] & 0xff00) >> 8;
+		}
+
+		/* EIR Data length */
+		*length = (i * sizeof(u16)) + 1;
+	}
+}
+
+static int update_eir(struct hci_dev *hdev)
+{
+	struct hci_cp_write_eir cp;
+
+	if (!(hdev->features[6] & LMP_EXT_INQ))
+		return 0;
+
+	if (hdev->ssp_mode == 0)
+		return 0;
+
+	if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
+		return 0;
+
+	memset(&cp, 0, sizeof(cp));
+
+	create_eir(hdev, cp.data);
+
+	if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
+		return 0;
+
+	memcpy(hdev->eir, cp.data, sizeof(cp.data));
+
+	return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
+}
+
 static u8 get_service_classes(struct hci_dev *hdev)
 {
 	struct list_head *p;
@@ -590,7 +739,7 @@
 	if (!hdev)
 		return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
 
-	hci_dev_lock_bh(hdev);
+	hci_dev_lock(hdev);
 
 	uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
 	if (!uuid) {
@@ -607,10 +756,14 @@
 	if (err < 0)
 		goto failed;
 
+	err = update_eir(hdev);
+	if (err < 0)
+		goto failed;
+
 	err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
 
 failed:
-	hci_dev_unlock_bh(hdev);
+	hci_dev_unlock(hdev);
 	hci_dev_put(hdev);
 
 	return err;
@@ -635,7 +788,7 @@
 	if (!hdev)
 		return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
 
-	hci_dev_lock_bh(hdev);
+	hci_dev_lock(hdev);
 
 	if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
 		err = hci_uuids_clear(hdev);
@@ -663,10 +816,14 @@
 	if (err < 0)
 		goto unlock;
 
+	err = update_eir(hdev);
+	if (err < 0)
+		goto unlock;
+
 	err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
 
 unlock:
-	hci_dev_unlock_bh(hdev);
+	hci_dev_unlock(hdev);
 	hci_dev_put(hdev);
 
 	return err;
@@ -690,7 +847,7 @@
 	if (!hdev)
 		return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
 
-	hci_dev_lock_bh(hdev);
+	hci_dev_lock(hdev);
 
 	hdev->major_class = cp->major;
 	hdev->minor_class = cp->minor;
@@ -700,7 +857,7 @@
 	if (err == 0)
 		err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
 
-	hci_dev_unlock_bh(hdev);
+	hci_dev_unlock(hdev);
 	hci_dev_put(hdev);
 
 	return err;
@@ -722,7 +879,7 @@
 	if (!hdev)
 		return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
 
-	hci_dev_lock_bh(hdev);
+	hci_dev_lock(hdev);
 
 	BT_DBG("hci%u enable %d", index, cp->enable);
 
@@ -732,13 +889,15 @@
 	} else {
 		clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
 		err = update_class(hdev);
+		if (err == 0)
+			err = update_eir(hdev);
 	}
 
 	if (err == 0)
 		err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
 									0);
 
-	hci_dev_unlock_bh(hdev);
+	hci_dev_unlock(hdev);
 	hci_dev_put(hdev);
 
 	return err;
@@ -772,7 +931,7 @@
 	BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
 								key_count);
 
-	hci_dev_lock_bh(hdev);
+	hci_dev_lock(hdev);
 
 	hci_link_keys_clear(hdev);
 
@@ -790,7 +949,7 @@
 								key->pin_len);
 	}
 
-	hci_dev_unlock_bh(hdev);
+	hci_dev_unlock(hdev);
 	hci_dev_put(hdev);
 
 	return 0;
@@ -812,7 +971,7 @@
 	if (!hdev)
 		return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
 
-	hci_dev_lock_bh(hdev);
+	hci_dev_lock(hdev);
 
 	err = hci_remove_link_key(hdev, &cp->bdaddr);
 	if (err < 0) {
@@ -835,7 +994,7 @@
 	}
 
 unlock:
-	hci_dev_unlock_bh(hdev);
+	hci_dev_unlock(hdev);
 	hci_dev_put(hdev);
 
 	return err;
@@ -861,7 +1020,7 @@
 	if (!hdev)
 		return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
 
-	hci_dev_lock_bh(hdev);
+	hci_dev_lock(hdev);
 
 	if (!test_bit(HCI_UP, &hdev->flags)) {
 		err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
@@ -893,7 +1052,7 @@
 		mgmt_pending_remove(cmd);
 
 failed:
-	hci_dev_unlock_bh(hdev);
+	hci_dev_unlock(hdev);
 	hci_dev_put(hdev);
 
 	return err;
@@ -914,7 +1073,7 @@
 	if (!hdev)
 		return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
 
-	hci_dev_lock_bh(hdev);
+	hci_dev_lock(hdev);
 
 	count = 0;
 	list_for_each(p, &hdev->conn_hash.list) {
@@ -945,7 +1104,7 @@
 
 unlock:
 	kfree(rp);
-	hci_dev_unlock_bh(hdev);
+	hci_dev_unlock(hdev);
 	hci_dev_put(hdev);
 	return err;
 }
@@ -970,7 +1129,7 @@
 	if (!hdev)
 		return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
 
-	hci_dev_lock_bh(hdev);
+	hci_dev_lock(hdev);
 
 	if (!test_bit(HCI_UP, &hdev->flags)) {
 		err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
@@ -992,7 +1151,7 @@
 		mgmt_pending_remove(cmd);
 
 failed:
-	hci_dev_unlock_bh(hdev);
+	hci_dev_unlock(hdev);
 	hci_dev_put(hdev);
 
 	return err;
@@ -1019,7 +1178,7 @@
 		return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
 									ENODEV);
 
-	hci_dev_lock_bh(hdev);
+	hci_dev_lock(hdev);
 
 	if (!test_bit(HCI_UP, &hdev->flags)) {
 		err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
@@ -1040,7 +1199,7 @@
 		mgmt_pending_remove(cmd);
 
 failed:
-	hci_dev_unlock_bh(hdev);
+	hci_dev_unlock(hdev);
 	hci_dev_put(hdev);
 
 	return err;
@@ -1063,14 +1222,14 @@
 	if (!hdev)
 		return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
 
-	hci_dev_lock_bh(hdev);
+	hci_dev_lock(hdev);
 
 	hdev->io_capability = cp->io_capability;
 
 	BT_DBG("%s IO capability set to 0x%02x", hdev->name,
 							hdev->io_capability);
 
-	hci_dev_unlock_bh(hdev);
+	hci_dev_unlock(hdev);
 	hci_dev_put(hdev);
 
 	return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
@@ -1156,7 +1315,7 @@
 	if (!hdev)
 		return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
 
-	hci_dev_lock_bh(hdev);
+	hci_dev_lock(hdev);
 
 	if (cp->io_cap == 0x03) {
 		sec_level = BT_SECURITY_MEDIUM;
@@ -1198,7 +1357,7 @@
 	err = 0;
 
 unlock:
-	hci_dev_unlock_bh(hdev);
+	hci_dev_unlock(hdev);
 	hci_dev_put(hdev);
 
 	return err;
@@ -1230,7 +1389,7 @@
 	if (!hdev)
 		return cmd_status(sk, index, mgmt_op, ENODEV);
 
-	hci_dev_lock_bh(hdev);
+	hci_dev_lock(hdev);
 
 	if (!test_bit(HCI_UP, &hdev->flags)) {
 		err = cmd_status(sk, index, mgmt_op, ENETDOWN);
@@ -1248,7 +1407,163 @@
 		mgmt_pending_remove(cmd);
 
 failed:
-	hci_dev_unlock_bh(hdev);
+	hci_dev_unlock(hdev);
+	hci_dev_put(hdev);
+
+	return err;
+}
+
+static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
+								u16 len)
+{
+	struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
+	struct hci_cp_write_local_name hci_cp;
+	struct hci_dev *hdev;
+	struct pending_cmd *cmd;
+	int err;
+
+	BT_DBG("");
+
+	if (len != sizeof(*mgmt_cp))
+		return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
+
+	hdev = hci_dev_get(index);
+	if (!hdev)
+		return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
+
+	hci_dev_lock(hdev);
+
+	cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
+	if (!cmd) {
+		err = -ENOMEM;
+		goto failed;
+	}
+
+	memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
+	err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
+								&hci_cp);
+	if (err < 0)
+		mgmt_pending_remove(cmd);
+
+failed:
+	hci_dev_unlock(hdev);
+	hci_dev_put(hdev);
+
+	return err;
+}
+
+static int read_local_oob_data(struct sock *sk, u16 index)
+{
+	struct hci_dev *hdev;
+	struct pending_cmd *cmd;
+	int err;
+
+	BT_DBG("hci%u", index);
+
+	hdev = hci_dev_get(index);
+	if (!hdev)
+		return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
+									ENODEV);
+
+	hci_dev_lock(hdev);
+
+	if (!test_bit(HCI_UP, &hdev->flags)) {
+		err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
+								ENETDOWN);
+		goto unlock;
+	}
+
+	if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
+		err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
+								EOPNOTSUPP);
+		goto unlock;
+	}
+
+	if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
+		err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
+		goto unlock;
+	}
+
+	cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
+	if (!cmd) {
+		err = -ENOMEM;
+		goto unlock;
+	}
+
+	err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
+	if (err < 0)
+		mgmt_pending_remove(cmd);
+
+unlock:
+	hci_dev_unlock(hdev);
+	hci_dev_put(hdev);
+
+	return err;
+}
+
+static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
+									u16 len)
+{
+	struct hci_dev *hdev;
+	struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
+	int err;
+
+	BT_DBG("hci%u ", index);
+
+	if (len != sizeof(*cp))
+		return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
+									EINVAL);
+
+	hdev = hci_dev_get(index);
+	if (!hdev)
+		return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
+									ENODEV);
+
+	hci_dev_lock(hdev);
+
+	err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
+								cp->randomizer);
+	if (err < 0)
+		err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
+	else
+		err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
+									0);
+
+	hci_dev_unlock(hdev);
+	hci_dev_put(hdev);
+
+	return err;
+}
+
+static int remove_remote_oob_data(struct sock *sk, u16 index,
+						unsigned char *data, u16 len)
+{
+	struct hci_dev *hdev;
+	struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
+	int err;
+
+	BT_DBG("hci%u ", index);
+
+	if (len != sizeof(*cp))
+		return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
+									EINVAL);
+
+	hdev = hci_dev_get(index);
+	if (!hdev)
+		return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
+									ENODEV);
+
+	hci_dev_lock(hdev);
+
+	err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
+	if (err < 0)
+		err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
+									-err);
+	else
+		err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
+								NULL, 0);
+
+	hci_dev_unlock(hdev);
 	hci_dev_put(hdev);
 
 	return err;
@@ -1266,7 +1581,7 @@
 	if (msglen < sizeof(*hdr))
 		return -EINVAL;
 
-	buf = kmalloc(msglen, GFP_ATOMIC);
+	buf = kmalloc(msglen, GFP_KERNEL);
 	if (!buf)
 		return -ENOMEM;
 
@@ -1349,6 +1664,20 @@
 	case MGMT_OP_USER_CONFIRM_NEG_REPLY:
 		err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
 		break;
+	case MGMT_OP_SET_LOCAL_NAME:
+		err = set_local_name(sk, index, buf + sizeof(*hdr), len);
+		break;
+	case MGMT_OP_READ_LOCAL_OOB_DATA:
+		err = read_local_oob_data(sk, index);
+		break;
+	case MGMT_OP_ADD_REMOTE_OOB_DATA:
+		err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
+		break;
+	case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
+		err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
+									len);
+		break;
+
 	default:
 		BT_DBG("Unknown op %u", opcode);
 		err = cmd_status(sk, index, opcode, 0x01);
@@ -1382,7 +1711,7 @@
 
 static void mode_rsp(struct pending_cmd *cmd, void *data)
 {
-	struct mgmt_mode *cp = cmd->cmd;
+	struct mgmt_mode *cp = cmd->param;
 	struct cmd_lookup *match = data;
 
 	if (cp->val != match->val)
@@ -1481,7 +1810,7 @@
 
 static void disconnect_rsp(struct pending_cmd *cmd, void *data)
 {
-	struct mgmt_cp_disconnect *cp = cmd->cmd;
+	struct mgmt_cp_disconnect *cp = cmd->param;
 	struct sock **sk = data;
 	struct mgmt_rp_disconnect rp;
 
@@ -1645,3 +1974,104 @@
 
 	return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
 }
+
+int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
+{
+	struct pending_cmd *cmd;
+	struct hci_dev *hdev;
+	struct mgmt_cp_set_local_name ev;
+	int err;
+
+	memset(&ev, 0, sizeof(ev));
+	memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
+
+	cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
+	if (!cmd)
+		goto send_event;
+
+	if (status) {
+		err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
+		goto failed;
+	}
+
+	hdev = hci_dev_get(index);
+	if (hdev) {
+		hci_dev_lock_bh(hdev);
+		update_eir(hdev);
+		hci_dev_unlock_bh(hdev);
+		hci_dev_put(hdev);
+	}
+
+	err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
+								sizeof(ev));
+	if (err < 0)
+		goto failed;
+
+send_event:
+	err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
+							cmd ? cmd->sk : NULL);
+
+failed:
+	if (cmd)
+		mgmt_pending_remove(cmd);
+	return err;
+}
+
+int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
+								u8 status)
+{
+	struct pending_cmd *cmd;
+	int err;
+
+	BT_DBG("hci%u status %u", index, status);
+
+	cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
+	if (!cmd)
+		return -ENOENT;
+
+	if (status) {
+		err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
+									EIO);
+	} else {
+		struct mgmt_rp_read_local_oob_data rp;
+
+		memcpy(rp.hash, hash, sizeof(rp.hash));
+		memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
+
+		err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
+							&rp, sizeof(rp));
+	}
+
+	mgmt_pending_remove(cmd);
+
+	return err;
+}
+
+int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
+								u8 *eir)
+{
+	struct mgmt_ev_device_found ev;
+
+	memset(&ev, 0, sizeof(ev));
+
+	bacpy(&ev.bdaddr, bdaddr);
+	memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
+	ev.rssi = rssi;
+
+	if (eir)
+		memcpy(ev.eir, eir, sizeof(ev.eir));
+
+	return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
+}
+
+int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name)
+{
+	struct mgmt_ev_remote_name ev;
+
+	memset(&ev, 0, sizeof(ev));
+
+	bacpy(&ev.bdaddr, bdaddr);
+	memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
+
+	return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
+}
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index 513f85c..f5fdfcb 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -2,7 +2,6 @@
 	tristate "Generic IEEE 802.11 Networking Stack (mac80211)"
 	depends on CFG80211
 	select CRYPTO
-	select CRYPTO_ECB
 	select CRYPTO_ARC4
 	select CRYPTO_AES
 	select CRC32
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 3342135..bf5d28d 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -342,7 +342,8 @@
 			STATION_INFO_TX_FAILED |
 			STATION_INFO_TX_BITRATE |
 			STATION_INFO_RX_BITRATE |
-			STATION_INFO_RX_DROP_MISC;
+			STATION_INFO_RX_DROP_MISC |
+			STATION_INFO_BSS_PARAM;
 
 	sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
 	sinfo->rx_bytes = sta->rx_bytes;
@@ -389,6 +390,16 @@
 		sinfo->plink_state = sta->plink_state;
 #endif
 	}
+
+	sinfo->bss_param.flags = 0;
+	if (sdata->vif.bss_conf.use_cts_prot)
+		sinfo->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT;
+	if (sdata->vif.bss_conf.use_short_preamble)
+		sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
+	if (sdata->vif.bss_conf.use_short_slot)
+		sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
+	sinfo->bss_param.dtim_period = sdata->local->hw.conf.ps_dtim_period;
+	sinfo->bss_param.beacon_interval = sdata->vif.bss_conf.beacon_int;
 }
 
 
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 51f0d78..0a602db 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -37,7 +37,7 @@
 	return simple_read_from_buffer(userbuf, count, ppos, buf, res);
 }
 
-#define DEBUGFS_READONLY_FILE(name, fmt, value...)			\
+#define DEBUGFS_READONLY_FILE_FN(name, fmt, value...)			\
 static ssize_t name## _read(struct file *file, char __user *userbuf,	\
 			    size_t count, loff_t *ppos)			\
 {									\
@@ -45,14 +45,19 @@
 									\
 	return mac80211_format_buffer(userbuf, count, ppos, 		\
 				      fmt "\n", ##value);		\
-}									\
-									\
+}
+
+#define DEBUGFS_READONLY_FILE_OPS(name)			\
 static const struct file_operations name## _ops = {			\
 	.read = name## _read,						\
 	.open = mac80211_open_file_generic,				\
 	.llseek = generic_file_llseek,					\
 };
 
+#define DEBUGFS_READONLY_FILE(name, fmt, value...)		\
+	DEBUGFS_READONLY_FILE_FN(name, fmt, value)		\
+	DEBUGFS_READONLY_FILE_OPS(name)
+
 #define DEBUGFS_ADD(name)						\
 	debugfs_create_file(#name, 0400, phyd, local, &name## _ops);
 
@@ -291,11 +296,70 @@
 	return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
 }
 
-static const struct file_operations channel_type_ops = {
-	.read = channel_type_read,
-	.open = mac80211_open_file_generic,
-	.llseek = default_llseek,
-};
+static ssize_t hwflags_read(struct file *file, char __user *user_buf,
+			    size_t count, loff_t *ppos)
+{
+	struct ieee80211_local *local = file->private_data;
+	int mxln = 500;
+	ssize_t rv;
+	char *buf = kzalloc(mxln, GFP_KERNEL);
+	int sf = 0; /* how many written so far */
+
+	sf += snprintf(buf, mxln - sf, "0x%x\n", local->hw.flags);
+	if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)
+		sf += snprintf(buf + sf, mxln - sf, "HAS_RATE_CONTROL\n");
+	if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
+		sf += snprintf(buf + sf, mxln - sf, "RX_INCLUDES_FCS\n");
+	if (local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING)
+		sf += snprintf(buf + sf, mxln - sf,
+			       "HOST_BCAST_PS_BUFFERING\n");
+	if (local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)
+		sf += snprintf(buf + sf, mxln - sf,
+			       "2GHZ_SHORT_SLOT_INCAPABLE\n");
+	if (local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)
+		sf += snprintf(buf + sf, mxln - sf,
+			       "2GHZ_SHORT_PREAMBLE_INCAPABLE\n");
+	if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
+		sf += snprintf(buf + sf, mxln - sf, "SIGNAL_UNSPEC\n");
+	if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
+		sf += snprintf(buf + sf, mxln - sf, "SIGNAL_DBM\n");
+	if (local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD)
+		sf += snprintf(buf + sf, mxln - sf, "NEED_DTIM_PERIOD\n");
+	if (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)
+		sf += snprintf(buf + sf, mxln - sf, "SPECTRUM_MGMT\n");
+	if (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)
+		sf += snprintf(buf + sf, mxln - sf, "AMPDU_AGGREGATION\n");
+	if (local->hw.flags & IEEE80211_HW_SUPPORTS_PS)
+		sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_PS\n");
+	if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)
+		sf += snprintf(buf + sf, mxln - sf, "PS_NULLFUNC_STACK\n");
+	if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
+		sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_PS\n");
+	if (local->hw.flags & IEEE80211_HW_MFP_CAPABLE)
+		sf += snprintf(buf + sf, mxln - sf, "MFP_CAPABLE\n");
+	if (local->hw.flags & IEEE80211_HW_BEACON_FILTER)
+		sf += snprintf(buf + sf, mxln - sf, "BEACON_FILTER\n");
+	if (local->hw.flags & IEEE80211_HW_SUPPORTS_STATIC_SMPS)
+		sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_STATIC_SMPS\n");
+	if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS)
+		sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_SMPS\n");
+	if (local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)
+		sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_UAPSD\n");
+	if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
+		sf += snprintf(buf + sf, mxln - sf, "REPORTS_TX_ACK_STATUS\n");
+	if (local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
+		sf += snprintf(buf + sf, mxln - sf, "CONNECTION_MONITOR\n");
+	if (local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)
+		sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_CQM_RSSI\n");
+	if (local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK)
+		sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_PER_STA_GTK\n");
+	if (local->hw.flags & IEEE80211_HW_AP_LINK_PS)
+		sf += snprintf(buf + sf, mxln - sf, "AP_LINK_PS\n");
+
+	rv = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
+	kfree(buf);
+	return rv;
+}
 
 static ssize_t queues_read(struct file *file, char __user *user_buf,
 			   size_t count, loff_t *ppos)
@@ -315,11 +379,9 @@
 	return simple_read_from_buffer(user_buf, count, ppos, buf, res);
 }
 
-static const struct file_operations queues_ops = {
-	.read = queues_read,
-	.open = mac80211_open_file_generic,
-	.llseek = default_llseek,
-};
+DEBUGFS_READONLY_FILE_OPS(hwflags);
+DEBUGFS_READONLY_FILE_OPS(channel_type);
+DEBUGFS_READONLY_FILE_OPS(queues);
 
 /* statistics stuff */
 
@@ -395,6 +457,7 @@
 	DEBUGFS_ADD(uapsd_queues);
 	DEBUGFS_ADD(uapsd_max_sp_len);
 	DEBUGFS_ADD(channel_type);
+	DEBUGFS_ADD(hwflags);
 	DEBUGFS_ADD(user_power);
 	DEBUGFS_ADD(power);
 
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 3e81af1..1488396 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -661,7 +661,6 @@
 static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
 					struct sk_buff *req)
 {
-	struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(req);
 	struct ieee80211_mgmt *mgmt = (void *)req->data;
 	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
 	struct ieee80211_local *local = sdata->local;
@@ -685,7 +684,7 @@
 	       mgmt->bssid, tx_last_beacon);
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
 
-	if (!tx_last_beacon && !(rx_status->rx_flags & IEEE80211_RX_RA_MATCH))
+	if (!tx_last_beacon && is_multicast_ether_addr(mgmt->da))
 		return;
 
 	if (memcmp(mgmt->bssid, ifibss->bssid, ETH_ALEN) != 0 &&
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index a404017..6eb2c852 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -809,8 +809,8 @@
 
 	struct rate_control_ref *rate_ctrl;
 
-	struct crypto_blkcipher *wep_tx_tfm;
-	struct crypto_blkcipher *wep_rx_tfm;
+	struct crypto_cipher *wep_tx_tfm;
+	struct crypto_cipher *wep_rx_tfm;
 	u32 wep_iv;
 
 	/* see iface.c */
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 562d298..dc50fc31 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -879,10 +879,6 @@
 
 	local->dynamic_ps_forced_timeout = -1;
 
-	result = sta_info_start(local);
-	if (result < 0)
-		goto fail_sta_info;
-
 	result = ieee80211_wep_init(local);
 	if (result < 0)
 		wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n",
@@ -945,7 +941,6 @@
 	rtnl_unlock();
 	ieee80211_wep_free(local);
 	sta_info_stop(local);
- fail_sta_info:
 	destroy_workqueue(local->workqueue);
  fail_workqueue:
 	wiphy_unregister(local->hw.wiphy);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 64d92d5..865fed4 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -90,20 +90,11 @@
 	/* no action required */
 	RX_MGMT_NONE,
 
-	/* caller must call cfg80211_send_rx_auth() */
-	RX_MGMT_CFG80211_AUTH,
-
-	/* caller must call cfg80211_send_rx_assoc() */
-	RX_MGMT_CFG80211_ASSOC,
-
 	/* caller must call cfg80211_send_deauth() */
 	RX_MGMT_CFG80211_DEAUTH,
 
 	/* caller must call cfg80211_send_disassoc() */
 	RX_MGMT_CFG80211_DISASSOC,
-
-	/* caller must tell cfg80211 about internal error */
-	RX_MGMT_CFG80211_ASSOC_ERROR,
 };
 
 /* utils */
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 2afeac9..fc2ff78 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -707,6 +707,8 @@
 	/*
 	 * If the current MPDU is in the right order and nothing else
 	 * is stored we can process it directly, no need to buffer it.
+	 * If it is first but there's something stored, we may be able
+	 * to release frames after this one.
 	 */
 	if (mpdu_seq_num == tid_agg_rx->head_seq_num &&
 	    tid_agg_rx->stored_mpdu_num == 0) {
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index d0311a3..999f8fb 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -698,6 +698,8 @@
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 	cancel_work_sync(&sta->drv_unblock_wk);
 
+	cfg80211_del_sta(sdata->dev, sta->sta.addr, GFP_KERNEL);
+
 	rate_control_remove_sta_debugfs(sta);
 	ieee80211_sta_debugfs_remove(sta);
 
@@ -766,9 +768,8 @@
 	if (!timer_needed)
 		return;
 
-	local->sta_cleanup.expires =
-		round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL);
-	add_timer(&local->sta_cleanup);
+	mod_timer(&local->sta_cleanup,
+		  round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL));
 }
 
 void sta_info_init(struct ieee80211_local *local)
@@ -781,14 +782,6 @@
 
 	setup_timer(&local->sta_cleanup, sta_info_cleanup,
 		    (unsigned long)local);
-	local->sta_cleanup.expires =
-		round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL);
-}
-
-int sta_info_start(struct ieee80211_local *local)
-{
-	add_timer(&local->sta_cleanup);
-	return 0;
 }
 
 void sta_info_stop(struct ieee80211_local *local)
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 5768114..43238e9 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -497,7 +497,6 @@
 void sta_info_clear_tim_bit(struct sta_info *sta);
 
 void sta_info_init(struct ieee80211_local *local);
-int sta_info_start(struct ieee80211_local *local);
 void sta_info_stop(struct ieee80211_local *local);
 int sta_info_flush(struct ieee80211_local *local,
 		   struct ieee80211_sub_if_data *sdata);
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index b936dd2..3ed3c83 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -189,16 +189,19 @@
 	bool acked;
 
 	for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
-		/* the HW cannot have attempted that rate */
-		if (i >= hw->max_report_rates) {
+		if (info->status.rates[i].idx < 0) {
+			break;
+		} else if (i >= hw->max_report_rates) {
+			/* the HW cannot have attempted that rate */
 			info->status.rates[i].idx = -1;
 			info->status.rates[i].count = 0;
-		} else if (info->status.rates[i].idx >= 0) {
-			rates_idx = i;
+			break;
 		}
 
 		retry_count += info->status.rates[i].count;
 	}
+	rates_idx = i - 1;
+
 	if (retry_count < 0)
 		retry_count = 0;
 
diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c
index e840c9c..757e4eb 100644
--- a/net/mac80211/tkip.c
+++ b/net/mac80211/tkip.c
@@ -202,7 +202,7 @@
  * @payload_len is the length of payload (_not_ including IV/ICV length).
  * @ta is the transmitter addresses.
  */
-int ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
+int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm,
 				struct ieee80211_key *key,
 				u8 *pos, size_t payload_len, u8 *ta)
 {
@@ -223,7 +223,7 @@
  * beginning of the buffer containing IEEE 802.11 header payload, i.e.,
  * including IV, Ext. IV, real data, Michael MIC, ICV. @payload_len is the
  * length of payload, including IV, Ext. IV, MIC, ICV.  */
-int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
+int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,
 				struct ieee80211_key *key,
 				u8 *payload, size_t payload_len, u8 *ta,
 				u8 *ra, int only_iv, int queue,
diff --git a/net/mac80211/tkip.h b/net/mac80211/tkip.h
index 7e83dee..1cab9c8 100644
--- a/net/mac80211/tkip.h
+++ b/net/mac80211/tkip.h
@@ -15,7 +15,7 @@
 
 u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key, u16 iv16);
 
-int ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
+int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm,
 				 struct ieee80211_key *key,
 				 u8 *pos, size_t payload_len, u8 *ta);
 enum {
@@ -24,7 +24,7 @@
 	TKIP_DECRYPT_INVALID_KEYIDX = -2,
 	TKIP_DECRYPT_REPLAY = -3,
 };
-int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
+int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,
 				struct ieee80211_key *key,
 				u8 *payload, size_t payload_len, u8 *ta,
 				u8 *ra, int only_iv, int queue,
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 556647a..ef0560a 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1290,7 +1290,7 @@
 		}
 	}
 
-	add_timer(&local->sta_cleanup);
+	mod_timer(&local->sta_cleanup, jiffies + 1);
 
 	mutex_lock(&local->sta_mtx);
 	list_for_each_entry(sta, &local->sta_list, list)
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c
index 2ff6d1e..a1c6bfd 100644
--- a/net/mac80211/wep.c
+++ b/net/mac80211/wep.c
@@ -30,17 +30,15 @@
 	/* start WEP IV from a random value */
 	get_random_bytes(&local->wep_iv, WEP_IV_LEN);
 
-	local->wep_tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0,
-						CRYPTO_ALG_ASYNC);
+	local->wep_tx_tfm = crypto_alloc_cipher("arc4", 0, CRYPTO_ALG_ASYNC);
 	if (IS_ERR(local->wep_tx_tfm)) {
 		local->wep_rx_tfm = ERR_PTR(-EINVAL);
 		return PTR_ERR(local->wep_tx_tfm);
 	}
 
-	local->wep_rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0,
-						CRYPTO_ALG_ASYNC);
+	local->wep_rx_tfm = crypto_alloc_cipher("arc4", 0, CRYPTO_ALG_ASYNC);
 	if (IS_ERR(local->wep_rx_tfm)) {
-		crypto_free_blkcipher(local->wep_tx_tfm);
+		crypto_free_cipher(local->wep_tx_tfm);
 		local->wep_tx_tfm = ERR_PTR(-EINVAL);
 		return PTR_ERR(local->wep_rx_tfm);
 	}
@@ -51,9 +49,9 @@
 void ieee80211_wep_free(struct ieee80211_local *local)
 {
 	if (!IS_ERR(local->wep_tx_tfm))
-		crypto_free_blkcipher(local->wep_tx_tfm);
+		crypto_free_cipher(local->wep_tx_tfm);
 	if (!IS_ERR(local->wep_rx_tfm))
-		crypto_free_blkcipher(local->wep_rx_tfm);
+		crypto_free_cipher(local->wep_rx_tfm);
 }
 
 static inline bool ieee80211_wep_weak_iv(u32 iv, int keylen)
@@ -127,12 +125,11 @@
 /* Perform WEP encryption using given key. data buffer must have tailroom
  * for 4-byte ICV. data_len must not include this ICV. Note: this function
  * does _not_ add IV. data = RC4(data | CRC32(data)) */
-int ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
+int ieee80211_wep_encrypt_data(struct crypto_cipher *tfm, u8 *rc4key,
 			       size_t klen, u8 *data, size_t data_len)
 {
-	struct blkcipher_desc desc = { .tfm = tfm };
-	struct scatterlist sg;
 	__le32 icv;
+	int i;
 
 	if (IS_ERR(tfm))
 		return -1;
@@ -140,9 +137,9 @@
 	icv = cpu_to_le32(~crc32_le(~0, data, data_len));
 	put_unaligned(icv, (__le32 *)(data + data_len));
 
-	crypto_blkcipher_setkey(tfm, rc4key, klen);
-	sg_init_one(&sg, data, data_len + WEP_ICV_LEN);
-	crypto_blkcipher_encrypt(&desc, &sg, &sg, sg.length);
+	crypto_cipher_setkey(tfm, rc4key, klen);
+	for (i = 0; i < data_len + WEP_ICV_LEN; i++)
+		crypto_cipher_encrypt_one(tfm, data + i, data + i);
 
 	return 0;
 }
@@ -186,19 +183,18 @@
 /* Perform WEP decryption using given key. data buffer includes encrypted
  * payload, including 4-byte ICV, but _not_ IV. data_len must not include ICV.
  * Return 0 on success and -1 on ICV mismatch. */
-int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
+int ieee80211_wep_decrypt_data(struct crypto_cipher *tfm, u8 *rc4key,
 			       size_t klen, u8 *data, size_t data_len)
 {
-	struct blkcipher_desc desc = { .tfm = tfm };
-	struct scatterlist sg;
 	__le32 crc;
+	int i;
 
 	if (IS_ERR(tfm))
 		return -1;
 
-	crypto_blkcipher_setkey(tfm, rc4key, klen);
-	sg_init_one(&sg, data, data_len + WEP_ICV_LEN);
-	crypto_blkcipher_decrypt(&desc, &sg, &sg, sg.length);
+	crypto_cipher_setkey(tfm, rc4key, klen);
+	for (i = 0; i < data_len + WEP_ICV_LEN; i++)
+		crypto_cipher_decrypt_one(tfm, data + i, data + i);
 
 	crc = cpu_to_le32(~crc32_le(~0, data, data_len));
 	if (memcmp(&crc, data + data_len, WEP_ICV_LEN) != 0)
diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h
index 58654ee..01e5484 100644
--- a/net/mac80211/wep.h
+++ b/net/mac80211/wep.h
@@ -18,12 +18,12 @@
 
 int ieee80211_wep_init(struct ieee80211_local *local);
 void ieee80211_wep_free(struct ieee80211_local *local);
-int ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
+int ieee80211_wep_encrypt_data(struct crypto_cipher *tfm, u8 *rc4key,
 				size_t klen, u8 *data, size_t data_len);
 int ieee80211_wep_encrypt(struct ieee80211_local *local,
 			  struct sk_buff *skb,
 			  const u8 *key, int keylen, int keyidx);
-int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
+int ieee80211_wep_decrypt_data(struct crypto_cipher *tfm, u8 *rc4key,
 			       size_t klen, u8 *data, size_t data_len);
 bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key);
 
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index aa5df88..16881fe 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -770,6 +770,15 @@
 }
 EXPORT_SYMBOL(cfg80211_new_sta);
 
+void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp)
+{
+	struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+	nl80211_send_sta_del_event(rdev, dev, mac_addr, gfp);
+}
+EXPORT_SYMBOL(cfg80211_del_sta);
+
 struct cfg80211_mgmt_registration {
 	struct list_head list;
 
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 4ebce42..297d7ce 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2002,7 +2002,7 @@
 				const u8 *mac_addr, struct station_info *sinfo)
 {
 	void *hdr;
-	struct nlattr *sinfoattr;
+	struct nlattr *sinfoattr, *bss_param;
 
 	hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION);
 	if (!hdr)
@@ -2062,6 +2062,25 @@
 	if (sinfo->filled & STATION_INFO_TX_FAILED)
 		NLA_PUT_U32(msg, NL80211_STA_INFO_TX_FAILED,
 			    sinfo->tx_failed);
+	if (sinfo->filled & STATION_INFO_BSS_PARAM) {
+		bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM);
+		if (!bss_param)
+			goto nla_put_failure;
+
+		if (sinfo->bss_param.flags & BSS_PARAM_FLAGS_CTS_PROT)
+			NLA_PUT_FLAG(msg, NL80211_STA_BSS_PARAM_CTS_PROT);
+		if (sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_PREAMBLE)
+			NLA_PUT_FLAG(msg, NL80211_STA_BSS_PARAM_SHORT_PREAMBLE);
+		if (sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_SLOT_TIME)
+			NLA_PUT_FLAG(msg,
+				     NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME);
+		NLA_PUT_U8(msg, NL80211_STA_BSS_PARAM_DTIM_PERIOD,
+			   sinfo->bss_param.dtim_period);
+		NLA_PUT_U16(msg, NL80211_STA_BSS_PARAM_BEACON_INTERVAL,
+			    sinfo->bss_param.beacon_interval);
+
+		nla_nest_end(msg, bss_param);
+	}
 	nla_nest_end(msg, sinfoattr);
 
 	return genlmsg_end(msg, hdr);
@@ -5966,6 +5985,40 @@
 				nl80211_mlme_mcgrp.id, gfp);
 }
 
+void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev,
+				struct net_device *dev, const u8 *mac_addr,
+				gfp_t gfp)
+{
+	struct sk_buff *msg;
+	void *hdr;
+
+	msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
+	if (!msg)
+		return;
+
+	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DEL_STATION);
+	if (!hdr) {
+		nlmsg_free(msg);
+		return;
+	}
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
+	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
+
+	if (genlmsg_end(msg, hdr) < 0) {
+		nlmsg_free(msg);
+		return;
+	}
+
+	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+				nl80211_mlme_mcgrp.id, gfp);
+	return;
+
+ nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+	nlmsg_free(msg);
+}
+
 int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
 		      struct net_device *netdev, u32 nlpid,
 		      int freq, const u8 *buf, size_t len, gfp_t gfp)
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index e3f7fa8..dcac5cd 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -79,6 +79,9 @@
 void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
 			    struct net_device *dev, const u8 *mac_addr,
 			    struct station_info *sinfo, gfp_t gfp);
+void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev,
+				struct net_device *dev, const u8 *mac_addr,
+				gfp_t gfp);
 
 int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
 		      struct net_device *netdev, u32 nlpid, int freq,
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 3332d5b..2714379 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -106,6 +106,9 @@
 static void reg_todo(struct work_struct *work);
 static DECLARE_WORK(reg_work, reg_todo);
 
+static void reg_timeout_work(struct work_struct *work);
+static DECLARE_DELAYED_WORK(reg_timeout, reg_timeout_work);
+
 /* We keep a static world regulatory domain in case of the absence of CRDA */
 static const struct ieee80211_regdomain world_regdom = {
 	.n_reg_rules = 5,
@@ -1330,6 +1333,9 @@
 		need_more_processing = true;
 	spin_unlock(&reg_requests_lock);
 
+	if (last_request->initiator == NL80211_REGDOM_SET_BY_USER)
+		cancel_delayed_work_sync(&reg_timeout);
+
 	if (need_more_processing)
 		schedule_work(&reg_work);
 }
@@ -1440,8 +1446,17 @@
 	r = __regulatory_hint(wiphy, reg_request);
 	/* This is required so that the orig_* parameters are saved */
 	if (r == -EALREADY && wiphy &&
-	    wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY)
+	    wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) {
 		wiphy_update_regulatory(wiphy, initiator);
+		return;
+	}
+
+	/*
+	 * We only time out user hints, given that they should be the only
+	 * source of bogus requests.
+	 */
+	if (reg_request->initiator == NL80211_REGDOM_SET_BY_USER)
+		schedule_delayed_work(&reg_timeout, msecs_to_jiffies(3142));
 }
 
 /*
@@ -1744,6 +1759,8 @@
 {
 	char alpha2[2];
 	struct reg_beacon *reg_beacon, *btmp;
+	struct regulatory_request *reg_request, *tmp;
+	LIST_HEAD(tmp_reg_req_list);
 
 	mutex_lock(&cfg80211_mutex);
 	mutex_lock(&reg_mutex);
@@ -1751,6 +1768,25 @@
 	reset_regdomains();
 	restore_alpha2(alpha2, reset_user);
 
+	/*
+	 * If there's any pending requests we simply
+	 * stash them to a temporary pending queue and
+	 * add then after we've restored regulatory
+	 * settings.
+	 */
+	spin_lock(&reg_requests_lock);
+	if (!list_empty(&reg_requests_list)) {
+		list_for_each_entry_safe(reg_request, tmp,
+					 &reg_requests_list, list) {
+			if (reg_request->initiator !=
+			    NL80211_REGDOM_SET_BY_USER)
+				continue;
+			list_del(&reg_request->list);
+			list_add_tail(&reg_request->list, &tmp_reg_req_list);
+		}
+	}
+	spin_unlock(&reg_requests_lock);
+
 	/* Clear beacon hints */
 	spin_lock_bh(&reg_pending_beacons_lock);
 	if (!list_empty(&reg_pending_beacons)) {
@@ -1785,8 +1821,31 @@
 	 */
 	if (is_an_alpha2(alpha2))
 		regulatory_hint_user(user_alpha2);
-}
 
+	if (list_empty(&tmp_reg_req_list))
+		return;
+
+	mutex_lock(&cfg80211_mutex);
+	mutex_lock(&reg_mutex);
+
+	spin_lock(&reg_requests_lock);
+	list_for_each_entry_safe(reg_request, tmp, &tmp_reg_req_list, list) {
+		REG_DBG_PRINT("Adding request for country %c%c back "
+			      "into the queue\n",
+			      reg_request->alpha2[0],
+			      reg_request->alpha2[1]);
+		list_del(&reg_request->list);
+		list_add_tail(&reg_request->list, &reg_requests_list);
+	}
+	spin_unlock(&reg_requests_lock);
+
+	mutex_unlock(&reg_mutex);
+	mutex_unlock(&cfg80211_mutex);
+
+	REG_DBG_PRINT("Kicking the queue\n");
+
+	schedule_work(&reg_work);
+}
 
 void regulatory_hint_disconnect(void)
 {
@@ -2125,6 +2184,13 @@
 	mutex_unlock(&reg_mutex);
 }
 
+static void reg_timeout_work(struct work_struct *work)
+{
+	REG_DBG_PRINT("Timeout while waiting for CRDA to reply, "
+		      "restoring regulatory settings");
+	restore_regulatory_settings(true);
+}
+
 int __init regulatory_init(void)
 {
 	int err = 0;
@@ -2178,6 +2244,7 @@
 	struct reg_beacon *reg_beacon, *btmp;
 
 	cancel_work_sync(&reg_work);
+	cancel_delayed_work_sync(&reg_timeout);
 
 	mutex_lock(&cfg80211_mutex);
 	mutex_lock(&reg_mutex);