summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rt2x00/rt2800pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2800pci.c')
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.c229
1 files changed, 99 insertions, 130 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index 6f11760117da..39b3846fa340 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -31,7 +31,6 @@
Supported chipsets: RT2800E & RT2800ED.
*/
-#include <linux/crc-ccitt.h>
#include <linux/delay.h>
#include <linux/etherdevice.h>
#include <linux/init.h>
@@ -192,82 +191,14 @@ static char *rt2800pci_get_firmware_name(struct rt2x00_dev *rt2x00dev)
return FIRMWARE_RT2860;
}
-static int rt2800pci_check_firmware(struct rt2x00_dev *rt2x00dev,
+static int rt2800pci_write_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.
- */
- crc = crc_ccitt(~0, data, len - 2);
-
- /*
- * There is a small difference between the crc-itu-t + bitrev and
- * the crc-ccitt crc calculation. In the latter method the 2 bytes
- * will be swapped, use swab16 to convert the crc to the correct
- * value.
- */
- crc = swab16(crc);
-
- return (fw_crc == crc) ? FW_OK : FW_BAD_CRC;
-}
-
-static int rt2800pci_load_firmware(struct rt2x00_dev *rt2x00dev,
- const u8 *data, const size_t len)
-{
- unsigned int i;
u32 reg;
- /*
- * Wait for stable hardware.
- */
- for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
- if (reg && reg != ~0)
- break;
- msleep(1);
- }
-
- if (i == REGISTER_BUSY_COUNT) {
- ERROR(rt2x00dev, "Unstable hardware.\n");
- return -EBUSY;
- }
-
- rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000002);
rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0x00000000);
/*
- * Disable DMA, will be reenabled later when enabling
- * the radio.
- */
- rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
- rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0);
- rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_DMA_BUSY, 0);
- rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0);
- rt2x00_set_field32(&reg, WPDMA_GLO_CFG_RX_DMA_BUSY, 0);
- rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
- rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
-
- /*
* enable Host program ram write selection
*/
reg = 0;
@@ -278,34 +209,11 @@ static int rt2800pci_load_firmware(struct rt2x00_dev *rt2x00dev,
* Write firmware to device.
*/
rt2800_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
- data, len);
+ data, len);
rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000);
rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001);
- /*
- * Wait for device to stabilize.
- */
- for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
- if (rt2x00_get_field32(reg, PBF_SYS_CTRL_READY))
- break;
- msleep(1);
- }
-
- if (i == REGISTER_BUSY_COUNT) {
- ERROR(rt2x00dev, "PBF system register not ready.\n");
- return -EBUSY;
- }
-
- /*
- * Disable interrupts
- */
- rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_IRQ_OFF);
-
- /*
- * Initialize BBP R/W access agent
- */
rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
@@ -422,7 +330,8 @@ static void rt2800pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
enum dev_state state)
{
- int mask = (state == STATE_RADIO_IRQ_ON);
+ int mask = (state == STATE_RADIO_IRQ_ON) ||
+ (state == STATE_RADIO_IRQ_ON_ISR);
u32 reg;
/*
@@ -631,7 +540,9 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev,
rt2800pci_toggle_rx(rt2x00dev, state);
break;
case STATE_RADIO_IRQ_ON:
+ case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
+ case STATE_RADIO_IRQ_OFF_ISR:
rt2800pci_toggle_irq(rt2x00dev, state);
break;
case STATE_DEEP_SLEEP:
@@ -805,7 +716,7 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
/*
* Process the RXWI structure that is at the start of the buffer.
*/
- rt2800_process_rxwi(entry->skb, rxdesc);
+ rt2800_process_rxwi(entry, rxdesc);
/*
* Set RX IDX in register to inform hardware that we have handled
@@ -929,42 +840,74 @@ static void rt2800pci_wakeup(struct rt2x00_dev *rt2x00dev)
rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS);
}
-static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
+static irqreturn_t rt2800pci_interrupt_thread(int irq, void *dev_instance)
{
struct rt2x00_dev *rt2x00dev = dev_instance;
- u32 reg;
-
- /* Read status and ACK all interrupts */
- rt2800_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
- rt2800_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
+ u32 reg = rt2x00dev->irqvalue[0];
- if (!reg)
- return IRQ_NONE;
+ /*
+ * 1 - Pre TBTT interrupt.
+ */
+ if (rt2x00_get_field32(reg, INT_SOURCE_CSR_PRE_TBTT))
+ rt2x00lib_pretbtt(rt2x00dev);
- if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
- return IRQ_HANDLED;
+ /*
+ * 2 - Beacondone interrupt.
+ */
+ if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TBTT))
+ rt2x00lib_beacondone(rt2x00dev);
/*
- * 1 - Rx ring done interrupt.
+ * 3 - Rx ring done interrupt.
*/
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RX_DONE))
rt2x00pci_rxdone(rt2x00dev);
+ /*
+ * 4 - Tx done interrupt.
+ */
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS))
rt2800pci_txdone(rt2x00dev);
/*
- * Current beacon was sent out, fetch the next one
+ * 5 - Auto wakeup interrupt.
*/
- if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TBTT))
- rt2x00lib_beacondone(rt2x00dev);
-
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP))
rt2800pci_wakeup(rt2x00dev);
+ /* Enable interrupts again. */
+ rt2x00dev->ops->lib->set_device_state(rt2x00dev,
+ STATE_RADIO_IRQ_ON_ISR);
+
return IRQ_HANDLED;
}
+static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
+{
+ struct rt2x00_dev *rt2x00dev = dev_instance;
+ u32 reg;
+
+ /* Read status and ACK all interrupts */
+ rt2800_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
+ rt2800_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
+
+ if (!reg)
+ return IRQ_NONE;
+
+ if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+ return IRQ_HANDLED;
+
+ /* Store irqvalue for use in the interrupt thread. */
+ rt2x00dev->irqvalue[0] = reg;
+
+ /* Disable interrupts, will be enabled again in the interrupt thread. */
+ rt2x00dev->ops->lib->set_device_state(rt2x00dev,
+ STATE_RADIO_IRQ_OFF_ISR);
+
+
+ return IRQ_WAKE_THREAD;
+}
+
/*
* Device probe functions.
*/
@@ -983,26 +926,10 @@ static int rt2800pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
return rt2800_validate_eeprom(rt2x00dev);
}
-static const struct rt2800_ops rt2800pci_rt2800_ops = {
- .register_read = rt2x00pci_register_read,
- .register_read_lock = rt2x00pci_register_read, /* same for PCI */
- .register_write = rt2x00pci_register_write,
- .register_write_lock = rt2x00pci_register_write, /* same for PCI */
-
- .register_multiread = rt2x00pci_register_multiread,
- .register_multiwrite = rt2x00pci_register_multiwrite,
-
- .regbusy_read = rt2x00pci_regbusy_read,
-
- .drv_init_registers = rt2800pci_init_registers,
-};
-
static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
{
int retval;
- rt2x00dev->priv = (void *)&rt2800pci_rt2800_ops;
-
/*
* Allocate eeprom data.
*/
@@ -1029,6 +956,12 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
__set_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags);
/*
+ * This device has a pre tbtt interrupt and thus fetches
+ * a new beacon directly prior to transmission.
+ */
+ __set_bit(DRIVER_SUPPORT_PRE_TBTT_INTERRUPT, &rt2x00dev->flags);
+
+ /*
* This device requires firmware.
*/
if (!rt2x00_is_soc(rt2x00dev))
@@ -1037,6 +970,7 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
__set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags);
if (!modparam_nohwcrypt)
__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
+ __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
/*
* Set the rssi offset.
@@ -1046,12 +980,46 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
return 0;
}
+static const struct ieee80211_ops rt2800pci_mac80211_ops = {
+ .tx = rt2x00mac_tx,
+ .start = rt2x00mac_start,
+ .stop = rt2x00mac_stop,
+ .add_interface = rt2x00mac_add_interface,
+ .remove_interface = rt2x00mac_remove_interface,
+ .config = rt2x00mac_config,
+ .configure_filter = rt2x00mac_configure_filter,
+ .set_key = rt2x00mac_set_key,
+ .sw_scan_start = rt2x00mac_sw_scan_start,
+ .sw_scan_complete = rt2x00mac_sw_scan_complete,
+ .get_stats = rt2x00mac_get_stats,
+ .get_tkip_seq = rt2800_get_tkip_seq,
+ .set_rts_threshold = rt2800_set_rts_threshold,
+ .bss_info_changed = rt2x00mac_bss_info_changed,
+ .conf_tx = rt2800_conf_tx,
+ .get_tsf = rt2800_get_tsf,
+ .rfkill_poll = rt2x00mac_rfkill_poll,
+ .ampdu_action = rt2800_ampdu_action,
+};
+
+static const struct rt2800_ops rt2800pci_rt2800_ops = {
+ .register_read = rt2x00pci_register_read,
+ .register_read_lock = rt2x00pci_register_read, /* same for PCI */
+ .register_write = rt2x00pci_register_write,
+ .register_write_lock = rt2x00pci_register_write, /* same for PCI */
+ .register_multiread = rt2x00pci_register_multiread,
+ .register_multiwrite = rt2x00pci_register_multiwrite,
+ .regbusy_read = rt2x00pci_regbusy_read,
+ .drv_write_firmware = rt2800pci_write_firmware,
+ .drv_init_registers = rt2800pci_init_registers,
+};
+
static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
.irq_handler = rt2800pci_interrupt,
+ .irq_handler_thread = rt2800pci_interrupt_thread,
.probe_hw = rt2800pci_probe_hw,
.get_firmware_name = rt2800pci_get_firmware_name,
- .check_firmware = rt2800pci_check_firmware,
- .load_firmware = rt2800pci_load_firmware,
+ .check_firmware = rt2800_check_firmware,
+ .load_firmware = rt2800_load_firmware,
.initialize = rt2x00pci_initialize,
.uninitialize = rt2x00pci_uninitialize,
.get_entry_state = rt2800pci_get_entry_state,
@@ -1109,7 +1077,8 @@ static const struct rt2x00_ops rt2800pci_ops = {
.tx = &rt2800pci_queue_tx,
.bcn = &rt2800pci_queue_bcn,
.lib = &rt2800pci_rt2x00_ops,
- .hw = &rt2800_mac80211_ops,
+ .drv = &rt2800pci_rt2800_ops,
+ .hw = &rt2800pci_mac80211_ops,
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
.debugfs = &rt2800_rt2x00debug,
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */