X-Git-Url: https://git.rohieb.name/openwrt.git/blobdiff_plain/5e29bec1cd7de71eb6368adeb147e2432d782295..713c08cb30a8586b70fbc454fac345d633276a04:/package/mac80211/patches/302-rt2x00-Implement-support-for-rt2800pci.patch?ds=sidebyside

diff --git a/package/mac80211/patches/302-rt2x00-Implement-support-for-rt2800pci.patch b/package/mac80211/patches/302-rt2x00-Implement-support-for-rt2800pci.patch
index 6df88d1df..89323f517 100644
--- a/package/mac80211/patches/302-rt2x00-Implement-support-for-rt2800pci.patch
+++ b/package/mac80211/patches/302-rt2x00-Implement-support-for-rt2800pci.patch
@@ -1,39 +1,42 @@
-From dda25991ee4dc0a2ebe2e3b50857971fe1d878c4 Mon Sep 17 00:00:00 2001
+From c5d3ab153ef4b68c9c6fab32f6f292c4394b72d3 Mon Sep 17 00:00:00 2001
 From: Ivo van Doorn <IvDoorn@gmail.com>
-Date: Sat, 10 Jan 2009 11:03:23 +0100
-Subject: [PATCH] rt2x00: Implement support for rt2800pci
+Date: Thu, 21 May 2009 19:21:31 +0200
+Subject: [PATCH 2/2] rt2x00: Implement support for rt2800pci
 
 Add support for the rt2800pci chipset.
 
-Includes various patches from Mattias, Mark and Felix.
+Includes various patches from Mattias, Mark, Felix and Xose.
 
+Signed-off-by: Xose Vazquez Perez <xose.vazquez@gmail.com>
 Signed-off-by: Mattias Nissler <mattias.nissler@gmx.de>
 Signed-off-by: Mark Asselstine <asselsm@gmail.com>
 Signed-off-by: Felix Fietkau <nbd@openwrt.org>
 Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 ---
- drivers/net/wireless/rt2x00/Kconfig     |   15 +
+ drivers/net/wireless/rt2x00/Kconfig     |   26 +
  drivers/net/wireless/rt2x00/Makefile    |    1 +
- drivers/net/wireless/rt2x00/rt2800pci.c | 2707 +++++++++++++++++++++++++++++++
- drivers/net/wireless/rt2x00/rt2800pci.h | 1879 +++++++++++++++++++++
- drivers/net/wireless/rt2x00/rt2x00.h    |    4 +
- 5 files changed, 4606 insertions(+), 0 deletions(-)
+ drivers/net/wireless/rt2x00/rt2800pci.c | 3241 +++++++++++++++++++++++++++++++
+ drivers/net/wireless/rt2x00/rt2800pci.h | 1929 ++++++++++++++++++
+ drivers/net/wireless/rt2x00/rt2x00.h    |    6 +
+ 5 files changed, 5203 insertions(+), 0 deletions(-)
  create mode 100644 drivers/net/wireless/rt2x00/rt2800pci.c
  create mode 100644 drivers/net/wireless/rt2x00/rt2800pci.h
+
 --- a/drivers/net/wireless/rt2x00/Makefile
 +++ b/drivers/net/wireless/rt2x00/Makefile
-@@ -16,5 +16,6 @@ obj-$(CONFIG_RT2X00_LIB_USB)		+= rt2x00u
+@@ -17,6 +17,7 @@ obj-$(CONFIG_RT2X00_LIB_USB)		+= rt2x00u
  obj-$(CONFIG_RT2400PCI)			+= rt2400pci.o
  obj-$(CONFIG_RT2500PCI)			+= rt2500pci.o
  obj-$(CONFIG_RT61PCI)			+= rt61pci.o
 +obj-$(CONFIG_RT2800PCI)			+= rt2800pci.o
  obj-$(CONFIG_RT2500USB)			+= rt2500usb.o
  obj-$(CONFIG_RT73USB)			+= rt73usb.o
+ obj-$(CONFIG_RT2800USB)			+= rt2800usb.o
 --- /dev/null
 +++ b/drivers/net/wireless/rt2x00/rt2800pci.c
-@@ -0,0 +1,2707 @@
+@@ -0,0 +1,3241 @@
 +/*
-+	Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
++	Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
 +	<http://rt2x00.serialmonkey.com>
 +
 +	This program is free software; you can redistribute it and/or modify
@@ -65,12 +68,22 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +#include <linux/kernel.h>
 +#include <linux/module.h>
 +#include <linux/pci.h>
++#include <linux/platform_device.h>
 +#include <linux/eeprom_93cx6.h>
 +
 +#include "rt2x00.h"
 +#include "rt2x00pci.h"
++#include "rt2x00soc.h"
 +#include "rt2800pci.h"
 +
++#ifdef CONFIG_RT2800PCI_PCI_MODULE
++#define CONFIG_RT2800PCI_PCI
++#endif
++
++#ifdef CONFIG_RT2800PCI_WISOC_MODULE
++#define CONFIG_RT2800PCI_WISOC
++#endif
++
 +/*
 + * Allow hardware encryption to be disabled.
 + */
@@ -91,6 +104,8 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 + */
 +#define WAIT_FOR_BBP(__dev, __reg) \
 +	rt2x00pci_regbusy_read((__dev), BBP_CSR_CFG, BBP_CSR_CFG_BUSY, (__reg))
++#define WAIT_FOR_RFCSR(__dev, __reg) \
++	rt2x00pci_regbusy_read((__dev), RF_CSR_CFG, RF_CSR_CFG_BUSY, (__reg))
 +#define WAIT_FOR_RF(__dev, __reg) \
 +	rt2x00pci_regbusy_read((__dev), RF_CSR_CFG0, RF_CSR_CFG0_BUSY, (__reg))
 +#define WAIT_FOR_MCU(__dev, __reg) \
@@ -154,14 +169,66 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	mutex_unlock(&rt2x00dev->csr_mutex);
 +}
 +
++static void rt2800pci_rfcsr_write(struct rt2x00_dev *rt2x00dev,
++				  const unsigned int word, const u8 value)
++{
++	u32 reg;
++
++	mutex_lock(&rt2x00dev->csr_mutex);
++
++	/*
++	 * Wait until the RFCSR becomes available, afterwards we
++	 * can safely write the new data into the register.
++	 */
++	if (WAIT_FOR_RFCSR(rt2x00dev, &reg)) {
++		reg = 0;
++		rt2x00_set_field32(&reg, RF_CSR_CFG_DATA, value);
++		rt2x00_set_field32(&reg, RF_CSR_CFG_REGNUM, word);
++		rt2x00_set_field32(&reg, RF_CSR_CFG_WRITE, 1);
++		rt2x00_set_field32(&reg, RF_CSR_CFG_BUSY, 1);
++
++		rt2x00pci_register_write(rt2x00dev, RF_CSR_CFG, reg);
++	}
++
++	mutex_unlock(&rt2x00dev->csr_mutex);
++}
++
++static void rt2800pci_rfcsr_read(struct rt2x00_dev *rt2x00dev,
++				 const unsigned int word, u8 *value)
++{
++	u32 reg;
++
++	mutex_lock(&rt2x00dev->csr_mutex);
++
++	/*
++	 * Wait until the RFCSR becomes available, afterwards we
++	 * can safely write the read request into the register.
++	 * After the data has been written, we wait until hardware
++	 * returns the correct value, if at any time the register
++	 * doesn't become available in time, reg will be 0xffffffff
++	 * which means we return 0xff to the caller.
++	 */
++	if (WAIT_FOR_RFCSR(rt2x00dev, &reg)) {
++		reg = 0;
++		rt2x00_set_field32(&reg, RF_CSR_CFG_REGNUM, word);
++		rt2x00_set_field32(&reg, RF_CSR_CFG_WRITE, 0);
++		rt2x00_set_field32(&reg, RF_CSR_CFG_BUSY, 1);
++
++		rt2x00pci_register_write(rt2x00dev, RF_CSR_CFG, reg);
++
++		WAIT_FOR_RFCSR(rt2x00dev, &reg);
++	}
++
++	*value = rt2x00_get_field32(reg, RF_CSR_CFG_DATA);
++
++	mutex_unlock(&rt2x00dev->csr_mutex);
++}
++
 +static void rt2800pci_rf_write(struct rt2x00_dev *rt2x00dev,
 +			       const unsigned int word, const u32 value)
 +{
 +	u32 reg;
 +
-+	if (!word)
-+		return;
-+
 +	mutex_lock(&rt2x00dev->csr_mutex);
 +
 +	/*
@@ -188,6 +255,13 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +{
 +	u32 reg;
 +
++	/*
++	 * RT2880 and RT3052 don't support MCU requests.
++	 */
++	if (rt2x00_rt(&rt2x00dev->chip, RT2880) ||
++	    rt2x00_rt(&rt2x00dev->chip, RT3052))
++		return;
++
 +	mutex_lock(&rt2x00dev->csr_mutex);
 +
 +	/*
@@ -209,6 +283,44 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	mutex_unlock(&rt2x00dev->csr_mutex);
 +}
 +
++static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token)
++{
++	unsigned int i;
++	u32 reg;
++
++	for (i = 0; i < 200; i++) {
++		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) ||
++		    (rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD2) == token) ||
++		    (rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD3) == token))
++			break;
++
++		udelay(REGISTER_BUSY_DELAY);
++	}
++
++	if (i == 200)
++		ERROR(rt2x00dev, "MCU request failed, no response from hardware\n");
++
++	rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
++	rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
++}
++
++#ifdef CONFIG_RT2800PCI_WISOC
++static void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
++{
++	u32 *base_addr = (u32 *) KSEG1ADDR(0x1F040000); /* XXX for RT3052 */
++
++	memcpy_fromio(rt2x00dev->eeprom, base_addr, EEPROM_SIZE);
++}
++#else
++static inline void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
++{
++}
++#endif /* CONFIG_RT2800PCI_WISOC */
++
++#ifdef CONFIG_RT2800PCI_PCI
 +static void rt2800pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
 +{
 +	struct rt2x00_dev *rt2x00dev = eeprom->data;
@@ -239,6 +351,32 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	rt2x00pci_register_write(rt2x00dev, E2PROM_CSR, reg);
 +}
 +
++static void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
++{
++	struct eeprom_93cx6 eeprom;
++	u32 reg;
++ 
++	rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, &reg);
++
++	eeprom.data = rt2x00dev;
++	eeprom.register_read = rt2800pci_eepromregister_read;
++	eeprom.register_write = rt2800pci_eepromregister_write;
++	eeprom.width = !rt2x00_get_field32(reg, E2PROM_CSR_TYPE) ?
++	    PCI_EEPROM_WIDTH_93C46 : PCI_EEPROM_WIDTH_93C66;
++	eeprom.reg_data_in = 0;
++	eeprom.reg_data_out = 0;
++	eeprom.reg_data_clock = 0;
++	eeprom.reg_chip_select = 0;
++
++	eeprom_93cx6_multiread(&eeprom, EEPROM_BASE, rt2x00dev->eeprom,
++			       EEPROM_SIZE / sizeof(u16));
++}
++#else
++static inline void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
++{
++}
++#endif /* CONFIG_RT2800PCI_PCI */
++
 +#ifdef CONFIG_RT2X00_LIB_DEBUGFS
 +static const struct rt2x00debug rt2800pci_rt2x00debug = {
 +	.owner	= THIS_MODULE,
@@ -363,20 +501,41 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +				       struct rt2x00lib_crypto *crypto,
 +				       struct ieee80211_key_conf *key)
 +{
++	struct mac_wcid_entry wcid_entry;
++	struct mac_iveiv_entry iveiv_entry;
 +	u32 offset;
 +	u32 reg;
 +
-+	offset = MAC_WCID_ATTR_ENTRY(crypto->aid);
++	offset = MAC_WCID_ATTR_ENTRY(key->hw_key_idx);
 +
-+	reg = 0;
++	rt2x00pci_register_read(rt2x00dev, offset, &reg);
 +	rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_KEYTAB,
 +			   !!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE));
-+	rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_PAIRKEY_MODE,
-+			   crypto->cipher);
++	rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_CIPHER,
++			   (crypto->cmd == SET_KEY) * crypto->cipher);
 +	rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_BSS_IDX,
-+			   (crypto->cmd == SET_KEY) ? crypto->bssidx : 0);
-+	rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_RX_WIUDF, 0);
++			   (crypto->cmd == SET_KEY) * crypto->bssidx);
++	rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_RX_WIUDF, crypto->cipher);
 +	rt2x00pci_register_write(rt2x00dev, offset, reg);
++
++	offset = MAC_IVEIV_ENTRY(key->hw_key_idx);
++
++	memset(&iveiv_entry, 0, sizeof(iveiv_entry));
++	if ((crypto->cipher == CIPHER_TKIP) ||
++	    (crypto->cipher == CIPHER_TKIP_NO_MIC) ||
++	    (crypto->cipher == CIPHER_AES))
++		iveiv_entry.iv[3] |= 0x20;
++	iveiv_entry.iv[3] |= key->keyidx << 6;
++	rt2x00pci_register_multiwrite(rt2x00dev, offset,
++				      &iveiv_entry, sizeof(iveiv_entry));
++
++	offset = MAC_WCID_ENTRY(key->hw_key_idx);
++
++	memset(&wcid_entry, 0, sizeof(wcid_entry));
++	if (crypto->cmd == SET_KEY)
++		memcpy(&wcid_entry, crypto->address, ETH_ALEN);
++	rt2x00pci_register_multiwrite(rt2x00dev, offset,
++				      &wcid_entry, sizeof(wcid_entry));
 +}
 +
 +static int rt2800pci_config_shared_key(struct rt2x00_dev *rt2x00dev,
@@ -386,10 +545,11 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	struct hw_key_entry key_entry;
 +	struct rt2x00_field32 field;
 +	u32 offset;
-+	u32 mask;
 +	u32 reg;
 +
 +	if (crypto->cmd == SET_KEY) {
++		key->hw_key_idx = (4 * crypto->bssidx) + key->keyidx;
++
 +		memcpy(key_entry.key, crypto->key,
 +		       sizeof(key_entry.key));
 +		memcpy(key_entry.tx_mic, crypto->tx_mic,
@@ -400,34 +560,23 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +		offset = SHARED_KEY_ENTRY(key->hw_key_idx);
 +		rt2x00pci_register_multiwrite(rt2x00dev, offset,
 +					      &key_entry, sizeof(key_entry));
-+
-+		/*
-+		 * The driver does not support the IV/EIV generation
-+		 * in hardware. However it doesn't support the IV/EIV
-+		 * inside the ieee80211 frame either, but requires it
-+		 * to be provided seperately for the descriptor.
-+		 * rt2x00lib will cut the IV/EIV data out of all frames
-+		 * given to us by mac80211, but we must tell mac80211
-+		 * to generate the IV/EIV data.
-+		 */
-+		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
 +	}
 +
 +	/*
 +	 * The cipher types are stored over multiple registers
 +	 * starting with SHARED_KEY_MODE_BASE each word will have
-+	 * 32 bits and contains the cipher types for 2 modes each.
++	 * 32 bits and contains the cipher types for 2 bssidx each.
 +	 * Using the correct defines correctly will cause overhead,
 +	 * so just calculate the correct offset.
 +	 */
-+	mask = key->hw_key_idx % 8;
-+	field.bit_offset = (3 * mask);
++	field.bit_offset = 4 * (key->hw_key_idx % 8);
 +	field.bit_mask = 0x7 << field.bit_offset;
 +
 +	offset = SHARED_KEY_MODE_ENTRY(key->hw_key_idx / 8);
++
 +	rt2x00pci_register_read(rt2x00dev, offset, &reg);
 +	rt2x00_set_field32(&reg, field,
-+			   (crypto->cmd == SET_KEY) ? crypto->cipher : 0);
++			   (crypto->cmd == SET_KEY) * crypto->cipher);
 +	rt2x00pci_register_write(rt2x00dev, offset, reg);
 +
 +	/*
@@ -445,13 +594,18 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	struct hw_key_entry key_entry;
 +	u32 offset;
 +
-+	/*
-+	 * 1 pairwise key is possible per AID, this means that the AID
-+	 * equals our hw_key_idx.
-+	 */
-+	key->hw_key_idx = crypto->aid;
-+
 +	if (crypto->cmd == SET_KEY) {
++		/*
++		 * 1 pairwise key is possible per AID, this means that the AID
++		 * equals our hw_key_idx. Make sure the WCID starts _after_ the
++		 * last possible shared key entry.
++		 */
++		if (crypto->aid > (256 - 32))
++			return -ENOSPC;
++
++		key->hw_key_idx = 32 + crypto->aid;
++
++
 +		memcpy(key_entry.key, crypto->key,
 +		       sizeof(key_entry.key));
 +		memcpy(key_entry.tx_mic, crypto->tx_mic,
@@ -462,17 +616,6 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +		offset = PAIRWISE_KEY_ENTRY(key->hw_key_idx);
 +		rt2x00pci_register_multiwrite(rt2x00dev, offset,
 +					      &key_entry, sizeof(key_entry));
-+
-+		/*
-+		 * The driver does not support the IV/EIV generation
-+		 * in hardware. However it doesn't support the IV/EIV
-+		 * inside the ieee80211 frame either, but requires it
-+		 * to be provided seperately for the descriptor.
-+		 * rt2x00lib will cut the IV/EIV data out of all frames
-+		 * given to us by mac80211, but we must tell mac80211
-+		 * to generate the IV/EIV data.
-+		 */
-+		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
 +	}
 +
 +	/*
@@ -501,8 +644,7 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +			   !(filter_flags & FIF_PLCPFAIL));
 +	rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_NOT_TO_ME,
 +			   !(filter_flags & FIF_PROMISC_IN_BSS));
-+	rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_NOT_MY_BSSD,
-+			   !(filter_flags & FIF_OTHER_BSS));
++	rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_NOT_MY_BSSD, 0);
 +	rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_VER_ERROR, 1);
 +	rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_MULTICAST,
 +			   !(filter_flags & FIF_ALLMULTI));
@@ -521,7 +663,7 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_PSPOLL,
 +			   !(filter_flags & FIF_CONTROL));
 +	rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BA, 1);
-+	rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BAR, 1);
++	rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BAR, 0);
 +	rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_CNTL,
 +			   !(filter_flags & FIF_CONTROL));
 +	rt2x00pci_register_write(rt2x00dev, RX_FILTER_CFG, reg);
@@ -582,7 +724,7 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +
 +	rt2x00pci_register_read(rt2x00dev, TX_TIMEOUT_CFG, &reg);
 +	rt2x00_set_field32(&reg, TX_TIMEOUT_CFG_RX_ACK_TIMEOUT,
-+			   erp->ack_timeout);
++			   DIV_ROUND_UP(erp->ack_timeout, erp->slot_time));
 +	rt2x00pci_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg);
 +
 +	rt2x00pci_register_read(rt2x00dev, AUTO_RSP_CFG, &reg);
@@ -599,8 +741,7 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +
 +	rt2x00pci_register_write(rt2x00dev, LEGACY_BASIC_RATE,
 +				 erp->basic_rates);
-+	rt2x00pci_register_write(rt2x00dev, HT_BASIC_RATE,
-+				 erp->basic_rates >> 32);
++	rt2x00pci_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003);
 +
 +	rt2x00pci_register_read(rt2x00dev, BKOFF_SLOT_CFG, &reg);
 +	rt2x00_set_field32(&reg, BKOFF_SLOT_CFG_SLOT_TIME, erp->slot_time);
@@ -614,32 +755,33 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	rt2x00_set_field32(&reg, XIFS_TIME_CFG_EIFS, erp->eifs);
 +	rt2x00_set_field32(&reg, XIFS_TIME_CFG_BB_RXEND_ENABLE, 1);
 +	rt2x00pci_register_write(rt2x00dev, XIFS_TIME_CFG, reg);
++
++	rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
++	rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_INTERVAL,
++			   erp->beacon_int * 16);
++	rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg);
 +}
 +
 +static void rt2800pci_config_ant(struct rt2x00_dev *rt2x00dev,
 +				 struct antenna_setup *ant)
 +{
-+	u16 eeprom;
 +	u8 r1;
 +	u8 r3;
 +
-+	/*
-+	 * FIXME: Use requested antenna configuration.
-+	 */
-+
-+	rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
-+
 +	rt2800pci_bbp_read(rt2x00dev, 1, &r1);
 +	rt2800pci_bbp_read(rt2x00dev, 3, &r3);
 +
 +	/*
 +	 * Configure the TX antenna.
 +	 */
-+	switch (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH)) {
++	switch ((int)ant->tx) {
 +	case 1:
++		rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0);
 +		rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0);
 +		break;
 +	case 2:
++		rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2);
++		break;
 +	case 3:
 +		/* Do nothing */
 +		break;
@@ -648,7 +790,7 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	/*
 +	 * Configure the RX antenna.
 +	 */
-+	switch (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH)) {
++	switch ((int)ant->rx) {
 +	case 1:
 +		rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0);
 +		break;
@@ -687,43 +829,20 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	rt2x00dev->lna_gain = lna_gain;
 +}
 +
-+static void rt2800pci_config_channel(struct rt2x00_dev *rt2x00dev,
-+				     struct rf_channel *rf,
-+				     struct channel_info *info)
++static void rt2800pci_config_channel_rt2x(struct rt2x00_dev *rt2x00dev,
++					  struct ieee80211_conf *conf,
++					  struct rf_channel *rf,
++					  struct channel_info *info)
 +{
-+	u32 reg;
-+	unsigned int tx_pin;
-+	u16 eeprom;
-+
-+	tx_pin = 0;
-+	rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G1_EN, 1);
-+	rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A0_EN, 1);
-+	rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G0_EN, 1);
-+	rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A1_EN, 1);
-+	rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G1_EN, 1);
-+	rt2x00_set_field32(&tx_pin, TX_PIN_CFG_RFTR_EN, 1);
-+	rt2x00_set_field32(&tx_pin, TX_PIN_CFG_TRSW_EN, 1);
-+
 +	rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
 +
-+	/*
-+	 * Determine antenna settings from EEPROM
-+	 */
-+	rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
-+	if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) == 1) {
++	if (rt2x00dev->default_ant.tx == 1)
 +		rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_TX1, 1);
-+		/* Turn off unused PA or LNA when only 1T or 1R */
-+		rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A1_EN, 0);
-+		rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G1_EN, 0);
-+	}
 +
-+	if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH) == 1) {
++	if (rt2x00dev->default_ant.rx == 1) {
 +		rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX1, 1);
 +		rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX2, 1);
-+		/* Turn off unused PA or LNA when only 1T or 1R */
-+		rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A1_EN, 0);
-+		rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G1_EN, 0);
-+	} else if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH) == 2)
++	} else if (rt2x00dev->default_ant.rx == 2)
 +		rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX2, 1);
 +
 +	if (rf->channel > 14) {
@@ -750,19 +869,14 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +
 +		rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A,
 +				   TXPOWER_A_TO_DEV(info->tx_power2));
-+
-+		rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A0_EN, 1);
 +	} else {
 +		rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_G,
 +				   TXPOWER_G_TO_DEV(info->tx_power1));
 +		rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_G,
 +				   TXPOWER_G_TO_DEV(info->tx_power2));
-+
-+		rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G0_EN, 1);
 +	}
 +
-+	rt2x00_set_field32(&rf->rf4, RF4_BW40,
-+			   test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags));
++	rt2x00_set_field32(&rf->rf4, RF4_HT40, conf_is_ht40(conf));
 +
 +	rt2800pci_rf_write(rt2x00dev, 1, rf->rf1);
 +	rt2800pci_rf_write(rt2x00dev, 2, rf->rf2);
@@ -782,6 +896,52 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	rt2800pci_rf_write(rt2x00dev, 2, rf->rf2);
 +	rt2800pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
 +	rt2800pci_rf_write(rt2x00dev, 4, rf->rf4);
++}
++
++static void rt2800pci_config_channel_rt3x(struct rt2x00_dev *rt2x00dev,
++					  struct ieee80211_conf *conf,
++					  struct rf_channel *rf,
++					  struct channel_info *info)
++{
++	u8 rfcsr;
++
++	rt2800pci_rfcsr_write(rt2x00dev, 2, rf->rf1);
++	rt2800pci_rfcsr_write(rt2x00dev, 2, rf->rf3);
++
++	rt2800pci_rfcsr_read(rt2x00dev, 6, &rfcsr);
++	rt2x00_set_field8(&rfcsr, RFCSR6_R, rf->rf2);
++	rt2800pci_rfcsr_write(rt2x00dev, 6, rfcsr);
++
++	rt2800pci_rfcsr_read(rt2x00dev, 12, &rfcsr);
++	rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER,
++			  TXPOWER_G_TO_DEV(info->tx_power1));
++	rt2800pci_rfcsr_write(rt2x00dev, 12, rfcsr);
++
++	rt2800pci_rfcsr_read(rt2x00dev, 23, &rfcsr);
++	rt2x00_set_field8(&rfcsr, RFCSR23_FREQ_OFFSET, rt2x00dev->freq_offset);
++	rt2800pci_rfcsr_write(rt2x00dev, 23, rfcsr);
++
++	rt2800pci_rfcsr_write(rt2x00dev, 24,
++			      rt2x00dev->calibration[conf_is_ht40(conf)]);
++
++	rt2800pci_rfcsr_read(rt2x00dev, 23, &rfcsr);
++	rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1);
++	rt2800pci_rfcsr_write(rt2x00dev, 23, rfcsr);
++}
++
++static void rt2800pci_config_channel(struct rt2x00_dev *rt2x00dev,
++				     struct ieee80211_conf *conf,
++				     struct rf_channel *rf,
++				     struct channel_info *info)
++{
++	u32 reg;
++	unsigned int tx_pin;
++	u8 bbp;
++
++	if (rt2x00_rev(&rt2x00dev->chip) != RT3070_VERSION)
++		rt2800pci_config_channel_rt2x(rt2x00dev, conf, rf, info);
++	else
++		rt2800pci_config_channel_rt3x(rt2x00dev, conf, rf, info);
 +
 +	/*
 +	 * Change BBP settings
@@ -799,11 +959,6 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +			rt2800pci_bbp_write(rt2x00dev, 82, 0x84);
 +			rt2800pci_bbp_write(rt2x00dev, 75, 0x50);
 +		}
-+
-+		rt2x00pci_register_read(rt2x00dev, TX_BAND_CFG, &reg);
-+		rt2x00_set_field32(&rf->rf3, TX_BAND_CFG_A, 0);
-+		rt2x00_set_field32(&rf->rf3, TX_BAND_CFG_BG, 1);
-+		rt2x00pci_register_write(rt2x00dev, TX_BAND_CFG, reg);
 +	} else {
 +		rt2800pci_bbp_write(rt2x00dev, 82, 0xf2);
 +
@@ -811,15 +966,57 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +			rt2800pci_bbp_write(rt2x00dev, 75, 0x46);
 +		else
 +			rt2800pci_bbp_write(rt2x00dev, 75, 0x50);
++	}
++
++	rt2x00pci_register_read(rt2x00dev, TX_BAND_CFG, &reg);
++	rt2x00_set_field32(&reg, TX_BAND_CFG_HT40_PLUS, conf_is_ht40_plus(conf));
++	rt2x00_set_field32(&reg, TX_BAND_CFG_A, rf->channel > 14);
++	rt2x00_set_field32(&reg, TX_BAND_CFG_BG, rf->channel <= 14);
++	rt2x00pci_register_write(rt2x00dev, TX_BAND_CFG, reg);
 +
-+		rt2x00pci_register_read(rt2x00dev, TX_BAND_CFG, &reg);
-+		rt2x00_set_field32(&rf->rf3, TX_BAND_CFG_A, 1);
-+		rt2x00_set_field32(&rf->rf3, TX_BAND_CFG_BG, 0);
-+		rt2x00pci_register_write(rt2x00dev, TX_BAND_CFG, reg);
++	tx_pin = 0;
++
++	/* Turn on unused PA or LNA when not using 1T or 1R */
++	if (rt2x00dev->default_ant.tx != 1) {
++		rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A1_EN, 1);
++		rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G1_EN, 1);
 +	}
 +
++	/* Turn on unused PA or LNA when not using 1T or 1R */
++	if (rt2x00dev->default_ant.rx != 1) {
++		rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A1_EN, 1);
++		rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G1_EN, 1);
++	}
++
++	rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A0_EN, 1);
++	rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G0_EN, 1);
++	rt2x00_set_field32(&tx_pin, TX_PIN_CFG_RFTR_EN, 1);
++	rt2x00_set_field32(&tx_pin, TX_PIN_CFG_TRSW_EN, 1);
++	rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G0_EN, rf->channel <= 14);
++	rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A0_EN, rf->channel > 14);
++
 +	rt2x00pci_register_write(rt2x00dev, TX_PIN_CFG, tx_pin);
 +
++	rt2800pci_bbp_read(rt2x00dev, 4, &bbp);
++	rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * conf_is_ht40(conf));
++	rt2800pci_bbp_write(rt2x00dev, 4, bbp);
++
++	rt2800pci_bbp_read(rt2x00dev, 3, &bbp);
++	rt2x00_set_field8(&bbp, BBP3_HT40_PLUS, conf_is_ht40_plus(conf));
++	rt2800pci_bbp_write(rt2x00dev, 3, bbp);
++
++	if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) {
++		if (conf_is_ht40(conf)) {
++			rt2800pci_bbp_write(rt2x00dev, 69, 0x1a);
++			rt2800pci_bbp_write(rt2x00dev, 70, 0x0a);
++			rt2800pci_bbp_write(rt2x00dev, 73, 0x16);
++		} else {
++			rt2800pci_bbp_write(rt2x00dev, 69, 0x16);
++			rt2800pci_bbp_write(rt2x00dev, 70, 0x08);
++			rt2800pci_bbp_write(rt2x00dev, 73, 0x11);
++		}
++	}
++
 +	msleep(1);
 +}
 +
@@ -903,15 +1100,34 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	rt2x00pci_register_write(rt2x00dev, TX_RTY_CFG, reg);
 +}
 +
-+static void rt2800pci_config_duration(struct rt2x00_dev *rt2x00dev,
-+				      struct rt2x00lib_conf *libconf)
++static void rt2800pci_config_ps(struct rt2x00_dev *rt2x00dev,
++				struct rt2x00lib_conf *libconf)
 +{
++	enum dev_state state =
++	    (libconf->conf->flags & IEEE80211_CONF_PS) ?
++		STATE_SLEEP : STATE_AWAKE;
 +	u32 reg;
 +
-+	rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
-+	rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_INTERVAL,
-+			   libconf->conf->beacon_int * 16);
-+	rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg);
++	if (state == STATE_SLEEP) {
++		rt2x00pci_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0);
++
++		rt2x00pci_register_read(rt2x00dev, AUTOWAKEUP_CFG, &reg);
++		rt2x00_set_field32(&reg, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 5);
++		rt2x00_set_field32(&reg, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE,
++				   libconf->conf->listen_interval - 1);
++		rt2x00_set_field32(&reg, AUTOWAKEUP_CFG_AUTOWAKE, 1);
++		rt2x00pci_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg);
++
++		rt2x00dev->ops->lib->set_device_state(rt2x00dev, state);
++	} else {
++		rt2x00dev->ops->lib->set_device_state(rt2x00dev, state);
++
++		rt2x00pci_register_read(rt2x00dev, AUTOWAKEUP_CFG, &reg);
++		rt2x00_set_field32(&reg, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 0);
++		rt2x00_set_field32(&reg, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE, 0);
++		rt2x00_set_field32(&reg, AUTOWAKEUP_CFG_AUTOWAKE, 0);
++		rt2x00pci_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg);
++	}
 +}
 +
 +static void rt2800pci_config(struct rt2x00_dev *rt2x00dev,
@@ -922,14 +1138,14 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	rt2800pci_config_lna_gain(rt2x00dev, libconf);
 +
 +	if (flags & IEEE80211_CONF_CHANGE_CHANNEL)
-+		rt2800pci_config_channel(rt2x00dev, &libconf->rf,
-+					 &libconf->channel);
++		rt2800pci_config_channel(rt2x00dev, libconf->conf,
++					 &libconf->rf, &libconf->channel);
 +	if (flags & IEEE80211_CONF_CHANGE_POWER)
 +		rt2800pci_config_txpower(rt2x00dev, libconf->conf->power_level);
 +	if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
 +		rt2800pci_config_retry_limit(rt2x00dev, libconf);
-+	if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL)
-+		rt2800pci_config_duration(rt2x00dev, libconf);
++	if (flags & IEEE80211_CONF_CHANGE_PS)
++		rt2800pci_config_ps(rt2x00dev, libconf);
 +}
 +
 +/*
@@ -945,12 +1161,6 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	 */
 +	rt2x00pci_register_read(rt2x00dev, RX_STA_CNT0, &reg);
 +	qual->rx_failed = rt2x00_get_field32(reg, RX_STA_CNT0_CRC_ERR);
-+
-+	/*
-+	 * Update False CCA count from register.
-+	 */
-+	rt2x00pci_register_read(rt2x00dev, RX_STA_CNT1, &reg);
-+	qual->false_cca = rt2x00_get_field32(reg, RX_STA_CNT1_FALSE_CCA);
 +}
 +
 +static u8 rt2800pci_get_default_vgc(struct rt2x00_dev *rt2x00dev)
@@ -984,7 +1194,7 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +static void rt2800pci_link_tuner(struct rt2x00_dev *rt2x00dev,
 +				 struct link_qual *qual, const u32 count)
 +{
-+	if (rt2x00_rev(&rt2x00dev->chip) == RT2860_VERSION_C)
++	if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION)
 +		return;
 +
 +	/*
@@ -1003,19 +1213,31 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	return FIRMWARE_RT2860;
 +}
 +
-+static u16 rt2800pci_get_firmware_crc(const void *data, const size_t len)
++static int rt2800pci_check_firmware(struct rt2x00_dev *rt2x00dev,
++				    const u8 *data, const size_t len)
 +{
++	u16 fw_crc;
 +	u16 crc;
 +
 +	/*
++	 * Only support 8kb firmware files.
++	 */
++	if (len != 8192)
++		return FW_BAD_LENGTH;
++
++	/*
++	 * The last 2 bytes in the firmware array are the crc checksum itself,
++	 * this means that we should never pass those 2 bytes to the crc
++	 * algorithm.
++	 */
++	fw_crc = (data[len - 2] << 8 | data[len - 1]);
++
++	/*
 +	 * Use the crc ccitt algorithm.
 +	 * This will return the same value as the legacy driver which
 +	 * used bit ordering reversion on the both the firmware bytes
 +	 * before input input as well as on the final output.
 +	 * Obviously using crc ccitt directly is much more efficient.
-+	 * The last 2 bytes in the firmware array are the crc checksum itself,
-+	 * this means that we should never pass those 2 bytes to the crc
-+	 * algorithm.
 +	 */
 +	crc = crc_ccitt(~0, data, len - 2);
 +
@@ -1025,11 +1247,13 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	 * will be swapped, use swab16 to convert the crc to the correct
 +	 * value.
 +	 */
-+	return swab16(crc);
++	crc = swab16(crc);
++
++	return (fw_crc == crc) ? FW_OK : FW_BAD_CRC;
 +}
 +
 +static int rt2800pci_load_firmware(struct rt2x00_dev *rt2x00dev,
-+				   const void *data, const size_t len)
++				   const u8 *data, const size_t len)
 +{
 +	unsigned int i;
 +	u32 reg;
@@ -1161,26 +1385,31 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	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;
 +	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;
 +	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;
 +	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;
 +	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, 0);
++	rt2x00pci_register_write(rt2x00dev, RX_CRX_IDX, rt2x00dev->rx[0].limit - 1);
++	rt2x00pci_register_write(rt2x00dev, RX_DRX_IDX, 0);
 +
 +	/*
 +	 * Enable global DMA configuration
@@ -1251,7 +1480,7 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	rt2x00_set_field32(&reg, BCN_TIME_CFG_TX_TIME_COMPENSATE, 0);
 +	rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg);
 +
-+	rt2x00pci_register_write(rt2x00dev, TX_SW_CFG0, 0x00040a06);
++	rt2x00pci_register_write(rt2x00dev, TX_SW_CFG0, 0x00000000);
 +	rt2x00pci_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
 +
 +	rt2x00pci_register_read(rt2x00dev, TX_LINK_CFG, &reg);
@@ -1272,7 +1501,11 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +
 +	rt2x00pci_register_read(rt2x00dev, MAX_LEN_CFG, &reg);
 +	rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_MPDU, AGGREGATION_SIZE);
-+	rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_PSDU, 1);
++	if (rt2x00_rev(&rt2x00dev->chip) >= RT2880E_VERSION &&
++	    rt2x00_rev(&rt2x00dev->chip) < RT3070_VERSION)
++		rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_PSDU, 2);
++	else
++		rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_PSDU, 1);
 +	rt2x00_set_field32(&reg, MAX_LEN_CFG_MIN_PSDU, 0);
 +	rt2x00_set_field32(&reg, MAX_LEN_CFG_MIN_MPDU, 0);
 +	rt2x00pci_register_write(rt2x00dev, MAX_LEN_CFG, reg);
@@ -1288,25 +1521,25 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	rt2x00pci_register_write(rt2x00dev, AUTO_RSP_CFG, reg);
 +
 +	rt2x00pci_register_read(rt2x00dev, CCK_PROT_CFG, &reg);
-+	rt2x00_set_field32(&reg, CCK_PROT_CFG_PROTECT_RATE, 3);
++	rt2x00_set_field32(&reg, CCK_PROT_CFG_PROTECT_RATE, 8);
 +	rt2x00_set_field32(&reg, CCK_PROT_CFG_PROTECT_CTRL, 0);
 +	rt2x00_set_field32(&reg, CCK_PROT_CFG_PROTECT_NAV, 1);
 +	rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_CCK, 1);
 +	rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_OFDM, 1);
 +	rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_MM20, 1);
-+	rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_MM40, 0);
++	rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_MM40, 1);
 +	rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_GF20, 1);
 +	rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_GF40, 1);
 +	rt2x00pci_register_write(rt2x00dev, CCK_PROT_CFG, reg);
 +
 +	rt2x00pci_register_read(rt2x00dev, OFDM_PROT_CFG, &reg);
-+	rt2x00_set_field32(&reg, OFDM_PROT_CFG_PROTECT_RATE, 3);
++	rt2x00_set_field32(&reg, OFDM_PROT_CFG_PROTECT_RATE, 8);
 +	rt2x00_set_field32(&reg, OFDM_PROT_CFG_PROTECT_CTRL, 0);
 +	rt2x00_set_field32(&reg, OFDM_PROT_CFG_PROTECT_NAV, 1);
 +	rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_CCK, 1);
 +	rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_OFDM, 1);
 +	rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_MM20, 1);
-+	rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_MM40, 0);
++	rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_MM40, 1);
 +	rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_GF20, 1);
 +	rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_GF40, 1);
 +	rt2x00pci_register_write(rt2x00dev, OFDM_PROT_CFG, reg);
@@ -1364,6 +1597,8 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +
 +	rt2x00pci_register_read(rt2x00dev, TX_RTS_CFG, &reg);
 +	rt2x00_set_field32(&reg, TX_RTS_CFG_AUTO_RTS_RETRY_LIMIT, 32);
++	rt2x00_set_field32(&reg, TX_RTS_CFG_RTS_THRES,
++			   IEEE80211_MAX_RTS_THRESHOLD);
 +	rt2x00_set_field32(&reg, TX_RTS_CFG_RTS_FBK_EN, 0);
 +	rt2x00pci_register_write(rt2x00dev, TX_RTS_CFG, reg);
 +
@@ -1373,19 +1608,19 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	/*
 +	 * ASIC will keep garbage value after boot, clear encryption keys.
 +	 */
-+	for (i = 0; i < 254; i++) {
-+		u32 wcid[2] = { 0xffffffff, 0x0000ffff };
++	for (i = 0; i < 256; i++) {
++		u32 wcid[2] = { 0xffffffff, 0x00ffffff };
 +		rt2x00pci_register_multiwrite(rt2x00dev, MAC_WCID_ENTRY(i),
 +					      wcid, sizeof(wcid));
++
++		rt2x00pci_register_write(rt2x00dev, MAC_WCID_ATTR_ENTRY(i), 1);
++		rt2x00pci_register_write(rt2x00dev, MAC_IVEIV_ENTRY(i), 0);
 +	}
 +
-+	for (i = 0; i < 4; i++)
++	for (i = 0; i < 16; i++)
 +		rt2x00pci_register_write(rt2x00dev,
 +					 SHARED_KEY_MODE_ENTRY(i), 0);
 +
-+	for (i = 0; i < 256; i++)
-+		rt2x00pci_register_write(rt2x00dev, MAC_WCID_ATTR_ENTRY(i), 1);
-+
 +	/*
 +	 * Clear all beacons
 +	 * For the Beacon base registers we only need to clear
@@ -1426,12 +1661,12 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	rt2x00pci_register_read(rt2x00dev, LG_FBK_CFG0, &reg);
 +	rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS0FBK, 8);
 +	rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS1FBK, 8);
-+	rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS2FBK, 10);
-+	rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS3FBK, 11);
-+	rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS4FBK, 12);
-+	rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS5FBK, 13);
-+	rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS6FBK, 14);
-+	rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS7FBK, 15);
++	rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS2FBK, 3);
++	rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS3FBK, 10);
++	rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS4FBK, 11);
++	rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS5FBK, 12);
++	rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS6FBK, 13);
++	rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS7FBK, 14);
 +	rt2x00pci_register_write(rt2x00dev, LG_FBK_CFG0, reg);
 +
 +	rt2x00pci_register_read(rt2x00dev, LG_FBK_CFG1, &reg);
@@ -1482,8 +1717,8 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	 * BBP was enabled after firmware was loaded,
 +	 * but we need to reactivate it now.
 +	 */
-+	rt2x00pci_register_write(rt2x00dev, H2M_BBP_AGENT, 0x00000000);
-+	rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0x00000000);
++	rt2x00pci_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
++	rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
 +	msleep(1);
 +
 +	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
@@ -1523,14 +1758,20 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	rt2800pci_bbp_write(rt2x00dev, 103, 0x00);
 +	rt2800pci_bbp_write(rt2x00dev, 105, 0x05);
 +
-+	if (rt2x00_rev(&rt2x00dev->chip) == RT2860_VERSION_C) {
++	if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) {
 +		rt2800pci_bbp_write(rt2x00dev, 69, 0x16);
 +		rt2800pci_bbp_write(rt2x00dev, 73, 0x12);
 +	}
 +
-+	if (rt2x00_rev(&rt2x00dev->chip) == RT2860_VERSION_D)
++	if (rt2x00_rev(&rt2x00dev->chip) > RT2860D_VERSION)
 +		rt2800pci_bbp_write(rt2x00dev, 84, 0x19);
 +
++	if (rt2x00_rt(&rt2x00dev->chip, RT3052)) {
++		rt2800pci_bbp_write(rt2x00dev, 31, 0x08);
++		rt2800pci_bbp_write(rt2x00dev, 78, 0x0e);
++		rt2800pci_bbp_write(rt2x00dev, 80, 0x08);
++	}
++
 +	for (i = 0; i < EEPROM_BBP_SIZE; i++) {
 +		rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom);
 +
@@ -1544,6 +1785,144 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	return 0;
 +}
 +
++static u8 rt2800pci_init_rx_filter(struct rt2x00_dev *rt2x00dev,
++				   bool bw40, u8 rfcsr24, u8 filter_target)
++{
++	unsigned int i;
++	u8 bbp;
++	u8 rfcsr;
++	u8 passband;
++	u8 stopband;
++	u8 overtuned = 0;
++
++	rt2800pci_rfcsr_write(rt2x00dev, 24, rfcsr24);
++
++	rt2800pci_bbp_read(rt2x00dev, 4, &bbp);
++	rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * bw40);
++	rt2800pci_bbp_write(rt2x00dev, 4, bbp);
++
++	rt2800pci_rfcsr_read(rt2x00dev, 22, &rfcsr);
++	rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 1);
++	rt2800pci_rfcsr_write(rt2x00dev, 22, rfcsr);
++
++	/*
++	 * Set power & frequency of passband test tone
++	 */
++	rt2800pci_bbp_write(rt2x00dev, 24, 0);
++
++	for (i = 0; i < 100; i++) {
++		rt2800pci_bbp_write(rt2x00dev, 25, 0x90);
++		msleep(1);
++
++		rt2800pci_bbp_read(rt2x00dev, 55, &passband);
++		if (passband)
++			break;
++	}
++
++	/*
++	 * Set power & frequency of stopband test tone
++	 */
++	rt2800pci_bbp_write(rt2x00dev, 24, 0x06);
++
++	for (i = 0; i < 100; i++) {
++		rt2800pci_bbp_write(rt2x00dev, 25, 0x90);
++		msleep(1);
++
++		rt2800pci_bbp_read(rt2x00dev, 55, &stopband);
++
++		if ((passband - stopband) <= filter_target) {
++			rfcsr24++;
++			overtuned += ((passband - stopband) == filter_target);
++		} else
++			break;
++
++		rt2800pci_rfcsr_write(rt2x00dev, 24, rfcsr24);
++	}
++
++	rfcsr24 -= !!overtuned;
++
++	rt2800pci_rfcsr_write(rt2x00dev, 24, rfcsr24);
++	return rfcsr24;
++}
++
++static int rt2800pci_init_rfcsr(struct rt2x00_dev *rt2x00dev)
++{
++	u8 rfcsr;
++	u8 bbp;
++	
++	if (!rt2x00_rf(&rt2x00dev->chip, RF3020) &&
++	    !rt2x00_rf(&rt2x00dev->chip, RF3021) &&
++	    !rt2x00_rf(&rt2x00dev->chip, RF3022))
++		return 0;
++
++	/*
++	 * Init RF calibration.
++	 */
++	rt2800pci_rfcsr_read(rt2x00dev, 30, &rfcsr);
++	rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1);
++	rt2800pci_rfcsr_write(rt2x00dev, 30, rfcsr);
++	msleep(1);
++	rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 0);
++	rt2800pci_rfcsr_write(rt2x00dev, 30, rfcsr);
++
++	rt2800pci_rfcsr_write(rt2x00dev, 0, 0x50);
++	rt2800pci_rfcsr_write(rt2x00dev, 1, 0x01);
++	rt2800pci_rfcsr_write(rt2x00dev, 2, 0xf7);
++	rt2800pci_rfcsr_write(rt2x00dev, 3, 0x75);
++	rt2800pci_rfcsr_write(rt2x00dev, 4, 0x40);
++	rt2800pci_rfcsr_write(rt2x00dev, 5, 0x03);
++	rt2800pci_rfcsr_write(rt2x00dev, 6, 0x02);
++	rt2800pci_rfcsr_write(rt2x00dev, 7, 0x50);
++	rt2800pci_rfcsr_write(rt2x00dev, 8, 0x39);
++	rt2800pci_rfcsr_write(rt2x00dev, 9, 0x0f);
++	rt2800pci_rfcsr_write(rt2x00dev, 10, 0x60);
++	rt2800pci_rfcsr_write(rt2x00dev, 11, 0x21);
++	rt2800pci_rfcsr_write(rt2x00dev, 12, 0x75);
++	rt2800pci_rfcsr_write(rt2x00dev, 13, 0x75);
++	rt2800pci_rfcsr_write(rt2x00dev, 14, 0x90);
++	rt2800pci_rfcsr_write(rt2x00dev, 15, 0x58);
++	rt2800pci_rfcsr_write(rt2x00dev, 16, 0xb3);
++	rt2800pci_rfcsr_write(rt2x00dev, 17, 0x92);
++	rt2800pci_rfcsr_write(rt2x00dev, 18, 0x2c);
++	rt2800pci_rfcsr_write(rt2x00dev, 19, 0x02);
++	rt2800pci_rfcsr_write(rt2x00dev, 20, 0xba);
++	rt2800pci_rfcsr_write(rt2x00dev, 21, 0xdb);
++	rt2800pci_rfcsr_write(rt2x00dev, 22, 0x00);
++	rt2800pci_rfcsr_write(rt2x00dev, 23, 0x31);
++	rt2800pci_rfcsr_write(rt2x00dev, 24, 0x08);
++	rt2800pci_rfcsr_write(rt2x00dev, 25, 0x01);
++	rt2800pci_rfcsr_write(rt2x00dev, 26, 0x25);
++	rt2800pci_rfcsr_write(rt2x00dev, 27, 0x23);
++	rt2800pci_rfcsr_write(rt2x00dev, 28, 0x13);
++	rt2800pci_rfcsr_write(rt2x00dev, 29, 0x83);
++
++	/*
++	 * Set RX Filter calibration for 20MHz and 40MHz
++	 */
++	rt2x00dev->calibration[0] =
++	    rt2800pci_init_rx_filter(rt2x00dev, false, 0x07, 0x16);
++	rt2x00dev->calibration[1] =
++	    rt2800pci_init_rx_filter(rt2x00dev, true, 0x27, 0x19);
++
++	/*
++	 * Set back to initial state
++	 */
++	rt2800pci_bbp_write(rt2x00dev, 24, 0);
++
++	rt2800pci_rfcsr_read(rt2x00dev, 22, &rfcsr);
++	rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 0);
++	rt2800pci_rfcsr_write(rt2x00dev, 22, rfcsr);
++
++	/*
++	 * set BBP back to BW20
++	 */
++	rt2800pci_bbp_read(rt2x00dev, 4, &bbp);
++	rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 0);
++	rt2800pci_bbp_write(rt2x00dev, 4, bbp);
++
++	return 0;
++}
++
 +/*
 + * Device state switch handlers.
 + */
@@ -1625,7 +2004,9 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	if (unlikely(rt2800pci_wait_wpdma_ready(rt2x00dev) ||
 +		     rt2800pci_init_queues(rt2x00dev) ||
 +		     rt2800pci_init_registers(rt2x00dev) ||
-+		     rt2800pci_init_bbp(rt2x00dev)))
++		     rt2800pci_wait_wpdma_ready(rt2x00dev) ||
++		     rt2800pci_init_bbp(rt2x00dev) ||
++		     rt2800pci_init_rfcsr(rt2x00dev)))
 +		return -EIO;
 +
 +	/*
@@ -1633,12 +2014,14 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	 */
 +	rt2800pci_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0xff, 0, 0);
 +
-+	/* Wait for DMA, ignore error */
-+	rt2800pci_wait_wpdma_ready(rt2x00dev);
-+
 +	/*
 +	 * Enable RX.
 +	 */
++	rt2x00pci_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
++	rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_TX, 1);
++	rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 0);
++	rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
++
 +	rt2x00pci_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
 +	rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 1);
 +	rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 1);
@@ -1694,12 +2077,17 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +static int rt2800pci_set_state(struct rt2x00_dev *rt2x00dev,
 +			       enum dev_state state)
 +{
-+	rt2x00pci_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0);
++	/*
++	 * Always put the device to sleep (even when we intend to wakup!)
++	 * if the device is booting and wasn't asleep it will return
++	 * failure when attempting to wakup.
++	 */
++	rt2800pci_mcu_request(rt2x00dev, MCU_SLEEP, 0xff, 0, 2);
 +
-+	if (state == STATE_AWAKE)
-+		rt2800pci_mcu_request(rt2x00dev, MCU_WAKEUP, 0xff, 0, 0);
-+	else
-+		rt2800pci_mcu_request(rt2x00dev, MCU_SLEEP, 0xff, 0, 2);
++	if (state == STATE_AWAKE) {
++		rt2800pci_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKUP, 0, 0);
++		rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKUP);
++	}
 +
 +	return 0;
 +}
@@ -1773,7 +2161,6 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	 */
 +	rt2x00_desc_read(txwi, 0, &word);
 +	rt2x00_set_field32(&word, TXWI_W0_FRAG,
-+			   test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags) ||
 +			   test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
 +	rt2x00_set_field32(&word, TXWI_W0_MIMO_PS, 0);
 +	rt2x00_set_field32(&word, TXWI_W0_CF_ACK, 0);
@@ -1799,16 +2186,23 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +			   test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags));
 +	rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->ba_size);
 +	rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID,
-+			   skbdesc->entry->entry_idx);
-+	rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT, skb->len);
++			   test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ?
++			       txdesc->key_idx : 0xff);
++	rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT,
++			   skb->len - txdesc->l2pad);
 +	rt2x00_set_field32(&word, TXWI_W1_PACKETID,
 +			   skbdesc->entry->queue->qid);
 +	rt2x00_desc_write(txwi, 1, word);
 +
-+	if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) {
-+		_rt2x00_desc_write(txwi, 2, skbdesc->iv[0]);
-+		_rt2x00_desc_write(txwi, 3, skbdesc->iv[1]);
-+	}
++	/*
++	 * Always write 0 to IV/EIV fields, hardware will insert the IV
++	 * from the IVEIV register when ENTRY_TXD_ENCRYPT_IV is set to 0.
++	 * When ENTRY_TXD_ENCRYPT_IV is set to 1 it will use the IV data
++	 * from the descriptor. The TXWI_W1_WIRELESS_CLI_ID indicates which
++	 * crypto entry in the registers should be used to encrypt the frame.
++	 */
++	_rt2x00_desc_write(txwi, 2, 0 /* skbdesc->iv[0] */);
++	_rt2x00_desc_write(txwi, 3, 0 /* skbdesc->iv[1] */);
 +
 +	/*
 +	 * Initialize TX descriptor
@@ -1835,7 +2229,8 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	rt2x00_desc_write(txd, 2, word);
 +
 +	rt2x00_desc_read(txd, 3, &word);
-+	rt2x00_set_field32(&word, TXD_W3_WIV, 1);
++	rt2x00_set_field32(&word, TXD_W3_WIV,
++			   !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags));
 +	rt2x00_set_field32(&word, TXD_W3_QSEL, 2);
 +	rt2x00_desc_write(txd, 3, word);
 +}
@@ -1910,6 +2305,24 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX(qidx), idx);
 +}
 +
++static void rt2800pci_kill_tx_queue(struct rt2x00_dev *rt2x00dev,
++				    const enum data_queue_qid qid)
++{
++	u32 reg;
++
++	if (qid == QID_BEACON) {
++		rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, 0);
++		return;
++	}
++
++	rt2x00pci_register_read(rt2x00dev, WPDMA_RST_IDX, &reg);
++	rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX0, (qid == QID_AC_BE));
++	rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX1, (qid == QID_AC_BK));
++	rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX2, (qid == QID_AC_VI));
++	rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX3, (qid == QID_AC_VO));
++	rt2x00pci_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
++}
++
 +/*
 + * RX control handlers
 + */
@@ -1941,7 +2354,7 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +		 * decryption. This prevents us from correct providing
 +		 * correct statistics through debugfs.
 +		 */
-+		rxdesc->cipher = CIPHER_NONE;
++		rxdesc->cipher = rt2x00_get_field32(rxwi0, RXWI_W0_UDF);
 +		rxdesc->cipher_status =
 +		    rt2x00_get_field32(rxd3, RXD_W3_CIPHER_ERROR);
 +	}
@@ -1964,6 +2377,9 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	if (rt2x00_get_field32(rxd3, RXD_W3_MY_BSS))
 +		rxdesc->dev_flags |= RXDONE_MY_BSS;
 +
++	if (rt2x00_get_field32(rxd3, RXD_W3_L2PAD))
++		rxdesc->dev_flags |= RXDONE_L2PAD;
++
 +	if (rt2x00_get_field32(rxwi1, RXWI_W1_SHORT_GI))
 +		rxdesc->flags |= RX_FLAG_SHORT_GI;
 +
@@ -1980,13 +2396,12 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	/*
 +	 * Mask of 0x8 bit to remove the short preamble flag.
 +	 */
-+	if (rxdesc->dev_flags == RATE_MODE_CCK)
++	if (rxdesc->rate_mode == RATE_MODE_CCK)
 +		rxdesc->signal &= ~0x8;
 +
 +	rxdesc->rssi =
 +	    (rt2x00_get_field32(rxwi2, RXWI_W2_RSSI0) +
-+	     rt2x00_get_field32(rxwi2, RXWI_W2_RSSI1) +
-+	     rt2x00_get_field32(rxwi2, RXWI_W2_RSSI2)) / 3;
++	     rt2x00_get_field32(rxwi2, RXWI_W2_RSSI1)) / 2;
 +
 +	rxdesc->noise =
 +	    (rt2x00_get_field32(rxwi3, RXWI_W3_SNR0) +
@@ -1995,9 +2410,15 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	rxdesc->size = rt2x00_get_field32(rxwi0, RXWI_W0_MPDU_TOTAL_BYTE_COUNT);
 +
 +	/*
++	 * Set RX IDX in register to inform hardware that we have handled
++	 * this entry and it is available for reuse again.
++	 */
++	rt2x00pci_register_write(rt2x00dev, RX_CRX_IDX, entry->entry_idx);
++
++	/*
 +	 * Remove TXWI descriptor from start of buffer.
 +	 */
-+	skb_pull(entry->skb, TXWI_DESC_SIZE);
++	skb_pull(entry->skb, RXWI_DESC_SIZE);
 +	skb_trim(entry->skb, rxdesc->size);
 +}
 +
@@ -2121,26 +2542,22 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 + */
 +static int rt2800pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
 +{
-+	struct eeprom_93cx6 eeprom;
-+	u32 reg;
 +	u16 word;
 +	u8 *mac;
 +	u8 default_lna_gain;
 +
-+	rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, &reg);
-+
-+	eeprom.data = rt2x00dev;
-+	eeprom.register_read = rt2800pci_eepromregister_read;
-+	eeprom.register_write = rt2800pci_eepromregister_write;
-+	eeprom.width = rt2x00_get_field32(reg, E2PROM_CSR_TYPE_93C46) ?
-+	    PCI_EEPROM_WIDTH_93C46 : PCI_EEPROM_WIDTH_93C66;
-+	eeprom.reg_data_in = 0;
-+	eeprom.reg_data_out = 0;
-+	eeprom.reg_data_clock = 0;
-+	eeprom.reg_chip_select = 0;
-+
-+	eeprom_93cx6_multiread(&eeprom, EEPROM_BASE, rt2x00dev->eeprom,
-+			       EEPROM_SIZE / sizeof(u16));
++	/*
++	 * Read EEPROM into buffer
++	 */
++	switch(rt2x00dev->chip.rt) {
++	case RT2880:
++	case RT3052:
++		rt2800pci_read_eeprom_soc(rt2x00dev);
++		break;
++	default:
++		rt2800pci_read_eeprom_pci(rt2x00dev);
++		break;
++	}
 +
 +	/*
 +	 * Start validation of the data that has been read.
@@ -2160,12 +2577,27 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +		rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2820);
 +		rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
 +		EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
++	} else if (rt2x00_rev(&rt2x00dev->chip) < RT2883_VERSION) {
++		/*
++		 * There is a max of 2 RX streams for RT2860 series
++		 */
++		if (rt2x00_get_field16(word, EEPROM_ANTENNA_RXPATH) > 2)
++			rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2);
++		rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
 +	}
 +
 +	rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word);
-+	if (word != 0) {
-+		/* NIC configuration must always be 0. */
-+		word = 0;
++	if (word == 0xffff) {
++		rt2x00_set_field16(&word, EEPROM_NIC_HW_RADIO, 0);
++		rt2x00_set_field16(&word, EEPROM_NIC_DYNAMIC_TX_AGC, 0);
++		rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_BG, 0);
++		rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_A, 0);
++		rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0);
++		rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_BG, 0);
++		rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_A, 0);
++		rt2x00_set_field16(&word, EEPROM_NIC_WPS_PBC, 0);
++		rt2x00_set_field16(&word, EEPROM_NIC_BW40M_BG, 0);
++		rt2x00_set_field16(&word, EEPROM_NIC_BW40M_A, 0);
 +		rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word);
 +		EEPROM(rt2x00dev, "NIC: 0x%04x\n", word);
 +	}
@@ -2231,7 +2663,6 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	u32 reg;
 +	u16 value;
 +	u16 eeprom;
-+	u16 device;
 +
 +	/*
 +	 * Read EEPROM word for configuration.
@@ -2240,25 +2671,32 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +
 +	/*
 +	 * Identify RF chipset.
-+	 * To determine the RT chip we have to read the
-+	 * PCI header of the device.
 +	 */
-+	pci_read_config_word(to_pci_dev(rt2x00dev->dev),
-+			     PCI_CONFIG_HEADER_DEVICE, &device);
 +	value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
 +	rt2x00pci_register_read(rt2x00dev, MAC_CSR0, &reg);
-+	reg = rt2x00_get_field32(reg, MAC_CSR0_ASIC_REV);
-+	rt2x00_set_chip(rt2x00dev, device, value, reg);
++	rt2x00_set_chip_rf(rt2x00dev, value, reg);
 +
 +	if (!rt2x00_rf(&rt2x00dev->chip, RF2820) &&
 +	    !rt2x00_rf(&rt2x00dev->chip, RF2850) &&
 +	    !rt2x00_rf(&rt2x00dev->chip, RF2720) &&
-+	    !rt2x00_rf(&rt2x00dev->chip, RF2750)) {
++	    !rt2x00_rf(&rt2x00dev->chip, RF2750) &&
++	    !rt2x00_rf(&rt2x00dev->chip, RF3020) &&
++	    !rt2x00_rf(&rt2x00dev->chip, RF2020) &&
++	    !rt2x00_rf(&rt2x00dev->chip, RF3021) &&
++	    !rt2x00_rf(&rt2x00dev->chip, RF3022)) {
 +		ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
 +		return -ENODEV;
 +	}
 +
 +	/*
++	 * Identify default antenna configuration.
++	 */
++	rt2x00dev->default_ant.tx =
++	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH);
++	rt2x00dev->default_ant.rx =
++	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH);
++
++	/*
 +	 * Read frequency offset and RF programming sequence.
 +	 */
 +	rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom);
@@ -2333,8 +2771,8 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	/* 802.11 HyperLan 2 */
 +	{ 100, 0x18402ec8, 0x184c06b2, 0x18178a55, 0x180ed783 },
 +	{ 102, 0x18402ec8, 0x184c06b2, 0x18578a55, 0x180ed793 },
-+	{ 104, 0x18402ec8, 0x184c06b2, 0x18578a55, 0x180ed1a3 },
-+	{ 108, 0x18402ecc, 0x184c0a32, 0x18578a55, 0x180ed193 },
++	{ 104, 0x18402ec8, 0x185c06b2, 0x18578a55, 0x180ed1a3 },
++	{ 108, 0x18402ecc, 0x185c0a32, 0x18578a55, 0x180ed193 },
 +	{ 110, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed183 },
 +	{ 112, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed19b },
 +	{ 116, 0x18402ecc, 0x184c0a3a, 0x18178a55, 0x180ed1a3 },
@@ -2374,13 +2812,16 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	char *tx_power1;
 +	char *tx_power2;
 +	unsigned int i;
++	u16 eeprom;
 +
 +	/*
 +	 * Initialize all hw fields.
 +	 */
 +	rt2x00dev->hw->flags =
 +	    IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
-+	    IEEE80211_HW_SIGNAL_DBM;
++	    IEEE80211_HW_SIGNAL_DBM |
++	    IEEE80211_HW_SUPPORTS_PS |
++	    IEEE80211_HW_PS_NULLFUNC_STACK;
 +	rt2x00dev->hw->extra_tx_headroom = TXWI_DESC_SIZE;
 +
 +	SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
@@ -2388,6 +2829,8 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +				rt2x00_eeprom_addr(rt2x00dev,
 +						   EEPROM_MAC_ADDR_0));
 +
++	rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
++
 +	/*
 +	 * Initialize hw_mode information.
 +	 */
@@ -2395,7 +2838,9 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
 +
 +	if (rt2x00_rf(&rt2x00dev->chip, RF2820) ||
-+	    rt2x00_rf(&rt2x00dev->chip, RF2720)) {
++	    rt2x00_rf(&rt2x00dev->chip, RF2720) ||
++	    rt2x00_rf(&rt2x00dev->chip, RF3021) ||
++	    rt2x00_rf(&rt2x00dev->chip, RF3022)) {
 +		spec->num_channels = 14;
 +		spec->channels = rf_vals;
 +	} else if (rt2x00_rf(&rt2x00dev->chip, RF2850) ||
@@ -2419,10 +2864,22 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	    IEEE80211_HT_CAP_PSMP_SUPPORT;
 +	spec->ht.ampdu_factor = 3;
 +	spec->ht.ampdu_density = 4;
-+	spec->ht.mcs.rx_mask[0] = 0xff;
-+	spec->ht.mcs.rx_mask[1] = 0xff;
 +	spec->ht.mcs.tx_params =
-+	    IEEE80211_HT_MCS_TX_DEFINED;
++	    IEEE80211_HT_MCS_TX_DEFINED |
++	    IEEE80211_HT_MCS_TX_RX_DIFF |
++	    ((rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) - 1) <<
++		IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
++
++	switch (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH)) {
++	case 3:
++		spec->ht.mcs.rx_mask[2] = 0xff;
++	case 2:
++		spec->ht.mcs.rx_mask[1] = 0xff;
++	case 1:
++		spec->ht.mcs.rx_mask[0] = 0xff;
++		spec->ht.mcs.rx_mask[4] = 0x1; /* MCS32 */
++		break;
++	}
 +
 +	/*
 +	 * Create channel information array
@@ -2479,7 +2936,11 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	/*
 +	 * This device requires firmware.
 +	 */
-+	__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
++	if (!rt2x00_rt(&rt2x00dev->chip, RT2880) &&
++	    !rt2x00_rt(&rt2x00dev->chip, RT3052))
++		__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
++	__set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
++	__set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags);
 +	if (!modparam_nohwcrypt)
 +		__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
 +
@@ -2494,37 +2955,53 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +/*
 + * IEEE80211 stack callback functions.
 + */
++static void rt2800pci_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx,
++				   u32 *iv32, u16 *iv16)
++{
++	struct rt2x00_dev *rt2x00dev = hw->priv;
++	struct mac_iveiv_entry iveiv_entry;
++	u32 offset;
++
++	offset = MAC_IVEIV_ENTRY(hw_key_idx);
++	rt2x00pci_register_multiread(rt2x00dev, offset,
++				      &iveiv_entry, sizeof(iveiv_entry));
++
++	memcpy(&iveiv_entry.iv[0], iv16, sizeof(iv16));
++	memcpy(&iveiv_entry.iv[4], iv32, sizeof(iv32));
++}
++
 +static int rt2800pci_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
 +{
 +	struct rt2x00_dev *rt2x00dev = hw->priv;
 +	u32 reg;
++	bool enabled = (value < IEEE80211_MAX_RTS_THRESHOLD);
 +
 +	rt2x00pci_register_read(rt2x00dev, TX_RTS_CFG, &reg);
 +	rt2x00_set_field32(&reg, TX_RTS_CFG_RTS_THRES, value);
 +	rt2x00pci_register_write(rt2x00dev, TX_RTS_CFG, reg);
 +
 +	rt2x00pci_register_read(rt2x00dev, CCK_PROT_CFG, &reg);
-+	rt2x00_set_field32(&reg, CCK_PROT_CFG_RTS_TH_EN, 1);
++	rt2x00_set_field32(&reg, CCK_PROT_CFG_RTS_TH_EN, enabled);
 +	rt2x00pci_register_write(rt2x00dev, CCK_PROT_CFG, reg);
 +
 +	rt2x00pci_register_read(rt2x00dev, OFDM_PROT_CFG, &reg);
-+	rt2x00_set_field32(&reg, OFDM_PROT_CFG_RTS_TH_EN, 1);
++	rt2x00_set_field32(&reg, OFDM_PROT_CFG_RTS_TH_EN, enabled);
 +	rt2x00pci_register_write(rt2x00dev, OFDM_PROT_CFG, reg);
 +
 +	rt2x00pci_register_read(rt2x00dev, MM20_PROT_CFG, &reg);
-+	rt2x00_set_field32(&reg, MM20_PROT_CFG_RTS_TH_EN, 1);
++	rt2x00_set_field32(&reg, MM20_PROT_CFG_RTS_TH_EN, enabled);
 +	rt2x00pci_register_write(rt2x00dev, MM20_PROT_CFG, reg);
 +
 +	rt2x00pci_register_read(rt2x00dev, MM40_PROT_CFG, &reg);
-+	rt2x00_set_field32(&reg, MM40_PROT_CFG_RTS_TH_EN, 1);
++	rt2x00_set_field32(&reg, MM40_PROT_CFG_RTS_TH_EN, enabled);
 +	rt2x00pci_register_write(rt2x00dev, MM40_PROT_CFG, reg);
 +
 +	rt2x00pci_register_read(rt2x00dev, GF20_PROT_CFG, &reg);
-+	rt2x00_set_field32(&reg, GF20_PROT_CFG_RTS_TH_EN, 1);
++	rt2x00_set_field32(&reg, GF20_PROT_CFG_RTS_TH_EN, enabled);
 +	rt2x00pci_register_write(rt2x00dev, GF20_PROT_CFG, reg);
 +
 +	rt2x00pci_register_read(rt2x00dev, GF40_PROT_CFG, &reg);
-+	rt2x00_set_field32(&reg, GF40_PROT_CFG_RTS_TH_EN, 1);
++	rt2x00_set_field32(&reg, GF40_PROT_CFG_RTS_TH_EN, enabled);
 +	rt2x00pci_register_write(rt2x00dev, GF40_PROT_CFG, reg);
 +
 +	return 0;
@@ -2550,24 +3027,23 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	if (retval)
 +		return retval;
 +
++	/*
++	 * We only need to perform additional register initialization
++	 * for WMM queues/
++	 */
++	if (queue_idx >= 4)
++		return 0;
++
 +	queue = rt2x00queue_get_queue(rt2x00dev, queue_idx);
 +
 +	/* Update WMM TXOP register */
-+	if (queue_idx < 2) {
-+		field.bit_offset = queue_idx * 16;
-+		field.bit_mask = 0xffff << field.bit_offset;
-+
-+		rt2x00pci_register_read(rt2x00dev, WMM_TXOP0_CFG, &reg);
-+		rt2x00_set_field32(&reg, field, queue->txop);
-+		rt2x00pci_register_write(rt2x00dev, WMM_TXOP0_CFG, reg);
-+	} else if (queue_idx < 4) {
-+		field.bit_offset = (queue_idx - 2) * 16;
-+		field.bit_mask = 0xffff << field.bit_offset;
-+
-+		rt2x00pci_register_read(rt2x00dev, WMM_TXOP1_CFG, &reg);
-+		rt2x00_set_field32(&reg, field, queue->txop);
-+		rt2x00pci_register_write(rt2x00dev, WMM_TXOP1_CFG, reg);
-+	}
++	offset = WMM_TXOP0_CFG + (sizeof(u32) * (!!(queue_idx & 2)));
++	field.bit_offset = (queue_idx & 1) * 16;
++	field.bit_mask = 0xffff << field.bit_offset;
++
++	rt2x00pci_register_read(rt2x00dev, offset, &reg);
++	rt2x00_set_field32(&reg, field, queue->txop);
++	rt2x00pci_register_write(rt2x00dev, offset, reg);
 +
 +	/* Update WMM registers */
 +	field.bit_offset = queue_idx * 4;
@@ -2586,15 +3062,14 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	rt2x00pci_register_write(rt2x00dev, WMM_CWMAX_CFG, reg);
 +
 +	/* Update EDCA registers */
-+	if (queue_idx < 4) {
-+		offset = EDCA_AC0_CFG + (sizeof(u32) * queue_idx);
-+
-+		rt2x00pci_register_read(rt2x00dev, offset, &reg);
-+		rt2x00_set_field32(&reg, EDCA_AC0_CFG_AIFSN, queue->aifs);
-+		rt2x00_set_field32(&reg, EDCA_AC0_CFG_CWMIN, queue->cw_min);
-+		rt2x00_set_field32(&reg, EDCA_AC0_CFG_CWMAX, queue->cw_max);
-+		rt2x00pci_register_write(rt2x00dev, offset, reg);
-+	}
++	offset = EDCA_AC0_CFG + (sizeof(u32) * queue_idx);
++
++	rt2x00pci_register_read(rt2x00dev, offset, &reg);
++	rt2x00_set_field32(&reg, EDCA_AC0_CFG_TX_OP, queue->txop);
++	rt2x00_set_field32(&reg, EDCA_AC0_CFG_AIFSN, queue->aifs);
++	rt2x00_set_field32(&reg, EDCA_AC0_CFG_CWMIN, queue->cw_min);
++	rt2x00_set_field32(&reg, EDCA_AC0_CFG_CWMAX, queue->cw_max);
++	rt2x00pci_register_write(rt2x00dev, offset, reg);
 +
 +	return 0;
 +}
@@ -2620,10 +3095,10 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	.add_interface		= rt2x00mac_add_interface,
 +	.remove_interface	= rt2x00mac_remove_interface,
 +	.config			= rt2x00mac_config,
-+	.config_interface	= rt2x00mac_config_interface,
 +	.configure_filter	= rt2x00mac_configure_filter,
 +	.set_key		= rt2x00mac_set_key,
 +	.get_stats		= rt2x00mac_get_stats,
++	.get_tkip_seq		= rt2800pci_get_tkip_seq,
 +	.set_rts_threshold	= rt2800pci_set_rts_threshold,
 +	.bss_info_changed	= rt2x00mac_bss_info_changed,
 +	.conf_tx		= rt2800pci_conf_tx,
@@ -2635,7 +3110,7 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	.irq_handler		= rt2800pci_interrupt,
 +	.probe_hw		= rt2800pci_probe_hw,
 +	.get_firmware_name	= rt2800pci_get_firmware_name,
-+	.get_firmware_crc	= rt2800pci_get_firmware_crc,
++	.check_firmware		= rt2800pci_check_firmware,
 +	.load_firmware		= rt2800pci_load_firmware,
 +	.initialize		= rt2x00pci_initialize,
 +	.uninitialize		= rt2x00pci_uninitialize,
@@ -2650,6 +3125,7 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	.write_tx_data		= rt2x00pci_write_tx_data,
 +	.write_beacon		= rt2800pci_write_beacon,
 +	.kick_tx_queue		= rt2800pci_kick_tx_queue,
++	.kill_tx_queue		= rt2800pci_kill_tx_queue,
 +	.fill_rxdone		= rt2800pci_fill_rxdone,
 +	.config_shared_key	= rt2800pci_config_shared_key,
 +	.config_pairwise_key	= rt2800pci_config_pairwise_key,
@@ -2662,14 +3138,14 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +
 +static const struct data_queue_desc rt2800pci_queue_rx = {
 +	.entry_num		= RX_ENTRIES,
-+	.data_size		= DATA_FRAME_SIZE,
++	.data_size		= AGGREGATION_SIZE,
 +	.desc_size		= RXD_DESC_SIZE,
 +	.priv_size		= sizeof(struct queue_entry_priv_pci),
 +};
 +
 +static const struct data_queue_desc rt2800pci_queue_tx = {
 +	.entry_num		= TX_ENTRIES,
-+	.data_size		= DATA_FRAME_SIZE,
++	.data_size		= AGGREGATION_SIZE,
 +	.desc_size		= TXD_DESC_SIZE,
 +	.priv_size		= sizeof(struct queue_entry_priv_pci),
 +};
@@ -2702,10 +3178,25 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 + * RT2800pci module information.
 + */
 +static struct pci_device_id rt2800pci_device_table[] = {
++	/* Edimax */
++	{ 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(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, 0x3062), 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(0x1814, 0x3562), PCI_DEVICE_DATA(&rt2800pci_ops) },
++	{ PCI_DEVICE(0x1814, 0x3592), PCI_DEVICE_DATA(&rt2800pci_ops) },
++	/* Awt */
 +	{ PCI_DEVICE(0x1a3b, 0x1059), PCI_DEVICE_DATA(&rt2800pci_ops) },
 +	{ 0, }
 +};
@@ -2714,10 +3205,33 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +MODULE_VERSION(DRV_VERSION);
 +MODULE_DESCRIPTION("Ralink RT2800 PCI & PCMCIA Wireless LAN driver.");
 +MODULE_SUPPORTED_DEVICE("Ralink RT2860 PCI & PCMCIA chipset based cards");
-+MODULE_DEVICE_TABLE(pci, rt2800pci_device_table);
++#ifdef CONFIG_RT2800PCI_PCI
 +MODULE_FIRMWARE(FIRMWARE_RT2860);
++MODULE_DEVICE_TABLE(pci, rt2800pci_device_table);
++#endif /* CONFIG_RT2800PCI_PCI */
 +MODULE_LICENSE("GPL");
 +
++#ifdef CONFIG_RT2800PCI_WISOC
++#if defined(CONFIG_RALINK_RT288X)
++__rt2x00soc_probe(RT2880, &rt2800pci_ops);
++#elif defined(CONFIG_RALINK_RT305X)
++__rt2x00soc_probe(RT3052, &rt2800pci_ops);
++#endif
++
++static struct platform_driver rt2800soc_driver = {
++	.driver		= {
++		.name		= "rt2800_wmac",
++		.owner		= THIS_MODULE,
++		.mod_name	= KBUILD_MODNAME,
++	},
++	.probe		= __rt2x00soc_probe,
++	.remove		= __devexit_p(rt2x00soc_remove),
++	.suspend	= rt2x00soc_suspend,
++	.resume		= rt2x00soc_resume,
++};
++#endif /* CONFIG_RT2800PCI_WISOC */
++
++#ifdef CONFIG_RT2800PCI_PCI
 +static struct pci_driver rt2800pci_driver = {
 +	.name		= KBUILD_MODNAME,
 +	.id_table	= rt2800pci_device_table,
@@ -2726,24 +3240,47 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +	.suspend	= rt2x00pci_suspend,
 +	.resume		= rt2x00pci_resume,
 +};
++#endif /* CONFIG_RT2800PCI_PCI */
 +
 +static int __init rt2800pci_init(void)
 +{
-+	return pci_register_driver(&rt2800pci_driver);
++	int ret = 0;
++
++#ifdef CONFIG_RT2800PCI_WISOC
++	ret = platform_driver_register(&rt2800soc_driver);
++	if (ret)
++		return ret;
++#endif
++#ifdef CONFIG_RT2800PCI_PCI
++	ret = pci_register_driver(&rt2800pci_driver);
++	if (ret) {
++#ifdef CONFIG_RT2800PCI_WISOC
++		platform_driver_unregister(&rt2800soc_driver);
++#endif
++		return ret;
++	}
++#endif
++
++	return ret;
 +}
 +
 +static void __exit rt2800pci_exit(void)
 +{
++#ifdef CONFIG_RT2800PCI_PCI
 +	pci_unregister_driver(&rt2800pci_driver);
++#endif
++#ifdef CONFIG_RT2800PCI_WISOC
++	platform_driver_unregister(&rt2800soc_driver);
++#endif
 +}
 +
 +module_init(rt2800pci_init);
 +module_exit(rt2800pci_exit);
 --- /dev/null
 +++ b/drivers/net/wireless/rt2x00/rt2800pci.h
-@@ -0,0 +1,1879 @@
+@@ -0,0 +1,1929 @@
 +/*
-+	Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
++	Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
 +	<http://rt2x00.serialmonkey.com>
 +
 +	This program is free software; you can redistribute it and/or modify
@@ -2780,6 +3317,8 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 + * RF2750 2.4G/5G 1T2R
 + * RF3020 2.4G 1T1R
 + * RF2020 2.4G B/G
++ * RF3021 2.4G 1T2R
++ * RF3022 2.4G 2T2R
 + */
 +#define RF2820				0x0001
 +#define RF2850				0x0002
@@ -2787,13 +3326,17 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +#define RF2750				0x0004
 +#define RF3020				0x0005
 +#define RF2020				0x0006
++#define RF3021				0x0007
++#define RF3022				0x0008
 +
 +/*
 + * RT2860 version
 + */
-+#define RT2860_VERSION_C		0x0100
-+#define RT2860_VERSION_D		0x0101
-+#define RT2860_VERSION_E		0x0200
++#define RT2860C_VERSION			0x28600100
++#define RT2860D_VERSION			0x28600101
++#define RT2880E_VERSION			0x28720200
++#define RT2883_VERSION			0x28830300
++#define RT3070_VERSION			0x30700200
 +
 +/*
 + * Signal information.
@@ -2810,8 +3353,8 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +#define EEPROM_SIZE			0x0110
 +#define BBP_BASE			0x0000
 +#define BBP_SIZE			0x0080
-+#define RF_BASE				0x0000
-+#define RF_SIZE				0x0014
++#define RF_BASE				0x0004
++#define RF_SIZE				0x0010
 +
 +/*
 + * Number of TX queues.
@@ -2823,15 +3366,9 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 + */
 +
 +/*
-+ * PCI Configuration Header
-+ */
-+#define PCI_CONFIG_HEADER_VENDOR	0x0000
-+#define PCI_CONFIG_HEADER_DEVICE	0x0002
-+
-+/*
 + * E2PROM_CSR: EEPROM control register.
 + * RELOAD: Write 1 to reload eeprom content.
-+ * TYPE_93C46: 1: 93c46, 0:93c66.
++ * TYPE: 0: 93c46, 1:93c66.
 + * LOAD_STATUS: 1:loading, 0:done.
 + */
 +#define E2PROM_CSR			0x0004
@@ -2839,7 +3376,7 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +#define E2PROM_CSR_CHIP_SELECT		FIELD32(0x00000002)
 +#define E2PROM_CSR_DATA_IN		FIELD32(0x00000004)
 +#define E2PROM_CSR_DATA_OUT		FIELD32(0x00000008)
-+#define E2PROM_CSR_TYPE_93C46		FIELD32(0x00000020)
++#define E2PROM_CSR_TYPE			FIELD32(0x00000030)
 +#define E2PROM_CSR_LOAD_STATUS		FIELD32(0x00000040)
 +#define E2PROM_CSR_RELOAD		FIELD32(0x00000080)
 +
@@ -2992,11 +3529,6 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +#define WMM_TXOP1_CFG_AC3TXOP		FIELD32(0xffff0000)
 +
 +/*
-+ * RINGREG_DIFF
-+ */
-+#define RINGREG_DIFF			0x0010
-+
-+/*
 + * GPIO_CTRL_CFG:
 + */
 +#define GPIO_CTRL_CFG			0x0228
@@ -3089,7 +3621,7 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +#define PBF_SYS_CTRL_HOST_RAM_WRITE	FIELD32(0x00010000)
 +
 +/*
-+ * PBF  registers
++ * PBF registers
 + * Most are for debug. Driver doesn't touch PBF register.
 + */
 +#define PBF_CFG				0x0408
@@ -3117,13 +3649,22 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +#define BCN_OFFSET1_BCN7		FIELD32(0xff000000)
 +
 +/*
-+ * PBF  registers
++ * PBF registers
 + * Most are for debug. Driver doesn't touch PBF register.
 + */
 +#define TXRXQ_PCNT			0x0438
 +#define PBF_DBG				0x043c
 +
 +/*
++ * RF registers
++ */
++#define	RF_CSR_CFG			0x0500
++#define RF_CSR_CFG_DATA			FIELD32(0x000000ff)
++#define RF_CSR_CFG_REGNUM		FIELD32(0x00001f00)
++#define RF_CSR_CFG_WRITE		FIELD32(0x00010000)
++#define RF_CSR_CFG_BUSY			FIELD32(0x00020000)
++
++/*
 + * MAC Control/Status Registers(CSR).
 + * Some values are set in TU, whereas 1 TU == 1024 us.
 + */
@@ -3411,7 +3952,7 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 + * EDCA_AC0_CFG:
 + */
 +#define EDCA_AC0_CFG			0x1300
-+#define EDCA_AC0_CFG_AC_TX_OP		FIELD32(0x000000ff)
++#define EDCA_AC0_CFG_TX_OP		FIELD32(0x000000ff)
 +#define EDCA_AC0_CFG_AIFSN		FIELD32(0x00000f00)
 +#define EDCA_AC0_CFG_CWMIN		FIELD32(0x0000f000)
 +#define EDCA_AC0_CFG_CWMAX		FIELD32(0x000f0000)
@@ -3420,7 +3961,7 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 + * EDCA_AC1_CFG:
 + */
 +#define EDCA_AC1_CFG			0x1304
-+#define EDCA_AC1_CFG_AC_TX_OP		FIELD32(0x000000ff)
++#define EDCA_AC1_CFG_TX_OP		FIELD32(0x000000ff)
 +#define EDCA_AC1_CFG_AIFSN		FIELD32(0x00000f00)
 +#define EDCA_AC1_CFG_CWMIN		FIELD32(0x0000f000)
 +#define EDCA_AC1_CFG_CWMAX		FIELD32(0x000f0000)
@@ -3429,7 +3970,7 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 + * EDCA_AC2_CFG:
 + */
 +#define EDCA_AC2_CFG			0x1308
-+#define EDCA_AC2_CFG_AC_TX_OP		FIELD32(0x000000ff)
++#define EDCA_AC2_CFG_TX_OP		FIELD32(0x000000ff)
 +#define EDCA_AC2_CFG_AIFSN		FIELD32(0x00000f00)
 +#define EDCA_AC2_CFG_CWMIN		FIELD32(0x0000f000)
 +#define EDCA_AC2_CFG_CWMAX		FIELD32(0x000f0000)
@@ -3438,7 +3979,7 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 + * EDCA_AC3_CFG:
 + */
 +#define EDCA_AC3_CFG			0x130c
-+#define EDCA_AC3_CFG_AC_TX_OP		FIELD32(0x000000ff)
++#define EDCA_AC3_CFG_TX_OP		FIELD32(0x000000ff)
 +#define EDCA_AC3_CFG_AIFSN		FIELD32(0x00000f00)
 +#define EDCA_AC3_CFG_CWMIN		FIELD32(0x0000f000)
 +#define EDCA_AC3_CFG_CWMAX		FIELD32(0x000f0000)
@@ -3538,6 +4079,7 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 + * TX_BAND_CFG: 0x1 use upper 20MHz, 0x0 use lower 20MHz
 + */
 +#define TX_BAND_CFG			0x132c
++#define TX_BAND_CFG_HT40_PLUS		FIELD32(0x00000001)
 +#define TX_BAND_CFG_A			FIELD32(0x00000002)
 +#define TX_BAND_CFG_BG			FIELD32(0x00000004)
 +
@@ -4029,64 +4571,54 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +#define MPDU_DENSITY_CNT_RX_ZERO_DEL	FIELD32(0xffff0000)
 +
 +/*
-+ * Security key table memory, base address = 0x1800
-+ */
-+struct hw_pairwise_ta_entry {
-+	u8 address[6];
-+	u8 reserved[2];
-+} __attribute__ ((packed));
-+
-+struct wcid_entry {
-+	u8 rx_ba_bitmat7;
-+	u8 rx_ba_bitmat0;
-+	u8 mac[6];
-+} __attribute__ ((packed));
-+
-+struct hw_key_entry {
-+	u8 key[16];
-+	u8 tx_mic[8];
-+	u8 rx_mic[8];
-+} __attribute__ ((packed));
-+
-+/*
 + * Security key table memory.
 + * MAC_WCID_BASE: 8-bytes (use only 6 bytes) * 256 entry
 + * PAIRWISE_KEY_TABLE_BASE: 32-byte * 256 entry
-+ * PAIRWISE_IVEIV_TABLE_BASE: 8-byte * 256-entry
 + * MAC_IVEIV_TABLE_BASE: 8-byte * 256-entry
 + * MAC_WCID_ATTRIBUTE_BASE: 4-byte * 256-entry
 + * SHARED_KEY_TABLE_BASE: 32-byte * 16-entry
-+ * SHARED_KEY_MODE_BASE: 32-byte * 16-entry
++ * SHARED_KEY_MODE_BASE: 4-byte * 16-entry
 + */
 +#define MAC_WCID_BASE			0x1800
 +#define PAIRWISE_KEY_TABLE_BASE		0x4000
-+#define PAIRWISE_IVEIV_TABLE_BASE	0x6000
 +#define MAC_IVEIV_TABLE_BASE		0x6000
 +#define MAC_WCID_ATTRIBUTE_BASE		0x6800
 +#define SHARED_KEY_TABLE_BASE		0x6c00
 +#define SHARED_KEY_MODE_BASE		0x7000
 +
++#define MAC_WCID_ENTRY(__idx) \
++	( MAC_WCID_BASE + ((__idx) * sizeof(struct mac_wcid_entry)) )
++#define PAIRWISE_KEY_ENTRY(__idx) \
++	( PAIRWISE_KEY_TABLE_BASE + ((__idx) * sizeof(struct hw_key_entry)) )
++#define MAC_IVEIV_ENTRY(__idx) \
++	( MAC_IVEIV_TABLE_BASE + ((__idx) & sizeof(struct mac_iveiv_entry)) )
++#define MAC_WCID_ATTR_ENTRY(__idx) \
++	( MAC_WCID_ATTRIBUTE_BASE + ((__idx) * sizeof(u32)) )
 +#define SHARED_KEY_ENTRY(__idx) \
-+	( SHARED_KEY_TABLE_BASE + \
-+		((__idx) * sizeof(struct hw_key_entry)) )
++	( SHARED_KEY_TABLE_BASE + ((__idx) * sizeof(struct hw_key_entry)) )
 +#define SHARED_KEY_MODE_ENTRY(__idx) \
 +	( SHARED_KEY_MODE_BASE + ((__idx) * sizeof(u32)) )
-+#define PAIRWISE_KEY_ENTRY(__idx) \
-+	( PAIRWISE_KEY_TABLE_BASE + \
-+		((__idx) * sizeof(struct hw_key_entry)) )
 +
-+#define MAC_WCID_ENTRY(__idx) \
-+	( MAC_WCID_BASE + (2 * sizeof(u32) * (__idx)) )
-+#define MAC_WCID_ATTR_ENTRY(__idx) \
-+	( MAC_WCID_ATTRIBUTE_BASE + ((__idx) * sizeof(u32)) )
++struct mac_wcid_entry {
++	u8 mac[6];
++	u8 reserved[2];
++} __attribute__ ((packed));
++
++struct hw_key_entry {
++	u8 key[16];
++	u8 tx_mic[8];
++	u8 rx_mic[8];
++} __attribute__ ((packed));
++
++struct mac_iveiv_entry {
++	u8 iv[8];
++} __attribute__ ((packed));
 +
 +/*
 + * MAC_WCID_ATTRIBUTE:
-+ * KEYTAB: 0: shared key table, 1: pairwise key table
-+ * BSS_IDX: multipleBSS index for the WCID
 + */
 +#define MAC_WCID_ATTRIBUTE_KEYTAB	FIELD32(0x00000001)
-+#define MAC_WCID_ATTRIBUTE_PAIRKEY_MODE	FIELD32(0x0000000e)
++#define MAC_WCID_ATTRIBUTE_CIPHER	FIELD32(0x0000000e)
 +#define MAC_WCID_ATTRIBUTE_BSS_IDX	FIELD32(0x00000070)
 +#define MAC_WCID_ATTRIBUTE_RX_WIUDF	FIELD32(0x00000380)
 +
@@ -4119,6 +4651,10 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 + * H2M_MAILBOX_CID:
 + */
 +#define H2M_MAILBOX_CID			0x7014
++#define H2M_MAILBOX_CID_CMD0		FIELD32(0x000000ff)
++#define H2M_MAILBOX_CID_CMD1		FIELD32(0x0000ff00)
++#define H2M_MAILBOX_CID_CMD2		FIELD32(0x00ff0000)
++#define H2M_MAILBOX_CID_CMD3		FIELD32(0xff000000)
 +
 +/*
 + * H2M_MAILBOX_STATUS:
@@ -4221,6 +4757,48 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 + * BBP 3: RX Antenna
 + */
 +#define BBP3_RX_ANTENNA			FIELD8(0x18)
++#define BBP3_HT40_PLUS			FIELD8(0x20)
++
++/*
++ * BBP 4: Bandwidth
++ */
++#define BBP4_TX_BF			FIELD8(0x01)
++#define BBP4_BANDWIDTH			FIELD8(0x18)
++
++/*
++ * RFCSR registers
++ * The wordsize of the RFCSR is 8 bits.
++ */
++
++/*
++ * RFCSR 6:
++ */
++#define RFCSR6_R			FIELD8(0x03)
++
++/*
++ * RFCSR 7:
++ */
++#define RFCSR7_RF_TUNING		FIELD8(0x01)
++
++/*
++ * RFCSR 12:
++ */
++#define RFCSR12_TX_POWER		FIELD8(0x1f)
++
++/*
++ * RFCSR 22:
++ */
++#define RFCSR22_BASEBAND_LOOPBACK	FIELD8(0x01)
++
++/*
++ * RFCSR 23:
++ */
++#define RFCSR23_FREQ_OFFSET		FIELD8(0x7f)
++
++/*
++ * RFCSR 30:
++ */
++#define RFCSR30_RF_CALIBRATION		FIELD8(0x80)
 +
 +/*
 + * RF registers
@@ -4247,7 +4825,7 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +#define RF4_TXPOWER_A_7DBM_BOOST	FIELD32(0x00000040)
 +#define RF4_TXPOWER_A			FIELD32(0x00000780)
 +#define RF4_FREQ_OFFSET			FIELD32(0x001f8000)
-+#define RF4_BW40			FIELD32(0x00200000)
++#define RF4_HT40			FIELD32(0x00200000)
 +
 +/*
 + * EEPROM content.
@@ -4381,7 +4959,7 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +#define EEPROM_TXPOWER_DELTA_TXPOWER	FIELD16(0x0080)
 +
 +/*
-+ * EEPROM TXPOWER 802.11G
++ * EEPROM TXPOWER 802.11BG
 + */
 +#define	EEPROM_TXPOWER_BG1		0x0029
 +#define	EEPROM_TXPOWER_BG2		0x0030
@@ -4416,6 +4994,8 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 + */
 +#define MCU_SLEEP			0x30
 +#define MCU_WAKEUP			0x31
++#define MCU_RADIO_OFF			0x35
++#define MCU_CURRENT			0x36
 +#define MCU_LED				0x50
 +#define MCU_LED_STRENGTH		0x51
 +#define MCU_LED_1			0x52
@@ -4423,6 +5003,13 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +#define MCU_LED_3			0x54
 +#define MCU_RADAR			0x60
 +#define MCU_BOOT_SIGNAL			0x72
++#define MCU_BBP_SIGNAL			0x80
++#define MCU_POWER_SAVE			0x83
++
++/*
++ * MCU mailbox tokens
++ */
++#define TOKEN_WAKUP			3
 +
 +/*
 + * DMA descriptor defines.
@@ -4623,7 +5210,7 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +#endif /* RT2800PCI_H */
 --- a/drivers/net/wireless/rt2x00/rt2x00.h
 +++ b/drivers/net/wireless/rt2x00/rt2x00.h
-@@ -139,6 +139,10 @@ struct rt2x00_chip {
+@@ -147,6 +147,12 @@ struct rt2x00_chip {
  #define RT2561		0x0302
  #define RT2661		0x0401
  #define RT2571		0x1300
@@ -4631,6 +5218,8 @@ Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
 +#define RT2860D		0x0681	/* 2.4GHz, 5GHz PCI/CB */
 +#define RT2890		0x0701	/* 2.4GHz PCIe */
 +#define RT2890D		0x0781	/* 2.4GHz, 5GHz PCIe */
++#define RT2880		0x2880	/* WSOC */
++#define RT3052		0x3052	/* WSOC */
+ #define RT2870		0x1600
  
  	u16 rf;
- 	u32 rev;