rt2x00: don't write past the end when writing short descriptors on rt61
[safe/jmp/linux-2.6] / drivers / net / wireless / rt2x00 / rt61pci.c
index 0693b39..5e08541 100644 (file)
@@ -1,5 +1,5 @@
 /*
-       Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+       Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
        <http://rt2x00.serialmonkey.com>
 
        This program is free software; you can redistribute it and/or modify
@@ -262,7 +262,7 @@ static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
        u32 reg;
 
        rt2x00pci_register_read(rt2x00dev, MAC_CSR13, &reg);
-       return rt2x00_get_field32(reg, MAC_CSR13_BIT5);;
+       return rt2x00_get_field32(reg, MAC_CSR13_BIT5);
 }
 #else
 #define rt61pci_rfkill_poll    NULL
@@ -317,7 +317,8 @@ static void rt61pci_config_type(struct rt2x00_dev *rt2x00dev, const int type,
         */
        rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
        rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
-       rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
+       rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE,
+                         (tsf_sync == TSF_SYNC_BEACON));
        rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
        rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, tsf_sync);
        rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
@@ -988,138 +989,101 @@ static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, void *data,
        return 0;
 }
 
-static void rt61pci_init_rxring(struct rt2x00_dev *rt2x00dev)
+static void rt61pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
+                                struct queue_entry *entry)
 {
-       struct data_ring *ring = rt2x00dev->rx;
-       __le32 *rxd;
-       unsigned int i;
+       struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data;
        u32 word;
 
-       memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring));
-
-       for (i = 0; i < ring->stats.limit; i++) {
-               rxd = ring->entry[i].priv;
+       rt2x00_desc_read(priv_rx->desc, 5, &word);
+       rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS, priv_rx->dma);
+       rt2x00_desc_write(priv_rx->desc, 5, word);
 
-               rt2x00_desc_read(rxd, 5, &word);
-               rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS,
-                                  ring->entry[i].data_dma);
-               rt2x00_desc_write(rxd, 5, word);
-
-               rt2x00_desc_read(rxd, 0, &word);
-               rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
-               rt2x00_desc_write(rxd, 0, word);
-       }
-
-       rt2x00_ring_index_clear(rt2x00dev->rx);
+       rt2x00_desc_read(priv_rx->desc, 0, &word);
+       rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
+       rt2x00_desc_write(priv_rx->desc, 0, word);
 }
 
-static void rt61pci_init_txring(struct rt2x00_dev *rt2x00dev, const int queue)
+static void rt61pci_init_txentry(struct rt2x00_dev *rt2x00dev,
+                                struct queue_entry *entry)
 {
-       struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue);
-       __le32 *txd;
-       unsigned int i;
+       struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data;
        u32 word;
 
-       memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring));
-
-       for (i = 0; i < ring->stats.limit; i++) {
-               txd = ring->entry[i].priv;
+       rt2x00_desc_read(priv_tx->desc, 1, &word);
+       rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1);
+       rt2x00_desc_write(priv_tx->desc, 1, word);
 
-               rt2x00_desc_read(txd, 1, &word);
-               rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1);
-               rt2x00_desc_write(txd, 1, word);
+       rt2x00_desc_read(priv_tx->desc, 5, &word);
+       rt2x00_set_field32(&word, TXD_W5_PID_TYPE, entry->queue->qid);
+       rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE, entry->entry_idx);
+       rt2x00_desc_write(priv_tx->desc, 5, word);
 
-               rt2x00_desc_read(txd, 5, &word);
-               rt2x00_set_field32(&word, TXD_W5_PID_TYPE, queue);
-               rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE, i);
-               rt2x00_desc_write(txd, 5, word);
+       rt2x00_desc_read(priv_tx->desc, 6, &word);
+       rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS, priv_tx->dma);
+       rt2x00_desc_write(priv_tx->desc, 6, word);
 
-               rt2x00_desc_read(txd, 6, &word);
-               rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS,
-                                  ring->entry[i].data_dma);
-               rt2x00_desc_write(txd, 6, word);
-
-               rt2x00_desc_read(txd, 0, &word);
-               rt2x00_set_field32(&word, TXD_W0_VALID, 0);
-               rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
-               rt2x00_desc_write(txd, 0, word);
-       }
-
-       rt2x00_ring_index_clear(ring);
+       rt2x00_desc_read(priv_tx->desc, 0, &word);
+       rt2x00_set_field32(&word, TXD_W0_VALID, 0);
+       rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
+       rt2x00_desc_write(priv_tx->desc, 0, word);
 }
 
-static int rt61pci_init_rings(struct rt2x00_dev *rt2x00dev)
+static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev)
 {
+       struct queue_entry_priv_pci_rx *priv_rx;
+       struct queue_entry_priv_pci_tx *priv_tx;
        u32 reg;
 
        /*
-        * Initialize rings.
-        */
-       rt61pci_init_rxring(rt2x00dev);
-       rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0);
-       rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA1);
-       rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA2);
-       rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA3);
-       rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA4);
-
-       /*
         * Initialize registers.
         */
        rt2x00pci_register_read(rt2x00dev, TX_RING_CSR0, &reg);
        rt2x00_set_field32(&reg, TX_RING_CSR0_AC0_RING_SIZE,
-                          rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].stats.limit);
+                          rt2x00dev->tx[0].limit);
        rt2x00_set_field32(&reg, TX_RING_CSR0_AC1_RING_SIZE,
-                          rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].stats.limit);
+                          rt2x00dev->tx[1].limit);
        rt2x00_set_field32(&reg, TX_RING_CSR0_AC2_RING_SIZE,
-                          rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA2].stats.limit);
+                          rt2x00dev->tx[2].limit);
        rt2x00_set_field32(&reg, TX_RING_CSR0_AC3_RING_SIZE,
-                          rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA3].stats.limit);
+                          rt2x00dev->tx[3].limit);
        rt2x00pci_register_write(rt2x00dev, TX_RING_CSR0, reg);
 
        rt2x00pci_register_read(rt2x00dev, TX_RING_CSR1, &reg);
-       rt2x00_set_field32(&reg, TX_RING_CSR1_MGMT_RING_SIZE,
-                          rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA4].stats.limit);
        rt2x00_set_field32(&reg, TX_RING_CSR1_TXD_SIZE,
-                          rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].desc_size /
-                          4);
+                          rt2x00dev->tx[0].desc_size / 4);
        rt2x00pci_register_write(rt2x00dev, TX_RING_CSR1, reg);
 
+       priv_tx = rt2x00dev->tx[0].entries[0].priv_data;
        rt2x00pci_register_read(rt2x00dev, AC0_BASE_CSR, &reg);
-       rt2x00_set_field32(&reg, AC0_BASE_CSR_RING_REGISTER,
-                          rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].data_dma);
+       rt2x00_set_field32(&reg, AC0_BASE_CSR_RING_REGISTER, priv_tx->dma);
        rt2x00pci_register_write(rt2x00dev, AC0_BASE_CSR, reg);
 
+       priv_tx = rt2x00dev->tx[1].entries[0].priv_data;
        rt2x00pci_register_read(rt2x00dev, AC1_BASE_CSR, &reg);
-       rt2x00_set_field32(&reg, AC1_BASE_CSR_RING_REGISTER,
-                          rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].data_dma);
+       rt2x00_set_field32(&reg, AC1_BASE_CSR_RING_REGISTER, priv_tx->dma);
        rt2x00pci_register_write(rt2x00dev, AC1_BASE_CSR, reg);
 
+       priv_tx = rt2x00dev->tx[2].entries[0].priv_data;
        rt2x00pci_register_read(rt2x00dev, AC2_BASE_CSR, &reg);
-       rt2x00_set_field32(&reg, AC2_BASE_CSR_RING_REGISTER,
-                          rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA2].data_dma);
+       rt2x00_set_field32(&reg, AC2_BASE_CSR_RING_REGISTER, priv_tx->dma);
        rt2x00pci_register_write(rt2x00dev, AC2_BASE_CSR, reg);
 
+       priv_tx = rt2x00dev->tx[3].entries[0].priv_data;
        rt2x00pci_register_read(rt2x00dev, AC3_BASE_CSR, &reg);
-       rt2x00_set_field32(&reg, AC3_BASE_CSR_RING_REGISTER,
-                          rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA3].data_dma);
+       rt2x00_set_field32(&reg, AC3_BASE_CSR_RING_REGISTER, priv_tx->dma);
        rt2x00pci_register_write(rt2x00dev, AC3_BASE_CSR, reg);
 
-       rt2x00pci_register_read(rt2x00dev, MGMT_BASE_CSR, &reg);
-       rt2x00_set_field32(&reg, MGMT_BASE_CSR_RING_REGISTER,
-                          rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA4].data_dma);
-       rt2x00pci_register_write(rt2x00dev, MGMT_BASE_CSR, reg);
-
        rt2x00pci_register_read(rt2x00dev, RX_RING_CSR, &reg);
-       rt2x00_set_field32(&reg, RX_RING_CSR_RING_SIZE,
-                          rt2x00dev->rx->stats.limit);
+       rt2x00_set_field32(&reg, RX_RING_CSR_RING_SIZE, rt2x00dev->rx->limit);
        rt2x00_set_field32(&reg, RX_RING_CSR_RXD_SIZE,
                           rt2x00dev->rx->desc_size / 4);
        rt2x00_set_field32(&reg, RX_RING_CSR_RXD_WRITEBACK_SIZE, 4);
        rt2x00pci_register_write(rt2x00dev, RX_RING_CSR, reg);
 
+       priv_rx = rt2x00dev->rx->entries[0].priv_data;
        rt2x00pci_register_read(rt2x00dev, RX_BASE_CSR, &reg);
-       rt2x00_set_field32(&reg, RX_BASE_CSR_RING_REGISTER,
-                          rt2x00dev->rx->data_dma);
+       rt2x00_set_field32(&reg, RX_BASE_CSR_RING_REGISTER, priv_rx->dma);
        rt2x00pci_register_write(rt2x00dev, RX_BASE_CSR, reg);
 
        rt2x00pci_register_read(rt2x00dev, TX_DMA_DST_CSR, &reg);
@@ -1135,7 +1099,7 @@ static int rt61pci_init_rings(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_field32(&reg, LOAD_TX_RING_CSR_LOAD_TXD_AC1, 1);
        rt2x00_set_field32(&reg, LOAD_TX_RING_CSR_LOAD_TXD_AC2, 1);
        rt2x00_set_field32(&reg, LOAD_TX_RING_CSR_LOAD_TXD_AC3, 1);
-       rt2x00_set_field32(&reg, LOAD_TX_RING_CSR_LOAD_TXD_MGMT, 1);
+       rt2x00_set_field32(&reg, LOAD_TX_RING_CSR_LOAD_TXD_MGMT, 0);
        rt2x00pci_register_write(rt2x00dev, LOAD_TX_RING_CSR, reg);
 
        rt2x00pci_register_read(rt2x00dev, RX_CNTL_CSR, &reg);
@@ -1402,7 +1366,7 @@ static int rt61pci_enable_radio(struct rt2x00_dev *rt2x00dev)
        /*
         * Initialize all registers.
         */
-       if (rt61pci_init_rings(rt2x00dev) ||
+       if (rt61pci_init_queues(rt2x00dev) ||
            rt61pci_init_registers(rt2x00dev) ||
            rt61pci_init_bbp(rt2x00dev)) {
                ERROR(rt2x00dev, "Register initialization failed.\n");
@@ -1509,8 +1473,12 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev,
                rt61pci_disable_radio(rt2x00dev);
                break;
        case STATE_RADIO_RX_ON:
+       case STATE_RADIO_RX_ON_LINK:
+               rt61pci_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
+               break;
        case STATE_RADIO_RX_OFF:
-               rt61pci_toggle_rx(rt2x00dev, state);
+       case STATE_RADIO_RX_OFF_LINK:
+               rt61pci_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
                break;
        case STATE_DEEP_SLEEP:
        case STATE_SLEEP:
@@ -1530,31 +1498,31 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev,
  * TX descriptor initialization
  */
 static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
-                                 __le32 *txd,
-                                 struct txdata_entry_desc *desc,
-                                 struct ieee80211_hdr *ieee80211hdr,
-                                 unsigned int length,
-                                 struct ieee80211_tx_control *control)
+                                   struct sk_buff *skb,
+                                   struct txentry_desc *txdesc,
+                                   struct ieee80211_tx_control *control)
 {
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
+       __le32 *txd = skbdesc->desc;
        u32 word;
 
        /*
         * Start writing the descriptor words.
         */
        rt2x00_desc_read(txd, 1, &word);
-       rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, desc->queue);
-       rt2x00_set_field32(&word, TXD_W1_AIFSN, desc->aifs);
-       rt2x00_set_field32(&word, TXD_W1_CWMIN, desc->cw_min);
-       rt2x00_set_field32(&word, TXD_W1_CWMAX, desc->cw_max);
+       rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->queue);
+       rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs);
+       rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min);
+       rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max);
        rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER);
        rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1);
        rt2x00_desc_write(txd, 1, word);
 
        rt2x00_desc_read(txd, 2, &word);
-       rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, desc->signal);
-       rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, desc->service);
-       rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, desc->length_low);
-       rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, desc->length_high);
+       rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, txdesc->signal);
+       rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, txdesc->service);
+       rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, txdesc->length_low);
+       rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, txdesc->length_high);
        rt2x00_desc_write(txd, 2, word);
 
        rt2x00_desc_read(txd, 5, &word);
@@ -1563,29 +1531,31 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1);
        rt2x00_desc_write(txd, 5, word);
 
-       rt2x00_desc_read(txd, 11, &word);
-       rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0, length);
-       rt2x00_desc_write(txd, 11, word);
+       if (skbdesc->desc_len > TXINFO_SIZE) {
+               rt2x00_desc_read(txd, 11, &word);
+               rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0, skbdesc->data_len);
+               rt2x00_desc_write(txd, 11, word);
+       }
 
        rt2x00_desc_read(txd, 0, &word);
        rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1);
        rt2x00_set_field32(&word, TXD_W0_VALID, 1);
        rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
-                          test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags));
+                          test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
        rt2x00_set_field32(&word, TXD_W0_ACK,
-                          test_bit(ENTRY_TXD_ACK, &desc->flags));
+                          test_bit(ENTRY_TXD_ACK, &txdesc->flags));
        rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
-                          test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags));
+                          test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
        rt2x00_set_field32(&word, TXD_W0_OFDM,
-                          test_bit(ENTRY_TXD_OFDM_RATE, &desc->flags));
-       rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs);
+                          test_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags));
+       rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
        rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
                           !!(control->flags &
                              IEEE80211_TXCTL_LONG_RETRY_LIMIT));
        rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0);
-       rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, length);
+       rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len);
        rt2x00_set_field32(&word, TXD_W0_BURST,
-                          test_bit(ENTRY_TXD_BURST, &desc->flags));
+                          test_bit(ENTRY_TXD_BURST, &txdesc->flags));
        rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE);
        rt2x00_desc_write(txd, 0, word);
 }
@@ -1671,29 +1641,28 @@ static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
        return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset;
 }
 
-static void rt61pci_fill_rxdone(struct data_entry *entry,
-                               struct rxdata_entry_desc *desc)
+static void rt61pci_fill_rxdone(struct queue_entry *entry,
+                               struct rxdone_entry_desc *rxdesc)
 {
-       __le32 *rxd = entry->priv;
+       struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data;
        u32 word0;
        u32 word1;
 
-       rt2x00_desc_read(rxd, 0, &word0);
-       rt2x00_desc_read(rxd, 1, &word1);
+       rt2x00_desc_read(priv_rx->desc, 0, &word0);
+       rt2x00_desc_read(priv_rx->desc, 1, &word1);
 
-       desc->flags = 0;
+       rxdesc->flags = 0;
        if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
-               desc->flags |= RX_FLAG_FAILED_FCS_CRC;
+               rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
 
        /*
         * Obtain the status about this packet.
         */
-       desc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
-       desc->rssi = rt61pci_agc_to_rssi(entry->ring->rt2x00dev, word1);
-       desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
-       desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
-
-       return;
+       rxdesc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
+       rxdesc->rssi = rt61pci_agc_to_rssi(entry->queue->rt2x00dev, word1);
+       rxdesc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
+       rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
+       rxdesc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS);
 }
 
 /*
@@ -1701,17 +1670,16 @@ static void rt61pci_fill_rxdone(struct data_entry *entry,
  */
 static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
 {
-       struct data_ring *ring;
-       struct data_entry *entry;
-       struct data_entry *entry_done;
-       __le32 *txd;
+       struct data_queue *queue;
+       struct queue_entry *entry;
+       struct queue_entry *entry_done;
+       struct queue_entry_priv_pci_tx *priv_tx;
+       struct txdone_entry_desc txdesc;
        u32 word;
        u32 reg;
        u32 old_reg;
        int type;
        int index;
-       int tx_status;
-       int retry;
 
        /*
         * During each loop we will compare the freshly read
@@ -1734,11 +1702,11 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
 
                /*
                 * Skip this entry when it contains an invalid
-                * ring identication number.
+                * queue identication number.
                 */
                type = rt2x00_get_field32(reg, STA_CSR4_PID_TYPE);
-               ring = rt2x00lib_get_ring(rt2x00dev, type);
-               if (unlikely(!ring))
+               queue = rt2x00queue_get_queue(rt2x00dev, type);
+               if (unlikely(!queue))
                        continue;
 
                /*
@@ -1746,35 +1714,40 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
                 * index number.
                 */
                index = rt2x00_get_field32(reg, STA_CSR4_PID_SUBTYPE);
-               if (unlikely(index >= ring->stats.limit))
+               if (unlikely(index >= queue->limit))
                        continue;
 
-               entry = &ring->entry[index];
-               txd = entry->priv;
-               rt2x00_desc_read(txd, 0, &word);
+               entry = &queue->entries[index];
+               priv_tx = entry->priv_data;
+               rt2x00_desc_read(priv_tx->desc, 0, &word);
 
                if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) ||
                    !rt2x00_get_field32(word, TXD_W0_VALID))
                        return;
 
