X-Git-Url: https://git.rohieb.name/openwrt.git/blobdiff_plain/acb7b631f32248190c9b28d706536977a32bc72f..27792506a45ee30e3cc7854786594481b0f8459b:/package/mac80211/patches/302-rt2x00-Implement-support-for-rt2800pci.patch 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 a37362ce6..7584e5a7d 100644 --- a/package/mac80211/patches/302-rt2x00-Implement-support-for-rt2800pci.patch +++ b/package/mac80211/patches/302-rt2x00-Implement-support-for-rt2800pci.patch @@ -1,38 +1,40 @@ -From 659988a6bb83536c5d0a01b0b58378cc1856c975 Mon Sep 17 00:00:00 2001 +From 67432230daedc23f808b79173703e27675fd0659 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn -Date: Fri, 23 Jan 2009 17:13:03 +0100 -Subject: [PATCH] rt2x00: Implement support for rt2800pci +Date: Sun, 26 Apr 2009 15:54:03 +0200 +Subject: [PATCH 2/4] 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 Signed-off-by: Mattias Nissler Signed-off-by: Mark Asselstine Signed-off-by: Felix Fietkau Signed-off-by: Ivo van Doorn --- - drivers/net/wireless/rt2x00/Kconfig | 15 + + drivers/net/wireless/rt2x00/Kconfig | 26 + drivers/net/wireless/rt2x00/Makefile | 1 + - drivers/net/wireless/rt2x00/rt2800pci.c | 2763 +++++++++++++++++++++++++++++++ - drivers/net/wireless/rt2x00/rt2800pci.h | 1881 +++++++++++++++++++++ - drivers/net/wireless/rt2x00/rt2x00.h | 4 + - 5 files changed, 4664 insertions(+), 0 deletions(-) + drivers/net/wireless/rt2x00/rt2800pci.c | 3245 +++++++++++++++++++++++++++++++ + drivers/net/wireless/rt2x00/rt2800pci.h | 1927 ++++++++++++++++++ + drivers/net/wireless/rt2x00/rt2x00.h | 6 + + 5 files changed, 5205 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,2763 @@ +@@ -0,0 +1,3245 @@ +/* + Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + @@ -66,12 +68,22 @@ Signed-off-by: Ivo van Doorn +#include +#include +#include ++#include +#include + +#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. + */ @@ -92,6 +104,8 @@ Signed-off-by: Ivo van Doorn + */ +#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) \ @@ -155,14 +169,66 @@ Signed-off-by: Ivo van Doorn + 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 = 0; ++ rt2x00_set_field32(®, RF_CSR_CFG_DATA, value); ++ rt2x00_set_field32(®, RF_CSR_CFG_REGNUM, word); ++ rt2x00_set_field32(®, RF_CSR_CFG_WRITE, 1); ++ rt2x00_set_field32(®, 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 = 0; ++ rt2x00_set_field32(®, RF_CSR_CFG_REGNUM, word); ++ rt2x00_set_field32(®, RF_CSR_CFG_WRITE, 0); ++ rt2x00_set_field32(®, RF_CSR_CFG_BUSY, 1); ++ ++ rt2x00pci_register_write(rt2x00dev, RF_CSR_CFG, reg); ++ ++ WAIT_FOR_RFCSR(rt2x00dev, ®); ++ } ++ ++ *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); + + /* @@ -189,6 +255,13 @@ Signed-off-by: Ivo van Doorn +{ + 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); + + /* @@ -210,6 +283,44 @@ Signed-off-by: Ivo van Doorn + 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, ®); ++ ++ 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; @@ -240,6 +351,32 @@ Signed-off-by: Ivo van Doorn + 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, ®); ++ ++ 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, @@ -364,20 +501,41 @@ Signed-off-by: Ivo van Doorn + 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, ®); + rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_KEYTAB, + !!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)); -+ rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_PAIRKEY_MODE, -+ crypto->cipher); ++ rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_CIPHER, ++ (crypto->cmd == SET_KEY) * crypto->cipher); + rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_BSS_IDX, -+ (crypto->cmd == SET_KEY) ? crypto->bssidx : 0); -+ rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_RX_WIUDF, 0); ++ (crypto->cmd == SET_KEY) * crypto->bssidx); ++ rt2x00_set_field32(®, 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, @@ -387,10 +545,11 @@ Signed-off-by: Ivo van Doorn + 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, @@ -401,34 +560,23 @@ Signed-off-by: Ivo van Doorn + 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, ®); + rt2x00_set_field32(®, field, -+ (crypto->cmd == SET_KEY) ? crypto->cipher : 0); ++ (crypto->cmd == SET_KEY) * crypto->cipher); + rt2x00pci_register_write(rt2x00dev, offset, reg); + + /* @@ -446,13 +594,18 @@ Signed-off-by: Ivo van Doorn + 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, @@ -463,17 +616,6 @@ Signed-off-by: Ivo van Doorn + 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; + } + + /* @@ -521,7 +663,7 @@ Signed-off-by: Ivo van Doorn + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PSPOLL, + !(filter_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BA, 1); -+ rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BAR, 1); ++ rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BAR, 0); + rt2x00_set_field32(®, 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 + + rt2x00pci_register_read(rt2x00dev, TX_TIMEOUT_CFG, ®); + rt2x00_set_field32(®, 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, ®); @@ -599,8 +741,7 @@ Signed-off-by: Ivo van Doorn + + 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, ®); + rt2x00_set_field32(®, BKOFF_SLOT_CFG_SLOT_TIME, erp->slot_time); @@ -619,29 +760,22 @@ Signed-off-by: Ivo van Doorn +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, 16); ++ rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2); + break; + case 3: + /* Do nothing */ @@ -651,7 +785,7 @@ Signed-off-by: Ivo van Doorn + /* + * 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; @@ -690,43 +824,20 @@ Signed-off-by: Ivo van Doorn + 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) { @@ -753,19 +864,14 @@ Signed-off-by: Ivo van Doorn + + 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); @@ -785,6 +891,52 @@ Signed-off-by: Ivo van Doorn + 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 @@ -802,11 +954,6 @@ Signed-off-by: Ivo van Doorn + rt2800pci_bbp_write(rt2x00dev, 82, 0x84); + rt2800pci_bbp_write(rt2x00dev, 75, 0x50); + } -+ -+ rt2x00pci_register_read(rt2x00dev, TX_BAND_CFG, ®); -+ 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); + @@ -814,15 +961,57 @@ Signed-off-by: Ivo van Doorn + rt2800pci_bbp_write(rt2x00dev, 75, 0x46); + else + rt2800pci_bbp_write(rt2x00dev, 75, 0x50); ++ } ++ ++ rt2x00pci_register_read(rt2x00dev, TX_BAND_CFG, ®); ++ rt2x00_set_field32(®, TX_BAND_CFG_HT40_PLUS, conf_is_ht40_plus(conf)); ++ rt2x00_set_field32(®, TX_BAND_CFG_A, rf->channel > 14); ++ rt2x00_set_field32(®, TX_BAND_CFG_BG, rf->channel <= 14); ++ 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); ++ } + -+ rt2x00pci_register_read(rt2x00dev, TX_BAND_CFG, ®); -+ 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); ++ /* 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); +} + @@ -935,9 +1124,9 @@ Signed-off-by: Ivo van Doorn + rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTOWAKE, 1); + rt2x00pci_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg); + -+ rt2800pci_mcu_request(rt2x00dev, MCU_SLEEP, 0xff, 0, 0); ++ rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); + } else { -+ rt2800pci_mcu_request(rt2x00dev, MCU_WAKEUP, 0xff, 0, 0); ++ rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); + + rt2x00pci_register_read(rt2x00dev, AUTOWAKEUP_CFG, ®); + rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 0); @@ -955,8 +1144,8 @@ Signed-off-by: Ivo van Doorn + 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) @@ -980,12 +1169,6 @@ Signed-off-by: Ivo van Doorn + */ + rt2x00pci_register_read(rt2x00dev, RX_STA_CNT0, ®); + 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, ®); -+ qual->false_cca = rt2x00_get_field32(reg, RX_STA_CNT1_FALSE_CCA); +} + +static u8 rt2800pci_get_default_vgc(struct rt2x00_dev *rt2x00dev) @@ -1038,19 +1221,31 @@ Signed-off-by: Ivo van Doorn + 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); + @@ -1060,20 +1255,17 @@ Signed-off-by: Ivo van Doorn + * 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; + -+ if (len != 8192) { -+ ERROR(rt2x00dev, "Invalid firmware file length (len=%zu)\n", len); -+ return -ENOENT; -+ } -+ + /* + * Wait for stable hardware. + */ @@ -1201,26 +1393,31 @@ Signed-off-by: Ivo van Doorn + 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 @@ -1291,7 +1488,7 @@ Signed-off-by: Ivo van Doorn + rt2x00_set_field32(®, 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, ®); @@ -1332,25 +1529,25 @@ Signed-off-by: Ivo van Doorn + rt2x00pci_register_write(rt2x00dev, AUTO_RSP_CFG, reg); + + rt2x00pci_register_read(rt2x00dev, CCK_PROT_CFG, ®); -+ rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_RATE, 3); ++ rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_RATE, 8); + rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_CTRL, 0); + rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_NAV, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_CCK, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_OFDM, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_MM20, 1); -+ rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_MM40, 0); ++ rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_MM40, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_GF20, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_GF40, 1); + rt2x00pci_register_write(rt2x00dev, CCK_PROT_CFG, reg); + + rt2x00pci_register_read(rt2x00dev, OFDM_PROT_CFG, ®); -+ rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_RATE, 3); ++ rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_RATE, 8); + rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_CTRL, 0); + rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_NAV, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_CCK, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_OFDM, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_MM20, 1); -+ rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_MM40, 0); ++ rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_MM40, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_GF20, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_GF40, 1); + rt2x00pci_register_write(rt2x00dev, OFDM_PROT_CFG, reg); @@ -1408,6 +1605,8 @@ Signed-off-by: Ivo van Doorn + + rt2x00pci_register_read(rt2x00dev, TX_RTS_CFG, ®); + rt2x00_set_field32(®, TX_RTS_CFG_AUTO_RTS_RETRY_LIMIT, 32); ++ rt2x00_set_field32(®, TX_RTS_CFG_RTS_THRES, ++ IEEE80211_MAX_RTS_THRESHOLD); + rt2x00_set_field32(®, TX_RTS_CFG_RTS_FBK_EN, 0); + rt2x00pci_register_write(rt2x00dev, TX_RTS_CFG, reg); + @@ -1417,19 +1616,19 @@ Signed-off-by: Ivo van Doorn + /* + * ASIC will keep garbage value after boot, clear encryption keys. + */ -+ for (i = 0; i < 254; i++) { ++ 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 @@ -1470,12 +1669,12 @@ Signed-off-by: Ivo van Doorn + rt2x00pci_register_read(rt2x00dev, LG_FBK_CFG0, ®); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS0FBK, 8); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS1FBK, 8); -+ rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS2FBK, 10); -+ rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS3FBK, 11); -+ rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS4FBK, 12); -+ rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS5FBK, 13); -+ rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS6FBK, 14); -+ rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS7FBK, 15); ++ rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS2FBK, 3); ++ rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS3FBK, 10); ++ rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS4FBK, 11); ++ rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS5FBK, 12); ++ rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS6FBK, 13); ++ rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS7FBK, 14); + rt2x00pci_register_write(rt2x00dev, LG_FBK_CFG0, reg); + + rt2x00pci_register_read(rt2x00dev, LG_FBK_CFG1, ®); @@ -1526,8 +1725,8 @@ Signed-off-by: Ivo van Doorn + * 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++) { @@ -1575,6 +1774,12 @@ Signed-off-by: Ivo van Doorn + 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); + @@ -1588,6 +1793,144 @@ Signed-off-by: Ivo van Doorn + 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. + */ @@ -1670,7 +2013,8 @@ Signed-off-by: Ivo van Doorn + rt2800pci_init_queues(rt2x00dev) || + rt2800pci_init_registers(rt2x00dev) || + rt2800pci_wait_wpdma_ready(rt2x00dev) || -+ rt2800pci_init_bbp(rt2x00dev))) ++ rt2800pci_init_bbp(rt2x00dev) || ++ rt2800pci_init_rfcsr(rt2x00dev))) + return -EIO; + + /* @@ -1743,9 +2087,10 @@ Signed-off-by: Ivo van Doorn +{ + rt2x00pci_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0); + -+ if (state == STATE_AWAKE) -+ rt2800pci_mcu_request(rt2x00dev, MCU_WAKEUP, 0xff, 0, 0); -+ else ++ if (state == STATE_AWAKE) { ++ rt2800pci_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKUP, 0, 0); ++ rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKUP); ++ } else + rt2800pci_mcu_request(rt2x00dev, MCU_SLEEP, 0xff, 0, 2); + + return 0; @@ -1820,7 +2165,6 @@ Signed-off-by: Ivo van Doorn + */ + 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); @@ -1846,16 +2190,23 @@ Signed-off-by: Ivo van Doorn + 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 @@ -1882,7 +2233,8 @@ Signed-off-by: Ivo van Doorn + 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); +} @@ -1957,6 +2309,24 @@ Signed-off-by: Ivo van Doorn + 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, ®); ++ rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX0, (qid == QID_AC_BE)); ++ rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX1, (qid == QID_AC_BK)); ++ rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX2, (qid == QID_AC_VI)); ++ rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX3, (qid == QID_AC_VO)); ++ rt2x00pci_register_write(rt2x00dev, WPDMA_RST_IDX, reg); ++} ++ +/* + * RX control handlers + */ @@ -1988,7 +2358,7 @@ Signed-off-by: Ivo van Doorn + * 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); + } @@ -2011,6 +2381,9 @@ Signed-off-by: Ivo van Doorn + 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; + @@ -2027,13 +2400,12 @@ Signed-off-by: Ivo van Doorn + /* + * 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) + @@ -2042,9 +2414,15 @@ Signed-off-by: Ivo van Doorn + 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); +} + @@ -2168,26 +2546,22 @@ Signed-off-by: Ivo van Doorn + */ +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, ®); -+ -+ 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. @@ -2207,6 +2581,13 @@ Signed-off-by: Ivo van Doorn + 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); @@ -2286,7 +2667,6 @@ Signed-off-by: Ivo van Doorn + u32 reg; + u16 value; + u16 eeprom; -+ u16 device; + + /* + * Read EEPROM word for configuration. @@ -2295,26 +2675,32 @@ Signed-off-by: Ivo van Doorn + + /* + * 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, ®); -+ 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, RF3020) && -+ !rt2x00_rf(&rt2x00dev->chip, RF2020)) { ++ !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); @@ -2389,8 +2775,8 @@ Signed-off-by: Ivo van Doorn + /* 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 }, @@ -2430,6 +2816,7 @@ Signed-off-by: Ivo van Doorn + char *tx_power1; + char *tx_power2; + unsigned int i; ++ u16 eeprom; + + /* + * Initialize all hw fields. @@ -2446,6 +2833,8 @@ Signed-off-by: Ivo van Doorn + rt2x00_eeprom_addr(rt2x00dev, + EEPROM_MAC_ADDR_0)); + ++ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); ++ + /* + * Initialize hw_mode information. + */ @@ -2453,7 +2842,9 @@ Signed-off-by: Ivo van Doorn + 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) || @@ -2477,10 +2868,22 @@ Signed-off-by: Ivo van Doorn + 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 @@ -2537,7 +2940,10 @@ Signed-off-by: Ivo van Doorn + /* + * 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_L2PAD, &rt2x00dev->flags); + if (!modparam_nohwcrypt) + __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); + @@ -2552,6 +2958,21 @@ Signed-off-by: Ivo van Doorn +/* + * 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; @@ -2681,6 +3102,7 @@ Signed-off-by: Ivo van Doorn + .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, @@ -2692,7 +3114,7 @@ Signed-off-by: Ivo van Doorn + .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, @@ -2707,6 +3129,7 @@ Signed-off-by: Ivo van Doorn + .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, @@ -2719,14 +3142,14 @@ Signed-off-by: Ivo van Doorn + +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), +}; @@ -2759,10 +3182,25 @@ Signed-off-by: Ivo van Doorn + * 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, } +}; @@ -2771,10 +3209,33 @@ Signed-off-by: Ivo van Doorn +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, @@ -2783,22 +3244,45 @@ Signed-off-by: Ivo van Doorn + .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,1881 @@ +@@ -0,0 +1,1927 @@ +/* + Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + @@ -2837,6 +3321,8 @@ Signed-off-by: Ivo van Doorn + * 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 @@ -2844,6 +3330,8 @@ Signed-off-by: Ivo van Doorn +#define RF2750 0x0004 +#define RF3020 0x0005 +#define RF2020 0x0006 ++#define RF3021 0x0007 ++#define RF3022 0x0008 + +/* + * RT2860 version @@ -2869,8 +3357,8 @@ Signed-off-by: Ivo van Doorn +#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. @@ -2882,15 +3370,9 @@ Signed-off-by: Ivo van Doorn + */ + +/* -+ * 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 @@ -2898,7 +3380,7 @@ Signed-off-by: Ivo van Doorn +#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) + @@ -3051,11 +3533,6 @@ Signed-off-by: Ivo van Doorn +#define WMM_TXOP1_CFG_AC3TXOP FIELD32(0xffff0000) + +/* -+ * RINGREG_DIFF -+ */ -+#define RINGREG_DIFF 0x0010 -+ -+/* + * GPIO_CTRL_CFG: + */ +#define GPIO_CTRL_CFG 0x0228 @@ -3148,7 +3625,7 @@ Signed-off-by: Ivo van Doorn +#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 @@ -3176,13 +3653,22 @@ Signed-off-by: Ivo van Doorn +#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. + */ @@ -3597,6 +4083,7 @@ Signed-off-by: Ivo van Doorn + * 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) + @@ -4088,64 +4575,54 @@ Signed-off-by: Ivo van Doorn +#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) + @@ -4178,6 +4655,10 @@ Signed-off-by: Ivo van Doorn + * 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: @@ -4280,6 +4761,48 @@ Signed-off-by: Ivo van Doorn + * 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 @@ -4306,7 +4829,7 @@ Signed-off-by: Ivo van Doorn +#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. @@ -4440,7 +4963,7 @@ Signed-off-by: Ivo van Doorn +#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 @@ -4475,6 +4998,7 @@ Signed-off-by: Ivo van Doorn + */ +#define MCU_SLEEP 0x30 +#define MCU_WAKEUP 0x31 ++#define MCU_RADIO_OFF 0x35 +#define MCU_LED 0x50 +#define MCU_LED_STRENGTH 0x51 +#define MCU_LED_1 0x52 @@ -4482,6 +5006,12 @@ Signed-off-by: Ivo van Doorn +#define MCU_LED_3 0x54 +#define MCU_RADAR 0x60 +#define MCU_BOOT_SIGNAL 0x72 ++#define MCU_BBP_SIGNAL 0x80 ++ ++/* ++ * MCU mailbox tokens ++ */ ++#define TOKEN_WAKUP 3 + +/* + * DMA descriptor defines. @@ -4682,7 +5212,7 @@ Signed-off-by: Ivo van Doorn +#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 @@ -4690,6 +5220,8 @@ Signed-off-by: Ivo van Doorn +#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;