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

Conflicts:
	drivers/net/wireless/iwlwifi/iwl-core.c
	drivers/net/wireless/rt2x00/rt2x00queue.c
	drivers/net/wireless/rt2x00/rt2x00queue.h
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index 8e0de9a..11b41fd 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -188,7 +188,7 @@
 	  The core driver to support Marvell Bluetooth devices.
 
 	  This driver is required if you want to support
-	  Marvell Bluetooth devices, such as 8688.
+	  Marvell Bluetooth devices, such as 8688/8787.
 
 	  Say Y here to compile Marvell Bluetooth driver
 	  into the kernel or say M to compile it as module.
@@ -201,7 +201,7 @@
 	  The driver for Marvell Bluetooth chipsets with SDIO interface.
 
 	  This driver is required if you want to use Marvell Bluetooth
-	  devices with SDIO interface. Currently only SD8688 chipset is
+	  devices with SDIO interface. Currently SD8688/SD8787 chipsets are
 	  supported.
 
 	  Say Y here to compile support for Marvell BT-over-SDIO driver
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index 5577ed6..695d441 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -138,9 +138,6 @@
 		count -= size;
 	}
 
-	kfree(send_buf);
-	return 0;
-
 error:
 	kfree(send_buf);
 	return err;
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index dcc2a6e..7f521d4 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -49,15 +49,59 @@
 static u8 user_rmmod;
 static u8 sdio_ireg;
 
+static const struct btmrvl_sdio_card_reg btmrvl_reg_8688 = {
+	.cfg = 0x03,
+	.host_int_mask = 0x04,
+	.host_intstatus = 0x05,
+	.card_status = 0x20,
+	.sq_read_base_addr_a0 = 0x10,
+	.sq_read_base_addr_a1 = 0x11,
+	.card_fw_status0 = 0x40,
+	.card_fw_status1 = 0x41,
+	.card_rx_len = 0x42,
+	.card_rx_unit = 0x43,
+	.io_port_0 = 0x00,
+	.io_port_1 = 0x01,
+	.io_port_2 = 0x02,
+};
+static const struct btmrvl_sdio_card_reg btmrvl_reg_8787 = {
+	.cfg = 0x00,
+	.host_int_mask = 0x02,
+	.host_intstatus = 0x03,
+	.card_status = 0x30,
+	.sq_read_base_addr_a0 = 0x40,
+	.sq_read_base_addr_a1 = 0x41,
+	.card_revision = 0x5c,
+	.card_fw_status0 = 0x60,
+	.card_fw_status1 = 0x61,
+	.card_rx_len = 0x62,
+	.card_rx_unit = 0x63,
+	.io_port_0 = 0x78,
+	.io_port_1 = 0x79,
+	.io_port_2 = 0x7a,
+};
+
 static const struct btmrvl_sdio_device btmrvl_sdio_sd6888 = {
 	.helper		= "sd8688_helper.bin",
 	.firmware	= "sd8688.bin",
+	.reg		= &btmrvl_reg_8688,
+	.sd_blksz_fw_dl	= 64,
+};
+
+static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = {
+	.helper		= NULL,
+	.firmware	= "mrvl/sd8787_uapsta.bin",
+	.reg		= &btmrvl_reg_8787,
+	.sd_blksz_fw_dl	= 256,
 };
 
 static const struct sdio_device_id btmrvl_sdio_ids[] = {
 	/* Marvell SD8688 Bluetooth device */
 	{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9105),
 			.driver_data = (unsigned long) &btmrvl_sdio_sd6888 },
+	/* Marvell SD8787 Bluetooth device */
+	{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911A),
+			.driver_data = (unsigned long) &btmrvl_sdio_sd8787 },
 
 	{ }	/* Terminating entry */
 };
@@ -69,7 +113,7 @@
 	u8 reg;
 	int ret;
 
-	reg = sdio_readb(card->func, CARD_RX_UNIT_REG, &ret);
+	reg = sdio_readb(card->func, card->reg->card_rx_unit, &ret);
 	if (!ret)
 		card->rx_unit = reg;
 
@@ -83,11 +127,11 @@
 
 	*dat = 0;
 
-	fws0 = sdio_readb(card->func, CARD_FW_STATUS0_REG, &ret);
+	fws0 = sdio_readb(card->func, card->reg->card_fw_status0, &ret);
 	if (ret)
 		return -EIO;
 
-	fws1 = sdio_readb(card->func, CARD_FW_STATUS1_REG, &ret);
+	fws1 = sdio_readb(card->func, card->reg->card_fw_status1, &ret);
 	if (ret)
 		return -EIO;
 
@@ -101,7 +145,7 @@
 	u8 reg;
 	int ret;
 
-	reg = sdio_readb(card->func, CARD_RX_LEN_REG, &ret);
+	reg = sdio_readb(card->func, card->reg->card_rx_len, &ret);
 	if (!ret)
 		*dat = (u16) reg << card->rx_unit;
 
@@ -113,7 +157,7 @@
 {
 	int ret;
 
-	sdio_writeb(card->func, mask, HOST_INT_MASK_REG, &ret);
+	sdio_writeb(card->func, mask, card->reg->host_int_mask, &ret);
 	if (ret) {
 		BT_ERR("Unable to enable the host interrupt!");
 		ret = -EIO;
@@ -128,13 +172,13 @@
 	u8 host_int_mask;
 	int ret;
 
-	host_int_mask = sdio_readb(card->func, HOST_INT_MASK_REG, &ret);
+	host_int_mask = sdio_readb(card->func, card->reg->host_int_mask, &ret);
 	if (ret)
 		return -EIO;
 
 	host_int_mask &= ~mask;
 
-	sdio_writeb(card->func, host_int_mask, HOST_INT_MASK_REG, &ret);
+	sdio_writeb(card->func, host_int_mask, card->reg->host_int_mask, &ret);
 	if (ret < 0) {
 		BT_ERR("Unable to disable the host interrupt!");
 		return -EIO;
@@ -150,7 +194,7 @@
 	int ret;
 
 	for (tries = 0; tries < MAX_POLL_TRIES * 1000; tries++) {
-		status = sdio_readb(card->func, CARD_STATUS_REG, &ret);
+		status = sdio_readb(card->func, card->reg->card_status,	&ret);
 		if (ret)
 			goto failed;
 		if ((status & bits) == bits)
@@ -299,7 +343,7 @@
 	u8 base0, base1;
 	void *tmpfwbuf = NULL;
 	u8 *fwbuf;
-	u16 len;
+	u16 len, blksz_dl = card->sd_blksz_fw_dl;
 	int txlen = 0, tx_blocks = 0, count = 0;
 
 	ret = request_firmware(&fw_firmware, card->firmware,
@@ -345,7 +389,7 @@
 
 		for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
 			base0 = sdio_readb(card->func,
-					SQ_READ_BASE_ADDRESS_A0_REG, &ret);
+					card->reg->sq_read_base_addr_a0, &ret);
 			if (ret) {
 				BT_ERR("BASE0 register read failed:"
 					" base0 = 0x%04X(%d)."
@@ -355,7 +399,7 @@
 				goto done;
 			}
 			base1 = sdio_readb(card->func,
-					SQ_READ_BASE_ADDRESS_A1_REG, &ret);
+					card->reg->sq_read_base_addr_a1, &ret);
 			if (ret) {
 				BT_ERR("BASE1 register read failed:"
 					" base1 = 0x%04X(%d)."
@@ -403,20 +447,19 @@
 			if (firmwarelen - offset < txlen)
 				txlen = firmwarelen - offset;
 
-			tx_blocks =
-			    (txlen + SDIO_BLOCK_SIZE - 1) / SDIO_BLOCK_SIZE;
+			tx_blocks = (txlen + blksz_dl - 1) / blksz_dl;
 
 			memcpy(fwbuf, &firmware[offset], txlen);
 		}
 
 		ret = sdio_writesb(card->func, card->ioport, fwbuf,
-					tx_blocks * SDIO_BLOCK_SIZE);
+						tx_blocks * blksz_dl);
 
 		if (ret < 0) {
 			BT_ERR("FW download, writesb(%d) failed @%d",
 							count, offset);
-			sdio_writeb(card->func, HOST_CMD53_FIN, CONFIG_REG,
-									&ret);
+			sdio_writeb(card->func, HOST_CMD53_FIN,
+						card->reg->cfg, &ret);
 			if (ret)
 				BT_ERR("writeb failed (CFG)");
 		}
@@ -597,7 +640,7 @@
 
 	priv = card->priv;
 
-	ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret);
+	ireg = sdio_readb(card->func, card->reg->host_intstatus, &ret);
 	if (ret) {
 		BT_ERR("sdio_readb: read int status register failed");
 		return;
@@ -613,7 +656,7 @@
 
 		sdio_writeb(card->func, ~(ireg) & (DN_LD_HOST_INT_STATUS |
 					UP_LD_HOST_INT_STATUS),
-				HOST_INTSTATUS_REG, &ret);
+				card->reg->host_intstatus, &ret);
 		if (ret) {
 			BT_ERR("sdio_writeb: clear int status register failed");
 			return;
@@ -664,7 +707,7 @@
 		goto release_irq;
 	}
 
-	reg = sdio_readb(func, IO_PORT_0_REG, &ret);
+	reg = sdio_readb(func, card->reg->io_port_0, &ret);
 	if (ret < 0) {
 		ret = -EIO;
 		goto release_irq;
@@ -672,7 +715,7 @@
 
 	card->ioport = reg;
 
-	reg = sdio_readb(func, IO_PORT_1_REG, &ret);
+	reg = sdio_readb(func, card->reg->io_port_1, &ret);
 	if (ret < 0) {
 		ret = -EIO;
 		goto release_irq;
@@ -680,7 +723,7 @@
 
 	card->ioport |= (reg << 8);
 
-	reg = sdio_readb(func, IO_PORT_2_REG, &ret);
+	reg = sdio_readb(func, card->reg->io_port_2, &ret);
 	if (ret < 0) {
 		ret = -EIO;
 		goto release_irq;
@@ -815,6 +858,8 @@
 static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card)
 {
 	int ret = 0;
+	u8 fws0;
+	int pollnum = MAX_POLL_TRIES;
 
 	if (!card || !card->func) {
 		BT_ERR("card or function is NULL!");
@@ -827,20 +872,36 @@
 		goto done;
 	}
 
-	ret = btmrvl_sdio_download_helper(card);
+	/* Check if other function driver is downloading the firmware */
+	fws0 = sdio_readb(card->func, card->reg->card_fw_status0, &ret);
 	if (ret) {
-		BT_ERR("Failed to download helper!");
+		BT_ERR("Failed to read FW downloading status!");
 		ret = -EIO;
 		goto done;
 	}
+	if (fws0) {
+		BT_DBG("BT not the winner (%#x). Skip FW downloading", fws0);
 
-	if (btmrvl_sdio_download_fw_w_helper(card)) {
-		BT_ERR("Failed to download firmware!");
-		ret = -EIO;
-		goto done;
+		/* Give other function more time to download the firmware */
+		pollnum *= 10;
+	} else {
+		if (card->helper) {
+			ret = btmrvl_sdio_download_helper(card);
+			if (ret) {
+				BT_ERR("Failed to download helper!");
+				ret = -EIO;
+				goto done;
+			}
+		}
+
+		if (btmrvl_sdio_download_fw_w_helper(card)) {
+			BT_ERR("Failed to download firmware!");
+			ret = -EIO;
+			goto done;
+		}
 	}
 
-	if (btmrvl_sdio_verify_fw_download(card, MAX_POLL_TRIES)) {
+	if (btmrvl_sdio_verify_fw_download(card, pollnum)) {
 		BT_ERR("FW failed to be active in time!");
 		ret = -ETIMEDOUT;
 		goto done;
@@ -864,7 +925,7 @@
 
 	sdio_claim_host(card->func);
 
-	sdio_writeb(card->func, HOST_POWER_UP, CONFIG_REG, &ret);
+	sdio_writeb(card->func, HOST_POWER_UP, card->reg->cfg, &ret);
 
 	sdio_release_host(card->func);
 
@@ -893,8 +954,10 @@
 
 	if (id->driver_data) {
 		struct btmrvl_sdio_device *data = (void *) id->driver_data;
-		card->helper   = data->helper;
+		card->helper = data->helper;
 		card->firmware = data->firmware;
+		card->reg = data->reg;
+		card->sd_blksz_fw_dl = data->sd_blksz_fw_dl;
 	}
 
 	if (btmrvl_sdio_register_dev(card) < 0) {
@@ -1011,3 +1074,4 @@
 MODULE_LICENSE("GPL v2");
 MODULE_FIRMWARE("sd8688_helper.bin");
 MODULE_FIRMWARE("sd8688.bin");
+MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");
diff --git a/drivers/bluetooth/btmrvl_sdio.h b/drivers/bluetooth/btmrvl_sdio.h
index 27329f1..43d35a6 100644
--- a/drivers/bluetooth/btmrvl_sdio.h
+++ b/drivers/bluetooth/btmrvl_sdio.h
@@ -47,44 +47,46 @@
 /* Max retry number of CMD53 write */
 #define MAX_WRITE_IOMEM_RETRY		2
 
-/* Host Control Registers */
-#define IO_PORT_0_REG			0x00
-#define IO_PORT_1_REG			0x01
-#define IO_PORT_2_REG			0x02
+/* register bitmasks */
+#define HOST_POWER_UP				BIT(1)
+#define HOST_CMD53_FIN				BIT(2)
 
-#define CONFIG_REG			0x03
-#define HOST_POWER_UP			BIT(1)
-#define HOST_CMD53_FIN			BIT(2)
+#define HIM_DISABLE				0xff
+#define HIM_ENABLE				(BIT(0) | BIT(1))
 
-#define HOST_INT_MASK_REG		0x04
-#define HIM_DISABLE			0xff
-#define HIM_ENABLE			(BIT(0) | BIT(1))
+#define UP_LD_HOST_INT_STATUS			BIT(0)
+#define DN_LD_HOST_INT_STATUS			BIT(1)
 
-#define HOST_INTSTATUS_REG		0x05
-#define UP_LD_HOST_INT_STATUS		BIT(0)
-#define DN_LD_HOST_INT_STATUS		BIT(1)
+#define DN_LD_CARD_RDY				BIT(0)
+#define CARD_IO_READY				BIT(3)
 
-/* Card Control Registers */
-#define SQ_READ_BASE_ADDRESS_A0_REG  	0x10
-#define SQ_READ_BASE_ADDRESS_A1_REG  	0x11
+#define FIRMWARE_READY				0xfedc
 
-#define CARD_STATUS_REG              	0x20
-#define DN_LD_CARD_RDY               	BIT(0)
-#define CARD_IO_READY              	BIT(3)
 
-#define CARD_FW_STATUS0_REG		0x40
-#define CARD_FW_STATUS1_REG		0x41
-#define FIRMWARE_READY			0xfedc
-
-#define CARD_RX_LEN_REG			0x42
-#define CARD_RX_UNIT_REG		0x43
-
+struct btmrvl_sdio_card_reg {
+	u8 cfg;
+	u8 host_int_mask;
+	u8 host_intstatus;
+	u8 card_status;
+	u8 sq_read_base_addr_a0;
+	u8 sq_read_base_addr_a1;
+	u8 card_revision;
+	u8 card_fw_status0;
+	u8 card_fw_status1;
+	u8 card_rx_len;
+	u8 card_rx_unit;
+	u8 io_port_0;
+	u8 io_port_1;
+	u8 io_port_2;
+};
 
 struct btmrvl_sdio_card {
 	struct sdio_func *func;
 	u32 ioport;
 	const char *helper;
 	const char *firmware;
+	const struct btmrvl_sdio_card_reg *reg;
+	u16 sd_blksz_fw_dl;
 	u8 rx_unit;
 	struct btmrvl_private *priv;
 };
@@ -92,6 +94,8 @@
 struct btmrvl_sdio_device {
 	const char *helper;
 	const char *firmware;
+	const struct btmrvl_sdio_card_reg *reg;
+	u16 sd_blksz_fw_dl;
 };
 
 
diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
index bd34406..4093935 100644
--- a/drivers/bluetooth/hci_ath.c
+++ b/drivers/bluetooth/hci_ath.c
@@ -201,8 +201,13 @@
 /* Recv data */
 static int ath_recv(struct hci_uart *hu, void *data, int count)
 {
-	if (hci_recv_stream_fragment(hu->hdev, data, count) < 0)
+	int ret;
+
+	ret = hci_recv_stream_fragment(hu->hdev, data, count);
+	if (ret < 0) {
 		BT_ERR("Frame Reassembly Failed");
+		return ret;
+	}
 
 	return count;
 }
diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c
index 7b8ad93..2fcd8b3 100644
--- a/drivers/bluetooth/hci_h4.c
+++ b/drivers/bluetooth/hci_h4.c
@@ -151,8 +151,13 @@
 /* Recv data */
 static int h4_recv(struct hci_uart *hu, void *data, int count)
 {
-	if (hci_recv_stream_fragment(hu->hdev, data, count) < 0)
+	int ret;
+
+	ret = hci_recv_stream_fragment(hu->hdev, data, count);
+	if (ret < 0) {
 		BT_ERR("Frame Reassembly Failed");
+		return ret;
+	}
 
 	return count;
 }
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 48ad2a7..320f718 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -359,6 +359,7 @@
  */
 static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count)
 {
+	int ret;
 	struct hci_uart *hu = (void *)tty->disc_data;
 
 	if (!hu || tty != hu->tty)
@@ -368,8 +369,9 @@
 		return;
 
 	spin_lock(&hu->rx_lock);
-	hu->proto->recv(hu, (void *) data, count);
-	hu->hdev->stat.byte_rx += count;
+	ret = hu->proto->recv(hu, (void *) data, count);
+	if (ret > 0)
+		hu->hdev->stat.byte_rx += count;
 	spin_unlock(&hu->rx_lock);
 
 	tty_unthrottle(tty);
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h
index 6d7105b..7cf4317 100644
--- a/drivers/net/wireless/ath/ath.h
+++ b/drivers/net/wireless/ath/ath.h
@@ -123,14 +123,7 @@
 };
 
 struct ath_common;
-
-struct ath_bus_ops {
-	enum ath_bus_type ath_bus_type;
-	void (*read_cachesize)(struct ath_common *common, int *csz);
-	bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data);
-	void (*bt_coex_prep)(struct ath_common *common);
-	void (*extn_synch_en)(struct ath_common *common);
-};
+struct ath_bus_ops;
 
 struct ath_common {
 	void *ah;
diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c
index 82324e9..ea99827 100644
--- a/drivers/net/wireless/ath/ath5k/ahb.c
+++ b/drivers/net/wireless/ath/ath5k/ahb.c
@@ -18,6 +18,7 @@
 
 #include <linux/nl80211.h>
 #include <linux/platform_device.h>
+#include <linux/etherdevice.h>
 #include <ar231x_platform.h>
 #include "ath5k.h"
 #include "debug.h"
@@ -62,10 +63,27 @@
 	return 0;
 }
 
+static int ath5k_ahb_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
+{
+	struct ath5k_softc *sc = ah->ah_sc;
+	struct platform_device *pdev = to_platform_device(sc->dev);
+	struct ar231x_board_config *bcfg = pdev->dev.platform_data;
+	u8 *cfg_mac;
+
+	if (to_platform_device(sc->dev)->id == 0)
+		cfg_mac = bcfg->config->wlan0_mac;
+	else
+		cfg_mac = bcfg->config->wlan1_mac;
+
+	memcpy(mac, cfg_mac, ETH_ALEN);
+	return 0;
+}
+
 static const struct ath_bus_ops ath_ahb_bus_ops = {
 	.ath_bus_type = ATH_AHB,
 	.read_cachesize = ath5k_ahb_read_cachesize,
 	.eeprom_read = ath5k_ahb_eeprom_read,
+	.eeprom_read_mac = ath5k_ahb_eeprom_read_mac,
 };
 
 /*Initialization*/
@@ -142,6 +160,16 @@
 		else
 			reg |= AR5K_AR5312_ENABLE_WLAN1;
 		__raw_writel(reg, (void __iomem *) AR5K_AR5312_ENABLE);
+
+		/*
+		 * On a dual-band AR5312, the multiband radio is only
+		 * used as pass-through. Disable 2 GHz support in the
+		 * driver for it
+		 */
+		if (to_platform_device(sc->dev)->id == 0 &&
+		    (bcfg->config->flags & (BD_WLAN0|BD_WLAN1)) ==
+		     (BD_WLAN1|BD_WLAN0))
+			__set_bit(ATH_STAT_2G_DISABLED, sc->status);
 	}
 
 	ret = ath5k_init_softc(sc, &ath_ahb_bus_ops);
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index 8a06dbd..bb50700 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -224,8 +224,7 @@
 
 /* SIFS */
 #define	AR5K_INIT_SIFS_TURBO			6
-/* XXX: 8 from initvals 10 from standard */
-#define	AR5K_INIT_SIFS_DEFAULT_BG		8
+#define	AR5K_INIT_SIFS_DEFAULT_BG		10
 #define	AR5K_INIT_SIFS_DEFAULT_A		16
 #define	AR5K_INIT_SIFS_HALF_RATE		32
 #define AR5K_INIT_SIFS_QUARTER_RATE		64
@@ -453,12 +452,10 @@
 	u16	ts_seqnum;
 	u16	ts_tstamp;
 	u8	ts_status;
-	u8	ts_rate[4];
-	u8	ts_retry[4];
 	u8	ts_final_idx;
+	u8	ts_final_retry;
 	s8	ts_rssi;
 	u8	ts_shortretry;
-	u8	ts_longretry;
 	u8	ts_virtcol;
 	u8	ts_antenna;
 };
@@ -875,6 +872,19 @@
 	AR5K_INT_QTRIG	=	0x40000000, /* Non common */
 	AR5K_INT_GLOBAL =	0x80000000,
 
+	AR5K_INT_TX_ALL = AR5K_INT_TXOK
+		| AR5K_INT_TXDESC
+		| AR5K_INT_TXERR
+		| AR5K_INT_TXEOL
+		| AR5K_INT_TXURN,
+
+	AR5K_INT_RX_ALL = AR5K_INT_RXOK
+		| AR5K_INT_RXDESC
+		| AR5K_INT_RXERR
+		| AR5K_INT_RXNOFRM
+		| AR5K_INT_RXEOL
+		| AR5K_INT_RXORN,
+
 	AR5K_INT_COMMON  = AR5K_INT_RXOK
 		| AR5K_INT_RXDESC
 		| AR5K_INT_RXERR
@@ -1058,6 +1068,7 @@
 	u8			ah_coverage_class;
 	bool			ah_ack_bitrate_high;
 	u8			ah_bwmode;
+	bool			ah_short_slot;
 
 	/* Antenna Control */
 	u32			ah_ant_ctl[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
@@ -1144,6 +1155,13 @@
 		struct ath5k_rx_status *);
 };
 
+struct ath_bus_ops {
+	enum ath_bus_type ath_bus_type;
+	void (*read_cachesize)(struct ath_common *common, int *csz);
+	bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data);
+	int (*eeprom_read_mac)(struct ath5k_hw *ah, u8 *mac);
+};
+
 /*
  * Prototypes
  */
@@ -1227,13 +1245,12 @@
 /* EEPROM access functions */
 int ath5k_eeprom_init(struct ath5k_hw *ah);
 void ath5k_eeprom_detach(struct ath5k_hw *ah);
-int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac);
 
 
 /* Protocol Control Unit Functions */
 /* Helpers */
 int ath5k_hw_get_frame_duration(struct ath5k_hw *ah,
-		int len, struct ieee80211_rate *rate);
+		int len, struct ieee80211_rate *rate, bool shortpre);
 unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah);
 unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah);
 extern int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype opmode);
diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c
index bc82405..1588401 100644
--- a/drivers/net/wireless/ath/ath5k/attach.c
+++ b/drivers/net/wireless/ath/ath5k/attach.c
@@ -313,12 +313,17 @@
 		goto err;
 	}
 
+	if (test_bit(ATH_STAT_2G_DISABLED, sc->status)) {
+		__clear_bit(AR5K_MODE_11B, ah->ah_capabilities.cap_mode);
+		__clear_bit(AR5K_MODE_11G, ah->ah_capabilities.cap_mode);
+	}
+
 	/* Crypto settings */
 	common->keymax = (sc->ah->ah_version == AR5K_AR5210 ?
 			  AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211);
 
 	if (srev >= AR5K_SREV_AR5212_V4 &&
-	    (ee->ee_version >= AR5K_EEPROM_VERSION_5_0 &&
+	    (ee->ee_version < AR5K_EEPROM_VERSION_5_0 ||
 	    !AR5K_EEPROM_AES_DIS(ee->ee_misc5)))
 		common->crypt_caps |= ATH_CRYPT_CAP_CIPHER_AESCCM;
 
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 349a596..203243b 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -1444,6 +1444,21 @@
 }
 
 static void
+ath5k_set_current_imask(struct ath5k_softc *sc)
+{
+	enum ath5k_int imask = sc->imask;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sc->irqlock, flags);
+	if (sc->rx_pending)
+		imask &= ~AR5K_INT_RX_ALL;
+	if (sc->tx_pending)
+		imask &= ~AR5K_INT_TX_ALL;
+	ath5k_hw_set_imr(sc->ah, imask);
+	spin_unlock_irqrestore(&sc->irqlock, flags);
+}
+
+static void
 ath5k_tasklet_rx(unsigned long data)
 {
 	struct ath5k_rx_status rs = {};
@@ -1506,6 +1521,8 @@
 	} while (ath5k_rxbuf_setup(sc, bf) == 0);
 unlock:
 	spin_unlock(&sc->rxbuflock);
+	sc->rx_pending = false;
+	ath5k_set_current_imask(sc);
 }
 
 
@@ -1573,28 +1590,28 @@
 			 struct ath5k_txq *txq, struct ath5k_tx_status *ts)
 {
 	struct ieee80211_tx_info *info;
+	u8 tries[3];
 	int i;
 
 	sc->stats.tx_all_count++;
 	sc->stats.tx_bytes_count += skb->len;
 	info = IEEE80211_SKB_CB(skb);
 
+	tries[0] = info->status.rates[0].count;
+	tries[1] = info->status.rates[1].count;
+	tries[2] = info->status.rates[2].count;
+
 	ieee80211_tx_info_clear_status(info);
-	for (i = 0; i < 4; i++) {
+
+	for (i = 0; i < ts->ts_final_idx; i++) {
 		struct ieee80211_tx_rate *r =
 			&info->status.rates[i];
 
-		if (ts->ts_rate[i]) {
-			r->idx = ath5k_hw_to_driver_rix(sc, ts->ts_rate[i]);
-			r->count = ts->ts_retry[i];
-		} else {
-			r->idx = -1;
-			r->count = 0;
-		}
+		r->count = tries[i];
 	}
 
-	/* count the successful attempt as well */
-	info->status.rates[ts->ts_final_idx].count++;
+	info->status.rates[ts->ts_final_idx].count = ts->ts_final_retry;
+	info->status.rates[ts->ts_final_idx + 1].idx = -1;
 
 	if (unlikely(ts->ts_status)) {
 		sc->stats.ack_fail++;
@@ -1609,6 +1626,9 @@
 	} else {
 		info->flags |= IEEE80211_TX_STAT_ACK;
 		info->status.ack_signal = ts->ts_rssi;
+
+		/* count the successful attempt as well */
+		info->status.rates[ts->ts_final_idx].count++;
 	}
 
 	/*
@@ -1690,6 +1710,9 @@
 	for (i=0; i < AR5K_NUM_TX_QUEUES; i++)
 		if (sc->txqs[i].setup && (sc->ah->ah_txq_isr & BIT(i)))
 			ath5k_tx_processq(sc, &sc->txqs[i]);
+
+	sc->tx_pending = false;
+	ath5k_set_current_imask(sc);
 }
 
 
@@ -2119,6 +2142,20 @@
 	 * AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); */
 }
 
+static void
+ath5k_schedule_rx(struct ath5k_softc *sc)
+{
+	sc->rx_pending = true;
+	tasklet_schedule(&sc->rxtq);
+}
+
+static void
+ath5k_schedule_tx(struct ath5k_softc *sc)
+{
+	sc->tx_pending = true;
+	tasklet_schedule(&sc->txtq);
+}
+
 irqreturn_t
 ath5k_intr(int irq, void *dev_id)
 {
@@ -2161,7 +2198,7 @@
 				ieee80211_queue_work(sc->hw, &sc->reset_work);
 			}
 			else
-				tasklet_schedule(&sc->rxtq);
+				ath5k_schedule_rx(sc);
 		} else {
 			if (status & AR5K_INT_SWBA) {
 				tasklet_hi_schedule(&sc->beacontq);
@@ -2179,10 +2216,10 @@
 				ath5k_hw_update_tx_triglevel(ah, true);
 			}
 			if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR))
-				tasklet_schedule(&sc->rxtq);
+				ath5k_schedule_rx(sc);
 			if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC
 					| AR5K_INT_TXERR | AR5K_INT_TXEOL))
-				tasklet_schedule(&sc->txtq);
+				ath5k_schedule_tx(sc);
 			if (status & AR5K_INT_BMISS) {
 				/* TODO */
 			}
@@ -2201,6 +2238,9 @@
 
 	} while (ath5k_hw_is_intr_pending(ah) && --counter > 0);
 
+	if (sc->rx_pending || sc->tx_pending)
+		ath5k_set_current_imask(sc);
+
 	if (unlikely(!counter))
 		ATH5K_WARN(sc, "too many interrupts, giving up for now\n");
 
@@ -2572,6 +2612,8 @@
 
 static void stop_tasklets(struct ath5k_softc *sc)
 {
+	sc->rx_pending = false;
+	sc->tx_pending = false;
 	tasklet_kill(&sc->rxtq);
 	tasklet_kill(&sc->txtq);
 	tasklet_kill(&sc->calib);
@@ -2838,7 +2880,7 @@
 	INIT_WORK(&sc->reset_work, ath5k_reset_work);
 	INIT_DELAYED_WORK(&sc->tx_complete_work, ath5k_tx_complete_poll_work);
 
-	ret = ath5k_eeprom_read_mac(ah, mac);
+	ret = ath5k_hw_common(ah)->bus_ops->eeprom_read_mac(ah, mac);
 	if (ret) {
 		ATH5K_ERR(sc, "unable to read address from EEPROM\n");
 		goto err_queues;
@@ -2898,7 +2940,6 @@
 	 * XXX: ??? detach ath5k_hw ???
 	 * Other than that, it's straightforward...
 	 */
-	ath5k_debug_finish_device(sc);
 	ieee80211_unregister_hw(hw);
 	ath5k_desc_free(sc);
 	ath5k_txq_release(sc);
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h
index 978f1f4..b294f33 100644
--- a/drivers/net/wireless/ath/ath5k/base.h
+++ b/drivers/net/wireless/ath/ath5k/base.h
@@ -193,12 +193,13 @@
 	dma_addr_t		desc_daddr;	/* DMA (physical) address */
 	size_t			desc_len;	/* size of TX/RX descriptors */
 
-	DECLARE_BITMAP(status, 5);
+	DECLARE_BITMAP(status, 6);
 #define ATH_STAT_INVALID	0		/* disable hardware accesses */
 #define ATH_STAT_MRRETRY	1		/* multi-rate retry support */
 #define ATH_STAT_PROMISC	2
 #define ATH_STAT_LEDSOFT	3		/* enable LED gpio status */
 #define ATH_STAT_STARTED	4		/* opened & irqs enabled */
+#define ATH_STAT_2G_DISABLED	5		/* multiband radio without 2G */
 
 	unsigned int		filter_flags;	/* HW flags, AR5K_RX_FILTER_* */
 	struct ieee80211_channel *curchan;	/* current h/w channel */
@@ -207,6 +208,10 @@
 
 	enum ath5k_int		imask;		/* interrupt mask copy */
 
+	spinlock_t		irqlock;
+	bool			rx_pending;	/* rx tasklet pending */
+	bool			tx_pending;	/* tx tasklet pending */
+
 	u8			lladdr[ETH_ALEN];
 	u8			bssidmask[ETH_ALEN];
 
diff --git a/drivers/net/wireless/ath/ath5k/caps.c b/drivers/net/wireless/ath/ath5k/caps.c
index f77e8a7..7dd88e1 100644
--- a/drivers/net/wireless/ath/ath5k/caps.c
+++ b/drivers/net/wireless/ath/ath5k/caps.c
@@ -94,6 +94,9 @@
 		}
 	}
 
+	if ((ah->ah_radio_5ghz_revision & 0xf0) == AR5K_SREV_RAD_2112)
+		__clear_bit(AR5K_MODE_11A, caps->cap_mode);
+
 	/* Set number of supported TX queues */
 	if (ah->ah_version == AR5K_AR5210)
 		caps->cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES_NOQCU;
diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c
index 0230f30..0bf7313 100644
--- a/drivers/net/wireless/ath/ath5k/debug.c
+++ b/drivers/net/wireless/ath/ath5k/debug.c
@@ -888,65 +888,38 @@
 void
 ath5k_debug_init_device(struct ath5k_softc *sc)
 {
+	struct dentry *phydir;
+
 	sc->debug.level = ath5k_debug;
 
-	sc->debug.debugfs_phydir = debugfs_create_dir("ath5k",
-				sc->hw->wiphy->debugfsdir);
+	phydir = debugfs_create_dir("ath5k", sc->hw->wiphy->debugfsdir);
+	if (!phydir)
+	    return;
 
-	sc->debug.debugfs_debug = debugfs_create_file("debug",
-				S_IWUSR | S_IRUSR,
-				sc->debug.debugfs_phydir, sc, &fops_debug);
+	debugfs_create_file("debug", S_IWUSR | S_IRUSR, phydir, sc,
+			    &fops_debug);
 
-	sc->debug.debugfs_registers = debugfs_create_file("registers", S_IRUSR,
-				sc->debug.debugfs_phydir, sc, &fops_registers);
+	debugfs_create_file("registers", S_IRUSR, phydir, sc, &fops_registers);
 
-	sc->debug.debugfs_beacon = debugfs_create_file("beacon",
-				S_IWUSR | S_IRUSR,
-				sc->debug.debugfs_phydir, sc, &fops_beacon);
+	debugfs_create_file("beacon", S_IWUSR | S_IRUSR, phydir, sc,
+			    &fops_beacon);
 
-	sc->debug.debugfs_reset = debugfs_create_file("reset", S_IWUSR,
-				sc->debug.debugfs_phydir, sc, &fops_reset);
+	debugfs_create_file("reset", S_IWUSR, phydir, sc, &fops_reset);
 
-	sc->debug.debugfs_antenna = debugfs_create_file("antenna",
-				S_IWUSR | S_IRUSR,
-				sc->debug.debugfs_phydir, sc, &fops_antenna);
+	debugfs_create_file("antenna", S_IWUSR | S_IRUSR, phydir, sc,
+			    &fops_antenna);
 
-	sc->debug.debugfs_misc = debugfs_create_file("misc",
-				S_IRUSR,
-				sc->debug.debugfs_phydir, sc, &fops_misc);
+	debugfs_create_file("misc", S_IRUSR, phydir, sc, &fops_misc);
 
-	sc->debug.debugfs_frameerrors = debugfs_create_file("frameerrors",
-				S_IWUSR | S_IRUSR,
-				sc->debug.debugfs_phydir, sc,
-				&fops_frameerrors);
+	debugfs_create_file("frameerrors", S_IWUSR | S_IRUSR, phydir, sc,
+			    &fops_frameerrors);
 
-	sc->debug.debugfs_ani = debugfs_create_file("ani",
-				S_IWUSR | S_IRUSR,
-				sc->debug.debugfs_phydir, sc,
-				&fops_ani);
+	debugfs_create_file("ani", S_IWUSR | S_IRUSR, phydir, sc, &fops_ani);
 
-	sc->debug.debugfs_queue = debugfs_create_file("queue",
-				S_IWUSR | S_IRUSR,
-				sc->debug.debugfs_phydir, sc,
-				&fops_queue);
+	debugfs_create_file("queue", S_IWUSR | S_IRUSR, phydir, sc,
+			    &fops_queue);
 }
 
-void
-ath5k_debug_finish_device(struct ath5k_softc *sc)
-{
-	debugfs_remove(sc->debug.debugfs_debug);
-	debugfs_remove(sc->debug.debugfs_registers);
-	debugfs_remove(sc->debug.debugfs_beacon);
-	debugfs_remove(sc->debug.debugfs_reset);
-	debugfs_remove(sc->debug.debugfs_antenna);
-	debugfs_remove(sc->debug.debugfs_misc);
-	debugfs_remove(sc->debug.debugfs_frameerrors);
-	debugfs_remove(sc->debug.debugfs_ani);
-	debugfs_remove(sc->debug.debugfs_queue);
-	debugfs_remove(sc->debug.debugfs_phydir);
-}
-
-
 /* functions used in other places */
 
 void
diff --git a/drivers/net/wireless/ath/ath5k/debug.h b/drivers/net/wireless/ath/ath5k/debug.h
index b0355ae..193dd2d 100644
--- a/drivers/net/wireless/ath/ath5k/debug.h
+++ b/drivers/net/wireless/ath/ath5k/debug.h
@@ -68,17 +68,6 @@
 
 struct ath5k_dbg_info {
 	unsigned int		level;		/* debug level */
-	/* debugfs entries */
-	struct dentry		*debugfs_phydir;
-	struct dentry		*debugfs_debug;
-	struct dentry		*debugfs_registers;
-	struct dentry		*debugfs_beacon;
-	struct dentry		*debugfs_reset;
-	struct dentry		*debugfs_antenna;
-	struct dentry		*debugfs_misc;
-	struct dentry		*debugfs_frameerrors;
-	struct dentry		*debugfs_ani;
-	struct dentry		*debugfs_queue;
 };
 
 /**
@@ -141,9 +130,6 @@
 ath5k_debug_init_device(struct ath5k_softc *sc);
 
 void
-ath5k_debug_finish_device(struct ath5k_softc *sc);
-
-void
 ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah);
 
 void
@@ -167,9 +153,6 @@
 ath5k_debug_init_device(struct ath5k_softc *sc) {}
 
 static inline void
-ath5k_debug_finish_device(struct ath5k_softc *sc) {}
-
-static inline void
 ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) {}
 
 static inline void
diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c
index a8fcc94..62172d5 100644
--- a/drivers/net/wireless/ath/ath5k/desc.c
+++ b/drivers/net/wireless/ath/ath5k/desc.c
@@ -185,6 +185,12 @@
 	struct ath5k_hw_4w_tx_ctl *tx_ctl;
 	unsigned int frame_len;
 
+	/*
+	 * Use local variables for these to reduce load/store access on
+	 * uncached memory
+	 */
+	u32 txctl0 = 0, txctl1 = 0, txctl2 = 0, txctl3 = 0;
+
 	tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
 
 	/*
@@ -208,8 +214,9 @@
 	if (tx_power > AR5K_TUNE_MAX_TXPOWER)
 		tx_power = AR5K_TUNE_MAX_TXPOWER;
 
-	/* Clear descriptor */
-	memset(&desc->ud.ds_tx5212, 0, sizeof(struct ath5k_hw_5212_tx_desc));
+	/* Clear descriptor status area */
+	memset(&desc->ud.ds_tx5212.tx_stat, 0,
+	       sizeof(desc->ud.ds_tx5212.tx_stat));
 
 	/* Setup control descriptor */
 
@@ -221,7 +228,7 @@
 	if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN)
 		return -EINVAL;
 
-	tx_ctl->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN;
+	txctl0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN;
 
 	/* Verify and set buffer length */
 
@@ -232,21 +239,17 @@
 	if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN)
 		return -EINVAL;
 
-	tx_ctl->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN;
+	txctl1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN;
 
-	tx_ctl->tx_control_0 |=
-		AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) |
-		AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT);
-	tx_ctl->tx_control_1 |= AR5K_REG_SM(type,
-					AR5K_4W_TX_DESC_CTL1_FRAME_TYPE);
-	tx_ctl->tx_control_2 = AR5K_REG_SM(tx_tries0,
-					AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0);
-	tx_ctl->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
+	txctl0 |= AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) |
+		  AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT);
+	txctl1 |= AR5K_REG_SM(type, AR5K_4W_TX_DESC_CTL1_FRAME_TYPE);
+	txctl2 = AR5K_REG_SM(tx_tries0, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0);
+	txctl3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
 
 #define _TX_FLAGS(_c, _flag)					\
 	if (flags & AR5K_TXDESC_##_flag) {			\
-		tx_ctl->tx_control_##_c |=			\
-			AR5K_4W_TX_DESC_CTL##_c##_##_flag;	\
+		txctl##_c |= AR5K_4W_TX_DESC_CTL##_c##_##_flag;	\
 	}
 
 	_TX_FLAGS(0, CLRDMASK);
@@ -262,8 +265,8 @@
 	 * WEP crap
 	 */
 	if (key_index != AR5K_TXKEYIX_INVALID) {
-		tx_ctl->tx_control_0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
-		tx_ctl->tx_control_1 |= AR5K_REG_SM(key_index,
+		txctl0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
+		txctl1 |= AR5K_REG_SM(key_index,
 				AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_IDX);
 	}
 
@@ -274,12 +277,16 @@
 		if ((flags & AR5K_TXDESC_RTSENA) &&
 				(flags & AR5K_TXDESC_CTSENA))
 			return -EINVAL;
-		tx_ctl->tx_control_2 |= rtscts_duration &
-				AR5K_4W_TX_DESC_CTL2_RTS_DURATION;
-		tx_ctl->tx_control_3 |= AR5K_REG_SM(rtscts_rate,
+		txctl2 |= rtscts_duration & AR5K_4W_TX_DESC_CTL2_RTS_DURATION;
+		txctl3 |= AR5K_REG_SM(rtscts_rate,
 				AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE);
 	}
 
+	tx_ctl->tx_control_0 = txctl0;
+	tx_ctl->tx_control_1 = txctl1;
+	tx_ctl->tx_control_2 = txctl2;
+	tx_ctl->tx_control_3 = txctl3;
+
 	return 0;
 }
 
@@ -364,7 +371,7 @@
 		AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
 	ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
 		AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
-	ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0,
+	ts->ts_final_retry = AR5K_REG_MS(tx_status->tx_status_0,
 		AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
 	/*TODO: ts->ts_virtcol + test*/
 	ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
@@ -373,9 +380,6 @@
 		AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
 	ts->ts_antenna = 1;
 	ts->ts_status = 0;
-	ts->ts_rate[0] = AR5K_REG_MS(tx_ctl->tx_control_0,
-		AR5K_2W_TX_DESC_CTL0_XMIT_RATE);
-	ts->ts_retry[0] = ts->ts_longretry;
 	ts->ts_final_idx = 0;
 
 	if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) {
@@ -401,81 +405,48 @@
 {
 	struct ath5k_hw_4w_tx_ctl *tx_ctl;
 	struct ath5k_hw_tx_status *tx_status;
+	u32 txstat0, txstat1;
 
 	tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
 	tx_status = &desc->ud.ds_tx5212.tx_stat;
 
+	txstat1 = ACCESS_ONCE(tx_status->tx_status_1);
+
 	/* No frame has been send or error */
-	if (unlikely(!(tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE)))
+	if (unlikely(!(txstat1 & AR5K_DESC_TX_STATUS1_DONE)))
 		return -EINPROGRESS;
 
+	txstat0 = ACCESS_ONCE(tx_status->tx_status_0);
+
 	/*
 	 * Get descriptor status
 	 */
-	ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0,
+	ts->ts_tstamp = AR5K_REG_MS(txstat0,
 		AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
-	ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
+	ts->ts_shortretry = AR5K_REG_MS(txstat0,
 		AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
-	ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0,
+	ts->ts_final_retry = AR5K_REG_MS(txstat0,
 		AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
-	ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
+	ts->ts_seqnum = AR5K_REG_MS(txstat1,
 		AR5K_DESC_TX_STATUS1_SEQ_NUM);
-	ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1,
+	ts->ts_rssi = AR5K_REG_MS(txstat1,
 		AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
-	ts->ts_antenna = (tx_status->tx_status_1 &
+	ts->ts_antenna = (txstat1 &
 		AR5K_DESC_TX_STATUS1_XMIT_ANTENNA_5212) ? 2 : 1;
 	ts->ts_status = 0;
 
-	ts->ts_final_idx = AR5K_REG_MS(tx_status->tx_status_1,
+	ts->ts_final_idx = AR5K_REG_MS(txstat1,
 			AR5K_DESC_TX_STATUS1_FINAL_TS_IX_5212);
 
-	/* The longretry counter has the number of un-acked retries
-	 * for the final rate. To get the total number of retries
-	 * we have to add the retry counters for the other rates
-	 * as well
-	 */
-	ts->ts_retry[ts->ts_final_idx] = ts->ts_longretry;
-	switch (ts->ts_final_idx) {
-	case 3:
-		ts->ts_rate[3] = AR5K_REG_MS(tx_ctl->tx_control_3,
-			AR5K_4W_TX_DESC_CTL3_XMIT_RATE3);
-
-		ts->ts_retry[2] = AR5K_REG_MS(tx_ctl->tx_control_2,
-			AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2);
-		ts->ts_longretry += ts->ts_retry[2];
-		/* fall through */
-	case 2:
-		ts->ts_rate[2] = AR5K_REG_MS(tx_ctl->tx_control_3,
-			AR5K_4W_TX_DESC_CTL3_XMIT_RATE2);
-
-		ts->ts_retry[1] = AR5K_REG_MS(tx_ctl->tx_control_2,
-			AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1);
-		ts->ts_longretry += ts->ts_retry[1];
-		/* fall through */
-	case 1:
-		ts->ts_rate[1] = AR5K_REG_MS(tx_ctl->tx_control_3,
-			AR5K_4W_TX_DESC_CTL3_XMIT_RATE1);
-
-		ts->ts_retry[0] = AR5K_REG_MS(tx_ctl->tx_control_2,
-			AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1);
-		ts->ts_longretry += ts->ts_retry[0];
-		/* fall through */
-	case 0:
-		ts->ts_rate[0] = tx_ctl->tx_control_3 &
-			AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
-		break;
-	}
-
 	/* TX error */
-	if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) {
-		if (tx_status->tx_status_0 &
-				AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
+	if (!(txstat0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) {
+		if (txstat0 & AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
 			ts->ts_status |= AR5K_TXERR_XRETRY;
 
-		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
+		if (txstat0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
 			ts->ts_status |= AR5K_TXERR_FIFO;
 
-		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED)
+		if (txstat0 & AR5K_DESC_TX_STATUS0_FILTERED)
 			ts->ts_status |= AR5K_TXERR_FILT;
 	}
 
@@ -609,37 +580,37 @@
 					struct ath5k_rx_status *rs)
 {
 	struct ath5k_hw_rx_status *rx_status;
+	u32 rxstat0, rxstat1;
 
 	rx_status = &desc->ud.ds_rx.rx_stat;
+	rxstat1 = ACCESS_ONCE(rx_status->rx_status_1);
 
 	/* No frame received / not ready */
-	if (unlikely(!(rx_status->rx_status_1 &
-				AR5K_5212_RX_DESC_STATUS1_DONE)))
+	if (unlikely(!(rxstat1 & AR5K_5212_RX_DESC_STATUS1_DONE)))
 		return -EINPROGRESS;
 
 	memset(rs, 0, sizeof(struct ath5k_rx_status));
+	rxstat0 = ACCESS_ONCE(rx_status->rx_status_0);
 
 	/*
 	 * Frame receive status
 	 */
-	rs->rs_datalen = rx_status->rx_status_0 &
-		AR5K_5212_RX_DESC_STATUS0_DATA_LEN;
-	rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0,
+	rs->rs_datalen = rxstat0 & AR5K_5212_RX_DESC_STATUS0_DATA_LEN;
+	rs->rs_rssi = AR5K_REG_MS(rxstat0,
 		AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL);
-	rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0,
+	rs->rs_rate = AR5K_REG_MS(rxstat0,
 		AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE);
-	rs->rs_antenna = AR5K_REG_MS(rx_status->rx_status_0,
+	rs->rs_antenna = AR5K_REG_MS(rxstat0,
 		AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA);
-	rs->rs_more = !!(rx_status->rx_status_0 &
-		AR5K_5212_RX_DESC_STATUS0_MORE);
-	rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
+	rs->rs_more = !!(rxstat0 & AR5K_5212_RX_DESC_STATUS0_MORE);
+	rs->rs_tstamp = AR5K_REG_MS(rxstat1,
 		AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
 
 	/*
 	 * Key table status
 	 */
-	if (rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID)
-		rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1,
+	if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID)
+		rs->rs_keyix = AR5K_REG_MS(rxstat1,
 					   AR5K_5212_RX_DESC_STATUS1_KEY_INDEX);
 	else
 		rs->rs_keyix = AR5K_RXKEYIX_INVALID;
@@ -647,27 +618,22 @@
 	/*
 	 * Receive/descriptor errors
 	 */
-	if (!(rx_status->rx_status_1 &
-	    AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) {
-		if (rx_status->rx_status_1 &
-				AR5K_5212_RX_DESC_STATUS1_CRC_ERROR)
+	if (!(rxstat1 & AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) {
+		if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_CRC_ERROR)
 			rs->rs_status |= AR5K_RXERR_CRC;
 
-		if (rx_status->rx_status_1 &
-				AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) {
+		if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) {
 			rs->rs_status |= AR5K_RXERR_PHY;
-			rs->rs_phyerr = AR5K_REG_MS(rx_status->rx_status_1,
+			rs->rs_phyerr = AR5K_REG_MS(rxstat1,
 				AR5K_5212_RX_DESC_STATUS1_PHY_ERROR_CODE);
 			if (!ah->ah_capabilities.cap_has_phyerr_counters)
 				ath5k_ani_phy_error_report(ah, rs->rs_phyerr);
 		}
 
-		if (rx_status->rx_status_1 &
-				AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
+		if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
 			rs->rs_status |= AR5K_RXERR_DECRYPT;
 
-		if (rx_status->rx_status_1 &
-				AR5K_5212_RX_DESC_STATUS1_MIC_ERROR)
+		if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_MIC_ERROR)
 			rs->rs_status |= AR5K_RXERR_MIC;
 	}
 	return 0;
diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c
index efb672c..1fef84f 100644
--- a/drivers/net/wireless/ath/ath5k/eeprom.c
+++ b/drivers/net/wireless/ath/ath5k/eeprom.c
@@ -660,6 +660,53 @@
 		vp[i] = (ip[i] * max + (100 - ip[i]) * min) / 100;
 }
 
+static int
+ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_chan_pcal_info *chinfo;
+	u8 pier, pdg;
+
+	switch (mode) {
+	case AR5K_EEPROM_MODE_11A:
+		if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
+			return 0;
+		chinfo = ee->ee_pwr_cal_a;
+		break;
+	case AR5K_EEPROM_MODE_11B:
+		if (!AR5K_EEPROM_HDR_11B(ee->ee_header))
+			return 0;
+		chinfo = ee->ee_pwr_cal_b;
+		break;
+	case AR5K_EEPROM_MODE_11G:
+		if (!AR5K_EEPROM_HDR_11G(ee->ee_header))
+			return 0;
+		chinfo = ee->ee_pwr_cal_g;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {
+		if (!chinfo[pier].pd_curves)
+			continue;
+
+		for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
+			struct ath5k_pdgain_info *pd =
+					&chinfo[pier].pd_curves[pdg];
+
+			if (pd != NULL) {
+				kfree(pd->pd_step);
+				kfree(pd->pd_pwr);
+			}
+		}
+
+		kfree(chinfo[pier].pd_curves);
+	}
+
+	return 0;
+}
+
 /* Convert RF5111 specific data to generic raw data
  * used by interpolation code */
 static int
@@ -684,7 +731,7 @@
 				GFP_KERNEL);
 
 		if (!chinfo[pier].pd_curves)
-			return -ENOMEM;
+			goto err_out;
 
 		/* Only one curve for RF5111
 		 * find out which one and place
@@ -708,12 +755,12 @@
 		pd->pd_step = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111,
 					sizeof(u8), GFP_KERNEL);
 		if (!pd->pd_step)
-			return -ENOMEM;
+			goto err_out;
 
 		pd->pd_pwr = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111,
 					sizeof(s16), GFP_KERNEL);
 		if (!pd->pd_pwr)
-			return -ENOMEM;
+			goto err_out;
 
 		/* Fill raw dataset
 		 * (convert power to 0.25dB units
@@ -734,6 +781,10 @@
 	}
 
 	return 0;
+
+err_out:
+	ath5k_eeprom_free_pcal_info(ah, mode);
+	return -ENOMEM;
 }
 
 /* Parse EEPROM data */
@@ -867,7 +918,7 @@
 					GFP_KERNEL);
 
 		if (!chinfo[pier].pd_curves)
-			return -ENOMEM;
+			goto err_out;
 
 		/* Fill pd_curves */
 		for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
@@ -886,14 +937,13 @@
 						sizeof(u8), GFP_KERNEL);
 
 				if (!pd->pd_step)
-					return -ENOMEM;
+					goto err_out;
 
 				pd->pd_pwr = kcalloc(pd->pd_points,
 						sizeof(s16), GFP_KERNEL);
 
 				if (!pd->pd_pwr)
-					return -ENOMEM;
-
+					goto err_out;
 
 				/* Fill raw dataset
 				 * (all power levels are in 0.25dB units) */
@@ -925,13 +975,13 @@
 						sizeof(u8), GFP_KERNEL);
 
 				if (!pd->pd_step)
-					return -ENOMEM;
+					goto err_out;
 
 				pd->pd_pwr = kcalloc(pd->pd_points,
 						sizeof(s16), GFP_KERNEL);
 
 				if (!pd->pd_pwr)
-					return -ENOMEM;
+					goto err_out;
 
 				/* Fill raw dataset
 				 * (all power levels are in 0.25dB units) */
@@ -954,6 +1004,10 @@
 	}
 
 	return 0;
+
+err_out:
+	ath5k_eeprom_free_pcal_info(ah, mode);
+	return -ENOMEM;
 }
 
 /* Parse EEPROM data */
@@ -1156,7 +1210,7 @@
 					GFP_KERNEL);
 
 		if (!chinfo[pier].pd_curves)
-			return -ENOMEM;
+			goto err_out;
 
 		/* Fill pd_curves */
 		for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
@@ -1177,13 +1231,13 @@
 					sizeof(u8), GFP_KERNEL);
 
 			if (!pd->pd_step)
-				return -ENOMEM;
+				goto err_out;
 
 			pd->pd_pwr = kcalloc(pd->pd_points,
 					sizeof(s16), GFP_KERNEL);
 
 			if (!pd->pd_pwr)
-				return -ENOMEM;
+				goto err_out;
 
 			/* Fill raw dataset
 			 * convert all pwr levels to
@@ -1213,6 +1267,10 @@
 	}
 
 	return 0;
+
+err_out:
+	ath5k_eeprom_free_pcal_info(ah, mode);
+	return -ENOMEM;
 }
 
 /* Parse EEPROM data */
@@ -1534,53 +1592,6 @@
 	return 0;
 }
 
-static int
-ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode)
-{
-	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-	struct ath5k_chan_pcal_info *chinfo;
-	u8 pier, pdg;
-
-	switch (mode) {
-	case AR5K_EEPROM_MODE_11A:
-		if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
-			return 0;
-		chinfo = ee->ee_pwr_cal_a;
-		break;
-	case AR5K_EEPROM_MODE_11B:
-		if (!AR5K_EEPROM_HDR_11B(ee->ee_header))
-			return 0;
-		chinfo = ee->ee_pwr_cal_b;
-		break;
-	case AR5K_EEPROM_MODE_11G:
-		if (!AR5K_EEPROM_HDR_11G(ee->ee_header))
-			return 0;
-		chinfo = ee->ee_pwr_cal_g;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {
-		if (!chinfo[pier].pd_curves)
-			continue;
-
-		for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
-			struct ath5k_pdgain_info *pd =
-					&chinfo[pier].pd_curves[pdg];
-
-			if (pd != NULL) {
-				kfree(pd->pd_step);
-				kfree(pd->pd_pwr);
-			}
-		}
-
-		kfree(chinfo[pier].pd_curves);
-	}
-
-	return 0;
-}
-
 /* Read conformance test limits used for regulatory control */
 static int
 ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah)
@@ -1721,35 +1732,6 @@
 	return ret;
 }
 
-/*
- * Read the MAC address from eeprom
- */
-int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
-{
-	u8 mac_d[ETH_ALEN] = {};
-	u32 total, offset;
-	u16 data;
-	int octet;
-
-	AR5K_EEPROM_READ(0x20, data);
-
-	for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) {
-		AR5K_EEPROM_READ(offset, data);
-
-		total += data;
-		mac_d[octet + 1] = data & 0xff;
-		mac_d[octet] = data >> 8;
-		octet += 2;
-	}
-
-	if (!total || total == 3 * 0xffff)
-		return -EINVAL;
-
-	memcpy(mac, mac_d, ETH_ALEN);
-
-	return 0;
-}
-
 
 /***********************\
 * Init/Detach functions *
diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
index 9be29b7..807bd64 100644
--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c
+++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
@@ -282,6 +282,15 @@
 	if (changes & BSS_CHANGED_BEACON_INT)
 		sc->bintval = bss_conf->beacon_int;
 
+	if (changes & BSS_CHANGED_ERP_SLOT) {
+		int slot_time;
+
+		ah->ah_short_slot = bss_conf->use_short_slot;
+		slot_time = ath5k_hw_get_default_slottime(ah) +
+			    3 * ah->ah_coverage_class;
+		ath5k_hw_set_ifs_intervals(ah, slot_time);
+	}
+
 	if (changes & BSS_CHANGED_ASSOC) {
 		avf->assoc = bss_conf->assoc;
 		if (bss_conf->assoc)
diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c
index 3c44689..296c316 100644
--- a/drivers/net/wireless/ath/ath5k/pci.c
+++ b/drivers/net/wireless/ath/ath5k/pci.c
@@ -17,6 +17,7 @@
 #include <linux/nl80211.h>
 #include <linux/pci.h>
 #include <linux/pci-aspm.h>
+#include <linux/etherdevice.h>
 #include "../ath.h"
 #include "ath5k.h"
 #include "debug.h"
@@ -108,11 +109,42 @@
 	return 0;
 }
 
+/*
+ * Read the MAC address from eeprom or platform_data
+ */
+static int ath5k_pci_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
+{
+	u8 mac_d[ETH_ALEN] = {};
+	u32 total, offset;
+	u16 data;
+	int octet;
+
+	AR5K_EEPROM_READ(0x20, data);
+
+	for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) {
+		AR5K_EEPROM_READ(offset, data);
+
+		total += data;
+		mac_d[octet + 1] = data & 0xff;
+		mac_d[octet] = data >> 8;
+		octet += 2;
+	}
+
+	if (!total || total == 3 * 0xffff)
+		return -EINVAL;
+
+	memcpy(mac, mac_d, ETH_ALEN);
+
+	return 0;
+}
+
+
 /* Common ath_bus_opts structure */
 static const struct ath_bus_ops ath_pci_bus_ops = {
 	.ath_bus_type = ATH_PCI,
 	.read_cachesize = ath5k_pci_read_cachesize,
 	.eeprom_read = ath5k_pci_eeprom_read,
+	.eeprom_read_mac = ath5k_pci_eeprom_read_mac,
 };
 
 /********************\
diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c
index d9b3f82..712a9ac 100644
--- a/drivers/net/wireless/ath/ath5k/pcu.c
+++ b/drivers/net/wireless/ath/ath5k/pcu.c
@@ -75,7 +75,7 @@
  * bwmodes.
  */
 int ath5k_hw_get_frame_duration(struct ath5k_hw *ah,
-		int len, struct ieee80211_rate *rate)
+		int len, struct ieee80211_rate *rate, bool shortpre)
 {
 	struct ath5k_softc *sc = ah->ah_sc;
 	int sifs, preamble, plcp_bits, sym_time;
@@ -84,9 +84,15 @@
 
 	/* Fallback */
 	if (!ah->ah_bwmode) {
-		dur = ieee80211_generic_frame_duration(sc->hw,
-						NULL, len, rate);
-		return le16_to_cpu(dur);
+		__le16 raw_dur = ieee80211_generic_frame_duration(sc->hw,
+					NULL, len, rate);
+
+		/* subtract difference between long and short preamble */
+		dur = le16_to_cpu(raw_dur);
+		if (shortpre)
+			dur -= 96;
+
+		return dur;
 	}
 
 	bitrate = rate->bitrate;
@@ -145,9 +151,9 @@
 		slot_time = AR5K_INIT_SLOT_TIME_QUARTER_RATE;
 		break;
 	case AR5K_BWMODE_DEFAULT:
-		slot_time = AR5K_INIT_SLOT_TIME_DEFAULT;
 	default:
-		if (channel->hw_value & CHANNEL_CCK)
+		slot_time = AR5K_INIT_SLOT_TIME_DEFAULT;
+		if ((channel->hw_value & CHANNEL_CCK) && !ah->ah_short_slot)
 			slot_time = AR5K_INIT_SLOT_TIME_B;
 		break;
 	}
@@ -263,27 +269,14 @@
 		 * actual rate for this rate. See mac80211 tx.c
 		 * ieee80211_duration() for a brief description of
 		 * what rate we should choose to TX ACKs. */
-		tx_time = ath5k_hw_get_frame_duration(ah, 10, rate);
+		tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, false);
 
 		ath5k_hw_reg_write(ah, tx_time, reg);
 
 		if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE))
 			continue;
 
-		/*
-		 * We're not distinguishing short preamble here,
-		 * This is true, all we'll get is a longer value here
-		 * which is not necessarilly bad. We could use
-		 * export ieee80211_frame_duration() but that needs to be
-		 * fixed first to be properly used by mac802111 drivers:
-		 *
-		 *  - remove erp stuff and let the routine figure ofdm
-		 *    erp rates
-		 *  - remove passing argument ieee80211_local as
-		 *    drivers don't have access to it
-		 *  - move drivers using ieee80211_generic_frame_duration()
-		 *    to this
-		 */
+		tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, true);
 		ath5k_hw_reg_write(ah, tx_time,
 			reg + (AR5K_SET_SHORT_PREAMBLE << 2));
 	}
diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c
index 3343fb9..b18c502 100644
--- a/drivers/net/wireless/ath/ath5k/qcu.c
+++ b/drivers/net/wireless/ath/ath5k/qcu.c
@@ -519,7 +519,7 @@
 		return -EINVAL;
 
 	sifs = ath5k_hw_get_default_sifs(ah);
-	sifs_clock = ath5k_hw_htoclock(ah, sifs);
+	sifs_clock = ath5k_hw_htoclock(ah, sifs - 2);
 
 	/* EIFS
 	 * Txtime of ack at lowest rate + SIFS + DIFS
@@ -550,7 +550,7 @@
 	else
 		rate = &sc->sbands[IEEE80211_BAND_2GHZ].bitrates[0];
 
-	ack_tx_time = ath5k_hw_get_frame_duration(ah, 10, rate);
+	ack_tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, false);
 
 	/* ack_tx_time includes an SIFS already */
 	eifs = ack_tx_time + sifs + 2 * slot_time;
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig
index ad57a6d..d9ff841 100644
--- a/drivers/net/wireless/ath/ath9k/Kconfig
+++ b/drivers/net/wireless/ath/ath9k/Kconfig
@@ -5,7 +5,7 @@
 
 config ATH9K
 	tristate "Atheros 802.11n wireless cards support"
-	depends on PCI && MAC80211
+	depends on MAC80211
 	select ATH9K_HW
 	select MAC80211_LEDS
 	select LEDS_CLASS
@@ -23,6 +23,25 @@
 
 	  If you choose to build a module, it'll be called ath9k.
 
+config ATH9K_PCI
+	bool "Atheros ath9k PCI/PCIe bus support"
+	depends on ATH9K && PCI
+	default PCI
+	---help---
+	  This option enables the PCI bus support in ath9k.
+
+	  Say Y, if you have a compatible PCI/PCIe wireless card.
+
+config ATH9K_AHB
+	bool "Atheros ath9k AHB bus support"
+	depends on ATH9K
+	default n
+	---help---
+	  This option enables the AHB bus support in ath9k.
+
+	  Say Y, if you have a SoC with a compatible built-in
+	  wireless MAC. Say N if unsure.
+
 config ATH9K_DEBUGFS
 	bool "Atheros ath9k debugging"
 	depends on ATH9K && DEBUG_FS
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile
index 4d66ca8..05a6fad 100644
--- a/drivers/net/wireless/ath/ath9k/Makefile
+++ b/drivers/net/wireless/ath/ath9k/Makefile
@@ -6,8 +6,8 @@
 		xmit.o \
 
 ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o
-ath9k-$(CONFIG_PCI) += pci.o
-ath9k-$(CONFIG_ATHEROS_AR71XX) += ahb.o
+ath9k-$(CONFIG_ATH9K_PCI) += pci.o
+ath9k-$(CONFIG_ATH9K_AHB) += ahb.o
 ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o
 
 obj-$(CONFIG_ATH9K) += ath9k.o
@@ -48,4 +48,6 @@
 		htc_drv_init.o \
 		htc_drv_gpio.o
 
+ath9k_htc-$(CONFIG_ATH9K_HTC_DEBUGFS) += htc_drv_debug.o
+
 obj-$(CONFIG_ATH9K_HTC) += ath9k_htc.o
diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c
index 9cb0efa..5193ed5 100644
--- a/drivers/net/wireless/ath/ath9k/ahb.c
+++ b/drivers/net/wireless/ath/ath9k/ahb.c
@@ -21,6 +21,14 @@
 #include <linux/ath9k_platform.h>
 #include "ath9k.h"
 
+const struct platform_device_id ath9k_platform_id_table[] = {
+	{
+		.name = "ath9k",
+		.driver_data = AR5416_AR9100_DEVID,
+	},
+	{},
+};
+
 /* return bus cachesize in 4B word units */
 static void ath_ahb_read_cachesize(struct ath_common *common, int *csz)
 {
@@ -57,6 +65,7 @@
 	struct ath_softc *sc;
 	struct ieee80211_hw *hw;
 	struct resource *res;
+	const struct platform_device_id *id = platform_get_device_id(pdev);
 	int irq;
 	int ret = 0;
 	struct ath_hw *ah;
@@ -116,7 +125,7 @@
 		goto err_free_hw;
 	}
 
-	ret = ath9k_init_device(AR5416_AR9100_DEVID, sc, 0x0, &ath_ahb_bus_ops);
+	ret = ath9k_init_device(id->driver_data, sc, 0x0, &ath_ahb_bus_ops);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to initialize device\n");
 		goto err_irq;
@@ -165,8 +174,11 @@
 		.name	= "ath9k",
 		.owner	= THIS_MODULE,
 	},
+	.id_table    = ath9k_platform_id_table,
 };
 
+MODULE_DEVICE_TABLE(platform, ath9k_platform_id_table);
+
 int ath_ahb_init(void)
 {
 	return platform_driver_register(&ath_ahb_driver);
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
index 8dd8f63..c338efb 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
@@ -290,7 +290,6 @@
 		| (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
 		| SM(txPower, AR_XmitPower)
 		| (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
-		| (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
 		| (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0)
 		| (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0);
 
@@ -311,6 +310,16 @@
 	}
 }
 
+static void ar9002_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+
+	if (val)
+		ads->ds_ctl0 |= AR_ClrDestMask;
+	else
+		ads->ds_ctl0 &= ~AR_ClrDestMask;
+}
+
 static void ar9002_hw_set11n_ratescenario(struct ath_hw *ah, void *ds,
 					  void *lastds,
 					  u32 durUpdateEn, u32 rtsctsRate,
@@ -448,4 +457,5 @@
 	ops->set11n_aggr_last = ar9002_hw_set11n_aggr_last;
 	ops->clr11n_aggr = ar9002_hw_clr11n_aggr;
 	ops->set11n_burstduration = ar9002_hw_set11n_burstduration;
+	ops->set_clrdmask = ar9002_hw_set_clrdmask;
 }
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.h b/drivers/net/wireless/ath/ath9k/ar9002_phy.h
index 37663db..47780ef 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.h
+++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.h
@@ -483,7 +483,11 @@
 #define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN     0x01F80000
 #define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN_S   19
 
+#define AR_PHY_TX_PWRCTRL8       0xa278
+
 #define AR_PHY_TX_PWRCTRL9       0xa27C
+
+#define AR_PHY_TX_PWRCTRL10       0xa394
 #define AR_PHY_TX_DESIRED_SCALE_CCK        0x00007C00
 #define AR_PHY_TX_DESIRED_SCALE_CCK_S      10
 #define AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL  0x80000000
@@ -495,6 +499,8 @@
 
 #define AR_PHY_CH0_TX_PWRCTRL11  0xa398
 #define AR_PHY_CH1_TX_PWRCTRL11  0xb398
+#define AR_PHY_CH0_TX_PWRCTRL12  0xa3dc
+#define AR_PHY_CH0_TX_PWRCTRL13  0xa3e0
 #define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP   0x0000FC00
 #define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP_S 10
 
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
index 9ecca93..f915a3d 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
@@ -34,10 +34,10 @@
 
 static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p2[][5] = {
 	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-	{0x0000a2dc, 0x00033800, 0x00033800, 0x00637800, 0x00637800},
-	{0x0000a2e0, 0x0003c000, 0x0003c000, 0x03838000, 0x03838000},
-	{0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03fc0000, 0x03fc0000},
-	{0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+	{0x0000a2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+	{0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
+	{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
 	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
 	{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
 	{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
@@ -119,14 +119,14 @@
 	{0x0000a634, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
 	{0x0000a638, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
 	{0x0000a63c, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
-	{0x0000b2dc, 0x00033800, 0x00033800, 0x00637800, 0x00637800},
-	{0x0000b2e0, 0x0003c000, 0x0003c000, 0x03838000, 0x03838000},
-	{0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03fc0000, 0x03fc0000},
-	{0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-	{0x0000c2dc, 0x00033800, 0x00033800, 0x00637800, 0x00637800},
-	{0x0000c2e0, 0x0003c000, 0x0003c000, 0x03838000, 0x03838000},
-	{0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03fc0000, 0x03fc0000},
-	{0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+	{0x0000b2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+	{0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
+	{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x0000c2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+	{0x0000c2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+	{0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
+	{0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
 	{0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
 	{0x00016048, 0x62480001, 0x62480001, 0x62480001, 0x62480001},
 	{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
@@ -835,10 +835,10 @@
 
 static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = {
 	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-	{0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800},
-	{0x0000a2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
-	{0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
-	{0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+	{0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+	{0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+	{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
 	{0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
 	{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
 	{0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
@@ -920,14 +920,14 @@
 	{0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
 	{0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
 	{0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-	{0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800},
-	{0x0000b2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
-	{0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
-	{0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-	{0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800},
-	{0x0000c2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
-	{0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
-	{0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+	{0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+	{0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+	{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+	{0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+	{0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+	{0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
 	{0x00016044, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
 	{0x00016048, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
 	{0x00016068, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
@@ -941,10 +941,10 @@
 
 static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = {
 	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-	{0x0000a2dc, 0x01feee00, 0x01feee00, 0x00637800, 0x00637800},
-	{0x0000a2e0, 0x0000f000, 0x0000f000, 0x03838000, 0x03838000},
-	{0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03fc0000, 0x03fc0000},
-	{0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
+	{0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
+	{0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
+	{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
 	{0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
 	{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
 	{0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
@@ -1026,14 +1026,14 @@
 	{0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
 	{0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
 	{0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-	{0x0000b2dc, 0x01feee00, 0x01feee00, 0x00637800, 0x00637800},
-	{0x0000b2e0, 0x0000f000, 0x0000f000, 0x03838000, 0x03838000},
-	{0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03fc0000, 0x03fc0000},
-	{0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-	{0x0000c2dc, 0x01feee00, 0x01feee00, 0x00637800, 0x00637800},
-	{0x0000c2e0, 0x0000f000, 0x0000f000, 0x03838000, 0x03838000},
-	{0x0000c2e4, 0x01ff0000, 0x01ff0000, 0x03fc0000, 0x03fc0000},
-	{0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
+	{0x0000b2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
+	{0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
+	{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x0000c2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
+	{0x0000c2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
+	{0x0000c2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
+	{0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
 	{0x00016044, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
 	{0x00016048, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001},
 	{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
@@ -1307,10 +1307,10 @@
 
 static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p2[][5] = {
 	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-	{0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800},
-	{0x0000a2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
-	{0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
-	{0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+	{0x0000a2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+	{0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
+	{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
 	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
 	{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
 	{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
@@ -1329,21 +1329,21 @@
 	{0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24},
 	{0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640},
 	{0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660},
-	{0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861},
-	{0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81},
-	{0x0000a54c, 0x5c02486b, 0x5c02486b, 0x47001a83, 0x47001a83},
-	{0x0000a550, 0x61024a6c, 0x61024a6c, 0x4a001c84, 0x4a001c84},
-	{0x0000a554, 0x66026a6c, 0x66026a6c, 0x4e001ce3, 0x4e001ce3},
-	{0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x52001ce5, 0x52001ce5},
-	{0x0000a55c, 0x7002708c, 0x7002708c, 0x56001ce9, 0x56001ce9},
-	{0x0000a560, 0x7302b08a, 0x7302b08a, 0x5a001ceb, 0x5a001ceb},
-	{0x0000a564, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
-	{0x0000a568, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
-	{0x0000a56c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
-	{0x0000a570, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
-	{0x0000a574, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
-	{0x0000a578, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
-	{0x0000a57c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a544, 0x52022470, 0x52022470, 0x3f001861, 0x3f001861},
+	{0x0000a548, 0x55022490, 0x55022490, 0x43001a81, 0x43001a81},
+	{0x0000a54c, 0x59022492, 0x59022492, 0x47001a83, 0x47001a83},
+	{0x0000a550, 0x5d022692, 0x5d022692, 0x4a001c84, 0x4a001c84},
+	{0x0000a554, 0x61022892, 0x61022892, 0x4e001ce3, 0x4e001ce3},
+	{0x0000a558, 0x65024890, 0x65024890, 0x52001ce5, 0x52001ce5},
+	{0x0000a55c, 0x69024892, 0x69024892, 0x56001ce9, 0x56001ce9},
+	{0x0000a560, 0x6e024c92, 0x6e024c92, 0x5a001ceb, 0x5a001ceb},
+	{0x0000a564, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+	{0x0000a568, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+	{0x0000a56c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+	{0x0000a570, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+	{0x0000a574, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+	{0x0000a578, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+	{0x0000a57c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
 	{0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
 	{0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
 	{0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
@@ -1361,45 +1361,45 @@
 	{0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24},
 	{0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640},
 	{0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660},
-	{0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861},
-	{0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81},
-	{0x0000a5cc, 0x5c82486b, 0x5c82486b, 0x47801a83, 0x47801a83},
-	{0x0000a5d0, 0x61824a6c, 0x61824a6c, 0x4a801c84, 0x4a801c84},
-	{0x0000a5d4, 0x66826a6c, 0x66826a6c, 0x4e801ce3, 0x4e801ce3},
-	{0x0000a5d8, 0x6b826e6c, 0x6b826e6c, 0x52801ce5, 0x52801ce5},
-	{0x0000a5dc, 0x7082708c, 0x7082708c, 0x56801ce9, 0x56801ce9},
-	{0x0000a5e0, 0x7382b08a, 0x7382b08a, 0x5a801ceb, 0x5a801ceb},
-	{0x0000a5e4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
-	{0x0000a5e8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
-	{0x0000a5ec, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
-	{0x0000a5f0, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
-	{0x0000a5f4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
-	{0x0000a5f8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
-	{0x0000a5fc, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5c4, 0x52822470, 0x52822470, 0x3f801861, 0x3f801861},
+	{0x0000a5c8, 0x55822490, 0x55822490, 0x43801a81, 0x43801a81},
+	{0x0000a5cc, 0x59822492, 0x59822492, 0x47801a83, 0x47801a83},
+	{0x0000a5d0, 0x5d822692, 0x5d822692, 0x4a801c84, 0x4a801c84},
+	{0x0000a5d4, 0x61822892, 0x61822892, 0x4e801ce3, 0x4e801ce3},
+	{0x0000a5d8, 0x65824890, 0x65824890, 0x52801ce5, 0x52801ce5},
+	{0x0000a5dc, 0x69824892, 0x69824892, 0x56801ce9, 0x56801ce9},
+	{0x0000a5e0, 0x6e824c92, 0x6e824c92, 0x5a801ceb, 0x5a801ceb},
+	{0x0000a5e4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+	{0x0000a5e8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+	{0x0000a5ec, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f0, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+	{0x0000a5fc, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
 	{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
 	{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
 	{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
 	{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
 	{0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-	{0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000},
-	{0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501},
-	{0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501},
-	{0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03},
-	{0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04},
-	{0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04},
-	{0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005},
-	{0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
-	{0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
-	{0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
-	{0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
-	{0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800},
-	{0x0000b2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
-	{0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
-	{0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-	{0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800},
-	{0x0000c2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
-	{0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
-	{0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a614, 0x02004000, 0x02004000, 0x01404000, 0x01404000},
+	{0x0000a618, 0x02004801, 0x02004801, 0x01404501, 0x01404501},
+	{0x0000a61c, 0x02808a02, 0x02808a02, 0x02008501, 0x02008501},
+	{0x0000a620, 0x0380ce03, 0x0380ce03, 0x0280ca03, 0x0280ca03},
+	{0x0000a624, 0x04411104, 0x04411104, 0x03010c04, 0x03010c04},
+	{0x0000a628, 0x04411104, 0x04411104, 0x04014c04, 0x04014c04},
+	{0x0000a62c, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+	{0x0000a630, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+	{0x0000a634, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+	{0x0000a638, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+	{0x0000a63c, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+	{0x0000b2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+	{0x0000b2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+	{0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
+	{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x0000c2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+	{0x0000c2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+	{0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
+	{0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
 	{0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
 	{0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
 	{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
index 724ac24..c1264d6 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
@@ -329,7 +329,6 @@
 		| (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
 		| SM(txpower, AR_XmitPower)
 		| (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
-		| (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
 		| (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0)
 		| (flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0);
 
@@ -350,6 +349,16 @@
 	ads->ctl22 = 0;
 }
 
+static void ar9003_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val)
+{
+	struct ar9003_txc *ads = (struct ar9003_txc *) ds;
+
+	if (val)
+		ads->ctl11 |= AR_ClrDestMask;
+	else
+		ads->ctl11 &= ~AR_ClrDestMask;
+}
+
 static void ar9003_hw_set11n_ratescenario(struct ath_hw *ah, void *ds,
 					  void *lastds,
 					  u32 durUpdateEn, u32 rtsctsRate,
@@ -510,6 +519,7 @@
 	ops->set11n_aggr_last = ar9003_hw_set11n_aggr_last;
 	ops->clr11n_aggr = ar9003_hw_clr11n_aggr;
 	ops->set11n_burstduration = ar9003_hw_set11n_burstduration;
+	ops->set_clrdmask = ar9003_hw_set_clrdmask;
 }
 
 void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size)
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index eb250d6..1bc33f5 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -75,9 +75,18 @@
 	freq = centers.synth_center;
 
 	if (freq < 4800) {     /* 2 GHz, fractional mode */
-		if (AR_SREV_9485(ah))
-			channelSel = CHANSEL_2G_9485(freq);
-		else
+		if (AR_SREV_9485(ah)) {
+			u32 chan_frac;
+
+			/*
+			 * freq_ref = 40 / (refdiva >> amoderefsel); where refdiva=1 and amoderefsel=0
+			 * ndiv = ((chan_mhz * 4) / 3) / freq_ref;
+			 * chansel = int(ndiv), chanfrac = (ndiv - chansel) * 0x20000
+			 */
+			channelSel = (freq * 4) / 120;
+			chan_frac = (((freq * 4) % 120) * 0x20000) / 120;
+			channelSel = (channelSel << 17) | chan_frac;
+		} else
 			channelSel = CHANSEL_2G(freq);
 		/* Set to 2G mode */
 		bMode = 1;
@@ -401,7 +410,7 @@
 
 	ar9003_hw_spur_ofdm_clear(ah);
 
-	for (i = 0; spurChansPtr[i] && i < 5; i++) {
+	for (i = 0; i < AR_EEPROM_MODAL_SPURS && spurChansPtr[i]; i++) {
 		freq_offset = FBIN2FREQ(spurChansPtr[i], mode) - synth_freq;
 		if (abs(freq_offset) < range) {
 			ar9003_hw_spur_ofdm_work(ah, chan, freq_offset);
diff --git a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h
index f91f73e..fbdde29 100644
--- a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h
@@ -396,7 +396,7 @@
 	{0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
 	{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
 	{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
-	{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb},
+	{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
 	{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
 	{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
 	{0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
@@ -469,7 +469,7 @@
 	{0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
 	{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
 	{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
-	{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb},
+	{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
 	{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
 	{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
 	{0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
@@ -635,7 +635,7 @@
 	{0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
 	{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
 	{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
-	{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb},
+	{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
 	{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
 	{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
 	{0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
@@ -728,7 +728,7 @@
 	{0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
 	{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
 	{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
-	{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb},
+	{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
 	{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
 	{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
 	{0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
@@ -827,7 +827,7 @@
 	{0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
 	{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
 	{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
-	{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb},
+	{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
 	{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
 	{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
 	{0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 38835bc..a6b5388 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -200,6 +200,7 @@
 	int sched;
 	struct list_head list;
 	struct list_head tid_q;
+	bool clear_ps_filter;
 };
 
 struct ath_frame_info {
@@ -255,8 +256,12 @@
 #endif
 	struct ath_atx_tid tid[WME_NUM_TID];
 	struct ath_atx_ac ac[WME_NUM_AC];
+	int ps_key;
+
 	u16 maxampdu;
 	u8 mpdudensity;
+
+	bool sleeping;
 };
 
 #define AGGR_CLEANUP         BIT(1)
@@ -338,6 +343,9 @@
 void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
 void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
 
+void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an);
+bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an);
+
 /********/
 /* VIFs */
 /********/
@@ -665,7 +673,7 @@
 bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode);
 bool ath9k_uses_beacons(int type);
 
-#ifdef CONFIG_PCI
+#ifdef CONFIG_ATH9K_PCI
 int ath_pci_init(void);
 void ath_pci_exit(void);
 #else
@@ -673,7 +681,7 @@
 static inline void ath_pci_exit(void) {};
 #endif
 
-#ifdef CONFIG_ATHEROS_AR71XX
+#ifdef CONFIG_ATH9K_AHB
 int ath_ahb_init(void);
 void ath_ahb_exit(void);
 #else
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index eccb0ec..24f565b 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -320,6 +320,7 @@
 	if (avp->av_bcbuf != NULL) {
 		struct ath_buf *bf;
 
+		avp->is_bslot_active = false;
 		if (avp->av_bslot != -1) {
 			sc->beacon.bslot[avp->av_bslot] = NULL;
 			sc->nbcnvifs--;
@@ -743,37 +744,10 @@
 		cur_conf->dtim_period = 1;
 
 	ath_set_beacon(sc);
-	sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
 }
 
-void ath_set_beacon(struct ath_softc *sc)
+static bool ath_has_valid_bslot(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;
-	case NL80211_IFTYPE_ADHOC:
-	case NL80211_IFTYPE_MESH_POINT:
-		ath_beacon_config_adhoc(sc, cur_conf);
-		break;
-	case NL80211_IFTYPE_STATION:
-		ath_beacon_config_sta(sc, cur_conf);
-		break;
-	default:
-		ath_dbg(common, ATH_DBG_CONFIG,
-			"Unsupported beaconing mode\n");
-		return;
-	}
-
-	sc->sc_flags |= SC_OP_BEACONS;
-}
-
-void ath9k_set_beaconing_status(struct ath_softc *sc, bool status)
-{
-	struct ath_hw *ah = sc->sc_ah;
 	struct ath_vif *avp;
 	int slot;
 	bool found = false;
@@ -787,7 +761,47 @@
 			}
 		}
 	}
-	if (!found)
+	return found;
+}
+
+
+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:
+		if (ath_has_valid_bslot(sc))
+			ath_beacon_config_ap(sc, cur_conf);
+		break;
+	case NL80211_IFTYPE_ADHOC:
+	case NL80211_IFTYPE_MESH_POINT:
+		ath_beacon_config_adhoc(sc, cur_conf);
+		break;
+	case NL80211_IFTYPE_STATION:
+		ath_beacon_config_sta(sc, cur_conf);
+		/*
+		 * 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 | PS_WAIT_FOR_BEACON;
+		break;
+	default:
+		ath_dbg(common, ATH_DBG_CONFIG,
+			"Unsupported beaconing mode\n");
+		return;
+	}
+
+	sc->sc_flags |= SC_OP_BEACONS;
+}
+
+void ath9k_set_beaconing_status(struct ath_softc *sc, bool status)
+{
+	struct ath_hw *ah = sc->sc_ah;
+
+	if (!ath_has_valid_bslot(sc))
 		return;
 
 	ath9k_ps_wakeup(sc);
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index a762cad..34f191e 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -845,7 +845,7 @@
 
 	struct ath_softc *sc = file->private_data;
 	char *buf;
-	unsigned int len = 0, size = 1152;
+	unsigned int len = 0, size = 1400;
 	ssize_t retval = 0;
 
 	buf = kzalloc(size, GFP_KERNEL);
@@ -874,6 +874,34 @@
 			"%18s : %10u\n", "DECRYPT BUSY ERR",
 			sc->debug.stats.rxstats.decrypt_busy_err);
 
+	len += snprintf(buf + len, size - len,
+			"%18s : %10d\n", "RSSI-CTL0",
+			sc->debug.stats.rxstats.rs_rssi_ctl0);
+
+	len += snprintf(buf + len, size - len,
+			"%18s : %10d\n", "RSSI-CTL1",
+			sc->debug.stats.rxstats.rs_rssi_ctl1);
+
+	len += snprintf(buf + len, size - len,
+			"%18s : %10d\n", "RSSI-CTL2",
+			sc->debug.stats.rxstats.rs_rssi_ctl2);
+
+	len += snprintf(buf + len, size - len,
+			"%18s : %10d\n", "RSSI-EXT0",
+			sc->debug.stats.rxstats.rs_rssi_ext0);
+
+	len += snprintf(buf + len, size - len,
+			"%18s : %10d\n", "RSSI-EXT1",
+			sc->debug.stats.rxstats.rs_rssi_ext1);
+
+	len += snprintf(buf + len, size - len,
+			"%18s : %10d\n", "RSSI-EXT2",
+			sc->debug.stats.rxstats.rs_rssi_ext2);
+
+	len += snprintf(buf + len, size - len,
+			"%18s : %10d\n", "Rx Antenna",
+			sc->debug.stats.rxstats.rs_antenna);
+
 	PHY_ERR("UNDERRUN", ATH9K_PHYERR_UNDERRUN);
 	PHY_ERR("TIMING", ATH9K_PHYERR_TIMING);
 	PHY_ERR("PARITY", ATH9K_PHYERR_PARITY);
@@ -948,6 +976,16 @@
 		RX_PHY_ERR_INC(phyerr);
 	}
 
+	sc->debug.stats.rxstats.rs_rssi_ctl0 = rs->rs_rssi_ctl0;
+	sc->debug.stats.rxstats.rs_rssi_ctl1 = rs->rs_rssi_ctl1;
+	sc->debug.stats.rxstats.rs_rssi_ctl2 = rs->rs_rssi_ctl2;
+
+	sc->debug.stats.rxstats.rs_rssi_ext0 = rs->rs_rssi_ext0;
+	sc->debug.stats.rxstats.rs_rssi_ext1 = rs->rs_rssi_ext1;
+	sc->debug.stats.rxstats.rs_rssi_ext2 = rs->rs_rssi_ext2;
+
+	sc->debug.stats.rxstats.rs_antenna = rs->rs_antenna;
+
 #undef RX_STAT_INC
 #undef RX_PHY_ERR_INC
 }
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index 59338de..1f9f8ea 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -157,6 +157,13 @@
 	u32 post_delim_crc_err;
 	u32 decrypt_busy_err;
 	u32 phy_err_stats[ATH9K_PHYERR_MAX];
+	int8_t rs_rssi_ctl0;
+	int8_t rs_rssi_ctl1;
+	int8_t rs_rssi_ctl2;
+	int8_t rs_rssi_ext0;
+	int8_t rs_rssi_ext1;
+	int8_t rs_rssi_ext2;
+	u8 rs_antenna;
 };
 
 struct ath_stats {
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h
index bd82447..3e31613 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/eeprom.h
@@ -436,7 +436,11 @@
 	u8 db2_2:4, db2_3:4;
 	u8 db2_4:4, reserved:4;
 #endif
-	u8 futureModal[4];
+	u8 tx_diversity;
+	u8 flc_pwr_thresh;
+	u8 bb_scale_smrt_antenna;
+#define EEP_4K_BB_DESIRED_SCALE_MASK	0x1f
+	u8 futureModal[1];
 	struct spur_chan spurChans[AR_EEPROM_MODAL_SPURS];
 } __packed;
 
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
index bc77a30..6f714dd 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
@@ -781,6 +781,7 @@
 {
 	struct modal_eep_4k_header *pModal;
 	struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
+	struct base_eep_header_4k *pBase = &eep->baseEepHeader;
 	u8 txRxAttenLocal;
 	u8 ob[5], db1[5], db2[5];
 	u8 ant_div_control1, ant_div_control2;
@@ -1003,6 +1004,31 @@
 				      AR_PHY_SETTLING_SWITCH,
 				      pModal->swSettleHt40);
 	}
+	if (AR_SREV_9271(ah) || AR_SREV_9285(ah)) {
+		u8 bb_desired_scale = (pModal->bb_scale_smrt_antenna &
+				EEP_4K_BB_DESIRED_SCALE_MASK);
+		if ((pBase->txGainType == 0) && (bb_desired_scale != 0)) {
+			u32 pwrctrl, mask, clr;
+
+			mask = BIT(0)|BIT(5)|BIT(10)|BIT(15)|BIT(20)|BIT(25);
+			pwrctrl = mask * bb_desired_scale;
+			clr = mask * 0x1f;
+			REG_RMW(ah, AR_PHY_TX_PWRCTRL8, pwrctrl, clr);
+			REG_RMW(ah, AR_PHY_TX_PWRCTRL10, pwrctrl, clr);
+			REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL12, pwrctrl, clr);
+
+			mask = BIT(0)|BIT(5)|BIT(15);
+			pwrctrl = mask * bb_desired_scale;
+			clr = mask * 0x1f;
+			REG_RMW(ah, AR_PHY_TX_PWRCTRL9, pwrctrl, clr);
+
+			mask = BIT(0)|BIT(5);
+			pwrctrl = mask * bb_desired_scale;
+			clr = mask * 0x1f;
+			REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL11, pwrctrl, clr);
+			REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL13, pwrctrl, clr);
+		}
+	}
 }
 
 static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz)
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
index 2f0712e..1357975 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
@@ -858,35 +858,12 @@
 {
 	struct ar9287_eeprom *eep = &ah->eeprom.map9287;
 	struct modal_eep_ar9287_header *pModal = &eep->modalHeader;
-	u16 antWrites[AR9287_ANT_16S];
 	u32 regChainOffset, regval;
 	u8 txRxAttenLocal;
-	int i, j, offset_num;
+	int i;
 
 	pModal = &eep->modalHeader;
 
-	antWrites[0] = (u16)((pModal->antCtrlCommon >> 28) & 0xF);
-	antWrites[1] = (u16)((pModal->antCtrlCommon >> 24) & 0xF);
-	antWrites[2] = (u16)((pModal->antCtrlCommon >> 20) & 0xF);
-	antWrites[3] = (u16)((pModal->antCtrlCommon >> 16) & 0xF);
-	antWrites[4] = (u16)((pModal->antCtrlCommon >> 12) & 0xF);
-	antWrites[5] = (u16)((pModal->antCtrlCommon >> 8) & 0xF);
-	antWrites[6] = (u16)((pModal->antCtrlCommon >> 4)  & 0xF);
-	antWrites[7] = (u16)(pModal->antCtrlCommon & 0xF);
-
-	offset_num = 8;
-
-	for (i = 0, j = offset_num; i < AR9287_MAX_CHAINS; i++) {
-		antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 28) & 0xf);
-		antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 10) & 0x3);
-		antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 8) & 0x3);
-		antWrites[j++] = 0;
-		antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 6) & 0x3);
-		antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 4) & 0x3);
-		antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 2) & 0x3);
-		antWrites[j++] = (u16)(pModal->antCtrlChain[i] & 0x3);
-	}
-
 	REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon);
 
 	for (i = 0; i < AR9287_MAX_CHAINS; i++)	{
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index 2d10239..2e3a33a 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -17,11 +17,9 @@
 #include "htc.h"
 
 /* identify firmware images */
-#define FIRMWARE_AR7010		"ar7010.fw"
-#define FIRMWARE_AR7010_1_1	"ar7010_1_1.fw"
-#define FIRMWARE_AR9271		"ar9271.fw"
+#define FIRMWARE_AR7010_1_1     "htc_7010.fw"
+#define FIRMWARE_AR9271         "htc_9271.fw"
 
-MODULE_FIRMWARE(FIRMWARE_AR7010);
 MODULE_FIRMWARE(FIRMWARE_AR7010_1_1);
 MODULE_FIRMWARE(FIRMWARE_AR9271);
 
@@ -80,7 +78,7 @@
 
 	if (cmd) {
 		ath9k_htc_txcompletion_cb(cmd->hif_dev->htc_handle,
-					  cmd->skb, 1);
+					  cmd->skb, true);
 		kfree(cmd);
 	}
 
@@ -126,6 +124,90 @@
 	return ret;
 }
 
+static void hif_usb_mgmt_cb(struct urb *urb)
+{
+	struct cmd_buf *cmd = (struct cmd_buf *)urb->context;
+	struct hif_device_usb *hif_dev = cmd->hif_dev;
+	bool txok = true;
+
+	if (!cmd || !cmd->skb || !cmd->hif_dev)
+		return;
+
+	switch (urb->status) {
+	case 0:
+		break;
+	case -ENOENT:
+	case -ECONNRESET:
+	case -ENODEV:
+	case -ESHUTDOWN:
+		txok = false;
+
+		/*
+		 * If the URBs are being flushed, no need to complete
+		 * this packet.
+		 */
+		spin_lock(&hif_dev->tx.tx_lock);
+		if (hif_dev->tx.flags & HIF_USB_TX_FLUSH) {
+			spin_unlock(&hif_dev->tx.tx_lock);
+			dev_kfree_skb_any(cmd->skb);
+			kfree(cmd);
+			return;
+		}
+		spin_unlock(&hif_dev->tx.tx_lock);
+
+		break;
+	default:
+		txok = false;
+		break;
+	}
+
+	skb_pull(cmd->skb, 4);
+	ath9k_htc_txcompletion_cb(cmd->hif_dev->htc_handle,
+				  cmd->skb, txok);
+	kfree(cmd);
+}
+
+static int hif_usb_send_mgmt(struct hif_device_usb *hif_dev,
+			     struct sk_buff *skb)
+{
+	struct urb *urb;
+	struct cmd_buf *cmd;
+	int ret = 0;
+	__le16 *hdr;
+
+	urb = usb_alloc_urb(0, GFP_ATOMIC);
+	if (urb == NULL)
+		return -ENOMEM;
+
+	cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
+	if (cmd == NULL) {
+		usb_free_urb(urb);
+		return -ENOMEM;
+	}
+
+	cmd->skb = skb;
+	cmd->hif_dev = hif_dev;
+
+	hdr = (__le16 *) skb_push(skb, 4);
+	*hdr++ = cpu_to_le16(skb->len - 4);
+	*hdr++ = cpu_to_le16(ATH_USB_TX_STREAM_MODE_TAG);
+
+	usb_fill_bulk_urb(urb, hif_dev->udev,
+			 usb_sndbulkpipe(hif_dev->udev, USB_WLAN_TX_PIPE),
+			 skb->data, skb->len,
+			 hif_usb_mgmt_cb, cmd);
+
+	usb_anchor_urb(urb, &hif_dev->mgmt_submitted);
+	ret = usb_submit_urb(urb, GFP_ATOMIC);
+	if (ret) {
+		usb_unanchor_urb(urb);
+		kfree(cmd);
+	}
+	usb_free_urb(urb);
+
+	return ret;
+}
+
 static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev,
 					 struct sk_buff_head *list)
 {
@@ -133,7 +215,22 @@
 
 	while ((skb = __skb_dequeue(list)) != NULL) {
 		dev_kfree_skb_any(skb);
-		TX_STAT_INC(skb_dropped);
+	}
+}
+
+static inline void ath9k_skb_queue_complete(struct hif_device_usb *hif_dev,
+					    struct sk_buff_head *queue,
+					    bool txok)
+{
+	struct sk_buff *skb;
+
+	while ((skb = __skb_dequeue(queue)) != NULL) {
+		ath9k_htc_txcompletion_cb(hif_dev->htc_handle,
+					  skb, txok);
+		if (txok)
+			TX_STAT_INC(skb_success);
+		else
+			TX_STAT_INC(skb_failed);
 	}
 }
 
@@ -141,7 +238,7 @@
 {
 	struct tx_buf *tx_buf = (struct tx_buf *) urb->context;
 	struct hif_device_usb *hif_dev;
-	struct sk_buff *skb;
+	bool txok = true;
 
 	if (!tx_buf || !tx_buf->hif_dev)
 		return;
@@ -155,10 +252,7 @@
 	case -ECONNRESET:
 	case -ENODEV:
 	case -ESHUTDOWN:
-		/*
-		 * The URB has been killed, free the SKBs.
-		 */
-		ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
+		txok = false;
 
 		/*
 		 * If the URBs are being flushed, no need to add this
@@ -167,41 +261,19 @@
 		spin_lock(&hif_dev->tx.tx_lock);
 		if (hif_dev->tx.flags & HIF_USB_TX_FLUSH) {
 			spin_unlock(&hif_dev->tx.tx_lock);
+			ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
 			return;
 		}
 		spin_unlock(&hif_dev->tx.tx_lock);
 
-		/*
-		 * In the stop() case, this URB has to be added to
-		 * the free list.
-		 */
-		goto add_free;
+		break;
 	default:
+		txok = false;
 		break;
 	}
 
-	/*
-	 * Check if TX has been stopped, this is needed because
-	 * this CB could have been invoked just after the TX lock
-	 * was released in hif_stop() and kill_urb() hasn't been
-	 * called yet.
-	 */
-	spin_lock(&hif_dev->tx.tx_lock);
-	if (hif_dev->tx.flags & HIF_USB_TX_STOP) {
-		spin_unlock(&hif_dev->tx.tx_lock);
-		ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
-		goto add_free;
-	}
-	spin_unlock(&hif_dev->tx.tx_lock);
+	ath9k_skb_queue_complete(hif_dev, &tx_buf->skb_queue, txok);
 
-	/* Complete the queued SKBs. */
-	while ((skb = __skb_dequeue(&tx_buf->skb_queue)) != NULL) {
-		ath9k_htc_txcompletion_cb(hif_dev->htc_handle,
-					  skb, 1);
-		TX_STAT_INC(skb_completed);
-	}
-
-add_free:
 	/* Re-initialize the SKB queue */
 	tx_buf->len = tx_buf->offset = 0;
 	__skb_queue_head_init(&tx_buf->skb_queue);
@@ -274,7 +346,7 @@
 	ret = usb_submit_urb(tx_buf->urb, GFP_ATOMIC);
 	if (ret) {
 		tx_buf->len = tx_buf->offset = 0;
-		ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
+		ath9k_skb_queue_complete(hif_dev, &tx_buf->skb_queue, false);
 		__skb_queue_head_init(&tx_buf->skb_queue);
 		list_move_tail(&tx_buf->list, &hif_dev->tx.tx_buf);
 		hif_dev->tx.tx_buf_cnt++;
@@ -286,10 +358,11 @@
 	return ret;
 }
 
-static int hif_usb_send_tx(struct hif_device_usb *hif_dev, struct sk_buff *skb,
-			   struct ath9k_htc_tx_ctl *tx_ctl)
+static int hif_usb_send_tx(struct hif_device_usb *hif_dev, struct sk_buff *skb)
 {
+	struct ath9k_htc_tx_ctl *tx_ctl;
 	unsigned long flags;
+	int ret = 0;
 
 	spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
 
@@ -304,26 +377,36 @@
 		return -ENOMEM;
 	}
 
-	__skb_queue_tail(&hif_dev->tx.tx_skb_queue, skb);
-	hif_dev->tx.tx_skb_cnt++;
+	spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
 
-	/* Send normal frames immediately */
-	if (!tx_ctl || (tx_ctl && (tx_ctl->type == ATH9K_HTC_NORMAL)))
-		__hif_usb_tx(hif_dev);
+	tx_ctl = HTC_SKB_CB(skb);
+
+	/* Mgmt/Beacon frames don't use the TX buffer pool */
+	if ((tx_ctl->type == ATH9K_HTC_MGMT) ||
+	    (tx_ctl->type == ATH9K_HTC_BEACON)) {
+		ret = hif_usb_send_mgmt(hif_dev, skb);
+	}
+
+	spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
+
+	if ((tx_ctl->type == ATH9K_HTC_NORMAL) ||
+	    (tx_ctl->type == ATH9K_HTC_AMPDU)) {
+		__skb_queue_tail(&hif_dev->tx.tx_skb_queue, skb);
+		hif_dev->tx.tx_skb_cnt++;
+	}
 
 	/* Check if AMPDUs have to be sent immediately */
-	if (tx_ctl && (tx_ctl->type == ATH9K_HTC_AMPDU) &&
-	    (hif_dev->tx.tx_buf_cnt == MAX_TX_URB_NUM) &&
+	if ((hif_dev->tx.tx_buf_cnt == MAX_TX_URB_NUM) &&
 	    (hif_dev->tx.tx_skb_cnt < 2)) {
 		__hif_usb_tx(hif_dev);
 	}
 
 	spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
 
-	return 0;
+	return ret;
 }
 
-static void hif_usb_start(void *hif_handle, u8 pipe_id)
+static void hif_usb_start(void *hif_handle)
 {
 	struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
 	unsigned long flags;
@@ -335,14 +418,14 @@
 	spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
 }
 
-static void hif_usb_stop(void *hif_handle, u8 pipe_id)
+static void hif_usb_stop(void *hif_handle)
 {
 	struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
 	struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL;
 	unsigned long flags;
 
 	spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
-	ath9k_skb_queue_purge(hif_dev, &hif_dev->tx.tx_skb_queue);
+	ath9k_skb_queue_complete(hif_dev, &hif_dev->tx.tx_skb_queue, false);
 	hif_dev->tx.tx_skb_cnt = 0;
 	hif_dev->tx.flags |= HIF_USB_TX_STOP;
 	spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
@@ -352,17 +435,18 @@
 				 &hif_dev->tx.tx_pending, list) {
 		usb_kill_urb(tx_buf->urb);
 	}
+
+	usb_kill_anchored_urbs(&hif_dev->mgmt_submitted);
 }
 
-static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb,
-			struct ath9k_htc_tx_ctl *tx_ctl)
+static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb)
 {
 	struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
 	int ret = 0;
 
 	switch (pipe_id) {
 	case USB_WLAN_TX_PIPE:
-		ret = hif_usb_send_tx(hif_dev, skb, tx_ctl);
+		ret = hif_usb_send_tx(hif_dev, skb);
 		break;
 	case USB_REG_OUT_PIPE:
 		ret = hif_usb_send_regout(hif_dev, skb);
@@ -377,6 +461,40 @@
 	return ret;
 }
 
+static inline bool check_index(struct sk_buff *skb, u8 idx)
+{
+	struct ath9k_htc_tx_ctl *tx_ctl;
+
+	tx_ctl = HTC_SKB_CB(skb);
+
+	if ((tx_ctl->type == ATH9K_HTC_AMPDU) &&
+	    (tx_ctl->sta_idx == idx))
+		return true;
+
+	return false;
+}
+
+static void hif_usb_sta_drain(void *hif_handle, u8 idx)
+{
+	struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
+	struct sk_buff *skb, *tmp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
+
+	skb_queue_walk_safe(&hif_dev->tx.tx_skb_queue, skb, tmp) {
+		if (check_index(skb, idx)) {
+			__skb_unlink(skb, &hif_dev->tx.tx_skb_queue);
+			ath9k_htc_txcompletion_cb(hif_dev->htc_handle,
+						  skb, false);
+			hif_dev->tx.tx_skb_cnt--;
+			TX_STAT_INC(skb_failed);
+		}
+	}
+
+	spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
+}
+
 static struct ath9k_htc_hif hif_usb = {
 	.transport = ATH9K_HIF_USB,
 	.name = "ath9k_hif_usb",
@@ -386,6 +504,7 @@
 
 	.start = hif_usb_start,
 	.stop = hif_usb_stop,
+	.sta_drain = hif_usb_sta_drain,
 	.send = hif_usb_send,
 };
 
@@ -567,6 +686,9 @@
 	case -ESHUTDOWN:
 		goto free;
 	default:
+		skb_reset_tail_pointer(skb);
+		skb_trim(skb, 0);
+
 		goto resubmit;
 	}
 
@@ -591,23 +713,15 @@
 						 USB_REG_IN_PIPE),
 				 nskb->data, MAX_REG_IN_BUF_SIZE,
 				 ath9k_hif_usb_reg_in_cb, nskb);
-
-		ret = usb_submit_urb(urb, GFP_ATOMIC);
-		if (ret) {
-			kfree_skb(nskb);
-			urb->context = NULL;
-		}
-
-		return;
 	}
 
 resubmit:
-	skb_reset_tail_pointer(skb);
-	skb_trim(skb, 0);
-
+	usb_anchor_urb(urb, &hif_dev->reg_in_submitted);
 	ret = usb_submit_urb(urb, GFP_ATOMIC);
-	if (ret)
+	if (ret) {
+		usb_unanchor_urb(urb);
 		goto free;
+	}
 
 	return;
 free:
@@ -641,6 +755,8 @@
 		kfree(tx_buf->buf);
 		kfree(tx_buf);
 	}
+
+	usb_kill_anchored_urbs(&hif_dev->mgmt_submitted);
 }
 
 static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev)
@@ -652,6 +768,7 @@
 	INIT_LIST_HEAD(&hif_dev->tx.tx_pending);
 	spin_lock_init(&hif_dev->tx.tx_lock);
 	__skb_queue_head_init(&hif_dev->tx.tx_skb_queue);
+	init_usb_anchor(&hif_dev->mgmt_submitted);
 
 	for (i = 0; i < MAX_TX_URB_NUM; i++) {
 		tx_buf = kzalloc(sizeof(struct tx_buf), GFP_KERNEL);
@@ -748,43 +865,67 @@
 	return ret;
 }
 
-static void ath9k_hif_usb_dealloc_reg_in_urb(struct hif_device_usb *hif_dev)
+static void ath9k_hif_usb_dealloc_reg_in_urbs(struct hif_device_usb *hif_dev)
 {
-	if (hif_dev->reg_in_urb) {
-		usb_kill_urb(hif_dev->reg_in_urb);
-		if (hif_dev->reg_in_urb->context)
-			kfree_skb((void *)hif_dev->reg_in_urb->context);
-		usb_free_urb(hif_dev->reg_in_urb);
-		hif_dev->reg_in_urb = NULL;
-	}
+	usb_kill_anchored_urbs(&hif_dev->reg_in_submitted);
 }
 
-static int ath9k_hif_usb_alloc_reg_in_urb(struct hif_device_usb *hif_dev)
+static int ath9k_hif_usb_alloc_reg_in_urbs(struct hif_device_usb *hif_dev)
 {
-	struct sk_buff *skb;
+	struct urb *urb = NULL;
+	struct sk_buff *skb = NULL;
+	int i, ret;
 
-	hif_dev->reg_in_urb = usb_alloc_urb(0, GFP_KERNEL);
-	if (hif_dev->reg_in_urb == NULL)
-		return -ENOMEM;
+	init_usb_anchor(&hif_dev->reg_in_submitted);
 
-	skb = alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_KERNEL);
-	if (!skb)
-		goto err;
+	for (i = 0; i < MAX_REG_IN_URB_NUM; i++) {
 
-	usb_fill_bulk_urb(hif_dev->reg_in_urb, hif_dev->udev,
-			 usb_rcvbulkpipe(hif_dev->udev,
-					 USB_REG_IN_PIPE),
-			 skb->data, MAX_REG_IN_BUF_SIZE,
-			 ath9k_hif_usb_reg_in_cb, skb);
+		/* Allocate URB */
+		urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (urb == NULL) {
+			ret = -ENOMEM;
+			goto err_urb;
+		}
 
-	if (usb_submit_urb(hif_dev->reg_in_urb, GFP_KERNEL) != 0)
-		goto err;
+		/* Allocate buffer */
+		skb = alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_KERNEL);
+		if (!skb) {
+			ret = -ENOMEM;
+			goto err_skb;
+		}
+
+		usb_fill_bulk_urb(urb, hif_dev->udev,
+				  usb_rcvbulkpipe(hif_dev->udev,
+						  USB_REG_IN_PIPE),
+				  skb->data, MAX_REG_IN_BUF_SIZE,
+				  ath9k_hif_usb_reg_in_cb, skb);
+
+		/* Anchor URB */
+		usb_anchor_urb(urb, &hif_dev->reg_in_submitted);
+
+		/* Submit URB */
+		ret = usb_submit_urb(urb, GFP_KERNEL);
+		if (ret) {
+			usb_unanchor_urb(urb);
+			goto err_submit;
+		}
+
+		/*
+		 * Drop reference count.
+		 * This ensures that the URB is freed when killing them.
+		 */
+		usb_free_urb(urb);
+	}
 
 	return 0;
 
-err:
-	ath9k_hif_usb_dealloc_reg_in_urb(hif_dev);
-	return -ENOMEM;
+err_submit:
+	kfree_skb(skb);
+err_skb:
+	usb_free_urb(urb);
+err_urb:
+	ath9k_hif_usb_dealloc_reg_in_urbs(hif_dev);
+	return ret;
 }
 
 static int ath9k_hif_usb_alloc_urbs(struct hif_device_usb *hif_dev)
@@ -801,7 +942,7 @@
 		goto err_rx;
 
 	/* Register Read */
-	if (ath9k_hif_usb_alloc_reg_in_urb(hif_dev) < 0)
+	if (ath9k_hif_usb_alloc_reg_in_urbs(hif_dev) < 0)
 		goto err_reg;
 
 	return 0;
@@ -816,7 +957,7 @@
 static void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev)
 {
 	usb_kill_anchored_urbs(&hif_dev->regout_submitted);
-	ath9k_hif_usb_dealloc_reg_in_urb(hif_dev);
+	ath9k_hif_usb_dealloc_reg_in_urbs(hif_dev);
 	ath9k_hif_usb_dealloc_tx_urbs(hif_dev);
 	ath9k_hif_usb_dealloc_rx_urbs(hif_dev);
 }
@@ -1026,10 +1167,7 @@
 	/* Find out which firmware to load */
 
 	if (IS_AR7010_DEVICE(id->driver_info))
-		if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x0202)
-			hif_dev->fw_name = FIRMWARE_AR7010_1_1;
-		else
-			hif_dev->fw_name = FIRMWARE_AR7010;
+		hif_dev->fw_name = FIRMWARE_AR7010_1_1;
 	else
 		hif_dev->fw_name = FIRMWARE_AR9271;
 
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h
index 7b9d863..f59df48 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.h
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.h
@@ -31,7 +31,7 @@
 
 /* FIXME: Verify these numbers (with Windows) */
 #define MAX_TX_URB_NUM  8
-#define MAX_TX_BUF_NUM  1024
+#define MAX_TX_BUF_NUM  256
 #define MAX_TX_BUF_SIZE 32768
 #define MAX_TX_AGGR_NUM 20
 
@@ -40,7 +40,7 @@
 #define MAX_PKT_NUM_IN_TRANSFER 10
 
 #define MAX_REG_OUT_URB_NUM  1
-#define MAX_REG_OUT_BUF_NUM  8
+#define MAX_REG_IN_URB_NUM   64
 
 #define MAX_REG_IN_BUF_SIZE 64
 
@@ -90,9 +90,10 @@
 	const struct firmware *firmware;
 	struct htc_target *htc_handle;
 	struct hif_usb_tx tx;
-	struct urb *reg_in_urb;
 	struct usb_anchor regout_submitted;
 	struct usb_anchor rx_submitted;
+	struct usb_anchor reg_in_submitted;
+	struct usb_anchor mgmt_submitted;
 	struct sk_buff *remain_skb;
 	const char *fw_name;
 	int rx_remain_len;
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index ec47be9..48a8855 100644
--- a/drivers/net/wireless/ath/ath9k/htc.h
+++ b/drivers/net/wireless/ath/ath9k/htc.h
@@ -67,8 +67,11 @@
 };
 
 #define ATH9K_HTC_HDRSPACE sizeof(struct htc_frame_hdr)
-#define ATH9K_HTC_AMPDU	1
+
+#define ATH9K_HTC_AMPDU  1
 #define ATH9K_HTC_NORMAL 2
+#define ATH9K_HTC_BEACON 3
+#define ATH9K_HTC_MGMT   4
 
 #define ATH9K_HTC_TX_CTSONLY      0x1
 #define ATH9K_HTC_TX_RTSCTS       0x2
@@ -82,7 +85,8 @@
 	__be32 flags; /* ATH9K_HTC_TX_* */
 	u8 key_type;
 	u8 keyix;
-	u8 reserved[26];
+	u8 cookie;
+	u8 pad;
 } __packed;
 
 struct tx_mgmt_hdr {
@@ -92,26 +96,16 @@
 	u8 flags;
 	u8 key_type;
 	u8 keyix;
-	u16 reserved;
+	u8 cookie;
+	u8 pad;
 } __packed;
 
 struct tx_beacon_header {
-	u8 len_changed;
 	u8 vif_index;
+	u8 len_changed;
 	u16 rev;
 } __packed;
 
-struct ath9k_htc_target_hw {
-	u32 flags;
-	u32 flags_ext;
-	u32 ampdu_limit;
-	u8 ampdu_subframes;
-	u8 tx_chainmask;
-	u8 tx_chainmask_legacy;
-	u8 rtscts_ratecode;
-	u8 protmode;
-} __packed;
-
 struct ath9k_htc_cap_target {
 	u32 flags;
 	u32 flags_ext;
@@ -121,21 +115,16 @@
 	u8 tx_chainmask_legacy;
 	u8 rtscts_ratecode;
 	u8 protmode;
+	u8 pad;
 } __packed;
 
 struct ath9k_htc_target_vif {
 	u8 index;
-	u8 des_bssid[ETH_ALEN];
-	__be32 opmode;
+	u8 opmode;
 	u8 myaddr[ETH_ALEN];
-	u8 bssid[ETH_ALEN];
-	u32 flags;
-	u32 flags_ext;
-	u16 ps_sta;
-	__be16 rtsthreshold;
 	u8 ath_cap;
-	u8 node;
-	s8 mcast_rate;
+	__be16 rtsthreshold;
+	u8 pad;
 } __packed;
 
 #define ATH_HTC_STA_AUTH  0x0001
@@ -143,27 +132,16 @@
 #define ATH_HTC_STA_ERP   0x0004
 #define ATH_HTC_STA_HT    0x0008
 
-/* FIXME: UAPSD variables */
 struct ath9k_htc_target_sta {
-	u16 associd;
-	u16 txpower;
-	u32 ucastkey;
 	u8 macaddr[ETH_ALEN];
 	u8 bssid[ETH_ALEN];
 	u8 sta_index;
 	u8 vif_index;
-	u8 vif_sta;
-	__be16 flags; /* ATH_HTC_STA_* */
-	u16 htcap;
-	u8 valid;
-	u16 capinfo;
-	struct ath9k_htc_target_hw *hw;
-	struct ath9k_htc_target_vif *vif;
-	u16 txseqmgmt;
 	u8 is_vif_sta;
-	u16 maxampdu;
-	u16 iv16;
-	u32 iv32;
+	__be16 flags; /* ATH_HTC_STA_* */
+	__be16 htcap;
+	__be16 maxampdu;
+	u8 pad;
 } __packed;
 
 struct ath9k_htc_target_aggr {
@@ -197,12 +175,31 @@
 	struct ath9k_htc_rate rates;
 };
 
-struct ath9k_htc_target_stats {
-	__be32 tx_shortretry;
-	__be32 tx_longretry;
-	__be32 tx_xretries;
-	__be32 ht_txunaggr_xretry;
-	__be32 ht_tx_xretries;
+struct ath9k_htc_target_int_stats {
+	__be32 rx;
+	__be32 rxorn;
+	__be32 rxeol;
+	__be32 txurn;
+	__be32 txto;
+	__be32 cst;
+} __packed;
+
+struct ath9k_htc_target_tx_stats {
+	__be32 xretries;
+	__be32 fifoerr;
+	__be32 filtered;
+	__be32 timer_exp;
+	__be32 shortretries;
+	__be32 longretries;
+	__be32 qnull;
+	__be32 encap_fail;
+	__be32 nobuf;
+} __packed;
+
+struct ath9k_htc_target_rx_stats {
+	__be32 nobuf;
+	__be32 host_send;
+	__be32 host_done;
 } __packed;
 
 #define ATH9K_HTC_MAX_VIF 2
@@ -244,6 +241,8 @@
 	u8 index;
 	u16 seq_no;
 	bool beacon_configured;
+	int bslot;
+	__le64 tsfadjust;
 };
 
 struct ath9k_vif_iter_data {
@@ -282,23 +281,65 @@
 	spinlock_t rxbuflock;
 };
 
+#define ATH9K_HTC_TX_CLEANUP_INTERVAL 50 /* ms */
+#define ATH9K_HTC_TX_TIMEOUT_INTERVAL 2500 /* ms */
+#define ATH9K_HTC_TX_RESERVE 10
+#define ATH9K_HTC_TX_TIMEOUT_COUNT 20
+#define ATH9K_HTC_TX_THRESHOLD (MAX_TX_BUF_NUM - ATH9K_HTC_TX_RESERVE)
+
+#define ATH9K_HTC_OP_TX_QUEUES_STOP BIT(0)
+#define ATH9K_HTC_OP_TX_DRAIN       BIT(1)
+
+struct ath9k_htc_tx {
+	u8 flags;
+	int queued_cnt;
+	struct sk_buff_head mgmt_ep_queue;
+	struct sk_buff_head cab_ep_queue;
+	struct sk_buff_head data_be_queue;
+	struct sk_buff_head data_bk_queue;
+	struct sk_buff_head data_vi_queue;
+	struct sk_buff_head data_vo_queue;
+	struct sk_buff_head tx_failed;
+	DECLARE_BITMAP(tx_slot, MAX_TX_BUF_NUM);
+	struct timer_list cleanup_timer;
+	spinlock_t tx_lock;
+};
+
 struct ath9k_htc_tx_ctl {
 	u8 type; /* ATH9K_HTC_* */
+	u8 epid;
+	u8 txok;
+	u8 sta_idx;
+	unsigned long timestamp;
 };
 
+static inline struct ath9k_htc_tx_ctl *HTC_SKB_CB(struct sk_buff *skb)
+{
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+
+	BUILD_BUG_ON(sizeof(struct ath9k_htc_tx_ctl) >
+		     IEEE80211_TX_INFO_DRIVER_DATA_SIZE);
+	return (struct ath9k_htc_tx_ctl *) &tx_info->driver_data;
+}
+
 #ifdef CONFIG_ATH9K_HTC_DEBUGFS
 
 #define TX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.tx_stats.c++)
 #define RX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.rx_stats.c++)
+#define CAB_STAT_INC   priv->debug.tx_stats.cab_queued++
 
 #define TX_QSTAT_INC(q) (priv->debug.tx_stats.queue_stats[q]++)
 
+void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv,
+			   struct ath_htc_rx_status *rxs);
+
 struct ath_tx_stats {
 	u32 buf_queued;
 	u32 buf_completed;
 	u32 skb_queued;
-	u32 skb_completed;
-	u32 skb_dropped;
+	u32 skb_success;
+	u32 skb_failed;
+	u32 cab_queued;
 	u32 queue_stats[WME_NUM_AC];
 };
 
@@ -306,25 +347,35 @@
 	u32 skb_allocated;
 	u32 skb_completed;
 	u32 skb_dropped;
+	u32 err_crc;
+	u32 err_decrypt_crc;
+	u32 err_mic;
+	u32 err_pre_delim;
+	u32 err_post_delim;
+	u32 err_decrypt_busy;
+	u32 err_phy;
+	u32 err_phy_stats[ATH9K_PHYERR_MAX];
 };
 
 struct ath9k_debug {
 	struct dentry *debugfs_phy;
-	struct dentry *debugfs_tgt_stats;
-	struct dentry *debugfs_xmit;
-	struct dentry *debugfs_recv;
 	struct ath_tx_stats tx_stats;
 	struct ath_rx_stats rx_stats;
-	u32 txrate;
 };
 
 #else
 
 #define TX_STAT_INC(c) do { } while (0)
 #define RX_STAT_INC(c) do { } while (0)
+#define CAB_STAT_INC   do { } while (0)
 
 #define TX_QSTAT_INC(c) do { } while (0)
 
+static inline void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv,
+					 struct ath_htc_rx_status *rxs)
+{
+}
+
 #endif /* CONFIG_ATH9K_HTC_DEBUGFS */
 
 #define ATH_LED_PIN_DEF             1
@@ -351,10 +402,21 @@
 	int brightness;
 };
 
+#define BSTUCK_THRESHOLD 10
+
+/*
+ * Adjust these when the max. no of beaconing interfaces is
+ * increased.
+ */
+#define DEFAULT_SWBA_RESPONSE 40 /* in TUs */
+#define MIN_SWBA_RESPONSE     10 /* in TUs */
+
 struct htc_beacon_config {
+	struct ieee80211_vif *bslot[ATH9K_HTC_MAX_BCN_VIF];
 	u16 beacon_interval;
 	u16 dtim_period;
 	u16 bmiss_timeout;
+	u32 bmiss_cnt;
 };
 
 struct ath_btcoex {
@@ -388,6 +450,9 @@
 	struct htc_target *htc;
 	struct wmi *wmi;
 
+	u16 fw_version_major;
+	u16 fw_version_minor;
+
 	enum htc_endpoint_id wmi_cmd_ep;
 	enum htc_endpoint_id beacon_ep;
 	enum htc_endpoint_id cab_ep;
@@ -411,27 +476,23 @@
 	u16 txpowlimit;
 	u16 nvifs;
 	u16 nstations;
-	u32 bmiss_cnt;
 	bool rearm_ani;
 	bool reconfig_beacon;
+	unsigned int rxfilter;
 
 	struct ath9k_hw_cal_data caldata;
+	struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
 
 	spinlock_t beacon_lock;
-
-	bool tx_queues_stop;
-	spinlock_t tx_lock;
-
-	struct ieee80211_vif *vif;
 	struct htc_beacon_config cur_beacon_conf;
-	unsigned int rxfilter;
+
+	struct ath9k_htc_rx rx;
+	struct ath9k_htc_tx tx;
+
 	struct tasklet_struct swba_tasklet;
 	struct tasklet_struct rx_tasklet;
-	struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
-	struct ath9k_htc_rx rx;
-	struct tasklet_struct tx_tasklet;
-	struct sk_buff_head tx_queue;
 	struct delayed_work ani_work;
+	struct tasklet_struct tx_failed_tasklet;
 	struct work_struct ps_work;
 	struct work_struct fatal_work;
 
@@ -470,11 +531,18 @@
 
 void ath9k_htc_reset(struct ath9k_htc_priv *priv);
 
+void ath9k_htc_assign_bslot(struct ath9k_htc_priv *priv,
+			    struct ieee80211_vif *vif);
+void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv,
+			    struct ieee80211_vif *vif);
+void ath9k_htc_set_tsfadjust(struct ath9k_htc_priv *priv,
+			     struct ieee80211_vif *vif);
 void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv);
 void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
 			     struct ieee80211_vif *vif);
 void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv);
-void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending);
+void ath9k_htc_swba(struct ath9k_htc_priv *priv,
+		    struct wmi_event_swba *swba);
 
 void ath9k_htc_rxep(void *priv, struct sk_buff *skb,
 		    enum htc_endpoint_id ep_id);
@@ -491,14 +559,23 @@
 void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv);
 
 int ath9k_tx_init(struct ath9k_htc_priv *priv);
-void ath9k_tx_tasklet(unsigned long data);
-int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb);
+int ath9k_htc_tx_start(struct ath9k_htc_priv *priv,
+		       struct sk_buff *skb, u8 slot, bool is_cab);
 void ath9k_tx_cleanup(struct ath9k_htc_priv *priv);
 bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype);
 int ath9k_htc_cabq_setup(struct ath9k_htc_priv *priv);
 int get_hw_qnum(u16 queue, int *hwq_map);
 int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum,
 		       struct ath9k_tx_queue_info *qinfo);
+void ath9k_htc_check_stop_queues(struct ath9k_htc_priv *priv);
+void ath9k_htc_check_wake_queues(struct ath9k_htc_priv *priv);
+int ath9k_htc_tx_get_slot(struct ath9k_htc_priv *priv);
+void ath9k_htc_tx_clear_slot(struct ath9k_htc_priv *priv, int slot);
+void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv);
+void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event);
+void ath9k_htc_tx_failed(struct ath9k_htc_priv *priv);
+void ath9k_tx_failed_tasklet(unsigned long data);
+void ath9k_htc_tx_cleanup_timer(unsigned long data);
 
 int ath9k_rx_init(struct ath9k_htc_priv *priv);
 void ath9k_rx_cleanup(struct ath9k_htc_priv *priv);
@@ -528,15 +605,9 @@
 int ath9k_htc_resume(struct htc_target *htc_handle);
 #endif
 #ifdef CONFIG_ATH9K_HTC_DEBUGFS
-int ath9k_htc_debug_create_root(void);
-void ath9k_htc_debug_remove_root(void);
 int ath9k_htc_init_debug(struct ath_hw *ah);
-void ath9k_htc_exit_debug(struct ath_hw *ah);
 #else
-static inline int ath9k_htc_debug_create_root(void) { return 0; };
-static inline void ath9k_htc_debug_remove_root(void) {};
 static inline int ath9k_htc_init_debug(struct ath_hw *ah) { return 0; };
-static inline void ath9k_htc_exit_debug(struct ath_hw *ah) {};
 #endif /* CONFIG_ATH9K_HTC_DEBUGFS */
 
 #endif /* HTC_H */
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
index 8f56158..a157107 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
@@ -18,6 +18,50 @@
 
 #define FUDGE 2
 
+void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv)
+{
+	struct ath_hw *ah = priv->ah;
+	struct ath9k_tx_queue_info qi, qi_be;
+
+	memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
+	memset(&qi_be, 0, sizeof(struct ath9k_tx_queue_info));
+
+	ath9k_hw_get_txq_props(ah, priv->beaconq, &qi);
+
+	if (priv->ah->opmode == NL80211_IFTYPE_AP) {
+		qi.tqi_aifs = 1;
+		qi.tqi_cwmin = 0;
+		qi.tqi_cwmax = 0;
+	} else if (priv->ah->opmode == NL80211_IFTYPE_ADHOC) {
+		int qnum = priv->hwq_map[WME_AC_BE];
+
+		ath9k_hw_get_txq_props(ah, qnum, &qi_be);
+
+		qi.tqi_aifs = qi_be.tqi_aifs;
+
+		/*
+		 * For WIFI Beacon Distribution
+		 * Long slot time  : 2x cwmin
+		 * Short slot time : 4x cwmin
+		 */
+		if (ah->slottime == ATH9K_SLOT_TIME_20)
+			qi.tqi_cwmin = 2*qi_be.tqi_cwmin;
+		else
+			qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
+
+		qi.tqi_cwmax = qi_be.tqi_cwmax;
+
+	}
+
+	if (!ath9k_hw_set_txq_props(ah, priv->beaconq, &qi)) {
+		ath_err(ath9k_hw_common(ah),
+			"Unable to update beacon queue %u!\n", priv->beaconq);
+	} else {
+		ath9k_hw_resettxqueue(ah, priv->beaconq);
+	}
+}
+
+
 static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
 					struct htc_beacon_config *bss_conf)
 {
@@ -154,6 +198,15 @@
 	intval /= ATH9K_HTC_MAX_BCN_VIF;
 	nexttbtt = intval;
 
+	/*
+	 * To reduce beacon misses under heavy TX load,
+	 * set the beacon response time to a larger value.
+	 */
+	if (intval > DEFAULT_SWBA_RESPONSE)
+		priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE;
+	else
+		priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE;
+
 	if (priv->op_flags & OP_TSF_RESET) {
 		ath9k_hw_reset_tsf(priv->ah);
 		priv->op_flags &= ~OP_TSF_RESET;
@@ -172,12 +225,16 @@
 		imask |= ATH9K_INT_SWBA;
 
 	ath_dbg(common, ATH_DBG_CONFIG,
-		"AP Beacon config, intval: %d, nexttbtt: %u imask: 0x%x\n",
-		bss_conf->beacon_interval, nexttbtt, imask);
+		"AP Beacon config, intval: %d, nexttbtt: %u, resp_time: %d "
+		"imask: 0x%x\n",
+		bss_conf->beacon_interval, nexttbtt,
+		priv->ah->config.sw_beacon_response_time, imask);
+
+	ath9k_htc_beaconq_config(priv);
 
 	WMI_CMD(WMI_DISABLE_INTR_CMDID);
 	ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval));
-	priv->bmiss_cnt = 0;
+	priv->cur_beacon_conf.bmiss_cnt = 0;
 	htc_imask = cpu_to_be32(imask);
 	WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
 }
@@ -205,16 +262,26 @@
 		nexttbtt += intval;
 	} while (nexttbtt < tsftu);
 
+	/*
+	 * Only one IBSS interfce is allowed.
+	 */
+	if (intval > DEFAULT_SWBA_RESPONSE)
+		priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE;
+	else
+		priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE;
+
 	if (priv->op_flags & OP_ENABLE_BEACON)
 		imask |= ATH9K_INT_SWBA;
 
 	ath_dbg(common, ATH_DBG_CONFIG,
-		"IBSS Beacon config, intval: %d, nexttbtt: %u, imask: 0x%x\n",
-		bss_conf->beacon_interval, nexttbtt, imask);
+		"IBSS Beacon config, intval: %d, nexttbtt: %u, "
+		"resp_time: %d, imask: 0x%x\n",
+		bss_conf->beacon_interval, nexttbtt,
+		priv->ah->config.sw_beacon_response_time, imask);
 
 	WMI_CMD(WMI_DISABLE_INTR_CMDID);
 	ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval));
-	priv->bmiss_cnt = 0;
+	priv->cur_beacon_conf.bmiss_cnt = 0;
 	htc_imask = cpu_to_be32(imask);
 	WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
 }
@@ -225,38 +292,101 @@
 	dev_kfree_skb_any(skb);
 }
 
-void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending)
+static void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv,
+				    int slot)
 {
-	struct ath9k_htc_vif *avp = (void *)priv->vif->drv_priv;
-	struct tx_beacon_header beacon_hdr;
-	struct ath9k_htc_tx_ctl tx_ctl;
-	struct ieee80211_tx_info *info;
-	struct sk_buff *beacon;
-	u8 *tx_fhdr;
-
-	memset(&beacon_hdr, 0, sizeof(struct tx_beacon_header));
-	memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl));
-
-	/* FIXME: Handle BMISS */
-	if (beacon_pending != 0) {
-		priv->bmiss_cnt++;
-		return;
-	}
+	struct ath_common *common = ath9k_hw_common(priv->ah);
+	struct ieee80211_vif *vif;
+	struct sk_buff *skb;
+	struct ieee80211_hdr *hdr;
+	int padpos, padsize, ret, tx_slot;
 
 	spin_lock_bh(&priv->beacon_lock);
 
+	vif = priv->cur_beacon_conf.bslot[slot];
+
+	skb = ieee80211_get_buffered_bc(priv->hw, vif);
+
+	while(skb) {
+		hdr = (struct ieee80211_hdr *) skb->data;
+
+		padpos = ath9k_cmn_padpos(hdr->frame_control);
+		padsize = padpos & 3;
+		if (padsize && skb->len > padpos) {
+			if (skb_headroom(skb) < padsize) {
+				dev_kfree_skb_any(skb);
+				goto next;
+			}
+			skb_push(skb, padsize);
+			memmove(skb->data, skb->data + padsize, padpos);
+		}
+
+		tx_slot = ath9k_htc_tx_get_slot(priv);
+		if (tx_slot < 0) {
+			ath_dbg(common, ATH_DBG_XMIT, "No free CAB slot\n");
+			dev_kfree_skb_any(skb);
+			goto next;
+		}
+
+		ret = ath9k_htc_tx_start(priv, skb, tx_slot, true);
+		if (ret != 0) {
+			ath9k_htc_tx_clear_slot(priv, tx_slot);
+			dev_kfree_skb_any(skb);
+
+			ath_dbg(common, ATH_DBG_XMIT,
+				"Failed to send CAB frame\n");
+		} else {
+			spin_lock_bh(&priv->tx.tx_lock);
+			priv->tx.queued_cnt++;
+			spin_unlock_bh(&priv->tx.tx_lock);
+		}
+	next:
+		skb = ieee80211_get_buffered_bc(priv->hw, vif);
+	}
+
+	spin_unlock_bh(&priv->beacon_lock);
+}
+
+static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv,
+				  int slot)
+{
+	struct ath_common *common = ath9k_hw_common(priv->ah);
+	struct ieee80211_vif *vif;
+	struct ath9k_htc_vif *avp;
+	struct tx_beacon_header beacon_hdr;
+	struct ath9k_htc_tx_ctl *tx_ctl;
+	struct ieee80211_tx_info *info;
+	struct ieee80211_mgmt *mgmt;
+	struct sk_buff *beacon;
+	u8 *tx_fhdr;
+	int ret;
+
+	memset(&beacon_hdr, 0, sizeof(struct tx_beacon_header));
+
+	spin_lock_bh(&priv->beacon_lock);
+
+	vif = priv->cur_beacon_conf.bslot[slot];
+	avp = (struct ath9k_htc_vif *)vif->drv_priv;
+
 	if (unlikely(priv->op_flags & OP_SCANNING)) {
 		spin_unlock_bh(&priv->beacon_lock);
 		return;
 	}
 
 	/* Get a new beacon */
-	beacon = ieee80211_beacon_get(priv->hw, priv->vif);
+	beacon = ieee80211_beacon_get(priv->hw, vif);
 	if (!beacon) {
 		spin_unlock_bh(&priv->beacon_lock);
 		return;
 	}
 
+	/*
+	 * Update the TSF adjust value here, the HW will
+	 * add this value for every beacon.
+	 */
+	mgmt = (struct ieee80211_mgmt *)beacon->data;
+	mgmt->u.beacon.timestamp = avp->tsfadjust;
+
 	info = IEEE80211_SKB_CB(beacon);
 	if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
 		struct ieee80211_hdr *hdr =
@@ -266,45 +396,149 @@
 		hdr->seq_ctrl |= cpu_to_le16(avp->seq_no);
 	}
 
-	tx_ctl.type = ATH9K_HTC_NORMAL;
+	tx_ctl = HTC_SKB_CB(beacon);
+	memset(tx_ctl, 0, sizeof(*tx_ctl));
+
+	tx_ctl->type = ATH9K_HTC_BEACON;
+	tx_ctl->epid = priv->beacon_ep;
+
 	beacon_hdr.vif_index = avp->index;
 	tx_fhdr = skb_push(beacon, sizeof(beacon_hdr));
 	memcpy(tx_fhdr, (u8 *) &beacon_hdr, sizeof(beacon_hdr));
 
-	htc_send(priv->htc, beacon, priv->beacon_ep, &tx_ctl);
+	ret = htc_send(priv->htc, beacon);
+	if (ret != 0) {
+		if (ret == -ENOMEM) {
+			ath_dbg(common, ATH_DBG_BSTUCK,
+				"Failed to send beacon, no free TX buffer\n");
+		}
+		dev_kfree_skb_any(beacon);
+	}
 
 	spin_unlock_bh(&priv->beacon_lock);
 }
 
-/* Currently, only for IBSS */
-void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv)
+static int ath9k_htc_choose_bslot(struct ath9k_htc_priv *priv,
+				  struct wmi_event_swba *swba)
 {
-	struct ath_hw *ah = priv->ah;
-	struct ath9k_tx_queue_info qi, qi_be;
-	int qnum = priv->hwq_map[WME_AC_BE];
+	struct ath_common *common = ath9k_hw_common(priv->ah);
+	u64 tsf;
+	u32 tsftu;
+	u16 intval;
+	int slot;
 
-	memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
-	memset(&qi_be, 0, sizeof(struct ath9k_tx_queue_info));
+	intval = priv->cur_beacon_conf.beacon_interval & ATH9K_BEACON_PERIOD;
 
-	ath9k_hw_get_txq_props(ah, qnum, &qi_be);
+	tsf = be64_to_cpu(swba->tsf);
+	tsftu = TSF_TO_TU(tsf >> 32, tsf);
+	slot = ((tsftu % intval) * ATH9K_HTC_MAX_BCN_VIF) / intval;
+	slot = ATH9K_HTC_MAX_BCN_VIF - slot - 1;
 
-	qi.tqi_aifs = qi_be.tqi_aifs;
-	/* For WIFI Beacon Distribution
-	 * Long slot time  : 2x cwmin
-	 * Short slot time : 4x cwmin
-	 */
-	if (ah->slottime == ATH9K_SLOT_TIME_20)
-		qi.tqi_cwmin = 2*qi_be.tqi_cwmin;
-	else
-		qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
-	qi.tqi_cwmax = qi_be.tqi_cwmax;
+	ath_dbg(common, ATH_DBG_BEACON,
+		"Choose slot: %d, tsf: %llu, tsftu: %u, intval: %u\n",
+		slot, tsf, tsftu, intval);
 
-	if (!ath9k_hw_set_txq_props(ah, priv->beaconq, &qi)) {
-		ath_err(ath9k_hw_common(ah),
-			"Unable to update beacon queue %u!\n", qnum);
-	} else {
-		ath9k_hw_resettxqueue(ah, priv->beaconq);
+	return slot;
+}
+
+void ath9k_htc_swba(struct ath9k_htc_priv *priv,
+		    struct wmi_event_swba *swba)
+{
+	struct ath_common *common = ath9k_hw_common(priv->ah);
+	int slot;
+
+	if (swba->beacon_pending != 0) {
+		priv->cur_beacon_conf.bmiss_cnt++;
+		if (priv->cur_beacon_conf.bmiss_cnt > BSTUCK_THRESHOLD) {
+			ath_dbg(common, ATH_DBG_BSTUCK,
+				"Beacon stuck, HW reset\n");
+			ieee80211_queue_work(priv->hw,
+					     &priv->fatal_work);
+		}
+		return;
 	}
+
+	if (priv->cur_beacon_conf.bmiss_cnt) {
+		ath_dbg(common, ATH_DBG_BSTUCK,
+			"Resuming beacon xmit after %u misses\n",
+			priv->cur_beacon_conf.bmiss_cnt);
+		priv->cur_beacon_conf.bmiss_cnt = 0;
+	}
+
+	slot = ath9k_htc_choose_bslot(priv, swba);
+	spin_lock_bh(&priv->beacon_lock);
+	if (priv->cur_beacon_conf.bslot[slot] == NULL) {
+		spin_unlock_bh(&priv->beacon_lock);
+		return;
+	}
+	spin_unlock_bh(&priv->beacon_lock);
+
+	ath9k_htc_send_buffered(priv, slot);
+	ath9k_htc_send_beacon(priv, slot);
+}
+
+void ath9k_htc_assign_bslot(struct ath9k_htc_priv *priv,
+			    struct ieee80211_vif *vif)
+{
+	struct ath_common *common = ath9k_hw_common(priv->ah);
+	struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv;
+	int i = 0;
+
+	spin_lock_bh(&priv->beacon_lock);
+	for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) {
+		if (priv->cur_beacon_conf.bslot[i] == NULL) {
+			avp->bslot = i;
+			break;
+		}
+	}
+
+	priv->cur_beacon_conf.bslot[avp->bslot] = vif;
+	spin_unlock_bh(&priv->beacon_lock);
+
+	ath_dbg(common, ATH_DBG_CONFIG,
+		"Added interface at beacon slot: %d\n", avp->bslot);
+}
+
+void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv,
+			    struct ieee80211_vif *vif)
+{
+	struct ath_common *common = ath9k_hw_common(priv->ah);
+	struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv;
+
+	spin_lock_bh(&priv->beacon_lock);
+	priv->cur_beacon_conf.bslot[avp->bslot] = NULL;
+	spin_unlock_bh(&priv->beacon_lock);
+
+	ath_dbg(common, ATH_DBG_CONFIG,
+		"Removed interface at beacon slot: %d\n", avp->bslot);
+}
+
+/*
+ * Calculate the TSF adjustment value for all slots
+ * other than zero.
+ */
+void ath9k_htc_set_tsfadjust(struct ath9k_htc_priv *priv,
+			     struct ieee80211_vif *vif)
+{
+	struct ath_common *common = ath9k_hw_common(priv->ah);
+	struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv;
+	struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf;
+	u64 tsfadjust;
+
+	if (avp->bslot == 0)
+		return;
+
+	/*
+	 * The beacon interval cannot be different for multi-AP mode,
+	 * and we reach here only for VIF slots greater than zero,
+	 * so beacon_interval is guaranteed to be set in cur_conf.
+	 */
+	tsfadjust = cur_conf->beacon_interval * avp->bslot / ATH9K_HTC_MAX_BCN_VIF;
+	avp->tsfadjust = cpu_to_le64(TU_TO_USEC(tsfadjust));
+
+	ath_dbg(common, ATH_DBG_CONFIG,
+		"tsfadjust is: %llu for bslot: %d\n",
+		(unsigned long long)tsfadjust, avp->bslot);
 }
 
 static void ath9k_htc_beacon_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
new file mode 100644
index 0000000..eca7774
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
@@ -0,0 +1,505 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "htc.h"
+
+static int ath9k_debugfs_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t read_file_tgt_int_stats(struct file *file, char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	struct ath9k_htc_priv *priv = file->private_data;
+	struct ath9k_htc_target_int_stats cmd_rsp;
+	char buf[512];
+	unsigned int len = 0;
+	int ret = 0;
+
+	memset(&cmd_rsp, 0, sizeof(cmd_rsp));
+
+	WMI_CMD(WMI_INT_STATS_CMDID);
+	if (ret)
+		return -EINVAL;
+
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "RX",
+			be32_to_cpu(cmd_rsp.rx));
+
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "RXORN",
+			be32_to_cpu(cmd_rsp.rxorn));
+
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "RXEOL",
+			be32_to_cpu(cmd_rsp.rxeol));
+
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "TXURN",
+			be32_to_cpu(cmd_rsp.txurn));
+
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "TXTO",
+			be32_to_cpu(cmd_rsp.txto));
+
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "CST",
+			be32_to_cpu(cmd_rsp.cst));
+
+	if (len > sizeof(buf))
+		len = sizeof(buf);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_tgt_int_stats = {
+	.read = read_file_tgt_int_stats,
+	.open = ath9k_debugfs_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+static ssize_t read_file_tgt_tx_stats(struct file *file, char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	struct ath9k_htc_priv *priv = file->private_data;
+	struct ath9k_htc_target_tx_stats cmd_rsp;
+	char buf[512];
+	unsigned int len = 0;
+	int ret = 0;
+
+	memset(&cmd_rsp, 0, sizeof(cmd_rsp));
+
+	WMI_CMD(WMI_TX_STATS_CMDID);
+	if (ret)
+		return -EINVAL;
+
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "Xretries",
+			be32_to_cpu(cmd_rsp.xretries));
+
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "FifoErr",
+			be32_to_cpu(cmd_rsp.fifoerr));
+
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "Filtered",
+			be32_to_cpu(cmd_rsp.filtered));
+
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "TimerExp",
+			be32_to_cpu(cmd_rsp.timer_exp));
+
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "ShortRetries",
+			be32_to_cpu(cmd_rsp.shortretries));
+
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "LongRetries",
+			be32_to_cpu(cmd_rsp.longretries));
+
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "QueueNull",
+			be32_to_cpu(cmd_rsp.qnull));
+
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "EncapFail",
+			be32_to_cpu(cmd_rsp.encap_fail));
+
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "NoBuf",
+			be32_to_cpu(cmd_rsp.nobuf));
+
+	if (len > sizeof(buf))
+		len = sizeof(buf);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_tgt_tx_stats = {
+	.read = read_file_tgt_tx_stats,
+	.open = ath9k_debugfs_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+static ssize_t read_file_tgt_rx_stats(struct file *file, char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	struct ath9k_htc_priv *priv = file->private_data;
+	struct ath9k_htc_target_rx_stats cmd_rsp;
+	char buf[512];
+	unsigned int len = 0;
+	int ret = 0;
+
+	memset(&cmd_rsp, 0, sizeof(cmd_rsp));
+
+	WMI_CMD(WMI_RX_STATS_CMDID);
+	if (ret)
+		return -EINVAL;
+
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "NoBuf",
+			be32_to_cpu(cmd_rsp.nobuf));
+
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "HostSend",
+			be32_to_cpu(cmd_rsp.host_send));
+
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "HostDone",
+			be32_to_cpu(cmd_rsp.host_done));
+
+	if (len > sizeof(buf))
+		len = sizeof(buf);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_tgt_rx_stats = {
+	.read = read_file_tgt_rx_stats,
+	.open = ath9k_debugfs_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
+			      size_t count, loff_t *ppos)
+{
+	struct ath9k_htc_priv *priv = file->private_data;
+	char buf[512];
+	unsigned int len = 0;
+
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "Buffers queued",
+			priv->debug.tx_stats.buf_queued);
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "Buffers completed",
+			priv->debug.tx_stats.buf_completed);
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "SKBs queued",
+			priv->debug.tx_stats.skb_queued);
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "SKBs success",
+			priv->debug.tx_stats.skb_success);
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "SKBs failed",
+			priv->debug.tx_stats.skb_failed);
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "CAB queued",
+			priv->debug.tx_stats.cab_queued);
+
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "BE queued",
+			priv->debug.tx_stats.queue_stats[WME_AC_BE]);
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "BK queued",
+			priv->debug.tx_stats.queue_stats[WME_AC_BK]);
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "VI queued",
+			priv->debug.tx_stats.queue_stats[WME_AC_VI]);
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "VO queued",
+			priv->debug.tx_stats.queue_stats[WME_AC_VO]);
+
+	if (len > sizeof(buf))
+		len = sizeof(buf);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_xmit = {
+	.read = read_file_xmit,
+	.open = ath9k_debugfs_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv,
+			   struct ath_htc_rx_status *rxs)
+{
+#define RX_PHY_ERR_INC(c) priv->debug.rx_stats.err_phy_stats[c]++
+
+	if (rxs->rs_status & ATH9K_RXERR_CRC)
+		priv->debug.rx_stats.err_crc++;
+	if (rxs->rs_status & ATH9K_RXERR_DECRYPT)
+		priv->debug.rx_stats.err_decrypt_crc++;
+	if (rxs->rs_status & ATH9K_RXERR_MIC)
+		priv->debug.rx_stats.err_mic++;
+	if (rxs->rs_status & ATH9K_RX_DELIM_CRC_PRE)
+		priv->debug.rx_stats.err_pre_delim++;
+	if (rxs->rs_status & ATH9K_RX_DELIM_CRC_POST)
+		priv->debug.rx_stats.err_post_delim++;
+	if (rxs->rs_status & ATH9K_RX_DECRYPT_BUSY)
+		priv->debug.rx_stats.err_decrypt_busy++;
+
+	if (rxs->rs_status & ATH9K_RXERR_PHY) {
+		priv->debug.rx_stats.err_phy++;
+		if (rxs->rs_phyerr < ATH9K_PHYERR_MAX)
+			RX_PHY_ERR_INC(rxs->rs_phyerr);
+	}
+
+#undef RX_PHY_ERR_INC
+}
+
+static ssize_t read_file_recv(struct file *file, char __user *user_buf,
+			      size_t count, loff_t *ppos)
+{
+#define PHY_ERR(s, p)							\
+	len += snprintf(buf + len, size - len, "%20s : %10u\n", s,	\
+			priv->debug.rx_stats.err_phy_stats[p]);
+
+	struct ath9k_htc_priv *priv = file->private_data;
+	char *buf;
+	unsigned int len = 0, size = 1500;
+	ssize_t retval = 0;
+
+	buf = kzalloc(size, GFP_KERNEL);
+	if (buf == NULL)
+		return -ENOMEM;
+
+	len += snprintf(buf + len, size - len,
+			"%20s : %10u\n", "SKBs allocated",
+			priv->debug.rx_stats.skb_allocated);
+	len += snprintf(buf + len, size - len,
+			"%20s : %10u\n", "SKBs completed",
+			priv->debug.rx_stats.skb_completed);
+	len += snprintf(buf + len, size - len,
+			"%20s : %10u\n", "SKBs Dropped",
+			priv->debug.rx_stats.skb_dropped);
+
+	len += snprintf(buf + len, size - len,
+			"%20s : %10u\n", "CRC ERR",
+			priv->debug.rx_stats.err_crc);
+	len += snprintf(buf + len, size - len,
+			"%20s : %10u\n", "DECRYPT CRC ERR",
+			priv->debug.rx_stats.err_decrypt_crc);
+	len += snprintf(buf + len, size - len,
+			"%20s : %10u\n", "MIC ERR",
+			priv->debug.rx_stats.err_mic);
+	len += snprintf(buf + len, size - len,
+			"%20s : %10u\n", "PRE-DELIM CRC ERR",
+			priv->debug.rx_stats.err_pre_delim);
+	len += snprintf(buf + len, size - len,
+			"%20s : %10u\n", "POST-DELIM CRC ERR",
+			priv->debug.rx_stats.err_post_delim);
+	len += snprintf(buf + len, size - len,
+			"%20s : %10u\n", "DECRYPT BUSY ERR",
+			priv->debug.rx_stats.err_decrypt_busy);
+	len += snprintf(buf + len, size - len,
+			"%20s : %10u\n", "TOTAL PHY ERR",
+			priv->debug.rx_stats.err_phy);
+
+
+	PHY_ERR("UNDERRUN", ATH9K_PHYERR_UNDERRUN);
+	PHY_ERR("TIMING", ATH9K_PHYERR_TIMING);
+	PHY_ERR("PARITY", ATH9K_PHYERR_PARITY);
+	PHY_ERR("RATE", ATH9K_PHYERR_RATE);
+	PHY_ERR("LENGTH", ATH9K_PHYERR_LENGTH);
+	PHY_ERR("RADAR", ATH9K_PHYERR_RADAR);
+	PHY_ERR("SERVICE", ATH9K_PHYERR_SERVICE);
+	PHY_ERR("TOR", ATH9K_PHYERR_TOR);
+	PHY_ERR("OFDM-TIMING", ATH9K_PHYERR_OFDM_TIMING);
+	PHY_ERR("OFDM-SIGNAL-PARITY", ATH9K_PHYERR_OFDM_SIGNAL_PARITY);
+	PHY_ERR("OFDM-RATE", ATH9K_PHYERR_OFDM_RATE_ILLEGAL);
+	PHY_ERR("OFDM-LENGTH", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL);
+	PHY_ERR("OFDM-POWER-DROP", ATH9K_PHYERR_OFDM_POWER_DROP);
+	PHY_ERR("OFDM-SERVICE", ATH9K_PHYERR_OFDM_SERVICE);
+	PHY_ERR("OFDM-RESTART", ATH9K_PHYERR_OFDM_RESTART);
+	PHY_ERR("FALSE-RADAR-EXT", ATH9K_PHYERR_FALSE_RADAR_EXT);
+	PHY_ERR("CCK-TIMING", ATH9K_PHYERR_CCK_TIMING);
+	PHY_ERR("CCK-HEADER-CRC", ATH9K_PHYERR_CCK_HEADER_CRC);
+	PHY_ERR("CCK-RATE", ATH9K_PHYERR_CCK_RATE_ILLEGAL);
+	PHY_ERR("CCK-SERVICE", ATH9K_PHYERR_CCK_SERVICE);
+	PHY_ERR("CCK-RESTART", ATH9K_PHYERR_CCK_RESTART);
+	PHY_ERR("CCK-LENGTH", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL);
+	PHY_ERR("CCK-POWER-DROP", ATH9K_PHYERR_CCK_POWER_DROP);
+	PHY_ERR("HT-CRC", ATH9K_PHYERR_HT_CRC_ERROR);
+	PHY_ERR("HT-LENGTH", ATH9K_PHYERR_HT_LENGTH_ILLEGAL);
+	PHY_ERR("HT-RATE", ATH9K_PHYERR_HT_RATE_ILLEGAL);
+
+	if (len > size)
+		len = size;
+
+	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+	kfree(buf);
+
+	return retval;
+
+#undef PHY_ERR
+}
+
+static const struct file_operations fops_recv = {
+	.read = read_file_recv,
+	.open = ath9k_debugfs_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+static ssize_t read_file_slot(struct file *file, char __user *user_buf,
+			      size_t count, loff_t *ppos)
+{
+	struct ath9k_htc_priv *priv = file->private_data;
+	char buf[512];
+	unsigned int len = 0;
+
+	spin_lock_bh(&priv->tx.tx_lock);
+
+	len += snprintf(buf + len, sizeof(buf) - len, "TX slot bitmap : ");
+
+	len += bitmap_scnprintf(buf + len, sizeof(buf) - len,
+			       priv->tx.tx_slot, MAX_TX_BUF_NUM);
+
+	len += snprintf(buf + len, sizeof(buf) - len, "\n");
+
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"Used slots     : %d\n",
+			bitmap_weight(priv->tx.tx_slot, MAX_TX_BUF_NUM));
+
+	spin_unlock_bh(&priv->tx.tx_lock);
+
+	if (len > sizeof(buf))
+		len = sizeof(buf);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_slot = {
+	.read = read_file_slot,
+	.open = ath9k_debugfs_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+static ssize_t read_file_queue(struct file *file, char __user *user_buf,
+			       size_t count, loff_t *ppos)
+{
+	struct ath9k_htc_priv *priv = file->private_data;
+	char buf[512];
+	unsigned int len = 0;
+
+	len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
+			"Mgmt endpoint", skb_queue_len(&priv->tx.mgmt_ep_queue));
+
+	len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
+			"Cab endpoint", skb_queue_len(&priv->tx.cab_ep_queue));
+
+	len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
+			"Data BE endpoint", skb_queue_len(&priv->tx.data_be_queue));
+
+	len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
+			"Data BK endpoint", skb_queue_len(&priv->tx.data_bk_queue));
+
+	len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
+			"Data VI endpoint", skb_queue_len(&priv->tx.data_vi_queue));
+
+	len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
+			"Data VO endpoint", skb_queue_len(&priv->tx.data_vo_queue));
+
+	len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
+			"Failed queue", skb_queue_len(&priv->tx.tx_failed));
+
+	spin_lock_bh(&priv->tx.tx_lock);
+	len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
+			"Queued count", priv->tx.queued_cnt);
+	spin_unlock_bh(&priv->tx.tx_lock);
+
+	if (len > sizeof(buf))
+		len = sizeof(buf);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+
+}
+
+static const struct file_operations fops_queue = {
+	.read = read_file_queue,
+	.open = ath9k_debugfs_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+static ssize_t read_file_debug(struct file *file, char __user *user_buf,
+			       size_t count, loff_t *ppos)
+{
+	struct ath9k_htc_priv *priv = file->private_data;
+	struct ath_common *common = ath9k_hw_common(priv->ah);
+	char buf[32];
+	unsigned int len;
+
+	len = sprintf(buf, "0x%08x\n", common->debug_mask);
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_debug(struct file *file, const char __user *user_buf,
+				size_t count, loff_t *ppos)
+{
+	struct ath9k_htc_priv *priv = file->private_data;
+	struct ath_common *common = ath9k_hw_common(priv->ah);
+	unsigned long mask;
+	char buf[32];
+	ssize_t len;
+
+	len = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, len))
+		return -EFAULT;
+
+	buf[len] = '\0';
+	if (strict_strtoul(buf, 0, &mask))
+		return -EINVAL;
+
+	common->debug_mask = mask;
+	return count;
+}
+
+static const struct file_operations fops_debug = {
+	.read = read_file_debug,
+	.write = write_file_debug,
+	.open = ath9k_debugfs_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+int ath9k_htc_init_debug(struct ath_hw *ah)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+
+	priv->debug.debugfs_phy = debugfs_create_dir(KBUILD_MODNAME,
+					     priv->hw->wiphy->debugfsdir);
+	if (!priv->debug.debugfs_phy)
+		return -ENOMEM;
+
+	debugfs_create_file("tgt_int_stats", S_IRUSR, priv->debug.debugfs_phy,
+				priv, &fops_tgt_int_stats);
+	debugfs_create_file("tgt_tx_stats", S_IRUSR, priv->debug.debugfs_phy,
+				priv, &fops_tgt_tx_stats);
+	debugfs_create_file("tgt_rx_stats", S_IRUSR, priv->debug.debugfs_phy,
+				priv, &fops_tgt_rx_stats);
+	debugfs_create_file("xmit", S_IRUSR, priv->debug.debugfs_phy,
+				priv, &fops_xmit);
+	debugfs_create_file("recv", S_IRUSR, priv->debug.debugfs_phy,
+				priv, &fops_recv);
+	debugfs_create_file("slot", S_IRUSR, priv->debug.debugfs_phy,
+				priv, &fops_slot);
+	debugfs_create_file("queue", S_IRUSR, priv->debug.debugfs_phy,
+				priv, &fops_queue);
+	debugfs_create_file("debug", S_IRUSR | S_IWUSR, priv->debug.debugfs_phy,
+				priv, &fops_debug);
+
+	return 0;
+}
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
index 7e630a8..dc0b33d 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
@@ -398,9 +398,9 @@
 
 	/* Start TX */
 	htc_start(priv->htc);
-	spin_lock_bh(&priv->tx_lock);
-	priv->tx_queues_stop = false;
-	spin_unlock_bh(&priv->tx_lock);
+	spin_lock_bh(&priv->tx.tx_lock);
+	priv->tx.flags &= ~ATH9K_HTC_OP_TX_QUEUES_STOP;
+	spin_unlock_bh(&priv->tx.tx_lock);
 	ieee80211_wake_queues(hw);
 
 	WMI_CMD(WMI_ENABLE_INTR_CMDID);
@@ -429,13 +429,15 @@
 
 	/* Stop TX */
 	ieee80211_stop_queues(hw);
-	htc_stop(priv->htc);
+	ath9k_htc_tx_drain(priv);
 	WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
-	skb_queue_purge(&priv->tx_queue);
 
 	/* Stop RX */
 	WMI_CMD(WMI_STOP_RECV_CMDID);
 
+	/* Clear the WMI event queue */
+	ath9k_wmi_event_drain(priv);
+
 	/*
 	 * The MIB counters have to be disabled here,
 	 * since the target doesn't do it.
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index 8303b34..06e043b 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -140,7 +140,6 @@
 
 static void ath9k_deinit_priv(struct ath9k_htc_priv *priv)
 {
-	ath9k_htc_exit_debug(priv->ah);
 	ath9k_hw_deinit(priv->ah);
 	kfree(priv->ah);
 	priv->ah = NULL;
@@ -643,7 +642,7 @@
 {
 	struct ath_hw *ah = NULL;
 	struct ath_common *common;
-	int ret = 0, csz = 0;
+	int i, ret = 0, csz = 0;
 
 	priv->op_flags |= OP_INVALID;
 
@@ -671,20 +670,19 @@
 	common->priv = priv;
 	common->debug_mask = ath9k_debug;
 
-	spin_lock_init(&priv->wmi->wmi_lock);
 	spin_lock_init(&priv->beacon_lock);
-	spin_lock_init(&priv->tx_lock);
+	spin_lock_init(&priv->tx.tx_lock);
 	mutex_init(&priv->mutex);
 	mutex_init(&priv->htc_pm_lock);
-	tasklet_init(&priv->swba_tasklet, ath9k_swba_tasklet,
-		     (unsigned long)priv);
 	tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet,
 		     (unsigned long)priv);
-	tasklet_init(&priv->tx_tasklet, ath9k_tx_tasklet,
+	tasklet_init(&priv->tx_failed_tasklet, ath9k_tx_failed_tasklet,
 		     (unsigned long)priv);
 	INIT_DELAYED_WORK(&priv->ani_work, ath9k_htc_ani_work);
 	INIT_WORK(&priv->ps_work, ath9k_ps_work);
 	INIT_WORK(&priv->fatal_work, ath9k_fatal_work);
+	setup_timer(&priv->tx.cleanup_timer, ath9k_htc_tx_cleanup_timer,
+		    (unsigned long)priv);
 
 	/*
 	 * Cache line size is used to size and align various
@@ -701,16 +699,13 @@
 		goto err_hw;
 	}
 
-	ret = ath9k_htc_init_debug(ah);
-	if (ret) {
-		ath_err(common, "Unable to create debugfs files\n");
-		goto err_debug;
-	}
-
 	ret = ath9k_init_queues(priv);
 	if (ret)
 		goto err_queues;
 
+	for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++)
+		priv->cur_beacon_conf.bslot[i] = NULL;
+
 	ath9k_init_crypto(priv);
 	ath9k_init_channels_rates(priv);
 	ath9k_init_misc(priv);
@@ -723,8 +718,6 @@
 	return 0;
 
 err_queues:
-	ath9k_htc_exit_debug(ah);
-err_debug:
 	ath9k_hw_deinit(ah);
 err_hw:
 
@@ -745,11 +738,15 @@
 		IEEE80211_HW_HAS_RATE_CONTROL |
 		IEEE80211_HW_RX_INCLUDES_FCS |
 		IEEE80211_HW_SUPPORTS_PS |
-		IEEE80211_HW_PS_NULLFUNC_STACK;
+		IEEE80211_HW_PS_NULLFUNC_STACK |
+		IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
 
 	hw->wiphy->interface_modes =
 		BIT(NL80211_IFTYPE_STATION) |
-		BIT(NL80211_IFTYPE_ADHOC);
+		BIT(NL80211_IFTYPE_ADHOC) |
+		BIT(NL80211_IFTYPE_AP) |
+		BIT(NL80211_IFTYPE_P2P_GO) |
+		BIT(NL80211_IFTYPE_P2P_CLIENT);
 
 	hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
 
@@ -782,6 +779,32 @@
 	SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
 }
 
+static int ath9k_init_firmware_version(struct ath9k_htc_priv *priv)
+{
+	struct ieee80211_hw *hw = priv->hw;
+	struct wmi_fw_version cmd_rsp;
+	int ret;
+
+	memset(&cmd_rsp, 0, sizeof(cmd_rsp));
+
+	WMI_CMD(WMI_GET_FW_VERSION);
+	if (ret)
+		return -EINVAL;
+
+	priv->fw_version_major = be16_to_cpu(cmd_rsp.major);
+	priv->fw_version_minor = be16_to_cpu(cmd_rsp.minor);
+
+	snprintf(hw->wiphy->fw_version, ETHTOOL_BUSINFO_LEN, "%d.%d",
+		 priv->fw_version_major,
+		 priv->fw_version_minor);
+
+	dev_info(priv->dev, "ath9k_htc: FW Version: %d.%d\n",
+		 priv->fw_version_major,
+		 priv->fw_version_minor);
+
+	return 0;
+}
+
 static int ath9k_init_device(struct ath9k_htc_priv *priv,
 			     u16 devid, char *product, u32 drv_info)
 {
@@ -801,6 +824,10 @@
 	common = ath9k_hw_common(ah);
 	ath9k_set_hw_capab(priv, hw);
 
+	error = ath9k_init_firmware_version(priv);
+	if (error != 0)
+		goto err_fw;
+
 	/* Initialize regulatory */
 	error = ath_regd_init(&common->regulatory, priv->hw->wiphy,
 			      ath9k_reg_notifier);
@@ -831,6 +858,12 @@
 			goto err_world;
 	}
 
+	error = ath9k_htc_init_debug(priv->ah);
+	if (error) {
+		ath_err(common, "Unable to create debugfs files\n");
+		goto err_world;
+	}
+
 	ath_dbg(common, ATH_DBG_CONFIG,
 		"WMI:%d, BCN:%d, CAB:%d, UAPSD:%d, MGMT:%d, "
 		"BE:%d, BK:%d, VI:%d, VO:%d\n",
@@ -861,6 +894,8 @@
 err_tx:
 	/* Nothing */
 err_regd:
+	/* Nothing */
+err_fw:
 	ath9k_deinit_priv(priv);
 err_init:
 	return error;
@@ -949,38 +984,20 @@
 
 static int __init ath9k_htc_init(void)
 {
-	int error;
-
-	error = ath9k_htc_debug_create_root();
-	if (error < 0) {
-		printk(KERN_ERR
-			"ath9k_htc: Unable to create debugfs root: %d\n",
-			error);
-		goto err_dbg;
-	}
-
-	error = ath9k_hif_usb_init();
-	if (error < 0) {
+	if (ath9k_hif_usb_init() < 0) {
 		printk(KERN_ERR
 			"ath9k_htc: No USB devices found,"
 			" driver not installed.\n");
-		error = -ENODEV;
-		goto err_usb;
+		return -ENODEV;
 	}
 
 	return 0;
-
-err_usb:
-	ath9k_htc_debug_remove_root();
-err_dbg:
-	return error;
 }
 module_init(ath9k_htc_init);
 
 static void __exit ath9k_htc_exit(void)
 {
 	ath9k_hif_usb_exit();
-	ath9k_htc_debug_remove_root();
 	printk(KERN_INFO "ath9k_htc: Driver unloaded\n");
 }
 module_exit(ath9k_htc_exit);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index db8c0c0..4de3864 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -16,10 +16,6 @@
 
 #include "htc.h"
 
-#ifdef CONFIG_ATH9K_HTC_DEBUGFS
-static struct dentry *ath9k_debugfs_root;
-#endif
-
 /*************/
 /* Utilities */
 /*************/
@@ -197,11 +193,16 @@
 
 	ath9k_htc_stop_ani(priv);
 	ieee80211_stop_queues(priv->hw);
-	htc_stop(priv->htc);
+
+	del_timer_sync(&priv->tx.cleanup_timer);
+	ath9k_htc_tx_drain(priv);
+
 	WMI_CMD(WMI_DISABLE_INTR_CMDID);
 	WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
 	WMI_CMD(WMI_STOP_RECV_CMDID);
 
+	ath9k_wmi_event_drain(priv);
+
 	caldata = &priv->caldata;
 	ret = ath9k_hw_reset(ah, ah->curchan, caldata, false);
 	if (ret) {
@@ -225,6 +226,9 @@
 	ath9k_htc_vif_reconfig(priv);
 	ieee80211_wake_queues(priv->hw);
 
+	mod_timer(&priv->tx.cleanup_timer,
+		  jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL));
+
 	ath9k_htc_ps_restore(priv);
 	mutex_unlock(&priv->mutex);
 }
@@ -250,11 +254,16 @@
 	fastcc = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL);
 
 	ath9k_htc_ps_wakeup(priv);
-	htc_stop(priv->htc);
+
+	del_timer_sync(&priv->tx.cleanup_timer);
+	ath9k_htc_tx_drain(priv);
+
 	WMI_CMD(WMI_DISABLE_INTR_CMDID);
 	WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
 	WMI_CMD(WMI_STOP_RECV_CMDID);
 
+	ath9k_wmi_event_drain(priv);
+
 	ath_dbg(common, ATH_DBG_CONFIG,
 		"(%u MHz) -> (%u MHz), HT: %d, HT40: %d fastcc: %d\n",
 		priv->ah->curchan->channel,
@@ -263,6 +272,7 @@
 
 	if (!fastcc)
 		caldata = &priv->caldata;
+
 	ret = ath9k_hw_reset(ah, hchan, caldata, fastcc);
 	if (ret) {
 		ath_err(common,
@@ -296,6 +306,9 @@
 	    !(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL))
 		ath9k_htc_vif_reconfig(priv);
 
+	mod_timer(&priv->tx.cleanup_timer,
+		  jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL));
+
 err:
 	ath9k_htc_ps_restore(priv);
 	return ret;
@@ -349,7 +362,7 @@
 	memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
 	memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN);
 
-	hvif.opmode = cpu_to_be32(HTC_M_MONITOR);
+	hvif.opmode = HTC_M_MONITOR;
 	hvif.index = ffz(priv->vif_slot);
 
 	WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif);
@@ -382,7 +395,7 @@
 	tsta.is_vif_sta = 1;
 	tsta.sta_index = sta_idx;
 	tsta.vif_index = hvif.index;
-	tsta.maxampdu = 0xffff;
+	tsta.maxampdu = cpu_to_be16(0xffff);
 
 	WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta);
 	if (ret) {
@@ -463,9 +476,7 @@
 		ista = (struct ath9k_htc_sta *) sta->drv_priv;
 		memcpy(&tsta.macaddr, sta->addr, ETH_ALEN);
 		memcpy(&tsta.bssid, common->curbssid, ETH_ALEN);
-		tsta.associd = common->curaid;
 		tsta.is_vif_sta = 0;
-		tsta.valid = true;
 		ista->index = sta_idx;
 	} else {
 		memcpy(&tsta.macaddr, vif->addr, ETH_ALEN);
@@ -474,7 +485,7 @@
 
 	tsta.sta_index = sta_idx;
 	tsta.vif_index = avp->index;
-	tsta.maxampdu = 0xffff;
+	tsta.maxampdu = cpu_to_be16(0xffff);
 	if (sta && sta->ht_cap.ht_supported)
 		tsta.flags = cpu_to_be16(ATH_HTC_STA_HT);
 
@@ -709,218 +720,13 @@
 			(aggr.aggr_enable) ? "Starting" : "Stopping",
 			sta->addr, tid);
 
-	spin_lock_bh(&priv->tx_lock);
+	spin_lock_bh(&priv->tx.tx_lock);
 	ista->tid_state[tid] = (aggr.aggr_enable && !ret) ? AGGR_START : AGGR_STOP;
-	spin_unlock_bh(&priv->tx_lock);
+	spin_unlock_bh(&priv->tx.tx_lock);
 
 	return ret;
 }
 
-/*********/
-/* DEBUG */
-/*********/
-
-#ifdef CONFIG_ATH9K_HTC_DEBUGFS
-
-static int ath9k_debugfs_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
-static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf,
-				   size_t count, loff_t *ppos)
-{
-	struct ath9k_htc_priv *priv = file->private_data;
-	struct ath9k_htc_target_stats cmd_rsp;
-	char buf[512];
-	unsigned int len = 0;
-	int ret = 0;
-
-	memset(&cmd_rsp, 0, sizeof(cmd_rsp));
-
-	WMI_CMD(WMI_TGT_STATS_CMDID);
-	if (ret)
-		return -EINVAL;
-
-
-	len += snprintf(buf + len, sizeof(buf) - len,
-			"%19s : %10u\n", "TX Short Retries",
-			be32_to_cpu(cmd_rsp.tx_shortretry));
-	len += snprintf(buf + len, sizeof(buf) - len,
-			"%19s : %10u\n", "TX Long Retries",
-			be32_to_cpu(cmd_rsp.tx_longretry));
-	len += snprintf(buf + len, sizeof(buf) - len,
-			"%19s : %10u\n", "TX Xretries",
-			be32_to_cpu(cmd_rsp.tx_xretries));
-	len += snprintf(buf + len, sizeof(buf) - len,
-			"%19s : %10u\n", "TX Unaggr. Xretries",
-			be32_to_cpu(cmd_rsp.ht_txunaggr_xretry));
-	len += snprintf(buf + len, sizeof(buf) - len,
-			"%19s : %10u\n", "TX Xretries (HT)",
-			be32_to_cpu(cmd_rsp.ht_tx_xretries));
-	len += snprintf(buf + len, sizeof(buf) - len,
-			"%19s : %10u\n", "TX Rate", priv->debug.txrate);
-
-	if (len > sizeof(buf))
-		len = sizeof(buf);
-
-	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
-}
-
-static const struct file_operations fops_tgt_stats = {
-	.read = read_file_tgt_stats,
-	.open = ath9k_debugfs_open,
-	.owner = THIS_MODULE,
-	.llseek = default_llseek,
-};
-
-static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
-			      size_t count, loff_t *ppos)
-{
-	struct ath9k_htc_priv *priv = file->private_data;
-	char buf[512];
-	unsigned int len = 0;
-
-	len += snprintf(buf + len, sizeof(buf) - len,
-			"%20s : %10u\n", "Buffers queued",
-			priv->debug.tx_stats.buf_queued);
-	len += snprintf(buf + len, sizeof(buf) - len,
-			"%20s : %10u\n", "Buffers completed",
-			priv->debug.tx_stats.buf_completed);
-	len += snprintf(buf + len, sizeof(buf) - len,
-			"%20s : %10u\n", "SKBs queued",
-			priv->debug.tx_stats.skb_queued);
-	len += snprintf(buf + len, sizeof(buf) - len,
-			"%20s : %10u\n", "SKBs completed",
-			priv->debug.tx_stats.skb_completed);
-	len += snprintf(buf + len, sizeof(buf) - len,
-			"%20s : %10u\n", "SKBs dropped",
-			priv->debug.tx_stats.skb_dropped);
-
-	len += snprintf(buf + len, sizeof(buf) - len,
-			"%20s : %10u\n", "BE queued",
-			priv->debug.tx_stats.queue_stats[WME_AC_BE]);
-	len += snprintf(buf + len, sizeof(buf) - len,
-			"%20s : %10u\n", "BK queued",
-			priv->debug.tx_stats.queue_stats[WME_AC_BK]);
-	len += snprintf(buf + len, sizeof(buf) - len,
-			"%20s : %10u\n", "VI queued",
-			priv->debug.tx_stats.queue_stats[WME_AC_VI]);
-	len += snprintf(buf + len, sizeof(buf) - len,
-			"%20s : %10u\n", "VO queued",
-			priv->debug.tx_stats.queue_stats[WME_AC_VO]);
-
-	if (len > sizeof(buf))
-		len = sizeof(buf);
-
-	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
-}
-
-static const struct file_operations fops_xmit = {
-	.read = read_file_xmit,
-	.open = ath9k_debugfs_open,
-	.owner = THIS_MODULE,
-	.llseek = default_llseek,
-};
-
-static ssize_t read_file_recv(struct file *file, char __user *user_buf,
-			      size_t count, loff_t *ppos)
-{
-	struct ath9k_htc_priv *priv = file->private_data;
-	char buf[512];
-	unsigned int len = 0;
-
-	len += snprintf(buf + len, sizeof(buf) - len,
-			"%20s : %10u\n", "SKBs allocated",
-			priv->debug.rx_stats.skb_allocated);
-	len += snprintf(buf + len, sizeof(buf) - len,
-			"%20s : %10u\n", "SKBs completed",
-			priv->debug.rx_stats.skb_completed);
-	len += snprintf(buf + len, sizeof(buf) - len,
-			"%20s : %10u\n", "SKBs Dropped",
-			priv->debug.rx_stats.skb_dropped);
-
-	if (len > sizeof(buf))
-		len = sizeof(buf);
-
-	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
-}
-
-static const struct file_operations fops_recv = {
-	.read = read_file_recv,
-	.open = ath9k_debugfs_open,
-	.owner = THIS_MODULE,
-	.llseek = default_llseek,
-};
-
-int ath9k_htc_init_debug(struct ath_hw *ah)
-{
-	struct ath_common *common = ath9k_hw_common(ah);
-	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
-
-	if (!ath9k_debugfs_root)
-		return -ENOENT;
-
-	priv->debug.debugfs_phy = debugfs_create_dir(wiphy_name(priv->hw->wiphy),
-						     ath9k_debugfs_root);
-	if (!priv->debug.debugfs_phy)
-		goto err;
-
-	priv->debug.debugfs_tgt_stats = debugfs_create_file("tgt_stats", S_IRUSR,
-						    priv->debug.debugfs_phy,
-						    priv, &fops_tgt_stats);
-	if (!priv->debug.debugfs_tgt_stats)
-		goto err;
-
-
-	priv->debug.debugfs_xmit = debugfs_create_file("xmit", S_IRUSR,
-						       priv->debug.debugfs_phy,
-						       priv, &fops_xmit);
-	if (!priv->debug.debugfs_xmit)
-		goto err;
-
-	priv->debug.debugfs_recv = debugfs_create_file("recv", S_IRUSR,
-						       priv->debug.debugfs_phy,
-						       priv, &fops_recv);
-	if (!priv->debug.debugfs_recv)
-		goto err;
-
-	return 0;
-
-err:
-	ath9k_htc_exit_debug(ah);
-	return -ENOMEM;
-}
-
-void ath9k_htc_exit_debug(struct ath_hw *ah)
-{
-	struct ath_common *common = ath9k_hw_common(ah);
-	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
-
-	debugfs_remove(priv->debug.debugfs_recv);
-	debugfs_remove(priv->debug.debugfs_xmit);
-	debugfs_remove(priv->debug.debugfs_tgt_stats);
-	debugfs_remove(priv->debug.debugfs_phy);
-}
-
-int ath9k_htc_debug_create_root(void)
-{
-	ath9k_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
-	if (!ath9k_debugfs_root)
-		return -ENOENT;
-
-	return 0;
-}
-
-void ath9k_htc_debug_remove_root(void)
-{
-	debugfs_remove(ath9k_debugfs_root);
-	ath9k_debugfs_root = NULL;
-}
-
-#endif /* CONFIG_ATH9K_HTC_DEBUGFS */
-
 /*******/
 /* ANI */
 /*******/
@@ -1040,7 +846,8 @@
 {
 	struct ieee80211_hdr *hdr;
 	struct ath9k_htc_priv *priv = hw->priv;
-	int padpos, padsize, ret;
+	struct ath_common *common = ath9k_hw_common(priv->ah);
+	int padpos, padsize, ret, slot;
 
 	hdr = (struct ieee80211_hdr *) skb->data;
 
@@ -1048,30 +855,32 @@
 	padpos = ath9k_cmn_padpos(hdr->frame_control);
 	padsize = padpos & 3;
 	if (padsize && skb->len > padpos) {
-		if (skb_headroom(skb) < padsize)
+		if (skb_headroom(skb) < padsize) {
+			ath_dbg(common, ATH_DBG_XMIT, "No room for padding\n");
 			goto fail_tx;
+		}
 		skb_push(skb, padsize);
 		memmove(skb->data, skb->data + padsize, padpos);
 	}
 
-	ret = ath9k_htc_tx_start(priv, skb);
-	if (ret != 0) {
-		if (ret == -ENOMEM) {
-			ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
-				"Stopping TX queues\n");
-			ieee80211_stop_queues(hw);
-			spin_lock_bh(&priv->tx_lock);
-			priv->tx_queues_stop = true;
-			spin_unlock_bh(&priv->tx_lock);
-		} else {
-			ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
-				"Tx failed\n");
-		}
+	slot = ath9k_htc_tx_get_slot(priv);
+	if (slot < 0) {
+		ath_dbg(common, ATH_DBG_XMIT, "No free TX slot\n");
 		goto fail_tx;
 	}
 
+	ret = ath9k_htc_tx_start(priv, skb, slot, false);
+	if (ret != 0) {
+		ath_dbg(common, ATH_DBG_XMIT, "Tx failed\n");
+		goto clear_slot;
+	}
+
+	ath9k_htc_check_stop_queues(priv);
+
 	return;
 
+clear_slot:
+	ath9k_htc_tx_clear_slot(priv, slot);
 fail_tx:
 	dev_kfree_skb_any(skb);
 }
@@ -1130,12 +939,15 @@
 	priv->op_flags &= ~OP_INVALID;
 	htc_start(priv->htc);
 
-	spin_lock_bh(&priv->tx_lock);
-	priv->tx_queues_stop = false;
-	spin_unlock_bh(&priv->tx_lock);
+	spin_lock_bh(&priv->tx.tx_lock);
+	priv->tx.flags &= ~ATH9K_HTC_OP_TX_QUEUES_STOP;
+	spin_unlock_bh(&priv->tx.tx_lock);
 
 	ieee80211_wake_queues(hw);
 
+	mod_timer(&priv->tx.cleanup_timer,
+		  jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL));
+
 	if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) {
 		ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
 					   AR_STOMP_LOW_WLAN_WGHT);
@@ -1164,16 +976,16 @@
 	}
 
 	ath9k_htc_ps_wakeup(priv);
-	htc_stop(priv->htc);
+
 	WMI_CMD(WMI_DISABLE_INTR_CMDID);
 	WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
 	WMI_CMD(WMI_STOP_RECV_CMDID);
 
-	tasklet_kill(&priv->swba_tasklet);
 	tasklet_kill(&priv->rx_tasklet);
-	tasklet_kill(&priv->tx_tasklet);
 
-	skb_queue_purge(&priv->tx_queue);
+	del_timer_sync(&priv->tx.cleanup_timer);
+	ath9k_htc_tx_drain(priv);
+	ath9k_wmi_event_drain(priv);
 
 	mutex_unlock(&priv->mutex);
 
@@ -1245,13 +1057,13 @@
 
 	switch (vif->type) {
 	case NL80211_IFTYPE_STATION:
-		hvif.opmode = cpu_to_be32(HTC_M_STA);
+		hvif.opmode = HTC_M_STA;
 		break;
 	case NL80211_IFTYPE_ADHOC:
-		hvif.opmode = cpu_to_be32(HTC_M_IBSS);
+		hvif.opmode = HTC_M_IBSS;
 		break;
 	case NL80211_IFTYPE_AP:
-		hvif.opmode = cpu_to_be32(HTC_M_HOSTAP);
+		hvif.opmode = HTC_M_HOSTAP;
 		break;
 	default:
 		ath_err(common,
@@ -1281,14 +1093,20 @@
 
 	priv->vif_slot |= (1 << avp->index);
 	priv->nvifs++;
-	priv->vif = vif;
 
 	INC_VIF(priv, vif->type);
+
+	if ((vif->type == NL80211_IFTYPE_AP) ||
+	    (vif->type == NL80211_IFTYPE_ADHOC))
+		ath9k_htc_assign_bslot(priv, vif);
+
 	ath9k_htc_set_opmode(priv);
 
 	if ((priv->ah->opmode == NL80211_IFTYPE_AP) &&
-	    !(priv->op_flags & OP_ANI_RUNNING))
+	    !(priv->op_flags & OP_ANI_RUNNING)) {
+		ath9k_hw_set_tsfadjust(priv->ah, 1);
 		ath9k_htc_start_ani(priv);
+	}
 
 	ath_dbg(common, ATH_DBG_CONFIG,
 		"Attach a VIF of type: %d at idx: %d\n", vif->type, avp->index);
@@ -1321,9 +1139,13 @@
 	priv->vif_slot &= ~(1 << avp->index);
 
 	ath9k_htc_remove_station(priv, vif, NULL);
-	priv->vif = NULL;
 
 	DEC_VIF(priv, vif->type);
+
+	if ((vif->type == NL80211_IFTYPE_AP) ||
+	    (vif->type == NL80211_IFTYPE_ADHOC))
+		ath9k_htc_remove_bslot(priv, vif);
+
 	ath9k_htc_set_opmode(priv);
 
 	/*
@@ -1493,10 +1315,13 @@
 				struct ieee80211_sta *sta)
 {
 	struct ath9k_htc_priv *priv = hw->priv;
+	struct ath9k_htc_sta *ista;
 	int ret;
 
 	mutex_lock(&priv->mutex);
 	ath9k_htc_ps_wakeup(priv);
+	ista = (struct ath9k_htc_sta *) sta->drv_priv;
+	htc_sta_drain(priv->htc, ista->index);
 	ret = ath9k_htc_remove_station(priv, vif, sta);
 	ath9k_htc_ps_restore(priv);
 	mutex_unlock(&priv->mutex);
@@ -1644,6 +1469,7 @@
 	if ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon) {
 		ath_dbg(common, ATH_DBG_CONFIG,
 			"Beacon enabled for BSS: %pM\n", bss_conf->bssid);
+		ath9k_htc_set_tsfadjust(priv, vif);
 		priv->op_flags |= OP_ENABLE_BEACON;
 		ath9k_htc_beacon_config(priv, vif);
 	}
@@ -1758,9 +1584,9 @@
 		break;
 	case IEEE80211_AMPDU_TX_OPERATIONAL:
 		ista = (struct ath9k_htc_sta *) sta->drv_priv;
-		spin_lock_bh(&priv->tx_lock);
+		spin_lock_bh(&priv->tx.tx_lock);
 		ista->tid_state[tid] = AGGR_OPERATIONAL;
-		spin_unlock_bh(&priv->tx_lock);
+		spin_unlock_bh(&priv->tx.tx_lock);
 		break;
 	default:
 		ath_err(ath9k_hw_common(priv->ah), "Unknown AMPDU action\n");
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
index 4a4f27b..723a3a9 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
@@ -53,6 +53,138 @@
 	}
 }
 
+void ath9k_htc_check_stop_queues(struct ath9k_htc_priv *priv)
+{
+	spin_lock_bh(&priv->tx.tx_lock);
+	priv->tx.queued_cnt++;
+	if ((priv->tx.queued_cnt >= ATH9K_HTC_TX_THRESHOLD) &&
+	    !(priv->tx.flags & ATH9K_HTC_OP_TX_QUEUES_STOP)) {
+		priv->tx.flags |= ATH9K_HTC_OP_TX_QUEUES_STOP;
+		ieee80211_stop_queues(priv->hw);
+	}
+	spin_unlock_bh(&priv->tx.tx_lock);
+}
+
+void ath9k_htc_check_wake_queues(struct ath9k_htc_priv *priv)
+{
+	spin_lock_bh(&priv->tx.tx_lock);
+	if ((priv->tx.queued_cnt < ATH9K_HTC_TX_THRESHOLD) &&
+	    (priv->tx.flags & ATH9K_HTC_OP_TX_QUEUES_STOP)) {
+		priv->tx.flags &= ~ATH9K_HTC_OP_TX_QUEUES_STOP;
+		ieee80211_wake_queues(priv->hw);
+	}
+	spin_unlock_bh(&priv->tx.tx_lock);
+}
+
+int ath9k_htc_tx_get_slot(struct ath9k_htc_priv *priv)
+{
+	int slot;
+
+	spin_lock_bh(&priv->tx.tx_lock);
+	slot = find_first_zero_bit(priv->tx.tx_slot, MAX_TX_BUF_NUM);
+	if (slot >= MAX_TX_BUF_NUM) {
+		spin_unlock_bh(&priv->tx.tx_lock);
+		return -ENOBUFS;
+	}
+	__set_bit(slot, priv->tx.tx_slot);
+	spin_unlock_bh(&priv->tx.tx_lock);
+
+	return slot;
+}
+
+void ath9k_htc_tx_clear_slot(struct ath9k_htc_priv *priv, int slot)
+{
+	spin_lock_bh(&priv->tx.tx_lock);
+	__clear_bit(slot, priv->tx.tx_slot);
+	spin_unlock_bh(&priv->tx.tx_lock);
+}
+
+static inline enum htc_endpoint_id get_htc_epid(struct ath9k_htc_priv *priv,
+						u16 qnum)
+{
+	enum htc_endpoint_id epid;
+
+	switch (qnum) {
+	case 0:
+		TX_QSTAT_INC(WME_AC_VO);
+		epid = priv->data_vo_ep;
+		break;
+	case 1:
+		TX_QSTAT_INC(WME_AC_VI);
+		epid = priv->data_vi_ep;
+		break;
+	case 2:
+		TX_QSTAT_INC(WME_AC_BE);
+		epid = priv->data_be_ep;
+		break;
+	case 3:
+	default:
+		TX_QSTAT_INC(WME_AC_BK);
+		epid = priv->data_bk_ep;
+		break;
+	}
+
+	return epid;
+}
+
+static inline struct sk_buff_head*
+get_htc_epid_queue(struct ath9k_htc_priv *priv, u8 epid)
+{
+	struct ath_common *common = ath9k_hw_common(priv->ah);
+	struct sk_buff_head *epid_queue = NULL;
+
+	if (epid == priv->mgmt_ep)
+		epid_queue = &priv->tx.mgmt_ep_queue;
+	else if (epid == priv->cab_ep)
+		epid_queue = &priv->tx.cab_ep_queue;
+	else if (epid == priv->data_be_ep)
+		epid_queue = &priv->tx.data_be_queue;
+	else if (epid == priv->data_bk_ep)
+		epid_queue = &priv->tx.data_bk_queue;
+	else if (epid == priv->data_vi_ep)
+		epid_queue = &priv->tx.data_vi_queue;
+	else if (epid == priv->data_vo_ep)
+		epid_queue = &priv->tx.data_vo_queue;
+	else
+		ath_err(common, "Invalid EPID: %d\n", epid);
+
+	return epid_queue;
+}
+
+/*
+ * Removes the driver header and returns the TX slot number
+ */
+static inline int strip_drv_header(struct ath9k_htc_priv *priv,
+				   struct sk_buff *skb)
+{
+	struct ath_common *common = ath9k_hw_common(priv->ah);
+	struct ath9k_htc_tx_ctl *tx_ctl;
+	int slot;
+
+	tx_ctl = HTC_SKB_CB(skb);
+
+	if (tx_ctl->epid == priv->mgmt_ep) {
+		struct tx_mgmt_hdr *tx_mhdr =
+			(struct tx_mgmt_hdr *)skb->data;
+		slot = tx_mhdr->cookie;
+		skb_pull(skb, sizeof(struct tx_mgmt_hdr));
+	} else if ((tx_ctl->epid == priv->data_bk_ep) ||
+		   (tx_ctl->epid == priv->data_be_ep) ||
+		   (tx_ctl->epid == priv->data_vi_ep) ||
+		   (tx_ctl->epid == priv->data_vo_ep) ||
+		   (tx_ctl->epid == priv->cab_ep)) {
+		struct tx_frame_hdr *tx_fhdr =
+			(struct tx_frame_hdr *)skb->data;
+		slot = tx_fhdr->cookie;
+		skb_pull(skb, sizeof(struct tx_frame_hdr));
+	} else {
+		ath_err(common, "Unsupported EPID: %d\n", tx_ctl->epid);
+		slot = -EINVAL;
+	}
+
+	return slot;
+}
+
 int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum,
 		       struct ath9k_tx_queue_info *qinfo)
 {
@@ -79,23 +211,140 @@
 	return error;
 }
 
-int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb)
+static void ath9k_htc_tx_mgmt(struct ath9k_htc_priv *priv,
+			      struct ath9k_htc_vif *avp,
+			      struct sk_buff *skb,
+			      u8 sta_idx, u8 vif_idx, u8 slot)
+{
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_mgmt *mgmt;
+	struct ieee80211_hdr *hdr;
+	struct tx_mgmt_hdr mgmt_hdr;
+	struct ath9k_htc_tx_ctl *tx_ctl;
+	u8 *tx_fhdr;
+
+	tx_ctl = HTC_SKB_CB(skb);
+	hdr = (struct ieee80211_hdr *) skb->data;
+
+	memset(tx_ctl, 0, sizeof(*tx_ctl));
+	memset(&mgmt_hdr, 0, sizeof(struct tx_mgmt_hdr));
+
+	/*
+	 * Set the TSF adjust value for probe response
+	 * frame also.
+	 */
+	if (avp && unlikely(ieee80211_is_probe_resp(hdr->frame_control))) {
+		mgmt = (struct ieee80211_mgmt *)skb->data;
+		mgmt->u.probe_resp.timestamp = avp->tsfadjust;
+	}
+
+	tx_ctl->type = ATH9K_HTC_MGMT;
+
+	mgmt_hdr.node_idx = sta_idx;
+	mgmt_hdr.vif_idx = vif_idx;
+	mgmt_hdr.tidno = 0;
+	mgmt_hdr.flags = 0;
+	mgmt_hdr.cookie = slot;
+
+	mgmt_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb);
+	if (mgmt_hdr.key_type == ATH9K_KEY_TYPE_CLEAR)
+		mgmt_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID;
+	else
+		mgmt_hdr.keyix = tx_info->control.hw_key->hw_key_idx;
+
+	tx_fhdr = skb_push(skb, sizeof(mgmt_hdr));
+	memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr));
+	tx_ctl->epid = priv->mgmt_ep;
+}
+
+static void ath9k_htc_tx_data(struct ath9k_htc_priv *priv,
+			      struct ieee80211_vif *vif,
+			      struct sk_buff *skb,
+			      u8 sta_idx, u8 vif_idx, u8 slot,
+			      bool is_cab)
+{
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_hdr *hdr;
+	struct ath9k_htc_tx_ctl *tx_ctl;
+	struct tx_frame_hdr tx_hdr;
+	u32 flags = 0;
+	u8 *qc, *tx_fhdr;
+	u16 qnum;
+
+	tx_ctl = HTC_SKB_CB(skb);
+	hdr = (struct ieee80211_hdr *) skb->data;
+
+	memset(tx_ctl, 0, sizeof(*tx_ctl));
+	memset(&tx_hdr, 0, sizeof(struct tx_frame_hdr));
+
+	tx_hdr.node_idx = sta_idx;
+	tx_hdr.vif_idx = vif_idx;
+	tx_hdr.cookie = slot;
+
+	/*
+	 * This is a bit redundant but it helps to get
+	 * the per-packet index quickly when draining the
+	 * TX queue in the HIF layer. Otherwise we would
+	 * have to parse the packet contents ...
+	 */
+	tx_ctl->sta_idx = sta_idx;
+
+	if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
+		tx_ctl->type = ATH9K_HTC_AMPDU;
+		tx_hdr.data_type = ATH9K_HTC_AMPDU;
+	} else {
+		tx_ctl->type = ATH9K_HTC_NORMAL;
+		tx_hdr.data_type = ATH9K_HTC_NORMAL;
+	}
+
+	if (ieee80211_is_data_qos(hdr->frame_control)) {
+		qc = ieee80211_get_qos_ctl(hdr);
+		tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
+	}
+
+	/* Check for RTS protection */
+	if (priv->hw->wiphy->rts_threshold != (u32) -1)
+		if (skb->len > priv->hw->wiphy->rts_threshold)
+			flags |= ATH9K_HTC_TX_RTSCTS;
+
+	/* CTS-to-self */
+	if (!(flags & ATH9K_HTC_TX_RTSCTS) &&
+	    (vif && vif->bss_conf.use_cts_prot))
+		flags |= ATH9K_HTC_TX_CTSONLY;
+
+	tx_hdr.flags = cpu_to_be32(flags);
+	tx_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb);
+	if (tx_hdr.key_type == ATH9K_KEY_TYPE_CLEAR)
+		tx_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID;
+	else
+		tx_hdr.keyix = tx_info->control.hw_key->hw_key_idx;
+
+	tx_fhdr = skb_push(skb, sizeof(tx_hdr));
+	memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr));
+
+	if (is_cab) {
+		CAB_STAT_INC;
+		tx_ctl->epid = priv->cab_ep;
+		return;
+	}
+
+	qnum = skb_get_queue_mapping(skb);
+	tx_ctl->epid = get_htc_epid(priv, qnum);
+}
+
+int ath9k_htc_tx_start(struct ath9k_htc_priv *priv,
+		       struct sk_buff *skb,
+		       u8 slot, bool is_cab)
 {
 	struct ieee80211_hdr *hdr;
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_sta *sta = tx_info->control.sta;
 	struct ieee80211_vif *vif = tx_info->control.vif;
 	struct ath9k_htc_sta *ista;
-	struct ath9k_htc_vif *avp;
-	struct ath9k_htc_tx_ctl tx_ctl;
-	enum htc_endpoint_id epid;
-	u16 qnum;
-	__le16 fc;
-	u8 *tx_fhdr;
+	struct ath9k_htc_vif *avp = NULL;
 	u8 sta_idx, vif_idx;
 
 	hdr = (struct ieee80211_hdr *) skb->data;
-	fc = hdr->frame_control;
 
 	/*
 	 * Find out on which interface this packet has to be
@@ -124,218 +373,432 @@
 		sta_idx = priv->vif_sta_pos[vif_idx];
 	}
 
-	memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl));
+	if (ieee80211_is_data(hdr->frame_control))
+		ath9k_htc_tx_data(priv, vif, skb,
+				  sta_idx, vif_idx, slot, is_cab);
+	else
+		ath9k_htc_tx_mgmt(priv, avp, skb,
+				  sta_idx, vif_idx, slot);
 
-	if (ieee80211_is_data(fc)) {
-		struct tx_frame_hdr tx_hdr;
-		u32 flags = 0;
-		u8 *qc;
 
-		memset(&tx_hdr, 0, sizeof(struct tx_frame_hdr));
-
-		tx_hdr.node_idx = sta_idx;
-		tx_hdr.vif_idx = vif_idx;
-
-		if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
-			tx_ctl.type = ATH9K_HTC_AMPDU;
-			tx_hdr.data_type = ATH9K_HTC_AMPDU;
-		} else {
-			tx_ctl.type = ATH9K_HTC_NORMAL;
-			tx_hdr.data_type = ATH9K_HTC_NORMAL;
-		}
-
-		if (ieee80211_is_data_qos(fc)) {
-			qc = ieee80211_get_qos_ctl(hdr);
-			tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
-		}
-
-		/* Check for RTS protection */
-		if (priv->hw->wiphy->rts_threshold != (u32) -1)
-			if (skb->len > priv->hw->wiphy->rts_threshold)
-				flags |= ATH9K_HTC_TX_RTSCTS;
-
-		/* CTS-to-self */
-		if (!(flags & ATH9K_HTC_TX_RTSCTS) &&
-		    (vif && vif->bss_conf.use_cts_prot))
-			flags |= ATH9K_HTC_TX_CTSONLY;
-
-		tx_hdr.flags = cpu_to_be32(flags);
-		tx_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb);
-		if (tx_hdr.key_type == ATH9K_KEY_TYPE_CLEAR)
-			tx_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID;
-		else
-			tx_hdr.keyix = tx_info->control.hw_key->hw_key_idx;
-
-		tx_fhdr = skb_push(skb, sizeof(tx_hdr));
-		memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr));
-
-		qnum = skb_get_queue_mapping(skb);
-
-		switch (qnum) {
-		case 0:
-			TX_QSTAT_INC(WME_AC_VO);
-			epid = priv->data_vo_ep;
-			break;
-		case 1:
-			TX_QSTAT_INC(WME_AC_VI);
-			epid = priv->data_vi_ep;
-			break;
-		case 2:
-			TX_QSTAT_INC(WME_AC_BE);
-			epid = priv->data_be_ep;
-			break;
-		case 3:
-		default:
-			TX_QSTAT_INC(WME_AC_BK);
-			epid = priv->data_bk_ep;
-			break;
-		}
-	} else {
-		struct tx_mgmt_hdr mgmt_hdr;
-
-		memset(&mgmt_hdr, 0, sizeof(struct tx_mgmt_hdr));
-
-		tx_ctl.type = ATH9K_HTC_NORMAL;
-
-		mgmt_hdr.node_idx = sta_idx;
-		mgmt_hdr.vif_idx = vif_idx;
-		mgmt_hdr.tidno = 0;
-		mgmt_hdr.flags = 0;
-
-		mgmt_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb);
-		if (mgmt_hdr.key_type == ATH9K_KEY_TYPE_CLEAR)
-			mgmt_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID;
-		else
-			mgmt_hdr.keyix = tx_info->control.hw_key->hw_key_idx;
-
-		tx_fhdr = skb_push(skb, sizeof(mgmt_hdr));
-		memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr));
-		epid = priv->mgmt_ep;
-	}
-
-	return htc_send(priv->htc, skb, epid, &tx_ctl);
+	return htc_send(priv->htc, skb);
 }
 
-static bool ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv,
-				    struct ath9k_htc_sta *ista, u8 tid)
+static inline bool __ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv,
+					     struct ath9k_htc_sta *ista, u8 tid)
 {
 	bool ret = false;
 
-	spin_lock_bh(&priv->tx_lock);
+	spin_lock_bh(&priv->tx.tx_lock);
 	if ((tid < ATH9K_HTC_MAX_TID) && (ista->tid_state[tid] == AGGR_STOP))
 		ret = true;
-	spin_unlock_bh(&priv->tx_lock);
+	spin_unlock_bh(&priv->tx.tx_lock);
 
 	return ret;
 }
 
-void ath9k_tx_tasklet(unsigned long data)
+static void ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv,
+				    struct ieee80211_vif *vif,
+				    struct sk_buff *skb)
 {
-	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
-	struct ieee80211_vif *vif;
 	struct ieee80211_sta *sta;
 	struct ieee80211_hdr *hdr;
-	struct ieee80211_tx_info *tx_info;
-	struct sk_buff *skb = NULL;
 	__le16 fc;
 
-	while ((skb = skb_dequeue(&priv->tx_queue)) != NULL) {
+	hdr = (struct ieee80211_hdr *) skb->data;
+	fc = hdr->frame_control;
 
-		hdr = (struct ieee80211_hdr *) skb->data;
-		fc = hdr->frame_control;
-		tx_info = IEEE80211_SKB_CB(skb);
-		vif = tx_info->control.vif;
+	rcu_read_lock();
 
-		memset(&tx_info->status, 0, sizeof(tx_info->status));
+	sta = ieee80211_find_sta(vif, hdr->addr1);
+	if (!sta) {
+		rcu_read_unlock();
+		return;
+	}
 
-		if (!vif)
-			goto send_mac80211;
+	if (sta && conf_is_ht(&priv->hw->conf) &&
+	    !(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
+		if (ieee80211_is_data_qos(fc)) {
+			u8 *qc, tid;
+			struct ath9k_htc_sta *ista;
 
-		rcu_read_lock();
+			qc = ieee80211_get_qos_ctl(hdr);
+			tid = qc[0] & 0xf;
+			ista = (struct ath9k_htc_sta *)sta->drv_priv;
+			if (__ath9k_htc_check_tx_aggr(priv, ista, tid)) {
+				ieee80211_start_tx_ba_session(sta, tid, 0);
+				spin_lock_bh(&priv->tx.tx_lock);
+				ista->tid_state[tid] = AGGR_PROGRESS;
+				spin_unlock_bh(&priv->tx.tx_lock);
+			}
+		}
+	}
 
-		sta = ieee80211_find_sta(vif, hdr->addr1);
-		if (!sta) {
-			rcu_read_unlock();
-			ieee80211_tx_status(priv->hw, skb);
+	rcu_read_unlock();
+}
+
+static void ath9k_htc_tx_process(struct ath9k_htc_priv *priv,
+				 struct sk_buff *skb,
+				 struct __wmi_event_txstatus *txs)
+{
+	struct ieee80211_vif *vif;
+	struct ath9k_htc_tx_ctl *tx_ctl;
+	struct ieee80211_tx_info *tx_info;
+	struct ieee80211_tx_rate *rate;
+	struct ieee80211_conf *cur_conf = &priv->hw->conf;
+	struct ieee80211_supported_band *sband;
+	bool txok;
+	int slot;
+
+	slot = strip_drv_header(priv, skb);
+	if (slot < 0) {
+		dev_kfree_skb_any(skb);
+		return;
+	}
+
+	tx_ctl = HTC_SKB_CB(skb);
+	txok = tx_ctl->txok;
+	tx_info = IEEE80211_SKB_CB(skb);
+	vif = tx_info->control.vif;
+	rate = &tx_info->status.rates[0];
+	sband = priv->hw->wiphy->bands[cur_conf->channel->band];
+
+	memset(&tx_info->status, 0, sizeof(tx_info->status));
+
+	/*
+	 * URB submission failed for this frame, it never reached
+	 * the target.
+	 */
+	if (!txok || !vif || !txs)
+		goto send_mac80211;
+
+	if (txs->ts_flags & ATH9K_HTC_TXSTAT_ACK)
+		tx_info->flags |= IEEE80211_TX_STAT_ACK;
+
+	if (txs->ts_flags & ATH9K_HTC_TXSTAT_FILT)
+		tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
+
+	if (txs->ts_flags & ATH9K_HTC_TXSTAT_RTC_CTS)
+		rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS;
+
+	rate->count = 1;
+	rate->idx = MS(txs->ts_rate, ATH9K_HTC_TXSTAT_RATE);
+
+	if (txs->ts_flags & ATH9K_HTC_TXSTAT_MCS) {
+		rate->flags |= IEEE80211_TX_RC_MCS;
+
+		if (txs->ts_flags & ATH9K_HTC_TXSTAT_CW40)
+			rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+		if (txs->ts_flags & ATH9K_HTC_TXSTAT_SGI)
+			rate->flags |= IEEE80211_TX_RC_SHORT_GI;
+	} else {
+		if (cur_conf->channel->band == IEEE80211_BAND_5GHZ)
+			rate->idx += 4; /* No CCK rates */
+	}
+
+	ath9k_htc_check_tx_aggr(priv, vif, skb);
+
+send_mac80211:
+	spin_lock_bh(&priv->tx.tx_lock);
+	if (WARN_ON(--priv->tx.queued_cnt < 0))
+		priv->tx.queued_cnt = 0;
+	spin_unlock_bh(&priv->tx.tx_lock);
+
+	ath9k_htc_tx_clear_slot(priv, slot);
+
+	/* Send status to mac80211 */
+	ieee80211_tx_status(priv->hw, skb);
+}
+
+static inline void ath9k_htc_tx_drainq(struct ath9k_htc_priv *priv,
+				       struct sk_buff_head *queue)
+{
+	struct sk_buff *skb;
+
+	while ((skb = skb_dequeue(queue)) != NULL) {
+		ath9k_htc_tx_process(priv, skb, NULL);
+	}
+}
+
+void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv)
+{
+	struct ath9k_htc_tx_event *event, *tmp;
+
+	spin_lock_bh(&priv->tx.tx_lock);
+	priv->tx.flags |= ATH9K_HTC_OP_TX_DRAIN;
+	spin_unlock_bh(&priv->tx.tx_lock);
+
+	/*
+	 * Ensure that all pending TX frames are flushed,
+	 * and that the TX completion/failed tasklets is killed.
+	 */
+	htc_stop(priv->htc);
+	tasklet_kill(&priv->wmi->wmi_event_tasklet);
+	tasklet_kill(&priv->tx_failed_tasklet);
+
+	ath9k_htc_tx_drainq(priv, &priv->tx.mgmt_ep_queue);
+	ath9k_htc_tx_drainq(priv, &priv->tx.cab_ep_queue);
+	ath9k_htc_tx_drainq(priv, &priv->tx.data_be_queue);
+	ath9k_htc_tx_drainq(priv, &priv->tx.data_bk_queue);
+	ath9k_htc_tx_drainq(priv, &priv->tx.data_vi_queue);
+	ath9k_htc_tx_drainq(priv, &priv->tx.data_vo_queue);
+	ath9k_htc_tx_drainq(priv, &priv->tx.tx_failed);
+
+	/*
+	 * The TX cleanup timer has already been killed.
+	 */
+	spin_lock_bh(&priv->wmi->event_lock);
+	list_for_each_entry_safe(event, tmp, &priv->wmi->pending_tx_events, list) {
+		list_del(&event->list);
+		kfree(event);
+	}
+	spin_unlock_bh(&priv->wmi->event_lock);
+
+	spin_lock_bh(&priv->tx.tx_lock);
+	priv->tx.flags &= ~ATH9K_HTC_OP_TX_DRAIN;
+	spin_unlock_bh(&priv->tx.tx_lock);
+}
+
+void ath9k_tx_failed_tasklet(unsigned long data)
+{
+	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
+
+	spin_lock_bh(&priv->tx.tx_lock);
+	if (priv->tx.flags & ATH9K_HTC_OP_TX_DRAIN) {
+		spin_unlock_bh(&priv->tx.tx_lock);
+		return;
+	}
+	spin_unlock_bh(&priv->tx.tx_lock);
+
+	ath9k_htc_tx_drainq(priv, &priv->tx.tx_failed);
+}
+
+static inline bool check_cookie(struct ath9k_htc_priv *priv,
+				struct sk_buff *skb,
+				u8 cookie, u8 epid)
+{
+	u8 fcookie = 0;
+
+	if (epid == priv->mgmt_ep) {
+		struct tx_mgmt_hdr *hdr;
+		hdr = (struct tx_mgmt_hdr *) skb->data;
+		fcookie = hdr->cookie;
+	} else if ((epid == priv->data_bk_ep) ||
+		   (epid == priv->data_be_ep) ||
+		   (epid == priv->data_vi_ep) ||
+		   (epid == priv->data_vo_ep) ||
+		   (epid == priv->cab_ep)) {
+		struct tx_frame_hdr *hdr;
+		hdr = (struct tx_frame_hdr *) skb->data;
+		fcookie = hdr->cookie;
+	}
+
+	if (fcookie == cookie)
+		return true;
+
+	return false;
+}
+
+static struct sk_buff* ath9k_htc_tx_get_packet(struct ath9k_htc_priv *priv,
+					       struct __wmi_event_txstatus *txs)
+{
+	struct ath_common *common = ath9k_hw_common(priv->ah);
+	struct sk_buff_head *epid_queue;
+	struct sk_buff *skb, *tmp;
+	unsigned long flags;
+	u8 epid = MS(txs->ts_rate, ATH9K_HTC_TXSTAT_EPID);
+
+	epid_queue = get_htc_epid_queue(priv, epid);
+	if (!epid_queue)
+		return NULL;
+
+	spin_lock_irqsave(&epid_queue->lock, flags);
+	skb_queue_walk_safe(epid_queue, skb, tmp) {
+		if (check_cookie(priv, skb, txs->cookie, epid)) {
+			__skb_unlink(skb, epid_queue);
+			spin_unlock_irqrestore(&epid_queue->lock, flags);
+			return skb;
+		}
+	}
+	spin_unlock_irqrestore(&epid_queue->lock, flags);
+
+	ath_dbg(common, ATH_DBG_XMIT,
+		"No matching packet for cookie: %d, epid: %d\n",
+		txs->cookie, epid);
+
+	return NULL;
+}
+
+void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event)
+{
+	struct wmi_event_txstatus *txs = (struct wmi_event_txstatus *)wmi_event;
+	struct __wmi_event_txstatus *__txs;
+	struct sk_buff *skb;
+	struct ath9k_htc_tx_event *tx_pend;
+	int i;
+
+	for (i = 0; i < txs->cnt; i++) {
+		WARN_ON(txs->cnt > HTC_MAX_TX_STATUS);
+
+		__txs = &txs->txstatus[i];
+
+		skb = ath9k_htc_tx_get_packet(priv, __txs);
+		if (!skb) {
+			/*
+			 * Store this event, so that the TX cleanup
+			 * routine can check later for the needed packet.
+			 */
+			tx_pend = kzalloc(sizeof(struct ath9k_htc_tx_event),
+					  GFP_ATOMIC);
+			if (!tx_pend)
+				continue;
+
+			memcpy(&tx_pend->txs, __txs,
+			       sizeof(struct __wmi_event_txstatus));
+
+			spin_lock(&priv->wmi->event_lock);
+			list_add_tail(&tx_pend->list,
+				      &priv->wmi->pending_tx_events);
+			spin_unlock(&priv->wmi->event_lock);
+
 			continue;
 		}
 
-		/* Check if we need to start aggregation */
-
-		if (sta && conf_is_ht(&priv->hw->conf) &&
-		    !(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
-			if (ieee80211_is_data_qos(fc)) {
-				u8 *qc, tid;
-				struct ath9k_htc_sta *ista;
-
-				qc = ieee80211_get_qos_ctl(hdr);
-				tid = qc[0] & 0xf;
-				ista = (struct ath9k_htc_sta *)sta->drv_priv;
-
-				if (ath9k_htc_check_tx_aggr(priv, ista, tid)) {
-					ieee80211_start_tx_ba_session(sta, tid, 0);
-					spin_lock_bh(&priv->tx_lock);
-					ista->tid_state[tid] = AGGR_PROGRESS;
-					spin_unlock_bh(&priv->tx_lock);
-				}
-			}
-		}
-
-		rcu_read_unlock();
-
-	send_mac80211:
-		/* Send status to mac80211 */
-		ieee80211_tx_status(priv->hw, skb);
+		ath9k_htc_tx_process(priv, skb, __txs);
 	}
 
 	/* Wake TX queues if needed */
-	spin_lock_bh(&priv->tx_lock);
-	if (priv->tx_queues_stop) {
-		priv->tx_queues_stop = false;
-		spin_unlock_bh(&priv->tx_lock);
-		ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
-			"Waking up TX queues\n");
-		ieee80211_wake_queues(priv->hw);
-		return;
-	}
-	spin_unlock_bh(&priv->tx_lock);
+	ath9k_htc_check_wake_queues(priv);
 }
 
 void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb,
 		    enum htc_endpoint_id ep_id, bool txok)
 {
 	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) drv_priv;
-	struct ath_common *common = ath9k_hw_common(priv->ah);
-	struct ieee80211_tx_info *tx_info;
+	struct ath9k_htc_tx_ctl *tx_ctl;
+	struct sk_buff_head *epid_queue;
 
-	if (!skb)
+	tx_ctl = HTC_SKB_CB(skb);
+	tx_ctl->txok = txok;
+	tx_ctl->timestamp = jiffies;
+
+	if (!txok) {
+		skb_queue_tail(&priv->tx.tx_failed, skb);
+		tasklet_schedule(&priv->tx_failed_tasklet);
 		return;
+	}
 
-	if (ep_id == priv->mgmt_ep) {
-		skb_pull(skb, sizeof(struct tx_mgmt_hdr));
-	} else if ((ep_id == priv->data_bk_ep) ||
-		   (ep_id == priv->data_be_ep) ||
-		   (ep_id == priv->data_vi_ep) ||
-		   (ep_id == priv->data_vo_ep)) {
-		skb_pull(skb, sizeof(struct tx_frame_hdr));
-	} else {
-		ath_err(common, "Unsupported TX EPID: %d\n", ep_id);
+	epid_queue = get_htc_epid_queue(priv, ep_id);
+	if (!epid_queue) {
 		dev_kfree_skb_any(skb);
 		return;
 	}
 
-	tx_info = IEEE80211_SKB_CB(skb);
+	skb_queue_tail(epid_queue, skb);
+}
 
-	if (txok)
-		tx_info->flags |= IEEE80211_TX_STAT_ACK;
+static inline bool check_packet(struct ath9k_htc_priv *priv, struct sk_buff *skb)
+{
+	struct ath_common *common = ath9k_hw_common(priv->ah);
+	struct ath9k_htc_tx_ctl *tx_ctl;
 
-	skb_queue_tail(&priv->tx_queue, skb);
-	tasklet_schedule(&priv->tx_tasklet);
+	tx_ctl = HTC_SKB_CB(skb);
+
+	if (time_after(jiffies,
+		       tx_ctl->timestamp +
+		       msecs_to_jiffies(ATH9K_HTC_TX_TIMEOUT_INTERVAL))) {
+		ath_dbg(common, ATH_DBG_XMIT,
+			"Dropping a packet due to TX timeout\n");
+		return true;
+	}
+
+	return false;
+}
+
+static void ath9k_htc_tx_cleanup_queue(struct ath9k_htc_priv *priv,
+				       struct sk_buff_head *epid_queue)
+{
+	bool process = false;
+	unsigned long flags;
+	struct sk_buff *skb, *tmp;
+	struct sk_buff_head queue;
+
+	skb_queue_head_init(&queue);
+
+	spin_lock_irqsave(&epid_queue->lock, flags);
+	skb_queue_walk_safe(epid_queue, skb, tmp) {
+		if (check_packet(priv, skb)) {
+			__skb_unlink(skb, epid_queue);
+			__skb_queue_tail(&queue, skb);
+			process = true;
+		}
+	}
+	spin_unlock_irqrestore(&epid_queue->lock, flags);
+
+	if (process) {
+		skb_queue_walk_safe(&queue, skb, tmp) {
+			__skb_unlink(skb, &queue);
+			ath9k_htc_tx_process(priv, skb, NULL);
+		}
+	}
+}
+
+void ath9k_htc_tx_cleanup_timer(unsigned long data)
+{
+	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) data;
+	struct ath_common *common = ath9k_hw_common(priv->ah);
+	struct ath9k_htc_tx_event *event, *tmp;
+	struct sk_buff *skb;
+
+	spin_lock(&priv->wmi->event_lock);
+	list_for_each_entry_safe(event, tmp, &priv->wmi->pending_tx_events, list) {
+
+		skb = ath9k_htc_tx_get_packet(priv, &event->txs);
+		if (skb) {
+			ath_dbg(common, ATH_DBG_XMIT,
+				"Found packet for cookie: %d, epid: %d\n",
+				event->txs.cookie,
+				MS(event->txs.ts_rate, ATH9K_HTC_TXSTAT_EPID));
+
+			ath9k_htc_tx_process(priv, skb, &event->txs);
+			list_del(&event->list);
+			kfree(event);
+			continue;
+		}
+
+		if (++event->count >= ATH9K_HTC_TX_TIMEOUT_COUNT) {
+			list_del(&event->list);
+			kfree(event);
+		}
+	}
+	spin_unlock(&priv->wmi->event_lock);
+
+	/*
+	 * Check if status-pending packets have to be cleaned up.
+	 */
+	ath9k_htc_tx_cleanup_queue(priv, &priv->tx.mgmt_ep_queue);
+	ath9k_htc_tx_cleanup_queue(priv, &priv->tx.cab_ep_queue);
+	ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_be_queue);
+	ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_bk_queue);
+	ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_vi_queue);
+	ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_vo_queue);
+
+	/* Wake TX queues if needed */
+	ath9k_htc_check_wake_queues(priv);
+
+	mod_timer(&priv->tx.cleanup_timer,
+		  jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL));
 }
 
 int ath9k_tx_init(struct ath9k_htc_priv *priv)
 {
-	skb_queue_head_init(&priv->tx_queue);
+	skb_queue_head_init(&priv->tx.mgmt_ep_queue);
+	skb_queue_head_init(&priv->tx.cab_ep_queue);
+	skb_queue_head_init(&priv->tx.data_be_queue);
+	skb_queue_head_init(&priv->tx.data_bk_queue);
+	skb_queue_head_init(&priv->tx.data_vi_queue);
+	skb_queue_head_init(&priv->tx.data_vo_queue);
+	skb_queue_head_init(&priv->tx.tx_failed);
 	return 0;
 }
 
@@ -507,8 +970,9 @@
 	int last_rssi = ATH_RSSI_DUMMY_MARKER;
 	__le16 fc;
 
-	if (skb->len <= HTC_RX_FRAME_HEADER_SIZE) {
-		ath_err(common, "Corrupted RX frame, dropping\n");
+	if (skb->len < HTC_RX_FRAME_HEADER_SIZE) {
+		ath_err(common, "Corrupted RX frame, dropping (len: %d)\n",
+			skb->len);
 		goto rx_next;
 	}
 
@@ -522,6 +986,8 @@
 		goto rx_next;
 	}
 
+	ath9k_htc_err_stat_rx(priv, rxstatus);
+
 	/* Get the RX status information */
 	memcpy(&rxbuf->rxstatus, rxstatus, HTC_RX_FRAME_HEADER_SIZE);
 	skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE);
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c
index 62e139a..cee970f 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.c
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.c
@@ -17,8 +17,8 @@
 #include "htc.h"
 
 static int htc_issue_send(struct htc_target *target, struct sk_buff* skb,
-			  u16 len, u8 flags, u8 epid,
-			  struct ath9k_htc_tx_ctl *tx_ctl)
+			  u16 len, u8 flags, u8 epid)
+
 {
 	struct htc_frame_hdr *hdr;
 	struct htc_endpoint *endpoint = &target->endpoint[epid];
@@ -30,8 +30,8 @@
 	hdr->flags = flags;
 	hdr->payload_len = cpu_to_be16(len);
 
-	status = target->hif->send(target->hif_dev, endpoint->ul_pipeid, skb,
-				   tx_ctl);
+	status = target->hif->send(target->hif_dev, endpoint->ul_pipeid, skb);
+
 	return status;
 }
 
@@ -162,7 +162,7 @@
 
 	target->htc_flags |= HTC_OP_CONFIG_PIPE_CREDITS;
 
-	ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0, NULL);
+	ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
 	if (ret)
 		goto err;
 
@@ -197,7 +197,7 @@
 
 	target->htc_flags |= HTC_OP_START_WAIT;
 
-	ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0, NULL);
+	ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
 	if (ret)
 		goto err;
 
@@ -268,7 +268,7 @@
 	conn_msg->dl_pipeid = endpoint->dl_pipeid;
 	conn_msg->ul_pipeid = endpoint->ul_pipeid;
 
-	ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0, NULL);
+	ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
 	if (ret)
 		goto err;
 
@@ -286,35 +286,33 @@
 	return ret;
 }
 
-int htc_send(struct htc_target *target, struct sk_buff *skb,
-	     enum htc_endpoint_id epid, struct ath9k_htc_tx_ctl *tx_ctl)
+int htc_send(struct htc_target *target, struct sk_buff *skb)
 {
-	return htc_issue_send(target, skb, skb->len, 0, epid, tx_ctl);
+	struct ath9k_htc_tx_ctl *tx_ctl;
+
+	tx_ctl = HTC_SKB_CB(skb);
+	return htc_issue_send(target, skb, skb->len, 0, tx_ctl->epid);
+}
+
+int htc_send_epid(struct htc_target *target, struct sk_buff *skb,
+		  enum htc_endpoint_id epid)
+{
+	return htc_issue_send(target, skb, skb->len, 0, epid);
 }
 
 void htc_stop(struct htc_target *target)
 {
-	enum htc_endpoint_id epid;
-	struct htc_endpoint *endpoint;
-
-	for (epid = ENDPOINT0; epid < ENDPOINT_MAX; epid++) {
-		endpoint = &target->endpoint[epid];
-		if (endpoint->service_id != 0)
-			target->hif->stop(target->hif_dev, endpoint->ul_pipeid);
-	}
+	target->hif->stop(target->hif_dev);
 }
 
 void htc_start(struct htc_target *target)
 {
-	enum htc_endpoint_id epid;
-	struct htc_endpoint *endpoint;
+	target->hif->start(target->hif_dev);
+}
 
-	for (epid = ENDPOINT0; epid < ENDPOINT_MAX; epid++) {
-		endpoint = &target->endpoint[epid];
-		if (endpoint->service_id != 0)
-			target->hif->start(target->hif_dev,
-					   endpoint->ul_pipeid);
-	}
+void htc_sta_drain(struct htc_target *target, u8 idx)
+{
+	target->hif->sta_drain(target->hif_dev, idx);
 }
 
 void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle,
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.h b/drivers/net/wireless/ath/ath9k/htc_hst.h
index ecd0187..cb9174a 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.h
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.h
@@ -33,10 +33,10 @@
 	u8 control_dl_pipe;
 	u8 control_ul_pipe;
 
-	void (*start) (void *hif_handle, u8 pipe);
-	void (*stop) (void *hif_handle, u8 pipe);
-	int (*send) (void *hif_handle, u8 pipe, struct sk_buff *buf,
-		     struct ath9k_htc_tx_ctl *tx_ctl);
+	void (*start) (void *hif_handle);
+	void (*stop) (void *hif_handle);
+	void (*sta_drain) (void *hif_handle, u8 idx);
+	int (*send) (void *hif_handle, u8 pipe, struct sk_buff *buf);
 };
 
 enum htc_endpoint_id {
@@ -205,10 +205,12 @@
 int htc_connect_service(struct htc_target *target,
 			  struct htc_service_connreq *service_connreq,
 			  enum htc_endpoint_id *conn_rsp_eid);
-int htc_send(struct htc_target *target, struct sk_buff *skb,
-	     enum htc_endpoint_id eid, struct ath9k_htc_tx_ctl *tx_ctl);
+int htc_send(struct htc_target *target, struct sk_buff *skb);
+int htc_send_epid(struct htc_target *target, struct sk_buff *skb,
+		  enum htc_endpoint_id epid);
 void htc_stop(struct htc_target *target);
 void htc_start(struct htc_target *target);
+void htc_sta_drain(struct htc_target *target, u8 idx);
 
 void ath9k_htc_rx_msg(struct htc_target *htc_handle,
 		      struct sk_buff *skb, u32 len, u8 pipe_id);
diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h
index 22ee888..9dd90a8 100644
--- a/drivers/net/wireless/ath/ath9k/hw-ops.h
+++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
@@ -122,6 +122,11 @@
 	ath9k_hw_ops(ah)->set11n_burstduration(ah, ds, burstDuration);
 }
 
+static inline void ath9k_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val)
+{
+	ath9k_hw_ops(ah)->set_clrdmask(ah, ds, val);
+}
+
 /* 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 c8a2d0d..045abd5 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -676,42 +676,55 @@
 }
 EXPORT_SYMBOL(ar9003_get_pll_sqsum_dvc);
 
-#define DPLL2_KD_VAL            0x3D
-#define DPLL2_KI_VAL            0x06
-#define DPLL3_PHASE_SHIFT_VAL   0x1
-
+#define DPLL3_PHASE_SHIFT_VAL 0x1
 static void ath9k_hw_init_pll(struct ath_hw *ah,
 			      struct ath9k_channel *chan)
 {
 	u32 pll;
 
 	if (AR_SREV_9485(ah)) {
-		REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0x886666);
-		REG_WRITE(ah, AR_CH0_DDR_DPLL2, 0x19e82f01);
 
-		REG_RMW_FIELD(ah, AR_CH0_DDR_DPLL3,
-			      AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL);
+		/* program BB PLL ki and kd value, ki=0x4, kd=0x40 */
+		REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
+			      AR_CH0_BB_DPLL2_PLL_PWD, 0x1);
+		REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
+			      AR_CH0_DPLL2_KD, 0x40);
+		REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
+			      AR_CH0_DPLL2_KI, 0x4);
 
-		REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c);
+		REG_RMW_FIELD(ah, AR_CH0_BB_DPLL1,
+			      AR_CH0_BB_DPLL1_REFDIV, 0x5);
+		REG_RMW_FIELD(ah, AR_CH0_BB_DPLL1,
+			      AR_CH0_BB_DPLL1_NINI, 0x58);
+		REG_RMW_FIELD(ah, AR_CH0_BB_DPLL1,
+			      AR_CH0_BB_DPLL1_NFRAC, 0x0);
+
+		REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
+			      AR_CH0_BB_DPLL2_OUTDIV, 0x1);
+		REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
+			      AR_CH0_BB_DPLL2_LOCAL_PLL, 0x1);
+		REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
+			      AR_CH0_BB_DPLL2_EN_NEGTRIG, 0x1);
+
+		/* program BB PLL phase_shift to 0x6 */
+		REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3,
+			      AR_CH0_BB_DPLL3_PHASE_SHIFT, 0x6);
+
+		REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
+			      AR_CH0_BB_DPLL2_PLL_PWD, 0x0);
 		udelay(1000);
 
-		REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0x886666);
-
-		REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
-			      AR_CH0_DPLL2_KD, DPLL2_KD_VAL);
-		REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
-			      AR_CH0_DPLL2_KI, DPLL2_KI_VAL);
-
 		REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3,
 			      AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL);
-		REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x142c);
-		udelay(1000);
 	}
 
 	pll = ath9k_hw_compute_pll_control(ah, chan);
 
 	REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll);
 
+	if (AR_SREV_9485(ah))
+		udelay(1000);
+
 	/* Switch the core clock for ar9271 to 117Mhz */
 	if (AR_SREV_9271(ah)) {
 		udelay(500);
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index a778b66..1018d6c 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -626,6 +626,7 @@
 	void (*clr11n_aggr)(struct ath_hw *ah, void *ds);
 	void (*set11n_burstduration)(struct ath_hw *ah, void *ds,
 				     u32 burstDuration);
+	void (*set_clrdmask)(struct ath_hw *ah, void *ds, bool val);
 };
 
 struct ath_nf_limits {
@@ -846,6 +847,14 @@
 	u32 ent_mode;
 };
 
+struct ath_bus_ops {
+	enum ath_bus_type ath_bus_type;
+	void (*read_cachesize)(struct ath_common *common, int *csz);
+	bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data);
+	void (*bt_coex_prep)(struct ath_common *common);
+	void (*extn_synch_en)(struct ath_common *common);
+};
+
 static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah)
 {
 	return &ah->common;
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
index c2a5938..b60c130 100644
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -239,7 +239,6 @@
 	void *ds_vdata;
 } __packed __aligned(4);
 
-#define ATH9K_TXDESC_CLRDMASK		0x0001
 #define ATH9K_TXDESC_NOACK		0x0002
 #define ATH9K_TXDESC_RTSENA		0x0004
 #define ATH9K_TXDESC_CTSENA		0x0008
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 4c5c999..a8d9009 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1373,6 +1373,9 @@
 	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);
 	}
 }
 
@@ -1733,23 +1736,63 @@
 			 struct ieee80211_sta *sta)
 {
 	struct ath_softc *sc = hw->priv;
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+	struct ath_node *an = (struct ath_node *) sta->drv_priv;
+	struct ieee80211_key_conf ps_key = { };
 
 	ath_node_attach(sc, sta);
+	an->ps_key = ath_key_config(common, vif, sta, &ps_key);
 
 	return 0;
 }
 
+static void ath9k_del_ps_key(struct ath_softc *sc,
+			     struct ieee80211_vif *vif,
+			     struct ieee80211_sta *sta)
+{
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+	struct ath_node *an = (struct ath_node *) sta->drv_priv;
+	struct ieee80211_key_conf ps_key = { .hw_key_idx = an->ps_key };
+
+	if (!an->ps_key)
+	    return;
+
+	ath_key_delete(common, &ps_key);
+}
+
 static int ath9k_sta_remove(struct ieee80211_hw *hw,
 			    struct ieee80211_vif *vif,
 			    struct ieee80211_sta *sta)
 {
 	struct ath_softc *sc = hw->priv;
 
+	ath9k_del_ps_key(sc, vif, sta);
 	ath_node_detach(sc, sta);
 
 	return 0;
 }
 
+static void ath9k_sta_notify(struct ieee80211_hw *hw,
+			 struct ieee80211_vif *vif,
+			 enum sta_notify_cmd cmd,
+			 struct ieee80211_sta *sta)
+{
+	struct ath_softc *sc = hw->priv;
+	struct ath_node *an = (struct ath_node *) sta->drv_priv;
+
+	switch (cmd) {
+	case STA_NOTIFY_SLEEP:
+		an->sleeping = true;
+		if (ath_tx_aggr_sleep(sc, an))
+			ieee80211_sta_set_tim(sta);
+		break;
+	case STA_NOTIFY_AWAKE:
+		an->sleeping = false;
+		ath_tx_aggr_wakeup(sc, an);
+		break;
+	}
+}
+
 static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue,
 			 const struct ieee80211_tx_queue_params *params)
 {
@@ -1826,6 +1869,9 @@
 
 	switch (cmd) {
 	case SET_KEY:
+		if (sta)
+			ath9k_del_ps_key(sc, vif, sta);
+
 		ret = ath_key_config(common, vif, sta, key);
 		if (ret >= 0) {
 			key->hw_key_idx = ret;
@@ -2209,6 +2255,21 @@
 	ath9k_ps_restore(sc);
 }
 
+static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw)
+{
+	struct ath_softc *sc = hw->priv;
+	int i;
+
+	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
+		if (!ATH_TXQ_SETUP(sc, i))
+			continue;
+
+		if (ath9k_has_pending_frames(sc, &sc->tx.txq[i]))
+			return true;
+	}
+	return false;
+}
+
 struct ieee80211_ops ath9k_ops = {
 	.tx 		    = ath9k_tx,
 	.start 		    = ath9k_start,
@@ -2220,6 +2281,7 @@
 	.configure_filter   = ath9k_configure_filter,
 	.sta_add	    = ath9k_sta_add,
 	.sta_remove	    = ath9k_sta_remove,
+	.sta_notify         = ath9k_sta_notify,
 	.conf_tx 	    = ath9k_conf_tx,
 	.bss_info_changed   = ath9k_bss_info_changed,
 	.set_key            = ath9k_set_key,
@@ -2231,4 +2293,5 @@
 	.rfkill_poll        = ath9k_rfkill_poll_state,
 	.set_coverage_class = ath9k_set_coverage_class,
 	.flush		    = ath9k_flush,
+	.tx_frames_pending  = ath9k_tx_frames_pending,
 };
diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h
index f50e2c2..8e5fe9d 100644
--- a/drivers/net/wireless/ath/ath9k/phy.h
+++ b/drivers/net/wireless/ath/ath9k/phy.h
@@ -19,7 +19,6 @@
 
 #define CHANSEL_DIV		15
 #define CHANSEL_2G(_freq)	(((_freq) * 0x10000) / CHANSEL_DIV)
-#define CHANSEL_2G_9485(_freq)	((((_freq) * 0x10000) - 215) / CHANSEL_DIV)
 #define CHANSEL_5G(_freq)	(((_freq) * 0x8000) / CHANSEL_DIV)
 
 #define AR_PHY_BASE     0x9800
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index 4c0d36a..1809409 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -1092,8 +1092,7 @@
 	if (!(rate->flags & IEEE80211_TX_RC_MCS))
 		return rate->idx;
 
-	while (rate->idx > mcs_rix_off[i] &&
-	       i < ARRAY_SIZE(mcs_rix_off)) {
+	while (i < ARRAY_SIZE(mcs_rix_off) && rate->idx > mcs_rix_off[i]) {
 		rix++; i++;
 	}
 
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index cfaf0a4..642504f 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -75,7 +75,6 @@
 		*sc->rx.rxlink = bf->bf_daddr;
 
 	sc->rx.rxlink = &ds->ds_link;
-	ath9k_hw_rxena(ah);
 }
 
 static void ath_setdefantenna(struct ath_softc *sc, u32 antenna)
@@ -426,9 +425,7 @@
 	else
 		rfilt |= ATH9K_RX_FILTER_BEACON;
 
-	if ((AR_SREV_9280_20_OR_LATER(sc->sc_ah) ||
-	    AR_SREV_9285_12_OR_LATER(sc->sc_ah)) &&
-	    (sc->sc_ah->opmode == NL80211_IFTYPE_AP) &&
+	if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) ||
 	    (sc->rx.rxfilter & FIF_PSPOLL))
 		rfilt |= ATH9K_RX_FILTER_PSPOLL;
 
@@ -1767,6 +1764,7 @@
 		} else {
 			list_move_tail(&bf->list, &sc->rx.rxbuf);
 			ath_rx_buf_link(sc, bf);
+			ath9k_hw_rxena(ah);
 		}
 	} while (1);
 
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index 693d543..6acbf0e 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -858,9 +858,7 @@
 #define AR_SREV_9300(_ah) \
 	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300))
 #define AR_SREV_9300_20_OR_LATER(_ah) \
-	(((_ah)->hw_version.macVersion > AR_SREV_VERSION_9300) || \
-	 (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300) && \
-	  ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9300_20)))
+	((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9300)
 
 #define AR_SREV_9485(_ah) \
 	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485))
@@ -1088,14 +1086,35 @@
 #define AR_ENT_OTP		  0x40d8
 #define AR_ENT_OTP_CHAIN2_DISABLE               0x00020000
 #define AR_ENT_OTP_MPSD		0x00800000
-#define AR_CH0_BB_DPLL2          0x16184
-#define AR_CH0_BB_DPLL3          0x16188
-#define AR_CH0_DDR_DPLL2         0x16244
-#define AR_CH0_DDR_DPLL3         0x16248
-#define AR_CH0_DPLL2_KD              0x03F80000
-#define AR_CH0_DPLL2_KD_S            19
+
+#define AR_CH0_BB_DPLL1		 0x16180
+#define AR_CH0_BB_DPLL1_REFDIV	 0xF8000000
+#define AR_CH0_BB_DPLL1_REFDIV_S 27
+#define AR_CH0_BB_DPLL1_NINI	 0x07FC0000
+#define AR_CH0_BB_DPLL1_NINI_S	 18
+#define AR_CH0_BB_DPLL1_NFRAC	 0x0003FFFF
+#define AR_CH0_BB_DPLL1_NFRAC_S	 0
+
+#define AR_CH0_BB_DPLL2		     0x16184
+#define AR_CH0_BB_DPLL2_LOCAL_PLL       0x40000000
+#define AR_CH0_BB_DPLL2_LOCAL_PLL_S     30
 #define AR_CH0_DPLL2_KI              0x3C000000
 #define AR_CH0_DPLL2_KI_S            26
+#define AR_CH0_DPLL2_KD              0x03F80000
+#define AR_CH0_DPLL2_KD_S            19
+#define AR_CH0_BB_DPLL2_EN_NEGTRIG   0x00040000
+#define AR_CH0_BB_DPLL2_EN_NEGTRIG_S 18
+#define AR_CH0_BB_DPLL2_PLL_PWD	     0x00010000
+#define AR_CH0_BB_DPLL2_PLL_PWD_S    16
+#define AR_CH0_BB_DPLL2_OUTDIV	     0x0000E000
+#define AR_CH0_BB_DPLL2_OUTDIV_S     13
+
+#define AR_CH0_BB_DPLL3          0x16188
+#define AR_CH0_BB_DPLL3_PHASE_SHIFT	0x3F800000
+#define AR_CH0_BB_DPLL3_PHASE_SHIFT_S	23
+
+#define AR_CH0_DDR_DPLL2         0x16244
+#define AR_CH0_DDR_DPLL3         0x16248
 #define AR_CH0_DPLL3_PHASE_SHIFT     0x3F800000
 #define AR_CH0_DPLL3_PHASE_SHIFT_S   23
 #define AR_PHY_CCA_NOM_VAL_2GHZ      -118
diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c
index d3d2490..8f095ad 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.c
+++ b/drivers/net/wireless/ath/ath9k/wmi.c
@@ -23,20 +23,18 @@
 		return "WMI_ECHO_CMDID";
 	case WMI_ACCESS_MEMORY_CMDID:
 		return "WMI_ACCESS_MEMORY_CMDID";
+	case WMI_GET_FW_VERSION:
+		return "WMI_GET_FW_VERSION";
 	case WMI_DISABLE_INTR_CMDID:
 		return "WMI_DISABLE_INTR_CMDID";
 	case WMI_ENABLE_INTR_CMDID:
 		return "WMI_ENABLE_INTR_CMDID";
-	case WMI_RX_LINK_CMDID:
-		return "WMI_RX_LINK_CMDID";
 	case WMI_ATH_INIT_CMDID:
 		return "WMI_ATH_INIT_CMDID";
 	case WMI_ABORT_TXQ_CMDID:
 		return "WMI_ABORT_TXQ_CMDID";
 	case WMI_STOP_TX_DMA_CMDID:
 		return "WMI_STOP_TX_DMA_CMDID";
-	case WMI_STOP_DMA_RECV_CMDID:
-		return "WMI_STOP_DMA_RECV_CMDID";
 	case WMI_ABORT_TX_DMA_CMDID:
 		return "WMI_ABORT_TX_DMA_CMDID";
 	case WMI_DRAIN_TXQ_CMDID:
@@ -51,8 +49,6 @@
 		return "WMI_FLUSH_RECV_CMDID";
 	case WMI_SET_MODE_CMDID:
 		return "WMI_SET_MODE_CMDID";
-	case WMI_RESET_CMDID:
-		return "WMI_RESET_CMDID";
 	case WMI_NODE_CREATE_CMDID:
 		return "WMI_NODE_CREATE_CMDID";
 	case WMI_NODE_REMOVE_CMDID:
@@ -61,8 +57,6 @@
 		return "WMI_VAP_REMOVE_CMDID";
 	case WMI_VAP_CREATE_CMDID:
 		return "WMI_VAP_CREATE_CMDID";
-	case WMI_BEACON_UPDATE_CMDID:
-		return "WMI_BEACON_UPDATE_CMDID";
 	case WMI_REG_READ_CMDID:
 		return "WMI_REG_READ_CMDID";
 	case WMI_REG_WRITE_CMDID:
@@ -71,20 +65,20 @@
 		return "WMI_RC_STATE_CHANGE_CMDID";
 	case WMI_RC_RATE_UPDATE_CMDID:
 		return "WMI_RC_RATE_UPDATE_CMDID";
-	case WMI_DEBUG_INFO_CMDID:
-		return "WMI_DEBUG_INFO_CMDID";
-	case WMI_HOST_ATTACH:
-		return "WMI_HOST_ATTACH";
 	case WMI_TARGET_IC_UPDATE_CMDID:
 		return "WMI_TARGET_IC_UPDATE_CMDID";
-	case WMI_TGT_STATS_CMDID:
-		return "WMI_TGT_STATS_CMDID";
 	case WMI_TX_AGGR_ENABLE_CMDID:
 		return "WMI_TX_AGGR_ENABLE_CMDID";
 	case WMI_TGT_DETACH_CMDID:
 		return "WMI_TGT_DETACH_CMDID";
-	case WMI_TGT_TXQ_ENABLE_CMDID:
-		return "WMI_TGT_TXQ_ENABLE_CMDID";
+	case WMI_NODE_UPDATE_CMDID:
+		return "WMI_NODE_UPDATE_CMDID";
+	case WMI_INT_STATS_CMDID:
+		return "WMI_INT_STATS_CMDID";
+	case WMI_TX_STATS_CMDID:
+		return "WMI_TX_STATS_CMDID";
+	case WMI_RX_STATS_CMDID:
+		return "WMI_RX_STATS_CMDID";
 	case WMI_AGGR_LIMIT_CMD:
 		return "WMI_AGGR_LIMIT_CMD";
 	}
@@ -102,9 +96,15 @@
 
 	wmi->drv_priv = priv;
 	wmi->stopped = false;
+	skb_queue_head_init(&wmi->wmi_event_queue);
+	spin_lock_init(&wmi->wmi_lock);
+	spin_lock_init(&wmi->event_lock);
 	mutex_init(&wmi->op_mutex);
 	mutex_init(&wmi->multi_write_mutex);
 	init_completion(&wmi->cmd_wait);
+	INIT_LIST_HEAD(&wmi->pending_tx_events);
+	tasklet_init(&wmi->wmi_event_tasklet, ath9k_wmi_event_tasklet,
+		     (unsigned long)wmi);
 
 	return wmi;
 }
@@ -120,11 +120,65 @@
 	kfree(priv->wmi);
 }
 
-void ath9k_swba_tasklet(unsigned long data)
+void ath9k_wmi_event_drain(struct ath9k_htc_priv *priv)
 {
-	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
+	unsigned long flags;
 
-	ath9k_htc_swba(priv, priv->wmi->beacon_pending);
+	tasklet_kill(&priv->wmi->wmi_event_tasklet);
+	spin_lock_irqsave(&priv->wmi->wmi_lock, flags);
+	__skb_queue_purge(&priv->wmi->wmi_event_queue);
+	spin_unlock_irqrestore(&priv->wmi->wmi_lock, flags);
+}
+
+void ath9k_wmi_event_tasklet(unsigned long data)
+{
+	struct wmi *wmi = (struct wmi *)data;
+	struct ath9k_htc_priv *priv = wmi->drv_priv;
+	struct wmi_cmd_hdr *hdr;
+	void *wmi_event;
+	struct wmi_event_swba *swba;
+	struct sk_buff *skb = NULL;
+	unsigned long flags;
+	u16 cmd_id;
+
+	do {
+		spin_lock_irqsave(&wmi->wmi_lock, flags);
+		skb = __skb_dequeue(&wmi->wmi_event_queue);
+		if (!skb) {
+			spin_unlock_irqrestore(&wmi->wmi_lock, flags);
+			return;
+		}
+		spin_unlock_irqrestore(&wmi->wmi_lock, flags);
+
+		hdr = (struct wmi_cmd_hdr *) skb->data;
+		cmd_id = be16_to_cpu(hdr->command_id);
+		wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr));
+
+		switch (cmd_id) {
+		case WMI_SWBA_EVENTID:
+			swba = (struct wmi_event_swba *) wmi_event;
+			ath9k_htc_swba(priv, swba);
+			break;
+		case WMI_FATAL_EVENTID:
+			ieee80211_queue_work(wmi->drv_priv->hw,
+					     &wmi->drv_priv->fatal_work);
+			break;
+		case WMI_TXSTATUS_EVENTID:
+			spin_lock_bh(&priv->tx.tx_lock);
+			if (priv->tx.flags & ATH9K_HTC_OP_TX_DRAIN) {
+				spin_unlock_bh(&priv->tx.tx_lock);
+				break;
+			}
+			spin_unlock_bh(&priv->tx.tx_lock);
+
+			ath9k_htc_txstatus(priv, wmi_event);
+			break;
+		default:
+			break;
+		}
+
+		kfree_skb(skb);
+	} while (1);
 }
 
 void ath9k_fatal_work(struct work_struct *work)
@@ -153,10 +207,6 @@
 	struct wmi *wmi = (struct wmi *) priv;
 	struct wmi_cmd_hdr *hdr;
 	u16 cmd_id;
-	void *wmi_event;
-#ifdef CONFIG_ATH9K_HTC_DEBUGFS
-	__be32 txrate;
-#endif
 
 	if (unlikely(wmi->stopped))
 		goto free_skb;
@@ -165,26 +215,10 @@
 	cmd_id = be16_to_cpu(hdr->command_id);
 
 	if (cmd_id & 0x1000) {
-		wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr));
-		switch (cmd_id) {
-		case WMI_SWBA_EVENTID:
-			wmi->beacon_pending = *(u8 *)wmi_event;
-			tasklet_schedule(&wmi->drv_priv->swba_tasklet);
-			break;
-		case WMI_FATAL_EVENTID:
-			ieee80211_queue_work(wmi->drv_priv->hw,
-					     &wmi->drv_priv->fatal_work);
-			break;
-		case WMI_TXRATE_EVENTID:
-#ifdef CONFIG_ATH9K_HTC_DEBUGFS
-			txrate = ((struct wmi_event_txrate *)wmi_event)->txrate;
-			wmi->drv_priv->debug.txrate = be32_to_cpu(txrate);
-#endif
-			break;
-		default:
-			break;
-		}
-		kfree_skb(skb);
+		spin_lock(&wmi->wmi_lock);
+		__skb_queue_tail(&wmi->wmi_event_queue, skb);
+		spin_unlock(&wmi->wmi_lock);
+		tasklet_schedule(&wmi->wmi_event_tasklet);
 		return;
 	}
 
@@ -243,7 +277,7 @@
 	hdr->command_id = cpu_to_be16(cmd);
 	hdr->seq_no = cpu_to_be16(++wmi->tx_seq_id);
 
-	return htc_send(wmi->htc, skb, wmi->ctrl_epid, NULL);
+	return htc_send_epid(wmi->htc, skb, wmi->ctrl_epid);
 }
 
 int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h
index 4208427..02ecb9f 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.h
+++ b/drivers/net/wireless/ath/ath9k/wmi.h
@@ -17,7 +17,6 @@
 #ifndef WMI_H
 #define WMI_H
 
-
 struct wmi_event_txrate {
 	__be32 txrate;
 	struct {
@@ -31,18 +30,65 @@
 	__be16 seq_no;
 } __packed;
 
+struct wmi_fw_version {
+	__be16 major;
+	__be16 minor;
+
+} __packed;
+
+struct wmi_event_swba {
+	__be64 tsf;
+	u8 beacon_pending;
+};
+
+/*
+ * 64 - HTC header - WMI header - 1 / txstatus
+ * And some other hdr. space is also accounted for.
+ * 12 seems to be the magic number.
+ */
+#define HTC_MAX_TX_STATUS 12
+
+#define ATH9K_HTC_TXSTAT_ACK        BIT(0)
+#define ATH9K_HTC_TXSTAT_FILT       BIT(1)
+#define ATH9K_HTC_TXSTAT_RTC_CTS    BIT(2)
+#define ATH9K_HTC_TXSTAT_MCS        BIT(3)
+#define ATH9K_HTC_TXSTAT_CW40       BIT(4)
+#define ATH9K_HTC_TXSTAT_SGI        BIT(5)
+
+/*
+ * Legacy rates are indicated as indices.
+ * HT rates are indicated as dot11 numbers.
+ * This allows us to resrict the rate field
+ * to 4 bits.
+ */
+#define ATH9K_HTC_TXSTAT_RATE       0x0f
+#define ATH9K_HTC_TXSTAT_RATE_S     0
+
+#define ATH9K_HTC_TXSTAT_EPID       0xf0
+#define ATH9K_HTC_TXSTAT_EPID_S     4
+
+struct __wmi_event_txstatus {
+	u8 cookie;
+	u8 ts_rate; /* Also holds EP ID */
+	u8 ts_flags;
+};
+
+struct wmi_event_txstatus {
+	u8 cnt;
+	struct __wmi_event_txstatus txstatus[HTC_MAX_TX_STATUS];
+} __packed;
+
 enum wmi_cmd_id {
 	WMI_ECHO_CMDID = 0x0001,
 	WMI_ACCESS_MEMORY_CMDID,
 
 	/* Commands to Target */
+	WMI_GET_FW_VERSION,
 	WMI_DISABLE_INTR_CMDID,
 	WMI_ENABLE_INTR_CMDID,
-	WMI_RX_LINK_CMDID,
 	WMI_ATH_INIT_CMDID,
 	WMI_ABORT_TXQ_CMDID,
 	WMI_STOP_TX_DMA_CMDID,
-	WMI_STOP_DMA_RECV_CMDID,
 	WMI_ABORT_TX_DMA_CMDID,
 	WMI_DRAIN_TXQ_CMDID,
 	WMI_DRAIN_TXQ_ALL_CMDID,
@@ -50,23 +96,21 @@
 	WMI_STOP_RECV_CMDID,
 	WMI_FLUSH_RECV_CMDID,
 	WMI_SET_MODE_CMDID,
-	WMI_RESET_CMDID,
 	WMI_NODE_CREATE_CMDID,
 	WMI_NODE_REMOVE_CMDID,
 	WMI_VAP_REMOVE_CMDID,
 	WMI_VAP_CREATE_CMDID,
-	WMI_BEACON_UPDATE_CMDID,
 	WMI_REG_READ_CMDID,
 	WMI_REG_WRITE_CMDID,
 	WMI_RC_STATE_CHANGE_CMDID,
 	WMI_RC_RATE_UPDATE_CMDID,
-	WMI_DEBUG_INFO_CMDID,
-	WMI_HOST_ATTACH,
 	WMI_TARGET_IC_UPDATE_CMDID,
-	WMI_TGT_STATS_CMDID,
 	WMI_TX_AGGR_ENABLE_CMDID,
 	WMI_TGT_DETACH_CMDID,
-	WMI_TGT_TXQ_ENABLE_CMDID,
+	WMI_NODE_UPDATE_CMDID,
+	WMI_INT_STATS_CMDID,
+	WMI_TX_STATS_CMDID,
+	WMI_RX_STATS_CMDID,
 	WMI_AGGR_LIMIT_CMD = 0x0026,
 };
 
@@ -76,9 +120,8 @@
 	WMI_FATAL_EVENTID,
 	WMI_TXTO_EVENTID,
 	WMI_BMISS_EVENTID,
-	WMI_WLAN_TXCOMP_EVENTID,
 	WMI_DELBA_EVENTID,
-	WMI_TXRATE_EVENTID,
+	WMI_TXSTATUS_EVENTID,
 };
 
 #define MAX_CMD_NUMBER 62
@@ -88,6 +131,12 @@
 	__be32 val;
 };
 
+struct ath9k_htc_tx_event {
+	int count;
+	struct __wmi_event_txstatus txs;
+	struct list_head list;
+};
+
 struct wmi {
 	struct ath9k_htc_priv *drv_priv;
 	struct htc_target *htc;
@@ -95,12 +144,16 @@
 	struct mutex op_mutex;
 	struct completion cmd_wait;
 	enum wmi_cmd_id last_cmd_id;
+	struct sk_buff_head wmi_event_queue;
+	struct tasklet_struct wmi_event_tasklet;
 	u16 tx_seq_id;
 	u8 *cmd_rsp_buf;
 	u32 cmd_rsp_len;
 	bool stopped;
 
-	u8 beacon_pending;
+	struct list_head pending_tx_events;
+	spinlock_t event_lock;
+
 	spinlock_t wmi_lock;
 
 	atomic_t mwrite_cnt;
@@ -117,8 +170,9 @@
 		  u8 *cmd_buf, u32 cmd_len,
 		  u8 *rsp_buf, u32 rsp_len,
 		  u32 timeout);
-void ath9k_swba_tasklet(unsigned long data);
+void ath9k_wmi_event_tasklet(unsigned long data);
 void ath9k_fatal_work(struct work_struct *work);
+void ath9k_wmi_event_drain(struct ath9k_htc_priv *priv);
 
 #define WMI_CMD(_wmi_cmd)						\
 	do {								\
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 3cea3f7..e9e99f7 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -357,6 +357,7 @@
 	struct ath_frame_info *fi;
 	int nframes;
 	u8 tidno;
+	bool clear_filter;
 
 	skb = bf->bf_mpdu;
 	hdr = (struct ieee80211_hdr *)skb->data;
@@ -441,22 +442,24 @@
 			/* transmit completion */
 			acked_cnt++;
 		} else {
-			if (!(tid->state & AGGR_CLEANUP) && retry) {
-				if (fi->retries < ATH_MAX_SW_RETRIES) {
-					ath_tx_set_retry(sc, txq, bf->bf_mpdu);
-					txpending = 1;
-				} else {
-					bf->bf_state.bf_type |= BUF_XRETRY;
-					txfail = 1;
-					sendbar = 1;
-					txfail_cnt++;
-				}
-			} else {
+			if ((tid->state & AGGR_CLEANUP) || !retry) {
 				/*
 				 * cleanup in progress, just fail
 				 * the un-acked sub-frames
 				 */
 				txfail = 1;
+			} else if (fi->retries < ATH_MAX_SW_RETRIES) {
+				if (!(ts->ts_status & ATH9K_TXERR_FILT) ||
+				    !an->sleeping)
+					ath_tx_set_retry(sc, txq, bf->bf_mpdu);
+
+				clear_filter = true;
+				txpending = 1;
+			} else {
+				bf->bf_state.bf_type |= BUF_XRETRY;
+				txfail = 1;
+				sendbar = 1;
+				txfail_cnt++;
 			}
 		}
 
@@ -496,6 +499,7 @@
 				!txfail, sendbar);
 		} else {
 			/* retry the un-acked ones */
+			ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, false);
 			if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) {
 				if (bf->bf_next == NULL && bf_last->bf_stale) {
 					struct ath_buf *tbf;
@@ -546,7 +550,12 @@
 
 	/* prepend un-acked frames to the beginning of the pending frame queue */
 	if (!list_empty(&bf_pending)) {
+		if (an->sleeping)
+			ieee80211_sta_set_tim(sta);
+
 		spin_lock_bh(&txq->axq_lock);
+		if (clear_filter)
+			tid->ac->clear_ps_filter = true;
 		list_splice(&bf_pending, &tid->buf_q);
 		ath_tx_queue_tid(txq, tid);
 		spin_unlock_bh(&txq->axq_lock);
@@ -816,6 +825,11 @@
 		bf = list_first_entry(&bf_q, struct ath_buf, list);
 		bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list);
 
+		if (tid->ac->clear_ps_filter) {
+			tid->ac->clear_ps_filter = false;
+			ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true);
+		}
+
 		/* if only one frame, send as non-aggregate */
 		if (bf == bf->bf_lastbf) {
 			fi = get_frame_info(bf->bf_mpdu);
@@ -896,6 +910,67 @@
 	ath_tx_flush_tid(sc, txtid);
 }
 
+bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an)
+{
+	struct ath_atx_tid *tid;
+	struct ath_atx_ac *ac;
+	struct ath_txq *txq;
+	bool buffered = false;
+	int tidno;
+
+	for (tidno = 0, tid = &an->tid[tidno];
+	     tidno < WME_NUM_TID; tidno++, tid++) {
+
+		if (!tid->sched)
+			continue;
+
+		ac = tid->ac;
+		txq = ac->txq;
+
+		spin_lock_bh(&txq->axq_lock);
+
+		if (!list_empty(&tid->buf_q))
+			buffered = true;
+
+		tid->sched = false;
+		list_del(&tid->list);
+
+		if (ac->sched) {
+			ac->sched = false;
+			list_del(&ac->list);
+		}
+
+		spin_unlock_bh(&txq->axq_lock);
+	}
+
+	return buffered;
+}
+
+void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
+{
+	struct ath_atx_tid *tid;
+	struct ath_atx_ac *ac;
+	struct ath_txq *txq;
+	int tidno;
+
+	for (tidno = 0, tid = &an->tid[tidno];
+	     tidno < WME_NUM_TID; tidno++, tid++) {
+
+		ac = tid->ac;
+		txq = ac->txq;
+
+		spin_lock_bh(&txq->axq_lock);
+		ac->clear_ps_filter = true;
+
+		if (!list_empty(&tid->buf_q) && !tid->paused) {
+			ath_tx_queue_tid(txq, tid);
+			ath_txq_schedule(sc, txq);
+		}
+
+		spin_unlock_bh(&txq->axq_lock);
+	}
+}
+
 void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
 {
 	struct ath_atx_tid *txtid;
@@ -1451,7 +1526,7 @@
 	struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
 	struct ieee80211_hdr *hdr;
 	struct ath_frame_info *fi = get_frame_info(skb);
-	struct ath_node *an;
+	struct ath_node *an = NULL;
 	struct ath_atx_tid *tid;
 	enum ath9k_key_type keytype;
 	u16 seqno = 0;
@@ -1459,11 +1534,13 @@
 
 	keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
 
+	if (sta)
+		an = (struct ath_node *) sta->drv_priv;
+
 	hdr = (struct ieee80211_hdr *)skb->data;
-	if (sta && ieee80211_is_data_qos(hdr->frame_control) &&
+	if (an && ieee80211_is_data_qos(hdr->frame_control) &&
 		conf_is_ht(&hw->conf) && (sc->sc_flags & SC_OP_TXAGGR)) {
 
-		an = (struct ath_node *) sta->drv_priv;
 		tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
 
 		/*
@@ -1479,6 +1556,8 @@
 	memset(fi, 0, sizeof(*fi));
 	if (hw_key)
 		fi->keyix = hw_key->hw_key_idx;
+	else if (an && ieee80211_is_data(hdr->frame_control) && an->ps_key > 0)
+		fi->keyix = an->ps_key;
 	else
 		fi->keyix = ATH9K_TXKEYIX_INVALID;
 	fi->keytype = keytype;
@@ -1491,7 +1570,6 @@
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 	int flags = 0;
 
-	flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
 	flags |= ATH9K_TXDESC_INTREQ;
 
 	if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
@@ -1754,6 +1832,9 @@
 		if (txctl->paprd)
 			bf->bf_state.bfs_paprd_timestamp = jiffies;
 
+		if (tx_info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
+			ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true);
+
 		ath_tx_send_normal(sc, txctl->txq, tid, &bf_head);
 	}
 
diff --git a/drivers/net/wireless/ath/key.c b/drivers/net/wireless/ath/key.c
index 0d4f39c..a61ef3d6 100644
--- a/drivers/net/wireless/ath/key.c
+++ b/drivers/net/wireless/ath/key.c
@@ -483,6 +483,9 @@
 	memset(&hk, 0, sizeof(hk));
 
 	switch (key->cipher) {
+	case 0:
+		hk.kv_type = ATH_CIPHER_CLR;
+		break;
 	case WLAN_CIPHER_SUITE_WEP40:
 	case WLAN_CIPHER_SUITE_WEP104:
 		hk.kv_type = ATH_CIPHER_WEP;
@@ -498,7 +501,8 @@
 	}
 
 	hk.kv_len = key->keylen;
-	memcpy(hk.kv_val, key->key, key->keylen);
+	if (key->keylen)
+		memcpy(hk.kv_val, key->key, key->keylen);
 
 	if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
 		switch (vif->type) {
diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c
index 0e1b879..028310f 100644
--- a/drivers/net/wireless/ath/regd.c
+++ b/drivers/net/wireless/ath/regd.c
@@ -97,8 +97,8 @@
 	}
 };
 
-/* Can be used by 0x67, 0x6A and 0x68 */
-static const struct ieee80211_regdomain ath_world_regdom_67_68_6A = {
+/* Can be used by 0x67, 0x68, 0x6A and 0x6C */
+static const struct ieee80211_regdomain ath_world_regdom_67_68_6A_6C = {
 	.n_reg_rules = 4,
 	.alpha2 =  "99",
 	.reg_rules = {
@@ -151,7 +151,8 @@
 	case 0x67:
 	case 0x68:
 	case 0x6A:
-		return &ath_world_regdom_67_68_6A;
+	case 0x6C:
+		return &ath_world_regdom_67_68_6A_6C;
 	default:
 		WARN_ON(1);
 		return ath_default_world_regdomain();
@@ -333,6 +334,7 @@
 	case 0x63:
 	case 0x66:
 	case 0x67:
+	case 0x6C:
 		ath_reg_apply_beaconing_flags(wiphy, initiator);
 		break;
 	case 0x68:
diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h
index 5c2cfe6..24b5383 100644
--- a/drivers/net/wireless/ath/regd_common.h
+++ b/drivers/net/wireless/ath/regd_common.h
@@ -86,6 +86,7 @@
 	WOR9_WORLD = 0x69,
 	WORA_WORLD = 0x6A,
 	WORB_WORLD = 0x6B,
+	WORC_WORLD = 0x6C,
 
 	MKK3_MKKB = 0x80,
 	MKK3_MKKA2 = 0x81,
@@ -282,6 +283,7 @@
 	{WOR9_WORLD, NO_CTL, NO_CTL},
 	{WORA_WORLD, NO_CTL, NO_CTL},
 	{WORB_WORLD, NO_CTL, NO_CTL},
+	{WORC_WORLD, NO_CTL, NO_CTL},
 };
 
 static struct country_code_to_enum_rd allCountries[] = {
diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-rs.c b/drivers/net/wireless/iwlegacy/iwl-4965-rs.c
index 31ac672..8950939 100644
--- a/drivers/net/wireless/iwlegacy/iwl-4965-rs.c
+++ b/drivers/net/wireless/iwlegacy/iwl-4965-rs.c
@@ -2860,7 +2860,6 @@
 
 int iwl4965_rate_control_register(void)
 {
-	pr_err("Registering 4965 rate control operations\n");
 	return ieee80211_rate_control_register(&rs_4965_ops);
 }
 
diff --git a/drivers/net/wireless/iwlegacy/iwl4965-base.c b/drivers/net/wireless/iwlegacy/iwl4965-base.c
index d484c36..f887054 100644
--- a/drivers/net/wireless/iwlegacy/iwl4965-base.c
+++ b/drivers/net/wireless/iwlegacy/iwl4965-base.c
@@ -3173,7 +3173,7 @@
 {
 	priv->hw_rev = _iwl_legacy_read32(priv, CSR_HW_REV);
 	priv->hw_wa_rev = _iwl_legacy_read32(priv, CSR_HW_REV_WA_REG);
-	pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &priv->rev_id);
+	priv->rev_id = priv->pci_dev->revision;
 	IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", priv->rev_id);
 }
 
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index 3652931..bb6a737 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -1,6 +1,6 @@
 # AGN
 obj-$(CONFIG_IWLAGN)	+= iwlagn.o
-iwlagn-objs		:= iwl-agn.o iwl-agn-rs.o iwl-agn-led.o
+iwlagn-objs		:= iwl-agn.o iwl-agn-rs.o
 iwlagn-objs		+= iwl-agn-ucode.o iwl-agn-tx.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
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index 1b27992..baf8011 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -45,7 +45,6 @@
 #include "iwl-agn.h"
 #include "iwl-helpers.h"
 #include "iwl-agn-hw.h"
-#include "iwl-agn-led.h"
 #include "iwl-agn-debugfs.h"
 
 /* Highest firmware API version supported */
@@ -57,12 +56,10 @@
 #define IWL100_UCODE_API_MIN 5
 
 #define IWL1000_FW_PRE "iwlwifi-1000-"
-#define _IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE #api ".ucode"
-#define IWL1000_MODULE_FIRMWARE(api) _IWL1000_MODULE_FIRMWARE(api)
+#define IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE #api ".ucode"
 
 #define IWL100_FW_PRE "iwlwifi-100-"
-#define _IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE #api ".ucode"
-#define IWL100_MODULE_FIRMWARE(api) _IWL100_MODULE_FIRMWARE(api)
+#define IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE #api ".ucode"
 
 
 /*
@@ -184,10 +181,6 @@
 	.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,
-	.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,
 	.send_tx_power = iwlagn_send_tx_power,
 	.update_chain_flags = iwl_update_chain_flags,
 	.apm_ops = {
@@ -202,7 +195,7 @@
 			EEPROM_REG_BAND_4_CHANNELS,
 			EEPROM_REG_BAND_5_CHANNELS,
 			EEPROM_REG_BAND_24_HT40_CHANNELS,
-			EEPROM_REG_BAND_52_HT40_CHANNELS
+			EEPROM_REGULATORY_BAND_NO_HT40,
 		},
 		.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
 		.release_semaphore = iwlcore_eeprom_release_semaphore,
@@ -221,19 +214,12 @@
 	},
 	.txfifo_flush = iwlagn_txfifo_flush,
 	.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
-	.tt_ops = {
-		.lower_power_detection = iwl_tt_is_low_power_state,
-		.tt_power_mode = iwl_tt_current_power_mode,
-		.ct_kill_check = iwl_check_for_ct_kill,
-	}
 };
 
 static const struct iwl_ops iwl1000_ops = {
 	.lib = &iwl1000_lib,
 	.hcmd = &iwlagn_hcmd,
 	.utils = &iwlagn_hcmd_utils,
-	.led = &iwlagn_led_ops,
-	.ieee80211_ops = &iwlagn_hw_ops,
 };
 
 static struct iwl_base_params iwl1000_base_params = {
@@ -241,7 +227,6 @@
 	.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
 	.eeprom_size = OTP_LOW_IMAGE_SIZE,
 	.pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
-	.set_l0s = true,
 	.max_ll_items = OTP_MAX_LL_ITEMS_1000,
 	.shadow_ram_support = false,
 	.led_compensation = 51,
@@ -251,9 +236,6 @@
 	.chain_noise_scale = 1000,
 	.wd_timeout = IWL_DEF_WD_TIMEOUT,
 	.max_event_log_size = 128,
-	.ucode_tracing = true,
-	.sensitivity_calib_by_driver = true,
-	.chain_noise_calib_by_driver = true,
 };
 static struct iwl_ht_params iwl1000_ht_params = {
 	.ht_greenfield_support = true,
diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c
index f602af4..e76e02c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-2000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-2000.c
@@ -46,7 +46,6 @@
 #include "iwl-helpers.h"
 #include "iwl-agn-hw.h"
 #include "iwl-6000-hw.h"
-#include "iwl-agn-led.h"
 #include "iwl-agn-debugfs.h"
 
 /* Highest firmware API version supported */
@@ -60,16 +59,13 @@
 #define IWL200_UCODE_API_MIN 5
 
 #define IWL2030_FW_PRE "iwlwifi-2030-"
-#define _IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE #api ".ucode"
-#define IWL2030_MODULE_FIRMWARE(api) _IWL2030_MODULE_FIRMWARE(api)
+#define IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE #api ".ucode"
 
 #define IWL2000_FW_PRE "iwlwifi-2000-"
-#define _IWL2000_MODULE_FIRMWARE(api) IWL2000_FW_PRE #api ".ucode"
-#define IWL2000_MODULE_FIRMWARE(api) _IWL2000_MODULE_FIRMWARE(api)
+#define IWL2000_MODULE_FIRMWARE(api) IWL2000_FW_PRE #api ".ucode"
 
 #define IWL200_FW_PRE "iwlwifi-200-"
-#define _IWL200_MODULE_FIRMWARE(api) IWL200_FW_PRE #api ".ucode"
-#define IWL200_MODULE_FIRMWARE(api) _IWL200_MODULE_FIRMWARE(api)
+#define IWL200_MODULE_FIRMWARE(api) IWL200_FW_PRE #api ".ucode"
 
 static void iwl2000_set_ct_threshold(struct iwl_priv *priv)
 {
@@ -101,6 +97,8 @@
 		iwl_set_bit(priv, CSR_GP_DRIVER_REG,
 			    CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER);
 
+	if (priv->cfg->disable_otp_refresh)
+		iwl_write_prph(priv, APMG_ANALOG_SVR_REG, 0x80000010);
 }
 
 static struct iwl_sensitivity_ranges iwl2000_sensitivity = {
@@ -265,10 +263,6 @@
 	.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,
-	.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,
 	.send_tx_power = iwlagn_send_tx_power,
 	.update_chain_flags = iwl_update_chain_flags,
 	.set_channel_switch = iwl2030_hw_channel_switch,
@@ -284,7 +278,7 @@
 			EEPROM_REG_BAND_4_CHANNELS,
 			EEPROM_REG_BAND_5_CHANNELS,
 			EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
-			EEPROM_REG_BAND_52_HT40_CHANNELS
+			EEPROM_REGULATORY_BAND_NO_HT40,
 		},
 		.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
 		.release_semaphore = iwlcore_eeprom_release_semaphore,
@@ -304,43 +298,30 @@
 	},
 	.txfifo_flush = iwlagn_txfifo_flush,
 	.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
-	.tt_ops = {
-		.lower_power_detection = iwl_tt_is_low_power_state,
-		.tt_power_mode = iwl_tt_current_power_mode,
-		.ct_kill_check = iwl_check_for_ct_kill,
-	}
 };
 
 static const struct iwl_ops iwl2000_ops = {
 	.lib = &iwl2000_lib,
 	.hcmd = &iwlagn_hcmd,
 	.utils = &iwlagn_hcmd_utils,
-	.led = &iwlagn_led_ops,
-	.ieee80211_ops = &iwlagn_hw_ops,
 };
 
 static const struct iwl_ops iwl2030_ops = {
 	.lib = &iwl2000_lib,
 	.hcmd = &iwlagn_bt_hcmd,
 	.utils = &iwlagn_hcmd_utils,
-	.led = &iwlagn_led_ops,
-	.ieee80211_ops = &iwlagn_hw_ops,
 };
 
 static const struct iwl_ops iwl200_ops = {
 	.lib = &iwl2000_lib,
 	.hcmd = &iwlagn_hcmd,
 	.utils = &iwlagn_hcmd_utils,
-	.led = &iwlagn_led_ops,
-	.ieee80211_ops = &iwlagn_hw_ops,
 };
 
 static const struct iwl_ops iwl230_ops = {
 	.lib = &iwl2000_lib,
 	.hcmd = &iwlagn_bt_hcmd,
 	.utils = &iwlagn_hcmd_utils,
-	.led = &iwlagn_led_ops,
-	.ieee80211_ops = &iwlagn_hw_ops,
 };
 
 static struct iwl_base_params iwl2000_base_params = {
@@ -348,7 +329,6 @@
 	.num_of_queues = IWLAGN_NUM_QUEUES,
 	.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
 	.pll_cfg_val = 0,
-	.set_l0s = true,
 	.max_ll_items = OTP_MAX_LL_ITEMS_2x00,
 	.shadow_ram_support = true,
 	.led_compensation = 51,
@@ -359,9 +339,6 @@
 	.chain_noise_scale = 1000,
 	.wd_timeout = IWL_DEF_WD_TIMEOUT,
 	.max_event_log_size = 512,
-	.ucode_tracing = true,
-	.sensitivity_calib_by_driver = true,
-	.chain_noise_calib_by_driver = true,
 	.shadow_reg_enable = true,
 };
 
@@ -371,7 +348,6 @@
 	.num_of_queues = IWLAGN_NUM_QUEUES,
 	.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
 	.pll_cfg_val = 0,
-	.set_l0s = true,
 	.max_ll_items = OTP_MAX_LL_ITEMS_2x00,
 	.shadow_ram_support = true,
 	.led_compensation = 57,
@@ -382,9 +358,6 @@
 	.chain_noise_scale = 1000,
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
 	.max_event_log_size = 512,
-	.ucode_tracing = true,
-	.sensitivity_calib_by_driver = true,
-	.chain_noise_calib_by_driver = true,
 	.shadow_reg_enable = true,
 };
 
@@ -394,7 +367,6 @@
 };
 
 static struct iwl_bt_params iwl2030_bt_params = {
-	.bt_statistics = true,
 	/* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
 	.advanced_bt_coexist = true,
 	.agg_time_limit = BT_AGG_THRESHOLD_DEF,
@@ -416,7 +388,8 @@
 	.need_dc_calib = true,					\
 	.need_temp_offset_calib = true,				\
 	.led_mode = IWL_LED_RF_STATE,				\
-	.iq_invert = true					\
+	.iq_invert = true,					\
+	.disable_otp_refresh = true				\
 
 struct iwl_cfg iwl2000_2bgn_cfg = {
 	.name = "2000 Series 2x2 BGN",
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index 66f5fe8..655afc1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -45,7 +45,6 @@
 #include "iwl-sta.h"
 #include "iwl-helpers.h"
 #include "iwl-agn.h"
-#include "iwl-agn-led.h"
 #include "iwl-agn-hw.h"
 #include "iwl-5000-hw.h"
 #include "iwl-agn-debugfs.h"
@@ -59,12 +58,10 @@
 #define IWL5150_UCODE_API_MIN 1
 
 #define IWL5000_FW_PRE "iwlwifi-5000-"
-#define _IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE #api ".ucode"
-#define IWL5000_MODULE_FIRMWARE(api) _IWL5000_MODULE_FIRMWARE(api)
+#define IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE #api ".ucode"
 
 #define IWL5150_FW_PRE "iwlwifi-5150-"
-#define _IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE #api ".ucode"
-#define IWL5150_MODULE_FIRMWARE(api) _IWL5150_MODULE_FIRMWARE(api)
+#define IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE #api ".ucode"
 
 /* NIC configuration for 5000 series */
 static void iwl5000_nic_config(struct iwl_priv *priv)
@@ -261,7 +258,7 @@
 	u32 vt = 0;
 	s32 offset =  iwl_temp_calib_to_offset(priv);
 
-	vt = le32_to_cpu(priv->_agn.statistics.general.common.temperature);
+	vt = le32_to_cpu(priv->statistics.common.temperature);
 	vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset;
 	/* now vt hold the temperature in Kelvin */
 	priv->temperature = KELVIN_TO_CELSIUS(vt);
@@ -352,10 +349,6 @@
 	.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,
-	.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,
 	.send_tx_power = iwlagn_send_tx_power,
 	.update_chain_flags = iwl_update_chain_flags,
 	.set_channel_switch = iwl5000_hw_channel_switch,
@@ -390,11 +383,6 @@
 	},
 	.txfifo_flush = iwlagn_txfifo_flush,
 	.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
-	.tt_ops = {
-		.lower_power_detection = iwl_tt_is_low_power_state,
-		.tt_power_mode = iwl_tt_current_power_mode,
-		.ct_kill_check = iwl_check_for_ct_kill,
-	}
 };
 
 static struct iwl_lib_ops iwl5150_lib = {
@@ -408,9 +396,6 @@
 	.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,
-	.dump_nic_event_log = iwl_dump_nic_event_log,
-	.dump_nic_error_log = iwl_dump_nic_error_log,
-	.dump_csr = iwl_dump_csr,
 	.send_tx_power = iwlagn_send_tx_power,
 	.update_chain_flags = iwl_update_chain_flags,
 	.set_channel_switch = iwl5000_hw_channel_switch,
@@ -445,27 +430,18 @@
 	},
 	.txfifo_flush = iwlagn_txfifo_flush,
 	.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
-	.tt_ops = {
-		.lower_power_detection = iwl_tt_is_low_power_state,
-		.tt_power_mode = iwl_tt_current_power_mode,
-		.ct_kill_check = iwl_check_for_ct_kill,
-	}
 };
 
 static const struct iwl_ops iwl5000_ops = {
 	.lib = &iwl5000_lib,
 	.hcmd = &iwlagn_hcmd,
 	.utils = &iwlagn_hcmd_utils,
-	.led = &iwlagn_led_ops,
-	.ieee80211_ops = &iwlagn_hw_ops,
 };
 
 static const struct iwl_ops iwl5150_ops = {
 	.lib = &iwl5150_lib,
 	.hcmd = &iwlagn_hcmd,
 	.utils = &iwlagn_hcmd_utils,
-	.led = &iwlagn_led_ops,
-	.ieee80211_ops = &iwlagn_hw_ops,
 };
 
 static struct iwl_base_params iwl5000_base_params = {
@@ -473,16 +449,12 @@
 	.num_of_queues = IWLAGN_NUM_QUEUES,
 	.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
 	.pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
-	.set_l0s = true,
 	.led_compensation = 51,
 	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
 	.chain_noise_scale = 1000,
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
 	.max_event_log_size = 512,
-	.ucode_tracing = true,
-	.sensitivity_calib_by_driver = true,
-	.chain_noise_calib_by_driver = true,
 };
 static struct iwl_ht_params iwl5000_ht_params = {
 	.ht_greenfield_support = true,
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index 24d105b..905eb57 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -46,7 +46,6 @@
 #include "iwl-helpers.h"
 #include "iwl-agn-hw.h"
 #include "iwl-6000-hw.h"
-#include "iwl-agn-led.h"
 #include "iwl-agn-debugfs.h"
 
 /* Highest firmware API version supported */
@@ -60,20 +59,16 @@
 #define IWL6000G2_UCODE_API_MIN 4
 
 #define IWL6000_FW_PRE "iwlwifi-6000-"
-#define _IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE #api ".ucode"
-#define IWL6000_MODULE_FIRMWARE(api) _IWL6000_MODULE_FIRMWARE(api)
+#define IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE #api ".ucode"
 
 #define IWL6050_FW_PRE "iwlwifi-6050-"
-#define _IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE #api ".ucode"
-#define IWL6050_MODULE_FIRMWARE(api) _IWL6050_MODULE_FIRMWARE(api)
+#define IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE #api ".ucode"
 
 #define IWL6005_FW_PRE "iwlwifi-6000g2a-"
-#define _IWL6005_MODULE_FIRMWARE(api) IWL6005_FW_PRE #api ".ucode"
-#define IWL6005_MODULE_FIRMWARE(api) _IWL6005_MODULE_FIRMWARE(api)
+#define IWL6005_MODULE_FIRMWARE(api) IWL6005_FW_PRE #api ".ucode"
 
 #define IWL6030_FW_PRE "iwlwifi-6000g2b-"
-#define _IWL6030_MODULE_FIRMWARE(api) IWL6030_FW_PRE #api ".ucode"
-#define IWL6030_MODULE_FIRMWARE(api) _IWL6030_MODULE_FIRMWARE(api)
+#define IWL6030_MODULE_FIRMWARE(api) IWL6030_FW_PRE #api ".ucode"
 
 static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
 {
@@ -293,10 +288,6 @@
 	.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,
-	.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,
 	.send_tx_power = iwlagn_send_tx_power,
 	.update_chain_flags = iwl_update_chain_flags,
 	.set_channel_switch = iwl6000_hw_channel_switch,
@@ -332,11 +323,6 @@
 	},
 	.txfifo_flush = iwlagn_txfifo_flush,
 	.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
-	.tt_ops = {
-		.lower_power_detection = iwl_tt_is_low_power_state,
-		.tt_power_mode = iwl_tt_current_power_mode,
-		.ct_kill_check = iwl_check_for_ct_kill,
-	}
 };
 
 static struct iwl_lib_ops iwl6030_lib = {
@@ -351,10 +337,6 @@
 	.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,
-	.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,
 	.send_tx_power = iwlagn_send_tx_power,
 	.update_chain_flags = iwl_update_chain_flags,
 	.set_channel_switch = iwl6000_hw_channel_switch,
@@ -390,11 +372,6 @@
 	},
 	.txfifo_flush = iwlagn_txfifo_flush,
 	.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
-	.tt_ops = {
-		.lower_power_detection = iwl_tt_is_low_power_state,
-		.tt_power_mode = iwl_tt_current_power_mode,
-		.ct_kill_check = iwl_check_for_ct_kill,
-	}
 };
 
 static struct iwl_nic_ops iwl6050_nic_ops = {
@@ -409,34 +386,26 @@
 	.lib = &iwl6000_lib,
 	.hcmd = &iwlagn_hcmd,
 	.utils = &iwlagn_hcmd_utils,
-	.led = &iwlagn_led_ops,
-	.ieee80211_ops = &iwlagn_hw_ops,
 };
 
 static const struct iwl_ops iwl6050_ops = {
 	.lib = &iwl6000_lib,
 	.hcmd = &iwlagn_hcmd,
 	.utils = &iwlagn_hcmd_utils,
-	.led = &iwlagn_led_ops,
 	.nic = &iwl6050_nic_ops,
-	.ieee80211_ops = &iwlagn_hw_ops,
 };
 
 static const struct iwl_ops iwl6150_ops = {
 	.lib = &iwl6000_lib,
 	.hcmd = &iwlagn_hcmd,
 	.utils = &iwlagn_hcmd_utils,
-	.led = &iwlagn_led_ops,
 	.nic = &iwl6150_nic_ops,
-	.ieee80211_ops = &iwlagn_hw_ops,
 };
 
 static const struct iwl_ops iwl6030_ops = {
 	.lib = &iwl6030_lib,
 	.hcmd = &iwlagn_bt_hcmd,
 	.utils = &iwlagn_hcmd_utils,
-	.led = &iwlagn_led_ops,
-	.ieee80211_ops = &iwlagn_hw_ops,
 };
 
 static struct iwl_base_params iwl6000_base_params = {
@@ -444,7 +413,6 @@
 	.num_of_queues = IWLAGN_NUM_QUEUES,
 	.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
 	.pll_cfg_val = 0,
-	.set_l0s = true,
 	.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
 	.shadow_ram_support = true,
 	.led_compensation = 51,
@@ -455,9 +423,6 @@
 	.chain_noise_scale = 1000,
 	.wd_timeout = IWL_DEF_WD_TIMEOUT,
 	.max_event_log_size = 512,
-	.ucode_tracing = true,
-	.sensitivity_calib_by_driver = true,
-	.chain_noise_calib_by_driver = true,
 	.shadow_reg_enable = true,
 };
 
@@ -466,7 +431,6 @@
 	.num_of_queues = IWLAGN_NUM_QUEUES,
 	.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
 	.pll_cfg_val = 0,
-	.set_l0s = true,
 	.max_ll_items = OTP_MAX_LL_ITEMS_6x50,
 	.shadow_ram_support = true,
 	.led_compensation = 51,
@@ -477,9 +441,6 @@
 	.chain_noise_scale = 1500,
 	.wd_timeout = IWL_DEF_WD_TIMEOUT,
 	.max_event_log_size = 1024,
-	.ucode_tracing = true,
-	.sensitivity_calib_by_driver = true,
-	.chain_noise_calib_by_driver = true,
 	.shadow_reg_enable = true,
 };
 static struct iwl_base_params iwl6000_g2_base_params = {
@@ -487,7 +448,6 @@
 	.num_of_queues = IWLAGN_NUM_QUEUES,
 	.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
 	.pll_cfg_val = 0,
-	.set_l0s = true,
 	.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
 	.shadow_ram_support = true,
 	.led_compensation = 57,
@@ -498,9 +458,6 @@
 	.chain_noise_scale = 1000,
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
 	.max_event_log_size = 512,
-	.ucode_tracing = true,
-	.sensitivity_calib_by_driver = true,
-	.chain_noise_calib_by_driver = true,
 	.shadow_reg_enable = true,
 };
 
@@ -510,7 +467,6 @@
 };
 
 static struct iwl_bt_params iwl6000_bt_params = {
-	.bt_statistics = true,
 	/* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
 	.advanced_bt_coexist = true,
 	.agg_time_limit = BT_AGG_THRESHOLD_DEF,
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
index 7b761de..0f6bb9b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
@@ -605,7 +605,7 @@
 	IWL_DEBUG_CALIB(priv, "<<return 0x%X\n", ret);
 }
 
-void iwl_sensitivity_calibration(struct iwl_priv *priv, void *resp)
+void iwl_sensitivity_calibration(struct iwl_priv *priv)
 {
 	u32 rx_enable_time;
 	u32 fa_cck;
@@ -631,16 +631,9 @@
 	}
 
 	spin_lock_irqsave(&priv->lock, flags);
-	if (iwl_bt_statistics(priv)) {
-		rx_info = &(((struct iwl_bt_notif_statistics *)resp)->
-			      rx.general.common);
-		ofdm = &(((struct iwl_bt_notif_statistics *)resp)->rx.ofdm);
-		cck = &(((struct iwl_bt_notif_statistics *)resp)->rx.cck);
-	} else {
-		rx_info = &(((struct iwl_notif_statistics *)resp)->rx.general);
-		ofdm = &(((struct iwl_notif_statistics *)resp)->rx.ofdm);
-		cck = &(((struct iwl_notif_statistics *)resp)->rx.cck);
-	}
+	rx_info = &priv->statistics.rx_non_phy;
+	ofdm = &priv->statistics.rx_ofdm;
+	cck = &priv->statistics.rx_cck;
 	if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
 		IWL_DEBUG_CALIB(priv, "<< invalid data.\n");
 		spin_unlock_irqrestore(&priv->lock, flags);
@@ -851,7 +844,7 @@
  * 1)  Which antennas are connected.
  * 2)  Differential rx gain settings to balance the 3 receivers.
  */
-void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
+void iwl_chain_noise_calibration(struct iwl_priv *priv)
 {
 	struct iwl_chain_noise_data *data = NULL;
 
@@ -896,13 +889,9 @@
 	}
 
 	spin_lock_irqsave(&priv->lock, flags);
-	if (iwl_bt_statistics(priv)) {
-		rx_info = &(((struct iwl_bt_notif_statistics *)stat_resp)->
-			      rx.general.common);
-	} else {
-		rx_info = &(((struct iwl_notif_statistics *)stat_resp)->
-			      rx.general);
-	}
+
+	rx_info = &priv->statistics.rx_non_phy;
+
 	if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
 		IWL_DEBUG_CALIB(priv, " << Interference data unavailable\n");
 		spin_unlock_irqrestore(&priv->lock, flags);
@@ -911,19 +900,9 @@
 
 	rxon_band24 = !!(ctx->staging.flags & RXON_FLG_BAND_24G_MSK);
 	rxon_chnum = le16_to_cpu(ctx->staging.channel);
-	if (iwl_bt_statistics(priv)) {
-		stat_band24 = !!(((struct iwl_bt_notif_statistics *)
-				 stat_resp)->flag &
-				 STATISTICS_REPLY_FLG_BAND_24G_MSK);
-		stat_chnum = le32_to_cpu(((struct iwl_bt_notif_statistics *)
-					 stat_resp)->flag) >> 16;
-	} else {
-		stat_band24 = !!(((struct iwl_notif_statistics *)
-				 stat_resp)->flag &
-				 STATISTICS_REPLY_FLG_BAND_24G_MSK);
-		stat_chnum = le32_to_cpu(((struct iwl_notif_statistics *)
-					 stat_resp)->flag) >> 16;
-	}
+	stat_band24 =
+		!!(priv->statistics.flag & STATISTICS_REPLY_FLG_BAND_24G_MSK);
+	stat_chnum = le32_to_cpu(priv->statistics.flag) >> 16;
 
 	/* Make sure we accumulate data for just the associated channel
 	 *   (even if scanning). */
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.h b/drivers/net/wireless/iwlwifi/iwl-agn-calib.h
index ef4d507..4ef4dd9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.h
@@ -66,8 +66,8 @@
 #include "iwl-core.h"
 #include "iwl-commands.h"
 
-void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp);
-void iwl_sensitivity_calibration(struct iwl_priv *priv, void *resp);
+void iwl_chain_noise_calibration(struct iwl_priv *priv);
+void iwl_sensitivity_calibration(struct iwl_priv *priv);
 
 void iwl_init_sensitivity(struct iwl_priv *priv);
 void iwl_reset_run_time_calib(struct iwl_priv *priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c
index d1834aa..71a5f31 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c
@@ -39,10 +39,7 @@
 	int p = 0;
 	u32 flag;
 
-	if (iwl_bt_statistics(priv))
-		flag = le32_to_cpu(priv->_agn.statistics_bt.flag);
-	else
-		flag = le32_to_cpu(priv->_agn.statistics.flag);
+	flag = le32_to_cpu(priv->statistics.flag);
 
 	p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n", flag);
 	if (flag & UCODE_STATISTICS_CLEAR_MSK)
@@ -88,43 +85,22 @@
 	 * the last statistics notification from uCode
 	 * might not reflect the current uCode activity
 	 */
-	if (iwl_bt_statistics(priv)) {
-		ofdm = &priv->_agn.statistics_bt.rx.ofdm;
-		cck = &priv->_agn.statistics_bt.rx.cck;
-		general = &priv->_agn.statistics_bt.rx.general.common;
-		ht = &priv->_agn.statistics_bt.rx.ofdm_ht;
-		accum_ofdm = &priv->_agn.accum_statistics_bt.rx.ofdm;
-		accum_cck = &priv->_agn.accum_statistics_bt.rx.cck;
-		accum_general =
-			&priv->_agn.accum_statistics_bt.rx.general.common;
-		accum_ht = &priv->_agn.accum_statistics_bt.rx.ofdm_ht;
-		delta_ofdm = &priv->_agn.delta_statistics_bt.rx.ofdm;
-		delta_cck = &priv->_agn.delta_statistics_bt.rx.cck;
-		delta_general =
-			&priv->_agn.delta_statistics_bt.rx.general.common;
-		delta_ht = &priv->_agn.delta_statistics_bt.rx.ofdm_ht;
-		max_ofdm = &priv->_agn.max_delta_bt.rx.ofdm;
-		max_cck = &priv->_agn.max_delta_bt.rx.cck;
-		max_general = &priv->_agn.max_delta_bt.rx.general.common;
-		max_ht = &priv->_agn.max_delta_bt.rx.ofdm_ht;
-	} else {
-		ofdm = &priv->_agn.statistics.rx.ofdm;
-		cck = &priv->_agn.statistics.rx.cck;
-		general = &priv->_agn.statistics.rx.general;
-		ht = &priv->_agn.statistics.rx.ofdm_ht;
-		accum_ofdm = &priv->_agn.accum_statistics.rx.ofdm;
-		accum_cck = &priv->_agn.accum_statistics.rx.cck;
-		accum_general = &priv->_agn.accum_statistics.rx.general;
-		accum_ht = &priv->_agn.accum_statistics.rx.ofdm_ht;
-		delta_ofdm = &priv->_agn.delta_statistics.rx.ofdm;
-		delta_cck = &priv->_agn.delta_statistics.rx.cck;
-		delta_general = &priv->_agn.delta_statistics.rx.general;
-		delta_ht = &priv->_agn.delta_statistics.rx.ofdm_ht;
-		max_ofdm = &priv->_agn.max_delta.rx.ofdm;
-		max_cck = &priv->_agn.max_delta.rx.cck;
-		max_general = &priv->_agn.max_delta.rx.general;
-		max_ht = &priv->_agn.max_delta.rx.ofdm_ht;
-	}
+	ofdm = &priv->statistics.rx_ofdm;
+	cck = &priv->statistics.rx_cck;
+	general = &priv->statistics.rx_non_phy;
+	ht = &priv->statistics.rx_ofdm_ht;
+	accum_ofdm = &priv->accum_stats.rx_ofdm;
+	accum_cck = &priv->accum_stats.rx_cck;
+	accum_general = &priv->accum_stats.rx_non_phy;
+	accum_ht = &priv->accum_stats.rx_ofdm_ht;
+	delta_ofdm = &priv->delta_stats.rx_ofdm;
+	delta_cck = &priv->delta_stats.rx_cck;
+	delta_general = &priv->delta_stats.rx_non_phy;
+	delta_ht = &priv->delta_stats.rx_ofdm_ht;
+	max_ofdm = &priv->max_delta_stats.rx_ofdm;
+	max_cck = &priv->max_delta_stats.rx_cck;
+	max_general = &priv->max_delta_stats.rx_non_phy;
+	max_ht = &priv->max_delta_stats.rx_ofdm_ht;
 
 	pos += iwl_statistics_flag(priv, buf, bufsz);
 	pos += scnprintf(buf + pos, bufsz - pos,
@@ -531,20 +507,13 @@
 	}
 
 	/* the statistic information display here is based on
-	  * the last statistics notification from uCode
-	  * might not reflect the current uCode activity
-	  */
-	if (iwl_bt_statistics(priv)) {
-		tx = &priv->_agn.statistics_bt.tx;
-		accum_tx = &priv->_agn.accum_statistics_bt.tx;
-		delta_tx = &priv->_agn.delta_statistics_bt.tx;
-		max_tx = &priv->_agn.max_delta_bt.tx;
-	} else {
-		tx = &priv->_agn.statistics.tx;
-		accum_tx = &priv->_agn.accum_statistics.tx;
-		delta_tx = &priv->_agn.delta_statistics.tx;
-		max_tx = &priv->_agn.max_delta.tx;
-	}
+	 * the last statistics notification from uCode
+	 * might not reflect the current uCode activity
+	 */
+	tx = &priv->statistics.tx;
+	accum_tx = &priv->accum_stats.tx;
+	delta_tx = &priv->delta_stats.tx;
+	max_tx = &priv->max_delta_stats.tx;
 
 	pos += iwl_statistics_flag(priv, buf, bufsz);
 	pos += scnprintf(buf + pos, bufsz - pos,
@@ -731,36 +700,21 @@
 	}
 
 	/* the statistic information display here is based on
-	  * the last statistics notification from uCode
-	  * might not reflect the current uCode activity
-	  */
-	if (iwl_bt_statistics(priv)) {
-		general = &priv->_agn.statistics_bt.general.common;
-		dbg = &priv->_agn.statistics_bt.general.common.dbg;
-		div = &priv->_agn.statistics_bt.general.common.div;
-		accum_general = &priv->_agn.accum_statistics_bt.general.common;
-		accum_dbg = &priv->_agn.accum_statistics_bt.general.common.dbg;
-		accum_div = &priv->_agn.accum_statistics_bt.general.common.div;
-		delta_general = &priv->_agn.delta_statistics_bt.general.common;
-		max_general = &priv->_agn.max_delta_bt.general.common;
-		delta_dbg = &priv->_agn.delta_statistics_bt.general.common.dbg;
-		max_dbg = &priv->_agn.max_delta_bt.general.common.dbg;
-		delta_div = &priv->_agn.delta_statistics_bt.general.common.div;
-		max_div = &priv->_agn.max_delta_bt.general.common.div;
-	} else {
-		general = &priv->_agn.statistics.general.common;
-		dbg = &priv->_agn.statistics.general.common.dbg;
-		div = &priv->_agn.statistics.general.common.div;
-		accum_general = &priv->_agn.accum_statistics.general.common;
-		accum_dbg = &priv->_agn.accum_statistics.general.common.dbg;
-		accum_div = &priv->_agn.accum_statistics.general.common.div;
-		delta_general = &priv->_agn.delta_statistics.general.common;
-		max_general = &priv->_agn.max_delta.general.common;
-		delta_dbg = &priv->_agn.delta_statistics.general.common.dbg;
-		max_dbg = &priv->_agn.max_delta.general.common.dbg;
-		delta_div = &priv->_agn.delta_statistics.general.common.div;
-		max_div = &priv->_agn.max_delta.general.common.div;
-	}
+	 * the last statistics notification from uCode
+	 * might not reflect the current uCode activity
+	 */
+	general = &priv->statistics.common;
+	dbg = &priv->statistics.common.dbg;
+	div = &priv->statistics.common.div;
+	accum_general = &priv->accum_stats.common;
+	accum_dbg = &priv->accum_stats.common.dbg;
+	accum_div = &priv->accum_stats.common.div;
+	delta_general = &priv->delta_stats.common;
+	max_general = &priv->max_delta_stats.common;
+	delta_dbg = &priv->delta_stats.common.dbg;
+	max_dbg = &priv->max_delta_stats.common.dbg;
+	delta_div = &priv->delta_stats.common.div;
+	max_div = &priv->max_delta_stats.common.div;
 
 	pos += iwl_statistics_flag(priv, buf, bufsz);
 	pos += scnprintf(buf + pos, bufsz - pos,
@@ -876,8 +830,8 @@
 	 * the last statistics notification from uCode
 	 * might not reflect the current uCode activity
 	 */
-	bt = &priv->_agn.statistics_bt.general.activity;
-	accum_bt = &priv->_agn.accum_statistics_bt.general.activity;
+	bt = &priv->statistics.bt_activity;
+	accum_bt = &priv->accum_stats.bt_activity;
 
 	pos += iwl_statistics_flag(priv, buf, bufsz);
 	pos += scnprintf(buf + pos, bufsz - pos, "Statistics_BT:\n");
@@ -918,10 +872,8 @@
 
 	pos += scnprintf(buf + pos, bufsz - pos,
 			 "(rx)num_bt_kills:\t\t%u\t\t\t%u\n",
-			 le32_to_cpu(priv->_agn.statistics_bt.rx.
-				general.num_bt_kills),
-			 priv->_agn.accum_statistics_bt.rx.
-				general.num_bt_kills);
+			 le32_to_cpu(priv->statistics.num_bt_kills),
+			 priv->statistics.accum_num_bt_kills);
 
 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 	kfree(buf);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-led.c b/drivers/net/wireless/iwlwifi/iwl-agn-led.c
deleted file mode 100644
index 4bb877e..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-agn-led.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/******************************************************************************
- *
- * 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
- * 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 <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/dma-mapping.h>
-#include <linux/delay.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/wireless.h>
-#include <net/mac80211.h>
-#include <linux/etherdevice.h>
-#include <asm/unaligned.h>
-
-#include "iwl-commands.h"
-#include "iwl-dev.h"
-#include "iwl-core.h"
-#include "iwl-io.h"
-#include "iwl-agn-led.h"
-
-/* Send led command */
-static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
-{
-	struct iwl_host_cmd cmd = {
-		.id = REPLY_LEDS_CMD,
-		.len = sizeof(struct iwl_led_cmd),
-		.data = led_cmd,
-		.flags = CMD_ASYNC,
-		.callback = NULL,
-	};
-	u32 reg;
-
-	reg = iwl_read32(priv, CSR_LED_REG);
-	if (reg != (reg & CSR_LED_BSM_CTRL_MSK))
-		iwl_write32(priv, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK);
-
-	return iwl_send_cmd(priv, &cmd);
-}
-
-/* Set led register off */
-void iwlagn_led_enable(struct iwl_priv *priv)
-{
-	iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
-}
-
-const struct iwl_led_ops iwlagn_led_ops = {
-	.cmd = iwl_send_led_cmd,
-};
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-led.h b/drivers/net/wireless/iwlwifi/iwl-agn-led.h
deleted file mode 100644
index c0b7611..0000000
--- a/drivers/net/wireless/iwlwifi/iwl-agn-led.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/******************************************************************************
- *
- * 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
- * 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
- *
- *****************************************************************************/
-
-#ifndef __iwl_agn_led_h__
-#define __iwl_agn_led_h__
-
-extern const struct iwl_led_ops iwlagn_led_ops;
-void iwlagn_led_enable(struct iwl_priv *priv);
-
-#endif /* __iwl_agn_led_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
index 9e47be6..e741128 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
@@ -172,6 +172,7 @@
 
 static void iwlagn_set_tx_status(struct iwl_priv *priv,
 				 struct ieee80211_tx_info *info,
+				 struct iwl_rxon_context *ctx,
 				 struct iwlagn_tx_resp *tx_resp,
 				 int txq_id, bool is_agg)
 {
@@ -186,6 +187,13 @@
 	if (!iwl_is_tx_success(status))
 		iwlagn_count_tx_err_status(priv, status);
 
+	if (status == TX_STATUS_FAIL_PASSIVE_NO_RX &&
+	    iwl_is_associated_ctx(ctx) && ctx->vif &&
+	    ctx->vif->type == NL80211_IFTYPE_STATION) {
+		ctx->last_tx_rejected = true;
+		iwl_stop_queue(priv, &priv->txq[txq_id]);
+	}
+
 	IWL_DEBUG_TX_REPLY(priv, "TXQ %d status %s (0x%08x) rate_n_flags "
 			   "0x%x retries %d\n",
 			   txq_id,
@@ -242,15 +250,16 @@
 
 	/* # frames attempted by Tx command */
 	if (agg->frame_count == 1) {
+		struct iwl_tx_info *txb;
+
 		/* Only one frame was attempted; no block-ack will arrive */
 		idx = start_idx;
 
 		IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, StartIdx=%d idx=%d\n",
 				   agg->frame_count, agg->start_idx, idx);
-		iwlagn_set_tx_status(priv,
-				     IEEE80211_SKB_CB(
-					priv->txq[txq_id].txb[idx].skb),
-				     tx_resp, txq_id, true);
+		txb = &priv->txq[txq_id].txb[idx];
+		iwlagn_set_tx_status(priv, IEEE80211_SKB_CB(txb->skb),
+				     txb->ctx, tx_resp, txq_id, true);
 		agg->wait_for_ba = 0;
 	} else {
 		/* Two or more frames were attempted; expect block-ack */
@@ -391,7 +400,8 @@
 	struct iwl_tx_queue *txq = &priv->txq[txq_id];
 	struct ieee80211_tx_info *info;
 	struct iwlagn_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
-	u32  status = le16_to_cpu(tx_resp->status.status);
+	struct iwl_tx_info *txb;
+	u32 status = le16_to_cpu(tx_resp->status.status);
 	int tid;
 	int sta_id;
 	int freed;
@@ -406,7 +416,8 @@
 	}
 
 	txq->time_stamp = jiffies;
-	info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb);
+	txb = &txq->txb[txq->q.read_ptr];
+	info = IEEE80211_SKB_CB(txb->skb);
 	memset(&info->status, 0, sizeof(info->status));
 
 	tid = (tx_resp->ra_tid & IWLAGN_TX_RES_TID_MSK) >>
@@ -450,12 +461,14 @@
 				iwl_wake_queue(priv, txq);
 		}
 	} else {
-		iwlagn_set_tx_status(priv, info, tx_resp, txq_id, false);
+		iwlagn_set_tx_status(priv, info, txb->ctx, tx_resp,
+				     txq_id, false);
 		freed = iwlagn_tx_queue_reclaim(priv, txq_id, index);
 		iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
 
 		if (priv->mac80211_registered &&
-		    (iwl_queue_space(&txq->q) > txq->q.low_mark))
+		    iwl_queue_space(&txq->q) > txq->q.low_mark &&
+		    status != TX_STATUS_FAIL_PASSIVE_NO_RX)
 			iwl_wake_queue(priv, txq);
 	}
 
@@ -482,8 +495,10 @@
 
 void iwlagn_setup_deferred_work(struct iwl_priv *priv)
 {
-	/* in agn, the tx power calibration is done in uCode */
-	priv->disable_tx_power_cal = 1;
+	/*
+	 * nothing need to be done here anymore
+	 * still keep for future use if needed
+	 */
 }
 
 int iwlagn_hw_valid_rtc_data_addr(u32 addr)
@@ -534,9 +549,7 @@
 void iwlagn_temperature(struct iwl_priv *priv)
 {
 	/* store temperature from correct statistics (in Celsius) */
-	priv->temperature = le32_to_cpu((iwl_bt_statistics(priv)) ?
-		priv->_agn.statistics_bt.general.common.temperature :
-		priv->_agn.statistics.general.common.temperature);
+	priv->temperature = le32_to_cpu(priv->statistics.common.temperature);
 	iwl_tt_handler(priv);
 }
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
index 69a2993..bdae82e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
@@ -83,7 +83,6 @@
 
 enum {
 	IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX,
-	IWL39_LAST_OFDM_RATE = IWL_RATE_54M_INDEX,
 	IWL_LAST_OFDM_RATE = IWL_RATE_60M_INDEX,
 	IWL_FIRST_CCK_RATE = IWL_RATE_1M_INDEX,
 	IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX,
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
index c335ee6..56f46ee 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
@@ -29,6 +29,7 @@
 #include "iwl-sta.h"
 #include "iwl-core.h"
 #include "iwl-agn-calib.h"
+#include "iwl-helpers.h"
 
 static int iwlagn_disable_bss(struct iwl_priv *priv,
 			      struct iwl_rxon_context *ctx,
@@ -600,6 +601,18 @@
 			priv->timestamp = bss_conf->timestamp;
 			ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
 		} else {
+			/*
+			 * If we disassociate while there are pending
+			 * frames, just wake up the queues and let the
+			 * frames "escape" ... This shouldn't really
+			 * be happening to start with, but we should
+			 * not get stuck in this case either since it
+			 * can happen if userspace gets confused.
+			 */
+			if (ctx->last_tx_rejected) {
+				ctx->last_tx_rejected = false;
+				iwl_wake_any_queue(priv, ctx);
+			}
 			ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 		}
 	}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
index 01a6d2f..5c30f6b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
@@ -428,6 +428,7 @@
 int iwlagn_alive_notify(struct iwl_priv *priv)
 {
 	const struct queue_to_fifo_ac *queue_to_fifo;
+	struct iwl_rxon_context *ctx;
 	u32 a;
 	unsigned long flags;
 	int i, chan;
@@ -501,6 +502,8 @@
 	memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped));
 	for (i = 0; i < 4; i++)
 		atomic_set(&priv->queue_stop_count[i], 0);
+	for_each_context(priv, ctx)
+		ctx->last_tx_rejected = false;
 
 	/* reset to 0 to enable all the queue first */
 	priv->txq_ctx_active_msk = 0;
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 60bfde7..cdeb09e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -59,7 +59,6 @@
 #include "iwl-sta.h"
 #include "iwl-agn-calib.h"
 #include "iwl-agn.h"
-#include "iwl-agn-led.h"
 
 
 /******************************************************************************
@@ -254,6 +253,10 @@
 	struct iwl_frame *frame;
 	unsigned int frame_size;
 	int rc;
+	struct iwl_host_cmd cmd = {
+		.id = REPLY_TX_BEACON,
+		.flags = CMD_SIZE_HUGE,
+	};
 
 	frame = iwl_get_free_frame(priv);
 	if (!frame) {
@@ -269,8 +272,10 @@
 		return -EINVAL;
 	}
 
-	rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size,
-			      &frame->u.cmd[0]);
+	cmd.len = frame_size;
+	cmd.data = &frame->u.cmd[0];
+
+	rc = iwl_send_cmd_sync(priv, &cmd);
 
 	iwl_free_frame(priv, frame);
 
@@ -395,7 +400,9 @@
 		return -EINVAL;
 	}
 
-	BUG_ON(addr & ~DMA_BIT_MASK(36));
+	if (WARN_ON(addr & ~DMA_BIT_MASK(36)))
+		return -EINVAL;
+
 	if (unlikely(addr & ~IWL_TX_DMA_MASK))
 		IWL_ERR(priv, "Unaligned address = %llx\n",
 			  (unsigned long long)addr);
@@ -719,7 +726,10 @@
 		/* If an RXB doesn't have a Rx queue slot associated with it,
 		 * then a bug has been introduced in the queue refilling
 		 * routines -- catch it here */
-		BUG_ON(rxb == NULL);
+		if (WARN_ON(rxb == NULL)) {
+			i = (i + 1) & RX_QUEUE_MASK;
+			continue;
+		}
 
 		rxq->queue[i] = NULL;
 
@@ -1481,7 +1491,7 @@
 					le32_to_cpup((__le32 *)tlv_data);
 			break;
 		default:
-			IWL_WARN(priv, "unknown TLV: %d\n", tlv_type);
+			IWL_DEBUG_INFO(priv, "unknown TLV: %d\n", tlv_type);
 			break;
 		}
 	}
@@ -1705,10 +1715,6 @@
 	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) */
@@ -2626,17 +2632,8 @@
 	}
 
 	if (priv->start_calib) {
-		if (iwl_bt_statistics(priv)) {
-			iwl_chain_noise_calibration(priv,
-					(void *)&priv->_agn.statistics_bt);
-			iwl_sensitivity_calibration(priv,
-					(void *)&priv->_agn.statistics_bt);
-		} else {
-			iwl_chain_noise_calibration(priv,
-					(void *)&priv->_agn.statistics);
-			iwl_sensitivity_calibration(priv,
-					(void *)&priv->_agn.statistics);
-		}
+		iwl_chain_noise_calibration(priv);
+		iwl_sensitivity_calibration(priv);
 	}
 
 	mutex_unlock(&priv->mutex);
@@ -2828,9 +2825,8 @@
 
 	hw->max_tx_aggregation_subframes = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
 
-	if (!priv->cfg->base_params->broken_powersave)
-		hw->flags |= IEEE80211_HW_SUPPORTS_PS |
-			     IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
+	hw->flags |= IEEE80211_HW_SUPPORTS_PS |
+		     IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
 
 	if (priv->cfg->sku & IWL_SKU_N)
 		hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
@@ -3732,6 +3728,28 @@
 	7, 6, 5, 4,
 };
 
+/* This function both allocates and initializes hw and priv. */
+static struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg)
+{
+	struct iwl_priv *priv;
+	/* mac80211 allocates memory for this device instance, including
+	 *   space for this driver's private structure */
+	struct ieee80211_hw *hw;
+
+	hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwlagn_hw_ops);
+	if (hw == NULL) {
+		pr_err("%s: Can not allocate network device\n",
+		       cfg->name);
+		goto out;
+	}
+
+	priv = hw->priv;
+	priv->hw = hw;
+
+out:
+	return hw;
+}
+
 static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	int err = 0, i;
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h
index 016b79e..078a23e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.h
@@ -173,8 +173,6 @@
 int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv);
 int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
 void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
-void iwl_dump_csr(struct iwl_priv *priv);
-int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display);
 
 /* rx */
 void iwlagn_rx_queue_restock(struct iwl_priv *priv);
@@ -222,6 +220,7 @@
 	case TX_STATUS_DIRECT_DONE:
 		return IEEE80211_TX_STAT_ACK;
 	case TX_STATUS_FAIL_DEST_PS:
+	case TX_STATUS_FAIL_PASSIVE_NO_RX:
 		return IEEE80211_TX_STAT_TX_FILTERED;
 	default:
 		return 0;
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index a1a5c1b..0edba8a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -2535,53 +2535,6 @@
 
 /* statistics command response */
 
-struct iwl39_statistics_rx_phy {
-	__le32 ina_cnt;
-	__le32 fina_cnt;
-	__le32 plcp_err;
-	__le32 crc32_err;
-	__le32 overrun_err;
-	__le32 early_overrun_err;
-	__le32 crc32_good;
-	__le32 false_alarm_cnt;
-	__le32 fina_sync_err_cnt;
-	__le32 sfd_timeout;
-	__le32 fina_timeout;
-	__le32 unresponded_rts;
-	__le32 rxe_frame_limit_overrun;
-	__le32 sent_ack_cnt;
-	__le32 sent_cts_cnt;
-} __packed;
-
-struct iwl39_statistics_rx_non_phy {
-	__le32 bogus_cts;	/* CTS received when not expecting CTS */
-	__le32 bogus_ack;	/* ACK received when not expecting ACK */
-	__le32 non_bssid_frames;	/* number of frames with BSSID that
-					 * doesn't belong to the STA BSSID */
-	__le32 filtered_frames;	/* count frames that were dumped in the
-				 * filtering process */
-	__le32 non_channel_beacons;	/* beacons with our bss id but not on
-					 * our serving channel */
-} __packed;
-
-struct iwl39_statistics_rx {
-	struct iwl39_statistics_rx_phy ofdm;
-	struct iwl39_statistics_rx_phy cck;
-	struct iwl39_statistics_rx_non_phy general;
-} __packed;
-
-struct iwl39_statistics_tx {
-	__le32 preamble_cnt;
-	__le32 rx_detected_cnt;
-	__le32 bt_prio_defer_cnt;
-	__le32 bt_prio_kill_cnt;
-	__le32 few_bytes_cnt;
-	__le32 cts_timeout;
-	__le32 ack_timeout;
-	__le32 expected_ack_cnt;
-	__le32 actual_ack_cnt;
-} __packed;
-
 struct statistics_dbg {
 	__le32 burst_check;
 	__le32 burst_count;
@@ -2589,23 +2542,6 @@
 	__le32 reserved[3];
 } __packed;
 
-struct iwl39_statistics_div {
-	__le32 tx_on_a;
-	__le32 tx_on_b;
-	__le32 exec_time;
-	__le32 probe_time;
-} __packed;
-
-struct iwl39_statistics_general {
-	__le32 temperature;
-	struct statistics_dbg dbg;
-	__le32 sleep_time;
-	__le32 slots_out;
-	__le32 slots_idle;
-	__le32 ttl_timestamp;
-	struct iwl39_statistics_div div;
-} __packed;
-
 struct statistics_rx_phy {
 	__le32 ina_cnt;
 	__le32 fina_cnt;
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 45ec5cf..885167f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -67,30 +67,6 @@
 
 const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
 
-
-/* This function both allocates and initializes hw and priv. */
-struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg)
-{
-	struct iwl_priv *priv;
-	/* mac80211 allocates memory for this device instance, including
-	 *   space for this driver's private structure */
-	struct ieee80211_hw *hw;
-
-	hw = ieee80211_alloc_hw(sizeof(struct iwl_priv),
-				cfg->ops->ieee80211_ops);
-	if (hw == NULL) {
-		pr_err("%s: Can not allocate network device\n",
-		       cfg->name);
-		goto out;
-	}
-
-	priv = hw->priv;
-	priv->hw = hw;
-
-out:
-	return hw;
-}
-
 #define MAX_BIT_RATE_40_MHZ 150 /* Mbps */
 #define MAX_BIT_RATE_20_MHZ 72 /* Mbps */
 static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
@@ -965,12 +941,10 @@
 	IWL_ERR(priv, "Loaded firmware version: %s\n",
 		priv->hw->wiphy->fw_version);
 
-	priv->cfg->ops->lib->dump_nic_error_log(priv);
-	if (priv->cfg->ops->lib->dump_csr)
-		priv->cfg->ops->lib->dump_csr(priv);
-	if (priv->cfg->ops->lib->dump_fh)
-		priv->cfg->ops->lib->dump_fh(priv, NULL, false);
-	priv->cfg->ops->lib->dump_nic_event_log(priv, false, NULL, false);
+	iwl_dump_nic_error_log(priv);
+	iwl_dump_csr(priv);
+	iwl_dump_fh(priv, NULL, false);
+	iwl_dump_nic_event_log(priv, false, NULL, false);
 #ifdef CONFIG_IWLWIFI_DEBUG
 	if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS)
 		iwl_print_rx_config_cmd(priv,
@@ -1051,7 +1025,6 @@
 	/*
 	 * Enable HAP INTA (interrupt from management bus) to
 	 * wake device's PCI Express link L1a -> L0s
-	 * NOTE:  This is no-op for 3945 (non-existent bit)
 	 */
 	iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
 				    CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A);
@@ -1064,20 +1037,18 @@
 	 * If not (unlikely), enable L0S, so there is at least some
 	 *    power savings, even without L1.
 	 */
-	if (priv->cfg->base_params->set_l0s) {
-		lctl = iwl_pcie_link_ctl(priv);
-		if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) ==
-					PCI_CFG_LINK_CTRL_VAL_L1_EN) {
-			/* L1-ASPM enabled; disable(!) L0S  */
-			iwl_set_bit(priv, CSR_GIO_REG,
-					CSR_GIO_REG_VAL_L0S_ENABLED);
-			IWL_DEBUG_POWER(priv, "L1 Enabled; Disabling L0S\n");
-		} else {
-			/* L1-ASPM disabled; enable(!) L0S */
-			iwl_clear_bit(priv, CSR_GIO_REG,
-					CSR_GIO_REG_VAL_L0S_ENABLED);
-			IWL_DEBUG_POWER(priv, "L1 Disabled; Enabling L0S\n");
-		}
+	lctl = iwl_pcie_link_ctl(priv);
+	if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) ==
+				PCI_CFG_LINK_CTRL_VAL_L1_EN) {
+		/* L1-ASPM enabled; disable(!) L0S  */
+		iwl_set_bit(priv, CSR_GIO_REG,
+				CSR_GIO_REG_VAL_L0S_ENABLED);
+		IWL_DEBUG_POWER(priv, "L1 Enabled; Disabling L0S\n");
+	} else {
+		/* L1-ASPM disabled; enable(!) L0S */
+		iwl_clear_bit(priv, CSR_GIO_REG,
+				CSR_GIO_REG_VAL_L0S_ENABLED);
+		IWL_DEBUG_POWER(priv, "L1 Disabled; Enabling L0S\n");
 	}
 
 	/* Configure analog phase-lock-loop before activating to D0A */
@@ -1777,6 +1748,15 @@
 
 	mutex_lock(&priv->mutex);
 
+	if (!ctx->vif || !iwl_is_ready_rf(priv)) {
+		/*
+		 * Huh? But wait ... this can maybe happen when
+		 * we're in the middle of a firmware restart!
+		 */
+		err = -EBUSY;
+		goto out;
+	}
+
 	interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes;
 
 	if (!(interface_modes & BIT(newtype))) {
@@ -1804,6 +1784,7 @@
 	/* success */
 	iwl_teardown_interface(priv, vif, true);
 	vif->type = newtype;
+	vif->p2p = newp2p;
 	err = iwl_setup_interface(priv, ctx);
 	WARN_ON(err);
 	/*
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 82939f8..32a990f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -139,12 +139,6 @@
 	void (*temperature)(struct iwl_priv *priv);
 };
 
-struct iwl_tt_ops {
-	bool (*lower_power_detection)(struct iwl_priv *priv);
-	u8 (*tt_power_mode)(struct iwl_priv *priv);
-	bool (*ct_kill_check)(struct iwl_priv *priv);
-};
-
 struct iwl_lib_ops {
 	/* set hw dependent parameters */
 	int (*set_hw_params)(struct iwl_priv *priv);
@@ -171,12 +165,6 @@
 	void (*cancel_deferred_work)(struct iwl_priv *priv);
 	/* check validity of rtc data address */
 	int (*is_valid_rtc_data_addr)(u32 addr);
-
-	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);
-	void (*dump_csr)(struct iwl_priv *priv);
-	int (*dump_fh)(struct iwl_priv *priv, char **buf, bool display);
 	int (*set_channel_switch)(struct iwl_priv *priv,
 				  struct ieee80211_channel_switch *ch_switch);
 	/* power management */
@@ -196,13 +184,6 @@
 	void (*dev_txfifo_flush)(struct iwl_priv *priv, u16 flush_control);
 
 	struct iwl_debugfs_ops debugfs_ops;
-
-	/* thermal throttling */
-	struct iwl_tt_ops tt_ops;
-};
-
-struct iwl_led_ops {
-	int (*cmd)(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd);
 };
 
 /* NIC specific ops */
@@ -210,23 +191,11 @@
 	void (*additional_nic_config)(struct iwl_priv *priv);
 };
 
-struct iwl_legacy_ops {
-	void (*post_associate)(struct iwl_priv *priv);
-	void (*config_ap)(struct iwl_priv *priv);
-	/* station management */
-	int (*update_bcast_stations)(struct iwl_priv *priv);
-	int (*manage_ibss_station)(struct iwl_priv *priv,
-				   struct ieee80211_vif *vif, bool add);
-};
-
 struct iwl_ops {
 	const struct iwl_lib_ops *lib;
 	const struct iwl_hcmd_ops *hcmd;
 	const struct iwl_hcmd_utils_ops *utils;
-	const struct iwl_led_ops *led;
 	const struct iwl_nic_ops *nic;
-	const struct iwl_legacy_ops *legacy;
-	const struct ieee80211_ops *ieee80211_ops;
 };
 
 struct iwl_mod_params {
@@ -256,13 +225,6 @@
  * @wd_timeout: TX queues watchdog timeout
  * @temperature_kelvin: temperature report by uCode in kelvin
  * @max_event_log_size: size of event log buffer size for ucode event logging
- * @tx_power_by_driver: tx power calibration performed by driver
- *	instead of uCode
- * @ucode_tracing: support ucode continuous tracing
- * @sensitivity_calib_by_driver: driver has the capability to perform
- *	sensitivity calibration operation
- * @chain_noise_calib_by_driver: driver has the capability to perform
- *	chain noise calibration operation
  * @shadow_reg_enable: HW shadhow register bit
  */
 struct iwl_base_params {
@@ -271,12 +233,10 @@
 	int num_of_ampdu_queues;/* def: HW dependent */
 	/* for iwl_apm_init() */
 	u32 pll_cfg_val;
-	bool set_l0s;
 
 	const u16 max_ll_items;
 	const bool shadow_ram_support;
 	u16 led_compensation;
-	const bool broken_powersave;
 	int chain_noise_num_beacons;
 	bool adv_thermal_throttle;
 	bool support_ct_kill_exit;
@@ -286,17 +246,12 @@
 	unsigned int wd_timeout;
 	bool temperature_kelvin;
 	u32 max_event_log_size;
-	const bool tx_power_by_driver;
-	const bool ucode_tracing;
-	const bool sensitivity_calib_by_driver;
-	const bool chain_noise_calib_by_driver;
 	const bool shadow_reg_enable;
 };
 /*
  * @advanced_bt_coexist: support advanced bt coexist
  * @bt_init_traffic_load: specify initial bt traffic load
  * @bt_prio_boost: default bt priority boost value
- * @bt_statistics: use BT version of statistics notification
  * @agg_time_limit: maximum number of uSec in aggregation
  * @ampdu_factor: Maximum A-MPDU length factor
  * @ampdu_density: Minimum A-MPDU spacing
@@ -306,7 +261,6 @@
 	bool advanced_bt_coexist;
 	u8 bt_init_traffic_load;
 	u8 bt_prio_boost;
-	const bool bt_statistics;
 	u16 agg_time_limit;
 	u8 ampdu_factor;
 	u8 ampdu_density;
@@ -337,6 +291,7 @@
  * @rx_with_siso_diversity: 1x1 device with rx antenna diversity
  * @internal_wimax_coex: internal wifi/wimax combo device
  * @iq_invert: I/Q inversion
+ * @disable_otp_refresh: disable OTP refresh current limit
  *
  * We enable the driver to be backward compatible wrt API version. The
  * driver specifies which APIs it supports (with @ucode_api_max being the
@@ -387,13 +342,13 @@
 	const bool rx_with_siso_diversity;
 	const bool internal_wimax_coex;
 	const bool iq_invert;
+	const bool disable_otp_refresh;
 };
 
 /***************************
  *   L i b                 *
  ***************************/
 
-struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg);
 int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
 		    const struct ieee80211_tx_queue_params *params);
 int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw);
@@ -598,6 +553,8 @@
 void iwl_dump_nic_error_log(struct iwl_priv *priv);
 int iwl_dump_nic_event_log(struct iwl_priv *priv,
 			   bool full_log, char **buf, bool display);
+void iwl_dump_csr(struct iwl_priv *priv);
+int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display);
 #ifdef CONFIG_IWLWIFI_DEBUG
 void iwl_print_rx_config_cmd(struct iwl_priv *priv,
 			     struct iwl_rxon_context *ctx);
@@ -709,11 +666,6 @@
 	       priv->cfg->bt_params->advanced_bt_coexist;
 }
 
-static inline bool iwl_bt_statistics(struct iwl_priv *priv)
-{
-	return priv->bt_statistics;
-}
-
 extern bool bt_coex_active;
 extern bool bt_siso_mode;
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 92f6efd..c272204 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -437,8 +437,7 @@
 	int pos = 0;
 	ssize_t ret = -ENOMEM;
 
-	ret = pos = priv->cfg->ops->lib->dump_nic_event_log(
-					priv, true, &buf, true);
+	ret = pos = iwl_dump_nic_event_log(priv, true, &buf, true);
 	if (buf) {
 		ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 		kfree(buf);
@@ -462,8 +461,7 @@
 	if (sscanf(buf, "%d", &event_log_flag) != 1)
 		return -EFAULT;
 	if (event_log_flag == 1)
-		priv->cfg->ops->lib->dump_nic_event_log(priv, true,
-							NULL, false);
+		iwl_dump_nic_event_log(priv, true, NULL, false);
 
 	return count;
 }
@@ -1268,8 +1266,7 @@
 	if (sscanf(buf, "%d", &csr) != 1)
 		return -EFAULT;
 
-	if (priv->cfg->ops->lib->dump_csr)
-		priv->cfg->ops->lib->dump_csr(priv);
+	iwl_dump_csr(priv);
 
 	return count;
 }
@@ -1359,13 +1356,11 @@
 	int pos = 0;
 	ssize_t ret = -EFAULT;
 
-	if (priv->cfg->ops->lib->dump_fh) {
-		ret = pos = priv->cfg->ops->lib->dump_fh(priv, &buf, true);
-		if (buf) {
-			ret = simple_read_from_buffer(user_buf,
-						      count, ppos, buf, pos);
-			kfree(buf);
-		}
+	ret = pos = iwl_dump_fh(priv, &buf, true);
+	if (buf) {
+		ret = simple_read_from_buffer(user_buf,
+					      count, ppos, buf, pos);
+		kfree(buf);
 	}
 
 	return ret;
@@ -1728,11 +1723,8 @@
 	DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR);
 	DEBUGFS_ADD_FILE(interrupt, dir_data, S_IWUSR | S_IRUSR);
 	DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR);
-	if (!priv->cfg->base_params->broken_powersave) {
-		DEBUGFS_ADD_FILE(sleep_level_override, dir_data,
-				 S_IWUSR | S_IRUSR);
-		DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR);
-	}
+	DEBUGFS_ADD_FILE(sleep_level_override, dir_data, S_IWUSR | S_IRUSR);
+	DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR);
 	DEBUGFS_ADD_FILE(thermal_throttling, dir_data, S_IRUSR);
 	DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR);
 	DEBUGFS_ADD_FILE(rx_statistics, dir_debug, S_IRUSR);
@@ -1755,29 +1747,20 @@
 		DEBUGFS_ADD_FILE(txfifo_flush, dir_debug, S_IWUSR);
 	DEBUGFS_ADD_FILE(protection_mode, dir_debug, S_IWUSR | S_IRUSR);
 
-	if (priv->cfg->base_params->sensitivity_calib_by_driver)
-		DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR);
-	if (priv->cfg->base_params->chain_noise_calib_by_driver)
-		DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR);
-	if (priv->cfg->base_params->ucode_tracing)
-		DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR);
-	if (iwl_bt_statistics(priv))
-		DEBUGFS_ADD_FILE(ucode_bt_stats, dir_debug, S_IRUSR);
+	DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR);
+	DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR);
+	DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR);
+	DEBUGFS_ADD_FILE(ucode_bt_stats, dir_debug, S_IRUSR);
 	DEBUGFS_ADD_FILE(reply_tx_error, dir_debug, S_IRUSR);
 	DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
 	DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
 	DEBUGFS_ADD_FILE(wd_timeout, dir_debug, S_IWUSR);
 	if (iwl_advanced_bt_coexist(priv))
 		DEBUGFS_ADD_FILE(bt_traffic, dir_debug, S_IRUSR);
-	if (priv->cfg->base_params->sensitivity_calib_by_driver)
-		DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf,
-				 &priv->disable_sens_cal);
-	if (priv->cfg->base_params->chain_noise_calib_by_driver)
-		DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf,
-				 &priv->disable_chain_noise_cal);
-	if (priv->cfg->base_params->tx_power_by_driver)
-		DEBUGFS_ADD_BOOL(disable_tx_power, dir_rf,
-				&priv->disable_tx_power_cal);
+	DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf,
+			 &priv->disable_sens_cal);
+	DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf,
+			 &priv->disable_chain_noise_cal);
 	return 0;
 
 err:
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 7213336..e84534c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -543,13 +543,12 @@
  * 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_RESERVED_1: reserved
  * @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_RESERVED_1	= BIT(1),
 	IWL_UCODE_TLV_FLAGS_MFP		= BIT(2),
 };
 
@@ -1170,6 +1169,8 @@
 		bool enabled, is_40mhz;
 		u8 extension_chan_offset;
 	} ht;
+
+	bool last_tx_rejected;
 };
 
 enum iwl_scan_type {
@@ -1355,6 +1356,31 @@
 	u64 timestamp;
 
 	struct {
+		__le32 flag;
+		struct statistics_general_common common;
+		struct statistics_rx_non_phy rx_non_phy;
+		struct statistics_rx_phy rx_ofdm;
+		struct statistics_rx_ht_phy rx_ofdm_ht;
+		struct statistics_rx_phy rx_cck;
+		struct statistics_tx tx;
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+		struct statistics_bt_activity bt_activity;
+		__le32 num_bt_kills, accum_num_bt_kills;
+#endif
+	} statistics;
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+	struct {
+		struct statistics_general_common common;
+		struct statistics_rx_non_phy rx_non_phy;
+		struct statistics_rx_phy rx_ofdm;
+		struct statistics_rx_ht_phy rx_ofdm_ht;
+		struct statistics_rx_phy rx_cck;
+		struct statistics_tx tx;
+		struct statistics_bt_activity bt_activity;
+	} accum_stats, delta_stats, max_delta_stats;
+#endif
+
+	struct {
 		/* INT ICT Table */
 		__le32 *ict_tbl;
 		void *ict_tbl_vir;
@@ -1385,19 +1411,9 @@
 		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;
@@ -1422,7 +1438,6 @@
 	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;
@@ -1487,7 +1502,6 @@
 	struct work_struct txpower_work;
 	u32 disable_sens_cal;
 	u32 disable_chain_noise_cal;
-	u32 disable_tx_power_cal;
 	struct work_struct run_time_calib_work;
 	struct timer_list statistics_periodic;
 	struct timer_list ucode_trace;
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index 859b94a..4027336 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -215,12 +215,6 @@
 	return  nvm_type;
 }
 
-const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset)
-{
-	BUG_ON(offset >= priv->cfg->base_params->eeprom_size);
-	return &priv->eeprom[offset];
-}
-
 static int iwl_init_otp_access(struct iwl_priv *priv)
 {
 	int ret;
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
index 0e9d970..9ce0525 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
@@ -309,7 +309,6 @@
 const u8 *iwl_eeprom_query_addr(const struct iwl_priv *priv, size_t offset);
 int iwlcore_eeprom_verify_signature(struct iwl_priv *priv);
 u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset);
-const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset);
 int iwl_init_channel_map(struct iwl_priv *priv);
 void iwl_free_channel_map(struct iwl_priv *priv);
 const struct iwl_channel_info *iwl_get_channel_info(
diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h
index e7a1bc6..6dfa806 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fh.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fh.h
@@ -77,14 +77,14 @@
 /**
  * Keep-Warm (KW) buffer base address.
  *
- * Driver must allocate a 4KByte buffer that is used by 4965 for keeping the
+ * Driver must allocate a 4KByte buffer that is for keeping the
  * host DRAM powered on (via dummy accesses to DRAM) to maintain low-latency
- * DRAM access when 4965 is Txing or Rxing.  The dummy accesses prevent host
+ * DRAM access when doing Txing or Rxing.  The dummy accesses prevent host
  * from going into a power-savings mode that would cause higher DRAM latency,
  * and possible data over/under-runs, before all Tx/Rx is complete.
  *
  * Driver loads FH_KW_MEM_ADDR_REG with the physical address (bits 35:4)
- * of the buffer, which must be 4K aligned.  Once this is set up, the 4965
+ * of the buffer, which must be 4K aligned.  Once this is set up, the device
  * automatically invokes keep-warm accesses when normal accesses might not
  * be sufficient to maintain fast DRAM response.
  *
@@ -97,7 +97,7 @@
 /**
  * TFD Circular Buffers Base (CBBC) addresses
  *
- * 4965 has 16 base pointer registers, one for each of 16 host-DRAM-resident
+ * Device has 16 base pointer registers, one for each of 16 host-DRAM-resident
  * circular buffers (CBs/queues) containing Transmit Frame Descriptors (TFDs)
  * (see struct iwl_tfd_frame).  These 16 pointer registers are offset by 0x04
  * bytes from one another.  Each TFD circular buffer in DRAM must be 256-byte
@@ -116,16 +116,16 @@
 /**
  * Rx SRAM Control and Status Registers (RSCSR)
  *
- * These registers provide handshake between driver and 4965 for the Rx queue
+ * These registers provide handshake between driver and device for the Rx queue
  * (this queue handles *all* command responses, notifications, Rx data, etc.
- * sent from 4965 uCode to host driver).  Unlike Tx, there is only one Rx
+ * sent from uCode to host driver).  Unlike Tx, there is only one Rx
  * queue, and only one Rx DMA/FIFO channel.  Also unlike Tx, which can
  * concatenate up to 20 DRAM buffers to form a Tx frame, each Receive Buffer
  * Descriptor (RBD) points to only one Rx Buffer (RB); there is a 1:1
  * mapping between RBDs and RBs.
  *
  * Driver must allocate host DRAM memory for the following, and set the
- * physical address of each into 4965 registers:
+ * physical address of each into device registers:
  *
  * 1)  Receive Buffer Descriptor (RBD) circular buffer (CB), typically with 256
  *     entries (although any power of 2, up to 4096, is selectable by driver).
@@ -140,20 +140,20 @@
  *     Driver sets physical address [35:8] of base of RBD circular buffer
  *     into FH_RSCSR_CHNL0_RBDCB_BASE_REG [27:0].
  *
- * 2)  Rx status buffer, 8 bytes, in which 4965 indicates which Rx Buffers
+ * 2)  Rx status buffer, 8 bytes, in which uCode indicates which Rx Buffers
  *     (RBs) have been filled, via a "write pointer", actually the index of
  *     the RB's corresponding RBD within the circular buffer.  Driver sets
  *     physical address [35:4] into FH_RSCSR_CHNL0_STTS_WPTR_REG [31:0].
  *
  *     Bit fields in lower dword of Rx status buffer (upper dword not used
- *     by driver; see struct iwl4965_shared, val0):
+ *     by driver:
  *     31-12:  Not used by driver
  *     11- 0:  Index of last filled Rx buffer descriptor
- *             (4965 writes, driver reads this value)
+ *             (device writes, driver reads this value)
  *
- * As the driver prepares Receive Buffers (RBs) for 4965 to fill, driver must
+ * As the driver prepares Receive Buffers (RBs) for device to fill, driver must
  * enter pointers to these RBs into contiguous RBD circular buffer entries,
- * and update the 4965's "write" index register,
+ * and update the device's "write" index register,
  * FH_RSCSR_CHNL0_RBDCB_WPTR_REG.
  *
  * This "write" index corresponds to the *next* RBD that the driver will make
@@ -162,12 +162,12 @@
  * RBs), should be 8 after preparing the first 8 RBs (for example), and must
  * wrap back to 0 at the end of the circular buffer (but don't wrap before
  * "read" index has advanced past 1!  See below).
- * NOTE:  4965 EXPECTS THE WRITE INDEX TO BE INCREMENTED IN MULTIPLES OF 8.
+ * NOTE:  DEVICE EXPECTS THE WRITE INDEX TO BE INCREMENTED IN MULTIPLES OF 8.
  *
- * As the 4965 fills RBs (referenced from contiguous RBDs within the circular
+ * As the device fills RBs (referenced from contiguous RBDs within the circular
  * buffer), it updates the Rx status buffer in host DRAM, 2) described above,
  * to tell the driver the index of the latest filled RBD.  The driver must
- * read this "read" index from DRAM after receiving an Rx interrupt from 4965.
+ * read this "read" index from DRAM after receiving an Rx interrupt from device
  *
  * The driver must also internally keep track of a third index, which is the
  * next RBD to process.  When receiving an Rx interrupt, driver should process
@@ -176,7 +176,7 @@
  * driver may process the RB pointed to by RBD 0.  Depending on volume of
  * traffic, there may be many RBs to process.
  *
- * If read index == write index, 4965 thinks there is no room to put new data.
+ * If read index == write index, device thinks there is no room to put new data.
  * Due to this, the maximum number of filled RBs is 255, instead of 256.  To
  * be safe, make sure that there is a gap of at least 2 RBDs between "write"
  * and "read" indexes; that is, make sure that there are no more than 254
@@ -303,7 +303,7 @@
 /**
  * Transmit DMA Channel Control/Status Registers (TCSR)
  *
- * 4965 has one configuration register for each of 8 Tx DMA/FIFO channels
+ * Device has one configuration register for each of 8 Tx DMA/FIFO channels
  * supported in hardware (don't confuse these with the 16 Tx queues in DRAM,
  * which feed the DMA/FIFO channels); config regs are separated by 0x20 bytes.
  *
@@ -326,7 +326,6 @@
 #define FH_TCSR_UPPER_BOUND  (FH_MEM_LOWER_BOUND + 0xE60)
 
 /* Find Control/Status reg for given Tx DMA/FIFO channel */
-#define FH49_TCSR_CHNL_NUM                            (7)
 #define FH50_TCSR_CHNL_NUM                            (8)
 
 /* TCSR: tx_config register values */
@@ -424,7 +423,6 @@
 #define RX_LOW_WATERMARK 8
 
 /* Size of one Rx buffer in host DRAM */
-#define IWL_RX_BUF_SIZE_3K (3 * 1000) /* 3945 only */
 #define IWL_RX_BUF_SIZE_4K (4 * 1024)
 #define IWL_RX_BUF_SIZE_8K (8 * 1024)
 
@@ -443,7 +441,7 @@
 	__le16 closed_fr_num;
 	__le16 finished_rb_num;
 	__le16 finished_fr_nam;
-	__le32 __unused; /* 3945 only */
+	__le32 __unused;
 } __packed;
 
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
index 9177b55..8f0beb9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
@@ -143,10 +143,12 @@
 {
 	int ret;
 
-	BUG_ON(!(cmd->flags & CMD_ASYNC));
+	if (WARN_ON(!(cmd->flags & CMD_ASYNC)))
+		return -EINVAL;
 
 	/* An asynchronous command can not expect an SKB to be set. */
-	BUG_ON(cmd->flags & CMD_WANT_SKB);
+	if (WARN_ON(cmd->flags & CMD_WANT_SKB))
+		return -EINVAL;
 
 	/* Assign a generic callback if one is not provided */
 	if (!cmd->callback)
@@ -169,10 +171,12 @@
 	int cmd_idx;
 	int ret;
 
-	lockdep_assert_held(&priv->mutex);
+	if (WARN_ON(cmd->flags & CMD_ASYNC))
+		return -EINVAL;
 
 	 /* A synchronous command can not have a callback set. */
-	BUG_ON((cmd->flags & CMD_ASYNC) || cmd->callback);
+	if (WARN_ON(cmd->callback))
+		return -EINVAL;
 
 	IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n",
 			get_cmd_string(cmd->id));
diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h
index 5da5761..9309ff2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-helpers.h
+++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h
@@ -131,6 +131,19 @@
 			ieee80211_stop_queue(priv->hw, ac);
 }
 
+static inline void iwl_wake_any_queue(struct iwl_priv *priv,
+				      struct iwl_rxon_context *ctx)
+{
+	u8 ac;
+
+	for (ac = 0; ac < AC_NUM; ac++) {
+		IWL_DEBUG_INFO(priv, "Queue Status: Q[%d] %s\n",
+			ac, (atomic_read(&priv->queue_stop_count[ac]) > 0)
+			      ? "stopped" : "awake");
+		iwl_wake_queue(priv, &priv->txq[ctx->ac_to_queue[ac]]);
+	}
+}
+
 #define ieee80211_stop_queue DO_NOT_USE_ieee80211_stop_queue
 #define ieee80211_wake_queue DO_NOT_USE_ieee80211_wake_queue
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c
index c2862d4..d798c2a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-led.c
@@ -61,10 +61,16 @@
 	{ .throughput = 300 * 1024 - 1, .blink_time = 50 },
 };
 
+/* Set led register off */
+void iwlagn_led_enable(struct iwl_priv *priv)
+{
+	iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
+}
+
 /*
  * Adjust led blink rate to compensate on a MAC Clock difference on every HW
- * Led blink rate analysis showed an average deviation of 0% on 3945,
- * 5% on 4965 HW and 20% on 5000 series and up.
+ * Led blink rate analysis showed an average deviation of 20% on 5000 series
+ * and up.
  * Need to compensate on the led on/off time per HW according to the deviation
  * to achieve the desired led frequency
  * The calculation is: (100-averageDeviation)/100 * blinkTime
@@ -84,6 +90,24 @@
 	return (u8)((time * compensation) >> 6);
 }
 
+static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
+{
+	struct iwl_host_cmd cmd = {
+		.id = REPLY_LEDS_CMD,
+		.len = sizeof(struct iwl_led_cmd),
+		.data = led_cmd,
+		.flags = CMD_ASYNC,
+		.callback = NULL,
+	};
+	u32 reg;
+
+	reg = iwl_read32(priv, CSR_LED_REG);
+	if (reg != (reg & CSR_LED_BSM_CTRL_MSK))
+		iwl_write32(priv, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK);
+
+	return iwl_send_cmd(priv, &cmd);
+}
+
 /* Set led pattern command */
 static int iwl_led_cmd(struct iwl_priv *priv,
 		       unsigned long on,
@@ -108,7 +132,7 @@
 	led_cmd.off = iwl_blink_compensation(priv, off,
 				priv->cfg->base_params->led_compensation);
 
-	ret = priv->cfg->ops->led->cmd(priv, &led_cmd);
+	ret = iwl_send_led_cmd(priv, &led_cmd);
 	if (!ret) {
 		priv->blink_on = on;
 		priv->blink_off = off;
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h
index 05b8e8f..1c93dfe 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.h
+++ b/drivers/net/wireless/iwlwifi/iwl-led.h
@@ -50,6 +50,7 @@
 	IWL_LED_BLINK,
 };
 
+void iwlagn_led_enable(struct iwl_priv *priv);
 void iwl_leds_init(struct iwl_priv *priv);
 void iwl_leds_exit(struct iwl_priv *priv);
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
index c43c8e6..595c930 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.c
+++ b/drivers/net/wireless/iwlwifi/iwl-power.c
@@ -188,9 +188,10 @@
 			table = range_0;
 	}
 
-	BUG_ON(lvl < 0 || lvl >= IWL_POWER_NUM);
-
-	*cmd = table[lvl].cmd;
+	if (WARN_ON(lvl < 0 || lvl >= IWL_POWER_NUM))
+		memset(cmd, 0, sizeof(*cmd));
+	else
+		*cmd = table[lvl].cmd;
 
 	if (period == 0) {
 		skip = 0;
@@ -354,16 +355,12 @@
 
 	dtimper = priv->hw->conf.ps_dtim_period ?: 1;
 
-	if (priv->cfg->base_params->broken_powersave)
-		iwl_power_sleep_cam_cmd(priv, cmd);
-	else if (priv->hw->conf.flags & IEEE80211_CONF_IDLE)
+	if (priv->hw->conf.flags & IEEE80211_CONF_IDLE)
 		iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, 20);
-	else if (priv->cfg->ops->lib->tt_ops.lower_power_detection &&
-		 priv->cfg->ops->lib->tt_ops.tt_power_mode &&
-		 priv->cfg->ops->lib->tt_ops.lower_power_detection(priv)) {
+	else if (iwl_tt_is_low_power_state(priv)) {
 		/* in thermal throttling low power state */
 		iwl_static_sleep_cmd(priv, cmd,
-		    priv->cfg->ops->lib->tt_ops.tt_power_mode(priv), dtimper);
+		    iwl_tt_current_power_mode(priv), dtimper);
 	} else if (!enabled)
 		iwl_power_sleep_cam_cmd(priv, cmd);
 	else if (priv->power_data.debug_sleep_level_override >= 0)
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index c960195..f00d188 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -107,17 +107,7 @@
  * device.  A queue maps to only one (selectable by driver) Tx DMA channel,
  * but one DMA channel may take input from several queues.
  *
- * Tx DMA FIFOs have dedicated purposes.  For 4965, they are used as follows
- * (cf. default_queue_to_tx_fifo in iwl-4965.c):
- *
- * 0 -- EDCA BK (background) frames, lowest priority
- * 1 -- EDCA BE (best effort) frames, normal priority
- * 2 -- EDCA VI (video) frames, higher priority
- * 3 -- EDCA VO (voice) and management frames, highest priority
- * 4 -- Commands (e.g. RXON, etc.)
- * 5 -- unused (HCCA)
- * 6 -- unused (HCCA)
- * 7 -- not used by driver (device-internal only)
+ * Tx DMA FIFOs have dedicated purposes.
  *
  * For 5000 series and up, they are used differently
  * (cf. iwl5000_default_queue_to_tx_fifo in iwl-5000.c):
@@ -151,7 +141,7 @@
  *     Tx completion may end up being out-of-order).
  *
  *     The driver must maintain the queue's Byte Count table in host DRAM
- *     (struct iwl4965_sched_queue_byte_cnt_tbl) for this mode.
+ *     for this mode.
  *     This mode does not support fragmentation.
  *
  * 2)  FIFO (a.k.a. non-Scheduler-ACK), in which each TFD is processed in order.
@@ -164,7 +154,7 @@
  *
  * Driver controls scheduler operation via 3 means:
  * 1)  Scheduler registers
- * 2)  Shared scheduler data base in internal 4956 SRAM
+ * 2)  Shared scheduler data base in internal SRAM
  * 3)  Shared data in host DRAM
  *
  * Initialization:
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index c421f56..b49819c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -390,21 +390,16 @@
  * the BA_TIMEOUT_MAX, reload firmware and bring system back to normal
  * operation state.
  */
-static bool iwl_good_ack_health(struct iwl_priv *priv, struct iwl_rx_packet *pkt)
+static bool iwl_good_ack_health(struct iwl_priv *priv,
+				struct statistics_tx *cur)
 {
 	int actual_delta, expected_delta, ba_timeout_delta;
-	struct statistics_tx *cur, *old;
+	struct statistics_tx *old;
 
 	if (priv->_agn.agg_tids_count)
 		return true;
 
-	if (iwl_bt_statistics(priv)) {
-		cur = &pkt->u.stats_bt.tx;
-		old = &priv->_agn.statistics_bt.tx;
-	} else {
-		cur = &pkt->u.stats.tx;
-		old = &priv->_agn.statistics.tx;
-	}
+	old = &priv->statistics.tx;
 
 	actual_delta = le32_to_cpu(cur->actual_ack_cnt) -
 		       le32_to_cpu(old->actual_ack_cnt);
@@ -430,10 +425,10 @@
 		 * DEBUG is not, these will just compile out.
 		 */
 		IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta %d\n",
-				priv->_agn.delta_statistics.tx.rx_detected_cnt);
+				priv->delta_stats.tx.rx_detected_cnt);
 		IWL_DEBUG_RADIO(priv,
 				"ack_or_ba_timeout_collision delta %d\n",
-				priv->_agn.delta_statistics.tx.ack_or_ba_timeout_collision);
+				priv->delta_stats.tx.ack_or_ba_timeout_collision);
 #endif
 
 		if (ba_timeout_delta >= BA_TIMEOUT_MAX)
@@ -450,7 +445,9 @@
  * to improve the throughput.
  */
 static bool iwl_good_plcp_health(struct iwl_priv *priv,
-				 struct iwl_rx_packet *pkt, unsigned int msecs)
+				 struct statistics_rx_phy *cur_ofdm,
+				 struct statistics_rx_ht_phy *cur_ofdm_ht,
+				 unsigned int msecs)
 {
 	int delta;
 	int threshold = priv->cfg->base_params->plcp_delta_threshold;
@@ -460,29 +457,12 @@
 		return true;
 	}
 
-	if (iwl_bt_statistics(priv)) {
-		struct statistics_rx_bt *cur, *old;
+	delta = le32_to_cpu(cur_ofdm->plcp_err) -
+		le32_to_cpu(priv->statistics.rx_ofdm.plcp_err) +
+		le32_to_cpu(cur_ofdm_ht->plcp_err) -
+		le32_to_cpu(priv->statistics.rx_ofdm_ht.plcp_err);
 
-		cur = &pkt->u.stats_bt.rx;
-		old = &priv->_agn.statistics_bt.rx;
-
-		delta = le32_to_cpu(cur->ofdm.plcp_err) -
-			le32_to_cpu(old->ofdm.plcp_err) +
-			le32_to_cpu(cur->ofdm_ht.plcp_err) -
-			le32_to_cpu(old->ofdm_ht.plcp_err);
-	} else {
-		struct statistics_rx *cur, *old;
-
-		cur = &pkt->u.stats.rx;
-		old = &priv->_agn.statistics.rx;
-
-		delta = le32_to_cpu(cur->ofdm.plcp_err) -
-			le32_to_cpu(old->ofdm.plcp_err) +
-			le32_to_cpu(cur->ofdm_ht.plcp_err) -
-			le32_to_cpu(old->ofdm_ht.plcp_err);
-	}
-
-	/* Can be negative if firmware reseted statistics */
+	/* Can be negative if firmware reset statistics */
 	if (delta <= 0)
 		return true;
 
@@ -497,44 +477,36 @@
 }
 
 static void iwl_recover_from_statistics(struct iwl_priv *priv,
-					struct iwl_rx_packet *pkt)
+					struct statistics_rx_phy *cur_ofdm,
+					struct statistics_rx_ht_phy *cur_ofdm_ht,
+					struct statistics_tx *tx,
+					unsigned long stamp)
 {
 	const struct iwl_mod_params *mod_params = priv->cfg->mod_params;
 	unsigned int msecs;
-	unsigned long stamp;
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 
-	stamp = jiffies;
 	msecs = jiffies_to_msecs(stamp - priv->rx_statistics_jiffies);
 
 	/* Only gather statistics and update time stamp when not associated */
 	if (!iwl_is_any_associated(priv))
-		goto out;
+		return;
 
 	/* Do not check/recover when do not have enough statistics data */
 	if (msecs < 99)
 		return;
 
-	if (mod_params->ack_check && !iwl_good_ack_health(priv, pkt)) {
+	if (mod_params->ack_check && !iwl_good_ack_health(priv, tx)) {
 		IWL_ERR(priv, "low ack count detected, restart firmware\n");
 		if (!iwl_force_reset(priv, IWL_FW_RESET, false))
 			return;
 	}
 
-	if (mod_params->plcp_check && !iwl_good_plcp_health(priv, pkt, msecs))
+	if (mod_params->plcp_check &&
+	    !iwl_good_plcp_health(priv, cur_ofdm, cur_ofdm_ht, msecs))
 		iwl_force_reset(priv, IWL_RF_RESET, false);
-
-out:
-	if (iwl_bt_statistics(priv))
-		memcpy(&priv->_agn.statistics_bt, &pkt->u.stats_bt,
-			sizeof(priv->_agn.statistics_bt));
-	else
-		memcpy(&priv->_agn.statistics, &pkt->u.stats,
-			sizeof(priv->_agn.statistics));
-
-	priv->rx_statistics_jiffies = stamp;
 }
 
 /* Calculate noise level, based on measurements during network silence just
@@ -548,10 +520,8 @@
 	int bcn_silence_a, bcn_silence_b, bcn_silence_c;
 	int last_rx_noise;
 
-	if (iwl_bt_statistics(priv))
-		rx_info = &(priv->_agn.statistics_bt.rx.general.common);
-	else
-		rx_info = &(priv->_agn.statistics.rx.general);
+	rx_info = &priv->statistics.rx_non_phy;
+
 	bcn_silence_a =
 		le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER;
 	bcn_silence_b =
@@ -583,105 +553,153 @@
 			last_rx_noise);
 }
 
+#ifdef CONFIG_IWLWIFI_DEBUGFS
 /*
  *  based on the assumption of all statistics counter are in DWORD
  *  FIXME: This function is for debugging, do not deal with
  *  the case of counters roll-over.
  */
-static void iwl_accumulative_statistics(struct iwl_priv *priv,
-					__le32 *stats)
+static void accum_stats(__le32 *prev, __le32 *cur, __le32 *delta,
+			__le32 *max_delta, __le32 *accum, int size)
 {
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-	int i, size;
-	__le32 *prev_stats;
-	u32 *accum_stats;
-	u32 *delta, *max_delta;
-	struct statistics_general_common *general, *accum_general;
-	struct statistics_tx *tx, *accum_tx;
+	int i;
 
-	if (iwl_bt_statistics(priv)) {
-		prev_stats = (__le32 *)&priv->_agn.statistics_bt;
-		accum_stats = (u32 *)&priv->_agn.accum_statistics_bt;
-		size = sizeof(struct iwl_bt_notif_statistics);
-		general = &priv->_agn.statistics_bt.general.common;
-		accum_general = &priv->_agn.accum_statistics_bt.general.common;
-		tx = &priv->_agn.statistics_bt.tx;
-		accum_tx = &priv->_agn.accum_statistics_bt.tx;
-		delta = (u32 *)&priv->_agn.delta_statistics_bt;
-		max_delta = (u32 *)&priv->_agn.max_delta_bt;
-	} else {
-		prev_stats = (__le32 *)&priv->_agn.statistics;
-		accum_stats = (u32 *)&priv->_agn.accum_statistics;
-		size = sizeof(struct iwl_notif_statistics);
-		general = &priv->_agn.statistics.general.common;
-		accum_general = &priv->_agn.accum_statistics.general.common;
-		tx = &priv->_agn.statistics.tx;
-		accum_tx = &priv->_agn.accum_statistics.tx;
-		delta = (u32 *)&priv->_agn.delta_statistics;
-		max_delta = (u32 *)&priv->_agn.max_delta;
-	}
-	for (i = sizeof(__le32); i < size;
-	     i += sizeof(__le32), stats++, prev_stats++, delta++,
-	     max_delta++, accum_stats++) {
-		if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) {
-			*delta = (le32_to_cpu(*stats) -
-				le32_to_cpu(*prev_stats));
-			*accum_stats += *delta;
-			if (*delta > *max_delta)
+	for (i = 0;
+	     i < size / sizeof(__le32);
+	     i++, prev++, cur++, delta++, max_delta++, accum++) {
+		if (le32_to_cpu(*cur) > le32_to_cpu(*prev)) {
+			*delta = cpu_to_le32(
+				le32_to_cpu(*cur) - le32_to_cpu(*prev));
+			le32_add_cpu(accum, le32_to_cpu(*delta));
+			if (le32_to_cpu(*delta) > le32_to_cpu(*max_delta))
 				*max_delta = *delta;
 		}
 	}
-
-	/* reset accumulative statistics for "no-counter" type statistics */
-	accum_general->temperature = general->temperature;
-	accum_general->temperature_m = general->temperature_m;
-	accum_general->ttl_timestamp = general->ttl_timestamp;
-	accum_tx->tx_power.ant_a = tx->tx_power.ant_a;
-	accum_tx->tx_power.ant_b = tx->tx_power.ant_b;
-	accum_tx->tx_power.ant_c = tx->tx_power.ant_c;
-#endif
 }
 
+static void
+iwl_accumulative_statistics(struct iwl_priv *priv,
+			    struct statistics_general_common *common,
+			    struct statistics_rx_non_phy *rx_non_phy,
+			    struct statistics_rx_phy *rx_ofdm,
+			    struct statistics_rx_ht_phy *rx_ofdm_ht,
+			    struct statistics_rx_phy *rx_cck,
+			    struct statistics_tx *tx,
+			    struct statistics_bt_activity *bt_activity)
+{
+#define ACCUM(_name)	\
+	accum_stats((__le32 *)&priv->statistics._name,		\
+		    (__le32 *)_name,				\
+		    (__le32 *)&priv->delta_stats._name,		\
+		    (__le32 *)&priv->max_delta_stats._name,	\
+		    (__le32 *)&priv->accum_stats._name,		\
+		    sizeof(*_name));
+
+	ACCUM(common);
+	ACCUM(rx_non_phy);
+	ACCUM(rx_ofdm);
+	ACCUM(rx_ofdm_ht);
+	ACCUM(rx_cck);
+	ACCUM(tx);
+	if (bt_activity)
+		ACCUM(bt_activity);
+#undef ACCUM
+}
+#else
+static inline void
+iwl_accumulative_statistics(struct iwl_priv *priv,
+			    struct statistics_general_common *common,
+			    struct statistics_rx_non_phy *rx_non_phy,
+			    struct statistics_rx_phy *rx_ofdm,
+			    struct statistics_rx_ht_phy *rx_ofdm_ht,
+			    struct statistics_rx_phy *rx_cck,
+			    struct statistics_tx *tx,
+			    struct statistics_bt_activity *bt_activity)
+{
+}
+#endif
+
 static void iwl_rx_statistics(struct iwl_priv *priv,
 			      struct iwl_rx_mem_buffer *rxb)
 {
+	unsigned long stamp = jiffies;
 	const int reg_recalib_period = 60;
 	int change;
 	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+	__le32 *flag;
+	struct statistics_general_common *common;
+	struct statistics_rx_non_phy *rx_non_phy;
+	struct statistics_rx_phy *rx_ofdm;
+	struct statistics_rx_ht_phy *rx_ofdm_ht;
+	struct statistics_rx_phy *rx_cck;
+	struct statistics_tx *tx;
+	struct statistics_bt_activity *bt_activity;
 
-	if (iwl_bt_statistics(priv)) {
-		IWL_DEBUG_RX(priv,
-			     "Statistics notification received (%d vs %d).\n",
-			     (int)sizeof(struct iwl_bt_notif_statistics),
-			     le32_to_cpu(pkt->len_n_flags) &
-			     FH_RSCSR_FRAME_SIZE_MSK);
+	len -= sizeof(struct iwl_cmd_header); /* skip header */
 
-		change = ((priv->_agn.statistics_bt.general.common.temperature !=
-			   pkt->u.stats_bt.general.common.temperature) ||
-			   ((priv->_agn.statistics_bt.flag &
-			   STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
-			   (pkt->u.stats_bt.flag &
-			   STATISTICS_REPLY_FLG_HT40_MODE_MSK)));
+	IWL_DEBUG_RX(priv, "Statistics notification received (%d bytes).\n",
+		     len);
 
-		iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats_bt);
+	if (len == sizeof(struct iwl_bt_notif_statistics)) {
+		struct iwl_bt_notif_statistics *stats;
+		stats = &pkt->u.stats_bt;
+		flag = &stats->flag;
+		common = &stats->general.common;
+		rx_non_phy = &stats->rx.general.common;
+		rx_ofdm = &stats->rx.ofdm;
+		rx_ofdm_ht = &stats->rx.ofdm_ht;
+		rx_cck = &stats->rx.cck;
+		tx = &stats->tx;
+		bt_activity = &stats->general.activity;
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+		/* handle this exception directly */
+		priv->statistics.num_bt_kills = stats->rx.general.num_bt_kills;
+		le32_add_cpu(&priv->statistics.accum_num_bt_kills,
+			     le32_to_cpu(stats->rx.general.num_bt_kills));
+#endif
+	} else if (len == sizeof(struct iwl_notif_statistics)) {
+		struct iwl_notif_statistics *stats;
+		stats = &pkt->u.stats;
+		flag = &stats->flag;
+		common = &stats->general.common;
+		rx_non_phy = &stats->rx.general;
+		rx_ofdm = &stats->rx.ofdm;
+		rx_ofdm_ht = &stats->rx.ofdm_ht;
+		rx_cck = &stats->rx.cck;
+		tx = &stats->tx;
+		bt_activity = NULL;
 	} else {
-		IWL_DEBUG_RX(priv,
-			     "Statistics notification received (%d vs %d).\n",
-			     (int)sizeof(struct iwl_notif_statistics),
-			     le32_to_cpu(pkt->len_n_flags) &
-			     FH_RSCSR_FRAME_SIZE_MSK);
-
-		change = ((priv->_agn.statistics.general.common.temperature !=
-			   pkt->u.stats.general.common.temperature) ||
-			   ((priv->_agn.statistics.flag &
-			   STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
-			   (pkt->u.stats.flag &
-			   STATISTICS_REPLY_FLG_HT40_MODE_MSK)));
-
-		iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats);
+		WARN_ONCE(1, "len %d doesn't match BT (%zu) or normal (%zu)\n",
+			  len, sizeof(struct iwl_bt_notif_statistics),
+			  sizeof(struct iwl_notif_statistics));
+		return;
 	}
 
-	iwl_recover_from_statistics(priv, pkt);
+	change = common->temperature != priv->statistics.common.temperature ||
+		 (*flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
+		 (priv->statistics.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK);
+
+	iwl_accumulative_statistics(priv, common, rx_non_phy, rx_ofdm,
+				    rx_ofdm_ht, rx_cck, tx, bt_activity);
+
+	iwl_recover_from_statistics(priv, rx_ofdm, rx_ofdm_ht, tx, stamp);
+
+	priv->statistics.flag = *flag;
+	memcpy(&priv->statistics.common, common, sizeof(*common));
+	memcpy(&priv->statistics.rx_non_phy, rx_non_phy, sizeof(*rx_non_phy));
+	memcpy(&priv->statistics.rx_ofdm, rx_ofdm, sizeof(*rx_ofdm));
+	memcpy(&priv->statistics.rx_ofdm_ht, rx_ofdm_ht, sizeof(*rx_ofdm_ht));
+	memcpy(&priv->statistics.rx_cck, rx_cck, sizeof(*rx_cck));
+	memcpy(&priv->statistics.tx, tx, sizeof(*tx));
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+	if (bt_activity)
+		memcpy(&priv->statistics.bt_activity, bt_activity,
+			sizeof(*bt_activity));
+#endif
+
+	priv->rx_statistics_jiffies = stamp;
 
 	set_bit(STATUS_STATISTICS, &priv->status);
 
@@ -708,18 +726,12 @@
 
 	if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) {
 #ifdef CONFIG_IWLWIFI_DEBUGFS
-		memset(&priv->_agn.accum_statistics, 0,
-			sizeof(struct iwl_notif_statistics));
-		memset(&priv->_agn.delta_statistics, 0,
-			sizeof(struct iwl_notif_statistics));
-		memset(&priv->_agn.max_delta, 0,
-			sizeof(struct iwl_notif_statistics));
-		memset(&priv->_agn.accum_statistics_bt, 0,
-			sizeof(struct iwl_bt_notif_statistics));
-		memset(&priv->_agn.delta_statistics_bt, 0,
-			sizeof(struct iwl_bt_notif_statistics));
-		memset(&priv->_agn.max_delta_bt, 0,
-			sizeof(struct iwl_bt_notif_statistics));
+		memset(&priv->accum_stats, 0,
+			sizeof(priv->accum_stats));
+		memset(&priv->delta_stats, 0,
+			sizeof(priv->delta_stats));
+		memset(&priv->max_delta_stats, 0,
+			sizeof(priv->max_delta_stats));
 #endif
 		IWL_DEBUG_RX(priv, "Statistics have been cleared\n");
 	}
@@ -873,6 +885,7 @@
 {
 	struct sk_buff *skb;
 	__le16 fc = hdr->frame_control;
+	struct iwl_rxon_context *ctx;
 
 	/* We only process data packets if the interface is open */
 	if (unlikely(!priv->is_open)) {
@@ -895,6 +908,26 @@
 	skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len);
 
 	iwl_update_stats(priv, false, fc, len);
+
+	/*
+	* Wake any queues that were stopped due to a passive channel tx
+	* failure. This can happen because the regulatory enforcement in
+	* the device waits for a beacon before allowing transmission,
+	* sometimes even after already having transmitted frames for the
+	* association because the new RXON may reset the information.
+	*/
+	if (unlikely(ieee80211_is_beacon(fc))) {
+		for_each_context(priv, ctx) {
+			if (!ctx->last_tx_rejected)
+				continue;
+			if (compare_ether_addr(hdr->addr3,
+					       ctx->active.bssid_addr))
+				continue;
+			ctx->last_tx_rejected = false;
+			iwl_wake_any_queue(priv, ctx);
+		}
+	}
+
 	memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
 
 	ieee80211_rx(priv->hw, skb);
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index c215156..3c8cebd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -494,7 +494,8 @@
 
 	priv->num_stations--;
 
-	BUG_ON(priv->num_stations < 0);
+	if (WARN_ON(priv->num_stations < 0))
+		priv->num_stations = 0;
 
 	spin_unlock_irqrestore(&priv->sta_lock, flags);
 
@@ -679,7 +680,8 @@
 
 		priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE;
 		priv->num_stations--;
-		BUG_ON(priv->num_stations < 0);
+		if (WARN_ON(priv->num_stations < 0))
+			priv->num_stations = 0;
 		kfree(priv->stations[i].lq);
 		priv->stations[i].lq = NULL;
 	}
@@ -775,7 +777,8 @@
 	spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
 
 	iwl_dump_lq_cmd(priv, lq);
-	BUG_ON(init && (cmd.flags & CMD_ASYNC));
+	if (WARN_ON(init && (cmd.flags & CMD_ASYNC)))
+		return -EINVAL;
 
 	if (is_lq_table_valid(priv, ctx, lq))
 		ret = iwl_send_cmd(priv, &cmd);
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 565980f..80c3565 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -232,7 +232,6 @@
  * reclaiming packets (on 'tx done IRQ), if free space become > high mark,
  * Tx queue resumed.
  *
- * See more detailed info in iwl-4965-hw.h.
  ***************************************************/
 
 int iwl_queue_space(const struct iwl_queue *q)
@@ -264,11 +263,13 @@
 
 	/* count must be power-of-two size, otherwise iwl_queue_inc_wrap
 	 * and iwl_queue_dec_wrap are broken. */
-	BUG_ON(!is_power_of_2(count));
+	if (WARN_ON(!is_power_of_2(count)))
+		return -EINVAL;
 
 	/* slots_num must be power-of-two size, otherwise
 	 * get_cmd_index is broken. */
-	BUG_ON(!is_power_of_2(slots_num));
+	if (WARN_ON(!is_power_of_2(slots_num)))
+		return -EINVAL;
 
 	q->low_mark = q->n_window / 4;
 	if (q->low_mark < 4)
@@ -385,7 +386,9 @@
 	BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
 
 	/* Initialize queue's high/low-water marks, and head/tail indexes */
-	iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
+	ret = iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
+	if (ret)
+		return ret;
 
 	/* Tell device where to find queue */
 	priv->cfg->ops->lib->txq_init(priv, txq);
@@ -447,14 +450,19 @@
 	cmd->len = priv->cfg->ops->utils->get_hcmd_size(cmd->id, cmd->len);
 	fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr));
 
-	/* If any of the command structures end up being larger than
+	/*
+	 * If any of the command structures end up being larger than
 	 * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then
 	 * we will need to increase the size of the TFD entries
 	 * Also, check to see if command buffer should not exceed the size
-	 * of device_cmd and max_cmd_size. */
-	BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
-	       !(cmd->flags & CMD_SIZE_HUGE));
-	BUG_ON(fix_size > IWL_MAX_CMD_SIZE);
+	 * of device_cmd and max_cmd_size.
+	 */
+	if (WARN_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
+		    !(cmd->flags & CMD_SIZE_HUGE)))
+		return -EINVAL;
+
+	if (WARN_ON(fix_size > IWL_MAX_CMD_SIZE))
+		return -EINVAL;
 
 	if (iwl_is_rfkill(priv) || iwl_is_ctkill(priv)) {
 		IWL_WARN(priv, "Not sending command - %s KILL\n",
@@ -462,16 +470,21 @@
 		return -EIO;
 	}
 
+	/*
+	 * As we only have a single huge buffer, check that the command
+	 * is synchronous (otherwise buffers could end up being reused).
+	 */
+
+	if (WARN_ON((cmd->flags & CMD_ASYNC) && (cmd->flags & CMD_SIZE_HUGE)))
+		return -EINVAL;
+
 	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 =
-				priv->cfg->ops->lib->tt_ops.ct_kill_check(priv);
-		}
+		is_ct_kill = iwl_check_for_ct_kill(priv);
 		if (!is_ct_kill) {
 			IWL_ERR(priv, "Restarting adapter due to queue full\n");
 			iwlagn_fw_error(priv, false);
diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c
index 73a6e62..e22d761 100644
--- a/drivers/net/wireless/mwifiex/11n.c
+++ b/drivers/net/wireless/mwifiex/11n.c
@@ -115,7 +115,7 @@
 		SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask);
 
 	/* Clear RD responder bit */
-	RESETHT_EXTCAP_RDG(ht_ext_cap);
+	ht_ext_cap &= ~IEEE80211_HT_EXT_CAP_RD_RESPONDER;
 
 	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);
@@ -242,9 +242,7 @@
  *
  * 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)
+int mwifiex_ret_11n_cfg(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;
@@ -298,8 +296,7 @@
  *      - 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 mwifiex_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd,
 				int cmd_action, void *data_buf)
 {
 	struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl =
@@ -331,8 +328,7 @@
  *
  * 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,
+int mwifiex_ret_amsdu_aggr_ctrl(struct host_cmd_ds_command *resp,
 				void *data_buf)
 {
 	struct mwifiex_ds_11n_amsdu_aggr_ctrl *amsdu_aggr_ctrl = NULL;
@@ -357,8 +353,7 @@
  *      - 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,
+int mwifiex_cmd_11n_cfg(struct host_cmd_ds_command *cmd,
 			u16 cmd_action, void *data_buf)
 {
 	struct host_cmd_ds_11n_cfg *htcfg = &cmd->params.htcfg;
@@ -541,11 +536,8 @@
 	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;
+		mwifiex_send_cmd_async(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF,
+				       HostCmd_ACT_GEN_SET, 0, &tx_buf);
 }
 
 /*
@@ -583,8 +575,6 @@
 	list_del(&tx_ba_tsr_tbl->list);
 
 	kfree(tx_ba_tsr_tbl);
-
-	return;
 }
 
 /*
@@ -663,8 +653,6 @@
 		list_add_tail(&new_node->list, &priv->tx_ba_stream_tbl_ptr);
 		spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
 	}
-
-	return;
 }
 
 /*
@@ -694,8 +682,8 @@
 	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);
+	ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_ADDBA_REQ,
+				     0, 0, &add_ba_req);
 
 	return ret;
 }
@@ -722,8 +710,8 @@
 	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);
+	ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_DELBA,
+				     HostCmd_ACT_GEN_SET, 0, &delba);
 
 	return ret;
 }
diff --git a/drivers/net/wireless/mwifiex/11n.h b/drivers/net/wireless/mwifiex/11n.h
index 71a853e..02602ff 100644
--- a/drivers/net/wireless/mwifiex/11n.h
+++ b/drivers/net/wireless/mwifiex/11n.h
@@ -28,15 +28,9 @@
 			  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,
+int mwifiex_ret_11n_cfg(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,
+int mwifiex_cmd_11n_cfg(struct host_cmd_ds_command *cmd,
 			u16 cmd_action, void *data_buf);
 
 int mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
@@ -67,24 +61,19 @@
 			      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,
+int mwifiex_ret_amsdu_aggr_ctrl(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);
+int mwifiex_cmd_amsdu_aggr_ctrl(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)
+mwifiex_is_ampdu_allowed(struct mwifiex_private *priv, int tid)
 {
 	return ((priv->aggr_prio_tbl[tid].ampdu_ap != BA_STREAM_NOT_ALLOWED)
 		? true : false);
@@ -94,8 +83,7 @@
  * 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)
+mwifiex_is_amsdu_allowed(struct mwifiex_private *priv, int tid)
 {
 	return (((priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED)
 			&& ((priv->is_data_rate_auto)
@@ -104,23 +92,21 @@
 }
 
 /*
- * This function checks whether a BA stream is available or not.
+ * This function checks whether a space is available for new BA stream or not.
  */
-static inline u8
-mwifiex_is_ba_stream_avail(struct mwifiex_private *priv)
+static inline u8 mwifiex_space_avail_for_new_ba_stream(
+					struct mwifiex_adapter *adapter)
 {
-	struct mwifiex_private *pmpriv = NULL;
-	u8 i = 0;
+	struct mwifiex_private *priv;
+	u8 i;
 	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);
+	for (i = 0; i < adapter->priv_num; i++) {
+		priv = adapter->priv[i];
+		if (priv)
+			ba_stream_num += mwifiex_wmm_list_len(
+						(struct list_head *)
+						&priv->tx_ba_stream_tbl_ptr);
 	}
 
 	return ((ba_stream_num <
@@ -133,8 +119,7 @@
  * 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,
+mwifiex_find_stream_to_delete(struct mwifiex_private *priv, int ptr_tid,
 			      int *ptid, u8 *ra)
 {
 	int tid;
diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c
index c2abced..c9fb062 100644
--- a/drivers/net/wireless/mwifiex/11n_aggr.c
+++ b/drivers/net/wireless/mwifiex/11n_aggr.c
@@ -44,8 +44,7 @@
  * MSDU => |DA|SA|Length|SNAP|......   ..|
  */
 static int
-mwifiex_11n_form_amsdu_pkt(struct mwifiex_adapter *adapter,
-			   struct sk_buff *skb_aggr,
+mwifiex_11n_form_amsdu_pkt(struct sk_buff *skb_aggr,
 			   struct sk_buff *skb_src, int *pad)
 
 {
@@ -324,7 +323,7 @@
 
 		spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
 				       ra_list_flags);
-		mwifiex_11n_form_amsdu_pkt(adapter, skb_aggr, skb_src, &pad);
+		mwifiex_11n_form_amsdu_pkt(skb_aggr, skb_src, &pad);
 
 		mwifiex_write_data_complete(adapter, skb_src, 0);
 
diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c
index 8e94e62..a93c03f 100644
--- a/drivers/net/wireless/mwifiex/11n_rxreorder.c
+++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c
@@ -27,19 +27,6 @@
 #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.
@@ -51,7 +38,7 @@
 					 struct mwifiex_rx_reorder_tbl
 					 *rx_reor_tbl_ptr, int start_win)
 {
-	int no_pkt_to_send, i, xchg;
+	int no_pkt_to_send, i;
 	void *rx_tmp_ptr = NULL;
 	unsigned long flags;
 
@@ -68,7 +55,7 @@
 		}
 		spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
 		if (rx_tmp_ptr)
-			mwifiex_11n_dispatch_pkt(priv, rx_tmp_ptr);
+			mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr);
 	}
 
 	spin_lock_irqsave(&priv->rx_pkt_lock, flags);
@@ -76,8 +63,7 @@
 	 * 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) {
+	for (i = 0; i < rx_reor_tbl_ptr->win_size - no_pkt_to_send; ++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;
@@ -114,7 +100,7 @@
 		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);
+		mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr);
 	}
 
 	spin_lock_irqsave(&priv->rx_pkt_lock, flags);
@@ -309,8 +295,6 @@
 	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;
 }
 
 /*
@@ -321,8 +305,7 @@
  *      - 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)
+int mwifiex_cmd_11n_addba_req(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 *)
@@ -393,8 +376,7 @@
  *      - 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)
+int mwifiex_cmd_11n_delba(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;
@@ -433,7 +415,7 @@
 						tid, ta);
 	if (!rx_reor_tbl_ptr) {
 		if (pkt_type != PKT_TYPE_BAR)
-			mwifiex_11n_dispatch_pkt(priv, payload);
+			mwifiex_process_rx_packet(priv->adapter, payload);
 		return 0;
 	}
 	start_win = rx_reor_tbl_ptr->start_win;
@@ -609,9 +591,7 @@
 	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;
+	mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_DELBA, 0, 0, &delba);
 }
 
 /*
diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.h b/drivers/net/wireless/mwifiex/11n_rxreorder.h
index 42f5690..f3ca8c8 100644
--- a/drivers/net/wireless/mwifiex/11n_rxreorder.h
+++ b/drivers/net/wireless/mwifiex/11n_rxreorder.h
@@ -49,14 +49,12 @@
 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,
+int mwifiex_cmd_11n_delba(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,
+int mwifiex_cmd_11n_addba_req(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
diff --git a/drivers/net/wireless/mwifiex/README b/drivers/net/wireless/mwifiex/README
index 338377f..b55bade 100644
--- a/drivers/net/wireless/mwifiex/README
+++ b/drivers/net/wireless/mwifiex/README
@@ -157,7 +157,7 @@
 	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>
+	cmd_pending = <number of cmd pending>
 	tx_pending = <number of Tx packet pending>
 	rx_pending = <number of Rx packet pending>
 
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index ec0895f..b99ae26 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -34,22 +34,17 @@
 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;
+		return NO_SEC_CHANNEL;
 	case NL80211_CHAN_HT40PLUS:
-		channel = SEC_CHANNEL_ABOVE;
-		break;
+		return SEC_CHANNEL_ABOVE;
 	case NL80211_CHAN_HT40MINUS:
-		channel = SEC_CHANNEL_BELOW;
-		break;
+		return SEC_CHANNEL_BELOW;
 	default:
-		channel = NO_SEC_CHANNEL;
+		return NO_SEC_CHANNEL;
 	}
-	return channel;
 }
 
 /*
@@ -64,21 +59,16 @@
 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;
+		return NL80211_CHAN_HT20;
 	case SEC_CHANNEL_ABOVE:
-		channel = NL80211_CHAN_HT40PLUS;
-		break;
+		return NL80211_CHAN_HT40PLUS;
 	case SEC_CHANNEL_BELOW:
-		channel = NL80211_CHAN_HT40MINUS;
-		break;
+		return NL80211_CHAN_HT40MINUS;
 	default:
-		channel = NL80211_CHAN_HT20;
+		return NL80211_CHAN_HT20;
 	}
-	return channel;
 }
 
 /*
@@ -117,10 +107,8 @@
 			 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) {
+	if (mwifiex_set_encode(priv, NULL, 0, key_index, 1)) {
 		wiphy_err(wiphy, "deleting the crypto keys\n");
 		return -EFAULT;
 	}
@@ -137,12 +125,17 @@
 			      enum nl80211_tx_power_setting type,
 			      int dbm)
 {
-	int ret = 0;
 	struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
+	struct mwifiex_power_cfg power_cfg;
 
-	ret = mwifiex_set_tx_power(priv, type, dbm);
+	if (type == NL80211_TX_POWER_FIXED) {
+		power_cfg.is_power_auto = 0;
+		power_cfg.power_level = dbm;
+	} else {
+		power_cfg.is_power_auto = 1;
+	}
 
-	return ret;
+	return mwifiex_set_tx_power(priv, &power_cfg);
 }
 
 /*
@@ -155,17 +148,17 @@
 				struct net_device *dev,
 				bool enabled, int timeout)
 {
-	int ret = 0;
 	struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
+	u32 ps_mode;
 
 	if (timeout)
 		wiphy_dbg(wiphy,
 			"info: ignoring the timeout value"
 			" for IEEE power save\n");
 
-	ret = mwifiex_drv_set_power(priv, enabled);
+	ps_mode = enabled;
 
-	return ret;
+	return mwifiex_drv_set_power(priv, &ps_mode);
 }
 
 /*
@@ -177,18 +170,15 @@
 				 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)
+	if (mwifiex_set_encode(priv, NULL, 0, key_index, 0)) {
+		wiphy_err(wiphy, "set default Tx key index\n");
 		return -EFAULT;
+	}
 
 	return 0;
 }
@@ -202,15 +192,12 @@
 			 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)
+	if (mwifiex_set_encode(priv, params->key, params->key_len,
+							key_index, 0)) {
+		wiphy_err(wiphy, "crypto keys added\n");
 		return -EFAULT;
+	}
 
 	return 0;
 }
@@ -235,7 +222,6 @@
 	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];
@@ -290,13 +276,14 @@
 	}
 
 	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;
+	if (mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11D_DOMAIN_INFO,
+				     HostCmd_ACT_GEN_SET, 0, NULL)) {
+		wiphy_err(wiphy, "11D: setting domain info in FW\n");
+		return -1;
+	}
+
+	return 0;
 }
 
 /*
@@ -346,8 +333,6 @@
 		       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;
@@ -366,15 +351,14 @@
 			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)
+		if (mwifiex_set_radio_band_cfg(priv, &band_cfg))
 			return -EFAULT;
+
 		mwifiex_send_domain_info_cmd_fw(wiphy);
 	}
 
@@ -382,20 +366,16 @@
 		"mode %d\n", config_bands, band_cfg.sec_chan_offset,
 		priv->bss_mode);
 	if (!chan)
-		return ret;
+		return 0;
 
 	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)
+	if (mwifiex_bss_set_channel(priv, &cfp))
 		return -EFAULT;
 
-	ret = mwifiex_drv_change_adhoc_chan(priv, cfp.channel);
-
-	return ret;
+	return mwifiex_drv_change_adhoc_chan(priv, cfp.channel);
 }
 
 /*
@@ -422,67 +402,41 @@
 /*
  * 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
+ * The fragmentation threshold value must lie 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;
+	/* Send request to firmware */
+	ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
+				    HostCmd_ACT_GEN_SET, FRAG_THRESH_I,
+				    &frag_thr);
 
-	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.
+
+ * The rts value must lie between MWIFIEX_RTS_MIN_VALUE
+ * and MWIFIEX_RTS_MAX_VALUE.
  */
 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;
+	return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
+				    HostCmd_ACT_GEN_SET, RTS_THRESH_I,
+				    &rts_thr);
 }
 
 /*
@@ -498,8 +452,11 @@
 
 	int ret = 0;
 
-	if (changed & WIPHY_PARAM_RTS_THRESHOLD)
+	if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
 		ret = mwifiex_set_rts(priv, wiphy->rts_threshold);
+		if (ret)
+			return ret;
+	}
 
 	if (changed & WIPHY_PARAM_FRAG_THRESHOLD)
 		ret = mwifiex_set_frag(priv, wiphy->frag_threshold);
@@ -518,7 +475,6 @@
 {
 	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");
@@ -545,24 +501,13 @@
 		return -EINVAL;
 	}
 
-	wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT);
-	if (!wait)
-		return -ENOMEM;
-
-	mwifiex_deauthenticate(priv, wait, NULL);
+	mwifiex_deauthenticate(priv, 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_send_cmd_sync(priv, HostCmd_CMD_SET_BSS_MODE,
+				    HostCmd_ACT_GEN_SET, 0, NULL);
 
-	ret = mwifiex_request_ioctl(priv, wait, ret, MWIFIEX_IOCTL_WAIT);
-	if (ret)
-		ret = -EFAULT;
-
-	kfree(wait);
 	return ret;
 }
 
@@ -592,7 +537,7 @@
 
 	/* 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)) {
+	if (mwifiex_get_signal_info(priv, &signal)) {
 		dev_err(priv->adapter->dev, "getting signal information\n");
 		ret = -EFAULT;
 	}
@@ -623,7 +568,6 @@
 			     u8 *mac, struct station_info *sinfo)
 {
 	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
-	int ret = 0;
 
 	mwifiex_dump_station_info(priv, sinfo);
 
@@ -632,10 +576,7 @@
 	if (memcmp(mac, priv->cfg_bssid, ETH_ALEN))
 		return -ENOENT;
 
-
-	ret = mwifiex_dump_station_info(priv, sinfo);
-
-	return ret;
+	return mwifiex_dump_station_info(priv, sinfo);
 }
 
 /* Supported rates to be advertised to the cfg80211 */
@@ -750,7 +691,7 @@
 		return -EBUSY;
 
 	priv->disconnect = 1;
-	if (mwifiex_disconnect(priv, MWIFIEX_IOCTL_WAIT, NULL))
+	if (mwifiex_deauthenticate(priv, NULL))
 		return -EFAULT;
 
 	wiphy_dbg(wiphy, "info: successfully disconnected from %pM:"
@@ -774,15 +715,13 @@
  */
 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;
+	if (mwifiex_get_bss_info(priv, &bss_info))
+		return -1;
 
 	ie_buf[0] = WLAN_EID_SSID;
 	ie_buf[1] = bss_info.ssid.ssid_len;
@@ -801,7 +740,7 @@
 		0, ie_buf, ie_len, 0, GFP_KERNEL);
 	memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN);
 
-	return ret;
+	return 0;
 }
 
 /*
@@ -830,16 +769,15 @@
 	struct mwifiex_bssdescriptor *scan_table;
 	int i, j;
 	struct ieee80211_channel *chan;
-	u8 *ie, *tmp, *ie_buf;
+	u8 *ie, *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;
+	scan_resp.scan_table = (u8 *) priv->adapter->scan_table;
+	scan_resp.num_in_scan_table = priv->adapter->num_in_scan_table;
 
 #define MAX_IE_BUF	2048
 	ie_buf = kzalloc(MAX_IE_BUF, GFP_KERNEL);
@@ -914,9 +852,9 @@
 			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),
+				       (u8 *) beacon
+				       + sizeof(struct ieee_types_header),
 				       element_len);
 				ie_len += ie[1] +
 					sizeof(struct ieee_types_header);
@@ -933,7 +871,7 @@
 						scan_table[i].freq);
 		cfg80211_inform_bss(priv->wdev->wiphy, chan,
 					scan_table[i].mac_address,
-					ts, scan_table[i].cap_info_bitmap,
+					0, scan_table[i].cap_info_bitmap,
 					scan_table[i].beacon_period,
 					ie_buf, ie_len,
 					scan_table[i].rssi, GFP_KERNEL);
@@ -966,9 +904,7 @@
 	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;
+	int auth_type = 0;
 
 	memset(&req_ssid, 0, sizeof(struct mwifiex_802_11_ssid));
 	memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid));
@@ -986,7 +922,7 @@
 	}
 
 	/* disconnect before try to associate */
-	mwifiex_disconnect(priv, MWIFIEX_IOCTL_WAIT, NULL);
+	mwifiex_deauthenticate(priv, NULL);
 
 	if (channel)
 		ret = mwifiex_set_rf_channel(priv, channel,
@@ -1034,9 +970,7 @@
 		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) {
+		if (mwifiex_is_alg_wep(0) | mwifiex_is_alg_wep(0)) {
 			dev_dbg(priv->adapter->dev,
 				"info: setting wep encryption"
 				" with key len %d\n", sme->key_len);
@@ -1046,7 +980,7 @@
 	}
 done:
 	/* Do specific SSID scanning */
-	if (mwifiex_request_scan(priv, MWIFIEX_IOCTL_WAIT, &req_ssid)) {
+	if (mwifiex_request_scan(priv, &req_ssid)) {
 		dev_err(priv->adapter->dev, "scan error\n");
 		return -EFAULT;
 	}
@@ -1055,8 +989,7 @@
 	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))
+		if (mwifiex_find_best_bss(priv, &ssid_bssid))
 			return -EFAULT;
 		/* Inform the BSS information to kernel, otherwise
 		 * kernel will give a panic after successful assoc */
@@ -1072,7 +1005,10 @@
 	/* Connect to BSS by ESSID */
 	memset(&ssid_bssid.bssid, 0, ETH_ALEN);
 
-	if (mwifiex_bss_start(priv, MWIFIEX_IOCTL_WAIT, &ssid_bssid))
+	if (!netif_queue_stopped(priv->netdev))
+		netif_stop_queue(priv->netdev);
+
+	if (mwifiex_bss_start(priv, &ssid_bssid))
 		return -EFAULT;
 
 	if (mode == NL80211_IFTYPE_ADHOC) {
@@ -1176,7 +1112,7 @@
 
 	wiphy_dbg(wiphy, "info: disconnecting from essid %pM\n",
 			priv->cfg_bssid);
-	if (mwifiex_disconnect(priv, MWIFIEX_IOCTL_WAIT, NULL))
+	if (mwifiex_deauthenticate(priv, NULL))
 		return -EFAULT;
 
 	queue_work(priv->workqueue, &priv->cfg_workqueue);
@@ -1451,6 +1387,4 @@
 		memset(priv->cfg_bssid, 0, ETH_ALEN);
 		priv->disconnect = 0;
 	}
-
-	return;
 }
diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c
index 07187a4..d0cada5 100644
--- a/drivers/net/wireless/mwifiex/cfp.c
+++ b/drivers/net/wireless/mwifiex/cfp.c
@@ -75,8 +75,7 @@
  * 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)
+u32 mwifiex_index_to_data_rate(u8 index, u8 ht_info)
 {
 	u16 mcs_rate[4][8] = {
 		{0x1b, 0x36, 0x51, 0x6c, 0xa2, 0xd8, 0xf3, 0x10e}
@@ -126,7 +125,7 @@
  * 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)
+u8 mwifiex_data_rate_to_index(u32 rate)
 {
 	u16 *ptr;
 
@@ -146,16 +145,12 @@
  */
 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);
+		return mwifiex_get_supported_rates(priv, rates);
 	else
-		k = mwifiex_copy_rates(rates, 0,
+		return mwifiex_copy_rates(rates, 0,
 				       priv->curr_bss_params.data_rates,
 				       priv->curr_bss_params.num_of_rates);
-
-	return k;
 }
 
 /*
@@ -265,9 +260,7 @@
 /*
  * This function converts rate bitmap into rate index.
  */
-int
-mwifiex_get_rate_index(struct mwifiex_adapter *adapter, u16 *rate_bitmap,
-		       int size)
+int mwifiex_get_rate_index(u16 *rate_bitmap, int size)
 {
 	int i;
 
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c
index a9aeb31..776146a 100644
--- a/drivers/net/wireless/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/mwifiex/cmdevt.c
@@ -36,11 +36,12 @@
 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)
+		      u32 cmd_oid, void *data_buf)
 {
 	cmd_node->priv = priv;
 	cmd_node->cmd_oid = cmd_oid;
-	cmd_node->wq_buf = wait_queue;
+	cmd_node->wait_q_enabled = priv->adapter->cmd_wait_q_required;
+	priv->adapter->cmd_wait_q_required = false;
 	cmd_node->data_buf = data_buf;
 	cmd_node->cmd_skb = cmd_node->skb;
 }
@@ -86,39 +87,13 @@
 {
 	cmd_node->cmd_oid = 0;
 	cmd_node->cmd_flag = 0;
-	cmd_node->wq_buf = NULL;
 	cmd_node->data_buf = NULL;
+	cmd_node->wait_q_enabled = false;
 
 	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;
 }
 
 /*
@@ -155,7 +130,6 @@
 	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;
@@ -165,15 +139,13 @@
 		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;
+		if (cmd_node->wait_q_enabled)
+			adapter->cmd_wait_q.status = -1;
 		mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
 		return -1;
 	}
@@ -206,10 +178,12 @@
 					     cmd_node->cmd_skb->data,
 					     cmd_node->cmd_skb->len, NULL);
 
+	skb_pull(cmd_node->cmd_skb, INTF_HEADER_LEN);
+
 	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;
+		if (cmd_node->wait_q_enabled)
+			adapter->cmd_wait_q.status = -1;
 		mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
 
 		spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
@@ -435,7 +409,31 @@
 }
 
 /*
- * This function prepares a command before sending it to the firmware.
+ * This function is used to send synchronous command to the firmware.
+ *
+ * it allocates a wait queue for the command and wait for the command
+ * response.
+ */
+int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no,
+			  u16 cmd_action, u32 cmd_oid, void *data_buf)
+{
+	int ret = 0;
+	struct mwifiex_adapter *adapter = priv->adapter;
+
+	adapter->cmd_wait_q_required = true;
+	adapter->cmd_wait_q.condition = false;
+
+	ret = mwifiex_send_cmd_async(priv, cmd_no, cmd_action, cmd_oid,
+				     data_buf);
+	if (!ret)
+		ret = mwifiex_wait_queue_complete(adapter);
+
+	return ret;
+}
+
+
+/*
+ * This function prepares a command and asynchronously send it to the firmware.
  *
  * Preparation includes -
  *      - Sanity tests to make sure the card is still present or the FW
@@ -445,9 +443,8 @@
  *      - 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 mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no,
+			   u16 cmd_action, u32 cmd_oid, void *data_buf)
 {
 	int ret = 0;
 	struct mwifiex_adapter *adapter = priv->adapter;
@@ -485,7 +482,7 @@
 	}
 
 	/* Initialize the command node */
-	mwifiex_init_cmd_node(priv, cmd_node, cmd_oid, wait_queue, data_buf);
+	mwifiex_init_cmd_node(priv, cmd_node, cmd_oid, data_buf);
 
 	if (!cmd_node->cmd_skb) {
 		dev_err(adapter->dev, "PREP_CMD: no free cmd buf\n");
@@ -535,18 +532,13 @@
 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)
+	if (!cmd_node)
 		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);
-	}
+
+	if (cmd_node->wait_q_enabled)
+		mwifiex_complete_cmd(adapter);
 	/* Clean the node */
 	mwifiex_clean_cmd_node(adapter, cmd_node);
 
@@ -554,8 +546,6 @@
 	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;
 }
 
 /*
@@ -600,8 +590,6 @@
 	spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
 
 	dev_dbg(adapter->dev, "cmd: QUEUE_CMD: cmd=%#x is queued\n", command);
-
-	return;
 }
 
 /*
@@ -692,7 +680,6 @@
 	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;
 
@@ -706,10 +693,6 @@
 		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;
@@ -764,8 +747,8 @@
 
 	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;
+		if (adapter->curr_cmd->wait_q_enabled)
+			adapter->cmd_wait_q.status = -1;
 
 		mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
 		spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
@@ -781,8 +764,7 @@
 			ret = mwifiex_ret_802_11_hs_cfg(priv, resp);
 	} else {
 		/* handle response */
-		ret = mwifiex_process_sta_cmdresp(priv, cmdresp_no, resp,
-						  wait_queue);
+		ret = mwifiex_process_sta_cmdresp(priv, cmdresp_no, resp);
 	}
 
 	/* Check init command response */
@@ -797,10 +779,10 @@
 	}
 
 	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;
+		if (adapter->curr_cmd->wait_q_enabled && (!ret))
+			adapter->cmd_wait_q.status = 0;
+		else if (adapter->curr_cmd->wait_q_enabled && (ret == -1))
+			adapter->cmd_wait_q.status = -1;
 
 		/* Clean up and put current command back to cmd_free_q */
 		mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
@@ -824,7 +806,6 @@
 	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++;
@@ -834,10 +815,8 @@
 		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->wait_q_enabled)
+		adapter->cmd_wait_q.status = -ETIMEDOUT;
 
 	if (cmd_node) {
 		adapter->dbg.timeout_cmd_id =
@@ -886,8 +865,6 @@
 	}
 	if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING)
 		mwifiex_init_fw_complete(adapter);
-
-	return;
 }
 
 /*
@@ -901,18 +878,15 @@
 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;
+	if ((adapter->curr_cmd) && (adapter->curr_cmd->wait_q_enabled)) {
 		spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
-		adapter->curr_cmd->wq_buf = NULL;
+		adapter->curr_cmd->wait_q_enabled = false;
 		spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
-		wait_queue->status = MWIFIEX_ERROR_CMD_CANCEL;
-		mwifiex_ioctl_complete(adapter, wait_queue, -1);
+		adapter->cmd_wait_q.status = -1;
+		mwifiex_complete_cmd(adapter);
 	}
 	/* Cancel all pending command */
 	spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
@@ -921,12 +895,10 @@
 		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;
+		if (cmd_node->wait_q_enabled) {
+			adapter->cmd_wait_q.status = -1;
+			mwifiex_complete_cmd(adapter);
+			cmd_node->wait_q_enabled = false;
 		}
 		mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
 		spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
@@ -940,7 +912,7 @@
 		list_del(&cmd_node->list);
 		spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
 
-		cmd_node->wq_buf = NULL;
+		cmd_node->wait_q_enabled = false;
 		mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
 		spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
 	}
@@ -962,8 +934,7 @@
  * are cancelled.
  */
 void
-mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter,
-			     struct mwifiex_wait_queue *wait_queue)
+mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
 {
 	struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL;
 	unsigned long cmd_flags;
@@ -972,45 +943,33 @@
 	uint16_t cancel_scan_cmd = false;
 
 	if ((adapter->curr_cmd) &&
-	    (adapter->curr_cmd->wq_buf == wait_queue)) {
+	     (adapter->curr_cmd->wait_q_enabled)) {
 		spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
 		cmd_node = adapter->curr_cmd;
-		cmd_node->wq_buf = NULL;
+		cmd_node->wait_q_enabled = false;
 		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);
 	}
-	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;
-		}
+		list_del(&cmd_node->list);
+		spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
+				       scan_pending_q_flags);
+		cmd_node->wait_q_enabled = false;
+		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);
@@ -1020,10 +979,8 @@
 		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;
+	adapter->cmd_wait_q.status = -1;
+	mwifiex_complete_cmd(adapter);
 }
 
 /*
@@ -1127,7 +1084,6 @@
 	adapter->is_hs_configured = false;
 	mwifiex_hs_activated_event(mwifiex_get_priv(adapter,
 				   MWIFIEX_BSS_ROLE_ANY), false);
-	return;
 }
 
 /*
diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c
index 63b0969..7ddcb06 100644
--- a/drivers/net/wireless/mwifiex/debugfs.c
+++ b/drivers/net/wireless/mwifiex/debugfs.c
@@ -129,8 +129,8 @@
 	 item_addr(event_received), 1},
 
 	/* variables defined in struct mwifiex_adapter */
-	{"ioctl_pending", adapter_item_size(ioctl_pending),
-	 adapter_item_addr(ioctl_pending), 1},
+	{"cmd_pending", adapter_item_size(cmd_pending),
+	 adapter_item_addr(cmd_pending), 1},
 	{"tx_pending", adapter_item_size(tx_pending),
 	 adapter_item_addr(tx_pending), 1},
 	{"rx_pending", adapter_item_size(rx_pending),
@@ -735,8 +735,6 @@
 	MWIFIEX_DFS_ADD_FILE(getlog);
 	MWIFIEX_DFS_ADD_FILE(regrdwr);
 	MWIFIEX_DFS_ADD_FILE(rdeeprom);
-
-	return;
 }
 
 /*
@@ -749,7 +747,6 @@
 		return;
 
 	debugfs_remove_recursive(priv->dfs_dev_dir);
-	return;
 }
 
 /*
diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h
index c3c15f9..0e90b09 100644
--- a/drivers/net/wireless/mwifiex/decl.h
+++ b/drivers/net/wireless/mwifiex/decl.h
@@ -61,23 +61,6 @@
 
 #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,
@@ -112,12 +95,9 @@
 };
 
 struct mwifiex_wait_queue {
-	u32 bss_index;
-	wait_queue_head_t *wait;
-	u16 *condition;
-	u32 start_time;
+	wait_queue_head_t wait;
+	u16 condition;
 	int status;
-	u32 enabled;
 };
 
 struct mwifiex_rxinfo {
@@ -133,11 +113,11 @@
 };
 
 struct mwifiex_bss_attr {
-	u32 bss_type;
-	u32 frame_type;
-	u32 active;
-	u32 bss_priority;
-	u32 bss_num;
+	u8 bss_type;
+	u8 frame_type;
+	u8 active;
+	u8 bss_priority;
+	u8 bss_num;
 };
 
 enum mwifiex_wmm_ac_e {
@@ -146,8 +126,4 @@
 	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
index 2b93811..6d1c454 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -72,33 +72,12 @@
 	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 KEY_MCAST	BIT(0)
+#define KEY_UNICAST	BIT(1)
+#define KEY_ENABLED	BIT(2)
 
 #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
@@ -155,7 +134,6 @@
 
 #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))
 
@@ -180,7 +158,6 @@
 #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))
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index 8189862..fc2c0c5 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -35,7 +35,6 @@
 {
 	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);
@@ -59,7 +58,7 @@
 	spin_unlock_irqrestore(&adapter->bss_prio_tbl[priv->bss_priority]
 			.bss_prio_lock, flags);
 
-	return status;
+	return 0;
 }
 
 /*
@@ -72,7 +71,6 @@
 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);
@@ -140,9 +138,7 @@
 
 	priv->scan_block = false;
 
-	ret = mwifiex_add_bss_prio_tbl(priv);
-
-	return ret;
+	return mwifiex_add_bss_prio_tbl(priv);
 }
 
 /*
@@ -300,8 +296,6 @@
 	adapter->adhoc_awake_period = 0;
 	memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter));
 	adapter->arp_filter_size = 0;
-
-	return;
 }
 
 /*
@@ -340,8 +334,6 @@
 	adapter->if_ops.cleanup_if(adapter);
 
 	dev_kfree_skb_any(adapter->sleep_cfm);
-
-	return;
 }
 
 /*
@@ -429,8 +421,6 @@
 			list_del(&priv->rx_reorder_tbl_ptr);
 		}
 	}
-
-	return;
 }
 
 /*
diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h
index 703a6d1..5488e11 100644
--- a/drivers/net/wireless/mwifiex/ioctl.h
+++ b/drivers/net/wireless/mwifiex/ioctl.h
@@ -268,14 +268,13 @@
 };
 
 #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 key_material[WLAN_MAX_KEY_LEN];
 	u8 mac_addr[ETH_ALEN];
 	u32 is_wapi_key;
 	u8 wapi_rxpn[WAPI_RXPN_LEN];
diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c
index 7a9e0b5..23d2d0b 100644
--- a/drivers/net/wireless/mwifiex/join.c
+++ b/drivers/net/wireless/mwifiex/join.c
@@ -590,11 +590,10 @@
  * 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)
+			     struct host_cmd_ds_command *resp)
 {
+	struct mwifiex_adapter *adapter = priv->adapter;
 	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;
@@ -718,16 +717,11 @@
 
 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;
-		}
+	if (adapter->curr_cmd->wait_q_enabled) {
+		if (ret)
+			adapter->cmd_wait_q.status = -1;
+		else
+			adapter->cmd_wait_q.status = 0;
 	}
 
 	return ret;
@@ -755,7 +749,7 @@
 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;
+	int 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;
@@ -885,11 +879,9 @@
 	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) {
+		if (mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL,
+					     HostCmd_ACT_GEN_SET, 0,
+					     &priv->curr_pkt_filter)) {
 			dev_err(adapter->dev,
 			       "ADHOC_S_CMD: G Protection config failed\n");
 			return -1;
@@ -1003,7 +995,7 @@
 					IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
 			}
 			ht_info->ht_info.operation_mode =
-				cpu_to_le16(NON_GREENFIELD_STAS);
+			     cpu_to_le16(IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
 			ht_info->ht_info.basic_set[0] = 0xff;
 			pos += sizeof(struct mwifiex_ie_types_htinfo);
 			cmd_append_size +=
@@ -1045,7 +1037,7 @@
 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;
+	int rsn_ie_len = 0;
 	struct host_cmd_ds_802_11_ad_hoc_join *adhoc_join =
 		&cmd->params.adhoc_join;
 	struct mwifiex_bssdescriptor *bss_desc =
@@ -1066,10 +1058,9 @@
 			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) {
+		if (mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL,
+					     HostCmd_ACT_GEN_SET, 0,
+					     &curr_pkt_filter)) {
 			dev_err(priv->adapter->dev,
 			       "ADHOC_J_CMD: G Protection config failed\n");
 			return -1;
@@ -1180,7 +1171,7 @@
 
 	adhoc_join->bss_descriptor.cap_info_bitmap = cpu_to_le16(tmp_cap);
 
-	return ret;
+	return 0;
 }
 
 /*
@@ -1192,22 +1183,19 @@
  * saves the beacon buffer.
  */
 int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv,
-			      struct host_cmd_ds_command *resp, void *wq_buf)
+			      struct host_cmd_ds_command *resp)
 {
 	int ret = 0;
-	struct mwifiex_wait_queue *wait_queue =
-		(struct mwifiex_wait_queue *) wq_buf;
+	struct mwifiex_adapter *adapter = priv->adapter;
 	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) {
+	if (le16_to_cpu(resp->result)) {
 		dev_err(priv->adapter->dev, "ADHOC_RESP: failed\n");
 		if (priv->media_connected)
 			mwifiex_reset_connect_state(priv);
@@ -1222,7 +1210,7 @@
 	/* Send a Media Connected event, according to the Spec */
 	priv->media_connected = true;
 
-	if (command == HostCmd_CMD_802_11_AD_HOC_START) {
+	if (le16_to_cpu(resp->command) == HostCmd_CMD_802_11_AD_HOC_START) {
 		dev_dbg(priv->adapter->dev, "info: ADHOC_S_RESP %s\n",
 				bss_desc->ssid.ssid);
 
@@ -1264,11 +1252,11 @@
 
 done:
 	/* Need to indicate IOCTL complete */
-	if (wait_queue) {
+	if (adapter->curr_cmd->wait_q_enabled) {
 		if (ret)
-			wait_queue->status = MWIFIEX_ERROR_ASSOC_FAIL;
+			adapter->cmd_wait_q.status = -1;
 		else
-			wait_queue->status = MWIFIEX_ERROR_NO_ERROR;
+			adapter->cmd_wait_q.status = 0;
 
 	}
 
@@ -1283,9 +1271,8 @@
  * command to firmware.
  */
 int mwifiex_associate(struct mwifiex_private *priv,
-		      void *wait_queue, struct mwifiex_bssdescriptor *bss_desc)
+		      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 */
@@ -1301,11 +1288,8 @@
 	   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;
+	return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_ASSOCIATE,
+				    HostCmd_ACT_GEN_SET, 0, bss_desc);
 }
 
 /*
@@ -1315,10 +1299,8 @@
  */
 int
 mwifiex_adhoc_start(struct mwifiex_private *priv,
-		    void *wait_queue, struct mwifiex_802_11_ssid *adhoc_ssid)
+		    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",
@@ -1326,11 +1308,8 @@
 	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;
+	return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_AD_HOC_START,
+				    HostCmd_ACT_GEN_SET, 0, adhoc_ssid);
 }
 
 /*
@@ -1340,10 +1319,8 @@
  * if already not connected to the requested SSID.
  */
 int mwifiex_adhoc_join(struct mwifiex_private *priv,
-		       void *wait_queue, struct mwifiex_bssdescriptor *bss_desc)
+		       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",
@@ -1369,20 +1346,15 @@
 	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;
+	return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_AD_HOC_JOIN,
+				    HostCmd_ACT_GEN_SET, 0, bss_desc);
 }
 
 /*
  * 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)
+static int mwifiex_deauthenticate_infra(struct mwifiex_private *priv, u8 *mac)
 {
 	u8 mac_address[ETH_ALEN];
 	int ret = 0;
@@ -1400,11 +1372,8 @@
 		       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;
+	ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_DEAUTHENTICATE,
+				    HostCmd_ACT_GEN_SET, 0, &mac_address);
 
 	return ret;
 }
@@ -1415,26 +1384,23 @@
  * 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 mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac)
 {
 	int ret = 0;
 
 	if (priv->media_connected) {
 		if (priv->bss_mode == NL80211_IFTYPE_STATION) {
-			ret = mwifiex_deauthenticate_infra(priv, wait, mac);
+			ret = mwifiex_deauthenticate_infra(priv, 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;
+			ret = mwifiex_send_cmd_sync(priv,
+						HostCmd_CMD_802_11_AD_HOC_STOP,
+						HostCmd_ACT_GEN_SET, 0, NULL);
 		}
 	}
 
 	return ret;
 }
+EXPORT_SYMBOL_GPL(mwifiex_deauthenticate);
 
 /*
  * This function converts band to radio type used in channel TLV.
@@ -1442,21 +1408,15 @@
 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;
+		return HostCmd_SCAN_RADIO_TYPE_A;
 	case BAND_B:
 	case BAND_G:
 	case BAND_B | BAND_G:
 	default:
-		ret_radio_type = HostCmd_SCAN_RADIO_TYPE_BG;
-		break;
+		return HostCmd_SCAN_RADIO_TYPE_BG;
 	}
-
-	return ret_radio_type;
 }
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
index ed89ca4..c597188 100644
--- a/drivers/net/wireless/mwifiex/main.c
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -40,14 +40,10 @@
 /* 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,
-	 }
-	,
+		.drv_mode = DRV_MODE_STA,
+		.intf_num = ARRAY_SIZE(mwifiex_bss_sta),
+		.bss_attr = mwifiex_bss_sta,
+	},
 };
 
 /*
@@ -66,14 +62,12 @@
  * proper cleanup before exiting.
  */
 static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops,
-			    struct mwifiex_device *mdevice, void **padapter)
+			    struct mwifiex_drv_mode *drv_mode_ptr)
 {
-	int ret = 0;
-	struct mwifiex_adapter *adapter = NULL;
-	u8 i = 0;
+	struct mwifiex_adapter *adapter;
+	int i;
 
 	adapter = kzalloc(sizeof(struct mwifiex_adapter), GFP_KERNEL);
-	/* Allocate memory for adapter structure */
 	if (!adapter)
 		return -1;
 
@@ -84,19 +78,17 @@
 	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)
+	if (adapter->if_ops.init_if(adapter))
 		goto error;
 
 	adapter->priv_num = 0;
-	for (i = 0; i < MWIFIEX_MAX_BSS_NUM; i++) {
+	for (i = 0; i < drv_mode_ptr->intf_num; i++) {
 		adapter->priv[i] = NULL;
 
-		if (!mdevice->bss_attr[i].active)
+		if (!drv_mode_ptr->bss_attr[i].active)
 			continue;
 
-		/* For valid bss_attr,
-		   allocate memory for private structure */
+		/* Allocate memory for private structure */
 		adapter->priv[i] = kzalloc(sizeof(struct mwifiex_private),
 				GFP_KERNEL);
 		if (!adapter->priv[i]) {
@@ -106,26 +98,26 @@
 		}
 
 		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]->bss_type = drv_mode_ptr->bss_attr[i].bss_type;
 		adapter->priv[i]->frame_type =
-			(u8) mdevice->bss_attr[i].frame_type;
+					drv_mode_ptr->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)
+					drv_mode_ptr->bss_attr[i].bss_priority;
+
+		if (drv_mode_ptr->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)
+		else if (drv_mode_ptr->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;
+		adapter->priv[i]->bss_num = drv_mode_ptr->bss_attr[i].bss_num;
 	}
+	adapter->drv_mode = drv_mode_ptr;
 
-	/* Initialize lock variables */
 	if (mwifiex_init_lock_list(adapter))
 		goto error;
 
@@ -133,16 +125,13 @@
 	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++)
+	for (i = 0; i < drv_mode_ptr->intf_num; i++)
 		kfree(adapter->priv[i]);
 	kfree(adapter);
 
@@ -337,10 +326,9 @@
  * and initializing the private structures.
  */
 static int
-mwifiex_init_sw(void *card, struct mwifiex_if_ops *if_ops, void **pmwifiex)
+mwifiex_init_sw(void *card, struct mwifiex_if_ops *if_ops)
 {
 	int i;
-	struct mwifiex_device device;
 	struct mwifiex_drv_mode *drv_mode_ptr;
 
 	/* find mwifiex_drv_mode entry from mwifiex_drv_mode_tbl */
@@ -357,20 +345,7 @@
 		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))
+	if (mwifiex_register(card, if_ops, drv_mode_ptr))
 		return -1;
 
 	return 0;
@@ -505,7 +480,6 @@
 	 */
 	do_gettimeofday(&tv);
 	skb->tstamp = timeval_to_ktime(tv);
-	return;
 }
 
 /*
@@ -597,16 +571,23 @@
 {
 	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
 	struct sockaddr *hw_addr = (struct sockaddr *) addr;
+	int ret = 0;
 
 	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;
-	}
+	/* Send request to firmware */
+	ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_MAC_ADDRESS,
+				    HostCmd_ACT_GEN_SET, 0, NULL);
+
+	if (!ret)
+		memcpy(priv->netdev->dev_addr, priv->curr_addr, ETH_ALEN);
+	else
+		dev_err(priv->adapter->dev, "set mac address failed: ret=%d"
+					    "\n", ret);
+
 	memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN);
 
-	return 0;
+	return ret;
 }
 
 /*
@@ -615,7 +596,20 @@
 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);
+	struct mwifiex_multicast_list mcast_list;
+
+	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);
+	}
+	mwifiex_request_set_multicast_list(priv, &mcast_list);
 }
 
 /*
@@ -677,9 +671,6 @@
 {
 	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));
@@ -803,37 +794,9 @@
 	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)
@@ -905,30 +868,30 @@
 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];
+	struct mwifiex_adapter *adapter;
 
 	if (down_interruptible(sem))
 		goto exit_sem_err;
 
-	if (mwifiex_init_sw(card, if_ops, (void **) &adapter)) {
+	if (mwifiex_init_sw(card, if_ops)) {
 		pr_err("%s: software init failed\n", __func__);
 		goto err_init_sw;
 	}
 
-	adapter->drv_mode = drv_mode_info;
+	adapter = g_adapter;
 
 	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);
+	adapter->cmd_wait_q_required = false;
+	init_waitqueue_head(&adapter->cmd_wait_q.wait);
+	adapter->cmd_wait_q.condition = false;
+	adapter->cmd_wait_q.status = 0;
 
-	/* Create workqueue */
 	adapter->workqueue = create_workqueue("MWIFIEX_WORK_QUEUE");
 	if (!adapter->workqueue)
 		goto err_kmalloc;
@@ -942,21 +905,18 @@
 		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++) {
+	for (i = 0; i < adapter->drv_mode->intf_num; i++) {
 		if (!mwifiex_add_interface(adapter, i,
 				adapter->drv_mode->bss_attr[i].bss_type)) {
-			status = -1;
-			break;
+			goto err_add_intf;
 		}
 	}
-	if (status)
-		goto err_add_intf;
 
 	up(sem);
 
@@ -966,7 +926,6 @@
 	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:
@@ -977,8 +936,8 @@
 	    (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)
+
+		if (mwifiex_shutdown_drv(adapter) == -EINPROGRESS)
 			wait_event_interruptible(adapter->init_wait_q,
 						 adapter->init_wait_q_woken);
 	}
@@ -1007,7 +966,6 @@
 int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem)
 {
 	struct mwifiex_private *priv = NULL;
-	int status;
 	int i;
 
 	if (down_interruptible(sem))
@@ -1031,19 +989,19 @@
 
 	dev_dbg(adapter->dev, "cmd: calling mwifiex_shutdown_drv...\n");
 	adapter->init_wait_q_woken = false;
-	status = mwifiex_shutdown_drv(adapter);
-	if (status == -EINPROGRESS)
+
+	if (mwifiex_shutdown_drv(adapter) == -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)) {
+	    atomic_read(&adapter->cmd_pending)) {
 		dev_err(adapter->dev, "rx_pending=%d, tx_pending=%d, "
-		       "ioctl_pending=%d\n",
+		       "cmd_pending=%d\n",
 		       atomic_read(&adapter->rx_pending),
 		       atomic_read(&adapter->tx_pending),
-		       atomic_read(&adapter->ioctl_pending));
+		       atomic_read(&adapter->cmd_pending));
 	}
 
 	/* Remove interface */
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 43ff149..1b50303 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -42,11 +42,8 @@
 extern struct mwifiex_adapter *g_adapter;
 
 enum {
-	MWIFIEX_NO_WAIT,
-	MWIFIEX_IOCTL_WAIT,
-	MWIFIEX_CMD_WAIT,
-	MWIFIEX_PROC_WAIT,
-	MWIFIEX_WSTATS_WAIT
+	MWIFIEX_ASYNC_CMD,
+	MWIFIEX_SYNC_CMD
 };
 
 #define DRV_MODE_STA       0x1
@@ -468,10 +465,6 @@
 	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];
@@ -480,8 +473,6 @@
 #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;
@@ -552,7 +543,7 @@
 	struct sk_buff *cmd_skb;
 	struct sk_buff *resp_skb;
 	void *data_buf;
-	void *wq_buf;
+	u32 wait_q_enabled;
 	struct sk_buff *skb;
 };
 
@@ -590,7 +581,7 @@
 	struct mwifiex_if_ops if_ops;
 	atomic_t rx_pending;
 	atomic_t tx_pending;
-	atomic_t ioctl_pending;
+	atomic_t cmd_pending;
 	struct workqueue_struct *workqueue;
 	struct work_struct main_work;
 	struct mwifiex_bss_prio_tbl bss_prio_tbl[MWIFIEX_MAX_BSS_NUM];
@@ -684,6 +675,8 @@
 	struct mwifiex_dbg dbg;
 	u8 arp_filter[ARP_FILTER_MAX_BUF_SIZE];
 	u32 arp_filter_size;
+	u16 cmd_wait_q_required;
+	struct mwifiex_wait_queue cmd_wait_q;
 };
 
 int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
@@ -707,29 +700,23 @@
 
 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_complete_cmd(struct mwifiex_adapter *adapter);
 
-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 mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no,
+			   u16 cmd_action, u32 cmd_oid, void *data_buf);
+
+int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no,
+			  u16 cmd_action, u32 cmd_oid, 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_cancel_pending_ioctl(struct mwifiex_adapter *adapter);
 
 void mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter,
 				  struct cmd_ctrl_node *cmd_node);
@@ -772,24 +759,20 @@
 			    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);
+				void *cmd_buf);
 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,
+int mwifiex_scan_networks(struct mwifiex_private *priv,
+			  const struct mwifiex_user_scan_cfg *user_scan_in);
+int mwifiex_cmd_802_11_scan(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);
+			    struct host_cmd_ds_command *resp);
 s32 mwifiex_find_ssid_in_list(struct mwifiex_private *priv,
 				struct mwifiex_802_11_ssid *ssid, u8 *bssid,
 				u32 mode);
@@ -799,23 +782,20 @@
 			      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,
+int mwifiex_associate(struct mwifiex_private *priv,
 		      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);
+				 struct host_cmd_ds_command *resp);
 void mwifiex_reset_connect_state(struct mwifiex_private *priv);
 void mwifiex_2040_coex_event(struct mwifiex_private *priv);
 u8 mwifiex_band_to_radio_type(u8 band);
-int mwifiex_deauthenticate(struct mwifiex_private *priv,
-			   struct mwifiex_wait_queue *wait_queue,
-			   u8 *mac);
-int mwifiex_adhoc_start(struct mwifiex_private *priv, void *wait_queue,
+int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac);
+int mwifiex_adhoc_start(struct mwifiex_private *priv,
 			struct mwifiex_802_11_ssid *adhoc_ssid);
-int mwifiex_adhoc_join(struct mwifiex_private *priv, void *wait_queue,
+int mwifiex_adhoc_join(struct mwifiex_private *priv,
 		       struct mwifiex_bssdescriptor *bss_desc);
 int mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
 				    struct host_cmd_ds_command *cmd,
@@ -824,11 +804,8 @@
 				   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 host_cmd_ds_command *resp);
+int mwifiex_cmd_802_11_bg_scan_query(struct host_cmd_ds_command *cmd);
 struct mwifiex_chan_freq_power *
 			mwifiex_get_cfp_by_band_and_channel_from_cfg80211(
 						struct mwifiex_private *priv,
@@ -836,20 +813,16 @@
 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_index_to_data_rate(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_data_rate_to_index(u32 rate);
 u8 mwifiex_is_rate_auto(struct mwifiex_private *priv);
-int mwifiex_get_rate_index(struct mwifiex_adapter *adapter,
-			   u16 *rateBitmap, int size);
+int mwifiex_get_rate_index(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);
@@ -899,7 +872,7 @@
  */
 static inline struct mwifiex_private *
 mwifiex_get_priv_by_id(struct mwifiex_adapter *adapter,
-		       u32 bss_num, u32 bss_type)
+		       u8 bss_num, u8 bss_type)
 {
 	int i;
 
@@ -943,52 +916,34 @@
 	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_init_shutdown_fw(struct mwifiex_private *priv,
+			     u32 func_init_shutdown);
 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_request_set_multicast_list(struct mwifiex_private *priv,
+			struct mwifiex_multicast_list *mcast_list);
+int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist,
+			    struct net_device *dev);
+int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter);
 int mwifiex_bss_start(struct mwifiex_private *priv,
-		      u8 wait_option,
 		      struct mwifiex_ssid_bssid *ssid_bssid);
 int mwifiex_set_hs_params(struct mwifiex_private *priv,
-			      u16 action, u8 wait_option,
+			      u16 action, int cmd_type,
 			      struct mwifiex_ds_hs_cfg *hscfg);
-int mwifiex_cancel_hs(struct mwifiex_private *priv, u8 wait_option);
+int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type);
 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,
+int mwifiex_find_best_bss(struct mwifiex_private *priv,
 			  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);
@@ -1024,27 +979,22 @@
 
 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_set_power(struct mwifiex_private *priv, u32 *ps_mode);
 
 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_set_tx_power(struct mwifiex_private *priv,
+			 struct mwifiex_power_cfg *power_cfg);
 
 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_set_channel(struct mwifiex_private *,
+			    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_set_radio_band_cfg(struct mwifiex_private *,
+			 struct mwifiex_ds_band_cfg *);
 int mwifiex_get_bss_info(struct mwifiex_private *,
 			 struct mwifiex_bss_info *);
 
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
index 6bb52d0..68d905d 100644
--- a/drivers/net/wireless/mwifiex/scan.c
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -178,35 +178,27 @@
  * 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_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) {
+	if (!mwifiex_bss_ioctl_find_bss(priv, &tmp_ssid_bssid)) {
 		memcpy(ssid_bssid, &tmp_ssid_bssid,
 		       sizeof(struct mwifiex_ssid_bssid));
 		mac = (u8 *) &ssid_bssid->bssid;
 		dev_dbg(priv->adapter->dev, "cmd: found network: ssid=%s,"
 				" %pM\n", ssid_bssid->ssid.ssid, mac);
+		return 0;
 	}
 
-	kfree(wait);
-	return ret;
+	return -1;
 }
 
 /*
@@ -221,22 +213,14 @@
 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;
+	priv->adapter->cmd_wait_q.condition = false;
 
-	status = mwifiex_scan_networks(priv, wait, HostCmd_ACT_GEN_SET,
-				       scan_req, NULL);
+	status = mwifiex_scan_networks(priv, scan_req);
+	if (!status)
+		status = mwifiex_wait_queue_complete(priv->adapter);
 
-	status = mwifiex_request_ioctl(priv, wait, status, wait_option);
-
-	if (wait && (status != -EINPROGRESS))
-		kfree(wait);
 	return status;
 }
 
@@ -674,7 +658,7 @@
  * along with the other TLVs, to the firmware.
  */
 static int
-mwifiex_scan_channel_list(struct mwifiex_private *priv, void *wait_buf,
+mwifiex_scan_channel_list(struct mwifiex_private *priv,
 			  u32 max_chan_per_scan, u8 filtered_scan,
 			  struct mwifiex_scan_cmd_config *scan_cfg_out,
 			  struct mwifiex_ie_types_chan_list_param_set
@@ -808,9 +792,9 @@
 
 		/* 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);
+		ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SCAN,
+					     HostCmd_ACT_GEN_SET, 0,
+					     scan_cfg_out);
 		if (ret)
 			break;
 	}
@@ -2076,19 +2060,13 @@
 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;
+		return BAND_A;
 	case HostCmd_SCAN_RADIO_TYPE_BG:
 	default:
-		ret_band = BAND_G;
-		break;
+		return BAND_G;
 	}
-
-	return ret_band;
 }
 
 /*
@@ -2241,8 +2219,7 @@
 mwifiex_scan_delete_ssid_table_entry(struct mwifiex_private *priv,
 				     struct mwifiex_802_11_ssid *del_ssid)
 {
-	int ret = -1;
-	s32 table_idx;
+	s32 table_idx = -1;
 
 	dev_dbg(priv->adapter->dev, "info: scan: delete ssid entry: %-32s\n",
 			del_ssid->ssid);
@@ -2255,11 +2232,10 @@
 		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;
+	return table_idx == -1 ? -1 : 0;
 }
 
 /*
@@ -2271,9 +2247,7 @@
  * 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)
+			  const struct mwifiex_user_scan_cfg *user_scan_in)
 {
 	int ret = 0;
 	struct mwifiex_adapter *adapter = priv->adapter;
@@ -2288,18 +2262,7 @@
 	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) {
+	if (adapter->scan_processing) {
 		dev_dbg(adapter->dev, "cmd: Scan already in process...\n");
 		return ret;
 	}
@@ -2308,7 +2271,7 @@
 	adapter->scan_processing = true;
 	spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
 
-	if (priv->scan_block && action == HostCmd_ACT_GEN_SET) {
+	if (priv->scan_block) {
 		dev_dbg(adapter->dev,
 			"cmd: Scan is blocked during association...\n");
 		return ret;
@@ -2348,9 +2311,9 @@
 		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);
+	ret = mwifiex_scan_channel_list(priv, 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) {
@@ -2367,7 +2330,6 @@
 			spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
 					       flags);
 		}
-		ret = -EINPROGRESS;
 	} else {
 		spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
 		adapter->scan_processing = true;
@@ -2393,8 +2355,7 @@
  *      - 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)
+int mwifiex_cmd_802_11_scan(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;
@@ -2437,11 +2398,10 @@
  *      .-------------------------------------------------------------.
  */
 int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
-			    struct host_cmd_ds_command *resp, void *wq_buf)
+			    struct host_cmd_ds_command *resp)
 {
 	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;
@@ -2653,13 +2613,9 @@
 		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 (adapter->curr_cmd->wait_q_enabled) {
+			adapter->cmd_wait_q.status = 0;
+			mwifiex_complete_cmd(adapter);
 		}
 		if (priv->report_scan_result)
 			priv->report_scan_result = false;
@@ -2692,9 +2648,7 @@
  *      - 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)
+int mwifiex_cmd_802_11_bg_scan_query(struct host_cmd_ds_command *cmd)
 {
 	struct host_cmd_ds_802_11_bg_scan_query *bg_query =
 		&cmd->params.bg_scan_query;
@@ -2853,6 +2807,7 @@
 	struct mwifiex_adapter *adapter = priv->adapter;
 	unsigned long flags;
 
+	cmd_node->wait_q_enabled = true;
 	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);
@@ -2899,9 +2854,7 @@
  * 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_802_11_ssid *req_ssid)
 {
 	struct mwifiex_adapter *adapter = priv->adapter;
 	int ret = 0;
@@ -2910,24 +2863,12 @@
 	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) {
+	if (adapter->scan_processing) {
 		dev_dbg(adapter->dev, "cmd: Scan already in process...\n");
 		return ret;
 	}
 
-	if (priv->scan_block && action == HostCmd_ACT_GEN_SET) {
+	if (priv->scan_block) {
 		dev_dbg(adapter->dev,
 			"cmd: Scan is blocked during association...\n");
 		return ret;
@@ -2945,7 +2886,7 @@
 	       req_ssid->ssid_len);
 	scan_cfg->keep_previous_scan = true;
 
-	ret = mwifiex_scan_networks(priv, wait_buf, action, scan_cfg, NULL);
+	ret = mwifiex_scan_networks(priv, scan_cfg);
 
 	kfree(scan_cfg);
 	return ret;
@@ -2960,12 +2901,10 @@
  * 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,
+int mwifiex_request_scan(struct mwifiex_private *priv,
 			 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",
@@ -2974,32 +2913,23 @@
 	}
 	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;
-	}
+	priv->adapter->cmd_wait_q.condition = false;
 
 	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);
+		ret = mwifiex_scan_specific_ssid(priv, req_ssid);
 	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);
+		ret = mwifiex_scan_networks(priv, NULL);
+
+	if (!ret)
+		ret = mwifiex_wait_queue_complete(priv->adapter);
+
 	if (ret == -1) {
 		priv->scan_pending_on_block = false;
 		up(&priv->async_sem);
 	}
+
 	return ret;
 }
 
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c
index f21e5cd..5148d0e 100644
--- a/drivers/net/wireless/mwifiex/sdio.c
+++ b/drivers/net/wireless/mwifiex/sdio.c
@@ -208,7 +208,7 @@
 
 	/* Disable Host Sleep */
 	mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA),
-			      MWIFIEX_NO_WAIT);
+			  MWIFIEX_ASYNC_CMD);
 
 	return 0;
 }
@@ -282,7 +282,7 @@
  */
 static int
 mwifiex_write_data_sync(struct mwifiex_adapter *adapter,
-			u8 *buffer, u32 pkt_len, u32 port, u32 timeout)
+			u8 *buffer, u32 pkt_len, u32 port)
 {
 	struct sdio_mmc_card *card = adapter->card;
 	int ret = -1;
@@ -314,9 +314,8 @@
 /*
  * 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)
+static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, u8 *buffer,
+				  u32 len, u32 port, u8 claim)
 {
 	struct sdio_mmc_card *card = adapter->card;
 	int ret = -1;
@@ -348,12 +347,9 @@
  */
 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;
+	return mwifiex_write_reg(adapter, CONFIGURATION_REG, HOST_POWER_UP);
 }
 
 /*
@@ -363,12 +359,9 @@
  */
 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;
+	return mwifiex_write_reg(adapter, CONFIGURATION_REG, 0);
 }
 
 /*
@@ -430,8 +423,7 @@
 	int ret = 0;
 
 	do {
-		ret = mwifiex_write_data_sync(adapter, payload, pkt_len,
-								port, 0);
+		ret = mwifiex_write_data_sync(adapter, payload, pkt_len, port);
 		if (ret) {
 			i++;
 			dev_err(adapter->dev, "host_to_card, write iomem"
@@ -630,7 +622,7 @@
 		return -1;
 	}
 
-	ret = mwifiex_read_data_sync(adapter, buffer, npayload, ioport, 0, 1);
+	ret = mwifiex_read_data_sync(adapter, buffer, npayload, ioport, 1);
 
 	if (ret) {
 		dev_err(adapter->dev, "%s: read iomem failed: %d\n", __func__,
@@ -769,7 +761,7 @@
 
 		ret = mwifiex_write_data_sync(adapter, fwbuf, tx_blocks *
 					      MWIFIEX_SDIO_BLOCK_SIZE,
-					      adapter->ioport, 0);
+					      adapter->ioport);
 		if (ret) {
 			dev_err(adapter->dev, "FW download, write iomem (%d)"
 					" failed @ %d\n", i, offset);
@@ -842,7 +834,7 @@
 	unsigned long flags;
 
 	if (mwifiex_read_data_sync(adapter, card->mp_regs, MAX_MP_REGS,
-				   REG_PORT | MWIFIEX_SDIO_BYTE_MODE_MASK, 0,
+				   REG_PORT | MWIFIEX_SDIO_BYTE_MODE_MASK,
 				   0)) {
 		dev_err(adapter->dev, "read mp_regs failed\n");
 		return;
@@ -859,8 +851,6 @@
 		adapter->int_status |= sdio_ireg;
 		spin_unlock_irqrestore(&adapter->int_lock, flags);
 	}
-
-	return;
 }
 
 /*
@@ -891,8 +881,6 @@
 
 	mwifiex_interrupt_status(adapter);
 	queue_work(adapter->workqueue, &adapter->main_work);
-
-	return;
 }
 
 /*
@@ -1054,7 +1042,7 @@
 					   card->mpa_rx.buf_len,
 					   (adapter->ioport | 0x1000 |
 					    (card->mpa_rx.ports << 4)) +
-					   card->mpa_rx.start_port, 0, 1))
+					   card->mpa_rx.start_port, 1))
 			return -1;
 
 		curr_ptr = card->mpa_rx.buf;
@@ -1709,13 +1697,9 @@
 static int
 mwifiex_sdio_init_module(void)
 {
-	int ret;
-
 	sema_init(&add_remove_card_sem, 1);
 
-	ret = sdio_register_driver(&mwifiex_sdio);
-
-	return ret;
+	return sdio_register_driver(&mwifiex_sdio);
 }
 
 /*
@@ -1745,13 +1729,12 @@
 	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);
+			mwifiex_deauthenticate(adapter->priv[i], NULL);
 
 	if (!adapter->surprise_removed)
-		mwifiex_shutdown_fw(mwifiex_get_priv
-				    (adapter, MWIFIEX_BSS_ROLE_ANY),
-				    MWIFIEX_CMD_WAIT);
+		mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter,
+							  MWIFIEX_BSS_ROLE_ANY),
+					 MWIFIEX_FUNC_SHUTDOWN);
 
 exit:
 	up(&add_remove_card_sem);
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c
index 6fff261..33c8ba1 100644
--- a/drivers/net/wireless/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -190,8 +190,7 @@
  *      - Ensuring correct endian-ness
  */
 static int
-mwifiex_cmd_802_11_get_log(struct mwifiex_private *priv,
-			   struct host_cmd_ds_command *cmd)
+mwifiex_cmd_802_11_get_log(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) +
@@ -272,8 +271,7 @@
  *        (as required)
  *      - Ensuring correct endian-ness
  */
-static int mwifiex_cmd_tx_power_cfg(struct mwifiex_private *priv,
-				    struct host_cmd_ds_command *cmd,
+static int mwifiex_cmd_tx_power_cfg(struct host_cmd_ds_command *cmd,
 				    u16 cmd_action, void *data_buf)
 {
 	struct mwifiex_types_power_group *pg_tlv = NULL;
@@ -407,8 +405,7 @@
  *      - 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,
+static int mwifiex_cmd_mac_multicast_adr(struct host_cmd_ds_command *cmd,
 					 u16 cmd_action, void *data_buf)
 {
 	struct mwifiex_multicast_list *mcast_list =
@@ -463,8 +460,7 @@
  *      - 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)
+static int mwifiex_cmd_802_11_ad_hoc_stop(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);
@@ -500,9 +496,8 @@
 			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);
+				cpu_to_le16(KEY_ENABLED | KEY_UNICAST |
+					    KEY_MCAST);
 			key_param_set->key_len =
 				cpu_to_le16(priv->wep_key[i].key_length);
 			/* Set WEP key index */
@@ -589,10 +584,10 @@
 			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);
+				cpu_to_le16(KEY_ENABLED);
 		else
 			key_material->key_param_set.key_info =
-				cpu_to_le16(!KEY_INFO_WAPI_ENABLED);
+				cpu_to_le16(!KEY_ENABLED);
 
 		key_material->key_param_set.key[0] = enc_key->key_index;
 		if (!priv->sec_info.wapi_key_on)
@@ -604,10 +599,10 @@
 		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);
+				cpu_to_le16(KEY_UNICAST);
 		} else {	/* WAPI group key: multicast */
 			key_material->key_param_set.key_info |=
-				cpu_to_le16(KEY_INFO_WAPI_MCAST);
+				cpu_to_le16(KEY_MCAST);
 			priv->sec_info.wapi_key_on = true;
 		}
 
@@ -634,32 +629,32 @@
 			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);
+				cpu_to_le16(KEY_ENABLED);
 		else
 			key_material->key_param_set.key_info =
-				cpu_to_le16(!KEY_INFO_AES_ENABLED);
+				cpu_to_le16(!KEY_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);
+				cpu_to_le16(KEY_UNICAST);
 		else		/* AES group key: multicast */
 			key_material->key_param_set.key_info |=
-				cpu_to_le16(KEY_INFO_AES_MCAST);
+				cpu_to_le16(KEY_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);
+			cpu_to_le16(KEY_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);
+				cpu_to_le16(KEY_UNICAST);
 		else		/* TKIP group key: multicast */
 			key_material->key_param_set.key_info |=
-				cpu_to_le16(KEY_INFO_TKIP_MCAST);
+				cpu_to_le16(KEY_MCAST);
 	}
 
 	if (key_material->key_param_set.key_type_id) {
@@ -778,8 +773,7 @@
  *      - 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,
+static int mwifiex_cmd_ibss_coalescing_status(struct host_cmd_ds_command *cmd,
 					      u16 cmd_action, void *data_buf)
 {
 	struct host_cmd_ds_802_11_ibss_status *ibss_coal =
@@ -947,7 +941,7 @@
 						     cmd_action);
 		break;
 	case HostCmd_CMD_MAC_MULTICAST_ADR:
-		ret = mwifiex_cmd_mac_multicast_adr(priv, cmd_ptr, cmd_action,
+		ret = mwifiex_cmd_mac_multicast_adr(cmd_ptr, cmd_action,
 						    data_buf);
 		break;
 	case HostCmd_CMD_TX_RATE_CFG:
@@ -955,7 +949,7 @@
 					      data_buf);
 		break;
 	case HostCmd_CMD_TXPWR_CFG:
-		ret = mwifiex_cmd_tx_power_cfg(priv, cmd_ptr, cmd_action,
+		ret = mwifiex_cmd_tx_power_cfg(cmd_ptr, cmd_action,
 					       data_buf);
 		break;
 	case HostCmd_CMD_802_11_PS_MODE_ENH:
@@ -967,11 +961,10 @@
 				(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);
+		ret = mwifiex_cmd_802_11_scan(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);
+		ret = mwifiex_cmd_802_11_bg_scan_query(cmd_ptr);
 		break;
 	case HostCmd_CMD_802_11_ASSOCIATE:
 		ret = mwifiex_cmd_802_11_associate(priv, cmd_ptr, data_buf);
@@ -985,14 +978,14 @@
 						      data_buf);
 		break;
 	case HostCmd_CMD_802_11_GET_LOG:
-		ret = mwifiex_cmd_802_11_get_log(priv, cmd_ptr);
+		ret = mwifiex_cmd_802_11_get_log(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);
+		ret = mwifiex_cmd_802_11_ad_hoc_stop(cmd_ptr);
 		break;
 	case HostCmd_CMD_RSSI_INFO:
 		ret = mwifiex_cmd_802_11_rssi_info(priv, cmd_ptr, cmd_action);
@@ -1037,10 +1030,10 @@
 		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);
+		ret = mwifiex_cmd_11n_addba_req(cmd_ptr, data_buf);
 		break;
 	case HostCmd_CMD_11N_DELBA:
-		ret = mwifiex_cmd_11n_delba(priv, cmd_ptr, data_buf);
+		ret = mwifiex_cmd_11n_delba(cmd_ptr, data_buf);
 		break;
 	case HostCmd_CMD_11N_ADDBA_RSP:
 		ret = mwifiex_cmd_11n_addba_rsp_gen(priv, cmd_ptr, data_buf);
@@ -1059,11 +1052,11 @@
 					       data_buf);
 		break;
 	case HostCmd_CMD_AMSDU_AGGR_CTRL:
-		ret = mwifiex_cmd_amsdu_aggr_ctrl(priv, cmd_ptr, cmd_action,
+		ret = mwifiex_cmd_amsdu_aggr_ctrl(cmd_ptr, cmd_action,
 						  data_buf);
 		break;
 	case HostCmd_CMD_11N_CFG:
-		ret = mwifiex_cmd_11n_cfg(priv, cmd_ptr, cmd_action,
+		ret = mwifiex_cmd_11n_cfg(cmd_ptr, cmd_action,
 					  data_buf);
 		break;
 	case HostCmd_CMD_WMM_GET_STATUS:
@@ -1076,8 +1069,8 @@
 		ret = 0;
 		break;
 	case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:
-		ret = mwifiex_cmd_ibss_coalescing_status(priv, cmd_ptr,
-							 cmd_action, data_buf);
+		ret = mwifiex_cmd_ibss_coalescing_status(cmd_ptr, cmd_action,
+							 data_buf);
 		break;
 	case HostCmd_CMD_MAC_REG_ACCESS:
 	case HostCmd_CMD_BBP_REG_ACCESS:
@@ -1136,65 +1129,66 @@
 
 	if (first_sta) {
 
-		ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_FUNC_INIT,
-					  HostCmd_ACT_GEN_SET, 0, NULL, NULL);
+		ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_FUNC_INIT,
+					     HostCmd_ACT_GEN_SET, 0, 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);
+		ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_GET_HW_SPEC,
+					     HostCmd_ACT_GEN_GET, 0, 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);
+		ret = mwifiex_send_cmd_async(priv,
+					     HostCmd_CMD_RECONFIGURE_TX_BUFF,
+					     HostCmd_ACT_GEN_SET, 0,
+					     &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);
+		ret = mwifiex_send_cmd_async(priv,
+					     HostCmd_CMD_802_11_PS_MODE_ENH,
+					     EN_AUTO_PS, BITMAP_STA_PS, 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);
+	ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_TX_RATE_CFG,
+				     HostCmd_ACT_GEN_GET, 0, 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);
+	ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_TXPWR_CFG,
+				     HostCmd_ACT_GEN_GET, 0, 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);
+	ret = mwifiex_send_cmd_async(priv,
+				     HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
+				     HostCmd_ACT_GEN_SET, 0, &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);
+	ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_AMSDU_AGGR_CTRL,
+				     HostCmd_ACT_GEN_SET, 0,
+				     (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);
+	ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL,
+				     HostCmd_ACT_GEN_SET, 0,
+				     &priv->curr_pkt_filter);
 	if (ret)
 		return -1;
 
@@ -1202,19 +1196,18 @@
 		/* 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);
+		ret = mwifiex_send_cmd_async(priv,
+					     HostCmd_CMD_802_11_PS_MODE_ENH,
+					     EN_AUTO_PS, BITMAP_AUTO_DS,
+					     &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);
+	ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SNMP_MIB,
+				     HostCmd_ACT_GEN_SET, DOT11D_I, &state_11d);
 	if (ret)
 		dev_err(priv->adapter->dev, "11D: failed to enable 11D\n");
 
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c
index 74add45..7f4f10b 100644
--- a/drivers/net/wireless/mwifiex/sta_cmdresp.c
+++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c
@@ -41,8 +41,7 @@
  */
 static void
 mwifiex_process_cmdresp_error(struct mwifiex_private *priv,
-			      struct host_cmd_ds_command *resp,
-			      struct mwifiex_wait_queue *wq_buf)
+			      struct host_cmd_ds_command *resp)
 {
 	struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL;
 	struct mwifiex_adapter *adapter = priv->adapter;
@@ -51,8 +50,9 @@
 
 	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;
+
+	if (adapter->curr_cmd->wait_q_enabled)
+		adapter->cmd_wait_q.status = -1;
 
 	switch (le16_to_cpu(resp->command)) {
 	case HostCmd_CMD_802_11_PS_MODE_ENH:
@@ -103,8 +103,6 @@
 	spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
 	adapter->curr_cmd = NULL;
 	spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
-
-	return;
 }
 
 /*
@@ -282,7 +280,6 @@
 				   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;
@@ -328,9 +325,9 @@
 	if (priv->is_data_rate_auto)
 		priv->data_rate = 0;
 	else
-		ret = mwifiex_prepare_cmd(priv,
+		ret = mwifiex_send_cmd_async(priv,
 					  HostCmd_CMD_802_11_TX_RATE_QUERY,
-					  HostCmd_ACT_GEN_GET, 0, NULL, NULL);
+					  HostCmd_ACT_GEN_GET, 0, NULL);
 
 	if (data_buf) {
 		ds_rate = (struct mwifiex_rate_cfg *) data_buf;
@@ -338,9 +335,7 @@
 			if (priv->is_data_rate_auto) {
 				ds_rate->is_rate_auto = 1;
 			} else {
-				ds_rate->rate =
-					mwifiex_get_rate_index(adapter,
-							       priv->
+				ds_rate->rate = mwifiex_get_rate_index(priv->
 							       bitmap_rates,
 							       sizeof(priv->
 							       bitmap_rates));
@@ -516,13 +511,11 @@
 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,
+			mwifiex_index_to_data_rate(priv->tx_rate,
 						   priv->tx_htinfo);
 
 	return 0;
@@ -574,8 +567,7 @@
 		&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)) {
+		if ((le16_to_cpu(key->key_param_set.key_info) & KEY_MCAST)) {
 			dev_dbg(priv->adapter->dev, "info: key: GTK is set\n");
 			priv->wpa_is_gtk_set = true;
 			priv->scan_block = false;
@@ -834,19 +826,17 @@
  * 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)
+				u16 cmdresp_no, void *cmd_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);
+		mwifiex_process_cmdresp_error(priv, resp);
 		return -1;
 	}
 	/* Command successful, handle response */
@@ -866,12 +856,11 @@
 		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;
+		ret = mwifiex_ret_802_11_scan(priv, resp);
+		adapter->curr_cmd->wait_q_enabled = false;
 		break;
 	case HostCmd_CMD_802_11_BG_SCAN_QUERY:
-		ret = mwifiex_ret_802_11_scan(priv, resp, wait_queue);
+		ret = mwifiex_ret_802_11_scan(priv, resp);
 		dev_dbg(adapter->dev,
 			"info: CMD_RESP: BG_SCAN result is ready!\n");
 		break;
@@ -885,14 +874,14 @@
 		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);
+		ret = mwifiex_ret_802_11_associate(priv, resp);
 		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);
+		ret = mwifiex_ret_802_11_ad_hoc(priv, resp);
 		break;
 	case HostCmd_CMD_802_11_AD_HOC_STOP:
 		ret = mwifiex_ret_802_11_ad_hoc_stop(priv, resp);
@@ -952,7 +941,7 @@
 						mp_end_port));
 		break;
 	case HostCmd_CMD_AMSDU_AGGR_CTRL:
-		ret = mwifiex_ret_amsdu_aggr_ctrl(priv, resp, data_buf);
+		ret = mwifiex_ret_amsdu_aggr_ctrl(resp, data_buf);
 		break;
 	case HostCmd_CMD_WMM_GET_STATUS:
 		ret = mwifiex_ret_wmm_get_status(priv, resp);
@@ -971,7 +960,7 @@
 	case HostCmd_CMD_SET_BSS_MODE:
 		break;
 	case HostCmd_CMD_11N_CFG:
-		ret = mwifiex_ret_11n_cfg(priv, resp, data_buf);
+		ret = mwifiex_ret_11n_cfg(resp, data_buf);
 		break;
 	default:
 		dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n",
diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c
index 936d7c1..fc265ca 100644
--- a/drivers/net/wireless/mwifiex/sta_event.c
+++ b/drivers/net/wireless/mwifiex/sta_event.c
@@ -271,8 +271,9 @@
 
 	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);
+		ret = mwifiex_send_cmd_async(priv,
+					     HostCmd_CMD_802_11_HS_CFG_ENH,
+					     0, 0, NULL);
 		break;
 
 	case EVENT_MIC_ERR_UNICAST:
@@ -303,9 +304,9 @@
 		       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);
+		ret = mwifiex_send_cmd_async(priv,
+					     HostCmd_CMD_802_11_BG_SCAN_QUERY,
+					     HostCmd_ACT_GEN_GET, 0, NULL);
 		break;
 
 	case EVENT_PORT_RELEASE:
@@ -314,8 +315,8 @@
 
 	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);
+		ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_WMM_GET_STATUS,
+					     0, 0, NULL);
 		break;
 
 	case EVENT_RSSI_LOW:
@@ -353,15 +354,15 @@
 		break;
 	case EVENT_IBSS_COALESCED:
 		dev_dbg(adapter->dev, "event: IBSS_COALESCED\n");
-		ret = mwifiex_prepare_cmd(priv,
+		ret = mwifiex_send_cmd_async(priv,
 				HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
-				HostCmd_ACT_GEN_GET, 0, NULL, NULL);
+				HostCmd_ACT_GEN_GET, 0, 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);
+		mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_ADDBA_RSP,
+				       HostCmd_ACT_GEN_SET, 0,
+				       adapter->event_body);
 		break;
 	case EVENT_DELBA:
 		dev_dbg(adapter->dev, "event: DELBA Request\n");
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index b163507..e7adaab 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -33,9 +33,8 @@
  * 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 mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist,
+			    struct net_device *dev)
 {
 	int i = 0;
 	struct netdev_hw_addr *ha;
@@ -47,216 +46,51 @@
 }
 
 /*
- * 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.
+ * This function waits on a cmd wait queue. It also cancels the pending
+ * 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)
+int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter)
 {
 	bool cancel_flag = false;
+	int status = adapter->cmd_wait_q.status;
 
-	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;
-	}
+	dev_dbg(adapter->dev, "cmd pending\n");
+	atomic_inc(&adapter->cmd_pending);
+
+	/* Status pending, wake up main process */
+	queue_work(adapter->workqueue, &adapter->main_work);
+
+	/* Wait for completion */
+	wait_event_interruptible(adapter->cmd_wait_q.wait,
+					adapter->cmd_wait_q.condition);
+	if (!adapter->cmd_wait_q.condition)
+		cancel_flag = true;
+
 	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);
+		mwifiex_cancel_pending_ioctl(adapter);
+		dev_dbg(adapter->dev, "cmd cancel\n");
 	}
+	adapter->cmd_wait_q.status = 0;
 
-	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 mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
+				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");
@@ -281,16 +115,15 @@
 				/* Set multicast addresses to firmware */
 				if (old_pkt_filter == priv->curr_pkt_filter) {
 					/* Send request to firmware */
-					ret = mwifiex_prepare_cmd(priv,
+					ret = mwifiex_send_cmd_async(priv,
 						HostCmd_CMD_MAC_MULTICAST_ADR,
-						action, 0, wait, mcast_list);
-					if (!ret)
-						ret = -EINPROGRESS;
+						HostCmd_ACT_GEN_SET, 0,
+						mcast_list);
 				} else {
 					/* Send request to firmware */
-					ret = mwifiex_prepare_cmd(priv,
+					ret = mwifiex_send_cmd_async(priv,
 						HostCmd_CMD_MAC_MULTICAST_ADR,
-						action, 0, NULL,
+						HostCmd_ACT_GEN_SET, 0,
 						mcast_list);
 				}
 			}
@@ -300,101 +133,21 @@
 		"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;
+		ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL,
+					     HostCmd_ACT_GEN_SET,
+					     0, &priv->curr_pkt_filter);
 	}
 
 	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 mwifiex_bss_start(struct mwifiex_private *priv,
+		      struct mwifiex_ssid_bssid *ssid_bssid)
 {
 	int ret = 0;
 	struct mwifiex_adapter *adapter = priv->adapter;
@@ -406,7 +159,7 @@
 
 	if (priv->bss_mode == NL80211_IFTYPE_STATION) {
 		/* Infra mode */
-		ret = mwifiex_deauthenticate(priv, NULL, NULL);
+		ret = mwifiex_deauthenticate(priv, NULL);
 		if (ret)
 			return ret;
 
@@ -427,7 +180,7 @@
 		/* Clear any past association response stored for
 		 * application retrieval */
 		priv->assoc_rsp_size = 0;
-		ret = mwifiex_associate(priv, wait, &adapter->scan_table[i]);
+		ret = mwifiex_associate(priv, &adapter->scan_table[i]);
 		if (ret)
 			return ret;
 	} else {
@@ -441,7 +194,7 @@
 
 		/* Exit Adhoc mode first */
 		dev_dbg(adapter->dev, "info: Sending Adhoc Stop\n");
-		ret = mwifiex_deauthenticate(priv, NULL, NULL);
+		ret = mwifiex_deauthenticate(priv, NULL);
 		if (ret)
 			return ret;
 
@@ -460,75 +213,39 @@
 		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]);
+			ret = mwifiex_adhoc_join(priv, &adapter->scan_table[i]);
 			if (ret)
 				return ret;
-		} else {	/* i >= 0 */
+		} else {
 			dev_dbg(adapter->dev, "info: Network not found in "
 				"the list, creating adhoc with ssid = %s\n",
 			       ssid_bssid->ssid.ssid);
-			ret = mwifiex_adhoc_start(priv, wait,
-						  &ssid_bssid->ssid);
+			ret = mwifiex_adhoc_start(priv, &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)
+int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action,
+			  int cmd_type, struct mwifiex_ds_hs_cfg *hs_cfg)
+
 {
 	struct mwifiex_adapter *adapter = priv->adapter;
 	int status = 0;
 	u32 prev_cond = 0;
 
+	if (!hs_cfg)
+		return -ENOMEM;
+
 	switch (action) {
 	case HostCmd_ACT_GEN_SET:
 		if (adapter->pps_uapsd_mode) {
@@ -561,12 +278,16 @@
 				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 (cmd_type == MWIFIEX_SYNC_CMD)
+				status = mwifiex_send_cmd_sync(priv,
+						HostCmd_CMD_802_11_HS_CFG_ENH,
+						HostCmd_ACT_GEN_SET, 0,
+						&adapter->hs_cfg);
+			else
+				status = mwifiex_send_cmd_async(priv,
+						HostCmd_CMD_802_11_HS_CFG_ENH,
+						HostCmd_ACT_GEN_SET, 0,
+						&adapter->hs_cfg);
 			if (hs_cfg->conditions == HOST_SLEEP_CFG_CANCEL)
 				/* Restore previous condition */
 				adapter->hs_cfg.conditions =
@@ -592,53 +313,20 @@
 }
 
 /*
- * 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 mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type)
 {
-	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;
+	return mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET,
+				    cmd_type, &hscfg);
 }
 EXPORT_SYMBOL_GPL(mwifiex_cancel_hs);
 
@@ -657,7 +345,6 @@
 		return true;
 	}
 
-	/* Enable Host Sleep */
 	adapter->hs_activate_wait_q_woken = false;
 
 	memset(&hscfg, 0, sizeof(struct mwifiex_hs_config_param));
@@ -665,8 +352,8 @@
 
 	if (mwifiex_set_hs_params(mwifiex_get_priv(adapter,
 						       MWIFIEX_BSS_ROLE_STA),
-				      HostCmd_ACT_GEN_SET,
-				      MWIFIEX_IOCTL_WAIT, &hscfg)) {
+				  HostCmd_ACT_GEN_SET, MWIFIEX_SYNC_CMD,
+				  &hscfg)) {
 		dev_err(adapter->dev, "IOCTL request HS enable failed\n");
 		return false;
 	}
@@ -679,69 +366,6 @@
 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
@@ -757,23 +381,17 @@
 	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 */
@@ -787,20 +405,15 @@
 			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
@@ -813,90 +426,20 @@
 }
 
 /*
- * IOCTL request handler to get extended version information.
+ * The function sets band configurations.
  *
- * 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
+ * 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)
+int mwifiex_set_radio_band_cfg(struct mwifiex_private *priv,
+			       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;
@@ -950,8 +493,8 @@
  * 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)
+int mwifiex_bss_set_channel(struct mwifiex_private *priv,
+			    struct mwifiex_chan_freq_power *chan)
 {
 	struct mwifiex_adapter *adapter = priv->adapter;
 	struct mwifiex_chan_freq_power *cfp = NULL;
@@ -959,16 +502,6 @@
 	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)
@@ -1024,27 +557,19 @@
  * 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;
+			return 0;
 		}
 	} 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;
+	return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_RF_CHANNEL,
+				    action, 0, channel);
 }
 
 /*
@@ -1054,11 +579,9 @@
  * 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];
@@ -1087,10 +610,10 @@
 		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 mwifiex_find_best_network(priv, ssid_bssid);
 	}
 
-	return ret;
+	return 0;
 }
 
 /*
@@ -1114,10 +637,7 @@
 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;
 
@@ -1127,19 +647,10 @@
 	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);
+	ret = mwifiex_bss_ioctl_ibss_channel(priv, 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;
@@ -1154,23 +665,13 @@
 
 	/* Do disonnect */
 	memset(&ssid_bssid, 0, ETH_ALEN);
-	status = mwifiex_bss_ioctl_stop(priv, wait, ssid_bssid.bssid);
+	ret = mwifiex_deauthenticate(priv, 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;
-	}
+	ret = mwifiex_bss_ioctl_ibss_channel(priv, HostCmd_ACT_GEN_SET,
+					     (u16 *) &channel);
 
 	/* Do specific SSID scanning */
-	if (mwifiex_request_scan(priv, wait_option, &bss_info.ssid)) {
+	if (mwifiex_request_scan(priv, &bss_info.ssid)) {
 		ret = -1;
 		goto done;
 	}
@@ -1179,13 +680,8 @@
 	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;
-
+	ret = mwifiex_bss_start(priv, &ssid_bssid);
 done:
-	kfree(wait);
 	return ret;
 }
 
@@ -1198,11 +694,9 @@
  * 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) {
@@ -1241,15 +735,12 @@
 			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 mwifiex_send_cmd_sync(priv,
+					    HostCmd_CMD_802_11_TX_RATE_QUERY,
+					    HostCmd_ACT_GEN_GET, 0, NULL);
 	}
 
-	return ret;
+	return 0;
 }
 
 /*
@@ -1261,7 +752,6 @@
  * 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];
@@ -1299,8 +789,7 @@
 		}
 		memset(bitmap_rates, 0, sizeof(bitmap_rates));
 
-		rate_index =
-			mwifiex_data_rate_to_index(adapter, rate_cfg->rate);
+		rate_index = mwifiex_data_rate_to_index(rate_cfg->rate);
 
 		/* Only allow b/g rates to be set */
 		if (rate_index >= MWIFIEX_RATE_INDEX_HRDSSS0 &&
@@ -1315,11 +804,8 @@
 		}
 	}
 
-	/* 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;
+	ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_TX_RATE_CFG,
+				    HostCmd_ACT_GEN_SET, 0, bitmap_rates);
 
 	return ret;
 }
@@ -1331,7 +817,6 @@
  * 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;
@@ -1340,11 +825,9 @@
 		return -1;
 
 	if (rate_cfg->action == HostCmd_ACT_GEN_GET)
-		status = mwifiex_rate_ioctl_get_rate_value(
-				priv, wait, rate_cfg);
+		status = mwifiex_rate_ioctl_get_rate_value(priv, rate_cfg);
 	else
-		status = mwifiex_rate_ioctl_set_rate_value(
-				priv, wait, rate_cfg);
+		status = mwifiex_rate_ioctl_set_rate_value(priv, rate_cfg);
 
 	return status;
 }
@@ -1359,30 +842,21 @@
 			      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_rate_ioctl_cfg(priv, 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);
+			rate->rate = mwifiex_index_to_data_rate(priv->tx_rate,
+							priv->tx_htinfo);
 		else if (rate)
 			rate->rate = priv->data_rate;
 	} else {
 		ret = -1;
 	}
 
-	kfree(wait);
 	return ret;
 }
 
@@ -1398,9 +872,8 @@
  *      - 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 mwifiex_set_tx_power(struct mwifiex_private *priv,
+			 struct mwifiex_power_cfg *power_cfg)
 {
 	int ret = 0;
 	struct host_cmd_ds_txpwr_cfg *txp_cfg = NULL;
@@ -1472,13 +945,10 @@
 		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);
+	ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_TXPWR_CFG,
+				    HostCmd_ACT_GEN_SET, 0, buf);
 
+	kfree(buf);
 	return ret;
 }
 
@@ -1488,33 +958,23 @@
  * 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 mwifiex_drv_set_power(struct mwifiex_private *priv, u32 *ps_mode)
 {
 	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;
+	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_send_cmd_sync(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
+				    sub_cmd, BITMAP_STA_PS, NULL);
+	if ((!ret) && (sub_cmd == DIS_AUTO_PS))
+		ret = mwifiex_send_cmd_async(priv,
+				HostCmd_CMD_802_11_PS_MODE_ENH, GET_PS,
+				0, NULL);
 
 	return ret;
 }
@@ -1600,20 +1060,13 @@
  * 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,
+static int mwifiex_sec_ioctl_set_wapi_key(struct mwifiex_private *priv,
 			       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;
+	return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
+				    HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED,
+				    encrypt_key);
 }
 
 /*
@@ -1622,12 +1075,10 @@
  * 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,
+static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv,
 			      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;
 
@@ -1641,7 +1092,7 @@
 		/* Copy the required key as the current key */
 		wep_key = &priv->wep_key[index];
 		if (!wep_key->key_length) {
-			dev_err(adapter->dev,
+			dev_err(priv->adapter->dev,
 				"key not set, so cannot enable it\n");
 			return -1;
 		}
@@ -1649,7 +1100,6 @@
 		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,
@@ -1661,8 +1111,9 @@
 	}
 	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);
+		ret = mwifiex_send_cmd_async(priv,
+					     HostCmd_CMD_802_11_KEY_MATERIAL,
+					     HostCmd_ACT_GEN_SET, 0, NULL);
 		if (ret)
 			return ret;
 	}
@@ -1671,12 +1122,9 @@
 	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;
+	ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_MAC_CONTROL,
+				    HostCmd_ACT_GEN_SET, 0,
+				    &priv->curr_pkt_filter);
 
 	return ret;
 }
@@ -1691,18 +1139,16 @@
  *
  * 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,
+static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_private *priv,
 			      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");
+	if (encrypt_key->key_len > WLAN_MAX_KEY_LEN) {
+		dev_err(priv->adapter->dev, "key length too long\n");
 		return -1;
 	}
 
@@ -1713,9 +1159,10 @@
 		 */
 		/* 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);
+		ret = mwifiex_send_cmd_async(priv,
+					HostCmd_CMD_802_11_KEY_MATERIAL,
+					HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED,
+					encrypt_key);
 		if (ret)
 			return ret;
 
@@ -1729,8 +1176,7 @@
 		       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);
+		ibss_key->key_param_set.key_info = cpu_to_le16(KEY_ENABLED);
 
 		/* Send the key as GTK to firmware */
 		encrypt_key->key_index = ~MWIFIEX_KEY_INDEX_UNICAST;
@@ -1740,19 +1186,15 @@
 		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);
+		ret = mwifiex_send_cmd_sync(priv,
+				       HostCmd_CMD_802_11_KEY_MATERIAL,
+				       HostCmd_ACT_GEN_SET, !(KEY_INFO_ENABLED),
+				       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;
+		ret = mwifiex_send_cmd_sync(priv,
+					HostCmd_CMD_802_11_KEY_MATERIAL,
+					HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED,
+					encrypt_key);
 
 	return ret;
 }
@@ -1765,21 +1207,16 @@
  */
 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);
+		status = mwifiex_sec_ioctl_set_wapi_key(priv, encrypt_key);
 	else if (encrypt_key->key_len > WLAN_KEY_LEN_WEP104)
-		status = mwifiex_sec_ioctl_set_wpa_key(adapter, wait,
-						       encrypt_key);
+		status = mwifiex_sec_ioctl_set_wpa_key(priv, encrypt_key);
 	else
-		status = mwifiex_sec_ioctl_set_wep_key(adapter, wait,
-						       encrypt_key);
+		status = mwifiex_sec_ioctl_set_wep_key(priv, encrypt_key);
 	return status;
 }
 
@@ -1807,94 +1244,30 @@
 }
 
 /*
- * 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,
+int mwifiex_get_signal_info(struct mwifiex_private *priv,
 			    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;
-
+	memset(&info, 0, sizeof(struct mwifiex_ds_get_signal));
 	info.selector = ALL_RSSI_INFO_MASK;
 
-	status = mwifiex_get_info_signal(priv, wait, &info);
+	/* 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;
+	}
 
-	status = mwifiex_request_ioctl(priv, wait, status, wait_option);
+	status = mwifiex_send_cmd_sync(priv, HostCmd_CMD_RSSI_INFO,
+				       HostCmd_ACT_GEN_GET, 0, signal);
+
 	if (!status) {
 		if (signal)
 			memcpy(signal, &info,
@@ -1905,8 +1278,6 @@
 			priv->w_stats.qual.noise = info.bcn_nf_avg;
 	}
 
-	if (wait && (status != -EINPROGRESS))
-		kfree(wait);
 	return status;
 }
 
@@ -1919,14 +1290,7 @@
 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;
@@ -1938,41 +1302,7 @@
 		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;
+	return mwifiex_sec_ioctl_encrypt_key(priv, &encrypt_key);
 }
 
 /*
@@ -1985,27 +1315,13 @@
 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);
+	if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_VERSION_EXT,
+				    HostCmd_ACT_GEN_GET, 0, &ver_ext))
+		return -1;
 
-	ret = mwifiex_request_ioctl(priv, wait, status, wait_option);
-
-	if (ret)
-		ret = -1;
-
-	kfree(wait);
-	return ret;
+	return 0;
 }
 
 /*
@@ -2019,21 +1335,12 @@
 		       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);
+	ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_GET_LOG,
+				    HostCmd_ACT_GEN_GET, 0, &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
@@ -2043,7 +1350,6 @@
 		priv->w_stats.discard.misc = get_log.ack_failure;
 	}
 
-	kfree(wait);
 	return ret;
 }
 
@@ -2061,11 +1367,9 @@
  *      - 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)) {
@@ -2088,13 +1392,8 @@
 		return -1;
 	}
 
-	/* Send request to firmware */
-	ret = mwifiex_prepare_cmd(priv, cmd_no, action, 0, wait, reg_rw);
+	return mwifiex_send_cmd_sync(priv, cmd_no, action, 0, reg_rw);
 
-	if (!ret)
-		ret = -EINPROGRESS;
-
-	return ret;
 }
 
 /*
@@ -2107,25 +1406,13 @@
 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;
+	return mwifiex_reg_mem_ioctl_reg_rw(priv, &reg_rw, HostCmd_ACT_GEN_SET);
 }
 
 /*
@@ -2139,50 +1426,18 @@
 		 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_reg_mem_ioctl_reg_rw(priv, &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;
 }
 
@@ -2197,25 +1452,17 @@
 		    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;
+	/* Send request to firmware */
+	ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_EEPROM_ACCESS,
+				    HostCmd_ACT_GEN_GET, 0, &rd_eeprom);
 
-	memcpy(value, rd_eeprom.value, MAX_EEPROM_DATA);
-done:
-	kfree(wait);
+	if (!ret)
+		memcpy(value, rd_eeprom.value, MAX_EEPROM_DATA);
 	return ret;
 }
 
@@ -2344,7 +1591,6 @@
 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;
@@ -2352,8 +1598,7 @@
 	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)
+	if (mwifiex_misc_ioctl_gen_ie(priv, &gen_ie, HostCmd_ACT_GEN_SET))
 		return -EFAULT;
 
 	return 0;
diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c
index e8db6bd..5d37ef1 100644
--- a/drivers/net/wireless/mwifiex/sta_tx.c
+++ b/drivers/net/wireless/mwifiex/sta_tx.c
@@ -51,7 +51,7 @@
 	if (!skb->len) {
 		dev_err(adapter->dev, "Tx: bad packet length: %d\n",
 		       skb->len);
-		tx_info->status_code = MWIFIEX_ERROR_PKT_SIZE_INVALID;
+		tx_info->status_code = -1;
 		return skb->data;
 	}
 
@@ -180,15 +180,11 @@
 {
 	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)
+	if (mwifiex_wmm_lists_empty(adapter))
 			ret = true;
-	}
 
 	if (ret && !adapter->cmd_sent && !adapter->curr_cmd
 	    && !is_command_pending(adapter)) {
diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c
index f06923c..ce772e0 100644
--- a/drivers/net/wireless/mwifiex/txrx.c
+++ b/drivers/net/wireless/mwifiex/txrx.c
@@ -36,7 +36,6 @@
 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;
@@ -50,9 +49,8 @@
 		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;
+	return mwifiex_process_sta_rx_packet(adapter, skb);
 }
 EXPORT_SYMBOL_GPL(mwifiex_handle_rx_packet);
 
diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c
index 205022a..7ab4fb2 100644
--- a/drivers/net/wireless/mwifiex/util.c
+++ b/drivers/net/wireless/mwifiex/util.c
@@ -55,18 +55,12 @@
 }
 
 /*
- * IOCTL request handler to send function init/shutdown command
+ * This function sends 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)
+int mwifiex_init_shutdown_fw(struct mwifiex_private *priv,
+			     u32 func_init_shutdown)
 {
-	struct mwifiex_private *priv = adapter->priv[wait->bss_index];
-	int ret;
 	u16 cmd;
 
 	if (func_init_shutdown == MWIFIEX_FUNC_INIT) {
@@ -74,19 +68,13 @@
 	} else if (func_init_shutdown == MWIFIEX_FUNC_SHUTDOWN) {
 		cmd = HostCmd_CMD_FUNC_SHUTDOWN;
 	} else {
-		dev_err(adapter->dev, "unsupported parameter\n");
+		dev_err(priv->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;
+	return mwifiex_send_cmd_sync(priv, cmd, HostCmd_ACT_GEN_SET, 0, NULL);
 }
+EXPORT_SYMBOL_GPL(mwifiex_init_shutdown_fw);
 
 /*
  * IOCTL request handler to set/get debug information.
@@ -222,31 +210,18 @@
  * 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)
+int mwifiex_complete_cmd(struct mwifiex_adapter *adapter)
 {
-	enum mwifiex_error_code status_code =
-		(enum mwifiex_error_code) wait_queue->status;
+	atomic_dec(&adapter->cmd_pending);
+	dev_dbg(adapter->dev, "cmd completed: status=%d\n",
+					adapter->cmd_wait_q.status);
 
-	atomic_dec(&adapter->ioctl_pending);
+	adapter->cmd_wait_q.condition = true;
 
-	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);
-	}
+	if (adapter->cmd_wait_q.status == -ETIMEDOUT)
+		dev_err(adapter->dev, "cmd timeout\n");
+	else
+		wake_up_interruptible(&adapter->cmd_wait_q.wait);
 
 	return 0;
 }
diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c
index 1cfbc6b..c009370 100644
--- a/drivers/net/wireless/mwifiex/wmm.c
+++ b/drivers/net/wireless/mwifiex/wmm.c
@@ -177,8 +177,7 @@
  * This function map ACs to TIDs.
  */
 static void
-mwifiex_wmm_queue_priorities_tid(struct mwifiex_private *priv,
-				 u8 queue_priority[])
+mwifiex_wmm_queue_priorities_tid(u8 queue_priority[])
 {
 	int i;
 
@@ -247,7 +246,7 @@
 		}
 	}
 
-	mwifiex_wmm_queue_priorities_tid(priv, priv->wmm.queue_priority);
+	mwifiex_wmm_queue_priorities_tid(priv->wmm.queue_priority);
 }
 
 /*
@@ -416,7 +415,7 @@
 		priv = adapter->priv[j];
 		if (priv) {
 			for (i = 0; i < MAX_NUM_TID; i++)
-				if (!mwifiex_wmm_is_ra_list_empty(adapter,
+				if (!mwifiex_wmm_is_ra_list_empty(
 					     &priv->wmm.tid_tbl_ptr[i].ra_list))
 					return false;
 		}
@@ -974,7 +973,6 @@
 	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)) {
@@ -1001,9 +999,7 @@
 	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) {
+	if (mwifiex_process_tx(priv, skb, &tx_param) == -EBUSY) {
 		/* Queue the packet back at the head */
 		spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
 
@@ -1161,7 +1157,7 @@
 	if (!ptr)
 		return -1;
 
-	tid = mwifiex_get_tid(priv->adapter, ptr);
+	tid = mwifiex_get_tid(ptr);
 
 	dev_dbg(adapter->dev, "data: tid=%d\n", tid);
 
@@ -1186,14 +1182,14 @@
 		/* 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)) {
+		if (mwifiex_is_ampdu_allowed(priv, tid)) {
+			if (mwifiex_space_avail_for_new_ba_stream(adapter)) {
 				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)) {
+				   (priv, tid, &tid_del, ra)) {
 				mwifiex_11n_create_tx_ba_stream_tbl(priv,
 						ptr->ra, tid,
 						BA_STREAM_SETUP_INPROGRESS);
@@ -1202,7 +1198,7 @@
 		}
 /* Minimum number of AMSDU */
 #define MIN_NUM_AMSDU 2
-		if (mwifiex_is_amsdu_allowed(priv, ptr, tid) &&
+		if (mwifiex_is_amsdu_allowed(priv, tid) &&
 		    (mwifiex_num_pkts_in_txq(priv, ptr, adapter->tx_buf_size) >=
 		     MIN_NUM_AMSDU))
 			mwifiex_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN,
@@ -1232,6 +1228,4 @@
 		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
index 241f1b0..fcea1f6 100644
--- a/drivers/net/wireless/mwifiex/wmm.h
+++ b/drivers/net/wireless/mwifiex/wmm.h
@@ -35,8 +35,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)
+mwifiex_get_tid(struct mwifiex_ra_list_tbl *ptr)
 {
 	struct sk_buff *skb;
 
@@ -52,7 +51,7 @@
  * This function gets the length of a list.
  */
 static inline int
-mwifiex_wmm_list_len(struct mwifiex_adapter *adapter, struct list_head *head)
+mwifiex_wmm_list_len(struct list_head *head)
 {
 	struct list_head *pos;
 	int count = 0;
@@ -67,8 +66,7 @@
  * 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)
+mwifiex_wmm_is_ra_list_empty(struct list_head *ra_list_hhead)
 {
 	struct mwifiex_ra_list_tbl *ra_list;
 	int is_list_empty;
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 8913180..28ebaec 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -289,10 +289,17 @@
 #define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv))
 #define IEEE80211_KEY_CONF(_u8) ((struct ieee80211_key_conf *)(_u8))
 
+struct tx_traffic_info {
+	u32 start_time;
+	u32 pkts;
+};
+
+#define MWL8K_MAX_TID 8
 struct mwl8k_sta {
 	/* Index into station database. Returned by UPDATE_STADB.  */
 	u8 peer_id;
 	u8 is_ampdu_allowed;
+	struct tx_traffic_info tx_stats[MWL8K_MAX_TID];
 };
 #define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv))
 
@@ -701,7 +708,7 @@
 			       "helper image\n", pci_name(priv->pdev));
 			return rc;
 		}
-		msleep(5);
+		msleep(20);
 
 		rc = mwl8k_feed_fw_image(priv, fw->data, fw->size);
 	} else {
@@ -823,8 +830,8 @@
 	/*
 	 * Make sure the packet header is in the DMA header format (4-address
 	 * without QoS), the necessary crypto padding between the header and the
-	 * payload has already been provided by mac80211, but it doesn't add tail
-	 * padding when HW crypto is enabled.
+	 * payload has already been provided by mac80211, but it doesn't add
+	 * tail padding when HW crypto is enabled.
 	 *
 	 * We have the following trailer padding requirements:
 	 * - WEP: 4 trailer bytes (ICV)
@@ -1487,9 +1494,8 @@
 
 		if (timeout) {
 			WARN_ON(priv->pending_tx_pkts);
-			if (retry) {
+			if (retry)
 				wiphy_notice(hw->wiphy, "tx rings drained\n");
-			}
 			break;
 		}
 
@@ -1649,8 +1655,8 @@
 		/* Rate control is happening in the firmware.
 		 * Ensure no tx rate is being reported.
 		 */
-                info->status.rates[0].idx = -1;
-                info->status.rates[0].count = 1;
+		info->status.rates[0].idx = -1;
+		info->status.rates[0].count = 1;
 
 		if (MWL8K_TXD_SUCCESS(status))
 			info->flags |= IEEE80211_TX_STAT_ACK;
@@ -1688,7 +1694,7 @@
 }
 
 /* caller must hold priv->stream_lock when calling the stream functions */
-struct mwl8k_ampdu_stream *
+static struct mwl8k_ampdu_stream *
 mwl8k_add_stream(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u8 tid)
 {
 	struct mwl8k_ampdu_stream *stream;
@@ -1755,6 +1761,41 @@
 	return NULL;
 }
 
+#define MWL8K_AMPDU_PACKET_THRESHOLD 64
+static inline bool mwl8k_ampdu_allowed(struct ieee80211_sta *sta, u8 tid)
+{
+	struct mwl8k_sta *sta_info = MWL8K_STA(sta);
+	struct tx_traffic_info *tx_stats;
+
+	BUG_ON(tid >= MWL8K_MAX_TID);
+	tx_stats = &sta_info->tx_stats[tid];
+
+	return sta_info->is_ampdu_allowed &&
+		tx_stats->pkts > MWL8K_AMPDU_PACKET_THRESHOLD;
+}
+
+static inline void mwl8k_tx_count_packet(struct ieee80211_sta *sta, u8 tid)
+{
+	struct mwl8k_sta *sta_info = MWL8K_STA(sta);
+	struct tx_traffic_info *tx_stats;
+
+	BUG_ON(tid >= MWL8K_MAX_TID);
+	tx_stats = &sta_info->tx_stats[tid];
+
+	if (tx_stats->start_time == 0)
+		tx_stats->start_time = jiffies;
+
+	/* reset the packet count after each second elapses.  If the number of
+	 * packets ever exceeds the ampdu_min_traffic threshold, we will allow
+	 * an ampdu stream to be started.
+	 */
+	if (jiffies - tx_stats->start_time > HZ) {
+		tx_stats->pkts = 0;
+		tx_stats->start_time = 0;
+	} else
+		tx_stats->pkts++;
+}
+
 static void
 mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
 {
@@ -1841,6 +1882,7 @@
 	    skb->protocol != cpu_to_be16(ETH_P_PAE) &&
 	    sta->ht_cap.ht_supported && priv->ap_fw) {
 		tid = qos & 0xf;
+		mwl8k_tx_count_packet(sta, tid);
 		spin_lock(&priv->stream_lock);
 		stream = mwl8k_lookup_stream(hw, sta->addr, tid);
 		if (stream != NULL) {
@@ -1881,7 +1923,7 @@
 			 * prevents sequence number mismatch at the recepient
 			 * as described above.
 			 */
-			if (MWL8K_STA(sta)->is_ampdu_allowed) {
+			if (mwl8k_ampdu_allowed(sta, tid)) {
 				stream = mwl8k_add_stream(hw, sta, tid);
 				if (stream != NULL)
 					start_ba_session = true;
@@ -2657,7 +2699,7 @@
 	__le16 bw;
 	__le16 sub_ch;
 	__le16 power_level_list[MWL8K_TX_POWER_LEVEL_TOTAL];
-} __attribute__((packed));
+} __packed;
 
 static int mwl8k_cmd_tx_power(struct ieee80211_hw *hw,
 				     struct ieee80211_conf *conf,
@@ -3520,13 +3562,13 @@
 #define BASTREAM_FLAG_DIRECTION_UPSTREAM	0x00
 #define BASTREAM_FLAG_IMMEDIATE_TYPE		0x01
 
-enum {
+enum ba_stream_action_type {
 	MWL8K_BA_CREATE,
 	MWL8K_BA_UPDATE,
 	MWL8K_BA_DESTROY,
 	MWL8K_BA_FLUSH,
 	MWL8K_BA_CHECK,
-} ba_stream_action_type;
+};
 
 
 struct mwl8k_create_ba_stream {
@@ -3780,7 +3822,7 @@
 	__u8 mac_addr[6];
 	__u8 encr_type;
 
-} __attribute__((packed));
+} __packed;
 
 struct mwl8k_cmd_set_key {
 	struct mwl8k_cmd_pkt header;
@@ -3800,7 +3842,7 @@
 	__le16 tkip_tsc_low;
 	__le32 tkip_tsc_high;
 	__u8 mac_addr[6];
-} __attribute__((packed));
+} __packed;
 
 enum {
 	MWL8K_ENCR_ENABLE,
@@ -4285,6 +4327,8 @@
 
 	/* Enable interrupts */
 	iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
+	iowrite32(MWL8K_A2H_EVENTS,
+		  priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK);
 
 	rc = mwl8k_fw_lock(hw);
 	if (!rc) {
@@ -4502,7 +4546,7 @@
 			   struct ieee80211_bss_conf *info, u32 changed)
 {
 	struct mwl8k_priv *priv = hw->priv;
-	u32 ap_legacy_rates;
+	u32 ap_legacy_rates = 0;
 	u8 ap_mcs_rates[16];
 	int rc;
 
@@ -5283,7 +5327,8 @@
 	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);
+	iowrite32(MWL8K_A2H_INT_OPC_DONE,
+		  priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK);
 
 	rc = request_irq(priv->pdev->irq, mwl8k_interrupt,
 			 IRQF_SHARED, MWL8K_NAME, hw);
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig
index f630552..c457731 100644
--- a/drivers/net/wireless/rt2x00/Kconfig
+++ b/drivers/net/wireless/rt2x00/Kconfig
@@ -59,7 +59,6 @@
 	select RT2800_LIB
 	select RT2X00_LIB_PCI if PCI
 	select RT2X00_LIB_SOC if RALINK_RT288X || RALINK_RT305X
-	select RT2X00_LIB_HT
 	select RT2X00_LIB_FIRMWARE
 	select RT2X00_LIB_CRYPTO
 	select CRC_CCITT
@@ -74,17 +73,13 @@
 if RT2800PCI
 
 config RT2800PCI_RT33XX
-	bool "rt2800pci - Include support for rt33xx devices (EXPERIMENTAL)"
-	depends on EXPERIMENTAL
-	default n
+	bool "rt2800pci - Include support for rt33xx devices"
+	default y
 	---help---
 	  This adds support for rt33xx wireless chipset family to the
 	  rt2800pci driver.
 	  Supported chips: RT3390
 
-	  Support for these devices is non-functional at the moment and is
-	  intended for testers and developers.
-
 config RT2800PCI_RT35XX
 	bool "rt2800pci - Include support for rt35xx devices (EXPERIMENTAL)"
 	depends on EXPERIMENTAL
@@ -100,15 +95,12 @@
 config RT2800PCI_RT53XX
        bool "rt2800-pci - Include support for rt53xx devices (EXPERIMENTAL)"
        depends on EXPERIMENTAL
-       default n
+       default y
        ---help---
          This adds support for rt53xx wireless chipset family to the
          rt2800pci driver.
          Supported chips: RT5390
 
-         Support for these devices is non-functional at the moment and is
-         intended for testers and developers.
-
 endif
 
 config RT2500USB
@@ -140,7 +132,6 @@
 	depends on USB
 	select RT2800_LIB
 	select RT2X00_LIB_USB
-	select RT2X00_LIB_HT
 	select RT2X00_LIB_FIRMWARE
 	select RT2X00_LIB_CRYPTO
 	select CRC_CCITT
@@ -153,17 +144,13 @@
 if RT2800USB
 
 config RT2800USB_RT33XX
-	bool "rt2800usb - Include support for rt33xx devices (EXPERIMENTAL)"
-	depends on EXPERIMENTAL
-	default n
+	bool "rt2800usb - Include support for rt33xx devices"
+	default y
 	---help---
 	  This adds support for rt33xx wireless chipset family to the
 	  rt2800usb driver.
 	  Supported chips: RT3370
 
-	  Support for these devices is non-functional at the moment and is
-	  intended for testers and developers.
-
 config RT2800USB_RT35XX
 	bool "rt2800usb - Include support for rt35xx devices (EXPERIMENTAL)"
 	depends on EXPERIMENTAL
@@ -207,9 +194,6 @@
 config RT2X00_LIB
 	tristate
 
-config RT2X00_LIB_HT
-	boolean
-
 config RT2X00_LIB_FIRMWARE
 	boolean
 	select FW_LOADER
diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile
index 9713398..349d5b8 100644
--- a/drivers/net/wireless/rt2x00/Makefile
+++ b/drivers/net/wireless/rt2x00/Makefile
@@ -7,7 +7,6 @@
 rt2x00lib-$(CONFIG_RT2X00_LIB_CRYPTO)	+= rt2x00crypto.o
 rt2x00lib-$(CONFIG_RT2X00_LIB_FIRMWARE)	+= rt2x00firmware.o
 rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS)	+= rt2x00leds.o
-rt2x00lib-$(CONFIG_RT2X00_LIB_HT)	+= rt2x00ht.o
 
 obj-$(CONFIG_RT2X00_LIB)		+= rt2x00lib.o
 obj-$(CONFIG_RT2X00_LIB_PCI)		+= rt2x00pci.o
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 137a24e..937f9e8 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -1314,8 +1314,8 @@
 	}
 }
 
-static void rt2400pci_enable_interrupt(struct rt2x00_dev *rt2x00dev,
-				       struct rt2x00_field32 irq_field)
+static inline void rt2400pci_enable_interrupt(struct rt2x00_dev *rt2x00dev,
+					      struct rt2x00_field32 irq_field)
 {
 	u32 reg;
 
@@ -1536,13 +1536,13 @@
 	 * Detect if this device has an hardware controlled radio.
 	 */
 	if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
-		__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
+		__set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags);
 
 	/*
 	 * Check if the BBP tuning should be enabled.
 	 */
 	if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_AGCVGC_TUNING))
-		__set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
+		__set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags);
 
 	return 0;
 }
@@ -1640,9 +1640,9 @@
 	/*
 	 * This device requires the atim queue and DMA-mapped skbs.
 	 */
-	__set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
-	__set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
-	__set_bit(DRIVER_REQUIRE_SW_SEQNO, &rt2x00dev->flags);
+	__set_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags);
+	__set_bit(REQUIRE_DMA, &rt2x00dev->cap_flags);
+	__set_bit(REQUIRE_SW_SEQNO, &rt2x00dev->cap_flags);
 
 	/*
 	 * Set the rssi offset.
@@ -1720,6 +1720,9 @@
 	.tx_last_beacon		= rt2400pci_tx_last_beacon,
 	.rfkill_poll		= rt2x00mac_rfkill_poll,
 	.flush			= rt2x00mac_flush,
+	.set_antenna		= rt2x00mac_set_antenna,
+	.get_antenna		= rt2x00mac_get_antenna,
+	.get_ringparam		= rt2x00mac_get_ringparam,
 };
 
 static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
@@ -1740,6 +1743,7 @@
 	.start_queue		= rt2400pci_start_queue,
 	.kick_queue		= rt2400pci_kick_queue,
 	.stop_queue		= rt2400pci_stop_queue,
+	.flush_queue		= rt2x00pci_flush_queue,
 	.write_tx_desc		= rt2400pci_write_tx_desc,
 	.write_beacon		= rt2400pci_write_beacon,
 	.fill_rxdone		= rt2400pci_fill_rxdone,
@@ -1801,10 +1805,11 @@
  * RT2400pci module information.
  */
 static DEFINE_PCI_DEVICE_TABLE(rt2400pci_device_table) = {
-	{ PCI_DEVICE(0x1814, 0x0101), PCI_DEVICE_DATA(&rt2400pci_ops) },
+	{ PCI_DEVICE(0x1814, 0x0101) },
 	{ 0, }
 };
 
+
 MODULE_AUTHOR(DRV_PROJECT);
 MODULE_VERSION(DRV_VERSION);
 MODULE_DESCRIPTION("Ralink RT2400 PCI & PCMCIA Wireless LAN driver.");
@@ -1812,10 +1817,16 @@
 MODULE_DEVICE_TABLE(pci, rt2400pci_device_table);
 MODULE_LICENSE("GPL");
 
+static int rt2400pci_probe(struct pci_dev *pci_dev,
+			   const struct pci_device_id *id)
+{
+	return rt2x00pci_probe(pci_dev, &rt2400pci_ops);
+}
+
 static struct pci_driver rt2400pci_driver = {
 	.name		= KBUILD_MODNAME,
 	.id_table	= rt2400pci_device_table,
-	.probe		= rt2x00pci_probe,
+	.probe		= rt2400pci_probe,
 	.remove		= __devexit_p(rt2x00pci_remove),
 	.suspend	= rt2x00pci_suspend,
 	.resume		= rt2x00pci_resume,
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 198fc0a..d27d7b8 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -1446,8 +1446,8 @@
 	}
 }
 
-static void rt2500pci_enable_interrupt(struct rt2x00_dev *rt2x00dev,
-				       struct rt2x00_field32 irq_field)
+static inline void rt2500pci_enable_interrupt(struct rt2x00_dev *rt2x00dev,
+					      struct rt2x00_field32 irq_field)
 {
 	u32 reg;
 
@@ -1687,14 +1687,14 @@
 	 * Detect if this device has an hardware controlled radio.
 	 */
 	if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
-		__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
+		__set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags);
 
 	/*
 	 * Check if the BBP tuning should be enabled.
 	 */
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
 	if (!rt2x00_get_field16(eeprom, EEPROM_NIC_DYN_BBP_TUNE))
-		__set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
+		__set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags);
 
 	/*
 	 * Read the RSSI <-> dBm offset information.
@@ -1958,9 +1958,9 @@
 	/*
 	 * This device requires the atim queue and DMA-mapped skbs.
 	 */
-	__set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
-	__set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
-	__set_bit(DRIVER_REQUIRE_SW_SEQNO, &rt2x00dev->flags);
+	__set_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags);
+	__set_bit(REQUIRE_DMA, &rt2x00dev->cap_flags);
+	__set_bit(REQUIRE_SW_SEQNO, &rt2x00dev->cap_flags);
 
 	/*
 	 * Set the rssi offset.
@@ -2013,6 +2013,9 @@
 	.tx_last_beacon		= rt2500pci_tx_last_beacon,
 	.rfkill_poll		= rt2x00mac_rfkill_poll,
 	.flush			= rt2x00mac_flush,
+	.set_antenna		= rt2x00mac_set_antenna,
+	.get_antenna		= rt2x00mac_get_antenna,
+	.get_ringparam		= rt2x00mac_get_ringparam,
 };
 
 static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
@@ -2033,6 +2036,7 @@
 	.start_queue		= rt2500pci_start_queue,
 	.kick_queue		= rt2500pci_kick_queue,
 	.stop_queue		= rt2500pci_stop_queue,
+	.flush_queue		= rt2x00pci_flush_queue,
 	.write_tx_desc		= rt2500pci_write_tx_desc,
 	.write_beacon		= rt2500pci_write_beacon,
 	.fill_rxdone		= rt2500pci_fill_rxdone,
@@ -2094,7 +2098,7 @@
  * RT2500pci module information.
  */
 static DEFINE_PCI_DEVICE_TABLE(rt2500pci_device_table) = {
-	{ PCI_DEVICE(0x1814, 0x0201), PCI_DEVICE_DATA(&rt2500pci_ops) },
+	{ PCI_DEVICE(0x1814, 0x0201) },
 	{ 0, }
 };
 
@@ -2105,10 +2109,16 @@
 MODULE_DEVICE_TABLE(pci, rt2500pci_device_table);
 MODULE_LICENSE("GPL");
 
+static int rt2500pci_probe(struct pci_dev *pci_dev,
+			   const struct pci_device_id *id)
+{
+	return rt2x00pci_probe(pci_dev, &rt2500pci_ops);
+}
+
 static struct pci_driver rt2500pci_driver = {
 	.name		= KBUILD_MODNAME,
 	.id_table	= rt2500pci_device_table,
-	.probe		= rt2x00pci_probe,
+	.probe		= rt2500pci_probe,
 	.remove		= __devexit_p(rt2x00pci_remove),
 	.suspend	= rt2x00pci_suspend,
 	.resume		= rt2x00pci_resume,
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index eac7881..b21f812 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -1519,7 +1519,7 @@
 	 * Detect if this device has an hardware controlled radio.
 	 */
 	if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
-		__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
+		__set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags);
 
 	/*
 	 * Read the RSSI <-> dBm offset information.
@@ -1790,13 +1790,13 @@
 	/*
 	 * This device requires the atim queue
 	 */
-	__set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
-	__set_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags);
+	__set_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags);
+	__set_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags);
 	if (!modparam_nohwcrypt) {
-		__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
-		__set_bit(DRIVER_REQUIRE_COPY_IV, &rt2x00dev->flags);
+		__set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags);
+		__set_bit(REQUIRE_COPY_IV, &rt2x00dev->cap_flags);
 	}
-	__set_bit(DRIVER_REQUIRE_SW_SEQNO, &rt2x00dev->flags);
+	__set_bit(REQUIRE_SW_SEQNO, &rt2x00dev->cap_flags);
 
 	/*
 	 * Set the rssi offset.
@@ -1823,6 +1823,9 @@
 	.conf_tx		= rt2x00mac_conf_tx,
 	.rfkill_poll		= rt2x00mac_rfkill_poll,
 	.flush			= rt2x00mac_flush,
+	.set_antenna		= rt2x00mac_set_antenna,
+	.get_antenna		= rt2x00mac_get_antenna,
+	.get_ringparam		= rt2x00mac_get_ringparam,
 };
 
 static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
@@ -1904,54 +1907,54 @@
  */
 static struct usb_device_id rt2500usb_device_table[] = {
 	/* ASUS */
-	{ USB_DEVICE(0x0b05, 0x1706), USB_DEVICE_DATA(&rt2500usb_ops) },
-	{ USB_DEVICE(0x0b05, 0x1707), USB_DEVICE_DATA(&rt2500usb_ops) },
+	{ USB_DEVICE(0x0b05, 0x1706) },
+	{ USB_DEVICE(0x0b05, 0x1707) },
 	/* Belkin */
-	{ USB_DEVICE(0x050d, 0x7050), USB_DEVICE_DATA(&rt2500usb_ops) },
-	{ USB_DEVICE(0x050d, 0x7051), USB_DEVICE_DATA(&rt2500usb_ops) },
+	{ USB_DEVICE(0x050d, 0x7050) },
+	{ USB_DEVICE(0x050d, 0x7051) },
 	/* 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) },
+	{ USB_DEVICE(0x13b1, 0x000d) },
+	{ USB_DEVICE(0x13b1, 0x0011) },
+	{ USB_DEVICE(0x13b1, 0x001a) },
 	/* Conceptronic */
-	{ USB_DEVICE(0x14b2, 0x3c02), USB_DEVICE_DATA(&rt2500usb_ops) },
+	{ USB_DEVICE(0x14b2, 0x3c02) },
 	/* D-LINK */
-	{ USB_DEVICE(0x2001, 0x3c00), USB_DEVICE_DATA(&rt2500usb_ops) },
+	{ USB_DEVICE(0x2001, 0x3c00) },
 	/* Gigabyte */
-	{ USB_DEVICE(0x1044, 0x8001), USB_DEVICE_DATA(&rt2500usb_ops) },
-	{ USB_DEVICE(0x1044, 0x8007), USB_DEVICE_DATA(&rt2500usb_ops) },
+	{ USB_DEVICE(0x1044, 0x8001) },
+	{ USB_DEVICE(0x1044, 0x8007) },
 	/* Hercules */
-	{ USB_DEVICE(0x06f8, 0xe000), USB_DEVICE_DATA(&rt2500usb_ops) },
+	{ USB_DEVICE(0x06f8, 0xe000) },
 	/* Melco */
-	{ USB_DEVICE(0x0411, 0x005e), USB_DEVICE_DATA(&rt2500usb_ops) },
-	{ USB_DEVICE(0x0411, 0x0066), USB_DEVICE_DATA(&rt2500usb_ops) },
-	{ USB_DEVICE(0x0411, 0x0067), USB_DEVICE_DATA(&rt2500usb_ops) },
-	{ USB_DEVICE(0x0411, 0x008b), USB_DEVICE_DATA(&rt2500usb_ops) },
-	{ USB_DEVICE(0x0411, 0x0097), USB_DEVICE_DATA(&rt2500usb_ops) },
+	{ USB_DEVICE(0x0411, 0x005e) },
+	{ USB_DEVICE(0x0411, 0x0066) },
+	{ USB_DEVICE(0x0411, 0x0067) },
+	{ USB_DEVICE(0x0411, 0x008b) },
+	{ USB_DEVICE(0x0411, 0x0097) },
 	/* MSI */
-	{ USB_DEVICE(0x0db0, 0x6861), USB_DEVICE_DATA(&rt2500usb_ops) },
-	{ USB_DEVICE(0x0db0, 0x6865), USB_DEVICE_DATA(&rt2500usb_ops) },
-	{ USB_DEVICE(0x0db0, 0x6869), USB_DEVICE_DATA(&rt2500usb_ops) },
+	{ USB_DEVICE(0x0db0, 0x6861) },
+	{ USB_DEVICE(0x0db0, 0x6865) },
+	{ USB_DEVICE(0x0db0, 0x6869) },
 	/* Ralink */
-	{ USB_DEVICE(0x148f, 0x1706), USB_DEVICE_DATA(&rt2500usb_ops) },
-	{ USB_DEVICE(0x148f, 0x2570), USB_DEVICE_DATA(&rt2500usb_ops) },
-	{ USB_DEVICE(0x148f, 0x9020), USB_DEVICE_DATA(&rt2500usb_ops) },
+	{ USB_DEVICE(0x148f, 0x1706) },
+	{ USB_DEVICE(0x148f, 0x2570) },
+	{ USB_DEVICE(0x148f, 0x9020) },
 	/* Sagem */
-	{ USB_DEVICE(0x079b, 0x004b), USB_DEVICE_DATA(&rt2500usb_ops) },
+	{ USB_DEVICE(0x079b, 0x004b) },
 	/* Siemens */
-	{ USB_DEVICE(0x0681, 0x3c06), USB_DEVICE_DATA(&rt2500usb_ops) },
+	{ USB_DEVICE(0x0681, 0x3c06) },
 	/* SMC */
-	{ USB_DEVICE(0x0707, 0xee13), USB_DEVICE_DATA(&rt2500usb_ops) },
+	{ USB_DEVICE(0x0707, 0xee13) },
 	/* Spairon */
-	{ USB_DEVICE(0x114b, 0x0110), USB_DEVICE_DATA(&rt2500usb_ops) },
+	{ USB_DEVICE(0x114b, 0x0110) },
 	/* SURECOM */
-	{ USB_DEVICE(0x0769, 0x11f3), USB_DEVICE_DATA(&rt2500usb_ops) },
+	{ USB_DEVICE(0x0769, 0x11f3) },
 	/* Trust */
-	{ USB_DEVICE(0x0eb0, 0x9020), USB_DEVICE_DATA(&rt2500usb_ops) },
+	{ USB_DEVICE(0x0eb0, 0x9020) },
 	/* VTech */
-	{ USB_DEVICE(0x0f88, 0x3012), USB_DEVICE_DATA(&rt2500usb_ops) },
+	{ USB_DEVICE(0x0f88, 0x3012) },
 	/* Zinwell */
-	{ USB_DEVICE(0x5a57, 0x0260), USB_DEVICE_DATA(&rt2500usb_ops) },
+	{ USB_DEVICE(0x5a57, 0x0260) },
 	{ 0, }
 };
 
@@ -1962,10 +1965,16 @@
 MODULE_DEVICE_TABLE(usb, rt2500usb_device_table);
 MODULE_LICENSE("GPL");
 
+static int rt2500usb_probe(struct usb_interface *usb_intf,
+			   const struct usb_device_id *id)
+{
+	return rt2x00usb_probe(usb_intf, &rt2500usb_ops);
+}
+
 static struct usb_driver rt2500usb_driver = {
 	.name		= KBUILD_MODNAME,
 	.id_table	= rt2500usb_device_table,
-	.probe		= rt2x00usb_probe,
+	.probe		= rt2500usb_probe,
 	.disconnect	= rt2x00usb_disconnect,
 	.suspend	= rt2x00usb_suspend,
 	.resume		= rt2x00usb_resume,
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 6331c61..5cd096e 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -730,34 +730,20 @@
 	struct data_queue *queue;
 	struct queue_entry *entry;
 	u32 reg;
-	u8 pid;
-	int i;
+	u8 qid;
 
-	/*
-	 * TX_STA_FIFO is a stack of X entries, hence read TX_STA_FIFO
-	 * at most X times and also stop processing once the TX_STA_FIFO_VALID
-	 * flag is not set anymore.
-	 *
-	 * The legacy drivers use X=TX_RING_SIZE but state in a comment
-	 * that the TX_STA_FIFO stack has a size of 16. We stick to our
-	 * tx ring size for now.
-	 */
-	for (i = 0; i < rt2x00dev->ops->tx->entry_num; i++) {
-		rt2800_register_read(rt2x00dev, TX_STA_FIFO, &reg);
-		if (!rt2x00_get_field32(reg, TX_STA_FIFO_VALID))
-			break;
+	while (kfifo_get(&rt2x00dev->txstatus_fifo, &reg)) {
 
-		/*
-		 * Skip this entry when it contains an invalid
-		 * queue identication number.
+		/* TX_STA_FIFO_PID_QUEUE is a 2-bit field, thus
+		 * qid is guaranteed to be one of the TX QIDs
 		 */
-		pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE);
-		if (pid >= QID_RX)
+		qid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE);
+		queue = rt2x00queue_get_tx_queue(rt2x00dev, qid);
+		if (unlikely(!queue)) {
+			WARNING(rt2x00dev, "Got TX status for an unavailable "
+					   "queue %u, dropping\n", qid);
 			continue;
-
-		queue = rt2x00queue_get_tx_queue(rt2x00dev, pid);
-		if (unlikely(!queue))
-			continue;
+		}
 
 		/*
 		 * Inside each queue, we process each entry in a chronological
@@ -949,25 +935,49 @@
 	unsigned int ledmode =
 		rt2x00_get_field16(led->rt2x00dev->led_mcu_reg,
 				   EEPROM_FREQ_LED_MODE);
+	u32 reg;
 
-	if (led->type == LED_TYPE_RADIO) {
-		rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode,
-				      enabled ? 0x20 : 0);
-	} else if (led->type == LED_TYPE_ASSOC) {
-		rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode,
-				      enabled ? (bg_mode ? 0x60 : 0xa0) : 0x20);
-	} else if (led->type == LED_TYPE_QUALITY) {
-		/*
-		 * The brightness is divided into 6 levels (0 - 5),
-		 * The specs tell us the following levels:
-		 *	0, 1 ,3, 7, 15, 31
-		 * to determine the level in a simple way we can simply
-		 * work with bitshifting:
-		 *	(1 << level) - 1
-		 */
-		rt2800_mcu_request(led->rt2x00dev, MCU_LED_STRENGTH, 0xff,
-				      (1 << brightness / (LED_FULL / 6)) - 1,
-				      polarity);
+	/* Check for SoC (SOC devices don't support MCU requests) */
+	if (rt2x00_is_soc(led->rt2x00dev)) {
+		rt2800_register_read(led->rt2x00dev, LED_CFG, &reg);
+
+		/* Set LED Polarity */
+		rt2x00_set_field32(&reg, LED_CFG_LED_POLAR, polarity);
+
+		/* Set LED Mode */
+		if (led->type == LED_TYPE_RADIO) {
+			rt2x00_set_field32(&reg, LED_CFG_G_LED_MODE,
+					   enabled ? 3 : 0);
+		} else if (led->type == LED_TYPE_ASSOC) {
+			rt2x00_set_field32(&reg, LED_CFG_Y_LED_MODE,
+					   enabled ? 3 : 0);
+		} else if (led->type == LED_TYPE_QUALITY) {
+			rt2x00_set_field32(&reg, LED_CFG_R_LED_MODE,
+					   enabled ? 3 : 0);
+		}
+
+		rt2800_register_write(led->rt2x00dev, LED_CFG, reg);
+
+	} else {
+		if (led->type == LED_TYPE_RADIO) {
+			rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode,
+					      enabled ? 0x20 : 0);
+		} else if (led->type == LED_TYPE_ASSOC) {
+			rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode,
+					      enabled ? (bg_mode ? 0x60 : 0xa0) : 0x20);
+		} else if (led->type == LED_TYPE_QUALITY) {
+			/*
+			 * The brightness is divided into 6 levels (0 - 5),
+			 * The specs tell us the following levels:
+			 *	0, 1 ,3, 7, 15, 31
+			 * to determine the level in a simple way we can simply
+			 * work with bitshifting:
+			 *	(1 << level) - 1
+			 */
+			rt2800_mcu_request(led->rt2x00dev, MCU_LED_STRENGTH, 0xff,
+					      (1 << brightness / (LED_FULL / 6)) - 1,
+					      polarity);
+		}
 	}
 }
 
@@ -1221,6 +1231,25 @@
 		rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
 		rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_SYNC, conf->sync);
 		rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+
+		if (conf->sync == TSF_SYNC_AP_NONE) {
+			/*
+			 * Tune beacon queue transmit parameters for AP mode
+			 */
+			rt2800_register_read(rt2x00dev, TBTT_SYNC_CFG, &reg);
+			rt2x00_set_field32(&reg, TBTT_SYNC_CFG_BCN_CWMIN, 0);
+			rt2x00_set_field32(&reg, TBTT_SYNC_CFG_BCN_AIFSN, 1);
+			rt2x00_set_field32(&reg, TBTT_SYNC_CFG_BCN_EXP_WIN, 32);
+			rt2x00_set_field32(&reg, TBTT_SYNC_CFG_TBTT_ADJUST, 0);
+			rt2800_register_write(rt2x00dev, TBTT_SYNC_CFG, reg);
+		} else {
+			rt2800_register_read(rt2x00dev, TBTT_SYNC_CFG, &reg);
+			rt2x00_set_field32(&reg, TBTT_SYNC_CFG_BCN_CWMIN, 4);
+			rt2x00_set_field32(&reg, TBTT_SYNC_CFG_BCN_AIFSN, 2);
+			rt2x00_set_field32(&reg, TBTT_SYNC_CFG_BCN_EXP_WIN, 32);
+			rt2x00_set_field32(&reg, TBTT_SYNC_CFG_TBTT_ADJUST, 16);
+			rt2800_register_write(rt2x00dev, TBTT_SYNC_CFG, reg);
+		}
 	}
 
 	if (flags & CONFIG_UPDATE_MAC) {
@@ -1739,8 +1768,8 @@
 
 	if (rf->channel <= 14) {
 		if (!rt2x00_rt(rt2x00dev, RT5390)) {
-			if (test_bit(CONFIG_EXTERNAL_LNA_BG,
-				     &rt2x00dev->flags)) {
+			if (test_bit(CAPABILITY_EXTERNAL_LNA_BG,
+				     &rt2x00dev->cap_flags)) {
 				rt2800_bbp_write(rt2x00dev, 82, 0x62);
 				rt2800_bbp_write(rt2x00dev, 75, 0x46);
 			} else {
@@ -1751,7 +1780,7 @@
 	} else {
 		rt2800_bbp_write(rt2x00dev, 82, 0xf2);
 
-		if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags))
+		if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags))
 			rt2800_bbp_write(rt2x00dev, 75, 0x46);
 		else
 			rt2800_bbp_write(rt2x00dev, 75, 0x50);
@@ -1984,7 +2013,7 @@
 	if (!((band == IEEE80211_BAND_5GHZ) && is_rate_b))
 		return txpower;
 
-	if (test_bit(CONFIG_SUPPORT_POWER_LIMIT, &rt2x00dev->flags)) {
+	if (test_bit(CAPABILITY_POWER_LIMIT, &rt2x00dev->cap_flags)) {
 		/*
 		 * Check if eirp txpower exceed txpower_limit.
 		 * We use OFDM 6M as criterion and its eirp txpower
@@ -2384,7 +2413,7 @@
 	} else if (rt2800_is_305x_soc(rt2x00dev)) {
 		rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
 		rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000);
-		rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x0000001f);
+		rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000030);
 	} else if (rt2x00_rt(rt2x00dev, RT5390)) {
 		rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000404);
 		rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
@@ -3285,8 +3314,8 @@
 		    rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
 		    rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) ||
 		    rt2x00_rt_rev_lt(rt2x00dev, RT3390, REV_RT3390E)) {
-			if (!test_bit(CONFIG_EXTERNAL_LNA_BG,
-				      &rt2x00dev->flags))
+			if (!test_bit(CAPABILITY_EXTERNAL_LNA_BG,
+				      &rt2x00dev->cap_flags))
 				rt2x00_set_field8(&rfcsr, RFCSR17_R, 1);
 		}
 		rt2x00_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_BG, &eeprom);
@@ -3709,15 +3738,15 @@
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
 
 	if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_LNA_5G))
-		__set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
+		__set_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags);
 	if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_LNA_2G))
-		__set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
+		__set_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags);
 
 	/*
 	 * Detect if this device has an hardware controlled radio.
 	 */
 	if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_HW_RADIO))
-		__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
+		__set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags);
 
 	/*
 	 * Store led settings, for correct led behaviour.
@@ -3737,7 +3766,7 @@
 
 	if (rt2x00_get_field16(eeprom, EEPROM_EIRP_MAX_TX_POWER_2GHZ) <
 					EIRP_MAX_TX_POWER_LIMIT)
-		__set_bit(CONFIG_SUPPORT_POWER_LIMIT, &rt2x00dev->flags);
+		__set_bit(CAPABILITY_POWER_LIMIT, &rt2x00dev->cap_flags);
 
 	return 0;
 }
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index adc3534..08d3947 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -66,7 +66,7 @@
 		return;
 
 	for (i = 0; i < 200; i++) {
-		rt2800_register_read(rt2x00dev, H2M_MAILBOX_CID, &reg);
+		rt2x00pci_register_read(rt2x00dev, H2M_MAILBOX_CID, &reg);
 
 		if ((rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD0) == token) ||
 		    (rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD1) == token) ||
@@ -80,8 +80,8 @@
 	if (i == 200)
 		ERROR(rt2x00dev, "MCU request failed, no response from hardware\n");
 
-	rt2800_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
-	rt2800_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
+	rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
+	rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
 }
 
 #if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X)
@@ -105,7 +105,7 @@
 	struct rt2x00_dev *rt2x00dev = eeprom->data;
 	u32 reg;
 
-	rt2800_register_read(rt2x00dev, E2PROM_CSR, &reg);
+	rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, &reg);
 
 	eeprom->reg_data_in = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_IN);
 	eeprom->reg_data_out = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_OUT);
@@ -127,7 +127,7 @@
 	rt2x00_set_field32(&reg, E2PROM_CSR_CHIP_SELECT,
 			   !!eeprom->reg_chip_select);
 
-	rt2800_register_write(rt2x00dev, E2PROM_CSR, reg);
+	rt2x00pci_register_write(rt2x00dev, E2PROM_CSR, reg);
 }
 
 static void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
@@ -135,7 +135,7 @@
 	struct eeprom_93cx6 eeprom;
 	u32 reg;
 
-	rt2800_register_read(rt2x00dev, E2PROM_CSR, &reg);
+	rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, &reg);
 
 	eeprom.data = rt2x00dev;
 	eeprom.register_read = rt2800pci_eepromregister_read;
@@ -195,9 +195,9 @@
 
 	switch (queue->qid) {
 	case QID_RX:
-		rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+		rt2x00pci_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
 		rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 1);
-		rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+		rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
 		break;
 	case QID_BEACON:
 		/*
@@ -207,15 +207,15 @@
 		tasklet_enable(&rt2x00dev->tbtt_tasklet);
 		tasklet_enable(&rt2x00dev->pretbtt_tasklet);
 
-		rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+		rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
 		rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
 		rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
 		rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
-		rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+		rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg);
 
-		rt2800_register_read(rt2x00dev, INT_TIMER_EN, &reg);
+		rt2x00pci_register_read(rt2x00dev, INT_TIMER_EN, &reg);
 		rt2x00_set_field32(&reg, INT_TIMER_EN_PRE_TBTT_TIMER, 1);
-		rt2800_register_write(rt2x00dev, INT_TIMER_EN, reg);
+		rt2x00pci_register_write(rt2x00dev, INT_TIMER_EN, reg);
 		break;
 	default:
 		break;
@@ -233,11 +233,13 @@
 	case QID_AC_BE:
 	case QID_AC_BK:
 		entry = rt2x00queue_get_entry(queue, Q_INDEX);
-		rt2800_register_write(rt2x00dev, TX_CTX_IDX(queue->qid), entry->entry_idx);
+		rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX(queue->qid),
+					 entry->entry_idx);
 		break;
 	case QID_MGMT:
 		entry = rt2x00queue_get_entry(queue, Q_INDEX);
-		rt2800_register_write(rt2x00dev, TX_CTX_IDX(5), entry->entry_idx);
+		rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX(5),
+					 entry->entry_idx);
 		break;
 	default:
 		break;
@@ -251,20 +253,20 @@
 
 	switch (queue->qid) {
 	case QID_RX:
-		rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+		rt2x00pci_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
 		rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 0);
-		rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+		rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
 		break;
 	case QID_BEACON:
-		rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+		rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
 		rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 0);
 		rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 0);
 		rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
-		rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+		rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg);
 
-		rt2800_register_read(rt2x00dev, INT_TIMER_EN, &reg);
+		rt2x00pci_register_read(rt2x00dev, INT_TIMER_EN, &reg);
 		rt2x00_set_field32(&reg, INT_TIMER_EN_PRE_TBTT_TIMER, 0);
-		rt2800_register_write(rt2x00dev, INT_TIMER_EN, reg);
+		rt2x00pci_register_write(rt2x00dev, INT_TIMER_EN, reg);
 
 		/*
 		 * Wait for tbtt tasklets to finish.
@@ -295,7 +297,7 @@
 	 */
 	reg = 0;
 	rt2x00_set_field32(&reg, PBF_SYS_CTRL_HOST_RAM_WRITE, 1);
-	rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, reg);
+	rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, reg);
 
 	/*
 	 * Write firmware to device.
@@ -303,11 +305,11 @@
 	rt2800_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
 				   data, len);
 
-	rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000);
-	rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001);
+	rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000);
+	rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001);
 
-	rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
-	rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
+	rt2x00pci_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
+	rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
 
 	return 0;
 }
@@ -351,7 +353,7 @@
 		 * Set RX IDX in register to inform hardware that we have
 		 * handled this entry and it is available for reuse again.
 		 */
-		rt2800_register_write(rt2x00dev, RX_CRX_IDX,
+		rt2x00pci_register_write(rt2x00dev, RX_CRX_IDX,
 				      entry->entry_idx);
 	} else {
 		rt2x00_desc_read(entry_priv->desc, 1, &word);
@@ -369,45 +371,51 @@
 	 * Initialize registers.
 	 */
 	entry_priv = rt2x00dev->tx[0].entries[0].priv_data;
-	rt2800_register_write(rt2x00dev, TX_BASE_PTR0, entry_priv->desc_dma);
-	rt2800_register_write(rt2x00dev, TX_MAX_CNT0, rt2x00dev->tx[0].limit);
-	rt2800_register_write(rt2x00dev, TX_CTX_IDX0, 0);
-	rt2800_register_write(rt2x00dev, TX_DTX_IDX0, 0);
+	rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR0, entry_priv->desc_dma);
+	rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT0,
+				 rt2x00dev->tx[0].limit);
+	rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX0, 0);
+	rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX0, 0);
 
 	entry_priv = rt2x00dev->tx[1].entries[0].priv_data;
-	rt2800_register_write(rt2x00dev, TX_BASE_PTR1, entry_priv->desc_dma);
-	rt2800_register_write(rt2x00dev, TX_MAX_CNT1, rt2x00dev->tx[1].limit);
-	rt2800_register_write(rt2x00dev, TX_CTX_IDX1, 0);
-	rt2800_register_write(rt2x00dev, TX_DTX_IDX1, 0);
+	rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR1, entry_priv->desc_dma);
+	rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT1,
+				 rt2x00dev->tx[1].limit);
+	rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX1, 0);
+	rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX1, 0);
 
 	entry_priv = rt2x00dev->tx[2].entries[0].priv_data;
-	rt2800_register_write(rt2x00dev, TX_BASE_PTR2, entry_priv->desc_dma);
-	rt2800_register_write(rt2x00dev, TX_MAX_CNT2, rt2x00dev->tx[2].limit);
-	rt2800_register_write(rt2x00dev, TX_CTX_IDX2, 0);
-	rt2800_register_write(rt2x00dev, TX_DTX_IDX2, 0);
+	rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR2, entry_priv->desc_dma);
+	rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT2,
+				 rt2x00dev->tx[2].limit);
+	rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX2, 0);
+	rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX2, 0);
 
 	entry_priv = rt2x00dev->tx[3].entries[0].priv_data;
-	rt2800_register_write(rt2x00dev, TX_BASE_PTR3, entry_priv->desc_dma);
-	rt2800_register_write(rt2x00dev, TX_MAX_CNT3, rt2x00dev->tx[3].limit);
-	rt2800_register_write(rt2x00dev, TX_CTX_IDX3, 0);
-	rt2800_register_write(rt2x00dev, TX_DTX_IDX3, 0);
+	rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR3, entry_priv->desc_dma);
+	rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT3,
+				 rt2x00dev->tx[3].limit);
+	rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX3, 0);
+	rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX3, 0);
 
 	entry_priv = rt2x00dev->rx->entries[0].priv_data;
-	rt2800_register_write(rt2x00dev, RX_BASE_PTR, entry_priv->desc_dma);
-	rt2800_register_write(rt2x00dev, RX_MAX_CNT, rt2x00dev->rx[0].limit);
-	rt2800_register_write(rt2x00dev, RX_CRX_IDX, rt2x00dev->rx[0].limit - 1);
-	rt2800_register_write(rt2x00dev, RX_DRX_IDX, 0);
+	rt2x00pci_register_write(rt2x00dev, RX_BASE_PTR, entry_priv->desc_dma);
+	rt2x00pci_register_write(rt2x00dev, RX_MAX_CNT,
+				 rt2x00dev->rx[0].limit);
+	rt2x00pci_register_write(rt2x00dev, RX_CRX_IDX,
+				 rt2x00dev->rx[0].limit - 1);
+	rt2x00pci_register_write(rt2x00dev, RX_DRX_IDX, 0);
 
 	/*
 	 * Enable global DMA configuration
 	 */
-	rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
+	rt2x00pci_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
 	rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0);
 	rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0);
 	rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
-	rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
+	rt2x00pci_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
 
-	rt2800_register_write(rt2x00dev, DELAY_INT_CFG, 0);
+	rt2x00pci_register_write(rt2x00dev, DELAY_INT_CFG, 0);
 
 	return 0;
 }
@@ -427,8 +435,8 @@
 	 * should clear the register to assure a clean state.
 	 */
 	if (state == STATE_RADIO_IRQ_ON) {
-		rt2800_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
-		rt2800_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
+		rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
+		rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
 
 		/*
 		 * Enable tasklets. The beacon related tasklets are
@@ -440,7 +448,7 @@
 	}
 
 	spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
-	rt2800_register_read(rt2x00dev, INT_MASK_CSR, &reg);
+	rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, &reg);
 	rt2x00_set_field32(&reg, INT_MASK_CSR_RXDELAYINT, 0);
 	rt2x00_set_field32(&reg, INT_MASK_CSR_TXDELAYINT, 0);
 	rt2x00_set_field32(&reg, INT_MASK_CSR_RX_DONE, mask);
@@ -459,7 +467,7 @@
 	rt2x00_set_field32(&reg, INT_MASK_CSR_GPTIMER, 0);
 	rt2x00_set_field32(&reg, INT_MASK_CSR_RX_COHERENT, 0);
 	rt2x00_set_field32(&reg, INT_MASK_CSR_TX_COHERENT, 0);
-	rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg);
+	rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
 	spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
 
 	if (state == STATE_RADIO_IRQ_OFF) {
@@ -480,7 +488,7 @@
 	/*
 	 * Reset DMA indexes
 	 */
-	rt2800_register_read(rt2x00dev, WPDMA_RST_IDX, &reg);
+	rt2x00pci_register_read(rt2x00dev, WPDMA_RST_IDX, &reg);
 	rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX0, 1);
 	rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX1, 1);
 	rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX2, 1);
@@ -488,26 +496,26 @@
 	rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX4, 1);
 	rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX5, 1);
 	rt2x00_set_field32(&reg, WPDMA_RST_IDX_DRX_IDX0, 1);
-	rt2800_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
+	rt2x00pci_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
 
-	rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f);
-	rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
+	rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f);
+	rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
 
 	if (rt2x00_rt(rt2x00dev, RT5390)) {
-		rt2800_register_read(rt2x00dev, AUX_CTRL, &reg);
+		rt2x00pci_register_read(rt2x00dev, AUX_CTRL, &reg);
 		rt2x00_set_field32(&reg, AUX_CTRL_FORCE_PCIE_CLK, 1);
 		rt2x00_set_field32(&reg, AUX_CTRL_WAKE_PCIE_EN, 1);
-		rt2800_register_write(rt2x00dev, AUX_CTRL, reg);
+		rt2x00pci_register_write(rt2x00dev, AUX_CTRL, reg);
 	}
 
-	rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
+	rt2x00pci_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
 
-	rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+	rt2x00pci_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
 	rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_CSR, 1);
 	rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_BBP, 1);
-	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+	rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
 
-	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000);
+	rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000);
 
 	return 0;
 }
@@ -525,8 +533,8 @@
 {
 	if (rt2x00_is_soc(rt2x00dev)) {
 		rt2800_disable_radio(rt2x00dev);
-		rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0);
-		rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0);
+		rt2x00pci_register_write(rt2x00dev, PWR_PIN_CFG, 0);
+		rt2x00pci_register_write(rt2x00dev, TX_PIN_CFG, 0);
 	}
 }
 
@@ -537,8 +545,10 @@
 		rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKUP, 0, 0x02);
 		rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKUP);
 	} else if (state == STATE_SLEEP) {
-		rt2800_register_write(rt2x00dev, H2M_MAILBOX_STATUS, 0xffffffff);
-		rt2800_register_write(rt2x00dev, H2M_MAILBOX_CID, 0xffffffff);
+		rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS,
+					 0xffffffff);
+		rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID,
+					 0xffffffff);
 		rt2800_mcu_request(rt2x00dev, MCU_SLEEP, 0x01, 0xff, 0x01);
 	}
 
@@ -768,8 +778,8 @@
 	return !max_tx_done;
 }
 
-static void rt2800pci_enable_interrupt(struct rt2x00_dev *rt2x00dev,
-				       struct rt2x00_field32 irq_field)
+static inline void rt2800pci_enable_interrupt(struct rt2x00_dev *rt2x00dev,
+					      struct rt2x00_field32 irq_field)
 {
 	u32 reg;
 
@@ -778,9 +788,9 @@
 	 * access needs locking.
 	 */
 	spin_lock_irq(&rt2x00dev->irqmask_lock);
-	rt2800_register_read(rt2x00dev, INT_MASK_CSR, &reg);
+	rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, &reg);
 	rt2x00_set_field32(&reg, irq_field, 1);
-	rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg);
+	rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
 	spin_unlock_irq(&rt2x00dev->irqmask_lock);
 }
 
@@ -851,7 +861,7 @@
 	 * need to lock the kfifo.
 	 */
 	for (i = 0; i < rt2x00dev->ops->tx->entry_num; i++) {
-		rt2800_register_read(rt2x00dev, TX_STA_FIFO, &status);
+		rt2x00pci_register_read(rt2x00dev, TX_STA_FIFO, &status);
 
 		if (!rt2x00_get_field32(status, TX_STA_FIFO_VALID))
 			break;
@@ -873,8 +883,8 @@
 	u32 reg, mask;
 
 	/* Read status and ACK all interrupts */
-	rt2800_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
-	rt2800_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
+	rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
+	rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
 
 	if (!reg)
 		return IRQ_NONE;
@@ -914,9 +924,9 @@
 	 * the tasklet will reenable the appropriate interrupts.
 	 */
 	spin_lock(&rt2x00dev->irqmask_lock);
-	rt2800_register_read(rt2x00dev, INT_MASK_CSR, &reg);
+	rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, &reg);
 	reg &= mask;
-	rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg);
+	rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
 	spin_unlock(&rt2x00dev->irqmask_lock);
 
 	return IRQ_HANDLED;
@@ -966,28 +976,28 @@
 	 * This device has multiple filters for control frames
 	 * and has a separate filter for PS Poll frames.
 	 */
-	__set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags);
-	__set_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags);
+	__set_bit(CAPABILITY_CONTROL_FILTERS, &rt2x00dev->cap_flags);
+	__set_bit(CAPABILITY_CONTROL_FILTER_PSPOLL, &rt2x00dev->cap_flags);
 
 	/*
 	 * This device has a pre tbtt interrupt and thus fetches
 	 * a new beacon directly prior to transmission.
 	 */
-	__set_bit(DRIVER_SUPPORT_PRE_TBTT_INTERRUPT, &rt2x00dev->flags);
+	__set_bit(CAPABILITY_PRE_TBTT_INTERRUPT, &rt2x00dev->cap_flags);
 
 	/*
 	 * This device requires firmware.
 	 */
 	if (!rt2x00_is_soc(rt2x00dev))
-		__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
-	__set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
-	__set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags);
-	__set_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags);
-	__set_bit(DRIVER_REQUIRE_TASKLET_CONTEXT, &rt2x00dev->flags);
+		__set_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags);
+	__set_bit(REQUIRE_DMA, &rt2x00dev->cap_flags);
+	__set_bit(REQUIRE_L2PAD, &rt2x00dev->cap_flags);
+	__set_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags);
+	__set_bit(REQUIRE_TASKLET_CONTEXT, &rt2x00dev->cap_flags);
 	if (!modparam_nohwcrypt)
-		__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
-	__set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
-	__set_bit(DRIVER_REQUIRE_HT_TX_DESC, &rt2x00dev->flags);
+		__set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags);
+	__set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags);
+	__set_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags);
 
 	/*
 	 * Set the rssi offset.
@@ -1018,6 +1028,7 @@
 	.ampdu_action		= rt2800_ampdu_action,
 	.flush			= rt2x00mac_flush,
 	.get_survey		= rt2800_get_survey,
+	.get_ringparam		= rt2x00mac_get_ringparam,
 };
 
 static const struct rt2800_ops rt2800pci_rt2800_ops = {
@@ -1057,6 +1068,7 @@
 	.start_queue		= rt2800pci_start_queue,
 	.kick_queue		= rt2800pci_kick_queue,
 	.stop_queue		= rt2800pci_stop_queue,
+	.flush_queue		= rt2x00pci_flush_queue,
 	.write_tx_desc		= rt2800pci_write_tx_desc,
 	.write_tx_data		= rt2800_write_tx_data,
 	.write_beacon		= rt2800_write_beacon,
@@ -1116,36 +1128,36 @@
  */
 #ifdef CONFIG_PCI
 static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = {
-	{ PCI_DEVICE(0x1814, 0x0601), PCI_DEVICE_DATA(&rt2800pci_ops) },
-	{ PCI_DEVICE(0x1814, 0x0681), PCI_DEVICE_DATA(&rt2800pci_ops) },
-	{ PCI_DEVICE(0x1814, 0x0701), PCI_DEVICE_DATA(&rt2800pci_ops) },
-	{ PCI_DEVICE(0x1814, 0x0781), PCI_DEVICE_DATA(&rt2800pci_ops) },
-	{ PCI_DEVICE(0x1814, 0x3090), PCI_DEVICE_DATA(&rt2800pci_ops) },
-	{ PCI_DEVICE(0x1814, 0x3091), PCI_DEVICE_DATA(&rt2800pci_ops) },
-	{ PCI_DEVICE(0x1814, 0x3092), PCI_DEVICE_DATA(&rt2800pci_ops) },
-	{ PCI_DEVICE(0x1432, 0x7708), PCI_DEVICE_DATA(&rt2800pci_ops) },
-	{ PCI_DEVICE(0x1432, 0x7727), PCI_DEVICE_DATA(&rt2800pci_ops) },
-	{ PCI_DEVICE(0x1432, 0x7728), PCI_DEVICE_DATA(&rt2800pci_ops) },
-	{ PCI_DEVICE(0x1432, 0x7738), PCI_DEVICE_DATA(&rt2800pci_ops) },
-	{ PCI_DEVICE(0x1432, 0x7748), PCI_DEVICE_DATA(&rt2800pci_ops) },
-	{ PCI_DEVICE(0x1432, 0x7758), PCI_DEVICE_DATA(&rt2800pci_ops) },
-	{ PCI_DEVICE(0x1432, 0x7768), PCI_DEVICE_DATA(&rt2800pci_ops) },
-	{ PCI_DEVICE(0x1462, 0x891a), PCI_DEVICE_DATA(&rt2800pci_ops) },
-	{ PCI_DEVICE(0x1a3b, 0x1059), PCI_DEVICE_DATA(&rt2800pci_ops) },
+	{ PCI_DEVICE(0x1814, 0x0601) },
+	{ PCI_DEVICE(0x1814, 0x0681) },
+	{ PCI_DEVICE(0x1814, 0x0701) },
+	{ PCI_DEVICE(0x1814, 0x0781) },
+	{ PCI_DEVICE(0x1814, 0x3090) },
+	{ PCI_DEVICE(0x1814, 0x3091) },
+	{ PCI_DEVICE(0x1814, 0x3092) },
+	{ PCI_DEVICE(0x1432, 0x7708) },
+	{ PCI_DEVICE(0x1432, 0x7727) },
+	{ PCI_DEVICE(0x1432, 0x7728) },
+	{ PCI_DEVICE(0x1432, 0x7738) },
+	{ PCI_DEVICE(0x1432, 0x7748) },
+	{ PCI_DEVICE(0x1432, 0x7758) },
+	{ PCI_DEVICE(0x1432, 0x7768) },
+	{ PCI_DEVICE(0x1462, 0x891a) },
+	{ PCI_DEVICE(0x1a3b, 0x1059) },
 #ifdef CONFIG_RT2800PCI_RT33XX
-	{ PCI_DEVICE(0x1814, 0x3390), PCI_DEVICE_DATA(&rt2800pci_ops) },
+	{ PCI_DEVICE(0x1814, 0x3390) },
 #endif
 #ifdef CONFIG_RT2800PCI_RT35XX
-	{ PCI_DEVICE(0x1432, 0x7711), PCI_DEVICE_DATA(&rt2800pci_ops) },
-	{ PCI_DEVICE(0x1432, 0x7722), PCI_DEVICE_DATA(&rt2800pci_ops) },
-	{ PCI_DEVICE(0x1814, 0x3060), PCI_DEVICE_DATA(&rt2800pci_ops) },
-	{ PCI_DEVICE(0x1814, 0x3062), PCI_DEVICE_DATA(&rt2800pci_ops) },
-	{ PCI_DEVICE(0x1814, 0x3562), PCI_DEVICE_DATA(&rt2800pci_ops) },
-	{ PCI_DEVICE(0x1814, 0x3592), PCI_DEVICE_DATA(&rt2800pci_ops) },
-	{ PCI_DEVICE(0x1814, 0x3593), PCI_DEVICE_DATA(&rt2800pci_ops) },
+	{ PCI_DEVICE(0x1432, 0x7711) },
+	{ PCI_DEVICE(0x1432, 0x7722) },
+	{ PCI_DEVICE(0x1814, 0x3060) },
+	{ PCI_DEVICE(0x1814, 0x3062) },
+	{ PCI_DEVICE(0x1814, 0x3562) },
+	{ PCI_DEVICE(0x1814, 0x3592) },
+	{ PCI_DEVICE(0x1814, 0x3593) },
 #endif
 #ifdef CONFIG_RT2800PCI_RT53XX
-	{ PCI_DEVICE(0x1814, 0x5390), PCI_DEVICE_DATA(&rt2800pci_ops) },
+	{ PCI_DEVICE(0x1814, 0x5390) },
 #endif
 	{ 0, }
 };
@@ -1181,10 +1193,16 @@
 #endif /* CONFIG_RALINK_RT288X || CONFIG_RALINK_RT305X */
 
 #ifdef CONFIG_PCI
+static int rt2800pci_probe(struct pci_dev *pci_dev,
+			   const struct pci_device_id *id)
+{
+	return rt2x00pci_probe(pci_dev, &rt2800pci_ops);
+}
+
 static struct pci_driver rt2800pci_driver = {
 	.name		= KBUILD_MODNAME,
 	.id_table	= rt2800pci_device_table,
-	.probe		= rt2x00pci_probe,
+	.probe		= rt2800pci_probe,
 	.remove		= __devexit_p(rt2x00pci_remove),
 	.suspend	= rt2x00pci_suspend,
 	.resume		= rt2x00pci_resume,
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 6ba31a0..0d4e8fa 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -59,16 +59,16 @@
 
 	switch (queue->qid) {
 	case QID_RX:
-		rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+		rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
 		rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 1);
-		rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+		rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
 		break;
 	case QID_BEACON:
-		rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+		rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
 		rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
 		rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
 		rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
-		rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+		rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg);
 		break;
 	default:
 		break;
@@ -82,16 +82,16 @@
 
 	switch (queue->qid) {
 	case QID_RX:
-		rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+		rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
 		rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 0);
-		rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+		rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
 		break;
 	case QID_BEACON:
-		rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+		rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
 		rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 0);
 		rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 0);
 		rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
-		rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+		rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg);
 		break;
 	default:
 		break;
@@ -99,6 +99,62 @@
 }
 
 /*
+ * test if there is an entry in any TX queue for which DMA is done
+ * but the TX status has not been returned yet
+ */
+static bool rt2800usb_txstatus_pending(struct rt2x00_dev *rt2x00dev)
+{
+	struct data_queue *queue;
+
+	tx_queue_for_each(rt2x00dev, queue) {
+		if (rt2x00queue_get_entry(queue, Q_INDEX_DMA_DONE) !=
+		    rt2x00queue_get_entry(queue, Q_INDEX_DONE))
+			return true;
+	}
+	return false;
+}
+
+static void rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev,
+						 int urb_status, u32 tx_status)
+{
+	if (urb_status) {
+		WARNING(rt2x00dev, "rt2x00usb_register_read_async failed: %d\n", urb_status);
+		return;
+	}
+
+	/* try to read all TX_STA_FIFO entries before scheduling txdone_work */
+	if (rt2x00_get_field32(tx_status, TX_STA_FIFO_VALID)) {
+		if (!kfifo_put(&rt2x00dev->txstatus_fifo, &tx_status)) {
+			WARNING(rt2x00dev, "TX status FIFO overrun, "
+				"drop tx status report.\n");
+			queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work);
+		} else
+			rt2x00usb_register_read_async(rt2x00dev, TX_STA_FIFO,
+						      rt2800usb_tx_sta_fifo_read_completed);
+	} else if (!kfifo_is_empty(&rt2x00dev->txstatus_fifo)) {
+		queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work);
+	} else if (rt2800usb_txstatus_pending(rt2x00dev)) {
+		mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(20));
+	}
+}
+
+static void rt2800usb_tx_dma_done(struct queue_entry *entry)
+{
+	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+
+	rt2x00usb_register_read_async(rt2x00dev, TX_STA_FIFO,
+				      rt2800usb_tx_sta_fifo_read_completed);
+}
+
+static void rt2800usb_tx_sta_fifo_timeout(unsigned long data)
+{
+	struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
+
+	rt2x00usb_register_read_async(rt2x00dev, TX_STA_FIFO,
+				      rt2800usb_tx_sta_fifo_read_completed);
+}
+
+/*
  * Firmware functions
  */
 static char *rt2800usb_get_firmware_name(struct rt2x00_dev *rt2x00dev)
@@ -129,11 +185,11 @@
 	/*
 	 * Write firmware to device.
 	 */
-	rt2800_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
-				   data + offset, length);
+	rt2x00usb_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
+				      data + offset, length);
 
-	rt2800_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
-	rt2800_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
+	rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
+	rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
 
 	/*
 	 * Send firmware request to device to load firmware,
@@ -148,7 +204,7 @@
 	}
 
 	msleep(10);
-	rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
+	rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
 
 	return 0;
 }
@@ -166,22 +222,22 @@
 	if (rt2800_wait_csr_ready(rt2x00dev))
 		return -EBUSY;
 
-	rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
-	rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000);
+	rt2x00usb_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
+	rt2x00usb_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000);
 
-	rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
+	rt2x00usb_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
 
-	rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+	rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
 	rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_CSR, 1);
 	rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_BBP, 1);
-	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+	rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
 
-	rt2800_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000);
+	rt2x00usb_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000);
 
 	rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0,
 				    USB_MODE_RESET, REGISTER_TIMEOUT);
 
-	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000);
+	rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000);
 
 	return 0;
 }
@@ -193,7 +249,7 @@
 	if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev)))
 		return -EIO;
 
-	rt2800_register_read(rt2x00dev, USB_DMA_CFG, &reg);
+	rt2x00usb_register_read(rt2x00dev, USB_DMA_CFG, &reg);
 	rt2x00_set_field32(&reg, USB_DMA_CFG_PHY_CLEAR, 0);
 	rt2x00_set_field32(&reg, USB_DMA_CFG_RX_BULK_AGG_EN, 0);
 	rt2x00_set_field32(&reg, USB_DMA_CFG_RX_BULK_AGG_TIMEOUT, 128);
@@ -206,7 +262,7 @@
 			    / 1024) - 3);
 	rt2x00_set_field32(&reg, USB_DMA_CFG_RX_BULK_EN, 1);
 	rt2x00_set_field32(&reg, USB_DMA_CFG_TX_BULK_EN, 1);
-	rt2800_register_write(rt2x00dev, USB_DMA_CFG, reg);
+	rt2x00usb_register_write(rt2x00dev, USB_DMA_CFG, reg);
 
 	return rt2800_enable_radio(rt2x00dev);
 }
@@ -282,12 +338,12 @@
 	unsigned int i;
 	u32 reg;
 
-	rt2800_register_read(rt2x00dev, TXRXQ_PCNT, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRXQ_PCNT, &reg);
 	if (rt2x00_get_field32(reg, TXRXQ_PCNT_TX0Q)) {
 		WARNING(rt2x00dev, "TX HW queue 0 timed out,"
 			" invoke forced kick\n");
 
-		rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40012);
+		rt2x00usb_register_write(rt2x00dev, PBF_CFG, 0xf40012);
 
 		for (i = 0; i < 10; i++) {
 			udelay(10);
@@ -295,15 +351,15 @@
 				break;
 		}
 
-		rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40006);
+		rt2x00usb_register_write(rt2x00dev, PBF_CFG, 0xf40006);
 	}
 
-	rt2800_register_read(rt2x00dev, TXRXQ_PCNT, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRXQ_PCNT, &reg);
 	if (rt2x00_get_field32(reg, TXRXQ_PCNT_TX1Q)) {
 		WARNING(rt2x00dev, "TX HW queue 1 timed out,"
 			" invoke forced kick\n");
 
-		rt2800_register_write(rt2x00dev, PBF_CFG, 0xf4000a);
+		rt2x00usb_register_write(rt2x00dev, PBF_CFG, 0xf4000a);
 
 		for (i = 0; i < 10; i++) {
 			udelay(10);
@@ -311,7 +367,7 @@
 				break;
 		}
 
-		rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40006);
+		rt2x00usb_register_write(rt2x00dev, PBF_CFG, 0xf40006);
 	}
 
 	rt2x00usb_watchdog(rt2x00dev);
@@ -420,13 +476,24 @@
 		while (!rt2x00queue_empty(queue)) {
 			entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
 
-			if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
-			    !test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
+			if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
 				break;
-
-			rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
+			if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
+				rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
+			else if (rt2x00queue_status_timeout(entry))
+				rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN);
+			else
+				break;
 		}
 	}
+
+	/*
+	 * The hw may delay sending the packet after DMA complete
+	 * if the medium is busy, thus the TX_STA_FIFO entry is
+	 * also delayed -> use a timer to retrieve it.
+	 */
+	if (rt2800usb_txstatus_pending(rt2x00dev))
+		mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(20));
 }
 
 /*
@@ -553,18 +620,23 @@
 	 * This device has multiple filters for control frames
 	 * and has a separate filter for PS Poll frames.
 	 */
-	__set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags);
-	__set_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags);
+	__set_bit(CAPABILITY_CONTROL_FILTERS, &rt2x00dev->cap_flags);
+	__set_bit(CAPABILITY_CONTROL_FILTER_PSPOLL, &rt2x00dev->cap_flags);
 
 	/*
 	 * This device requires firmware.
 	 */
-	__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
-	__set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags);
+	__set_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags);
+	__set_bit(REQUIRE_L2PAD, &rt2x00dev->cap_flags);
 	if (!modparam_nohwcrypt)
-		__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
-	__set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
-	__set_bit(DRIVER_REQUIRE_HT_TX_DESC, &rt2x00dev->flags);
+		__set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags);
+	__set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags);
+	__set_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags);
+	__set_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags);
+
+	setup_timer(&rt2x00dev->txstatus_timer,
+		    rt2800usb_tx_sta_fifo_timeout,
+		    (unsigned long) rt2x00dev);
 
 	/*
 	 * Set the rssi offset.
@@ -601,6 +673,7 @@
 	.ampdu_action		= rt2800_ampdu_action,
 	.flush			= rt2x00mac_flush,
 	.get_survey		= rt2800_get_survey,
+	.get_ringparam		= rt2x00mac_get_ringparam,
 };
 
 static const struct rt2800_ops rt2800usb_rt2800_ops = {
@@ -635,6 +708,7 @@
 	.kick_queue		= rt2x00usb_kick_queue,
 	.stop_queue		= rt2800usb_stop_queue,
 	.flush_queue		= rt2x00usb_flush_queue,
+	.tx_dma_done		= rt2800usb_tx_dma_done,
 	.write_tx_desc		= rt2800usb_write_tx_desc,
 	.write_tx_data		= rt2800usb_write_tx_data,
 	.write_beacon		= rt2800_write_beacon,
@@ -695,295 +769,332 @@
  */
 static struct usb_device_id rt2800usb_device_table[] = {
 	/* Abocom */
-	{ USB_DEVICE(0x07b8, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x07b8, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x07b8, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x07b8, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x07b8, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x1482, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x07b8, 0x2870) },
+	{ USB_DEVICE(0x07b8, 0x2770) },
+	{ USB_DEVICE(0x07b8, 0x3070) },
+	{ USB_DEVICE(0x07b8, 0x3071) },
+	{ USB_DEVICE(0x07b8, 0x3072) },
+	{ USB_DEVICE(0x1482, 0x3c09) },
 	/* AirTies */
-	{ USB_DEVICE(0x1eda, 0x2310), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x1eda, 0x2012) },
+	{ USB_DEVICE(0x1eda, 0x2310) },
 	/* Allwin */
-	{ USB_DEVICE(0x8516, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x8516, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x8516, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x8516, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x8516, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x8516, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x8516, 0x2070) },
+	{ USB_DEVICE(0x8516, 0x2770) },
+	{ USB_DEVICE(0x8516, 0x2870) },
+	{ USB_DEVICE(0x8516, 0x3070) },
+	{ USB_DEVICE(0x8516, 0x3071) },
+	{ USB_DEVICE(0x8516, 0x3072) },
+	/* Alpha Networks */
+	{ USB_DEVICE(0x14b2, 0x3c06) },
+	{ USB_DEVICE(0x14b2, 0x3c07) },
+	{ USB_DEVICE(0x14b2, 0x3c09) },
+	{ USB_DEVICE(0x14b2, 0x3c12) },
+	{ USB_DEVICE(0x14b2, 0x3c23) },
+	{ USB_DEVICE(0x14b2, 0x3c25) },
+	{ USB_DEVICE(0x14b2, 0x3c27) },
+	{ USB_DEVICE(0x14b2, 0x3c28) },
+	{ USB_DEVICE(0x14b2, 0x3c2c) },
 	/* Amit */
-	{ USB_DEVICE(0x15c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x15c5, 0x0008) },
 	/* Askey */
-	{ USB_DEVICE(0x1690, 0x0740), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x1690, 0x0740) },
 	/* ASUS */
-	{ USB_DEVICE(0x0b05, 0x1731), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0b05, 0x1732), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0b05, 0x1742), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0b05, 0x1784), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x1761, 0x0b05), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x0b05, 0x1731) },
+	{ USB_DEVICE(0x0b05, 0x1732) },
+	{ USB_DEVICE(0x0b05, 0x1742) },
+	{ USB_DEVICE(0x0b05, 0x1784) },
+	{ USB_DEVICE(0x1761, 0x0b05) },
 	/* AzureWave */
-	{ USB_DEVICE(0x13d3, 0x3247), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x13d3, 0x3273), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x13d3, 0x3305), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x13d3, 0x3307), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x13d3, 0x3321), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x13d3, 0x3247) },
+	{ USB_DEVICE(0x13d3, 0x3273) },
+	{ USB_DEVICE(0x13d3, 0x3305) },
+	{ USB_DEVICE(0x13d3, 0x3307) },
+	{ USB_DEVICE(0x13d3, 0x3321) },
 	/* Belkin */
-	{ USB_DEVICE(0x050d, 0x8053), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x050d, 0x805c), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x050d, 0x815c), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x050d, 0x825b), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x050d, 0x935a), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x050d, 0x935b), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x050d, 0x8053) },
+	{ USB_DEVICE(0x050d, 0x805c) },
+	{ USB_DEVICE(0x050d, 0x815c) },
+	{ USB_DEVICE(0x050d, 0x825b) },
+	{ USB_DEVICE(0x050d, 0x935a) },
+	{ USB_DEVICE(0x050d, 0x935b) },
 	/* Buffalo */
-	{ USB_DEVICE(0x0411, 0x00e8), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0411, 0x016f), USB_DEVICE_DATA(&rt2800usb_ops) },
-	/* Conceptronic */
-	{ USB_DEVICE(0x14b2, 0x3c06), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x14b2, 0x3c07), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x14b2, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x14b2, 0x3c12), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x14b2, 0x3c23), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x14b2, 0x3c25), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x14b2, 0x3c27), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x14b2, 0x3c28), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x0411, 0x00e8) },
+	{ USB_DEVICE(0x0411, 0x016f) },
+	{ USB_DEVICE(0x0411, 0x01a2) },
 	/* Corega */
-	{ USB_DEVICE(0x07aa, 0x002f), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x07aa, 0x003c), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x07aa, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x18c5, 0x0012), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x07aa, 0x002f) },
+	{ USB_DEVICE(0x07aa, 0x003c) },
+	{ USB_DEVICE(0x07aa, 0x003f) },
+	{ USB_DEVICE(0x18c5, 0x0012) },
 	/* D-Link */
-	{ USB_DEVICE(0x07d1, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x07d1, 0x3c0a), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x07d1, 0x3c0d), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x07d1, 0x3c0e), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x07d1, 0x3c0f), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x07d1, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x07d1, 0x3c16), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x07d1, 0x3c09) },
+	{ USB_DEVICE(0x07d1, 0x3c0a) },
+	{ USB_DEVICE(0x07d1, 0x3c0d) },
+	{ USB_DEVICE(0x07d1, 0x3c0e) },
+	{ USB_DEVICE(0x07d1, 0x3c0f) },
+	{ USB_DEVICE(0x07d1, 0x3c11) },
+	{ USB_DEVICE(0x07d1, 0x3c16) },
 	/* Draytek */
-	{ USB_DEVICE(0x07fa, 0x7712), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x07fa, 0x7712) },
 	/* Edimax */
-	{ USB_DEVICE(0x7392, 0x7711), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x7392, 0x7711) },
+	{ USB_DEVICE(0x7392, 0x7717) },
+	{ USB_DEVICE(0x7392, 0x7718) },
 	/* Encore */
-	{ USB_DEVICE(0x203d, 0x1480), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x203d, 0x14a9), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x203d, 0x1480) },
+	{ USB_DEVICE(0x203d, 0x14a9) },
 	/* EnGenius */
-	{ USB_DEVICE(0x1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x1740, 0x9702), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x1740, 0x9703), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x1740, 0x9705), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x1740, 0x9706), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x1740, 0x9707), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x1740, 0x9708), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x1740, 0x9709), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x1740, 0x9701) },
+	{ USB_DEVICE(0x1740, 0x9702) },
+	{ USB_DEVICE(0x1740, 0x9703) },
+	{ USB_DEVICE(0x1740, 0x9705) },
+	{ USB_DEVICE(0x1740, 0x9706) },
+	{ USB_DEVICE(0x1740, 0x9707) },
+	{ USB_DEVICE(0x1740, 0x9708) },
+	{ USB_DEVICE(0x1740, 0x9709) },
+	/* Gemtek */
+	{ USB_DEVICE(0x15a9, 0x0012) },
 	/* Gigabyte */
-	{ USB_DEVICE(0x1044, 0x800b), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x1044, 0x800d), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x1044, 0x800b) },
+	{ USB_DEVICE(0x1044, 0x800d) },
 	/* Hawking */
-	{ USB_DEVICE(0x0e66, 0x0001), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0e66, 0x0003), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0e66, 0x0009), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0e66, 0x000b), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0e66, 0x0013), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0e66, 0x0017), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0e66, 0x0018), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x0e66, 0x0001) },
+	{ USB_DEVICE(0x0e66, 0x0003) },
+	{ USB_DEVICE(0x0e66, 0x0009) },
+	{ USB_DEVICE(0x0e66, 0x000b) },
+	{ USB_DEVICE(0x0e66, 0x0013) },
+	{ USB_DEVICE(0x0e66, 0x0017) },
+	{ USB_DEVICE(0x0e66, 0x0018) },
 	/* I-O DATA */
-	{ USB_DEVICE(0x04bb, 0x0945), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x04bb, 0x0947), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x04bb, 0x0948), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x04bb, 0x0945) },
+	{ USB_DEVICE(0x04bb, 0x0947) },
+	{ USB_DEVICE(0x04bb, 0x0948) },
 	/* Linksys */
-	{ USB_DEVICE(0x1737, 0x0070), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x1737, 0x0071), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x13b1, 0x0031) },
+	{ USB_DEVICE(0x1737, 0x0070) },
+	{ USB_DEVICE(0x1737, 0x0071) },
 	/* Logitec */
-	{ USB_DEVICE(0x0789, 0x0162), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0789, 0x0163), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0789, 0x0164), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0789, 0x0166), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x0789, 0x0162) },
+	{ USB_DEVICE(0x0789, 0x0163) },
+	{ USB_DEVICE(0x0789, 0x0164) },
+	{ USB_DEVICE(0x0789, 0x0166) },
 	/* Motorola */
-	{ USB_DEVICE(0x100d, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x100d, 0x9031) },
 	/* MSI */
-	{ USB_DEVICE(0x0db0, 0x3820), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0db0, 0x3821), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0db0, 0x3822), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0db0, 0x3870), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0db0, 0x3871), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0db0, 0x6899), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0db0, 0x821a), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0db0, 0x822a), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0db0, 0x822b), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0db0, 0x822c), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0db0, 0x870a), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0db0, 0x871a), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0db0, 0x871b), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0db0, 0x871c), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0db0, 0x899a), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x0db0, 0x3820) },
+	{ USB_DEVICE(0x0db0, 0x3821) },
+	{ USB_DEVICE(0x0db0, 0x3822) },
+	{ USB_DEVICE(0x0db0, 0x3870) },
+	{ USB_DEVICE(0x0db0, 0x3871) },
+	{ USB_DEVICE(0x0db0, 0x6899) },
+	{ USB_DEVICE(0x0db0, 0x821a) },
+	{ USB_DEVICE(0x0db0, 0x822a) },
+	{ USB_DEVICE(0x0db0, 0x822b) },
+	{ USB_DEVICE(0x0db0, 0x822c) },
+	{ USB_DEVICE(0x0db0, 0x870a) },
+	{ USB_DEVICE(0x0db0, 0x871a) },
+	{ USB_DEVICE(0x0db0, 0x871b) },
+	{ USB_DEVICE(0x0db0, 0x871c) },
+	{ USB_DEVICE(0x0db0, 0x899a) },
 	/* Para */
-	{ USB_DEVICE(0x20b8, 0x8888), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x20b8, 0x8888) },
 	/* Pegatron */
-	{ USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x1d4d, 0x000e), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x1d4d, 0x0011), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x1d4d, 0x000c) },
+	{ USB_DEVICE(0x1d4d, 0x000e) },
+	{ USB_DEVICE(0x1d4d, 0x0011) },
 	/* Philips */
-	{ USB_DEVICE(0x0471, 0x200f), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x0471, 0x200f) },
 	/* Planex */
-	{ USB_DEVICE(0x2019, 0xab25), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x2019, 0xed06), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x2019, 0xab25) },
+	{ USB_DEVICE(0x2019, 0xed06) },
 	/* Quanta */
-	{ USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x1a32, 0x0304) },
 	/* Ralink */
-	{ USB_DEVICE(0x148f, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x148f, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x148f, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x148f, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x148f, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x148f, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x148f, 0x2070) },
+	{ USB_DEVICE(0x148f, 0x2770) },
+	{ USB_DEVICE(0x148f, 0x2870) },
+	{ USB_DEVICE(0x148f, 0x3070) },
+	{ USB_DEVICE(0x148f, 0x3071) },
+	{ USB_DEVICE(0x148f, 0x3072) },
 	/* Samsung */
-	{ USB_DEVICE(0x04e8, 0x2018), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x04e8, 0x2018) },
 	/* Siemens */
-	{ USB_DEVICE(0x129b, 0x1828), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x129b, 0x1828) },
 	/* Sitecom */
-	{ USB_DEVICE(0x0df6, 0x0017), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0df6, 0x002b), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0df6, 0x002c), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0df6, 0x002d), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0df6, 0x0039), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0df6, 0x003b), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0df6, 0x003d), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0df6, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0df6, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0df6, 0x0040), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0df6, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0df6, 0x0047), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0df6, 0x0048), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x0df6, 0x0017) },
+	{ USB_DEVICE(0x0df6, 0x002b) },
+	{ USB_DEVICE(0x0df6, 0x002c) },
+	{ USB_DEVICE(0x0df6, 0x002d) },
+	{ USB_DEVICE(0x0df6, 0x0039) },
+	{ USB_DEVICE(0x0df6, 0x003b) },
+	{ USB_DEVICE(0x0df6, 0x003d) },
+	{ USB_DEVICE(0x0df6, 0x003e) },
+	{ USB_DEVICE(0x0df6, 0x003f) },
+	{ USB_DEVICE(0x0df6, 0x0040) },
+	{ USB_DEVICE(0x0df6, 0x0042) },
+	{ USB_DEVICE(0x0df6, 0x0047) },
+	{ USB_DEVICE(0x0df6, 0x0048) },
+	{ USB_DEVICE(0x0df6, 0x0051) },
+	{ USB_DEVICE(0x0df6, 0x005f) },
 	/* SMC */
-	{ USB_DEVICE(0x083a, 0x6618), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x083a, 0x7511), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x083a, 0x7512), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x083a, 0x7522), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x083a, 0x8522), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x083a, 0xa618), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x083a, 0xa701), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x083a, 0xa702), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x083a, 0xa703), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x083a, 0xb522), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x083a, 0x6618) },
+	{ USB_DEVICE(0x083a, 0x7511) },
+	{ USB_DEVICE(0x083a, 0x7512) },
+	{ USB_DEVICE(0x083a, 0x7522) },
+	{ USB_DEVICE(0x083a, 0x8522) },
+	{ USB_DEVICE(0x083a, 0xa618) },
+	{ USB_DEVICE(0x083a, 0xa701) },
+	{ USB_DEVICE(0x083a, 0xa702) },
+	{ USB_DEVICE(0x083a, 0xa703) },
+	{ USB_DEVICE(0x083a, 0xb522) },
 	/* Sparklan */
-	{ USB_DEVICE(0x15a9, 0x0006), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x15a9, 0x0006) },
 	/* Sweex */
-	{ USB_DEVICE(0x177f, 0x0302), USB_DEVICE_DATA(&rt2800usb_ops) },
-	/* U-Media*/
-	{ USB_DEVICE(0x157e, 0x300e), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x177f, 0x0302) },
+	/* U-Media */
+	{ USB_DEVICE(0x157e, 0x300e) },
+	{ USB_DEVICE(0x157e, 0x3013) },
 	/* ZCOM */
-	{ USB_DEVICE(0x0cde, 0x0022), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0cde, 0x0025), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x0cde, 0x0022) },
+	{ USB_DEVICE(0x0cde, 0x0025) },
 	/* Zinwell */
-	{ USB_DEVICE(0x5a57, 0x0280), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x5a57, 0x0282), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x5a57, 0x0283), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x5a57, 0x0280) },
+	{ USB_DEVICE(0x5a57, 0x0282) },
+	{ USB_DEVICE(0x5a57, 0x0283) },
+	{ USB_DEVICE(0x5a57, 0x5257) },
 	/* Zyxel */
-	{ USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0586, 0x3418), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x0586, 0x3416) },
+	{ USB_DEVICE(0x0586, 0x3418) },
+	{ USB_DEVICE(0x0586, 0x341e) },
+	{ USB_DEVICE(0x0586, 0x343e) },
 #ifdef CONFIG_RT2800USB_RT33XX
 	/* Ralink */
-	{ USB_DEVICE(0x148f, 0x3370), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x148f, 0x8070), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x148f, 0x3370) },
+	{ USB_DEVICE(0x148f, 0x8070) },
 	/* Sitecom */
-	{ USB_DEVICE(0x0df6, 0x0050), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x0df6, 0x0050) },
 #endif
 #ifdef CONFIG_RT2800USB_RT35XX
 	/* Allwin */
-	{ USB_DEVICE(0x8516, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x8516, 0x3572) },
 	/* Askey */
-	{ USB_DEVICE(0x1690, 0x0744), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x1690, 0x0744) },
 	/* Cisco */
-	{ USB_DEVICE(0x167b, 0x4001), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x167b, 0x4001) },
 	/* EnGenius */
-	{ USB_DEVICE(0x1740, 0x9801), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x1740, 0x9801) },
 	/* I-O DATA */
-	{ USB_DEVICE(0x04bb, 0x0944), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x04bb, 0x0944) },
+	/* Linksys */
+	{ USB_DEVICE(0x13b1, 0x002f) },
+	{ USB_DEVICE(0x1737, 0x0079) },
 	/* Ralink */
-	{ USB_DEVICE(0x148f, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x148f, 0x3572) },
 	/* Sitecom */
-	{ USB_DEVICE(0x0df6, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x0df6, 0x0041) },
 	/* Toshiba */
-	{ USB_DEVICE(0x0930, 0x0a07), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x0930, 0x0a07) },
 	/* Zinwell */
-	{ USB_DEVICE(0x5a57, 0x0284), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x5a57, 0x0284) },
 #endif
 #ifdef CONFIG_RT2800USB_UNKNOWN
 	/*
 	 * Unclear what kind of devices these are (they aren't supported by the
 	 * vendor linux driver).
 	 */
+	/* Abocom */
+	{ USB_DEVICE(0x07b8, 0x3073) },
+	{ USB_DEVICE(0x07b8, 0x3074) },
+	/* Alpha Networks */
+	{ USB_DEVICE(0x14b2, 0x3c08) },
+	{ USB_DEVICE(0x14b2, 0x3c11) },
 	/* Amigo */
-	{ USB_DEVICE(0x0e0b, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0e0b, 0x9041), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x0e0b, 0x9031) },
+	{ USB_DEVICE(0x0e0b, 0x9041) },
 	/* ASUS */
-	{ USB_DEVICE(0x0b05, 0x1760), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0b05, 0x1761), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0b05, 0x1790), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x0b05, 0x166a) },
+	{ USB_DEVICE(0x0b05, 0x1760) },
+	{ USB_DEVICE(0x0b05, 0x1761) },
+	{ USB_DEVICE(0x0b05, 0x1790) },
+	{ USB_DEVICE(0x0b05, 0x179d) },
 	/* AzureWave */
-	{ USB_DEVICE(0x13d3, 0x3262), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x13d3, 0x3284), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x13d3, 0x3322), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x13d3, 0x3262) },
+	{ USB_DEVICE(0x13d3, 0x3284) },
+	{ USB_DEVICE(0x13d3, 0x3322) },
 	/* Belkin */
-	{ USB_DEVICE(0x050d, 0x825a), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x050d, 0x1003) },
+	{ USB_DEVICE(0x050d, 0x825a) },
 	/* Buffalo */
-	{ USB_DEVICE(0x0411, 0x012e), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0411, 0x0148), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0411, 0x0150), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x0411, 0x015d), USB_DEVICE_DATA(&rt2800usb_ops) },
-	/* Conceptronic */
-	{ USB_DEVICE(0x14b2, 0x3c08), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x14b2, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x0411, 0x012e) },
+	{ USB_DEVICE(0x0411, 0x0148) },
+	{ USB_DEVICE(0x0411, 0x0150) },
+	{ USB_DEVICE(0x0411, 0x015d) },
 	/* Corega */
-	{ USB_DEVICE(0x07aa, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x07aa, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x18c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x07aa, 0x0041) },
+	{ USB_DEVICE(0x07aa, 0x0042) },
+	{ USB_DEVICE(0x18c5, 0x0008) },
 	/* D-Link */
-	{ USB_DEVICE(0x07d1, 0x3c0b), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x07d1, 0x3c15), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x07d1, 0x3c17), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x07d1, 0x3c0b) },
+	{ USB_DEVICE(0x07d1, 0x3c13) },
+	{ USB_DEVICE(0x07d1, 0x3c15) },
+	{ USB_DEVICE(0x07d1, 0x3c17) },
+	{ USB_DEVICE(0x2001, 0x3c17) },
 	/* Edimax */
-	{ USB_DEVICE(0x7392, 0x4085), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x7392, 0x4085) },
+	{ USB_DEVICE(0x7392, 0x7722) },
 	/* Encore */
-	{ USB_DEVICE(0x203d, 0x14a1), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x203d, 0x14a1) },
 	/* Gemtek */
-	{ USB_DEVICE(0x15a9, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x15a9, 0x0010) },
 	/* Gigabyte */
-	{ USB_DEVICE(0x1044, 0x800c), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x1044, 0x800c) },
+	/* Huawei */
+	{ USB_DEVICE(0x148f, 0xf101) },
+	/* I-O DATA */
+	{ USB_DEVICE(0x04bb, 0x094b) },
 	/* LevelOne */
-	{ USB_DEVICE(0x1740, 0x0605), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x1740, 0x0615), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x1740, 0x0605) },
+	{ USB_DEVICE(0x1740, 0x0615) },
 	/* Linksys */
-	{ USB_DEVICE(0x1737, 0x0077), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x1737, 0x0078), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x1737, 0x0079), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x1737, 0x0077) },
+	{ USB_DEVICE(0x1737, 0x0078) },
+	/* Logitec */
+	{ USB_DEVICE(0x0789, 0x0168) },
+	{ USB_DEVICE(0x0789, 0x0169) },
 	/* Motorola */
-	{ USB_DEVICE(0x100d, 0x9032), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x100d, 0x9032) },
 	/* Ovislink */
-	{ USB_DEVICE(0x1b75, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x1b75, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x1b75, 0x3071) },
+	{ USB_DEVICE(0x1b75, 0x3072) },
 	/* Pegatron */
-	{ USB_DEVICE(0x05a6, 0x0101), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x1d4d, 0x0002), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x1d4d, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x05a6, 0x0101) },
+	{ USB_DEVICE(0x1d4d, 0x0002) },
+	{ USB_DEVICE(0x1d4d, 0x0010) },
 	/* Planex */
-	{ USB_DEVICE(0x2019, 0x5201), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x2019, 0xab24), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x2019, 0x5201) },
+	{ USB_DEVICE(0x2019, 0xab24) },
 	/* Qcom */
-	{ USB_DEVICE(0x18e8, 0x6259), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x18e8, 0x6259) },
+	/* RadioShack */
+	{ USB_DEVICE(0x08b9, 0x1197) },
+	/* Sitecom */
+	{ USB_DEVICE(0x0df6, 0x003c) },
+	{ USB_DEVICE(0x0df6, 0x004a) },
+	{ USB_DEVICE(0x0df6, 0x004d) },
+	{ USB_DEVICE(0x0df6, 0x0053) },
+	{ USB_DEVICE(0x0df6, 0x0060) },
+	{ USB_DEVICE(0x0df6, 0x0062) },
 	/* SMC */
-	{ USB_DEVICE(0x083a, 0xa512), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x083a, 0xc522), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x083a, 0xd522), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x083a, 0xf511), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x083a, 0xa512) },
+	{ USB_DEVICE(0x083a, 0xc522) },
+	{ USB_DEVICE(0x083a, 0xd522) },
+	{ USB_DEVICE(0x083a, 0xf511) },
 	/* Sweex */
-	{ USB_DEVICE(0x177f, 0x0153), USB_DEVICE_DATA(&rt2800usb_ops) },
-	{ USB_DEVICE(0x177f, 0x0313), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x177f, 0x0153) },
+	{ USB_DEVICE(0x177f, 0x0313) },
 	/* Zyxel */
-	{ USB_DEVICE(0x0586, 0x341a), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x0586, 0x341a) },
 #endif
 	{ 0, }
 };
@@ -996,10 +1107,16 @@
 MODULE_FIRMWARE(FIRMWARE_RT2870);
 MODULE_LICENSE("GPL");
 
+static int rt2800usb_probe(struct usb_interface *usb_intf,
+			   const struct usb_device_id *id)
+{
+	return rt2x00usb_probe(usb_intf, &rt2800usb_ops);
+}
+
 static struct usb_driver rt2800usb_driver = {
 	.name		= KBUILD_MODNAME,
 	.id_table	= rt2800usb_device_table,
-	.probe		= rt2x00usb_probe,
+	.probe		= rt2800usb_probe,
 	.disconnect	= rt2x00usb_disconnect,
 	.suspend	= rt2x00usb_suspend,
 	.resume		= rt2x00usb_resume,
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index a2bd5fe..9d1a158 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -37,6 +37,7 @@
 #include <linux/etherdevice.h>
 #include <linux/input-polldev.h>
 #include <linux/kfifo.h>
+#include <linux/timer.h>
 
 #include <net/mac80211.h>
 
@@ -570,7 +571,8 @@
 	void (*start_queue) (struct data_queue *queue);
 	void (*kick_queue) (struct data_queue *queue);
 	void (*stop_queue) (struct data_queue *queue);
-	void (*flush_queue) (struct data_queue *queue);
+	void (*flush_queue) (struct data_queue *queue, bool drop);
+	void (*tx_dma_done) (struct queue_entry *entry);
 
 	/*
 	 * TX control handlers
@@ -643,11 +645,11 @@
 };
 
 /*
- * rt2x00 device flags
+ * rt2x00 state flags
  */
-enum rt2x00_flags {
+enum rt2x00_state_flags {
 	/*
-	 * Device state flags
+	 * Device flags
 	 */
 	DEVICE_STATE_PRESENT,
 	DEVICE_STATE_REGISTERED_HW,
@@ -657,42 +659,47 @@
 	DEVICE_STATE_SCANNING,
 
 	/*
-	 * Driver requirements
-	 */
-	DRIVER_REQUIRE_FIRMWARE,
-	DRIVER_REQUIRE_BEACON_GUARD,
-	DRIVER_REQUIRE_ATIM_QUEUE,
-	DRIVER_REQUIRE_DMA,
-	DRIVER_REQUIRE_COPY_IV,
-	DRIVER_REQUIRE_L2PAD,
-	DRIVER_REQUIRE_TXSTATUS_FIFO,
-	DRIVER_REQUIRE_TASKLET_CONTEXT,
-	DRIVER_REQUIRE_SW_SEQNO,
-	DRIVER_REQUIRE_HT_TX_DESC,
-
-	/*
-	 * Driver features
-	 */
-	CONFIG_SUPPORT_HW_BUTTON,
-	CONFIG_SUPPORT_HW_CRYPTO,
-	CONFIG_SUPPORT_POWER_LIMIT,
-	DRIVER_SUPPORT_CONTROL_FILTERS,
-	DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL,
-	DRIVER_SUPPORT_PRE_TBTT_INTERRUPT,
-	DRIVER_SUPPORT_LINK_TUNING,
-
-	/*
 	 * Driver configuration
 	 */
-	CONFIG_FRAME_TYPE,
-	CONFIG_RF_SEQUENCE,
-	CONFIG_EXTERNAL_LNA_A,
-	CONFIG_EXTERNAL_LNA_BG,
-	CONFIG_DOUBLE_ANTENNA,
 	CONFIG_CHANNEL_HT40,
 };
 
 /*
+ * rt2x00 capability flags
+ */
+enum rt2x00_capability_flags {
+	/*
+	 * Requirements
+	 */
+	REQUIRE_FIRMWARE,
+	REQUIRE_BEACON_GUARD,
+	REQUIRE_ATIM_QUEUE,
+	REQUIRE_DMA,
+	REQUIRE_COPY_IV,
+	REQUIRE_L2PAD,
+	REQUIRE_TXSTATUS_FIFO,
+	REQUIRE_TASKLET_CONTEXT,
+	REQUIRE_SW_SEQNO,
+	REQUIRE_HT_TX_DESC,
+
+	/*
+	 * Capabilities
+	 */
+	CAPABILITY_HW_BUTTON,
+	CAPABILITY_HW_CRYPTO,
+	CAPABILITY_POWER_LIMIT,
+	CAPABILITY_CONTROL_FILTERS,
+	CAPABILITY_CONTROL_FILTER_PSPOLL,
+	CAPABILITY_PRE_TBTT_INTERRUPT,
+	CAPABILITY_LINK_TUNING,
+	CAPABILITY_FRAME_TYPE,
+	CAPABILITY_RF_SEQUENCE,
+	CAPABILITY_EXTERNAL_LNA_A,
+	CAPABILITY_EXTERNAL_LNA_BG,
+	CAPABILITY_DOUBLE_ANTENNA,
+};
+
+/*
  * rt2x00 device structure.
  */
 struct rt2x00_dev {
@@ -738,13 +745,20 @@
 #endif /* CONFIG_RT2X00_LIB_LEDS */
 
 	/*
-	 * Device flags.
-	 * In these flags the current status and some
-	 * of the device capabilities are stored.
+	 * Device state flags.
+	 * In these flags the current status is stored.
+	 * Access to these flags should occur atomically.
 	 */
 	unsigned long flags;
 
 	/*
+	 * Device capabiltiy flags.
+	 * In these flags the device/driver capabilities are stored.
+	 * Access to these flags should occur non-atomically.
+	 */
+	unsigned long cap_flags;
+
+	/*
 	 * Device information, Bus IRQ and name (PCI, SoC)
 	 */
 	int irq;
@@ -911,6 +925,11 @@
 	DECLARE_KFIFO_PTR(txstatus_fifo, u32);
 
 	/*
+	 * Timer to ensure tx status reports are read (rt2800usb).
+	 */
+	struct timer_list txstatus_timer;
+
+	/*
 	 * Tasklet for processing tx status reports (rt2800pci).
 	 */
 	struct tasklet_struct txstatus_tasklet;
@@ -1235,6 +1254,10 @@
 		      const struct ieee80211_tx_queue_params *params);
 void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw);
 void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop);
+int rt2x00mac_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant);
+int rt2x00mac_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant);
+void rt2x00mac_get_ringparam(struct ieee80211_hw *hw,
+			     u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max);
 
 /*
  * Driver allocation handlers.
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index 9416e36..f787264 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -109,15 +109,6 @@
 	rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp, changed);
 }
 
-static inline
-enum antenna rt2x00lib_config_antenna_check(enum antenna current_ant,
-					    enum antenna default_ant)
-{
-	if (current_ant != ANTENNA_SW_DIVERSITY)
-		return current_ant;
-	return (default_ant != ANTENNA_SW_DIVERSITY) ? default_ant : ANTENNA_B;
-}
-
 void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
 			      struct antenna_setup config)
 {
@@ -126,19 +117,35 @@
 	struct antenna_setup *active = &rt2x00dev->link.ant.active;
 
 	/*
-	 * Failsafe: Make sure we are not sending the
-	 * ANTENNA_SW_DIVERSITY state to the driver.
-	 * If that happens, fallback to hardware defaults,
-	 * or our own default.
+	 * When the caller tries to send the SW diversity,
+	 * we must update the ANTENNA_RX_DIVERSITY flag to
+	 * enable the antenna diversity in the link tuner.
+	 *
+	 * Secondly, we must guarentee we never send the
+	 * software antenna diversity command to the driver.
 	 */
-	if (!(ant->flags & ANTENNA_RX_DIVERSITY))
-		config.rx = rt2x00lib_config_antenna_check(config.rx, def->rx);
-	else if (config.rx == ANTENNA_SW_DIVERSITY)
+	if (!(ant->flags & ANTENNA_RX_DIVERSITY)) {
+		if (config.rx == ANTENNA_SW_DIVERSITY) {
+			ant->flags |= ANTENNA_RX_DIVERSITY;
+
+			if (def->rx == ANTENNA_SW_DIVERSITY)
+				config.rx = ANTENNA_B;
+			else
+				config.rx = def->rx;
+		}
+	} else if (config.rx == ANTENNA_SW_DIVERSITY)
 		config.rx = active->rx;
 
-	if (!(ant->flags & ANTENNA_TX_DIVERSITY))
-		config.tx = rt2x00lib_config_antenna_check(config.tx, def->tx);
-	else if (config.tx == ANTENNA_SW_DIVERSITY)
+	if (!(ant->flags & ANTENNA_TX_DIVERSITY)) {
+		if (config.tx == ANTENNA_SW_DIVERSITY) {
+			ant->flags |= ANTENNA_TX_DIVERSITY;
+
+			if (def->tx == ANTENNA_SW_DIVERSITY)
+				config.tx = ANTENNA_B;
+			else
+				config.tx = def->tx;
+		}
+	} else if (config.tx == ANTENNA_SW_DIVERSITY)
 		config.tx = active->tx;
 
 	/*
@@ -163,6 +170,34 @@
 		rt2x00queue_start_queue(rt2x00dev->rx);
 }
 
+static u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev,
+				   struct ieee80211_conf *conf)
+{
+	struct hw_mode_spec *spec = &rt2x00dev->spec;
+	int center_channel;
+	u16 i;
+
+	/*
+	 * Initialize center channel to current channel.
+	 */
+	center_channel = spec->channels[conf->channel->hw_value].channel;
+
+	/*
+	 * Adjust center channel to HT40+ and HT40- operation.
+	 */
+	if (conf_is_ht40_plus(conf))
+		center_channel += 2;
+	else if (conf_is_ht40_minus(conf))
+		center_channel -= (center_channel == 14) ? 1 : 2;
+
+	for (i = 0; i < spec->num_channels; i++)
+		if (spec->channels[i].channel == center_channel)
+			return i;
+
+	WARN_ON(1);
+	return conf->channel->hw_value;
+}
+
 void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
 		      struct ieee80211_conf *conf,
 		      unsigned int ieee80211_flags)
@@ -176,10 +211,10 @@
 
 	if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) {
 		if (conf_is_ht40(conf)) {
-			__set_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags);
+			set_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags);
 			hw_value = rt2x00ht_center_channel(rt2x00dev, conf);
 		} else {
-			__clear_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags);
+			clear_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags);
 			hw_value = conf->channel->hw_value;
 		}
 
diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c
index 3f5688f..1bb9d46 100644
--- a/drivers/net/wireless/rt2x00/rt2x00crypto.c
+++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c
@@ -52,7 +52,7 @@
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
 	struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
 
-	if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) || !hw_key)
+	if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags) || !hw_key)
 		return;
 
 	__set_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags);
@@ -80,7 +80,7 @@
 	struct ieee80211_key_conf *key = tx_info->control.hw_key;
 	unsigned int overhead = 0;
 
-	if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) || !key)
+	if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags) || !key)
 		return overhead;
 
 	/*
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c
index 66166ef..78787fc 100644
--- a/drivers/net/wireless/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.c
@@ -63,7 +63,8 @@
 	 * - driver folder
 	 *   - driver file
 	 *   - chipset file
-	 *   - device flags file
+	 *   - device state flags file
+	 *   - device capability flags file
 	 *   - register folder
 	 *     - csr offset/value files
 	 *     - eeprom offset/value files
@@ -78,6 +79,7 @@
 	struct dentry *driver_entry;
 	struct dentry *chipset_entry;
 	struct dentry *dev_flags;
+	struct dentry *cap_flags;
 	struct dentry *register_folder;
 	struct dentry *csr_off_entry;
 	struct dentry *csr_val_entry;
@@ -553,6 +555,35 @@
 	.llseek		= default_llseek,
 };
 
+static ssize_t rt2x00debug_read_cap_flags(struct file *file,
+					  char __user *buf,
+					  size_t length,
+					  loff_t *offset)
+{
+	struct rt2x00debug_intf *intf =	file->private_data;
+	char line[16];
+	size_t size;
+
+	if (*offset)
+		return 0;
+
+	size = sprintf(line, "0x%.8x\n", (unsigned int)intf->rt2x00dev->cap_flags);
+
+	if (copy_to_user(buf, line, size))
+		return -EFAULT;
+
+	*offset += size;
+	return size;
+}
+
+static const struct file_operations rt2x00debug_fop_cap_flags = {
+	.owner		= THIS_MODULE,
+	.read		= rt2x00debug_read_cap_flags,
+	.open		= rt2x00debug_file_open,
+	.release	= rt2x00debug_file_release,
+	.llseek		= default_llseek,
+};
+
 static struct dentry *rt2x00debug_create_file_driver(const char *name,
 						     struct rt2x00debug_intf
 						     *intf,
@@ -652,6 +683,12 @@
 	if (IS_ERR(intf->dev_flags) || !intf->dev_flags)
 		goto exit;
 
+	intf->cap_flags = debugfs_create_file("cap_flags", S_IRUSR,
+					      intf->driver_folder, intf,
+					      &rt2x00debug_fop_cap_flags);
+	if (IS_ERR(intf->cap_flags) || !intf->cap_flags)
+		goto exit;
+
 	intf->register_folder =
 	    debugfs_create_dir("register", intf->driver_folder);
 	if (IS_ERR(intf->register_folder) || !intf->register_folder)
@@ -705,7 +742,7 @@
 				intf, &rt2x00debug_fop_queue_stats);
 
 #ifdef CONFIG_RT2X00_LIB_CRYPTO
-	if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags))
+	if (test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags))
 		intf->crypto_stats_entry =
 		    debugfs_create_file("crypto", S_IRUGO, intf->queue_folder,
 					intf, &rt2x00debug_fop_crypto_stats);
@@ -743,6 +780,7 @@
 	debugfs_remove(intf->csr_off_entry);
 	debugfs_remove(intf->register_folder);
 	debugfs_remove(intf->dev_flags);
+	debugfs_remove(intf->cap_flags);
 	debugfs_remove(intf->chipset_entry);
 	debugfs_remove(intf->driver_entry);
 	debugfs_remove(intf->driver_folder);
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 9bffe84..7776d9f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -200,7 +200,7 @@
 	 * here as they will fetch the next beacon directly prior to
 	 * transmission.
 	 */
-	if (test_bit(DRIVER_SUPPORT_PRE_TBTT_INTERRUPT, &rt2x00dev->flags))
+	if (test_bit(CAPABILITY_PRE_TBTT_INTERRUPT, &rt2x00dev->cap_flags))
 		return;
 
 	/* fetch next beacon */
@@ -225,7 +225,7 @@
 void rt2x00lib_dmastart(struct queue_entry *entry)
 {
 	set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
-	rt2x00queue_index_inc(entry->queue, Q_INDEX);
+	rt2x00queue_index_inc(entry, Q_INDEX);
 }
 EXPORT_SYMBOL_GPL(rt2x00lib_dmastart);
 
@@ -233,7 +233,7 @@
 {
 	set_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags);
 	clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
-	rt2x00queue_index_inc(entry->queue, Q_INDEX_DMA_DONE);
+	rt2x00queue_index_inc(entry, Q_INDEX_DMA_DONE);
 }
 EXPORT_SYMBOL_GPL(rt2x00lib_dmadone);
 
@@ -271,7 +271,7 @@
 	/*
 	 * Remove L2 padding which was added during
 	 */
-	if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags))
+	if (test_bit(REQUIRE_L2PAD, &rt2x00dev->cap_flags))
 		rt2x00queue_remove_l2pad(entry->skb, header_length);
 
 	/*
@@ -280,7 +280,7 @@
 	 * mac80211 will expect the same data to be present it the
 	 * frame as it was passed to us.
 	 */
-	if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags))
+	if (test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags))
 		rt2x00crypto_tx_insert_iv(entry->skb, header_length);
 
 	/*
@@ -377,7 +377,7 @@
 	 * send the status report back.
 	 */
 	if (!(skbdesc_flags & SKBDESC_NOT_MAC80211)) {
-		if (test_bit(DRIVER_REQUIRE_TASKLET_CONTEXT, &rt2x00dev->flags))
+		if (test_bit(REQUIRE_TASKLET_CONTEXT, &rt2x00dev->cap_flags))
 			ieee80211_tx_status(rt2x00dev->hw, entry->skb);
 		else
 			ieee80211_tx_status_ni(rt2x00dev->hw, entry->skb);
@@ -392,7 +392,7 @@
 
 	rt2x00dev->ops->lib->clear_entry(entry);
 
-	rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
+	rt2x00queue_index_inc(entry, Q_INDEX_DONE);
 
 	/*
 	 * If the data queue was below the threshold before the txdone
@@ -559,7 +559,7 @@
 
 submit_entry:
 	entry->flags = 0;
-	rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
+	rt2x00queue_index_inc(entry, Q_INDEX_DONE);
 	if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
 	    test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
 		rt2x00dev->ops->lib->clear_entry(entry);
@@ -806,15 +806,15 @@
 	/*
 	 * Take TX headroom required for alignment into account.
 	 */
-	if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags))
+	if (test_bit(REQUIRE_L2PAD, &rt2x00dev->cap_flags))
 		rt2x00dev->hw->extra_tx_headroom += RT2X00_L2PAD_SIZE;
-	else if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags))
+	else if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags))
 		rt2x00dev->hw->extra_tx_headroom += RT2X00_ALIGN_SIZE;
 
 	/*
 	 * Allocate tx status FIFO for driver use.
 	 */
-	if (test_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags)) {
+	if (test_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags)) {
 		/*
 		 * Allocate the txstatus fifo. In the worst case the tx
 		 * status fifo has to hold the tx status of all entries
@@ -1071,6 +1071,7 @@
 	/*
 	 * Stop all work.
 	 */
+	del_timer_sync(&rt2x00dev->txstatus_timer);
 	cancel_work_sync(&rt2x00dev->intf_work);
 	if (rt2x00_is_usb(rt2x00dev)) {
 		cancel_work_sync(&rt2x00dev->rxdone_work);
diff --git a/drivers/net/wireless/rt2x00/rt2x00firmware.c b/drivers/net/wireless/rt2x00/rt2x00firmware.c
index be0ff78..f316aad 100644
--- a/drivers/net/wireless/rt2x00/rt2x00firmware.c
+++ b/drivers/net/wireless/rt2x00/rt2x00firmware.c
@@ -99,7 +99,7 @@
 {
 	int retval;
 
-	if (!test_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags))
+	if (!test_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags))
 		return 0;
 
 	if (!rt2x00dev->fw) {
diff --git a/drivers/net/wireless/rt2x00/rt2x00ht.c b/drivers/net/wireless/rt2x00/rt2x00ht.c
deleted file mode 100644
index e8c0c3e..0000000
--- a/drivers/net/wireless/rt2x00/rt2x00ht.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
-	Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
-	<http://rt2x00.serialmonkey.com>
-
-	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; if not, write to the
-	Free Software Foundation, Inc.,
-	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/*
-	Module: rt2x00lib
-	Abstract: rt2x00 HT specific routines.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-
-#include "rt2x00.h"
-#include "rt2x00lib.h"
-
-void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
-				   struct txentry_desc *txdesc,
-				   const struct rt2x00_rate *hwrate)
-{
-	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
-	struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0];
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data;
-
-	if (tx_info->control.sta)
-		txdesc->u.ht.mpdu_density =
-		    tx_info->control.sta->ht_cap.ampdu_density;
-
-	txdesc->u.ht.ba_size = 7;	/* FIXME: What value is needed? */
-
-	/*
-	 * 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
-	 * mcs rate to be used
-	 */
-	if (txrate->flags & IEEE80211_TX_RC_MCS) {
-		txdesc->u.ht.mcs = txrate->idx;
-
-		/*
-		 * MIMO PS should be set to 1 for STA's using dynamic SM PS
-		 * when using more then one tx stream (>MCS7).
-		 */
-		if (tx_info->control.sta && txdesc->u.ht.mcs > 7 &&
-		    ((tx_info->control.sta->ht_cap.cap &
-		      IEEE80211_HT_CAP_SM_PS) >>
-		     IEEE80211_HT_CAP_SM_PS_SHIFT) ==
-		    WLAN_HT_CAP_SM_PS_DYNAMIC)
-			__set_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags);
-	} else {
-		txdesc->u.ht.mcs = rt2x00_get_rate_mcs(hwrate->mcs);
-		if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
-			txdesc->u.ht.mcs |= 0x08;
-	}
-
-	/*
-	 * This frame is eligible for an AMPDU, however, don't aggregate
-	 * frames that are intended to probe a specific tx rate.
-	 */
-	if (tx_info->flags & IEEE80211_TX_CTL_AMPDU &&
-	    !(tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE))
-		__set_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags);
-
-	/*
-	 * Set 40Mhz mode if necessary (for legacy rates this will
-	 * duplicate the frame to both channels).
-	 */
-	if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH ||
-	    txrate->flags & IEEE80211_TX_RC_DUP_DATA)
-		__set_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags);
-	if (txrate->flags & IEEE80211_TX_RC_SHORT_GI)
-		__set_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags);
-
-	/*
-	 * Determine IFS values
-	 * - Use TXOP_BACKOFF for management frames
-	 * - Use TXOP_SIFS for fragment bursts
-	 * - Use TXOP_HTTXOP for everything else
-	 *
-	 * Note: rt2800 devices won't use CTS protection (if used)
-	 * for frames not transmitted with TXOP_HTTXOP
-	 */
-	if (ieee80211_is_mgmt(hdr->frame_control))
-		txdesc->u.ht.txop = TXOP_BACKOFF;
-	else if (!(tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT))
-		txdesc->u.ht.txop = TXOP_SIFS;
-	else
-		txdesc->u.ht.txop = TXOP_HTTXOP;
-}
-
-u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev,
-			    struct ieee80211_conf *conf)
-{
-	struct hw_mode_spec *spec = &rt2x00dev->spec;
-	int center_channel;
-	u16 i;
-
-	/*
-	 * Initialize center channel to current channel.
-	 */
-	center_channel = spec->channels[conf->channel->hw_value].channel;
-
-	/*
-	 * Adjust center channel to HT40+ and HT40- operation.
-	 */
-	if (conf_is_ht40_plus(conf))
-		center_channel += 2;
-	else if (conf_is_ht40_minus(conf))
-		center_channel -= (center_channel == 14) ? 1 : 2;
-
-	for (i = 0; i < spec->num_channels; i++)
-		if (spec->channels[i].channel == center_channel)
-			return i;
-
-	WARN_ON(1);
-	return conf->channel->hw_value;
-}
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index 88f2f92..322cc4f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -175,14 +175,14 @@
 
 /**
  * rt2x00queue_index_inc - Index incrementation function
- * @queue: Queue (&struct data_queue) to perform the action on.
+ * @entry: Queue entry (&struct queue_entry) to perform the action on.
  * @index: Index type (&enum queue_index) to perform the action on.
  *
- * This function will increase the requested index on the queue,
+ * This function will increase the requested index on the entry's queue,
  * it will grab the appropriate locks and handle queue overflow events by
  * resetting the index to the start of the queue.
  */
-void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index);
+void rt2x00queue_index_inc(struct queue_entry *entry, enum queue_index index);
 
 /**
  * rt2x00queue_init_queues - Initialize all data queues
@@ -388,41 +388,17 @@
 #endif /* CONFIG_RT2X00_LIB_CRYPTO */
 
 /*
- * HT handlers.
- */
-#ifdef CONFIG_RT2X00_LIB_HT
-void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
-				   struct txentry_desc *txdesc,
-				   const struct rt2x00_rate *hwrate);
-
-u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev,
-			    struct ieee80211_conf *conf);
-#else
-static inline void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
-						 struct txentry_desc *txdesc,
-						 const struct rt2x00_rate *hwrate)
-{
-}
-
-static inline u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev,
-					  struct ieee80211_conf *conf)
-{
-	return conf->channel->hw_value;
-}
-#endif /* CONFIG_RT2X00_LIB_HT */
-
-/*
  * RFkill handlers.
  */
 static inline void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev)
 {
-	if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
+	if (test_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags))
 		wiphy_rfkill_start_polling(rt2x00dev->hw->wiphy);
 }
 
 static inline void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev)
 {
-	if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
+	if (test_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags))
 		wiphy_rfkill_stop_polling(rt2x00dev->hw->wiphy);
 }
 
diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c
index 1435976..ea10b00 100644
--- a/drivers/net/wireless/rt2x00/rt2x00link.c
+++ b/drivers/net/wireless/rt2x00/rt2x00link.c
@@ -192,17 +192,7 @@
 	/*
 	 * Determine if software diversity is enabled for
 	 * either the TX or RX antenna (or both).
-	 * Always perform this check since within the link
-	 * tuner interval the configuration might have changed.
 	 */
-	ant->flags &= ~ANTENNA_RX_DIVERSITY;
-	ant->flags &= ~ANTENNA_TX_DIVERSITY;
-
-	if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY)
-		ant->flags |= ANTENNA_RX_DIVERSITY;
-	if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY)
-		ant->flags |= ANTENNA_TX_DIVERSITY;
-
 	if (!(ant->flags & ANTENNA_RX_DIVERSITY) &&
 	    !(ant->flags & ANTENNA_TX_DIVERSITY)) {
 		ant->flags = 0;
@@ -383,7 +373,7 @@
 	 * do not support link tuning at all, while other devices can disable
 	 * the feature from the EEPROM.
 	 */
-	if (test_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags))
+	if (test_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags))
 		rt2x00dev->ops->lib->link_tuner(rt2x00dev, qual, link->count);
 
 	/*
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index 661c6ba..93bec14 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -119,7 +119,7 @@
 	 * Use the ATIM queue if appropriate and present.
 	 */
 	if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM &&
-	    test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags))
+	    test_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags))
 		qid = QID_ATIM;
 
 	queue = rt2x00queue_get_tx_queue(rt2x00dev, qid);
@@ -158,7 +158,7 @@
 	return;
 
  exit_fail:
-	ieee80211_stop_queue(rt2x00dev->hw, qid);
+	rt2x00queue_pause_queue(queue);
 	dev_kfree_skb_any(skb);
 }
 EXPORT_SYMBOL_GPL(rt2x00mac_tx);
@@ -411,11 +411,11 @@
 	 * of different types, but has no a separate filter for PS Poll frames,
 	 * FIF_CONTROL flag implies FIF_PSPOLL.
 	 */
-	if (!test_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags)) {
+	if (!test_bit(CAPABILITY_CONTROL_FILTERS, &rt2x00dev->cap_flags)) {
 		if (*total_flags & FIF_CONTROL || *total_flags & FIF_PSPOLL)
 			*total_flags |= FIF_CONTROL | FIF_PSPOLL;
 	}
-	if (!test_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags)) {
+	if (!test_bit(CAPABILITY_CONTROL_FILTER_PSPOLL, &rt2x00dev->cap_flags)) {
 		if (*total_flags & FIF_CONTROL)
 			*total_flags |= FIF_PSPOLL;
 	}
@@ -496,7 +496,7 @@
 
 	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
 		return 0;
-	else if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags))
+	else if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags))
 		return -EOPNOTSUPP;
 	else if (key->keylen > 32)
 		return -ENOSPC;
@@ -562,7 +562,7 @@
 void rt2x00mac_sw_scan_start(struct ieee80211_hw *hw)
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
-	__set_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags);
+	set_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags);
 	rt2x00link_stop_tuner(rt2x00dev);
 }
 EXPORT_SYMBOL_GPL(rt2x00mac_sw_scan_start);
@@ -570,7 +570,7 @@
 void rt2x00mac_sw_scan_complete(struct ieee80211_hw *hw)
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
-	__clear_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags);
+	clear_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags);
 	rt2x00link_start_tuner(rt2x00dev);
 }
 EXPORT_SYMBOL_GPL(rt2x00mac_sw_scan_complete);
@@ -737,3 +737,84 @@
 		rt2x00queue_flush_queue(queue, drop);
 }
 EXPORT_SYMBOL_GPL(rt2x00mac_flush);
+
+int rt2x00mac_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	struct link_ant *ant = &rt2x00dev->link.ant;
+	struct antenna_setup *def = &rt2x00dev->default_ant;
+	struct antenna_setup setup;
+
+	// The antenna value is not supposed to be 0,
+	// or exceed the maximum number of antenna's.
+	if (!tx_ant || (tx_ant & ~3) || !rx_ant || (rx_ant & ~3))
+		return -EINVAL;
+
+	// When the client tried to configure the antenna to or from
+	// diversity mode, we must reset the default antenna as well
+	// as that controls the diversity switch.
+	if (ant->flags & ANTENNA_TX_DIVERSITY && tx_ant != 3)
+		ant->flags &= ~ANTENNA_TX_DIVERSITY;
+	if (ant->flags & ANTENNA_RX_DIVERSITY && rx_ant != 3)
+		ant->flags &= ~ANTENNA_RX_DIVERSITY;
+
+	// If diversity is being enabled, check if we need hardware
+	// or software diversity. In the latter case, reset the value,
+	// and make sure we update the antenna flags to have the
+	// link tuner pick up the diversity tuning.
+	if (tx_ant == 3 && def->tx == ANTENNA_SW_DIVERSITY) {
+		tx_ant = ANTENNA_SW_DIVERSITY;
+		ant->flags |= ANTENNA_TX_DIVERSITY;
+	}
+
+	if (rx_ant == 3 && def->rx == ANTENNA_SW_DIVERSITY) {
+		rx_ant = ANTENNA_SW_DIVERSITY;
+		ant->flags |= ANTENNA_RX_DIVERSITY;
+	}
+
+	setup.tx = tx_ant;
+	setup.rx = rx_ant;
+
+	rt2x00lib_config_antenna(rt2x00dev, setup);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_set_antenna);
+
+int rt2x00mac_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	struct link_ant *ant = &rt2x00dev->link.ant;
+	struct antenna_setup *active = &rt2x00dev->link.ant.active;
+
+	// When software diversity is active, we must report this to the
+	// client and not the current active antenna state.
+	if (ant->flags & ANTENNA_TX_DIVERSITY)
+		*tx_ant = ANTENNA_HW_DIVERSITY;
+	else
+		*tx_ant = active->tx;
+
+	if (ant->flags & ANTENNA_RX_DIVERSITY)
+		*rx_ant = ANTENNA_HW_DIVERSITY;
+	else
+		*rx_ant = active->rx;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_get_antenna);
+
+void rt2x00mac_get_ringparam(struct ieee80211_hw *hw,
+			     u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	struct data_queue *queue;
+
+	tx_queue_for_each(rt2x00dev, queue) {
+		*tx += queue->length;
+		*tx_max += queue->limit;
+	}
+
+	*rx = rt2x00dev->rx->length;
+	*rx_max = rt2x00dev->rx->limit;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_get_ringparam);
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index 9649bd0..17148bb 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -99,6 +99,15 @@
 }
 EXPORT_SYMBOL_GPL(rt2x00pci_rxdone);
 
+void rt2x00pci_flush_queue(struct data_queue *queue, bool drop)
+{
+	unsigned int i;
+
+	for (i = 0; !rt2x00queue_empty(queue) && i < 10; i++)
+		msleep(10);
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_flush_queue);
+
 /*
  * Device initialization handlers.
  */
@@ -242,9 +251,8 @@
 	return -ENOMEM;
 }
 
-int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
+int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops)
 {
-	struct rt2x00_ops *ops = (struct rt2x00_ops *)id->driver_data;
 	struct ieee80211_hw *hw;
 	struct rt2x00_dev *rt2x00dev;
 	int retval;
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h
index 07961b8..e2c99f2 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.h
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.h
@@ -107,6 +107,16 @@
  */
 bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev);
 
+/**
+ * rt2x00pci_flush_queue - Flush data queue
+ * @queue: Data queue to stop
+ * @drop: True to drop all pending frames.
+ *
+ * This will wait for a maximum of 100ms, waiting for the queues
+ * to become empty.
+ */
+void rt2x00pci_flush_queue(struct data_queue *queue, bool drop);
+
 /*
  * Device initialization handlers.
  */
@@ -116,7 +126,7 @@
 /*
  * PCI driver handlers.
  */
-int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id);
+int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops);
 void rt2x00pci_remove(struct pci_dev *pci_dev);
 #ifdef CONFIG_PM
 int rt2x00pci_suspend(struct pci_dev *pci_dev, pm_message_t state);
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 94b8bbb..ab8c16f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -60,7 +60,7 @@
 	 * at least 8 bytes bytes available in headroom for IV/EIV
 	 * and 8 bytes for ICV data as tailroon.
 	 */
-	if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
+	if (test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags)) {
 		head_size += 8;
 		tail_size += 8;
 	}
@@ -86,7 +86,7 @@
 	memset(skbdesc, 0, sizeof(*skbdesc));
 	skbdesc->entry = entry;
 
-	if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags)) {
+	if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags)) {
 		skbdesc->skb_dma = dma_map_single(rt2x00dev->dev,
 						  skb->data,
 						  skb->len,
@@ -213,7 +213,7 @@
 
 	__set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags);
 
-	if (!test_bit(DRIVER_REQUIRE_SW_SEQNO, &entry->queue->rt2x00dev->flags))
+	if (!test_bit(REQUIRE_SW_SEQNO, &entry->queue->rt2x00dev->cap_flags))
 		return;
 
 	/*
@@ -302,6 +302,85 @@
 	}
 }
 
+static void rt2x00queue_create_tx_descriptor_ht(struct queue_entry *entry,
+						struct txentry_desc *txdesc,
+						const struct rt2x00_rate *hwrate)
+{
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
+	struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0];
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data;
+
+	if (tx_info->control.sta)
+		txdesc->u.ht.mpdu_density =
+		    tx_info->control.sta->ht_cap.ampdu_density;
+
+	txdesc->u.ht.ba_size = 7;	/* FIXME: What value is needed? */
+
+	/*
+	 * 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
+	 * mcs rate to be used
+	 */
+	if (txrate->flags & IEEE80211_TX_RC_MCS) {
+		txdesc->u.ht.mcs = txrate->idx;
+
+		/*
+		 * MIMO PS should be set to 1 for STA's using dynamic SM PS
+		 * when using more then one tx stream (>MCS7).
+		 */
+		if (tx_info->control.sta && txdesc->u.ht.mcs > 7 &&
+		    ((tx_info->control.sta->ht_cap.cap &
+		      IEEE80211_HT_CAP_SM_PS) >>
+		     IEEE80211_HT_CAP_SM_PS_SHIFT) ==
+		    WLAN_HT_CAP_SM_PS_DYNAMIC)
+			__set_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags);
+	} else {
+		txdesc->u.ht.mcs = rt2x00_get_rate_mcs(hwrate->mcs);
+		if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
+			txdesc->u.ht.mcs |= 0x08;
+	}
+
+	/*
+	 * This frame is eligible for an AMPDU, however, don't aggregate
+	 * frames that are intended to probe a specific tx rate.
+	 */
+	if (tx_info->flags & IEEE80211_TX_CTL_AMPDU &&
+	    !(tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE))
+		__set_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags);
+
+	/*
+	 * Set 40Mhz mode if necessary (for legacy rates this will
+	 * duplicate the frame to both channels).
+	 */
+	if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH ||
+	    txrate->flags & IEEE80211_TX_RC_DUP_DATA)
+		__set_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags);
+	if (txrate->flags & IEEE80211_TX_RC_SHORT_GI)
+		__set_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags);
+
+	/*
+	 * Determine IFS values
+	 * - Use TXOP_BACKOFF for management frames except beacons
+	 * - Use TXOP_SIFS for fragment bursts
+	 * - Use TXOP_HTTXOP for everything else
+	 *
+	 * Note: rt2800 devices won't use CTS protection (if used)
+	 * for frames not transmitted with TXOP_HTTXOP
+	 */
+	if (ieee80211_is_mgmt(hdr->frame_control) &&
+	    !ieee80211_is_beacon(hdr->frame_control))
+		txdesc->u.ht.txop = TXOP_BACKOFF;
+	else if (!(tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT))
+		txdesc->u.ht.txop = TXOP_SIFS;
+	else
+		txdesc->u.ht.txop = TXOP_HTTXOP;
+}
+
 static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
 					     struct txentry_desc *txdesc)
 {
@@ -396,8 +475,8 @@
 	rt2x00crypto_create_tx_descriptor(entry, txdesc);
 	rt2x00queue_create_tx_descriptor_seq(entry, txdesc);
 
-	if (test_bit(DRIVER_REQUIRE_HT_TX_DESC, &rt2x00dev->flags))
-		rt2x00ht_create_tx_descriptor(entry, txdesc, hwrate);
+	if (test_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags))
+		rt2x00queue_create_tx_descriptor_ht(entry, txdesc, hwrate);
 	else
 		rt2x00queue_create_tx_descriptor_plcp(entry, txdesc, hwrate);
 }
@@ -436,7 +515,7 @@
 	/*
 	 * Map the skb to DMA.
 	 */
-	if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags))
+	if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags))
 		rt2x00queue_map_txskb(entry);
 
 	return 0;
@@ -529,7 +608,7 @@
 	 */
 	if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) &&
 	    !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) {
-		if (test_bit(DRIVER_REQUIRE_COPY_IV, &queue->rt2x00dev->flags))
+		if (test_bit(REQUIRE_COPY_IV, &queue->rt2x00dev->cap_flags))
 			rt2x00crypto_tx_copy_iv(skb, &txdesc);
 		else
 			rt2x00crypto_tx_remove_iv(skb, &txdesc);
@@ -543,9 +622,9 @@
 	 * PCI and USB devices, while header alignment only is valid
 	 * for PCI devices.
 	 */
-	if (test_bit(DRIVER_REQUIRE_L2PAD, &queue->rt2x00dev->flags))
+	if (test_bit(REQUIRE_L2PAD, &queue->rt2x00dev->cap_flags))
 		rt2x00queue_insert_l2pad(entry->skb, txdesc.header_length);
-	else if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags))
+	else if (test_bit(REQUIRE_DMA, &queue->rt2x00dev->cap_flags))
 		rt2x00queue_align_frame(entry->skb);
 
 	/*
@@ -561,7 +640,7 @@
 
 	set_bit(ENTRY_DATA_PENDING, &entry->flags);
 
-	rt2x00queue_index_inc(queue, Q_INDEX);
+	rt2x00queue_index_inc(entry, Q_INDEX);
 	rt2x00queue_write_tx_descriptor(entry, &txdesc);
 	rt2x00queue_kick_tx_queue(queue, &txdesc);
 
@@ -650,10 +729,12 @@
 	return ret;
 }
 
-void rt2x00queue_for_each_entry(struct data_queue *queue,
+bool rt2x00queue_for_each_entry(struct data_queue *queue,
 				enum queue_index start,
 				enum queue_index end,
-				void (*fn)(struct queue_entry *entry))
+				void *data,
+				bool (*fn)(struct queue_entry *entry,
+					   void *data))
 {
 	unsigned long irqflags;
 	unsigned int index_start;
@@ -664,7 +745,7 @@
 		ERROR(queue->rt2x00dev,
 		      "Entry requested from invalid index range (%d - %d)\n",
 		      start, end);
-		return;
+		return true;
 	}
 
 	/*
@@ -683,15 +764,23 @@
 	 * send out all frames in the correct order.
 	 */
 	if (index_start < index_end) {
-		for (i = index_start; i < index_end; i++)
-			fn(&queue->entries[i]);
+		for (i = index_start; i < index_end; i++) {
+			if (fn(&queue->entries[i], data))
+				return true;
+		}
 	} else {
-		for (i = index_start; i < queue->limit; i++)
-			fn(&queue->entries[i]);
+		for (i = index_start; i < queue->limit; i++) {
+			if (fn(&queue->entries[i], data))
+				return true;
+		}
 
-		for (i = 0; i < index_end; i++)
-			fn(&queue->entries[i]);
+		for (i = 0; i < index_end; i++) {
+			if (fn(&queue->entries[i], data))
+				return true;
+		}
 	}
+
+	return false;
 }
 EXPORT_SYMBOL_GPL(rt2x00queue_for_each_entry);
 
@@ -717,8 +806,9 @@
 }
 EXPORT_SYMBOL_GPL(rt2x00queue_get_entry);
 
-void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index)
+void rt2x00queue_index_inc(struct queue_entry *entry, enum queue_index index)
 {
+	struct data_queue *queue = entry->queue;
 	unsigned long irqflags;
 
 	if (unlikely(index >= Q_INDEX_MAX)) {
@@ -733,7 +823,7 @@
 	if (queue->index[index] >= queue->limit)
 		queue->index[index] = 0;
 
-	queue->last_action[index] = jiffies;
+	entry->last_action = jiffies;
 
 	if (index == Q_INDEX) {
 		queue->length++;
@@ -838,7 +928,6 @@
 
 void rt2x00queue_flush_queue(struct data_queue *queue, bool drop)
 {
-	unsigned int i;
 	bool started;
 	bool tx_queue =
 		(queue->qid == QID_AC_VO) ||
@@ -873,20 +962,12 @@
 	}
 
 	/*
-	 * Check if driver supports flushing, we can only guarantee
-	 * full support for flushing if the driver is able
-	 * to cancel all pending frames (drop = true).
+	 * Check if driver supports flushing, if that is the case we can
+	 * defer the flushing to the driver. Otherwise we must use the
+	 * alternative which just waits for the queue to become empty.
 	 */
-	if (drop && queue->rt2x00dev->ops->lib->flush_queue)
-		queue->rt2x00dev->ops->lib->flush_queue(queue);
-
-	/*
-	 * When we don't want to drop any frames, or when
-	 * the driver doesn't fully flush the queue correcly,
-	 * we must wait for the queue to become empty.
-	 */
-	for (i = 0; !rt2x00queue_empty(queue) && i < 100; i++)
-		msleep(10);
+	if (likely(queue->rt2x00dev->ops->lib->flush_queue))
+		queue->rt2x00dev->ops->lib->flush_queue(queue, drop);
 
 	/*
 	 * The queue flush has failed...
@@ -959,10 +1040,8 @@
 	queue->count = 0;
 	queue->length = 0;
 
-	for (i = 0; i < Q_INDEX_MAX; i++) {
+	for (i = 0; i < Q_INDEX_MAX; i++)
 		queue->index[i] = 0;
-		queue->last_action[i] = jiffies;
-	}
 
 	spin_unlock_irqrestore(&queue->index_lock, irqflags);
 }
@@ -1069,7 +1148,7 @@
 	if (status)
 		goto exit;
 
-	if (test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags)) {
+	if (test_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags)) {
 		status = rt2x00queue_alloc_entries(rt2x00dev->atim,
 						   rt2x00dev->ops->atim);
 		if (status)
@@ -1121,7 +1200,7 @@
 	struct data_queue *queue;
 	enum data_queue_qid qid;
 	unsigned int req_atim =
-	    !!test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
+	    !!test_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags);
 
 	/*
 	 * We need the following queues:
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index 5db6a99..167d458 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -364,6 +364,7 @@
  * struct queue_entry: Entry inside the &struct data_queue
  *
  * @flags: Entry flags, see &enum queue_entry_flags.
+ * @last_action: Timestamp of last change.
  * @queue: The data queue (&struct data_queue) to which this entry belongs.
  * @skb: The buffer which is currently being transmitted (for TX queue),
  *	or used to directly receive data in (for RX queue).
@@ -373,6 +374,7 @@
  */
 struct queue_entry {
 	unsigned long flags;
+	unsigned long last_action;
 
 	struct data_queue *queue;
 
@@ -463,7 +465,6 @@
 	unsigned short threshold;
 	unsigned short length;
 	unsigned short index[Q_INDEX_MAX];
-	unsigned long last_action[Q_INDEX_MAX];
 
 	unsigned short txop;
 	unsigned short aifs;
@@ -580,16 +581,22 @@
  * @queue: Pointer to @data_queue
  * @start: &enum queue_index Pointer to start index
  * @end: &enum queue_index Pointer to end index
+ * @data: Data to pass to the callback function
  * @fn: The function to call for each &struct queue_entry
  *
  * This will walk through all entries in the queue, in chronological
  * order. This means it will start at the current @start pointer
  * and will walk through the queue until it reaches the @end pointer.
+ *
+ * If fn returns true for an entry rt2x00queue_for_each_entry will stop
+ * processing and return true as well.
  */
-void rt2x00queue_for_each_entry(struct data_queue *queue,
+bool rt2x00queue_for_each_entry(struct data_queue *queue,
 				enum queue_index start,
 				enum queue_index end,
-				void (*fn)(struct queue_entry *entry));
+				void *data,
+				bool (*fn)(struct queue_entry *entry,
+					   void *data));
 
 /**
  * rt2x00queue_empty - Check if the queue is empty.
@@ -629,22 +636,24 @@
 
 /**
  * rt2x00queue_status_timeout - Check if a timeout occurred for STATUS reports
- * @queue: Queue to check.
+ * @entry: Queue entry to check.
  */
-static inline int rt2x00queue_status_timeout(struct data_queue *queue)
+static inline int rt2x00queue_status_timeout(struct queue_entry *entry)
 {
-	return time_after(queue->last_action[Q_INDEX_DMA_DONE],
-			  queue->last_action[Q_INDEX_DONE] + (HZ / 10));
+	if (!test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
+		return false;
+	return time_after(jiffies, entry->last_action + msecs_to_jiffies(100));
 }
 
 /**
- * rt2x00queue_timeout - Check if a timeout occurred for DMA transfers
- * @queue: Queue to check.
+ * rt2x00queue_dma_timeout - Check if a timeout occurred for DMA transfers
+ * @entry: Queue entry to check.
  */
-static inline int rt2x00queue_dma_timeout(struct data_queue *queue)
+static inline int rt2x00queue_dma_timeout(struct queue_entry *entry)
 {
-	return time_after(queue->last_action[Q_INDEX],
-			  queue->last_action[Q_INDEX_DMA_DONE] + (HZ / 10));
+	if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+		return false;
+	return time_after(jiffies, entry->last_action + msecs_to_jiffies(100));
 }
 
 /**
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index 36f388f..cb208d5 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -165,6 +165,56 @@
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_regbusy_read);
 
+
+struct rt2x00_async_read_data {
+	__le32 reg;
+	struct usb_ctrlrequest cr;
+	struct rt2x00_dev *rt2x00dev;
+	void (*callback)(struct rt2x00_dev *,int,u32);
+};
+
+static void rt2x00usb_register_read_async_cb(struct urb *urb)
+{
+	struct rt2x00_async_read_data *rd = urb->context;
+	rd->callback(rd->rt2x00dev, urb->status, le32_to_cpu(rd->reg));
+	kfree(urb->context);
+}
+
+void rt2x00usb_register_read_async(struct rt2x00_dev *rt2x00dev,
+				   const unsigned int offset,
+				   void (*callback)(struct rt2x00_dev*,int,u32))
+{
+	struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
+	struct urb *urb;
+	struct rt2x00_async_read_data *rd;
+
+	rd = kmalloc(sizeof(*rd), GFP_ATOMIC);
+	if (!rd)
+		return;
+
+	urb = usb_alloc_urb(0, GFP_ATOMIC);
+	if (!urb) {
+		kfree(rd);
+		return;
+	}
+
+	rd->rt2x00dev = rt2x00dev;
+	rd->callback = callback;
+	rd->cr.bRequestType = USB_VENDOR_REQUEST_IN;
+	rd->cr.bRequest = USB_MULTI_READ;
+	rd->cr.wValue = 0;
+	rd->cr.wIndex = cpu_to_le16(offset);
+	rd->cr.wLength = cpu_to_le16(sizeof(u32));
+
+	usb_fill_control_urb(urb, usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+			     (unsigned char *)(&rd->cr), &rd->reg, sizeof(rd->reg),
+			     rt2x00usb_register_read_async_cb, rd);
+	if (usb_submit_urb(urb, GFP_ATOMIC) < 0)
+		kfree(rd);
+	usb_free_urb(urb);
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_register_read_async);
+
 /*
  * TX data handlers.
  */
@@ -212,6 +262,9 @@
 	if (!test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
 		return;
 
+	if (rt2x00dev->ops->lib->tx_dma_done)
+		rt2x00dev->ops->lib->tx_dma_done(entry);
+
 	/*
 	 * Report the frame as DMA done
 	 */
@@ -227,10 +280,12 @@
 	 * Schedule the delayed work for reading the TX status
 	 * from the device.
 	 */
-	queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work);
+	if (!test_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags) ||
+	    !kfifo_is_empty(&rt2x00dev->txstatus_fifo))
+		queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work);
 }
 
-static void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
+static bool rt2x00usb_kick_tx_entry(struct queue_entry *entry, void* data)
 {
 	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
 	struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
@@ -240,7 +295,7 @@
 
 	if (!test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags) ||
 	    test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
-		return;
+		return true;
 
 	/*
 	 * USB devices cannot blindly pass the skb->len as the
@@ -261,6 +316,8 @@
 		set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
 		rt2x00lib_dmadone(entry);
 	}
+
+	return false;
 }
 
 /*
@@ -323,7 +380,7 @@
 	queue_work(rt2x00dev->workqueue, &rt2x00dev->rxdone_work);
 }
 
-static void rt2x00usb_kick_rx_entry(struct queue_entry *entry)
+static bool rt2x00usb_kick_rx_entry(struct queue_entry *entry, void* data)
 {
 	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
 	struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
@@ -332,7 +389,7 @@
 
 	if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
 	    test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
-		return;
+		return true;
 
 	rt2x00lib_dmastart(entry);
 
@@ -348,6 +405,8 @@
 		set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
 		rt2x00lib_dmadone(entry);
 	}
+
+	return false;
 }
 
 void rt2x00usb_kick_queue(struct data_queue *queue)
@@ -358,12 +417,18 @@
 	case QID_AC_BE:
 	case QID_AC_BK:
 		if (!rt2x00queue_empty(queue))
-			rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
+			rt2x00queue_for_each_entry(queue,
+						   Q_INDEX_DONE,
+						   Q_INDEX,
+						   NULL,
 						   rt2x00usb_kick_tx_entry);
 		break;
 	case QID_RX:
 		if (!rt2x00queue_full(queue))
-			rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
+			rt2x00queue_for_each_entry(queue,
+						   Q_INDEX_DONE,
+						   Q_INDEX,
+						   NULL,
 						   rt2x00usb_kick_rx_entry);
 		break;
 	default:
@@ -372,14 +437,14 @@
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_kick_queue);
 
-static void rt2x00usb_flush_entry(struct queue_entry *entry)
+static bool rt2x00usb_flush_entry(struct queue_entry *entry, void* data)
 {
 	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
 	struct queue_entry_priv_usb *entry_priv = entry->priv_data;
 	struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data;
 
 	if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
-		return;
+		return true;
 
 	usb_kill_urb(entry_priv->urb);
 
@@ -387,17 +452,20 @@
 	 * Kill guardian urb (if required by driver).
 	 */
 	if ((entry->queue->qid == QID_BEACON) &&
-	    (test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags)))
+	    (test_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags)))
 		usb_kill_urb(bcn_priv->guardian_urb);
+
+	return false;
 }
 
-void rt2x00usb_flush_queue(struct data_queue *queue)
+void rt2x00usb_flush_queue(struct data_queue *queue, bool drop)
 {
 	struct work_struct *completion;
 	unsigned int i;
 
-	rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
-				   rt2x00usb_flush_entry);
+	if (drop)
+		rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, NULL,
+					   rt2x00usb_flush_entry);
 
 	/*
 	 * Obtain the queue completion handler
@@ -416,7 +484,7 @@
 		return;
 	}
 
-	for (i = 0; i < 20; i++) {
+	for (i = 0; i < 10; i++) {
 		/*
 		 * Check if the driver is already done, otherwise we
 		 * have to sleep a little while to give the driver/hw
@@ -456,15 +524,31 @@
 	queue_work(queue->rt2x00dev->workqueue, &queue->rt2x00dev->txdone_work);
 }
 
+static int rt2x00usb_status_timeout(struct data_queue *queue)
+{
+	struct queue_entry *entry;
+
+	entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
+	return rt2x00queue_status_timeout(entry);
+}
+
+static int rt2x00usb_dma_timeout(struct data_queue *queue)
+{
+	struct queue_entry *entry;
+
+	entry = rt2x00queue_get_entry(queue, Q_INDEX_DMA_DONE);
+	return rt2x00queue_dma_timeout(entry);
+}
+
 void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev)
 {
 	struct data_queue *queue;
 
 	tx_queue_for_each(rt2x00dev, queue) {
 		if (!rt2x00queue_empty(queue)) {
-			if (rt2x00queue_dma_timeout(queue))
+			if (rt2x00usb_dma_timeout(queue))
 				rt2x00usb_watchdog_tx_dma(queue);
-			if (rt2x00queue_status_timeout(queue))
+			if (rt2x00usb_status_timeout(queue))
 				rt2x00usb_watchdog_tx_status(queue);
 		}
 	}
@@ -489,7 +573,7 @@
 	entry->flags = 0;
 
 	if (entry->queue->qid == QID_RX)
-		rt2x00usb_kick_rx_entry(entry);
+		rt2x00usb_kick_rx_entry(entry, NULL);
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry);
 
@@ -583,7 +667,7 @@
 	 * then we are done.
 	 */
 	if (queue->qid != QID_BEACON ||
-	    !test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags))
+	    !test_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags))
 		return 0;
 
 	for (i = 0; i < queue->limit; i++) {
@@ -618,7 +702,7 @@
 	 * then we are done.
 	 */
 	if (queue->qid != QID_BEACON ||
-	    !test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags))
+	    !test_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags))
 		return;
 
 	for (i = 0; i < queue->limit; i++) {
@@ -707,10 +791,9 @@
 }
 
 int rt2x00usb_probe(struct usb_interface *usb_intf,
-		    const struct usb_device_id *id)
+		    const struct rt2x00_ops *ops)
 {
 	struct usb_device *usb_dev = interface_to_usbdev(usb_intf);
-	struct rt2x00_ops *ops = (struct rt2x00_ops *)id->driver_info;
 	struct ieee80211_hw *hw;
 	struct rt2x00_dev *rt2x00dev;
 	int retval;
@@ -735,6 +818,7 @@
 
 	INIT_WORK(&rt2x00dev->rxdone_work, rt2x00usb_work_rxdone);
 	INIT_WORK(&rt2x00dev->txdone_work, rt2x00usb_work_txdone);
+	init_timer(&rt2x00dev->txstatus_timer);
 
 	retval = rt2x00usb_alloc_reg(rt2x00dev);
 	if (retval)
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h
index e11c759..64be34f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.h
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.h
@@ -35,12 +35,6 @@
 })
 
 /*
- * This variable should be used with the
- * usb_driver structure initialization.
- */
-#define USB_DEVICE_DATA(__ops)	.driver_info = (kernel_ulong_t)(__ops)
-
-/*
  * For USB vendor requests we need to pass a timeout
  * time in ms, for this we use the REGISTER_TIMEOUT,
  * however when loading firmware a higher value is
@@ -345,6 +339,21 @@
 			   const struct rt2x00_field32 field,
 			   u32 *reg);
 
+/**
+ * rt2x00usb_register_read_async - Asynchronously read 32bit register word
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @callback: Functon to call when read completes.
+ *
+ * Submit a control URB to read a 32bit register. This safe to
+ * be called from atomic context.  The callback will be called
+ * when the URB completes. Otherwise the function is similar
+ * to rt2x00usb_register_read().
+ */
+void rt2x00usb_register_read_async(struct rt2x00_dev *rt2x00dev,
+				   const unsigned int offset,
+				   void (*callback)(struct rt2x00_dev*,int,u32));
+
 /*
  * Radio handlers
  */
@@ -389,11 +398,13 @@
 /**
  * rt2x00usb_flush_queue - Flush data queue
  * @queue: Data queue to stop
+ * @drop: True to drop all pending frames.
  *
- * This will walk through all entries of the queue and kill all
- * URB's which were send to the device.
+ * This will walk through all entries of the queue and will optionally
+ * kill all URB's which were send to the device, or at least wait until
+ * they have been returned from the device..
  */
-void rt2x00usb_flush_queue(struct data_queue *queue);
+void rt2x00usb_flush_queue(struct data_queue *queue, bool drop);
 
 /**
  * rt2x00usb_watchdog - Watchdog for USB communication
@@ -416,7 +427,7 @@
  * USB driver handlers.
  */
 int rt2x00usb_probe(struct usb_interface *usb_intf,
-		    const struct usb_device_id *id);
+		    const struct rt2x00_ops *ops);
 void rt2x00usb_disconnect(struct usb_interface *usb_intf);
 #ifdef CONFIG_PM
 int rt2x00usb_suspend(struct usb_interface *usb_intf, pm_message_t state);
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 8ee1514..9d35ec1 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -683,7 +683,7 @@
 
 	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, rt2x00_rf(rt2x00dev, RF2529));
 	rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END,
-			  !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags));
+			  !test_bit(CAPABILITY_FRAME_TYPE, &rt2x00dev->cap_flags));
 
 	/*
 	 * Configure the RX antenna.
@@ -811,10 +811,10 @@
 
 	if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) {
 		sel = antenna_sel_a;
-		lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
+		lna = test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags);
 	} else {
 		sel = antenna_sel_bg;
-		lna = test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
+		lna = test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags);
 	}
 
 	for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++)
@@ -834,7 +834,7 @@
 	else if (rt2x00_rf(rt2x00dev, RF2527))
 		rt61pci_config_antenna_2x(rt2x00dev, ant);
 	else if (rt2x00_rf(rt2x00dev, RF2529)) {
-		if (test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags))
+		if (test_bit(CAPABILITY_DOUBLE_ANTENNA, &rt2x00dev->cap_flags))
 			rt61pci_config_antenna_2x(rt2x00dev, ant);
 		else
 			rt61pci_config_antenna_2529(rt2x00dev, ant);
@@ -848,13 +848,13 @@
 	short lna_gain = 0;
 
 	if (libconf->conf->channel->band == IEEE80211_BAND_2GHZ) {
-		if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
+		if (test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags))
 			lna_gain += 14;
 
 		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
 		lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
 	} else {
-		if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags))
+		if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags))
 			lna_gain += 14;
 
 		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
@@ -1050,14 +1050,14 @@
 	if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) {
 		low_bound = 0x28;
 		up_bound = 0x48;
-		if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) {
+		if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags)) {
 			low_bound += 0x10;
 			up_bound += 0x10;
 		}
 	} else {
 		low_bound = 0x20;
 		up_bound = 0x40;
-		if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) {
+		if (test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags)) {
 			low_bound += 0x10;
 			up_bound += 0x10;
 		}
@@ -2260,8 +2260,8 @@
 	rt61pci_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS);
 }
 
-static void rt61pci_enable_interrupt(struct rt2x00_dev *rt2x00dev,
-				     struct rt2x00_field32 irq_field)
+static inline void rt61pci_enable_interrupt(struct rt2x00_dev *rt2x00dev,
+					    struct rt2x00_field32 irq_field)
 {
 	u32 reg;
 
@@ -2537,7 +2537,7 @@
 	 * Determine number of antennas.
 	 */
 	if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_NUM) == 2)
-		__set_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags);
+		__set_bit(CAPABILITY_DOUBLE_ANTENNA, &rt2x00dev->cap_flags);
 
 	/*
 	 * Identify default antenna configuration.
@@ -2551,20 +2551,20 @@
 	 * Read the Frame type.
 	 */
 	if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_FRAME_TYPE))
-		__set_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags);
+		__set_bit(CAPABILITY_FRAME_TYPE, &rt2x00dev->cap_flags);
 
 	/*
 	 * Detect if this device has a hardware controlled radio.
 	 */
 	if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
-		__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
+		__set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags);
 
 	/*
 	 * Read frequency offset and RF programming sequence.
 	 */
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom);
 	if (rt2x00_get_field16(eeprom, EEPROM_FREQ_SEQ))
-		__set_bit(CONFIG_RF_SEQUENCE, &rt2x00dev->flags);
+		__set_bit(CAPABILITY_RF_SEQUENCE, &rt2x00dev->cap_flags);
 
 	rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET);
 
@@ -2574,9 +2574,9 @@
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
 
 	if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_A))
-		__set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
+		__set_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags);
 	if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG))
-		__set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
+		__set_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags);
 
 	/*
 	 * When working with a RF2529 chip without double antenna,
@@ -2584,7 +2584,7 @@
 	 * eeprom word.
 	 */
 	if (rt2x00_rf(rt2x00dev, RF2529) &&
-	    !test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags)) {
+	    !test_bit(CAPABILITY_DOUBLE_ANTENNA, &rt2x00dev->cap_flags)) {
 		rt2x00dev->default_ant.rx =
 		    ANTENNA_A + rt2x00_get_field16(eeprom, EEPROM_NIC_RX_FIXED);
 		rt2x00dev->default_ant.tx =
@@ -2799,7 +2799,7 @@
 	spec->supported_bands = SUPPORT_BAND_2GHZ;
 	spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
 
-	if (!test_bit(CONFIG_RF_SEQUENCE, &rt2x00dev->flags)) {
+	if (!test_bit(CAPABILITY_RF_SEQUENCE, &rt2x00dev->cap_flags)) {
 		spec->num_channels = 14;
 		spec->channels = rf_vals_noseq;
 	} else {
@@ -2869,16 +2869,16 @@
 	 * This device has multiple filters for control frames,
 	 * but has no a separate filter for PS Poll frames.
 	 */
-	__set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags);
+	__set_bit(CAPABILITY_CONTROL_FILTERS, &rt2x00dev->cap_flags);
 
 	/*
 	 * This device requires firmware and DMA mapped skbs.
 	 */
-	__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
-	__set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
+	__set_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags);
+	__set_bit(REQUIRE_DMA, &rt2x00dev->cap_flags);
 	if (!modparam_nohwcrypt)
-		__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
-	__set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
+		__set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags);
+	__set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags);
 
 	/*
 	 * Set the rssi offset.
@@ -2979,6 +2979,9 @@
 	.get_tsf		= rt61pci_get_tsf,
 	.rfkill_poll		= rt2x00mac_rfkill_poll,
 	.flush			= rt2x00mac_flush,
+	.set_antenna		= rt2x00mac_set_antenna,
+	.get_antenna		= rt2x00mac_get_antenna,
+	.get_ringparam		= rt2x00mac_get_ringparam,
 };
 
 static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
@@ -3003,6 +3006,7 @@
 	.start_queue		= rt61pci_start_queue,
 	.kick_queue		= rt61pci_kick_queue,
 	.stop_queue		= rt61pci_stop_queue,
+	.flush_queue		= rt2x00pci_flush_queue,
 	.write_tx_desc		= rt61pci_write_tx_desc,
 	.write_beacon		= rt61pci_write_beacon,
 	.clear_beacon		= rt61pci_clear_beacon,
@@ -3060,11 +3064,11 @@
  */
 static DEFINE_PCI_DEVICE_TABLE(rt61pci_device_table) = {
 	/* RT2561s */
-	{ PCI_DEVICE(0x1814, 0x0301), PCI_DEVICE_DATA(&rt61pci_ops) },
+	{ PCI_DEVICE(0x1814, 0x0301) },
 	/* RT2561 v2 */
-	{ PCI_DEVICE(0x1814, 0x0302), PCI_DEVICE_DATA(&rt61pci_ops) },
+	{ PCI_DEVICE(0x1814, 0x0302) },
 	/* RT2661 */
-	{ PCI_DEVICE(0x1814, 0x0401), PCI_DEVICE_DATA(&rt61pci_ops) },
+	{ PCI_DEVICE(0x1814, 0x0401) },
 	{ 0, }
 };
 
@@ -3079,10 +3083,16 @@
 MODULE_FIRMWARE(FIRMWARE_RT2661);
 MODULE_LICENSE("GPL");
 
+static int rt61pci_probe(struct pci_dev *pci_dev,
+			 const struct pci_device_id *id)
+{
+	return rt2x00pci_probe(pci_dev, &rt61pci_ops);
+}
+
 static struct pci_driver rt61pci_driver = {
 	.name		= KBUILD_MODNAME,
 	.id_table	= rt61pci_device_table,
-	.probe		= rt2x00pci_probe,
+	.probe		= rt61pci_probe,
 	.remove		= __devexit_p(rt2x00pci_remove),
 	.suspend	= rt2x00pci_suspend,
 	.resume		= rt2x00pci_resume,
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 6593059..a6ce7d6 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -595,7 +595,7 @@
 	switch (ant->rx) {
 	case ANTENNA_HW_DIVERSITY:
 		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 2);
-		temp = !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags)
+		temp = !test_bit(CAPABILITY_FRAME_TYPE, &rt2x00dev->cap_flags)
 		       && (rt2x00dev->curr_band != IEEE80211_BAND_5GHZ);
 		rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, temp);
 		break;
@@ -636,7 +636,7 @@
 
 	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, 0);
 	rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END,
-			  !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags));
+			  !test_bit(CAPABILITY_FRAME_TYPE, &rt2x00dev->cap_flags));
 
 	/*
 	 * Configure the RX antenna.
@@ -709,10 +709,10 @@
 
 	if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) {
 		sel = antenna_sel_a;
-		lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
+		lna = test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags);
 	} else {
 		sel = antenna_sel_bg;
-		lna = test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
+		lna = test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags);
 	}
 
 	for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++)
@@ -740,7 +740,7 @@
 	short lna_gain = 0;
 
 	if (libconf->conf->channel->band == IEEE80211_BAND_2GHZ) {
-		if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
+		if (test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags))
 			lna_gain += 14;
 
 		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
@@ -930,7 +930,7 @@
 		low_bound = 0x28;
 		up_bound = 0x48;
 
-		if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) {
+		if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags)) {
 			low_bound += 0x10;
 			up_bound += 0x10;
 		}
@@ -946,7 +946,7 @@
 			up_bound = 0x1c;
 		}
 
-		if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) {
+		if (test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags)) {
 			low_bound += 0x14;
 			up_bound += 0x10;
 		}
@@ -1661,7 +1661,7 @@
 	}
 
 	if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) {
-		if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) {
+		if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags)) {
 			if (lna == 3 || lna == 2)
 				offset += 10;
 		} else {
@@ -1899,13 +1899,13 @@
 	 * Read the Frame type.
 	 */
 	if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_FRAME_TYPE))
-		__set_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags);
+		__set_bit(CAPABILITY_FRAME_TYPE, &rt2x00dev->cap_flags);
 
 	/*
 	 * Detect if this device has an hardware controlled radio.
 	 */
 	if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
-		__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
+		__set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags);
 
 	/*
 	 * Read frequency offset.
@@ -1919,8 +1919,8 @@
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
 
 	if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA)) {
-		__set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
-		__set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
+		__set_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags);
+		__set_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags);
 	}
 
 	/*
@@ -2200,15 +2200,15 @@
 	 * This device has multiple filters for control frames,
 	 * but has no a separate filter for PS Poll frames.
 	 */
-	__set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags);
+	__set_bit(CAPABILITY_CONTROL_FILTERS, &rt2x00dev->cap_flags);
 
 	/*
 	 * This device requires firmware.
 	 */
-	__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
+	__set_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags);
 	if (!modparam_nohwcrypt)
-		__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
-	__set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
+		__set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags);
+	__set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags);
 
 	/*
 	 * Set the rssi offset.
@@ -2310,6 +2310,9 @@
 	.get_tsf		= rt73usb_get_tsf,
 	.rfkill_poll		= rt2x00mac_rfkill_poll,
 	.flush			= rt2x00mac_flush,
+	.set_antenna		= rt2x00mac_set_antenna,
+	.get_antenna		= rt2x00mac_get_antenna,
+	.get_ringparam		= rt2x00mac_get_ringparam,
 };
 
 static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
@@ -2388,113 +2391,113 @@
  */
 static struct usb_device_id rt73usb_device_table[] = {
 	/* AboCom */
-	{ USB_DEVICE(0x07b8, 0xb21b), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x07b8, 0xb21c), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x07b8, 0xb21d), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x07b8, 0xb21e), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x07b8, 0xb21f), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x07b8, 0xb21b) },
+	{ USB_DEVICE(0x07b8, 0xb21c) },
+	{ USB_DEVICE(0x07b8, 0xb21d) },
+	{ USB_DEVICE(0x07b8, 0xb21e) },
+	{ USB_DEVICE(0x07b8, 0xb21f) },
 	/* AL */
-	{ USB_DEVICE(0x14b2, 0x3c10), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x14b2, 0x3c10) },
 	/* Amigo */
-	{ USB_DEVICE(0x148f, 0x9021), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x0eb0, 0x9021), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x148f, 0x9021) },
+	{ USB_DEVICE(0x0eb0, 0x9021) },
 	/* AMIT  */
-	{ USB_DEVICE(0x18c5, 0x0002), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x18c5, 0x0002) },
 	/* Askey */
-	{ USB_DEVICE(0x1690, 0x0722), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x1690, 0x0722) },
 	/* ASUS */
-	{ USB_DEVICE(0x0b05, 0x1723), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x0b05, 0x1724), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x0b05, 0x1723) },
+	{ USB_DEVICE(0x0b05, 0x1724) },
 	/* Belkin */
-	{ 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) },
+	{ USB_DEVICE(0x050d, 0x705a) },
+	{ USB_DEVICE(0x050d, 0x905b) },
+	{ USB_DEVICE(0x050d, 0x905c) },
 	/* Billionton */
-	{ USB_DEVICE(0x1631, 0xc019), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x08dd, 0x0120), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x1631, 0xc019) },
+	{ USB_DEVICE(0x08dd, 0x0120) },
 	/* Buffalo */
-	{ USB_DEVICE(0x0411, 0x00d8), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x0411, 0x00d9), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x0411, 0x00f4), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x0411, 0x0116), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x0411, 0x0119), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x0411, 0x0137), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x0411, 0x00d8) },
+	{ USB_DEVICE(0x0411, 0x00d9) },
+	{ USB_DEVICE(0x0411, 0x00f4) },
+	{ USB_DEVICE(0x0411, 0x0116) },
+	{ USB_DEVICE(0x0411, 0x0119) },
+	{ USB_DEVICE(0x0411, 0x0137) },
 	/* CEIVA */
-	{ USB_DEVICE(0x178d, 0x02be), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x178d, 0x02be) },
 	/* CNet */
-	{ USB_DEVICE(0x1371, 0x9022), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x1371, 0x9032), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x1371, 0x9022) },
+	{ USB_DEVICE(0x1371, 0x9032) },
 	/* Conceptronic */
-	{ USB_DEVICE(0x14b2, 0x3c22), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x14b2, 0x3c22) },
 	/* Corega */
-	{ USB_DEVICE(0x07aa, 0x002e), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x07aa, 0x002e) },
 	/* D-Link */
-	{ USB_DEVICE(0x07d1, 0x3c03), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x07d1, 0x3c04), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x07d1, 0x3c06), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x07d1, 0x3c07), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x07d1, 0x3c03) },
+	{ USB_DEVICE(0x07d1, 0x3c04) },
+	{ USB_DEVICE(0x07d1, 0x3c06) },
+	{ USB_DEVICE(0x07d1, 0x3c07) },
 	/* Edimax */
-	{ USB_DEVICE(0x7392, 0x7318), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x7392, 0x7618), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x7392, 0x7318) },
+	{ USB_DEVICE(0x7392, 0x7618) },
 	/* EnGenius */
-	{ USB_DEVICE(0x1740, 0x3701), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x1740, 0x3701) },
 	/* Gemtek */
-	{ USB_DEVICE(0x15a9, 0x0004), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x15a9, 0x0004) },
 	/* Gigabyte */
-	{ USB_DEVICE(0x1044, 0x8008), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x1044, 0x800a), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x1044, 0x8008) },
+	{ USB_DEVICE(0x1044, 0x800a) },
 	/* Huawei-3Com */
-	{ USB_DEVICE(0x1472, 0x0009), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x1472, 0x0009) },
 	/* Hercules */
-	{ USB_DEVICE(0x06f8, 0xe002), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x06f8, 0xe010), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x06f8, 0xe020), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x06f8, 0xe002) },
+	{ USB_DEVICE(0x06f8, 0xe010) },
+	{ USB_DEVICE(0x06f8, 0xe020) },
 	/* Linksys */
-	{ USB_DEVICE(0x13b1, 0x0020), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x13b1, 0x0023), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x13b1, 0x0028), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x13b1, 0x0020) },
+	{ USB_DEVICE(0x13b1, 0x0023) },
+	{ USB_DEVICE(0x13b1, 0x0028) },
 	/* MSI */
-	{ USB_DEVICE(0x0db0, 0x4600), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x0db0, 0x6877), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x0db0, 0x6874), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x0db0, 0xa861), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x0db0, 0xa874), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x0db0, 0x4600) },
+	{ USB_DEVICE(0x0db0, 0x6877) },
+	{ USB_DEVICE(0x0db0, 0x6874) },
+	{ USB_DEVICE(0x0db0, 0xa861) },
+	{ USB_DEVICE(0x0db0, 0xa874) },
 	/* Ovislink */
-	{ USB_DEVICE(0x1b75, 0x7318), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x1b75, 0x7318) },
 	/* Ralink */
-	{ USB_DEVICE(0x04bb, 0x093d), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x148f, 0x2671), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x0812, 0x3101), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x04bb, 0x093d) },
+	{ USB_DEVICE(0x148f, 0x2573) },
+	{ USB_DEVICE(0x148f, 0x2671) },
+	{ USB_DEVICE(0x0812, 0x3101) },
 	/* Qcom */
-	{ USB_DEVICE(0x18e8, 0x6196), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x18e8, 0x6229), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x18e8, 0x6238), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x18e8, 0x6196) },
+	{ USB_DEVICE(0x18e8, 0x6229) },
+	{ USB_DEVICE(0x18e8, 0x6238) },
 	/* Samsung */
-	{ USB_DEVICE(0x04e8, 0x4471), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x04e8, 0x4471) },
 	/* Senao */
-	{ USB_DEVICE(0x1740, 0x7100), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x1740, 0x7100) },
 	/* Sitecom */
-	{ USB_DEVICE(0x0df6, 0x0024), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x0df6, 0x0027), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x0df6, 0x002f), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x0df6, 0x90ac), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x0df6, 0x9712), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x0df6, 0x0024) },
+	{ USB_DEVICE(0x0df6, 0x0027) },
+	{ USB_DEVICE(0x0df6, 0x002f) },
+	{ USB_DEVICE(0x0df6, 0x90ac) },
+	{ USB_DEVICE(0x0df6, 0x9712) },
 	/* Surecom */
-	{ USB_DEVICE(0x0769, 0x31f3), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x0769, 0x31f3) },
 	/* Tilgin */
-	{ USB_DEVICE(0x6933, 0x5001), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x6933, 0x5001) },
 	/* Philips */
-	{ USB_DEVICE(0x0471, 0x200a), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x0471, 0x200a) },
 	/* Planex */
-	{ USB_DEVICE(0x2019, 0xab01), USB_DEVICE_DATA(&rt73usb_ops) },
-	{ USB_DEVICE(0x2019, 0xab50), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x2019, 0xab01) },
+	{ USB_DEVICE(0x2019, 0xab50) },
 	/* WideTell */
-	{ USB_DEVICE(0x7167, 0x3840), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x7167, 0x3840) },
 	/* Zcom */
-	{ USB_DEVICE(0x0cde, 0x001c), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x0cde, 0x001c) },
 	/* ZyXEL */
-	{ USB_DEVICE(0x0586, 0x3415), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x0586, 0x3415) },
 	{ 0, }
 };
 
@@ -2506,10 +2509,16 @@
 MODULE_FIRMWARE(FIRMWARE_RT2571);
 MODULE_LICENSE("GPL");
 
+static int rt73usb_probe(struct usb_interface *usb_intf,
+			 const struct usb_device_id *id)
+{
+	return rt2x00usb_probe(usb_intf, &rt73usb_ops);
+}
+
 static struct usb_driver rt73usb_driver = {
 	.name		= KBUILD_MODNAME,
 	.id_table	= rt73usb_device_table,
-	.probe		= rt2x00usb_probe,
+	.probe		= rt73usb_probe,
 	.disconnect	= rt2x00usb_disconnect,
 	.suspend	= rt2x00usb_suspend,
 	.resume		= rt2x00usb_resume,
diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c
index 4803f54..b259f80 100644
--- a/drivers/net/wireless/rtlwifi/base.c
+++ b/drivers/net/wireless/rtlwifi/base.c
@@ -251,14 +251,16 @@
 	bool blocked;
 	u8 valid = 0;
 
+	/*set init state to on */
+	rtlpriv->rfkill.rfkill_state = 1;
+	wiphy_rfkill_set_hw_state(hw->wiphy, 0);
+
 	radio_state = rtlpriv->cfg->ops->radio_onoff_checking(hw, &valid);
 
-	/*set init state to that of switch */
-	rtlpriv->rfkill.rfkill_state = radio_state;
-	printk(KERN_INFO "rtlwifi: wireless switch is %s\n",
-	       rtlpriv->rfkill.rfkill_state ? "on" : "off");
-
 	if (valid) {
+		printk(KERN_INFO "rtlwifi: wireless switch is %s\n",
+				rtlpriv->rfkill.rfkill_state ? "on" : "off");
+
 		rtlpriv->rfkill.rfkill_state = radio_state;
 
 		blocked = (rtlpriv->rfkill.rfkill_state == 1) ? 0 : 1;
diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c
index fbde52d..c3dd4cc 100644
--- a/drivers/net/wireless/rtlwifi/pci.c
+++ b/drivers/net/wireless/rtlwifi/pci.c
@@ -1785,7 +1785,8 @@
 
 	rtl_pci_deinit(hw);
 	rtl_deinit_core(hw);
-	rtlpriv->cfg->ops->deinit_sw_leds(hw);
+	if (rtlpriv->cfg->ops->deinit_sw_leds)
+		rtlpriv->cfg->ops->deinit_sw_leds(hw);
 	_rtl_pci_io_handler_release(hw);
 	rtlpriv->cfg->ops->deinit_sw_vars(hw);
 
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
index bb02327..c228b9e 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
@@ -634,7 +634,7 @@
 	u8 thermalvalue, delta, delta_lck, delta_iqk;
 	long ele_a, ele_d, temp_cck, val_x, value32;
 	long val_y, ele_c;
-	u8 ofdm_index[2], cck_index, ofdm_index_old[2], cck_index_old;
+	u8 ofdm_index[2], cck_index = 0, ofdm_index_old[2], cck_index_old = 0;
 	int i;
 	bool is2t = IS_92C_SERIAL(rtlhal->version);
 	u8 txpwr_level[2] = {0, 0};
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
index f107660..bc9d241 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
@@ -293,7 +293,7 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 	u8 boxnum;
-	u16 box_reg, box_extreg;
+	u16 box_reg = 0, box_extreg = 0;
 	u8 u1b_tmp;
 	bool isfw_read = false;
 	bool bwrite_sucess = false;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/led.c b/drivers/net/wireless/rtlwifi/rtl8192ce/led.c
index 7b1da8d..d21b934 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/led.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/led.c
@@ -32,6 +32,14 @@
 #include "reg.h"
 #include "led.h"
 
+static void _rtl92ce_init_led(struct ieee80211_hw *hw,
+			      struct rtl_led *pled, enum rtl_led_pin ledpin)
+{
+	pled->hw = hw;
+	pled->ledpin = ledpin;
+	pled->ledon = false;
+}
+
 void rtl92ce_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled)
 {
 	u8 ledcfg;
@@ -97,10 +105,10 @@
 
 void rtl92ce_init_sw_leds(struct ieee80211_hw *hw)
 {
-}
+	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
 
-void rtl92ce_deinit_sw_leds(struct ieee80211_hw *hw)
-{
+	_rtl92ce_init_led(hw, &(pcipriv->ledctl.sw_led0), LED_PIN_LED0);
+	_rtl92ce_init_led(hw, &(pcipriv->ledctl.sw_led1), LED_PIN_LED1);
 }
 
 void _rtl92ce_sw_led_control(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/led.h b/drivers/net/wireless/rtlwifi/rtl8192ce/led.h
index 10da301..94332b3 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/led.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/led.h
@@ -31,7 +31,6 @@
 #define __RTL92CE_LED_H__
 
 void rtl92ce_init_sw_leds(struct ieee80211_hw *hw);
-void rtl92ce_deinit_sw_leds(struct ieee80211_hw *hw);
 void rtl92ce_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled);
 void rtl92ce_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled);
 void rtl92ce_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c
index 669b116..e301b12 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c
@@ -202,7 +202,7 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
-	u8 i, chnlgroup, pwr_diff_limit[4];
+	u8 i, chnlgroup = 0, pwr_diff_limit[4];
 	u32 writeVal, customer_limit, rf;
 
 	for (rf = 0; rf < 2; rf++) {
@@ -447,7 +447,7 @@
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
-	u32 u4_regvalue;
+	u32 u4_regvalue = 0;
 	u8 rfpath;
 	bool rtstatus;
 	struct bb_reg_def *pphyreg;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
index b1cc4d4..f4e2f3d 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
@@ -131,7 +131,6 @@
 	.enable_hw_sec = rtl92ce_enable_hw_security_config,
 	.set_key = rtl92ce_set_key,
 	.init_sw_leds = rtl92ce_init_sw_leds,
-	.deinit_sw_leds = rtl92ce_deinit_sw_leds,
 	.get_bbreg = rtl92c_phy_query_bb_reg,
 	.set_bbreg = rtl92c_phy_set_bb_reg,
 	.get_rfreg = rtl92ce_phy_query_rf_reg,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
index 9444e76..e43be25 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
@@ -921,7 +921,7 @@
 					       u8 out_ep_num,
 					       u8 queue_sel)
 {
-	u8	hq_sele;
+	u8 hq_sele = 0;
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
 	switch (out_ep_num) {
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 1832c27..216b1d8 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -410,6 +410,16 @@
  *	notification. This event is used to indicate that an unprotected
  *	disassociation frame was dropped when MFP is in use.
  *
+ * @NL80211_CMD_NEW_PEER_CANDIDATE: Notification on the reception of a
+ *      beacon or probe response from a compatible mesh peer.  This is only
+ *      sent while no station information (sta_info) exists for the new peer
+ *      candidate and when @NL80211_MESH_SETUP_USERSPACE_AUTH is set.  On
+ *      reception of this notification, userspace may decide to create a new
+ *      station (@NL80211_CMD_NEW_STATION).  To stop this notification from
+ *      reoccurring, the userspace authentication daemon may want to create the
+ *      new station with the AUTHENTICATED flag unset and maybe change it later
+ *      depending on the authentication result.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -522,6 +532,8 @@
 	NL80211_CMD_UNPROT_DEAUTHENTICATE,
 	NL80211_CMD_UNPROT_DISASSOCIATE,
 
+	NL80211_CMD_NEW_PEER_CANDIDATE,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
@@ -545,6 +557,7 @@
 /* source-level API compatibility */
 #define NL80211_CMD_GET_MESH_PARAMS NL80211_CMD_GET_MESH_CONFIG
 #define NL80211_CMD_SET_MESH_PARAMS NL80211_CMD_SET_MESH_CONFIG
+#define NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE NL80211_MESH_SETUP_IE
 
 /**
  * enum nl80211_attrs - nl80211 netlink attributes
@@ -886,6 +899,9 @@
  *	changed once the mesh is active.
  * @NL80211_ATTR_MESH_CONFIG: Mesh configuration parameters, a nested attribute
  *	containing attributes from &enum nl80211_meshconf_params.
+ * @NL80211_ATTR_SUPPORT_MESH_AUTH: Currently, this means the underlying driver
+ *	allows auth frames in a mesh to be passed to userspace for processing via
+ *	the @NL80211_MESH_SETUP_USERSPACE_AUTH flag.
  *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -1074,6 +1090,8 @@
 	NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX,
 	NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
 
+	NL80211_ATTR_SUPPORT_MESH_AUTH,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -1168,6 +1186,7 @@
  *	with short barker preamble
  * @NL80211_STA_FLAG_WME: station is WME/QoS capable
  * @NL80211_STA_FLAG_MFP: station uses management frame protection
+ * @NL80211_STA_FLAG_AUTHENTICATED: station is authenticated
  * @NL80211_STA_FLAG_MAX: highest station flag number currently defined
  * @__NL80211_STA_FLAG_AFTER_LAST: internal use
  */
@@ -1177,6 +1196,7 @@
 	NL80211_STA_FLAG_SHORT_PREAMBLE,
 	NL80211_STA_FLAG_WME,
 	NL80211_STA_FLAG_MFP,
+	NL80211_STA_FLAG_AUTHENTICATED,
 
 	/* keep last */
 	__NL80211_STA_FLAG_AFTER_LAST,
@@ -1277,6 +1297,7 @@
  *	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_CONNECTED_TIME: time since the station is last connected
  * @__NL80211_STA_INFO_AFTER_LAST: internal
  * @NL80211_STA_INFO_MAX: highest possible station info attribute
  */
@@ -1297,6 +1318,7 @@
 	NL80211_STA_INFO_SIGNAL_AVG,
 	NL80211_STA_INFO_RX_BITRATE,
 	NL80211_STA_INFO_BSS_PARAM,
+	NL80211_STA_INFO_CONNECTED_TIME,
 
 	/* keep last */
 	__NL80211_STA_INFO_AFTER_LAST,
@@ -1719,9 +1741,12 @@
  * vendor specific path metric or disable it to use the default Airtime
  * metric.
  *
- * @NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE: A vendor specific information
- * element that vendors will use to identify the path selection methods and
- * metrics in use.
+ * @NL80211_MESH_SETUP_IE: Information elements for this mesh, for instance, a
+ * robust security network ie, or a vendor specific information element that
+ * vendors will use to identify the path selection methods and metrics in use.
+ *
+ * @NL80211_MESH_SETUP_USERSPACE_AUTH: Enable this option if an authentication
+ * daemon will be authenticating mesh candidates.
  *
  * @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number
  * @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use
@@ -1730,7 +1755,8 @@
 	__NL80211_MESH_SETUP_INVALID,
 	NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL,
 	NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC,
-	NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE,
+	NL80211_MESH_SETUP_IE,
+	NL80211_MESH_SETUP_USERSPACE_AUTH,
 
 	/* keep last */
 	__NL80211_MESH_SETUP_ATTR_AFTER_LAST,
diff --git a/include/linux/rfkill-regulator.h b/include/linux/rfkill-regulator.h
new file mode 100644
index 0000000..aca36bc
--- /dev/null
+++ b/include/linux/rfkill-regulator.h
@@ -0,0 +1,48 @@
+/*
+ * rfkill-regulator.c - Regulator consumer driver for rfkill
+ *
+ * Copyright (C) 2009  Guiming Zhuo <gmzhuo@gmail.com>
+ * Copyright (C) 2011  Antonio Ospite <ospite@studenti.unina.it>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __LINUX_RFKILL_REGULATOR_H
+#define __LINUX_RFKILL_REGULATOR_H
+
+/*
+ * Use "vrfkill" as supply id when declaring the regulator consumer:
+ *
+ * static struct regulator_consumer_supply pcap_regulator_V6_consumers [] = {
+ * 	{ .dev_name = "rfkill-regulator.0", .supply = "vrfkill" },
+ * };
+ *
+ * If you have several regulator driven rfkill, you can append a numerical id to
+ * .dev_name as done above, and use the same id when declaring the platform
+ * device:
+ *
+ * static struct rfkill_regulator_platform_data ezx_rfkill_bt_data = {
+ * 	.name  = "ezx-bluetooth",
+ * 	.type  = RFKILL_TYPE_BLUETOOTH,
+ * };
+ *
+ * static struct platform_device a910_rfkill = {
+ * 	.name  = "rfkill-regulator",
+ * 	.id    = 0,
+ * 	.dev   = {
+ * 		.platform_data = &ezx_rfkill_bt_data,
+ * 	},
+ * };
+ */
+
+#include <linux/rfkill.h>
+
+struct rfkill_regulator_platform_data {
+	char *name;             /* the name for the rfkill switch */
+	enum rfkill_type type;  /* the type as specified in rfkill.h */
+};
+
+#endif /* __LINUX_RFKILL_REGULATOR_H */
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 2b9ca0d..7a215a7 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -276,10 +276,52 @@
 #define L2CAP_CONN_PARAM_ACCEPTED	0x0000
 #define L2CAP_CONN_PARAM_REJECTED	0x0001
 
-/* ----- L2CAP connections ----- */
-struct l2cap_chan_list {
-	struct sock	*head;
-	rwlock_t	lock;
+/* ----- L2CAP channels and connections ----- */
+struct srej_list {
+	__u8	tx_seq;
+	struct list_head list;
+};
+
+struct l2cap_chan {
+	struct sock *sk;
+	__u8		ident;
+
+	__u8		conf_req[64];
+	__u8		conf_len;
+	__u8		num_conf_req;
+	__u8		num_conf_rsp;
+
+	__u16		conn_state;
+
+	__u8		next_tx_seq;
+	__u8		expected_ack_seq;
+	__u8		expected_tx_seq;
+	__u8		buffer_seq;
+	__u8		buffer_seq_srej;
+	__u8		srej_save_reqseq;
+	__u8		frames_sent;
+	__u8		unacked_frames;
+	__u8		retry_count;
+	__u8		num_acked;
+	__u16		sdu_len;
+	__u16		partial_sdu_len;
+	struct sk_buff	*sdu;
+
+	__u8		remote_tx_win;
+	__u8		remote_max_tx;
+	__u16		remote_mps;
+
+	struct timer_list	retrans_timer;
+	struct timer_list	monitor_timer;
+	struct timer_list	ack_timer;
+	struct sk_buff		*tx_send_head;
+	struct sk_buff_head	tx_q;
+	struct sk_buff_head	srej_q;
+	struct sk_buff_head	busy_q;
+	struct work_struct	busy_work;
+	struct list_head	srej_l;
+
+	struct list_head list;
 };
 
 struct l2cap_conn {
@@ -305,29 +347,16 @@
 
 	__u8		disc_reason;
 
-	struct l2cap_chan_list chan_list;
-};
-
-struct sock_del_list {
-	struct sock *sk;
-	struct list_head list;
+	struct list_head chan_l;
+	rwlock_t	chan_lock;
 };
 
 #define L2CAP_INFO_CL_MTU_REQ_SENT	0x01
 #define L2CAP_INFO_FEAT_MASK_REQ_SENT	0x04
 #define L2CAP_INFO_FEAT_MASK_REQ_DONE	0x08
 
-/* ----- L2CAP channel and socket info ----- */
+/* ----- L2CAP socket info ----- */
 #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
-#define TX_QUEUE(sk) (&l2cap_pi(sk)->tx_queue)
-#define SREJ_QUEUE(sk) (&l2cap_pi(sk)->srej_queue)
-#define BUSY_QUEUE(sk) (&l2cap_pi(sk)->busy_queue)
-#define SREJ_LIST(sk) (&l2cap_pi(sk)->srej_l.list)
-
-struct srej_list {
-	__u8	tx_seq;
-	struct list_head list;
-};
 
 struct l2cap_pinfo {
 	struct bt_sock	bt;
@@ -339,8 +368,6 @@
 	__u16		omtu;
 	__u16		flush_to;
 	__u8		mode;
-	__u8		num_conf_req;
-	__u8		num_conf_rsp;
 
 	__u8		fcs;
 	__u8		sec_level;
@@ -348,49 +375,18 @@
 	__u8		force_reliable;
 	__u8		flushable;
 
-	__u8		conf_req[64];
-	__u8		conf_len;
 	__u8		conf_state;
-	__u16		conn_state;
-
-	__u8		next_tx_seq;
-	__u8		expected_ack_seq;
-	__u8		expected_tx_seq;
-	__u8		buffer_seq;
-	__u8		buffer_seq_srej;
-	__u8		srej_save_reqseq;
-	__u8		frames_sent;
-	__u8		unacked_frames;
-	__u8		retry_count;
-	__u8		num_acked;
-	__u16		sdu_len;
-	__u16		partial_sdu_len;
-	struct sk_buff	*sdu;
-
-	__u8		ident;
 
 	__u8		tx_win;
 	__u8		max_tx;
-	__u8		remote_tx_win;
-	__u8		remote_max_tx;
 	__u16		retrans_timeout;
 	__u16		monitor_timeout;
-	__u16		remote_mps;
 	__u16		mps;
 
 	__le16		sport;
 
-	struct timer_list	retrans_timer;
-	struct timer_list	monitor_timer;
-	struct timer_list	ack_timer;
-	struct sk_buff_head	tx_queue;
-	struct sk_buff_head	srej_queue;
-	struct sk_buff_head	busy_queue;
-	struct work_struct	busy_work;
-	struct srej_list	srej_l;
 	struct l2cap_conn	*conn;
-	struct sock		*next_c;
-	struct sock		*prev_c;
+	struct l2cap_chan	*chan;
 };
 
 #define L2CAP_CONF_REQ_SENT       0x01
@@ -417,24 +413,23 @@
 #define L2CAP_CONN_RNR_SENT        0x0200
 #define L2CAP_CONN_SAR_RETRY       0x0400
 
-#define __mod_retrans_timer() mod_timer(&l2cap_pi(sk)->retrans_timer, \
+#define __mod_retrans_timer() mod_timer(&chan->retrans_timer, \
 		jiffies +  msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO));
-#define __mod_monitor_timer() mod_timer(&l2cap_pi(sk)->monitor_timer, \
+#define __mod_monitor_timer() mod_timer(&chan->monitor_timer, \
 		jiffies + msecs_to_jiffies(L2CAP_DEFAULT_MONITOR_TO));
-#define __mod_ack_timer() mod_timer(&l2cap_pi(sk)->ack_timer, \
+#define __mod_ack_timer() mod_timer(&chan->ack_timer, \
 		jiffies + msecs_to_jiffies(L2CAP_DEFAULT_ACK_TO));
 
-static inline int l2cap_tx_window_full(struct sock *sk)
+static inline int l2cap_tx_window_full(struct l2cap_chan *ch)
 {
-	struct l2cap_pinfo *pi = l2cap_pi(sk);
 	int sub;
 
-	sub = (pi->next_tx_seq - pi->expected_ack_seq) % 64;
+	sub = (ch->next_tx_seq - ch->expected_ack_seq) % 64;
 
 	if (sub < 0)
 		sub += 64;
 
-	return sub == pi->remote_tx_win;
+	return sub == ch->remote_tx_win;
 }
 
 #define __get_txseq(ctrl)	(((ctrl) & L2CAP_CTRL_TXSEQ) >> 1)
@@ -450,18 +445,17 @@
 int l2cap_init_sockets(void);
 void l2cap_cleanup_sockets(void);
 
-u8 l2cap_get_ident(struct l2cap_conn *conn);
 void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data);
-int l2cap_build_conf_req(struct sock *sk, void *data);
+void __l2cap_connect_rsp_defer(struct sock *sk);
 int __l2cap_wait_ack(struct sock *sk);
 
 struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, size_t len);
 struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size_t len);
 struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 control, u16 sdulen);
-int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, size_t len);
+int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len);
 void l2cap_do_send(struct sock *sk, struct sk_buff *skb);
-void l2cap_streaming_send(struct sock *sk);
-int l2cap_ertm_send(struct sock *sk);
+void l2cap_streaming_send(struct l2cap_chan *chan);
+int l2cap_ertm_send(struct l2cap_chan *chan);
 
 void l2cap_sock_set_timer(struct sock *sk, long timeout);
 void l2cap_sock_clear_timer(struct sock *sk);
@@ -470,8 +464,8 @@
 void l2cap_sock_init(struct sock *sk, struct sock *parent);
 struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
 							int proto, gfp_t prio);
-void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err);
-void l2cap_chan_del(struct sock *sk, int err);
+void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err);
+void l2cap_chan_del(struct l2cap_chan *chan, int err);
 int l2cap_do_connect(struct sock *sk);
 
 #endif /* __L2CAP_H */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index ba7384a..d30eada 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -423,6 +423,7 @@
  * @STATION_INFO_SIGNAL_AVG: @signal_avg filled
  * @STATION_INFO_RX_BITRATE: @rxrate fields are filled
  * @STATION_INFO_BSS_PARAM: @bss_param filled
+ * @STATION_INFO_CONNECTED_TIME: @connected_time filled
  */
 enum station_info_flags {
 	STATION_INFO_INACTIVE_TIME	= 1<<0,
@@ -441,6 +442,7 @@
 	STATION_INFO_SIGNAL_AVG		= 1<<13,
 	STATION_INFO_RX_BITRATE		= 1<<14,
 	STATION_INFO_BSS_PARAM          = 1<<15,
+	STATION_INFO_CONNECTED_TIME	= 1<<16
 };
 
 /**
@@ -511,6 +513,7 @@
  * Station information filled by driver for get_station() and dump_station.
  *
  * @filled: bitflag of flags from &enum station_info_flags
+ * @connected_time: time(in secs) since a station is last connected
  * @inactive_time: time since last station activity (tx/rx) in milliseconds
  * @rx_bytes: bytes received from this station
  * @tx_bytes: bytes transmitted to this station
@@ -533,6 +536,7 @@
  */
 struct station_info {
 	u32 filled;
+	u32 connected_time;
 	u32 inactive_time;
 	u32 rx_bytes;
 	u32 tx_bytes;
@@ -689,8 +693,9 @@
  * @mesh_id_len: length of the mesh ID, at least 1 and at most 32 bytes
  * @path_sel_proto: which path selection protocol to use
  * @path_metric: which metric to use
- * @vendor_ie: vendor information elements (optional)
- * @vendor_ie_len: length of vendor information elements
+ * @ie: vendor information elements (optional)
+ * @ie_len: length of vendor information elements
+ * @is_secure: or not
  *
  * These parameters are fixed when the mesh is created.
  */
@@ -699,8 +704,9 @@
 	u8 mesh_id_len;
 	u8  path_sel_proto;
 	u8  path_metric;
-	const u8 *vendor_ie;
-	u8 vendor_ie_len;
+	const u8 *ie;
+	u8 ie_len;
+	bool is_secure;
 };
 
 /**
@@ -1451,6 +1457,8 @@
  * @WIPHY_FLAG_IBSS_RSN: The device supports IBSS RSN.
  * @WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS: The device supports separate
  *	unicast and multicast TX keys.
+ * @WIPHY_FLAG_MESH_AUTH: The device supports mesh authentication by routing
+ *	auth frames to userspace. See @NL80211_MESH_SETUP_USERSPACE_AUTH.
  */
 enum wiphy_flags {
 	WIPHY_FLAG_CUSTOM_REGULATORY		= BIT(0),
@@ -1463,6 +1471,7 @@
 	WIPHY_FLAG_CONTROL_PORT_PROTOCOL	= BIT(7),
 	WIPHY_FLAG_IBSS_RSN			= BIT(8),
 	WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS= BIT(9),
+	WIPHY_FLAG_MESH_AUTH			= BIT(10),
 };
 
 struct mac_address {
@@ -2484,6 +2493,22 @@
 void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp);
 
 /**
+ * cfg80211_notify_new_candidate - notify cfg80211 of a new mesh peer candidate
+ *
+ * @dev: network device
+ * @macaddr: the MAC address of the new candidate
+ * @ie: information elements advertised by the peer candidate
+ * @ie_len: lenght of the information elements buffer
+ * @gfp: allocation flags
+ *
+ * This function notifies cfg80211 that the mesh peer candidate has been
+ * detected, most likely via a beacon or, less likely, via a probe response.
+ * cfg80211 then sends a notification to userspace.
+ */
+void cfg80211_notify_new_peer_candidate(struct net_device *dev,
+		const u8 *macaddr, const u8 *ie, u8 ie_len, gfp_t gfp);
+
+/**
  * DOC: RFkill integration
  *
  * RFkill integration in cfg80211 is almost invisible to drivers,
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 025d4cc..d23dd6c 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1819,6 +1819,9 @@
  * @set_ringparam: Set tx and rx ring sizes.
  *
  * @get_ringparam: Get tx and rx ring current and maximum sizes.
+ *
+ * @tx_frames_pending: Check if there is any pending frame in the hardware
+ *	queues before entering power save.
  */
 struct ieee80211_ops {
 	void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
@@ -1906,6 +1909,7 @@
 	int (*set_ringparam)(struct ieee80211_hw *hw, u32 tx, u32 rx);
 	void (*get_ringparam)(struct ieee80211_hw *hw,
 			      u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max);
+	bool (*tx_frames_pending)(struct ieee80211_hw *hw);
 };
 
 /**
@@ -2223,6 +2227,18 @@
 #define IEEE80211_TX_STATUS_HEADROOM	13
 
 /**
+ * ieee80211_sta_set_tim - set the TIM bit for a sleeping station
+ *
+ * If a driver buffers frames for a powersave station instead of passing
+ * them back to mac80211 for retransmission, the station needs to be told
+ * to wake up using the TIM bitmap in the beacon.
+ *
+ * This function sets the station's TIM bit - it will be cleared when the
+ * station wakes up.
+ */
+void ieee80211_sta_set_tim(struct ieee80211_sta *sta);
+
+/**
  * ieee80211_tx_status - transmit status callback
  *
  * Call this function for all transmitted frames after they have been
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 7a3398d..c7eb073 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2497,6 +2497,9 @@
 
 	hci_dev_lock(hdev);
 
+	if (!test_bit(HCI_MGMT, &hdev->flags))
+		goto unlock;
+
 	data = hci_find_remote_oob_data(hdev, &ev->bdaddr);
 	if (data) {
 		struct hci_cp_remote_oob_data_reply cp;
@@ -2515,6 +2518,7 @@
 									&cp);
 	}
 
+unlock:
 	hci_dev_unlock(hdev);
 }
 
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index c3cebed..d47de2b 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -70,108 +70,101 @@
 
 static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
 				u8 code, u8 ident, u16 dlen, void *data);
+static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
 
 static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
 
 /* ---- L2CAP channels ---- */
-static struct sock *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid)
+static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
 {
-	struct sock *s;
-	for (s = l->head; s; s = l2cap_pi(s)->next_c) {
+	struct l2cap_chan *c;
+
+	list_for_each_entry(c, &conn->chan_l, list) {
+		struct sock *s = c->sk;
 		if (l2cap_pi(s)->dcid == cid)
-			break;
+			return c;
 	}
-	return s;
+	return NULL;
+
 }
 
-static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid)
+static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
 {
-	struct sock *s;
-	for (s = l->head; s; s = l2cap_pi(s)->next_c) {
+	struct l2cap_chan *c;
+
+	list_for_each_entry(c, &conn->chan_l, list) {
+		struct sock *s = c->sk;
 		if (l2cap_pi(s)->scid == cid)
-			break;
+			return c;
 	}
-	return s;
+	return NULL;
 }
 
 /* Find channel with given SCID.
  * Returns locked socket */
-static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid)
+static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
 {
-	struct sock *s;
-	read_lock(&l->lock);
-	s = __l2cap_get_chan_by_scid(l, cid);
-	if (s)
-		bh_lock_sock(s);
-	read_unlock(&l->lock);
-	return s;
+	struct l2cap_chan *c;
+
+	read_lock(&conn->chan_lock);
+	c = __l2cap_get_chan_by_scid(conn, cid);
+	if (c)
+		bh_lock_sock(c->sk);
+	read_unlock(&conn->chan_lock);
+	return c;
 }
 
-static struct sock *__l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident)
+static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
 {
-	struct sock *s;
-	for (s = l->head; s; s = l2cap_pi(s)->next_c) {
-		if (l2cap_pi(s)->ident == ident)
-			break;
+	struct l2cap_chan *c;
+
+	list_for_each_entry(c, &conn->chan_l, list) {
+		if (c->ident == ident)
+			return c;
 	}
-	return s;
+	return NULL;
 }
 
-static inline struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident)
+static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
 {
-	struct sock *s;
-	read_lock(&l->lock);
-	s = __l2cap_get_chan_by_ident(l, ident);
-	if (s)
-		bh_lock_sock(s);
-	read_unlock(&l->lock);
-	return s;
+	struct l2cap_chan *c;
+
+	read_lock(&conn->chan_lock);
+	c = __l2cap_get_chan_by_ident(conn, ident);
+	if (c)
+		bh_lock_sock(c->sk);
+	read_unlock(&conn->chan_lock);
+	return c;
 }
 
-static u16 l2cap_alloc_cid(struct l2cap_chan_list *l)
+static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
 {
 	u16 cid = L2CAP_CID_DYN_START;
 
 	for (; cid < L2CAP_CID_DYN_END; cid++) {
-		if (!__l2cap_get_chan_by_scid(l, cid))
+		if (!__l2cap_get_chan_by_scid(conn, cid))
 			return cid;
 	}
 
 	return 0;
 }
 
-static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk)
+static struct l2cap_chan *l2cap_chan_alloc(struct sock *sk)
 {
-	sock_hold(sk);
+	struct l2cap_chan *chan;
 
-	if (l->head)
-		l2cap_pi(l->head)->prev_c = sk;
+	chan = kzalloc(sizeof(*chan), GFP_ATOMIC);
+	if (!chan)
+		return NULL;
 
-	l2cap_pi(sk)->next_c = l->head;
-	l2cap_pi(sk)->prev_c = NULL;
-	l->head = sk;
+	chan->sk = sk;
+
+	return chan;
 }
 
-static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk)
+static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 {
-	struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c;
-
-	write_lock_bh(&l->lock);
-	if (sk == l->head)
-		l->head = next;
-
-	if (next)
-		l2cap_pi(next)->prev_c = prev;
-	if (prev)
-		l2cap_pi(prev)->next_c = next;
-	write_unlock_bh(&l->lock);
-
-	__sock_put(sk);
-}
-
-static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk)
-{
-	struct l2cap_chan_list *l = &conn->chan_list;
+	struct sock *sk = chan->sk;
 
 	BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
 			l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid);
@@ -188,7 +181,7 @@
 			l2cap_pi(sk)->dcid = L2CAP_CID_LE_DATA;
 		} else {
 			/* Alloc CID for connection-oriented socket */
-			l2cap_pi(sk)->scid = l2cap_alloc_cid(l);
+			l2cap_pi(sk)->scid = l2cap_alloc_cid(conn);
 			l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
 		}
 	} else if (sk->sk_type == SOCK_DGRAM) {
@@ -203,23 +196,30 @@
 		l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
 	}
 
-	__l2cap_chan_link(l, sk);
+	sock_hold(sk);
+
+	list_add(&chan->list, &conn->chan_l);
 }
 
 /* Delete channel.
  * Must be called on the locked socket. */
-void l2cap_chan_del(struct sock *sk, int err)
+void l2cap_chan_del(struct l2cap_chan *chan, int err)
 {
+	struct sock *sk = chan->sk;
 	struct l2cap_conn *conn = l2cap_pi(sk)->conn;
 	struct sock *parent = bt_sk(sk)->parent;
 
 	l2cap_sock_clear_timer(sk);
 
-	BT_DBG("sk %p, conn %p, err %d", sk, conn, err);
+	BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
 
 	if (conn) {
-		/* Unlink from channel list */
-		l2cap_chan_unlink(&conn->chan_list, sk);
+		/* Delete from channel list */
+		write_lock_bh(&conn->chan_lock);
+		list_del(&chan->list);
+		write_unlock_bh(&conn->chan_lock);
+		__sock_put(sk);
+
 		l2cap_pi(sk)->conn = NULL;
 		hci_conn_put(conn->hcon);
 	}
@@ -236,23 +236,30 @@
 	} else
 		sk->sk_state_change(sk);
 
-	skb_queue_purge(TX_QUEUE(sk));
+	if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE &&
+			l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE))
+		goto free;
+
+	skb_queue_purge(&chan->tx_q);
 
 	if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) {
 		struct srej_list *l, *tmp;
 
-		del_timer(&l2cap_pi(sk)->retrans_timer);
-		del_timer(&l2cap_pi(sk)->monitor_timer);
-		del_timer(&l2cap_pi(sk)->ack_timer);
+		del_timer(&chan->retrans_timer);
+		del_timer(&chan->monitor_timer);
+		del_timer(&chan->ack_timer);
 
-		skb_queue_purge(SREJ_QUEUE(sk));
-		skb_queue_purge(BUSY_QUEUE(sk));
+		skb_queue_purge(&chan->srej_q);
+		skb_queue_purge(&chan->busy_q);
 
-		list_for_each_entry_safe(l, tmp, SREJ_LIST(sk), list) {
+		list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
 			list_del(&l->list);
 			kfree(l);
 		}
 	}
+
+free:
+	kfree(chan);
 }
 
 static inline u8 l2cap_get_auth_type(struct sock *sk)
@@ -338,10 +345,11 @@
 	hci_send_acl(conn->hcon, skb, flags);
 }
 
-static inline void l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control)
+static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
 {
 	struct sk_buff *skb;
 	struct l2cap_hdr *lh;
+	struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
 	struct l2cap_conn *conn = pi->conn;
 	struct sock *sk = (struct sock *)pi;
 	int count, hlen = L2CAP_HDR_SIZE + 2;
@@ -353,19 +361,19 @@
 	if (pi->fcs == L2CAP_FCS_CRC16)
 		hlen += 2;
 
-	BT_DBG("pi %p, control 0x%2.2x", pi, control);
+	BT_DBG("chan %p, control 0x%2.2x", chan, control);
 
 	count = min_t(unsigned int, conn->mtu, hlen);
 	control |= L2CAP_CTRL_FRAME_TYPE;
 
-	if (pi->conn_state & L2CAP_CONN_SEND_FBIT) {
+	if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
 		control |= L2CAP_CTRL_FINAL;
-		pi->conn_state &= ~L2CAP_CONN_SEND_FBIT;
+		chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
 	}
 
-	if (pi->conn_state & L2CAP_CONN_SEND_PBIT) {
+	if (chan->conn_state & L2CAP_CONN_SEND_PBIT) {
 		control |= L2CAP_CTRL_POLL;
-		pi->conn_state &= ~L2CAP_CONN_SEND_PBIT;
+		chan->conn_state &= ~L2CAP_CONN_SEND_PBIT;
 	}
 
 	skb = bt_skb_alloc(count, GFP_ATOMIC);
@@ -390,17 +398,17 @@
 	hci_send_acl(pi->conn->hcon, skb, flags);
 }
 
-static inline void l2cap_send_rr_or_rnr(struct l2cap_pinfo *pi, u16 control)
+static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control)
 {
-	if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
+	if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
 		control |= L2CAP_SUPER_RCV_NOT_READY;
-		pi->conn_state |= L2CAP_CONN_RNR_SENT;
+		chan->conn_state |= L2CAP_CONN_RNR_SENT;
 	} else
 		control |= L2CAP_SUPER_RCV_READY;
 
-	control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+	control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
 
-	l2cap_send_sframe(pi, control);
+	l2cap_send_sframe(chan, control);
 }
 
 static inline int __l2cap_no_conn_pending(struct sock *sk)
@@ -408,8 +416,9 @@
 	return !(l2cap_pi(sk)->conf_state & L2CAP_CONF_CONNECT_PEND);
 }
 
-static void l2cap_do_start(struct sock *sk)
+static void l2cap_do_start(struct l2cap_chan *chan)
 {
+	struct sock *sk = chan->sk;
 	struct l2cap_conn *conn = l2cap_pi(sk)->conn;
 
 	if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
@@ -421,11 +430,11 @@
 			req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
 			req.psm  = l2cap_pi(sk)->psm;
 
-			l2cap_pi(sk)->ident = l2cap_get_ident(conn);
+			chan->ident = l2cap_get_ident(conn);
 			l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND;
 
-			l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
-					L2CAP_CONN_REQ, sizeof(req), &req);
+			l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
+							sizeof(req), &req);
 		}
 	} else {
 		struct l2cap_info_req req;
@@ -458,19 +467,20 @@
 	}
 }
 
-void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err)
+void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
 {
+	struct sock *sk;
 	struct l2cap_disconn_req req;
 
 	if (!conn)
 		return;
 
-	skb_queue_purge(TX_QUEUE(sk));
+	sk = chan->sk;
 
 	if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) {
-		del_timer(&l2cap_pi(sk)->retrans_timer);
-		del_timer(&l2cap_pi(sk)->monitor_timer);
-		del_timer(&l2cap_pi(sk)->ack_timer);
+		del_timer(&chan->retrans_timer);
+		del_timer(&chan->monitor_timer);
+		del_timer(&chan->ack_timer);
 	}
 
 	req.dcid = cpu_to_le16(l2cap_pi(sk)->dcid);
@@ -485,17 +495,15 @@
 /* ---- L2CAP connections ---- */
 static void l2cap_conn_start(struct l2cap_conn *conn)
 {
-	struct l2cap_chan_list *l = &conn->chan_list;
-	struct sock_del_list del, *tmp1, *tmp2;
-	struct sock *sk;
+	struct l2cap_chan *chan, *tmp;
 
 	BT_DBG("conn %p", conn);
 
-	INIT_LIST_HEAD(&del.list);
+	read_lock(&conn->chan_lock);
 
-	read_lock(&l->lock);
+	list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
+		struct sock *sk = chan->sk;
 
-	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
 		bh_lock_sock(sk);
 
 		if (sk->sk_type != SOCK_SEQPACKET &&
@@ -517,10 +525,11 @@
 					conn->feat_mask)
 					&& l2cap_pi(sk)->conf_state &
 					L2CAP_CONF_STATE2_DEVICE) {
-				tmp1 = kzalloc(sizeof(struct sock_del_list),
-						GFP_ATOMIC);
-				tmp1->sk = sk;
-				list_add_tail(&tmp1->list, &del.list);
+				/* __l2cap_sock_close() calls list_del(chan)
+				 * so release the lock */
+				read_unlock_bh(&conn->chan_lock);
+				 __l2cap_sock_close(sk, ECONNRESET);
+				read_lock_bh(&conn->chan_lock);
 				bh_unlock_sock(sk);
 				continue;
 			}
@@ -528,11 +537,11 @@
 			req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
 			req.psm  = l2cap_pi(sk)->psm;
 
-			l2cap_pi(sk)->ident = l2cap_get_ident(conn);
+			chan->ident = l2cap_get_ident(conn);
 			l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND;
 
-			l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
-				L2CAP_CONN_REQ, sizeof(req), &req);
+			l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
+							sizeof(req), &req);
 
 		} else if (sk->sk_state == BT_CONNECT2) {
 			struct l2cap_conn_rsp rsp;
@@ -557,8 +566,8 @@
 				rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
 			}
 
-			l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
-					L2CAP_CONN_RSP, sizeof(rsp), &rsp);
+			l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
+							sizeof(rsp), &rsp);
 
 			if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT ||
 					rsp.result != L2CAP_CR_SUCCESS) {
@@ -568,22 +577,14 @@
 
 			l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
 			l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
-						l2cap_build_conf_req(sk, buf), buf);
-			l2cap_pi(sk)->num_conf_req++;
+						l2cap_build_conf_req(chan, buf), buf);
+			chan->num_conf_req++;
 		}
 
 		bh_unlock_sock(sk);
 	}
 
-	read_unlock(&l->lock);
-
-	list_for_each_entry_safe(tmp1, tmp2, &del.list, list) {
-		bh_lock_sock(tmp1->sk);
-		__l2cap_sock_close(tmp1->sk, ECONNRESET);
-		bh_unlock_sock(tmp1->sk);
-		list_del(&tmp1->list);
-		kfree(tmp1);
-	}
+	read_unlock(&conn->chan_lock);
 }
 
 /* Find socket with cid and source bdaddr.
@@ -591,7 +592,7 @@
  */
 static struct sock *l2cap_get_sock_by_scid(int state, __le16 cid, bdaddr_t *src)
 {
-	struct sock *s, *sk = NULL, *sk1 = NULL;
+	struct sock *sk = NULL, *sk1 = NULL;
 	struct hlist_node *node;
 
 	read_lock(&l2cap_sk_list.lock);
@@ -610,18 +611,16 @@
 				sk1 = sk;
 		}
 	}
-	s = node ? sk : sk1;
-	if (s)
-		bh_lock_sock(s);
+
 	read_unlock(&l2cap_sk_list.lock);
 
-	return s;
+	return node ? sk : sk1;
 }
 
 static void l2cap_le_conn_ready(struct l2cap_conn *conn)
 {
-	struct l2cap_chan_list *list = &conn->chan_list;
-	struct sock *parent, *uninitialized_var(sk);
+	struct sock *parent, *sk;
+	struct l2cap_chan *chan;
 
 	BT_DBG("");
 
@@ -631,6 +630,8 @@
 	if (!parent)
 		return;
 
+	bh_lock_sock(parent);
+
 	/* Check for backlog size */
 	if (sk_acceptq_is_full(parent)) {
 		BT_DBG("backlog full %d", parent->sk_ack_backlog);
@@ -641,24 +642,33 @@
 	if (!sk)
 		goto clean;
 
-	write_lock_bh(&list->lock);
+	chan = l2cap_chan_alloc(sk);
+	if (!chan) {
+		l2cap_sock_kill(sk);
+		goto clean;
+	}
+
+	write_lock_bh(&conn->chan_lock);
 
 	hci_conn_hold(conn->hcon);
 
 	l2cap_sock_init(sk, parent);
+
 	bacpy(&bt_sk(sk)->src, conn->src);
 	bacpy(&bt_sk(sk)->dst, conn->dst);
 
 	bt_accept_enqueue(parent, sk);
 
-	__l2cap_chan_add(conn, sk);
+	__l2cap_chan_add(conn, chan);
+
+	l2cap_pi(sk)->chan = chan;
 
 	l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
 
 	sk->sk_state = BT_CONNECTED;
 	parent->sk_data_ready(parent, 0);
 
-	write_unlock_bh(&list->lock);
+	write_unlock_bh(&conn->chan_lock);
 
 clean:
 	bh_unlock_sock(parent);
@@ -666,17 +676,18 @@
 
 static void l2cap_conn_ready(struct l2cap_conn *conn)
 {
-	struct l2cap_chan_list *l = &conn->chan_list;
-	struct sock *sk;
+	struct l2cap_chan *chan;
 
 	BT_DBG("conn %p", conn);
 
 	if (!conn->hcon->out && conn->hcon->type == LE_LINK)
 		l2cap_le_conn_ready(conn);
 
-	read_lock(&l->lock);
+	read_lock(&conn->chan_lock);
 
-	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
+	list_for_each_entry(chan, &conn->chan_l, list) {
+		struct sock *sk = chan->sk;
+
 		bh_lock_sock(sk);
 
 		if (conn->hcon->type == LE_LINK) {
@@ -691,30 +702,31 @@
 			sk->sk_state = BT_CONNECTED;
 			sk->sk_state_change(sk);
 		} else if (sk->sk_state == BT_CONNECT)
-			l2cap_do_start(sk);
+			l2cap_do_start(chan);
 
 		bh_unlock_sock(sk);
 	}
 
-	read_unlock(&l->lock);
+	read_unlock(&conn->chan_lock);
 }
 
 /* Notify sockets that we cannot guaranty reliability anymore */
 static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
 {
-	struct l2cap_chan_list *l = &conn->chan_list;
-	struct sock *sk;
+	struct l2cap_chan *chan;
 
 	BT_DBG("conn %p", conn);
 
-	read_lock(&l->lock);
+	read_lock(&conn->chan_lock);
 
-	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
+	list_for_each_entry(chan, &conn->chan_l, list) {
+		struct sock *sk = chan->sk;
+
 		if (l2cap_pi(sk)->force_reliable)
 			sk->sk_err = err;
 	}
 
-	read_unlock(&l->lock);
+	read_unlock(&conn->chan_lock);
 }
 
 static void l2cap_info_timeout(unsigned long arg)
@@ -754,7 +766,9 @@
 	conn->feat_mask = 0;
 
 	spin_lock_init(&conn->lock);
-	rwlock_init(&conn->chan_list.lock);
+	rwlock_init(&conn->chan_lock);
+
+	INIT_LIST_HEAD(&conn->chan_l);
 
 	if (hcon->type != LE_LINK)
 		setup_timer(&conn->info_timer, l2cap_info_timeout,
@@ -768,6 +782,7 @@
 static void l2cap_conn_del(struct hci_conn *hcon, int err)
 {
 	struct l2cap_conn *conn = hcon->l2cap_data;
+	struct l2cap_chan *chan, *l;
 	struct sock *sk;
 
 	if (!conn)
@@ -778,9 +793,10 @@
 	kfree_skb(conn->rx_skb);
 
 	/* Kill channels */
-	while ((sk = conn->chan_list.head)) {
+	list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
+		sk = chan->sk;
 		bh_lock_sock(sk);
-		l2cap_chan_del(sk, err);
+		l2cap_chan_del(chan, err);
 		bh_unlock_sock(sk);
 		l2cap_sock_kill(sk);
 	}
@@ -792,12 +808,11 @@
 	kfree(conn);
 }
 
-static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk)
+static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 {
-	struct l2cap_chan_list *l = &conn->chan_list;
-	write_lock_bh(&l->lock);
-	__l2cap_chan_add(conn, sk);
-	write_unlock_bh(&l->lock);
+	write_lock_bh(&conn->chan_lock);
+	__l2cap_chan_add(conn, chan);
+	write_unlock_bh(&conn->chan_lock);
 }
 
 /* ---- Socket interface ---- */
@@ -837,6 +852,7 @@
 	bdaddr_t *src = &bt_sk(sk)->src;
 	bdaddr_t *dst = &bt_sk(sk)->dst;
 	struct l2cap_conn *conn;
+	struct l2cap_chan *chan;
 	struct hci_conn *hcon;
 	struct hci_dev *hdev;
 	__u8 auth_type;
@@ -872,10 +888,19 @@
 		goto done;
 	}
 
+	chan = l2cap_chan_alloc(sk);
+	if (!chan) {
+		hci_conn_put(hcon);
+		err = -ENOMEM;
+		goto done;
+	}
+
 	/* Update source addr of the socket */
 	bacpy(src, conn->src);
 
-	l2cap_chan_add(conn, sk);
+	l2cap_chan_add(conn, chan);
+
+	l2cap_pi(sk)->chan = chan;
 
 	sk->sk_state = BT_CONNECT;
 	l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
@@ -887,7 +912,7 @@
 			if (l2cap_check_security(sk))
 				sk->sk_state = BT_CONNECTED;
 		} else
-			l2cap_do_start(sk);
+			l2cap_do_start(chan);
 	}
 
 	err = 0;
@@ -905,7 +930,7 @@
 	int timeo = HZ/5;
 
 	add_wait_queue(sk_sleep(sk), &wait);
-	while ((l2cap_pi(sk)->unacked_frames > 0 && l2cap_pi(sk)->conn)) {
+	while ((l2cap_pi(sk)->chan->unacked_frames > 0 && l2cap_pi(sk)->conn)) {
 		set_current_state(TASK_INTERRUPTIBLE);
 
 		if (!timeo)
@@ -931,57 +956,59 @@
 
 static void l2cap_monitor_timeout(unsigned long arg)
 {
-	struct sock *sk = (void *) arg;
+	struct l2cap_chan *chan = (void *) arg;
+	struct sock *sk = chan->sk;
 
-	BT_DBG("sk %p", sk);
+	BT_DBG("chan %p", chan);
 
 	bh_lock_sock(sk);
-	if (l2cap_pi(sk)->retry_count >= l2cap_pi(sk)->remote_max_tx) {
-		l2cap_send_disconn_req(l2cap_pi(sk)->conn, sk, ECONNABORTED);
+	if (chan->retry_count >= chan->remote_max_tx) {
+		l2cap_send_disconn_req(l2cap_pi(sk)->conn, chan, ECONNABORTED);
 		bh_unlock_sock(sk);
 		return;
 	}
 
-	l2cap_pi(sk)->retry_count++;
+	chan->retry_count++;
 	__mod_monitor_timer();
 
-	l2cap_send_rr_or_rnr(l2cap_pi(sk), L2CAP_CTRL_POLL);
+	l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
 	bh_unlock_sock(sk);
 }
 
 static void l2cap_retrans_timeout(unsigned long arg)
 {
-	struct sock *sk = (void *) arg;
+	struct l2cap_chan *chan = (void *) arg;
+	struct sock *sk = chan->sk;
 
-	BT_DBG("sk %p", sk);
+	BT_DBG("chan %p", chan);
 
 	bh_lock_sock(sk);
-	l2cap_pi(sk)->retry_count = 1;
+	chan->retry_count = 1;
 	__mod_monitor_timer();
 
-	l2cap_pi(sk)->conn_state |= L2CAP_CONN_WAIT_F;
+	chan->conn_state |= L2CAP_CONN_WAIT_F;
 
-	l2cap_send_rr_or_rnr(l2cap_pi(sk), L2CAP_CTRL_POLL);
+	l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
 	bh_unlock_sock(sk);
 }
 
-static void l2cap_drop_acked_frames(struct sock *sk)
+static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
 {
 	struct sk_buff *skb;
 
-	while ((skb = skb_peek(TX_QUEUE(sk))) &&
-			l2cap_pi(sk)->unacked_frames) {
-		if (bt_cb(skb)->tx_seq == l2cap_pi(sk)->expected_ack_seq)
+	while ((skb = skb_peek(&chan->tx_q)) &&
+			chan->unacked_frames) {
+		if (bt_cb(skb)->tx_seq == chan->expected_ack_seq)
 			break;
 
-		skb = skb_dequeue(TX_QUEUE(sk));
+		skb = skb_dequeue(&chan->tx_q);
 		kfree_skb(skb);
 
-		l2cap_pi(sk)->unacked_frames--;
+		chan->unacked_frames--;
 	}
 
-	if (!l2cap_pi(sk)->unacked_frames)
-		del_timer(&l2cap_pi(sk)->retrans_timer);
+	if (!chan->unacked_frames)
+		del_timer(&chan->retrans_timer);
 }
 
 void l2cap_do_send(struct sock *sk, struct sk_buff *skb)
@@ -1000,15 +1027,16 @@
 	hci_send_acl(hcon, skb, flags);
 }
 
-void l2cap_streaming_send(struct sock *sk)
+void l2cap_streaming_send(struct l2cap_chan *chan)
 {
+	struct sock *sk = chan->sk;
 	struct sk_buff *skb;
 	struct l2cap_pinfo *pi = l2cap_pi(sk);
 	u16 control, fcs;
 
-	while ((skb = skb_dequeue(TX_QUEUE(sk)))) {
+	while ((skb = skb_dequeue(&chan->tx_q))) {
 		control = get_unaligned_le16(skb->data + L2CAP_HDR_SIZE);
-		control |= pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT;
+		control |= chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT;
 		put_unaligned_le16(control, skb->data + L2CAP_HDR_SIZE);
 
 		if (pi->fcs == L2CAP_FCS_CRC16) {
@@ -1018,17 +1046,18 @@
 
 		l2cap_do_send(sk, skb);
 
-		pi->next_tx_seq = (pi->next_tx_seq + 1) % 64;
+		chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
 	}
 }
 
-static void l2cap_retransmit_one_frame(struct sock *sk, u8 tx_seq)
+static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
 {
+	struct sock *sk = chan->sk;
 	struct l2cap_pinfo *pi = l2cap_pi(sk);
 	struct sk_buff *skb, *tx_skb;
 	u16 control, fcs;
 
-	skb = skb_peek(TX_QUEUE(sk));
+	skb = skb_peek(&chan->tx_q);
 	if (!skb)
 		return;
 
@@ -1036,14 +1065,14 @@
 		if (bt_cb(skb)->tx_seq == tx_seq)
 			break;
 
-		if (skb_queue_is_last(TX_QUEUE(sk), skb))
+		if (skb_queue_is_last(&chan->tx_q, skb))
 			return;
 
-	} while ((skb = skb_queue_next(TX_QUEUE(sk), skb)));
+	} while ((skb = skb_queue_next(&chan->tx_q, skb)));
 
-	if (pi->remote_max_tx &&
-			bt_cb(skb)->retries == pi->remote_max_tx) {
-		l2cap_send_disconn_req(pi->conn, sk, ECONNABORTED);
+	if (chan->remote_max_tx &&
+			bt_cb(skb)->retries == chan->remote_max_tx) {
+		l2cap_send_disconn_req(pi->conn, chan, ECONNABORTED);
 		return;
 	}
 
@@ -1051,12 +1080,12 @@
 	bt_cb(skb)->retries++;
 	control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
 
-	if (pi->conn_state & L2CAP_CONN_SEND_FBIT) {
+	if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
 		control |= L2CAP_CTRL_FINAL;
-		pi->conn_state &= ~L2CAP_CONN_SEND_FBIT;
+		chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
 	}
 
-	control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
+	control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
 			| (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
 
 	put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
@@ -1069,9 +1098,10 @@
 	l2cap_do_send(sk, tx_skb);
 }
 
-int l2cap_ertm_send(struct sock *sk)
+int l2cap_ertm_send(struct l2cap_chan *chan)
 {
 	struct sk_buff *skb, *tx_skb;
+	struct sock *sk = chan->sk;
 	struct l2cap_pinfo *pi = l2cap_pi(sk);
 	u16 control, fcs;
 	int nsent = 0;
@@ -1079,11 +1109,11 @@
 	if (sk->sk_state != BT_CONNECTED)
 		return -ENOTCONN;
 
-	while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(sk))) {
+	while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
 
-		if (pi->remote_max_tx &&
-				bt_cb(skb)->retries == pi->remote_max_tx) {
-			l2cap_send_disconn_req(pi->conn, sk, ECONNABORTED);
+		if (chan->remote_max_tx &&
+				bt_cb(skb)->retries == chan->remote_max_tx) {
+			l2cap_send_disconn_req(pi->conn, chan, ECONNABORTED);
 			break;
 		}
 
@@ -1094,12 +1124,12 @@
 		control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
 		control &= L2CAP_CTRL_SAR;
 
-		if (pi->conn_state & L2CAP_CONN_SEND_FBIT) {
+		if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
 			control |= L2CAP_CTRL_FINAL;
-			pi->conn_state &= ~L2CAP_CONN_SEND_FBIT;
+			chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
 		}
-		control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
-				| (pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
+		control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
+				| (chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
 		put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
 
 
@@ -1112,18 +1142,18 @@
 
 		__mod_retrans_timer();
 
-		bt_cb(skb)->tx_seq = pi->next_tx_seq;
-		pi->next_tx_seq = (pi->next_tx_seq + 1) % 64;
+		bt_cb(skb)->tx_seq = chan->next_tx_seq;
+		chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
 
 		if (bt_cb(skb)->retries == 1)
-			pi->unacked_frames++;
+			chan->unacked_frames++;
 
-		pi->frames_sent++;
+		chan->frames_sent++;
 
-		if (skb_queue_is_last(TX_QUEUE(sk), skb))
-			sk->sk_send_head = NULL;
+		if (skb_queue_is_last(&chan->tx_q, skb))
+			chan->tx_send_head = NULL;
 		else
-			sk->sk_send_head = skb_queue_next(TX_QUEUE(sk), skb);
+			chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
 
 		nsent++;
 	}
@@ -1131,41 +1161,39 @@
 	return nsent;
 }
 
-static int l2cap_retransmit_frames(struct sock *sk)
+static int l2cap_retransmit_frames(struct l2cap_chan *chan)
 {
-	struct l2cap_pinfo *pi = l2cap_pi(sk);
 	int ret;
 
-	if (!skb_queue_empty(TX_QUEUE(sk)))
-		sk->sk_send_head = TX_QUEUE(sk)->next;
+	if (!skb_queue_empty(&chan->tx_q))
+		chan->tx_send_head = chan->tx_q.next;
 
-	pi->next_tx_seq = pi->expected_ack_seq;
-	ret = l2cap_ertm_send(sk);
+	chan->next_tx_seq = chan->expected_ack_seq;
+	ret = l2cap_ertm_send(chan);
 	return ret;
 }
 
-static void l2cap_send_ack(struct l2cap_pinfo *pi)
+static void l2cap_send_ack(struct l2cap_chan *chan)
 {
-	struct sock *sk = (struct sock *)pi;
 	u16 control = 0;
 
-	control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+	control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
 
-	if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
+	if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
 		control |= L2CAP_SUPER_RCV_NOT_READY;
-		pi->conn_state |= L2CAP_CONN_RNR_SENT;
-		l2cap_send_sframe(pi, control);
+		chan->conn_state |= L2CAP_CONN_RNR_SENT;
+		l2cap_send_sframe(chan, control);
 		return;
 	}
 
-	if (l2cap_ertm_send(sk) > 0)
+	if (l2cap_ertm_send(chan) > 0)
 		return;
 
 	control |= L2CAP_SUPER_RCV_READY;
-	l2cap_send_sframe(pi, control);
+	l2cap_send_sframe(chan, control);
 }
 
-static void l2cap_send_srejtail(struct sock *sk)
+static void l2cap_send_srejtail(struct l2cap_chan *chan)
 {
 	struct srej_list *tail;
 	u16 control;
@@ -1173,10 +1201,10 @@
 	control = L2CAP_SUPER_SELECT_REJECT;
 	control |= L2CAP_CTRL_FINAL;
 
-	tail = list_entry(SREJ_LIST(sk)->prev, struct srej_list, list);
+	tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
 	control |= tail->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
 
-	l2cap_send_sframe(l2cap_pi(sk), control);
+	l2cap_send_sframe(chan, control);
 }
 
 static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, int len, int count, struct sk_buff *skb)
@@ -1313,9 +1341,9 @@
 	return skb;
 }
 
-int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, size_t len)
+int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
 {
-	struct l2cap_pinfo *pi = l2cap_pi(sk);
+	struct sock *sk = chan->sk;
 	struct sk_buff *skb;
 	struct sk_buff_head sar_queue;
 	u16 control;
@@ -1323,20 +1351,20 @@
 
 	skb_queue_head_init(&sar_queue);
 	control = L2CAP_SDU_START;
-	skb = l2cap_create_iframe_pdu(sk, msg, pi->remote_mps, control, len);
+	skb = l2cap_create_iframe_pdu(sk, msg, chan->remote_mps, control, len);
 	if (IS_ERR(skb))
 		return PTR_ERR(skb);
 
 	__skb_queue_tail(&sar_queue, skb);
-	len -= pi->remote_mps;
-	size += pi->remote_mps;
+	len -= chan->remote_mps;
+	size += chan->remote_mps;
 
 	while (len > 0) {
 		size_t buflen;
 
-		if (len > pi->remote_mps) {
+		if (len > chan->remote_mps) {
 			control = L2CAP_SDU_CONTINUE;
-			buflen = pi->remote_mps;
+			buflen = chan->remote_mps;
 		} else {
 			control = L2CAP_SDU_END;
 			buflen = len;
@@ -1352,9 +1380,9 @@
 		len -= buflen;
 		size += buflen;
 	}
-	skb_queue_splice_tail(&sar_queue, TX_QUEUE(sk));
-	if (sk->sk_send_head == NULL)
-		sk->sk_send_head = sar_queue.next;
+	skb_queue_splice_tail(&sar_queue, &chan->tx_q);
+	if (chan->tx_send_head == NULL)
+		chan->tx_send_head = sar_queue.next;
 
 	return size;
 }
@@ -1385,14 +1413,14 @@
 /* Copy frame to all raw sockets on that connection */
 static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
 {
-	struct l2cap_chan_list *l = &conn->chan_list;
 	struct sk_buff *nskb;
-	struct sock *sk;
+	struct l2cap_chan *chan;
 
 	BT_DBG("conn %p", conn);
 
-	read_lock(&l->lock);
-	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
+	read_lock(&conn->chan_lock);
+	list_for_each_entry(chan, &conn->chan_l, list) {
+		struct sock *sk = chan->sk;
 		if (sk->sk_type != SOCK_RAW)
 			continue;
 
@@ -1406,7 +1434,7 @@
 		if (sock_queue_rcv_skb(sk, nskb))
 			kfree_skb(nskb);
 	}
-	read_unlock(&l->lock);
+	read_unlock(&conn->chan_lock);
 }
 
 /* ---- L2CAP signalling commands ---- */
@@ -1538,32 +1566,35 @@
 
 static void l2cap_ack_timeout(unsigned long arg)
 {
-	struct sock *sk = (void *) arg;
+	struct l2cap_chan *chan = (void *) arg;
 
-	bh_lock_sock(sk);
-	l2cap_send_ack(l2cap_pi(sk));
-	bh_unlock_sock(sk);
+	bh_lock_sock(chan->sk);
+	l2cap_send_ack(chan);
+	bh_unlock_sock(chan->sk);
 }
 
-static inline void l2cap_ertm_init(struct sock *sk)
+static inline void l2cap_ertm_init(struct l2cap_chan *chan)
 {
-	l2cap_pi(sk)->expected_ack_seq = 0;
-	l2cap_pi(sk)->unacked_frames = 0;
-	l2cap_pi(sk)->buffer_seq = 0;
-	l2cap_pi(sk)->num_acked = 0;
-	l2cap_pi(sk)->frames_sent = 0;
+	struct sock *sk = chan->sk;
 
-	setup_timer(&l2cap_pi(sk)->retrans_timer,
-			l2cap_retrans_timeout, (unsigned long) sk);
-	setup_timer(&l2cap_pi(sk)->monitor_timer,
-			l2cap_monitor_timeout, (unsigned long) sk);
-	setup_timer(&l2cap_pi(sk)->ack_timer,
-			l2cap_ack_timeout, (unsigned long) sk);
+	chan->expected_ack_seq = 0;
+	chan->unacked_frames = 0;
+	chan->buffer_seq = 0;
+	chan->num_acked = 0;
+	chan->frames_sent = 0;
 
-	__skb_queue_head_init(SREJ_QUEUE(sk));
-	__skb_queue_head_init(BUSY_QUEUE(sk));
+	setup_timer(&chan->retrans_timer, l2cap_retrans_timeout,
+							(unsigned long) chan);
+	setup_timer(&chan->monitor_timer, l2cap_monitor_timeout,
+							(unsigned long) chan);
+	setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan);
 
-	INIT_WORK(&l2cap_pi(sk)->busy_work, l2cap_busy_work);
+	skb_queue_head_init(&chan->srej_q);
+	skb_queue_head_init(&chan->busy_q);
+
+	INIT_LIST_HEAD(&chan->srej_l);
+
+	INIT_WORK(&chan->busy_work, l2cap_busy_work);
 
 	sk->sk_backlog_rcv = l2cap_ertm_data_rcv;
 }
@@ -1581,16 +1612,16 @@
 	}
 }
 
-int l2cap_build_conf_req(struct sock *sk, void *data)
+static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
 {
-	struct l2cap_pinfo *pi = l2cap_pi(sk);
+	struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
 	struct l2cap_conf_req *req = data;
 	struct l2cap_conf_rfc rfc = { .mode = pi->mode };
 	void *ptr = req->data;
 
-	BT_DBG("sk %p", sk);
+	BT_DBG("chan %p", chan);
 
-	if (pi->num_conf_req || pi->num_conf_rsp)
+	if (chan->num_conf_req || chan->num_conf_rsp)
 		goto done;
 
 	switch (pi->mode) {
@@ -1679,20 +1710,20 @@
 	return ptr - data;
 }
 
-static int l2cap_parse_conf_req(struct sock *sk, void *data)
+static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
 {
-	struct l2cap_pinfo *pi = l2cap_pi(sk);
+	struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
 	struct l2cap_conf_rsp *rsp = data;
 	void *ptr = rsp->data;
-	void *req = pi->conf_req;
-	int len = pi->conf_len;
+	void *req = chan->conf_req;
+	int len = chan->conf_len;
 	int type, hint, olen;
 	unsigned long val;
 	struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
 	u16 mtu = L2CAP_DEFAULT_MTU;
 	u16 result = L2CAP_CONF_SUCCESS;
 
-	BT_DBG("sk %p", sk);
+	BT_DBG("chan %p", chan);
 
 	while (len >= L2CAP_CONF_OPT_SIZE) {
 		len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
@@ -1733,7 +1764,7 @@
 		}
 	}
 
-	if (pi->num_conf_rsp || pi->num_conf_req > 1)
+	if (chan->num_conf_rsp || chan->num_conf_req > 1)
 		goto done;
 
 	switch (pi->mode) {
@@ -1756,7 +1787,7 @@
 		result = L2CAP_CONF_UNACCEPT;
 		rfc.mode = pi->mode;
 
-		if (pi->num_conf_rsp == 1)
+		if (chan->num_conf_rsp == 1)
 			return -ECONNREFUSED;
 
 		l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
@@ -1783,13 +1814,13 @@
 			break;
 
 		case L2CAP_MODE_ERTM:
-			pi->remote_tx_win = rfc.txwin_size;
-			pi->remote_max_tx = rfc.max_transmit;
+			chan->remote_tx_win = rfc.txwin_size;
+			chan->remote_max_tx = rfc.max_transmit;
 
 			if (le16_to_cpu(rfc.max_pdu_size) > pi->conn->mtu - 10)
 				rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10);
 
-			pi->remote_mps = le16_to_cpu(rfc.max_pdu_size);
+			chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
 
 			rfc.retrans_timeout =
 				le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
@@ -1807,7 +1838,7 @@
 			if (le16_to_cpu(rfc.max_pdu_size) > pi->conn->mtu - 10)
 				rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10);
 
-			pi->remote_mps = le16_to_cpu(rfc.max_pdu_size);
+			chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
 
 			pi->conf_state |= L2CAP_CONF_MODE_DONE;
 
@@ -1916,6 +1947,31 @@
 	return ptr - data;
 }
 
+void __l2cap_connect_rsp_defer(struct sock *sk)
+{
+	struct l2cap_conn_rsp rsp;
+	struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+	u8 buf[128];
+
+	sk->sk_state = BT_CONFIG;
+
+	rsp.scid   = cpu_to_le16(l2cap_pi(sk)->dcid);
+	rsp.dcid   = cpu_to_le16(l2cap_pi(sk)->scid);
+	rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
+	rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
+	l2cap_send_cmd(conn, chan->ident,
+				L2CAP_CONN_RSP, sizeof(rsp), &rsp);
+
+	if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)
+		return;
+
+	l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
+	l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
+			l2cap_build_conf_req(chan, buf), buf);
+	chan->num_conf_req++;
+}
+
 static void l2cap_conf_rfc_get(struct sock *sk, void *rsp, int len)
 {
 	struct l2cap_pinfo *pi = l2cap_pi(sk);
@@ -1973,9 +2029,9 @@
 
 static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
 {
-	struct l2cap_chan_list *list = &conn->chan_list;
 	struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
 	struct l2cap_conn_rsp rsp;
+	struct l2cap_chan *chan = NULL;
 	struct sock *parent, *sk = NULL;
 	int result, status = L2CAP_CS_NO_INFO;
 
@@ -2013,11 +2069,17 @@
 	if (!sk)
 		goto response;
 
-	write_lock_bh(&list->lock);
+	chan = l2cap_chan_alloc(sk);
+	if (!chan) {
+		l2cap_sock_kill(sk);
+		goto response;
+	}
+
+	write_lock_bh(&conn->chan_lock);
 
 	/* Check if we already have channel with that dcid */
-	if (__l2cap_get_chan_by_dcid(list, scid)) {
-		write_unlock_bh(&list->lock);
+	if (__l2cap_get_chan_by_dcid(conn, scid)) {
+		write_unlock_bh(&conn->chan_lock);
 		sock_set_flag(sk, SOCK_ZAPPED);
 		l2cap_sock_kill(sk);
 		goto response;
@@ -2033,12 +2095,15 @@
 
 	bt_accept_enqueue(parent, sk);
 
-	__l2cap_chan_add(conn, sk);
+	__l2cap_chan_add(conn, chan);
+
+	l2cap_pi(sk)->chan = chan;
+
 	dcid = l2cap_pi(sk)->scid;
 
 	l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
 
-	l2cap_pi(sk)->ident = cmd->ident;
+	chan->ident = cmd->ident;
 
 	if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
 		if (l2cap_check_security(sk)) {
@@ -2063,7 +2128,7 @@
 		status = L2CAP_CS_NO_INFO;
 	}
 
-	write_unlock_bh(&list->lock);
+	write_unlock_bh(&conn->chan_lock);
 
 response:
 	bh_unlock_sock(parent);
@@ -2089,13 +2154,13 @@
 					L2CAP_INFO_REQ, sizeof(info), &info);
 	}
 
-	if (sk && !(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) &&
+	if (chan && !(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) &&
 				result == L2CAP_CR_SUCCESS) {
 		u8 buf[128];
 		l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
 		l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
-					l2cap_build_conf_req(sk, buf), buf);
-		l2cap_pi(sk)->num_conf_req++;
+					l2cap_build_conf_req(chan, buf), buf);
+		chan->num_conf_req++;
 	}
 
 	return 0;
@@ -2105,6 +2170,7 @@
 {
 	struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
 	u16 scid, dcid, result, status;
+	struct l2cap_chan *chan;
 	struct sock *sk;
 	u8 req[128];
 
@@ -2116,19 +2182,21 @@
 	BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
 
 	if (scid) {
-		sk = l2cap_get_chan_by_scid(&conn->chan_list, scid);
-		if (!sk)
+		chan = l2cap_get_chan_by_scid(conn, scid);
+		if (!chan)
 			return -EFAULT;
 	} else {
-		sk = l2cap_get_chan_by_ident(&conn->chan_list, cmd->ident);
-		if (!sk)
+		chan = l2cap_get_chan_by_ident(conn, cmd->ident);
+		if (!chan)
 			return -EFAULT;
 	}
 
+	sk = chan->sk;
+
 	switch (result) {
 	case L2CAP_CR_SUCCESS:
 		sk->sk_state = BT_CONFIG;
-		l2cap_pi(sk)->ident = 0;
+		chan->ident = 0;
 		l2cap_pi(sk)->dcid = dcid;
 		l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_CONNECT_PEND;
 
@@ -2138,8 +2206,8 @@
 		l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
 
 		l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
-					l2cap_build_conf_req(sk, req), req);
-		l2cap_pi(sk)->num_conf_req++;
+					l2cap_build_conf_req(chan, req), req);
+		chan->num_conf_req++;
 		break;
 
 	case L2CAP_CR_PEND:
@@ -2155,7 +2223,7 @@
 			break;
 		}
 
-		l2cap_chan_del(sk, ECONNREFUSED);
+		l2cap_chan_del(chan, ECONNREFUSED);
 		break;
 	}
 
@@ -2179,6 +2247,7 @@
 	struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
 	u16 dcid, flags;
 	u8 rsp[64];
+	struct l2cap_chan *chan;
 	struct sock *sk;
 	int len;
 
@@ -2187,10 +2256,12 @@
 
 	BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
 
-	sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid);
-	if (!sk)
+	chan = l2cap_get_chan_by_scid(conn, dcid);
+	if (!chan)
 		return -ENOENT;
 
+	sk = chan->sk;
+
 	if (sk->sk_state != BT_CONFIG) {
 		struct l2cap_cmd_rej rej;
 
@@ -2202,7 +2273,7 @@
 
 	/* Reject if config buffer is too small. */
 	len = cmd_len - sizeof(*req);
-	if (l2cap_pi(sk)->conf_len + len > sizeof(l2cap_pi(sk)->conf_req)) {
+	if (chan->conf_len + len > sizeof(chan->conf_req)) {
 		l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
 				l2cap_build_conf_rsp(sk, rsp,
 					L2CAP_CONF_REJECT, flags), rsp);
@@ -2210,8 +2281,8 @@
 	}
 
 	/* Store config. */
-	memcpy(l2cap_pi(sk)->conf_req + l2cap_pi(sk)->conf_len, req->data, len);
-	l2cap_pi(sk)->conf_len += len;
+	memcpy(chan->conf_req + chan->conf_len, req->data, len);
+	chan->conf_len += len;
 
 	if (flags & 0x0001) {
 		/* Incomplete config. Send empty response. */
@@ -2222,17 +2293,17 @@
 	}
 
 	/* Complete config. */
-	len = l2cap_parse_conf_req(sk, rsp);
+	len = l2cap_parse_conf_req(chan, rsp);
 	if (len < 0) {
-		l2cap_send_disconn_req(conn, sk, ECONNRESET);
+		l2cap_send_disconn_req(conn, chan, ECONNRESET);
 		goto unlock;
 	}
 
 	l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
-	l2cap_pi(sk)->num_conf_rsp++;
+	chan->num_conf_rsp++;
 
 	/* Reset config buffer. */
-	l2cap_pi(sk)->conf_len = 0;
+	chan->conf_len = 0;
 
 	if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE))
 		goto unlock;
@@ -2242,11 +2313,11 @@
 
 		sk->sk_state = BT_CONNECTED;
 
-		l2cap_pi(sk)->next_tx_seq = 0;
-		l2cap_pi(sk)->expected_tx_seq = 0;
-		__skb_queue_head_init(TX_QUEUE(sk));
+		chan->next_tx_seq = 0;
+		chan->expected_tx_seq = 0;
+		skb_queue_head_init(&chan->tx_q);
 		if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM)
-			l2cap_ertm_init(sk);
+			l2cap_ertm_init(chan);
 
 		l2cap_chan_ready(sk);
 		goto unlock;
@@ -2256,8 +2327,8 @@
 		u8 buf[64];
 		l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
 		l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
-					l2cap_build_conf_req(sk, buf), buf);
-		l2cap_pi(sk)->num_conf_req++;
+					l2cap_build_conf_req(chan, buf), buf);
+		chan->num_conf_req++;
 	}
 
 unlock:
@@ -2269,6 +2340,7 @@
 {
 	struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
 	u16 scid, flags, result;
+	struct l2cap_chan *chan;
 	struct sock *sk;
 	int len = cmd->len - sizeof(*rsp);
 
@@ -2279,21 +2351,23 @@
 	BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x",
 			scid, flags, result);
 
-	sk = l2cap_get_chan_by_scid(&conn->chan_list, scid);
-	if (!sk)
+	chan = l2cap_get_chan_by_scid(conn, scid);
+	if (!chan)
 		return 0;
 
+	sk = chan->sk;
+
 	switch (result) {
 	case L2CAP_CONF_SUCCESS:
 		l2cap_conf_rfc_get(sk, rsp->data, len);
 		break;
 
 	case L2CAP_CONF_UNACCEPT:
-		if (l2cap_pi(sk)->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
+		if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
 			char req[64];
 
 			if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
-				l2cap_send_disconn_req(conn, sk, ECONNRESET);
+				l2cap_send_disconn_req(conn, chan, ECONNRESET);
 				goto done;
 			}
 
@@ -2302,13 +2376,13 @@
 			len = l2cap_parse_conf_rsp(sk, rsp->data,
 							len, req, &result);
 			if (len < 0) {
-				l2cap_send_disconn_req(conn, sk, ECONNRESET);
+				l2cap_send_disconn_req(conn, chan, ECONNRESET);
 				goto done;
 			}
 
 			l2cap_send_cmd(conn, l2cap_get_ident(conn),
 						L2CAP_CONF_REQ, len, req);
-			l2cap_pi(sk)->num_conf_req++;
+			chan->num_conf_req++;
 			if (result != L2CAP_CONF_SUCCESS)
 				goto done;
 			break;
@@ -2317,7 +2391,7 @@
 	default:
 		sk->sk_err = ECONNRESET;
 		l2cap_sock_set_timer(sk, HZ * 5);
-		l2cap_send_disconn_req(conn, sk, ECONNRESET);
+		l2cap_send_disconn_req(conn, chan, ECONNRESET);
 		goto done;
 	}
 
@@ -2330,11 +2404,11 @@
 		set_default_fcs(l2cap_pi(sk));
 
 		sk->sk_state = BT_CONNECTED;
-		l2cap_pi(sk)->next_tx_seq = 0;
-		l2cap_pi(sk)->expected_tx_seq = 0;
-		__skb_queue_head_init(TX_QUEUE(sk));
+		chan->next_tx_seq = 0;
+		chan->expected_tx_seq = 0;
+		skb_queue_head_init(&chan->tx_q);
 		if (l2cap_pi(sk)->mode ==  L2CAP_MODE_ERTM)
-			l2cap_ertm_init(sk);
+			l2cap_ertm_init(chan);
 
 		l2cap_chan_ready(sk);
 	}
@@ -2349,6 +2423,7 @@
 	struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
 	struct l2cap_disconn_rsp rsp;
 	u16 dcid, scid;
+	struct l2cap_chan *chan;
 	struct sock *sk;
 
 	scid = __le16_to_cpu(req->scid);
@@ -2356,10 +2431,12 @@
 
 	BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
 
-	sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid);
-	if (!sk)
+	chan = l2cap_get_chan_by_scid(conn, dcid);
+	if (!chan)
 		return 0;
 
+	sk = chan->sk;
+
 	rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
 	rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
 	l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
@@ -2375,7 +2452,7 @@
 		return 0;
 	}
 
-	l2cap_chan_del(sk, ECONNRESET);
+	l2cap_chan_del(chan, ECONNRESET);
 	bh_unlock_sock(sk);
 
 	l2cap_sock_kill(sk);
@@ -2386,6 +2463,7 @@
 {
 	struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
 	u16 dcid, scid;
+	struct l2cap_chan *chan;
 	struct sock *sk;
 
 	scid = __le16_to_cpu(rsp->scid);
@@ -2393,10 +2471,12 @@
 
 	BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
 
-	sk = l2cap_get_chan_by_scid(&conn->chan_list, scid);
-	if (!sk)
+	chan = l2cap_get_chan_by_scid(conn, scid);
+	if (!chan)
 		return 0;
 
+	sk = chan->sk;
+
 	/* don't delete l2cap channel if sk is owned by user */
 	if (sock_owned_by_user(sk)) {
 		sk->sk_state = BT_DISCONN;
@@ -2406,7 +2486,7 @@
 		return 0;
 	}
 
-	l2cap_chan_del(sk, 0);
+	l2cap_chan_del(chan, 0);
 	bh_unlock_sock(sk);
 
 	l2cap_sock_kill(sk);
@@ -2709,49 +2789,47 @@
 	return 0;
 }
 
-static inline void l2cap_send_i_or_rr_or_rnr(struct sock *sk)
+static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
 {
-	struct l2cap_pinfo *pi = l2cap_pi(sk);
 	u16 control = 0;
 
-	pi->frames_sent = 0;
+	chan->frames_sent = 0;
 
-	control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+	control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
 
-	if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
+	if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
 		control |= L2CAP_SUPER_RCV_NOT_READY;
-		l2cap_send_sframe(pi, control);
-		pi->conn_state |= L2CAP_CONN_RNR_SENT;
+		l2cap_send_sframe(chan, control);
+		chan->conn_state |= L2CAP_CONN_RNR_SENT;
 	}
 
-	if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY)
-		l2cap_retransmit_frames(sk);
+	if (chan->conn_state & L2CAP_CONN_REMOTE_BUSY)
+		l2cap_retransmit_frames(chan);
 
-	l2cap_ertm_send(sk);
+	l2cap_ertm_send(chan);
 
-	if (!(pi->conn_state & L2CAP_CONN_LOCAL_BUSY) &&
-			pi->frames_sent == 0) {
+	if (!(chan->conn_state & L2CAP_CONN_LOCAL_BUSY) &&
+			chan->frames_sent == 0) {
 		control |= L2CAP_SUPER_RCV_READY;
-		l2cap_send_sframe(pi, control);
+		l2cap_send_sframe(chan, control);
 	}
 }
 
-static int l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_seq, u8 sar)
+static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, u8 tx_seq, u8 sar)
 {
 	struct sk_buff *next_skb;
-	struct l2cap_pinfo *pi = l2cap_pi(sk);
 	int tx_seq_offset, next_tx_seq_offset;
 
 	bt_cb(skb)->tx_seq = tx_seq;
 	bt_cb(skb)->sar = sar;
 
-	next_skb = skb_peek(SREJ_QUEUE(sk));
+	next_skb = skb_peek(&chan->srej_q);
 	if (!next_skb) {
-		__skb_queue_tail(SREJ_QUEUE(sk), skb);
+		__skb_queue_tail(&chan->srej_q, skb);
 		return 0;
 	}
 
-	tx_seq_offset = (tx_seq - pi->buffer_seq) % 64;
+	tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
 	if (tx_seq_offset < 0)
 		tx_seq_offset += 64;
 
@@ -2760,53 +2838,53 @@
 			return -EINVAL;
 
 		next_tx_seq_offset = (bt_cb(next_skb)->tx_seq -
-						pi->buffer_seq) % 64;
+						chan->buffer_seq) % 64;
 		if (next_tx_seq_offset < 0)
 			next_tx_seq_offset += 64;
 
 		if (next_tx_seq_offset > tx_seq_offset) {
-			__skb_queue_before(SREJ_QUEUE(sk), next_skb, skb);
+			__skb_queue_before(&chan->srej_q, next_skb, skb);
 			return 0;
 		}
 
-		if (skb_queue_is_last(SREJ_QUEUE(sk), next_skb))
+		if (skb_queue_is_last(&chan->srej_q, next_skb))
 			break;
 
-	} while ((next_skb = skb_queue_next(SREJ_QUEUE(sk), next_skb)));
+	} while ((next_skb = skb_queue_next(&chan->srej_q, next_skb)));
 
-	__skb_queue_tail(SREJ_QUEUE(sk), skb);
+	__skb_queue_tail(&chan->srej_q, skb);
 
 	return 0;
 }
 
-static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control)
+static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
 {
-	struct l2cap_pinfo *pi = l2cap_pi(sk);
+	struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
 	struct sk_buff *_skb;
 	int err;
 
 	switch (control & L2CAP_CTRL_SAR) {
 	case L2CAP_SDU_UNSEGMENTED:
-		if (pi->conn_state & L2CAP_CONN_SAR_SDU)
+		if (chan->conn_state & L2CAP_CONN_SAR_SDU)
 			goto drop;
 
-		err = sock_queue_rcv_skb(sk, skb);
+		err = sock_queue_rcv_skb(chan->sk, skb);
 		if (!err)
 			return err;
 
 		break;
 
 	case L2CAP_SDU_START:
-		if (pi->conn_state & L2CAP_CONN_SAR_SDU)
+		if (chan->conn_state & L2CAP_CONN_SAR_SDU)
 			goto drop;
 
-		pi->sdu_len = get_unaligned_le16(skb->data);
+		chan->sdu_len = get_unaligned_le16(skb->data);
 
-		if (pi->sdu_len > pi->imtu)
+		if (chan->sdu_len > pi->imtu)
 			goto disconnect;
 
-		pi->sdu = bt_skb_alloc(pi->sdu_len, GFP_ATOMIC);
-		if (!pi->sdu)
+		chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC);
+		if (!chan->sdu)
 			return -ENOMEM;
 
 		/* pull sdu_len bytes only after alloc, because of Local Busy
@@ -2814,63 +2892,63 @@
 		 * only once, i.e., when alloc does not fail */
 		skb_pull(skb, 2);
 
-		memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
+		memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
 
-		pi->conn_state |= L2CAP_CONN_SAR_SDU;
-		pi->partial_sdu_len = skb->len;
+		chan->conn_state |= L2CAP_CONN_SAR_SDU;
+		chan->partial_sdu_len = skb->len;
 		break;
 
 	case L2CAP_SDU_CONTINUE:
-		if (!(pi->conn_state & L2CAP_CONN_SAR_SDU))
+		if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
 			goto disconnect;
 
-		if (!pi->sdu)
+		if (!chan->sdu)
 			goto disconnect;
 
-		pi->partial_sdu_len += skb->len;
-		if (pi->partial_sdu_len > pi->sdu_len)
+		chan->partial_sdu_len += skb->len;
+		if (chan->partial_sdu_len > chan->sdu_len)
 			goto drop;
 
-		memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
+		memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
 
 		break;
 
 	case L2CAP_SDU_END:
-		if (!(pi->conn_state & L2CAP_CONN_SAR_SDU))
+		if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
 			goto disconnect;
 
-		if (!pi->sdu)
+		if (!chan->sdu)
 			goto disconnect;
 
-		if (!(pi->conn_state & L2CAP_CONN_SAR_RETRY)) {
-			pi->partial_sdu_len += skb->len;
+		if (!(chan->conn_state & L2CAP_CONN_SAR_RETRY)) {
+			chan->partial_sdu_len += skb->len;
 
-			if (pi->partial_sdu_len > pi->imtu)
+			if (chan->partial_sdu_len > pi->imtu)
 				goto drop;
 
-			if (pi->partial_sdu_len != pi->sdu_len)
+			if (chan->partial_sdu_len != chan->sdu_len)
 				goto drop;
 
-			memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
+			memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
 		}
 
-		_skb = skb_clone(pi->sdu, GFP_ATOMIC);
+		_skb = skb_clone(chan->sdu, GFP_ATOMIC);
 		if (!_skb) {
-			pi->conn_state |= L2CAP_CONN_SAR_RETRY;
+			chan->conn_state |= L2CAP_CONN_SAR_RETRY;
 			return -ENOMEM;
 		}
 
-		err = sock_queue_rcv_skb(sk, _skb);
+		err = sock_queue_rcv_skb(chan->sk, _skb);
 		if (err < 0) {
 			kfree_skb(_skb);
-			pi->conn_state |= L2CAP_CONN_SAR_RETRY;
+			chan->conn_state |= L2CAP_CONN_SAR_RETRY;
 			return err;
 		}
 
-		pi->conn_state &= ~L2CAP_CONN_SAR_RETRY;
-		pi->conn_state &= ~L2CAP_CONN_SAR_SDU;
+		chan->conn_state &= ~L2CAP_CONN_SAR_RETRY;
+		chan->conn_state &= ~L2CAP_CONN_SAR_SDU;
 
-		kfree_skb(pi->sdu);
+		kfree_skb(chan->sdu);
 		break;
 	}
 
@@ -2878,51 +2956,50 @@
 	return 0;
 
 drop:
-	kfree_skb(pi->sdu);
-	pi->sdu = NULL;
+	kfree_skb(chan->sdu);
+	chan->sdu = NULL;
 
 disconnect:
-	l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
+	l2cap_send_disconn_req(pi->conn, chan, ECONNRESET);
 	kfree_skb(skb);
 	return 0;
 }
 
-static int l2cap_try_push_rx_skb(struct sock *sk)
+static int l2cap_try_push_rx_skb(struct l2cap_chan *chan)
 {
-	struct l2cap_pinfo *pi = l2cap_pi(sk);
 	struct sk_buff *skb;
 	u16 control;
 	int err;
 
-	while ((skb = skb_dequeue(BUSY_QUEUE(sk)))) {
+	while ((skb = skb_dequeue(&chan->busy_q))) {
 		control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
-		err = l2cap_ertm_reassembly_sdu(sk, skb, control);
+		err = l2cap_ertm_reassembly_sdu(chan, skb, control);
 		if (err < 0) {
-			skb_queue_head(BUSY_QUEUE(sk), skb);
+			skb_queue_head(&chan->busy_q, skb);
 			return -EBUSY;
 		}
 
-		pi->buffer_seq = (pi->buffer_seq + 1) % 64;
+		chan->buffer_seq = (chan->buffer_seq + 1) % 64;
 	}
 
-	if (!(pi->conn_state & L2CAP_CONN_RNR_SENT))
+	if (!(chan->conn_state & L2CAP_CONN_RNR_SENT))
 		goto done;
 
-	control = pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+	control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
 	control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL;
-	l2cap_send_sframe(pi, control);
-	l2cap_pi(sk)->retry_count = 1;
+	l2cap_send_sframe(chan, control);
+	chan->retry_count = 1;
 
-	del_timer(&pi->retrans_timer);
+	del_timer(&chan->retrans_timer);
 	__mod_monitor_timer();
 
-	l2cap_pi(sk)->conn_state |= L2CAP_CONN_WAIT_F;
+	chan->conn_state |= L2CAP_CONN_WAIT_F;
 
 done:
-	pi->conn_state &= ~L2CAP_CONN_LOCAL_BUSY;
-	pi->conn_state &= ~L2CAP_CONN_RNR_SENT;
+	chan->conn_state &= ~L2CAP_CONN_LOCAL_BUSY;
+	chan->conn_state &= ~L2CAP_CONN_RNR_SENT;
 
-	BT_DBG("sk %p, Exit local busy", sk);
+	BT_DBG("chan %p, Exit local busy", chan);
 
 	return 0;
 }
@@ -2930,21 +3007,21 @@
 static void l2cap_busy_work(struct work_struct *work)
 {
 	DECLARE_WAITQUEUE(wait, current);
-	struct l2cap_pinfo *pi =
-		container_of(work, struct l2cap_pinfo, busy_work);
-	struct sock *sk = (struct sock *)pi;
+	struct l2cap_chan *chan =
+		container_of(work, struct l2cap_chan, busy_work);
+	struct sock *sk = chan->sk;
 	int n_tries = 0, timeo = HZ/5, err;
 	struct sk_buff *skb;
 
 	lock_sock(sk);
 
 	add_wait_queue(sk_sleep(sk), &wait);
-	while ((skb = skb_peek(BUSY_QUEUE(sk)))) {
+	while ((skb = skb_peek(&chan->busy_q))) {
 		set_current_state(TASK_INTERRUPTIBLE);
 
 		if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) {
 			err = -EBUSY;
-			l2cap_send_disconn_req(pi->conn, sk, EBUSY);
+			l2cap_send_disconn_req(l2cap_pi(sk)->conn, chan, EBUSY);
 			break;
 		}
 
@@ -2964,7 +3041,7 @@
 		if (err)
 			break;
 
-		if (l2cap_try_push_rx_skb(sk) == 0)
+		if (l2cap_try_push_rx_skb(chan) == 0)
 			break;
 	}
 
@@ -2974,48 +3051,47 @@
 	release_sock(sk);
 }
 
-static int l2cap_push_rx_skb(struct sock *sk, struct sk_buff *skb, u16 control)
+static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
 {
-	struct l2cap_pinfo *pi = l2cap_pi(sk);
 	int sctrl, err;
 
-	if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
+	if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
 		bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
-		__skb_queue_tail(BUSY_QUEUE(sk), skb);
-		return l2cap_try_push_rx_skb(sk);
+		__skb_queue_tail(&chan->busy_q, skb);
+		return l2cap_try_push_rx_skb(chan);
 
 
 	}
 
-	err = l2cap_ertm_reassembly_sdu(sk, skb, control);
+	err = l2cap_ertm_reassembly_sdu(chan, skb, control);
 	if (err >= 0) {
-		pi->buffer_seq = (pi->buffer_seq + 1) % 64;
+		chan->buffer_seq = (chan->buffer_seq + 1) % 64;
 		return err;
 	}
 
 	/* Busy Condition */
-	BT_DBG("sk %p, Enter local busy", sk);
+	BT_DBG("chan %p, Enter local busy", chan);
 
-	pi->conn_state |= L2CAP_CONN_LOCAL_BUSY;
+	chan->conn_state |= L2CAP_CONN_LOCAL_BUSY;
 	bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
-	__skb_queue_tail(BUSY_QUEUE(sk), skb);
+	__skb_queue_tail(&chan->busy_q, skb);
 
-	sctrl = pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+	sctrl = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
 	sctrl |= L2CAP_SUPER_RCV_NOT_READY;
-	l2cap_send_sframe(pi, sctrl);
+	l2cap_send_sframe(chan, sctrl);
 
-	pi->conn_state |= L2CAP_CONN_RNR_SENT;
+	chan->conn_state |= L2CAP_CONN_RNR_SENT;
 
-	del_timer(&pi->ack_timer);
+	del_timer(&chan->ack_timer);
 
-	queue_work(_busy_wq, &pi->busy_work);
+	queue_work(_busy_wq, &chan->busy_work);
 
 	return err;
 }
 
-static int l2cap_streaming_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control)
+static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
 {
-	struct l2cap_pinfo *pi = l2cap_pi(sk);
+	struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
 	struct sk_buff *_skb;
 	int err = -EINVAL;
 
@@ -3026,80 +3102,80 @@
 
 	switch (control & L2CAP_CTRL_SAR) {
 	case L2CAP_SDU_UNSEGMENTED:
-		if (pi->conn_state & L2CAP_CONN_SAR_SDU) {
-			kfree_skb(pi->sdu);
+		if (chan->conn_state & L2CAP_CONN_SAR_SDU) {
+			kfree_skb(chan->sdu);
 			break;
 		}
 
-		err = sock_queue_rcv_skb(sk, skb);
+		err = sock_queue_rcv_skb(chan->sk, skb);
 		if (!err)
 			return 0;
 
 		break;
 
 	case L2CAP_SDU_START:
-		if (pi->conn_state & L2CAP_CONN_SAR_SDU) {
-			kfree_skb(pi->sdu);
+		if (chan->conn_state & L2CAP_CONN_SAR_SDU) {
+			kfree_skb(chan->sdu);
 			break;
 		}
 
-		pi->sdu_len = get_unaligned_le16(skb->data);
+		chan->sdu_len = get_unaligned_le16(skb->data);
 		skb_pull(skb, 2);
 
-		if (pi->sdu_len > pi->imtu) {
+		if (chan->sdu_len > pi->imtu) {
 			err = -EMSGSIZE;
 			break;
 		}
 
-		pi->sdu = bt_skb_alloc(pi->sdu_len, GFP_ATOMIC);
-		if (!pi->sdu) {
+		chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC);
+		if (!chan->sdu) {
 			err = -ENOMEM;
 			break;
 		}
 
-		memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
+		memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
 
-		pi->conn_state |= L2CAP_CONN_SAR_SDU;
-		pi->partial_sdu_len = skb->len;
+		chan->conn_state |= L2CAP_CONN_SAR_SDU;
+		chan->partial_sdu_len = skb->len;
 		err = 0;
 		break;
 
 	case L2CAP_SDU_CONTINUE:
-		if (!(pi->conn_state & L2CAP_CONN_SAR_SDU))
+		if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
 			break;
 
-		memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
+		memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
 
-		pi->partial_sdu_len += skb->len;
-		if (pi->partial_sdu_len > pi->sdu_len)
-			kfree_skb(pi->sdu);
+		chan->partial_sdu_len += skb->len;
+		if (chan->partial_sdu_len > chan->sdu_len)
+			kfree_skb(chan->sdu);
 		else
 			err = 0;
 
 		break;
 
 	case L2CAP_SDU_END:
-		if (!(pi->conn_state & L2CAP_CONN_SAR_SDU))
+		if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
 			break;
 
-		memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
+		memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
 
-		pi->conn_state &= ~L2CAP_CONN_SAR_SDU;
-		pi->partial_sdu_len += skb->len;
+		chan->conn_state &= ~L2CAP_CONN_SAR_SDU;
+		chan->partial_sdu_len += skb->len;
 
-		if (pi->partial_sdu_len > pi->imtu)
+		if (chan->partial_sdu_len > pi->imtu)
 			goto drop;
 
-		if (pi->partial_sdu_len == pi->sdu_len) {
-			_skb = skb_clone(pi->sdu, GFP_ATOMIC);
-			err = sock_queue_rcv_skb(sk, _skb);
+		if (chan->partial_sdu_len == chan->sdu_len) {
+			_skb = skb_clone(chan->sdu, GFP_ATOMIC);
+			err = sock_queue_rcv_skb(chan->sk, _skb);
 			if (err < 0)
 				kfree_skb(_skb);
 		}
 		err = 0;
 
 drop:
-		kfree_skb(pi->sdu);
+		kfree_skb(chan->sdu);
 		break;
 	}
 
@@ -3107,31 +3183,30 @@
 	return err;
 }
 
-static void l2cap_check_srej_gap(struct sock *sk, u8 tx_seq)
+static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
 {
 	struct sk_buff *skb;
 	u16 control;
 
-	while ((skb = skb_peek(SREJ_QUEUE(sk)))) {
+	while ((skb = skb_peek(&chan->srej_q))) {
 		if (bt_cb(skb)->tx_seq != tx_seq)
 			break;
 
-		skb = skb_dequeue(SREJ_QUEUE(sk));
+		skb = skb_dequeue(&chan->srej_q);
 		control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
-		l2cap_ertm_reassembly_sdu(sk, skb, control);
-		l2cap_pi(sk)->buffer_seq_srej =
-			(l2cap_pi(sk)->buffer_seq_srej + 1) % 64;
+		l2cap_ertm_reassembly_sdu(chan, skb, control);
+		chan->buffer_seq_srej =
+			(chan->buffer_seq_srej + 1) % 64;
 		tx_seq = (tx_seq + 1) % 64;
 	}
 }
 
-static void l2cap_resend_srejframe(struct sock *sk, u8 tx_seq)
+static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq)
 {
-	struct l2cap_pinfo *pi = l2cap_pi(sk);
 	struct srej_list *l, *tmp;
 	u16 control;
 
-	list_for_each_entry_safe(l, tmp, SREJ_LIST(sk), list) {
+	list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
 		if (l->tx_seq == tx_seq) {
 			list_del(&l->list);
 			kfree(l);
@@ -3139,34 +3214,33 @@
 		}
 		control = L2CAP_SUPER_SELECT_REJECT;
 		control |= l->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
-		l2cap_send_sframe(pi, control);
+		l2cap_send_sframe(chan, control);
 		list_del(&l->list);
-		list_add_tail(&l->list, SREJ_LIST(sk));
+		list_add_tail(&l->list, &chan->srej_l);
 	}
 }
 
-static void l2cap_send_srejframe(struct sock *sk, u8 tx_seq)
+static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq)
 {
-	struct l2cap_pinfo *pi = l2cap_pi(sk);
 	struct srej_list *new;
 	u16 control;
 
-	while (tx_seq != pi->expected_tx_seq) {
+	while (tx_seq != chan->expected_tx_seq) {
 		control = L2CAP_SUPER_SELECT_REJECT;
-		control |= pi->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
-		l2cap_send_sframe(pi, control);
+		control |= chan->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+		l2cap_send_sframe(chan, control);
 
 		new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
-		new->tx_seq = pi->expected_tx_seq;
-		pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64;
-		list_add_tail(&new->list, SREJ_LIST(sk));
+		new->tx_seq = chan->expected_tx_seq;
+		chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
+		list_add_tail(&new->list, &chan->srej_l);
 	}
-	pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64;
+	chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
 }
 
-static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, struct sk_buff *skb)
+static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb)
 {
-	struct l2cap_pinfo *pi = l2cap_pi(sk);
+	struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
 	u8 tx_seq = __get_txseq(rx_control);
 	u8 req_seq = __get_reqseq(rx_control);
 	u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT;
@@ -3174,72 +3248,72 @@
 	int num_to_ack = (pi->tx_win/6) + 1;
 	int err = 0;
 
-	BT_DBG("sk %p len %d tx_seq %d rx_control 0x%4.4x", sk, skb->len, tx_seq,
-								rx_control);
+	BT_DBG("chan %p len %d tx_seq %d rx_control 0x%4.4x", chan, skb->len,
+							tx_seq, rx_control);
 
 	if (L2CAP_CTRL_FINAL & rx_control &&
-			l2cap_pi(sk)->conn_state & L2CAP_CONN_WAIT_F) {
-		del_timer(&pi->monitor_timer);
-		if (pi->unacked_frames > 0)
+			chan->conn_state & L2CAP_CONN_WAIT_F) {
+		del_timer(&chan->monitor_timer);
+		if (chan->unacked_frames > 0)
 			__mod_retrans_timer();
-		pi->conn_state &= ~L2CAP_CONN_WAIT_F;
+		chan->conn_state &= ~L2CAP_CONN_WAIT_F;
 	}
 
-	pi->expected_ack_seq = req_seq;
-	l2cap_drop_acked_frames(sk);
+	chan->expected_ack_seq = req_seq;
+	l2cap_drop_acked_frames(chan);
 
-	if (tx_seq == pi->expected_tx_seq)
+	if (tx_seq == chan->expected_tx_seq)
 		goto expected;
 
-	tx_seq_offset = (tx_seq - pi->buffer_seq) % 64;
+	tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
 	if (tx_seq_offset < 0)
 		tx_seq_offset += 64;
 
 	/* invalid tx_seq */
 	if (tx_seq_offset >= pi->tx_win) {
-		l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
+		l2cap_send_disconn_req(pi->conn, chan, ECONNRESET);
 		goto drop;
 	}
 
-	if (pi->conn_state == L2CAP_CONN_LOCAL_BUSY)
+	if (chan->conn_state == L2CAP_CONN_LOCAL_BUSY)
 		goto drop;
 
-	if (pi->conn_state & L2CAP_CONN_SREJ_SENT) {
+	if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
 		struct srej_list *first;
 
-		first = list_first_entry(SREJ_LIST(sk),
+		first = list_first_entry(&chan->srej_l,
 				struct srej_list, list);
 		if (tx_seq == first->tx_seq) {
-			l2cap_add_to_srej_queue(sk, skb, tx_seq, sar);
-			l2cap_check_srej_gap(sk, tx_seq);
+			l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
+			l2cap_check_srej_gap(chan, tx_seq);
 
 			list_del(&first->list);
 			kfree(first);
 
-			if (list_empty(SREJ_LIST(sk))) {
-				pi->buffer_seq = pi->buffer_seq_srej;
-				pi->conn_state &= ~L2CAP_CONN_SREJ_SENT;
-				l2cap_send_ack(pi);
-				BT_DBG("sk %p, Exit SREJ_SENT", sk);
+			if (list_empty(&chan->srej_l)) {
+				chan->buffer_seq = chan->buffer_seq_srej;
+				chan->conn_state &= ~L2CAP_CONN_SREJ_SENT;
+				l2cap_send_ack(chan);
+				BT_DBG("chan %p, Exit SREJ_SENT", chan);
 			}
 		} else {
 			struct srej_list *l;
 
 			/* duplicated tx_seq */
-			if (l2cap_add_to_srej_queue(sk, skb, tx_seq, sar) < 0)
+			if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
 				goto drop;
 
-			list_for_each_entry(l, SREJ_LIST(sk), list) {
+			list_for_each_entry(l, &chan->srej_l, list) {
 				if (l->tx_seq == tx_seq) {
-					l2cap_resend_srejframe(sk, tx_seq);
+					l2cap_resend_srejframe(chan, tx_seq);
 					return 0;
 				}
 			}
-			l2cap_send_srejframe(sk, tx_seq);
+			l2cap_send_srejframe(chan, tx_seq);
 		}
 	} else {
 		expected_tx_seq_offset =
-			(pi->expected_tx_seq - pi->buffer_seq) % 64;
+			(chan->expected_tx_seq - chan->buffer_seq) % 64;
 		if (expected_tx_seq_offset < 0)
 			expected_tx_seq_offset += 64;
 
@@ -3247,51 +3321,51 @@
 		if (tx_seq_offset < expected_tx_seq_offset)
 			goto drop;
 
-		pi->conn_state |= L2CAP_CONN_SREJ_SENT;
+		chan->conn_state |= L2CAP_CONN_SREJ_SENT;
 
-		BT_DBG("sk %p, Enter SREJ", sk);
+		BT_DBG("chan %p, Enter SREJ", chan);
 
-		INIT_LIST_HEAD(SREJ_LIST(sk));
-		pi->buffer_seq_srej = pi->buffer_seq;
+		INIT_LIST_HEAD(&chan->srej_l);
+		chan->buffer_seq_srej = chan->buffer_seq;
 
-		__skb_queue_head_init(SREJ_QUEUE(sk));
-		__skb_queue_head_init(BUSY_QUEUE(sk));
-		l2cap_add_to_srej_queue(sk, skb, tx_seq, sar);
+		__skb_queue_head_init(&chan->srej_q);
+		__skb_queue_head_init(&chan->busy_q);
+		l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
 
-		pi->conn_state |= L2CAP_CONN_SEND_PBIT;
+		chan->conn_state |= L2CAP_CONN_SEND_PBIT;
 
-		l2cap_send_srejframe(sk, tx_seq);
+		l2cap_send_srejframe(chan, tx_seq);
 
-		del_timer(&pi->ack_timer);
+		del_timer(&chan->ack_timer);
 	}
 	return 0;
 
 expected:
-	pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64;
+	chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
 
-	if (pi->conn_state & L2CAP_CONN_SREJ_SENT) {
+	if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
 		bt_cb(skb)->tx_seq = tx_seq;
 		bt_cb(skb)->sar = sar;
-		__skb_queue_tail(SREJ_QUEUE(sk), skb);
+		__skb_queue_tail(&chan->srej_q, skb);
 		return 0;
 	}
 
-	err = l2cap_push_rx_skb(sk, skb, rx_control);
+	err = l2cap_push_rx_skb(chan, skb, rx_control);
 	if (err < 0)
 		return 0;
 
 	if (rx_control & L2CAP_CTRL_FINAL) {
-		if (pi->conn_state & L2CAP_CONN_REJ_ACT)
-			pi->conn_state &= ~L2CAP_CONN_REJ_ACT;
+		if (chan->conn_state & L2CAP_CONN_REJ_ACT)
+			chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
 		else
-			l2cap_retransmit_frames(sk);
+			l2cap_retransmit_frames(chan);
 	}
 
 	__mod_ack_timer();
 
-	pi->num_acked = (pi->num_acked + 1) % num_to_ack;
-	if (pi->num_acked == num_to_ack - 1)
-		l2cap_send_ack(pi);
+	chan->num_acked = (chan->num_acked + 1) % num_to_ack;
+	if (chan->num_acked == num_to_ack - 1)
+		l2cap_send_ack(chan);
 
 	return 0;
 
@@ -3300,165 +3374,160 @@
 	return 0;
 }
 
-static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control)
+static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_control)
 {
-	struct l2cap_pinfo *pi = l2cap_pi(sk);
-
-	BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, __get_reqseq(rx_control),
+	BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, __get_reqseq(rx_control),
 						rx_control);
 
-	pi->expected_ack_seq = __get_reqseq(rx_control);
-	l2cap_drop_acked_frames(sk);
+	chan->expected_ack_seq = __get_reqseq(rx_control);
+	l2cap_drop_acked_frames(chan);
 
 	if (rx_control & L2CAP_CTRL_POLL) {
-		pi->conn_state |= L2CAP_CONN_SEND_FBIT;
-		if (pi->conn_state & L2CAP_CONN_SREJ_SENT) {
-			if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
-					(pi->unacked_frames > 0))
+		chan->conn_state |= L2CAP_CONN_SEND_FBIT;
+		if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
+			if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
+					(chan->unacked_frames > 0))
 				__mod_retrans_timer();
 
-			pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
-			l2cap_send_srejtail(sk);
+			chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
+			l2cap_send_srejtail(chan);
 		} else {
-			l2cap_send_i_or_rr_or_rnr(sk);
+			l2cap_send_i_or_rr_or_rnr(chan);
 		}
 
 	} else if (rx_control & L2CAP_CTRL_FINAL) {
-		pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
+		chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
 
-		if (pi->conn_state & L2CAP_CONN_REJ_ACT)
-			pi->conn_state &= ~L2CAP_CONN_REJ_ACT;
+		if (chan->conn_state & L2CAP_CONN_REJ_ACT)
+			chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
 		else
-			l2cap_retransmit_frames(sk);
+			l2cap_retransmit_frames(chan);
 
 	} else {
-		if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
-				(pi->unacked_frames > 0))
+		if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
+				(chan->unacked_frames > 0))
 			__mod_retrans_timer();
 
-		pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
-		if (pi->conn_state & L2CAP_CONN_SREJ_SENT)
-			l2cap_send_ack(pi);
+		chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
+		if (chan->conn_state & L2CAP_CONN_SREJ_SENT)
+			l2cap_send_ack(chan);
 		else
-			l2cap_ertm_send(sk);
+			l2cap_ertm_send(chan);
 	}
 }
 
-static inline void l2cap_data_channel_rejframe(struct sock *sk, u16 rx_control)
+static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u16 rx_control)
 {
-	struct l2cap_pinfo *pi = l2cap_pi(sk);
 	u8 tx_seq = __get_reqseq(rx_control);
 
-	BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, tx_seq, rx_control);
+	BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
 
-	pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
+	chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
 
-	pi->expected_ack_seq = tx_seq;
-	l2cap_drop_acked_frames(sk);
+	chan->expected_ack_seq = tx_seq;
+	l2cap_drop_acked_frames(chan);
 
 	if (rx_control & L2CAP_CTRL_FINAL) {
-		if (pi->conn_state & L2CAP_CONN_REJ_ACT)
-			pi->conn_state &= ~L2CAP_CONN_REJ_ACT;
+		if (chan->conn_state & L2CAP_CONN_REJ_ACT)
+			chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
 		else
-			l2cap_retransmit_frames(sk);
+			l2cap_retransmit_frames(chan);
 	} else {
-		l2cap_retransmit_frames(sk);
+		l2cap_retransmit_frames(chan);
 
-		if (pi->conn_state & L2CAP_CONN_WAIT_F)
-			pi->conn_state |= L2CAP_CONN_REJ_ACT;
+		if (chan->conn_state & L2CAP_CONN_WAIT_F)
+			chan->conn_state |= L2CAP_CONN_REJ_ACT;
 	}
 }
-static inline void l2cap_data_channel_srejframe(struct sock *sk, u16 rx_control)
+static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_control)
 {
-	struct l2cap_pinfo *pi = l2cap_pi(sk);
 	u8 tx_seq = __get_reqseq(rx_control);
 
-	BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, tx_seq, rx_control);
+	BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
 
-	pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
+	chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
 
 	if (rx_control & L2CAP_CTRL_POLL) {
-		pi->expected_ack_seq = tx_seq;
-		l2cap_drop_acked_frames(sk);
+		chan->expected_ack_seq = tx_seq;
+		l2cap_drop_acked_frames(chan);
 
-		pi->conn_state |= L2CAP_CONN_SEND_FBIT;
-		l2cap_retransmit_one_frame(sk, tx_seq);
+		chan->conn_state |= L2CAP_CONN_SEND_FBIT;
+		l2cap_retransmit_one_frame(chan, tx_seq);
 
-		l2cap_ertm_send(sk);
+		l2cap_ertm_send(chan);
 
-		if (pi->conn_state & L2CAP_CONN_WAIT_F) {
-			pi->srej_save_reqseq = tx_seq;
-			pi->conn_state |= L2CAP_CONN_SREJ_ACT;
+		if (chan->conn_state & L2CAP_CONN_WAIT_F) {
+			chan->srej_save_reqseq = tx_seq;
+			chan->conn_state |= L2CAP_CONN_SREJ_ACT;
 		}
 	} else if (rx_control & L2CAP_CTRL_FINAL) {
-		if ((pi->conn_state & L2CAP_CONN_SREJ_ACT) &&
-				pi->srej_save_reqseq == tx_seq)
-			pi->conn_state &= ~L2CAP_CONN_SREJ_ACT;
+		if ((chan->conn_state & L2CAP_CONN_SREJ_ACT) &&
+				chan->srej_save_reqseq == tx_seq)
+			chan->conn_state &= ~L2CAP_CONN_SREJ_ACT;
 		else
-			l2cap_retransmit_one_frame(sk, tx_seq);
+			l2cap_retransmit_one_frame(chan, tx_seq);
 	} else {
-		l2cap_retransmit_one_frame(sk, tx_seq);
-		if (pi->conn_state & L2CAP_CONN_WAIT_F) {
-			pi->srej_save_reqseq = tx_seq;
-			pi->conn_state |= L2CAP_CONN_SREJ_ACT;
+		l2cap_retransmit_one_frame(chan, tx_seq);
+		if (chan->conn_state & L2CAP_CONN_WAIT_F) {
+			chan->srej_save_reqseq = tx_seq;
+			chan->conn_state |= L2CAP_CONN_SREJ_ACT;
 		}
 	}
 }
 
-static inline void l2cap_data_channel_rnrframe(struct sock *sk, u16 rx_control)
+static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u16 rx_control)
 {
-	struct l2cap_pinfo *pi = l2cap_pi(sk);
 	u8 tx_seq = __get_reqseq(rx_control);
 
-	BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, tx_seq, rx_control);
+	BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
 
-	pi->conn_state |= L2CAP_CONN_REMOTE_BUSY;
-	pi->expected_ack_seq = tx_seq;
-	l2cap_drop_acked_frames(sk);
+	chan->conn_state |= L2CAP_CONN_REMOTE_BUSY;
+	chan->expected_ack_seq = tx_seq;
+	l2cap_drop_acked_frames(chan);
 
 	if (rx_control & L2CAP_CTRL_POLL)
-		pi->conn_state |= L2CAP_CONN_SEND_FBIT;
+		chan->conn_state |= L2CAP_CONN_SEND_FBIT;
 
-	if (!(pi->conn_state & L2CAP_CONN_SREJ_SENT)) {
-		del_timer(&pi->retrans_timer);
+	if (!(chan->conn_state & L2CAP_CONN_SREJ_SENT)) {
+		del_timer(&chan->retrans_timer);
 		if (rx_control & L2CAP_CTRL_POLL)
-			l2cap_send_rr_or_rnr(pi, L2CAP_CTRL_FINAL);
+			l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
 		return;
 	}
 
 	if (rx_control & L2CAP_CTRL_POLL)
-		l2cap_send_srejtail(sk);
+		l2cap_send_srejtail(chan);
 	else
-		l2cap_send_sframe(pi, L2CAP_SUPER_RCV_READY);
+		l2cap_send_sframe(chan, L2CAP_SUPER_RCV_READY);
 }
 
-static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, struct sk_buff *skb)
+static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb)
 {
-	BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len);
+	BT_DBG("chan %p rx_control 0x%4.4x len %d", chan, rx_control, skb->len);
 
 	if (L2CAP_CTRL_FINAL & rx_control &&
-			l2cap_pi(sk)->conn_state & L2CAP_CONN_WAIT_F) {
-		del_timer(&l2cap_pi(sk)->monitor_timer);
-		if (l2cap_pi(sk)->unacked_frames > 0)
+			chan->conn_state & L2CAP_CONN_WAIT_F) {
+		del_timer(&chan->monitor_timer);
+		if (chan->unacked_frames > 0)
 			__mod_retrans_timer();
-		l2cap_pi(sk)->conn_state &= ~L2CAP_CONN_WAIT_F;
+		chan->conn_state &= ~L2CAP_CONN_WAIT_F;
 	}
 
 	switch (rx_control & L2CAP_CTRL_SUPERVISE) {
 	case L2CAP_SUPER_RCV_READY:
-		l2cap_data_channel_rrframe(sk, rx_control);
+		l2cap_data_channel_rrframe(chan, rx_control);
 		break;
 
 	case L2CAP_SUPER_REJECT:
-		l2cap_data_channel_rejframe(sk, rx_control);
+		l2cap_data_channel_rejframe(chan, rx_control);
 		break;
 
 	case L2CAP_SUPER_SELECT_REJECT:
-		l2cap_data_channel_srejframe(sk, rx_control);
+		l2cap_data_channel_srejframe(chan, rx_control);
 		break;
 
 	case L2CAP_SUPER_RCV_NOT_READY:
-		l2cap_data_channel_rnrframe(sk, rx_control);
+		l2cap_data_channel_rnrframe(chan, rx_control);
 		break;
 	}
 
@@ -3468,6 +3537,7 @@
 
 static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
 {
+	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
 	struct l2cap_pinfo *pi = l2cap_pi(sk);
 	u16 control;
 	u8 req_seq;
@@ -3492,41 +3562,41 @@
 		len -= 2;
 
 	if (len > pi->mps) {
-		l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
+		l2cap_send_disconn_req(pi->conn, chan, ECONNRESET);
 		goto drop;
 	}
 
 	req_seq = __get_reqseq(control);
-	req_seq_offset = (req_seq - pi->expected_ack_seq) % 64;
+	req_seq_offset = (req_seq - chan->expected_ack_seq) % 64;
 	if (req_seq_offset < 0)
 		req_seq_offset += 64;
 
 	next_tx_seq_offset =
-		(pi->next_tx_seq - pi->expected_ack_seq) % 64;
+		(chan->next_tx_seq - chan->expected_ack_seq) % 64;
 	if (next_tx_seq_offset < 0)
 		next_tx_seq_offset += 64;
 
 	/* check for invalid req-seq */
 	if (req_seq_offset > next_tx_seq_offset) {
-		l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
+		l2cap_send_disconn_req(pi->conn, chan, ECONNRESET);
 		goto drop;
 	}
 
 	if (__is_iframe(control)) {
 		if (len < 0) {
-			l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
+			l2cap_send_disconn_req(pi->conn, chan, ECONNRESET);
 			goto drop;
 		}
 
-		l2cap_data_channel_iframe(sk, control, skb);
+		l2cap_data_channel_iframe(chan, control, skb);
 	} else {
 		if (len != 0) {
 			BT_ERR("%d", len);
-			l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
+			l2cap_send_disconn_req(pi->conn, chan, ECONNRESET);
 			goto drop;
 		}
 
-		l2cap_data_channel_sframe(sk, control, skb);
+		l2cap_data_channel_sframe(chan, control, skb);
 	}
 
 	return 0;
@@ -3538,21 +3608,23 @@
 
 static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
 {
+	struct l2cap_chan *chan;
 	struct sock *sk;
 	struct l2cap_pinfo *pi;
 	u16 control;
 	u8 tx_seq;
 	int len;
 
-	sk = l2cap_get_chan_by_scid(&conn->chan_list, cid);
-	if (!sk) {
+	chan = l2cap_get_chan_by_scid(conn, cid);
+	if (!chan) {
 		BT_DBG("unknown cid 0x%4.4x", cid);
 		goto drop;
 	}
 
+	sk = chan->sk;
 	pi = l2cap_pi(sk);
 
-	BT_DBG("sk %p, len %d", sk, skb->len);
+	BT_DBG("chan %p, len %d", chan, skb->len);
 
 	if (sk->sk_state != BT_CONNECTED)
 		goto drop;
@@ -3600,17 +3672,17 @@
 
 		tx_seq = __get_txseq(control);
 
-		if (pi->expected_tx_seq == tx_seq)
-			pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64;
+		if (chan->expected_tx_seq == tx_seq)
+			chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
 		else
-			pi->expected_tx_seq = (tx_seq + 1) % 64;
+			chan->expected_tx_seq = (tx_seq + 1) % 64;
 
-		l2cap_streaming_reassembly_sdu(sk, skb, control);
+		l2cap_streaming_reassembly_sdu(chan, skb, control);
 
 		goto done;
 
 	default:
-		BT_DBG("sk %p: bad mode 0x%2.2x", sk, pi->mode);
+		BT_DBG("chan %p: bad mode 0x%2.2x", chan, pi->mode);
 		break;
 	}
 
@@ -3654,6 +3726,36 @@
 	return 0;
 }
 
+static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
+{
+	struct sock *sk;
+
+	sk = l2cap_get_sock_by_scid(0, cid, conn->src);
+	if (!sk)
+		goto drop;
+
+	bh_lock_sock(sk);
+
+	BT_DBG("sk %p, len %d", sk, skb->len);
+
+	if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED)
+		goto drop;
+
+	if (l2cap_pi(sk)->imtu < skb->len)
+		goto drop;
+
+	if (!sock_queue_rcv_skb(sk, skb))
+		goto done;
+
+drop:
+	kfree_skb(skb);
+
+done:
+	if (sk)
+		bh_unlock_sock(sk);
+	return 0;
+}
+
 static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
 {
 	struct l2cap_hdr *lh = (void *) skb->data;
@@ -3683,6 +3785,10 @@
 		l2cap_conless_channel(conn, psm, skb);
 		break;
 
+	case L2CAP_CID_LE_DATA:
+		l2cap_att_channel(conn, cid, skb);
+		break;
+
 	default:
 		l2cap_data_channel(conn, cid, skb);
 		break;
@@ -3786,20 +3892,19 @@
 
 static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
 {
-	struct l2cap_chan_list *l;
 	struct l2cap_conn *conn = hcon->l2cap_data;
-	struct sock *sk;
+	struct l2cap_chan *chan;
 
 	if (!conn)
 		return 0;
 
-	l = &conn->chan_list;
-
 	BT_DBG("conn %p", conn);
 
-	read_lock(&l->lock);
+	read_lock(&conn->chan_lock);
 
-	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
+	list_for_each_entry(chan, &conn->chan_l, list) {
+		struct sock *sk = chan->sk;
+
 		bh_lock_sock(sk);
 
 		if (l2cap_pi(sk)->conf_state & L2CAP_CONF_CONNECT_PEND) {
@@ -3820,10 +3925,10 @@
 				req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
 				req.psm  = l2cap_pi(sk)->psm;
 
-				l2cap_pi(sk)->ident = l2cap_get_ident(conn);
+				chan->ident = l2cap_get_ident(conn);
 				l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND;
 
-				l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
+				l2cap_send_cmd(conn, chan->ident,
 					L2CAP_CONN_REQ, sizeof(req), &req);
 			} else {
 				l2cap_sock_clear_timer(sk);
@@ -3846,14 +3951,14 @@
 			rsp.dcid   = cpu_to_le16(l2cap_pi(sk)->scid);
 			rsp.result = cpu_to_le16(result);
 			rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
-			l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
-					L2CAP_CONN_RSP, sizeof(rsp), &rsp);
+			l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
+							sizeof(rsp), &rsp);
 		}
 
 		bh_unlock_sock(sk);
 	}
 
-	read_unlock(&l->lock);
+	read_unlock(&conn->chan_lock);
 
 	return 0;
 }
@@ -3872,7 +3977,7 @@
 
 	if (!(flags & ACL_CONT)) {
 		struct l2cap_hdr *hdr;
-		struct sock *sk;
+		struct l2cap_chan *chan;
 		u16 cid;
 		int len;
 
@@ -3910,19 +4015,22 @@
 			goto drop;
 		}
 
-		sk = l2cap_get_chan_by_scid(&conn->chan_list, cid);
+		chan = l2cap_get_chan_by_scid(conn, cid);
 
-		if (sk && l2cap_pi(sk)->imtu < len - L2CAP_HDR_SIZE) {
-			BT_ERR("Frame exceeding recv MTU (len %d, MTU %d)",
-					len, l2cap_pi(sk)->imtu);
+		if (chan && chan->sk) {
+			struct sock *sk = chan->sk;
+
+			if (l2cap_pi(sk)->imtu < len - L2CAP_HDR_SIZE) {
+				BT_ERR("Frame exceeding recv MTU (len %d, "
+							"MTU %d)", len,
+							l2cap_pi(sk)->imtu);
+				bh_unlock_sock(sk);
+				l2cap_conn_unreliable(conn, ECOMM);
+				goto drop;
+			}
 			bh_unlock_sock(sk);
-			l2cap_conn_unreliable(conn, ECOMM);
-			goto drop;
 		}
 
-		if (sk)
-			bh_unlock_sock(sk);
-
 		/* Allocate skb for the complete frame (with header) */
 		conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
 		if (!conn->rx_skb)
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 299fe56..47394a1 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -269,7 +269,7 @@
 		goto done;
 	}
 
-	if (!l2cap_pi(sk)->psm && !l2cap_pi(sk)->dcid) {
+	if (!l2cap_pi(sk)->psm && !l2cap_pi(sk)->scid) {
 		bdaddr_t *src = &bt_sk(sk)->src;
 		u16 psm;
 
@@ -757,36 +757,38 @@
 	case L2CAP_MODE_ERTM:
 	case L2CAP_MODE_STREAMING:
 		/* Entire SDU fits into one PDU */
-		if (len <= pi->remote_mps) {
+		if (len <= pi->chan->remote_mps) {
 			control = L2CAP_SDU_UNSEGMENTED;
 			skb = l2cap_create_iframe_pdu(sk, msg, len, control, 0);
 			if (IS_ERR(skb)) {
 				err = PTR_ERR(skb);
 				goto done;
 			}
-			__skb_queue_tail(TX_QUEUE(sk), skb);
+			__skb_queue_tail(&pi->chan->tx_q, skb);
 
-			if (sk->sk_send_head == NULL)
-				sk->sk_send_head = skb;
+			if (pi->chan->tx_send_head == NULL)
+				pi->chan->tx_send_head = skb;
 
 		} else {
 		/* Segment SDU into multiples PDUs */
-			err = l2cap_sar_segment_sdu(sk, msg, len);
+			err = l2cap_sar_segment_sdu(pi->chan, msg, len);
 			if (err < 0)
 				goto done;
 		}
 
 		if (pi->mode == L2CAP_MODE_STREAMING) {
-			l2cap_streaming_send(sk);
-		} else {
-			if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
-					(pi->conn_state & L2CAP_CONN_WAIT_F)) {
-				err = len;
-				break;
-			}
-			err = l2cap_ertm_send(sk);
+			l2cap_streaming_send(pi->chan);
+			err = len;
+			break;
 		}
 
+		if ((pi->chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
+				(pi->chan->conn_state & L2CAP_CONN_WAIT_F)) {
+			err = len;
+			break;
+		}
+		err = l2cap_ertm_send(pi->chan);
+
 		if (err >= 0)
 			err = len;
 		break;
@@ -808,29 +810,7 @@
 	lock_sock(sk);
 
 	if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) {
-		struct l2cap_conn_rsp rsp;
-		struct l2cap_conn *conn = l2cap_pi(sk)->conn;
-		u8 buf[128];
-
-		sk->sk_state = BT_CONFIG;
-
-		rsp.scid   = cpu_to_le16(l2cap_pi(sk)->dcid);
-		rsp.dcid   = cpu_to_le16(l2cap_pi(sk)->scid);
-		rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
-		rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
-		l2cap_send_cmd(l2cap_pi(sk)->conn, l2cap_pi(sk)->ident,
-					L2CAP_CONN_RSP, sizeof(rsp), &rsp);
-
-		if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) {
-			release_sock(sk);
-			return 0;
-		}
-
-		l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
-		l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
-				l2cap_build_conf_req(sk, buf), buf);
-		l2cap_pi(sk)->num_conf_req++;
-
+		__l2cap_connect_rsp_defer(sk);
 		release_sock(sk);
 		return 0;
 	}
@@ -886,6 +866,7 @@
 void __l2cap_sock_close(struct sock *sk, int reason)
 {
 	struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
 
 	BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket);
 
@@ -900,9 +881,9 @@
 					sk->sk_type == SOCK_STREAM) &&
 					conn->hcon->type == ACL_LINK) {
 			l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
-			l2cap_send_disconn_req(conn, sk, reason);
+			l2cap_send_disconn_req(conn, chan, reason);
 		} else
-			l2cap_chan_del(sk, reason);
+			l2cap_chan_del(chan, reason);
 		break;
 
 	case BT_CONNECT2:
@@ -921,16 +902,16 @@
 			rsp.dcid   = cpu_to_le16(l2cap_pi(sk)->scid);
 			rsp.result = cpu_to_le16(result);
 			rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
-			l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
-					L2CAP_CONN_RSP, sizeof(rsp), &rsp);
+			l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
+							sizeof(rsp), &rsp);
 		}
 
-		l2cap_chan_del(sk, reason);
+		l2cap_chan_del(chan, reason);
 		break;
 
 	case BT_CONNECT:
 	case BT_DISCONN:
-		l2cap_chan_del(sk, reason);
+		l2cap_chan_del(chan, reason);
 		break;
 
 	default:
@@ -1035,12 +1016,7 @@
 	}
 
 	/* Default config options */
-	pi->conf_len = 0;
 	pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
-	skb_queue_head_init(TX_QUEUE(sk));
-	skb_queue_head_init(SREJ_QUEUE(sk));
-	skb_queue_head_init(BUSY_QUEUE(sk));
-	INIT_LIST_HEAD(SREJ_LIST(sk));
 }
 
 static struct proto l2cap_proto = {
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index bf5d28d..a6d191f 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -330,6 +330,7 @@
 static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
 {
 	struct ieee80211_sub_if_data *sdata = sta->sdata;
+	struct timespec uptime;
 
 	sinfo->generation = sdata->local->sta_generation;
 
@@ -343,7 +344,11 @@
 			STATION_INFO_TX_BITRATE |
 			STATION_INFO_RX_BITRATE |
 			STATION_INFO_RX_DROP_MISC |
-			STATION_INFO_BSS_PARAM;
+			STATION_INFO_BSS_PARAM |
+			STATION_INFO_CONNECTED_TIME;
+
+	do_posix_clock_monotonic_gettime(&uptime);
+	sinfo->connected_time = uptime.tv_sec - sta->last_connected;
 
 	sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
 	sinfo->rx_bytes = sta->rx_bytes;
@@ -686,6 +691,12 @@
 		if (set & BIT(NL80211_STA_FLAG_MFP))
 			sta->flags |= WLAN_STA_MFP;
 	}
+
+	if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) {
+		sta->flags &= ~WLAN_STA_AUTH;
+		if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED))
+			sta->flags |= WLAN_STA_AUTH;
+	}
 	spin_unlock_irqrestore(&sta->flaglock, flags);
 
 	/*
@@ -1034,26 +1045,26 @@
 	u8 *new_ie;
 	const u8 *old_ie;
 
-	/* first allocate the new vendor information element */
+	/* allocate information elements */
 	new_ie = NULL;
-	old_ie = ifmsh->vendor_ie;
+	old_ie = ifmsh->ie;
 
-	ifmsh->vendor_ie_len = setup->vendor_ie_len;
-	if (setup->vendor_ie_len) {
-		new_ie = kmemdup(setup->vendor_ie, setup->vendor_ie_len,
+	if (setup->ie_len) {
+		new_ie = kmemdup(setup->ie, setup->ie_len,
 				GFP_KERNEL);
 		if (!new_ie)
 			return -ENOMEM;
 	}
+	ifmsh->ie_len = setup->ie_len;
+	ifmsh->ie = new_ie;
+	kfree(old_ie);
 
 	/* now copy the rest of the setup parameters */
 	ifmsh->mesh_id_len = setup->mesh_id_len;
 	memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len);
 	ifmsh->mesh_pp_id = setup->path_sel_proto;
 	ifmsh->mesh_pm_id = setup->path_metric;
-	ifmsh->vendor_ie = new_ie;
-
-	kfree(old_ie);
+	ifmsh->is_secure = setup->is_secure;
 
 	return 0;
 }
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index c04a139..a01d213 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -92,6 +92,31 @@
 }
 STA_OPS(inactive_ms);
 
+
+static ssize_t sta_connected_time_read(struct file *file, char __user *userbuf,
+					size_t count, loff_t *ppos)
+{
+	struct sta_info *sta = file->private_data;
+	struct timespec uptime;
+	struct tm result;
+	long connected_time_secs;
+	char buf[100];
+	int res;
+	do_posix_clock_monotonic_gettime(&uptime);
+	connected_time_secs = uptime.tv_sec - sta->last_connected;
+	time_to_tm(connected_time_secs, 0, &result);
+	result.tm_year -= 70;
+	result.tm_mday -= 1;
+	res = scnprintf(buf, sizeof(buf),
+		"years  - %ld\nmonths - %d\ndays   - %d\nclock  - %d:%d:%d\n\n",
+			result.tm_year, result.tm_mon, result.tm_mday,
+			result.tm_hour, result.tm_min, result.tm_sec);
+	return simple_read_from_buffer(userbuf, count, ppos, buf, res);
+}
+STA_OPS(connected_time);
+
+
+
 static ssize_t sta_last_seq_ctrl_read(struct file *file, char __user *userbuf,
 				      size_t count, loff_t *ppos)
 {
@@ -324,6 +349,7 @@
 	DEBUGFS_ADD(flags);
 	DEBUGFS_ADD(num_ps_buf_frames);
 	DEBUGFS_ADD(inactive_ms);
+	DEBUGFS_ADD(connected_time);
 	DEBUGFS_ADD(last_seq_ctrl);
 	DEBUGFS_ADD(agg_status);
 	DEBUGFS_ADD(dev);
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 9c0d62b..00a0685 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -552,4 +552,17 @@
 	trace_drv_return_void(local);
 }
 
+static inline bool drv_tx_frames_pending(struct ieee80211_local *local)
+{
+	bool ret = false;
+
+	might_sleep();
+
+	trace_drv_tx_frames_pending(local);
+	if (local->ops->tx_frames_pending)
+		ret = local->ops->tx_frames_pending(&local->hw);
+	trace_drv_return_bool(local, ret);
+
+	return ret;
+}
 #endif /* __MAC80211_DRIVER_OPS */
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
index 45aab80..c8c934d 100644
--- a/net/mac80211/driver-trace.h
+++ b/net/mac80211/driver-trace.h
@@ -74,6 +74,21 @@
 	TP_printk(LOCAL_PR_FMT " - %d", LOCAL_PR_ARG, __entry->ret)
 );
 
+TRACE_EVENT(drv_return_bool,
+	TP_PROTO(struct ieee80211_local *local, bool ret),
+	TP_ARGS(local, ret),
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		__field(bool, ret)
+	),
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		__entry->ret = ret;
+	),
+	TP_printk(LOCAL_PR_FMT " - %s", LOCAL_PR_ARG, (__entry->ret) ?
+		  "true" : "false")
+);
+
 TRACE_EVENT(drv_return_u64,
 	TP_PROTO(struct ieee80211_local *local, u64 ret),
 	TP_ARGS(local, ret),
@@ -964,6 +979,11 @@
 	)
 );
 
+DEFINE_EVENT(local_only_evt, drv_tx_frames_pending,
+	TP_PROTO(struct ieee80211_local *local),
+	TP_ARGS(local)
+);
+
 DEFINE_EVENT(local_only_evt, drv_offchannel_tx_cancel_wait,
 	TP_PROTO(struct ieee80211_local *local),
 	TP_ARGS(local)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 89ce1e3..a778499 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -488,8 +488,9 @@
 	struct mesh_config mshcfg;
 	u32 mesh_seqnum;
 	bool accepting_plinks;
-	const u8 *vendor_ie;
-	u8 vendor_ie_len;
+	const u8 *ie;
+	u8 ie_len;
+	bool is_secure;
 };
 
 #ifdef CONFIG_MAC80211_MESH
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index dc50fc31..0ab2a8d 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -545,7 +545,9 @@
 	},
 	[NL80211_IFTYPE_MESH_POINT] = {
 		.tx = 0xffff,
-		.rx = BIT(IEEE80211_STYPE_ACTION >> 4),
+		.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+			BIT(IEEE80211_STYPE_AUTH >> 4) |
+			BIT(IEEE80211_STYPE_DEAUTH >> 4),
 	},
 };
 
@@ -760,6 +762,11 @@
 	local->hw.wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MESH_POINT);
 #endif
 
+	/* if the underlying driver supports mesh, mac80211 will (at least)
+	 * provide routing of mesh authentication frames to userspace */
+	if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_MESH_POINT))
+		local->hw.wiphy->flags |= WIPHY_FLAG_MESH_AUTH;
+
 	/* mac80211 supports control port protocol changing */
 	local->hw.wiphy->flags |= WIPHY_FLAG_CONTROL_PORT_PROTOCOL;
 
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 2a57cc0..1120797 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -279,9 +279,9 @@
 	    MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
 	*pos++ = 0x00;
 
-	if (sdata->u.mesh.vendor_ie) {
-		int len = sdata->u.mesh.vendor_ie_len;
-		const u8 *data = sdata->u.mesh.vendor_ie;
+	if (sdata->u.mesh.ie) {
+		int len = sdata->u.mesh.ie_len;
+		const u8 *data = sdata->u.mesh.ie;
 		if (skb_tailroom(skb) > len)
 			memcpy(skb_put(skb, len), data, len);
 	}
@@ -573,6 +573,10 @@
 	ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
 			       &elems);
 
+	/* ignore beacons from secure mesh peers if our security is off */
+	if (elems.rsn_len && !sdata->u.mesh.is_secure)
+		return;
+
 	if (elems.ds_params && elems.ds_params_len == 1)
 		freq = ieee80211_channel_to_frequency(elems.ds_params[0], band);
 	else
@@ -586,9 +590,7 @@
 	if (elems.mesh_id && elems.mesh_config &&
 	    mesh_matches_local(&elems, sdata)) {
 		supp_rates = ieee80211_sta_get_rates(local, &elems, band);
-
-		mesh_neighbour_update(mgmt->sa, supp_rates, sdata,
-				      mesh_peer_accepts_plinks(&elems));
+		mesh_neighbour_update(mgmt->sa, supp_rates, sdata, &elems);
 	}
 }
 
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index b99e230..10acf1c 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -226,7 +226,8 @@
 int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata);
 /* Mesh plinks */
 void mesh_neighbour_update(u8 *hw_addr, u32 rates,
-		struct ieee80211_sub_if_data *sdata, bool add);
+		struct ieee80211_sub_if_data *sdata,
+		struct ieee802_11_elems *ie);
 bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie);
 void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata);
 void mesh_plink_broken(struct sta_info *sta);
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 336ca9d..35c715a 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -65,42 +65,37 @@
 	__mesh_table_free(tbl);
 }
 
-static struct mesh_table *mesh_table_grow(struct mesh_table *tbl)
+static int mesh_table_grow(struct mesh_table *oldtbl,
+		struct mesh_table *newtbl)
 {
-	struct mesh_table *newtbl;
 	struct hlist_head *oldhash;
 	struct hlist_node *p, *q;
 	int i;
 
-	if (atomic_read(&tbl->entries)
-			< tbl->mean_chain_len * (tbl->hash_mask + 1))
-		goto endgrow;
+	if (atomic_read(&oldtbl->entries)
+			< oldtbl->mean_chain_len * (oldtbl->hash_mask + 1))
+		return -EAGAIN;
 
-	newtbl = mesh_table_alloc(tbl->size_order + 1);
-	if (!newtbl)
-		goto endgrow;
 
-	newtbl->free_node = tbl->free_node;
-	newtbl->mean_chain_len = tbl->mean_chain_len;
-	newtbl->copy_node = tbl->copy_node;
-	atomic_set(&newtbl->entries, atomic_read(&tbl->entries));
+	newtbl->free_node = oldtbl->free_node;
+	newtbl->mean_chain_len = oldtbl->mean_chain_len;
+	newtbl->copy_node = oldtbl->copy_node;
+	atomic_set(&newtbl->entries, atomic_read(&oldtbl->entries));
 
-	oldhash = tbl->hash_buckets;
-	for (i = 0; i <= tbl->hash_mask; i++)
+	oldhash = oldtbl->hash_buckets;
+	for (i = 0; i <= oldtbl->hash_mask; i++)
 		hlist_for_each(p, &oldhash[i])
-			if (tbl->copy_node(p, newtbl) < 0)
+			if (oldtbl->copy_node(p, newtbl) < 0)
 				goto errcopy;
 
-	return newtbl;
+	return 0;
 
 errcopy:
 	for (i = 0; i <= newtbl->hash_mask; i++) {
 		hlist_for_each_safe(p, q, &newtbl->hash_buckets[i])
-			tbl->free_node(p, 0);
+			oldtbl->free_node(p, 0);
 	}
-	__mesh_table_free(newtbl);
-endgrow:
-	return NULL;
+	return -ENOMEM;
 }
 
 
@@ -334,10 +329,13 @@
 {
 	struct mesh_table *oldtbl, *newtbl;
 
+	newtbl = mesh_table_alloc(mesh_paths->size_order + 1);
+	if (!newtbl)
+		return;
 	write_lock(&pathtbl_resize_lock);
 	oldtbl = mesh_paths;
-	newtbl = mesh_table_grow(mesh_paths);
-	if (!newtbl) {
+	if (mesh_table_grow(mesh_paths, newtbl) < 0) {
+		__mesh_table_free(newtbl);
 		write_unlock(&pathtbl_resize_lock);
 		return;
 	}
@@ -352,10 +350,13 @@
 {
 	struct mesh_table *oldtbl, *newtbl;
 
+	newtbl = mesh_table_alloc(mpp_paths->size_order + 1);
+	if (!newtbl)
+		return;
 	write_lock(&pathtbl_resize_lock);
 	oldtbl = mpp_paths;
-	newtbl = mesh_table_grow(mpp_paths);
-	if (!newtbl) {
+	if (mesh_table_grow(mpp_paths, newtbl) < 0) {
+		__mesh_table_free(newtbl);
 		write_unlock(&pathtbl_resize_lock);
 		return;
 	}
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 44b5393..84e5b05 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -105,7 +105,7 @@
 	if (!sta)
 		return NULL;
 
-	sta->flags = WLAN_STA_AUTHORIZED;
+	sta->flags = WLAN_STA_AUTHORIZED | WLAN_STA_AUTH;
 	sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
 	rate_control_rate_init(sta);
 
@@ -161,7 +161,7 @@
 		__le16 reason) {
 	struct ieee80211_local *local = sdata->local;
 	struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400 +
-			sdata->u.mesh.vendor_ie_len);
+			sdata->u.mesh.ie_len);
 	struct ieee80211_mgmt *mgmt;
 	bool include_plid = false;
 	static const u8 meshpeeringproto[] = { 0x00, 0x0F, 0xAC, 0x2A };
@@ -237,8 +237,9 @@
 	return 0;
 }
 
-void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data *sdata,
-			   bool peer_accepting_plinks)
+void mesh_neighbour_update(u8 *hw_addr, u32 rates,
+		struct ieee80211_sub_if_data *sdata,
+		struct ieee802_11_elems *elems)
 {
 	struct ieee80211_local *local = sdata->local;
 	struct sta_info *sta;
@@ -248,8 +249,14 @@
 	sta = sta_info_get(sdata, hw_addr);
 	if (!sta) {
 		rcu_read_unlock();
-
-		sta = mesh_plink_alloc(sdata, hw_addr, rates);
+		/* Userspace handles peer allocation when security is enabled
+		 * */
+		if (sdata->u.mesh.is_secure)
+			cfg80211_notify_new_peer_candidate(sdata->dev, hw_addr,
+					elems->ie_start, elems->total_len,
+					GFP_KERNEL);
+		else
+			sta = mesh_plink_alloc(sdata, hw_addr, rates);
 		if (!sta)
 			return;
 		if (sta_info_insert_rcu(sta)) {
@@ -260,7 +267,8 @@
 
 	sta->last_rx = jiffies;
 	sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
-	if (peer_accepting_plinks && sta->plink_state == PLINK_LISTEN &&
+	if (mesh_peer_accepts_plinks(elems) &&
+			sta->plink_state == PLINK_LISTEN &&
 			sdata->u.mesh.accepting_plinks &&
 			sdata->u.mesh.mshcfg.auto_open_plinks)
 		mesh_plink_open(sta);
@@ -372,6 +380,9 @@
 	__le16 llid;
 	struct ieee80211_sub_if_data *sdata = sta->sdata;
 
+	if (!test_sta_flags(sta, WLAN_STA_AUTH))
+		return -EPERM;
+
 	spin_lock_bh(&sta->lock);
 	get_random_bytes(&llid, 2);
 	sta->llid = llid;
@@ -449,6 +460,10 @@
 		mpl_dbg("Mesh plink: missing necessary peer link ie\n");
 		return;
 	}
+	if (elems.rsn_len && !sdata->u.mesh.is_secure) {
+		mpl_dbg("Mesh plink: can't establish link with secure peer\n");
+		return;
+	}
 
 	ftype = mgmt->u.action.u.plink_action.action_code;
 	ie_len = elems.peer_link_len;
@@ -480,6 +495,12 @@
 		return;
 	}
 
+	if (sta && !test_sta_flags(sta, WLAN_STA_AUTH)) {
+		mpl_dbg("Mesh plink: Action frame from non-authed peer\n");
+		rcu_read_unlock();
+		return;
+	}
+
 	if (sta && sta->plink_state == PLINK_BLOCKED) {
 		rcu_read_unlock();
 		return;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 865fed4..a41f234 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -761,15 +761,16 @@
 	if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) &&
 	    (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED))) {
 		netif_tx_stop_all_queues(sdata->dev);
-		/*
-		 * Flush all the frames queued in the driver before
-		 * going to power save
-		 */
-		drv_flush(local, false);
-		ieee80211_send_nullfunc(local, sdata, 1);
 
-		/* Flush once again to get the tx status of nullfunc frame */
-		drv_flush(local, false);
+		if (drv_tx_frames_pending(local))
+			mod_timer(&local->dynamic_ps_timer, jiffies +
+				  msecs_to_jiffies(
+				  local->hw.conf.dynamic_ps_timeout));
+		else {
+			ieee80211_send_nullfunc(local, sdata, 1);
+			/* Flush to get the tx status of nullfunc frame */
+			drv_flush(local, false);
+		}
 	}
 
 	if (!((local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) &&
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 1f0b010..a864890 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -143,7 +143,8 @@
 	if (status->flag & RX_FLAG_HT) {
 		/*
 		 * MCS information is a separate field in radiotap,
-		 * added below.
+		 * added below. The byte here is needed as padding
+		 * for the channel though, so initialise it to 0.
 		 */
 		*pos = 0;
 	} else {
@@ -502,7 +503,8 @@
 
 		if (ieee80211_is_probe_req(hdr->frame_control) ||
 		    ieee80211_is_probe_resp(hdr->frame_control) ||
-		    ieee80211_is_beacon(hdr->frame_control))
+		    ieee80211_is_beacon(hdr->frame_control) ||
+		    ieee80211_is_auth(hdr->frame_control))
 			return RX_CONTINUE;
 
 		return RX_DROP_MONITOR;
@@ -1585,7 +1587,7 @@
 }
 
 static int
-__ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
+__ieee80211_data_to_8023(struct ieee80211_rx_data *rx, bool *port_control)
 {
 	struct ieee80211_sub_if_data *sdata = rx->sdata;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
@@ -1593,6 +1595,7 @@
 	struct ethhdr *ehdr;
 	int ret;
 
+	*port_control = false;
 	if (ieee80211_has_a4(hdr->frame_control) &&
 	    sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->u.vlan.sta)
 		return -1;
@@ -1611,11 +1614,13 @@
 		return -1;
 
 	ret = ieee80211_data_to_8023(rx->skb, sdata->vif.addr, sdata->vif.type);
-	if (ret < 0 || !check_port_control)
+	if (ret < 0)
 		return ret;
 
 	ehdr = (struct ethhdr *) rx->skb->data;
-	if (ehdr->h_proto != rx->sdata->control_port_protocol)
+	if (ehdr->h_proto == rx->sdata->control_port_protocol)
+		*port_control = true;
+	else if (check_port_control)
 		return -1;
 
 	return 0;
@@ -1916,6 +1921,7 @@
 	struct net_device *dev = sdata->dev;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
 	__le16 fc = hdr->frame_control;
+	bool port_control;
 	int err;
 
 	if (unlikely(!ieee80211_is_data(hdr->frame_control)))
@@ -1932,13 +1938,21 @@
 	    sdata->vif.type == NL80211_IFTYPE_AP)
 		return RX_DROP_MONITOR;
 
-	err = __ieee80211_data_to_8023(rx);
+	err = __ieee80211_data_to_8023(rx, &port_control);
 	if (unlikely(err))
 		return RX_DROP_UNUSABLE;
 
 	if (!ieee80211_frame_allowed(rx, fc))
 		return RX_DROP_MONITOR;
 
+	if (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+	    unlikely(port_control) && sdata->bss) {
+		sdata = container_of(sdata->bss, struct ieee80211_sub_if_data,
+				     u.ap);
+		dev = sdata->dev;
+		rx->sdata = sdata;
+	}
+
 	rx->skb->dev = dev;
 
 	dev->stats.rx_packets++;
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 52d4b1a..a03d8a3 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -228,6 +228,7 @@
 {
 	struct ieee80211_local *local = sdata->local;
 	struct sta_info *sta;
+	struct timespec uptime;
 	int i;
 
 	sta = kzalloc(sizeof(*sta) + local->hw.sta_data_size, gfp);
@@ -245,6 +246,8 @@
 	sta->sdata = sdata;
 	sta->last_rx = jiffies;
 
+	do_posix_clock_monotonic_gettime(&uptime);
+	sta->last_connected = uptime.tv_sec;
 	ewma_init(&sta->avg_signal, 1024, 8);
 
 	if (sta_prepare_rate_control(local, sta, gfp)) {
@@ -609,7 +612,8 @@
 #endif
 		dev_kfree_skb(skb);
 
-		if (skb_queue_empty(&sta->ps_tx_buf))
+		if (skb_queue_empty(&sta->ps_tx_buf) &&
+		    !test_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF))
 			sta_info_clear_tim_bit(sta);
 	}
 
@@ -893,6 +897,7 @@
 	struct ieee80211_local *local = sdata->local;
 	int sent, buffered;
 
+	clear_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF);
 	if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS))
 		drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta);
 
@@ -985,3 +990,12 @@
 		ieee80211_queue_work(hw, &sta->drv_unblock_wk);
 }
 EXPORT_SYMBOL(ieee80211_sta_block_awake);
+
+void ieee80211_sta_set_tim(struct ieee80211_sta *pubsta)
+{
+	struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
+
+	set_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF);
+	sta_info_set_tim_bit(sta);
+}
+EXPORT_SYMBOL(ieee80211_sta_set_tim);
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 87b18ba..aa0adcb 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -43,6 +43,8 @@
  *	be in the queues
  * @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping
  *	station in power-save mode, reply when the driver unblocks.
+ * @WLAN_STA_PS_DRIVER_BUF: Station has frames pending in driver internal
+ *	buffers. Automatically cleared on station wake-up.
  */
 enum ieee80211_sta_info_flags {
 	WLAN_STA_AUTH		= 1<<0,
@@ -58,6 +60,7 @@
 	WLAN_STA_BLOCK_BA	= 1<<11,
 	WLAN_STA_PS_DRIVER	= 1<<12,
 	WLAN_STA_PSPOLL		= 1<<13,
+	WLAN_STA_PS_DRIVER_BUF	= 1<<14,
 };
 
 #define STA_TID_NUM 16
@@ -226,6 +229,7 @@
  * @rx_bytes: Number of bytes received from this STA
  * @wep_weak_iv_count: number of weak WEP IVs received from this station
  * @last_rx: time (in jiffies) when last frame was received from this STA
+ * @last_connected: time (in seconds) when a station got connected
  * @num_duplicates: number of duplicate frames received from this STA
  * @rx_fragments: number of received MPDUs
  * @rx_dropped: number of dropped MPDUs from this STA
@@ -295,6 +299,7 @@
 	unsigned long rx_packets, rx_bytes;
 	unsigned long wep_weak_iv_count;
 	unsigned long last_rx;
+	long last_connected;
 	unsigned long num_duplicates;
 	unsigned long rx_fragments;
 	unsigned long rx_dropped;
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index ce4596e..17b10be 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2262,7 +2262,7 @@
 
 		/* headroom, head length, tail length and maximum TIM length */
 		skb = dev_alloc_skb(local->tx_headroom + 400 +
-				sdata->u.mesh.vendor_ie_len);
+				sdata->u.mesh.ie_len);
 		if (!skb)
 			goto out;
 
diff --git a/net/rfkill/Kconfig b/net/rfkill/Kconfig
index 7fce6df..48464ca 100644
--- a/net/rfkill/Kconfig
+++ b/net/rfkill/Kconfig
@@ -22,3 +22,14 @@
 	depends on RFKILL
 	depends on INPUT = y || RFKILL = INPUT
 	default y if !EXPERT
+
+config RFKILL_REGULATOR
+	tristate "Generic rfkill regulator driver"
+	depends on RFKILL || !RFKILL
+	depends on REGULATOR
+	help
+          This options enable controlling radio transmitters connected to
+          voltage regulator using the regulator framework.
+
+          To compile this driver as a module, choose M here: the module will
+          be called rfkill-regulator.
diff --git a/net/rfkill/Makefile b/net/rfkill/Makefile
index 6621053..d9a5a58 100644
--- a/net/rfkill/Makefile
+++ b/net/rfkill/Makefile
@@ -5,3 +5,4 @@
 rfkill-y			+= core.o
 rfkill-$(CONFIG_RFKILL_INPUT)	+= input.o
 obj-$(CONFIG_RFKILL)		+= rfkill.o
+obj-$(CONFIG_RFKILL_REGULATOR)	+= rfkill-regulator.o
diff --git a/net/rfkill/rfkill-regulator.c b/net/rfkill/rfkill-regulator.c
new file mode 100644
index 0000000..18dc512
--- /dev/null
+++ b/net/rfkill/rfkill-regulator.c
@@ -0,0 +1,164 @@
+/*
+ * rfkill-regulator.c - Regulator consumer driver for rfkill
+ *
+ * Copyright (C) 2009  Guiming Zhuo <gmzhuo@gmail.com>
+ * Copyright (C) 2011  Antonio Ospite <ospite@studenti.unina.it>
+ *
+ * Implementation inspired by leds-regulator driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/rfkill.h>
+#include <linux/rfkill-regulator.h>
+
+struct rfkill_regulator_data {
+	struct rfkill *rf_kill;
+	bool reg_enabled;
+
+	struct regulator *vcc;
+};
+
+static int rfkill_regulator_set_block(void *data, bool blocked)
+{
+	struct rfkill_regulator_data *rfkill_data = data;
+
+	pr_debug("%s: blocked: %d\n", __func__, blocked);
+
+	if (blocked) {
+		if (rfkill_data->reg_enabled) {
+			regulator_disable(rfkill_data->vcc);
+			rfkill_data->reg_enabled = 0;
+		}
+	} else {
+		if (!rfkill_data->reg_enabled) {
+			regulator_enable(rfkill_data->vcc);
+			rfkill_data->reg_enabled = 1;
+		}
+	}
+
+	pr_debug("%s: regulator_is_enabled after set_block: %d\n", __func__,
+		regulator_is_enabled(rfkill_data->vcc));
+
+	return 0;
+}
+
+struct rfkill_ops rfkill_regulator_ops = {
+	.set_block = rfkill_regulator_set_block,
+};
+
+static int __devinit rfkill_regulator_probe(struct platform_device *pdev)
+{
+	struct rfkill_regulator_platform_data *pdata = pdev->dev.platform_data;
+	struct rfkill_regulator_data *rfkill_data;
+	struct regulator *vcc;
+	struct rfkill *rf_kill;
+	int ret = 0;
+
+	if (pdata == NULL) {
+		dev_err(&pdev->dev, "no platform data\n");
+		return -ENODEV;
+	}
+
+	if (pdata->name == NULL || pdata->type == 0) {
+		dev_err(&pdev->dev, "invalid name or type in platform data\n");
+		return -EINVAL;
+	}
+
+	vcc = regulator_get_exclusive(&pdev->dev, "vrfkill");
+	if (IS_ERR(vcc)) {
+		dev_err(&pdev->dev, "Cannot get vcc for %s\n", pdata->name);
+		ret = PTR_ERR(vcc);
+		goto out;
+	}
+
+	rfkill_data = kzalloc(sizeof(*rfkill_data), GFP_KERNEL);
+	if (rfkill_data == NULL) {
+		ret = -ENOMEM;
+		goto err_data_alloc;
+	}
+
+	rf_kill = rfkill_alloc(pdata->name, &pdev->dev,
+				pdata->type,
+				&rfkill_regulator_ops, rfkill_data);
+	if (rf_kill == NULL) {
+		dev_err(&pdev->dev, "Cannot alloc rfkill device\n");
+		ret = -ENOMEM;
+		goto err_rfkill_alloc;
+	}
+
+	if (regulator_is_enabled(vcc)) {
+		dev_dbg(&pdev->dev, "Regulator already enabled\n");
+		rfkill_data->reg_enabled = 1;
+	}
+	rfkill_data->vcc = vcc;
+	rfkill_data->rf_kill = rf_kill;
+
+	ret = rfkill_register(rf_kill);
+	if (ret) {
+		dev_err(&pdev->dev, "Cannot register rfkill device\n");
+		goto err_rfkill_register;
+	}
+
+	platform_set_drvdata(pdev, rfkill_data);
+	dev_info(&pdev->dev, "%s initialized\n", pdata->name);
+
+	return 0;
+
+err_rfkill_register:
+	rfkill_destroy(rf_kill);
+err_rfkill_alloc:
+	kfree(rfkill_data);
+err_data_alloc:
+	regulator_put(vcc);
+out:
+	return ret;
+}
+
+static int __devexit rfkill_regulator_remove(struct platform_device *pdev)
+{
+	struct rfkill_regulator_data *rfkill_data = platform_get_drvdata(pdev);
+	struct rfkill *rf_kill = rfkill_data->rf_kill;
+
+	rfkill_unregister(rf_kill);
+	rfkill_destroy(rf_kill);
+	regulator_put(rfkill_data->vcc);
+	kfree(rfkill_data);
+
+	return 0;
+}
+
+static struct platform_driver rfkill_regulator_driver = {
+	.probe = rfkill_regulator_probe,
+	.remove = __devexit_p(rfkill_regulator_remove),
+	.driver = {
+		.name = "rfkill-regulator",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init rfkill_regulator_init(void)
+{
+	return platform_driver_register(&rfkill_regulator_driver);
+}
+module_init(rfkill_regulator_init);
+
+static void __exit rfkill_regulator_exit(void)
+{
+	platform_driver_unregister(&rfkill_regulator_driver);
+}
+module_exit(rfkill_regulator_exit);
+
+MODULE_AUTHOR("Guiming Zhuo <gmzhuo@gmail.com>");
+MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>");
+MODULE_DESCRIPTION("Regulator consumer driver for rfkill");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:rfkill-regulator");
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index 73e39c1..5c11608 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -1,5 +1,6 @@
 #include <linux/ieee80211.h>
 #include <net/cfg80211.h>
+#include "nl80211.h"
 #include "core.h"
 
 /* Default values, timeouts in ms */
@@ -53,8 +54,9 @@
 const struct mesh_setup default_mesh_setup = {
 	.path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP,
 	.path_metric = IEEE80211_PATH_METRIC_AIRTIME,
-	.vendor_ie = NULL,
-	.vendor_ie_len = 0,
+	.ie = NULL,
+	.ie_len = 0,
+	.is_secure = false,
 };
 
 int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
@@ -72,6 +74,10 @@
 	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
 		return -EOPNOTSUPP;
 
+	if (!(rdev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) &&
+	      setup->is_secure)
+		return -EOPNOTSUPP;
+
 	if (wdev->mesh_id_len)
 		return -EALREADY;
 
@@ -105,6 +111,19 @@
 	return err;
 }
 
+void cfg80211_notify_new_peer_candidate(struct net_device *dev,
+		const u8 *macaddr, const u8* ie, u8 ie_len, gfp_t gfp)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT))
+		return;
+
+	nl80211_send_new_peer_candidate(wiphy_to_dev(wdev->wiphy), dev,
+			macaddr, ie, ie_len, gfp);
+}
+EXPORT_SYMBOL(cfg80211_notify_new_peer_candidate);
+
 static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
 				 struct net_device *dev)
 {
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 297d7ce..0efa7fd 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -124,6 +124,7 @@
 	[NL80211_ATTR_BSS_HT_OPMODE] = { .type = NLA_U16 },
 
 	[NL80211_ATTR_MESH_CONFIG] = { .type = NLA_NESTED },
+	[NL80211_ATTR_SUPPORT_MESH_AUTH] = { .type = NLA_FLAG },
 
 	[NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY,
 					 .len = NL80211_HT_CAPABILITY_LEN },
@@ -594,6 +595,8 @@
 
 	if (dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)
 		NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_IBSS_RSN);
+	if (dev->wiphy.flags & WIPHY_FLAG_MESH_AUTH)
+		NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_MESH_AUTH);
 
 	NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES,
 		sizeof(u32) * dev->wiphy.n_cipher_suites,
@@ -1922,6 +1925,7 @@
 	[NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG },
 	[NL80211_STA_FLAG_WME] = { .type = NLA_FLAG },
 	[NL80211_STA_FLAG_MFP] = { .type = NLA_FLAG },
+	[NL80211_STA_FLAG_AUTHENTICATED] = { .type = NLA_FLAG },
 };
 
 static int parse_station_flags(struct genl_info *info,
@@ -2016,6 +2020,9 @@
 	sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO);
 	if (!sinfoattr)
 		goto nla_put_failure;
+	if (sinfo->filled & STATION_INFO_CONNECTED_TIME)
+		NLA_PUT_U32(msg, NL80211_STA_INFO_CONNECTED_TIME,
+			    sinfo->connected_time);
 	if (sinfo->filled & STATION_INFO_INACTIVE_TIME)
 		NLA_PUT_U32(msg, NL80211_STA_INFO_INACTIVE_TIME,
 			    sinfo->inactive_time);
@@ -2281,7 +2288,9 @@
 			err = -EINVAL;
 		if (params.supported_rates)
 			err = -EINVAL;
-		if (params.sta_flags_mask)
+		if (params.sta_flags_mask &
+				~(BIT(NL80211_STA_FLAG_AUTHENTICATED) |
+				  BIT(NL80211_STA_FLAG_AUTHORIZED)))
 			err = -EINVAL;
 		break;
 	default:
@@ -2343,11 +2352,16 @@
 		params.ht_capa =
 			nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
 
+	if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION])
+		params.plink_action =
+		    nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
+
 	if (parse_station_flags(info, &params))
 		return -EINVAL;
 
 	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
 	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
+	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
 	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
 		return -EINVAL;
 
@@ -2823,7 +2837,8 @@
 	nl80211_mesh_setup_params_policy[NL80211_MESH_SETUP_ATTR_MAX+1] = {
 	[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 },
 	[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 },
-	[NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE] = { .type = NLA_BINARY,
+	[NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG },
+	[NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY,
 		.len = IEEE80211_MAX_DATA_LEN },
 };
 
@@ -2925,14 +2940,16 @@
 		 IEEE80211_PATH_METRIC_VENDOR :
 		 IEEE80211_PATH_METRIC_AIRTIME;
 
-	if (tb[NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE]) {
+
+	if (tb[NL80211_MESH_SETUP_IE]) {
 		struct nlattr *ieattr =
-			tb[NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE];
+			tb[NL80211_MESH_SETUP_IE];
 		if (!is_valid_ie_attr(ieattr))
 			return -EINVAL;
-		setup->vendor_ie = nla_data(ieattr);
-		setup->vendor_ie_len = nla_len(ieattr);
+		setup->ie = nla_data(ieattr);
+		setup->ie_len = nla_len(ieattr);
 	}
+	setup->is_secure = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AUTH]);
 
 	return 0;
 }
@@ -5804,6 +5821,44 @@
 	nlmsg_free(msg);
 }
 
+void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev,
+		struct net_device *netdev,
+		const u8 *macaddr, const u8* ie, u8 ie_len,
+		gfp_t gfp)
+{
+	struct sk_buff *msg;
+	void *hdr;
+
+	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+	if (!msg)
+		return;
+
+	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NEW_PEER_CANDIDATE);
+	if (!hdr) {
+		nlmsg_free(msg);
+		return;
+	}
+
+	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, macaddr);
+	if (ie_len && ie)
+		NLA_PUT(msg, NL80211_ATTR_IE, ie_len , ie);
+
+	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);
+}
+
 void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
 				 struct net_device *netdev, const u8 *addr,
 				 enum nl80211_key_type key_type, int key_id,
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index dcac5cd..f2af695 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -50,6 +50,10 @@
 			       struct net_device *netdev, u16 reason,
 			       const u8 *ie, size_t ie_len, bool from_ap);
 
+void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev,
+				     struct net_device *netdev,
+				     const u8 *macaddr, const u8* ie, u8 ie_len,
+				     gfp_t gfp);
 void
 nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
 			    struct net_device *netdev, const u8 *addr,