-               entry_done = rt2x00_get_data_entry_done(ring);
+               entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
                while (entry != entry_done) {
-                       /* Catch up. Just report any entries we missed as
-                        * failed. */
+                       /* Catch up.
+                        * Just report any entries we missed as failed.
+                        */
                        WARNING(rt2x00dev,
-                               "TX status report missed for entry %p\n",
-                               entry_done);
-                       rt2x00lib_txdone(entry_done, TX_FAIL_OTHER, 0);
-                       entry_done = rt2x00_get_data_entry_done(ring);
+                               "TX status report missed for entry %d\n",
+                               entry_done->entry_idx);
+
+                       txdesc.status = TX_FAIL_OTHER;
+                       txdesc.retry = 0;
+
+                       rt2x00pci_txdone(rt2x00dev, entry_done, &txdesc);
+                       entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
                }
 
                /*
                 * Obtain the status about this packet.
                 */
-               tx_status = rt2x00_get_field32(reg, STA_CSR4_TX_RESULT);
-               retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT);
+               txdesc.status = rt2x00_get_field32(reg, STA_CSR4_TX_RESULT);
+               txdesc.retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT);
 
-               rt2x00pci_txdone(rt2x00dev, entry, tx_status, retry);
+               rt2x00pci_txdone(rt2x00dev, entry, &txdesc);
        }
 }
 
@@ -2307,7 +2280,6 @@ static void rt61pci_configure_filter(struct ieee80211_hw *hw,
                                     struct dev_addr_list *mc_list)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
-       struct interface *intf = &rt2x00dev->interface;
        u32 reg;
 
        /*
@@ -2326,22 +2298,19 @@ static void rt61pci_configure_filter(struct ieee80211_hw *hw,
         * Apply some rules to the filters:
         * - Some filters imply different filters to be set.
         * - Some things we can't filter out at all.
-        * - Some filters are set based on interface type.
         */
        if (mc_count)
                *total_flags |= FIF_ALLMULTI;
        if (*total_flags & FIF_OTHER_BSS ||
            *total_flags & FIF_PROMISC_IN_BSS)
                *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
-       if (is_interface_type(intf, IEEE80211_IF_TYPE_AP))
-               *total_flags |= FIF_PROMISC_IN_BSS;
 
        /*
         * Check if there is any work left for us.
         */
-       if (intf->filter == *total_flags)
+       if (rt2x00dev->packet_filter == *total_flags)
                return;
-       intf->filter = *total_flags;
+       rt2x00dev->packet_filter = *total_flags;
 
        /*
         * Start configuration steps.
@@ -2408,9 +2377,9 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
                          struct ieee80211_tx_control *control)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
-       struct skb_desc *desc;
-       struct data_ring *ring;
-       struct data_entry *entry;
+       struct skb_frame_desc *skbdesc;
+       struct data_queue *queue;
+       struct queue_entry *entry;
 
        /*
         * Just in case the ieee80211 doesn't set this,
@@ -2418,15 +2387,15 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
         * initialization.
         */
        control->queue = IEEE80211_TX_QUEUE_BEACON;
-       ring = rt2x00lib_get_ring(rt2x00dev, control->queue);
-       entry = rt2x00_get_data_entry(ring);
+       queue = rt2x00queue_get_queue(rt2x00dev, control->queue);
+       entry = rt2x00queue_get_entry(queue, Q_INDEX);
 
        /*
         * We need to append the descriptor in front of the
         * beacon frame.
         */
-       if (skb_headroom(skb) < TXD_DESC_SIZE) {
-               if (pskb_expand_head(skb, TXD_DESC_SIZE, 0, GFP_ATOMIC)) {
+       if (skb_headroom(skb) < queue->desc_size) {
+               if (pskb_expand_head(skb, queue->desc_size, 0, GFP_ATOMIC)) {
                        dev_kfree_skb(skb);
                        return -ENOMEM;
                }
@@ -2435,19 +2404,19 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
        /*
         * Add the descriptor in front of the skb.
         */
-       skb_push(skb, ring->desc_size);
-       memset(skb->data, 0, ring->desc_size);
+       skb_push(skb, queue->desc_size);
+       memset(skb->data, 0, queue->desc_size);
 
        /*
         * Fill in skb descriptor
         */
-       desc = get_skb_desc(skb);
-       desc->desc_len = ring->desc_size;
-       desc->data_len = skb->len - ring->desc_size;
-       desc->desc = skb->data;
-       desc->data = skb->data + ring->desc_size;
-       desc->ring = ring;
-       desc->entry = entry;
+       skbdesc = get_skb_frame_desc(skb);
+       memset(skbdesc, 0, sizeof(*skbdesc));
+       skbdesc->data = skb->data + queue->desc_size;
+       skbdesc->data_len = queue->data_size;
+       skbdesc->desc = skb->data;
+       skbdesc->desc_len = queue->desc_size;
+       skbdesc->entry = entry;
 
        rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
 
@@ -2473,7 +2442,7 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = {
        .configure_filter       = rt61pci_configure_filter,
        .get_stats              = rt2x00mac_get_stats,
        .set_retry_limit        = rt61pci_set_retry_limit,
-       .erp_ie_changed         = rt2x00mac_erp_ie_changed,
+       .bss_info_changed       = rt2x00mac_bss_info_changed,
        .conf_tx                = rt2x00mac_conf_tx,
        .get_tx_stats           = rt2x00mac_get_tx_stats,
        .get_tsf                = rt61pci_get_tsf,
@@ -2488,6 +2457,8 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
        .load_firmware          = rt61pci_load_firmware,
        .initialize             = rt2x00pci_initialize,
        .uninitialize           = rt2x00pci_uninitialize,
+       .init_rxentry           = rt61pci_init_rxentry,
+       .init_txentry           = rt61pci_init_txentry,
        .set_device_state       = rt61pci_set_device_state,
        .rfkill_poll            = rt61pci_rfkill_poll,
        .link_stats             = rt61pci_link_stats,
@@ -2504,12 +2475,34 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
        .config                 = rt61pci_config,
 };
 
+static const struct data_queue_desc rt61pci_queue_rx = {
+       .entry_num              = RX_ENTRIES,
+       .data_size              = DATA_FRAME_SIZE,
+       .desc_size              = RXD_DESC_SIZE,
+       .priv_size              = sizeof(struct queue_entry_priv_pci_rx),
+};
+
+static const struct data_queue_desc rt61pci_queue_tx = {
+       .entry_num              = TX_ENTRIES,
+       .data_size              = DATA_FRAME_SIZE,
+       .desc_size              = TXD_DESC_SIZE,
+       .priv_size              = sizeof(struct queue_entry_priv_pci_tx),
+};
+
+static const struct data_queue_desc rt61pci_queue_bcn = {
+       .entry_num              = BEACON_ENTRIES,
+       .data_size              = MGMT_FRAME_SIZE,
+       .desc_size              = TXINFO_SIZE,
+       .priv_size              = sizeof(struct queue_entry_priv_pci_tx),
+};
+
 static const struct rt2x00_ops rt61pci_ops = {
        .name           = KBUILD_MODNAME,
-       .rxd_size       = RXD_DESC_SIZE,
-       .txd_size       = TXD_DESC_SIZE,
        .eeprom_size    = EEPROM_SIZE,
        .rf_size        = RF_SIZE,
+       .rx             = &rt61pci_queue_rx,
+       .tx             = &rt61pci_queue_tx,
+       .bcn            = &rt61pci_queue_bcn,
        .lib            = &rt61pci_rt2x00_ops,
        .hw             = &rt61pci_mac80211_ops,
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS