From 181d6902b6bad978d157e69479c95cc0ff213a76 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 5 Feb 2008 16:42:23 -0500 Subject: rt2x00: Queue handling overhaul This introduces a big queue handling overhaul, this also renames "ring" to "queues". Move queue handling into rt2x00queue.c and the matching header, use Kerneldoc to improve rt2x00 library documentation. Access to the queues is now protected under a spinlock, this to prevent race conditions which could corrupt the indexing system of the queue. Each queue entry allocates x bytes for driver/device specific data, this cleans up the queue structure significantly and improves code readability. rt2500usb no longer needs 2 entries in the beacon queue to correctly send out the guardian byte. This is now handled in the entry specific structure. rt61 and rt73 now use the correct descriptor size for beacon frames, since this data is written into the registers not the entire TXD descriptor was used but instead of a subset of it named TXINFO. Finally this also fixes numerous other bugs related to incorrect beacon handling or beacon related code. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00pci.c | 223 +++++++++++++++++--------------- 1 file changed, 118 insertions(+), 105 deletions(-) (limited to 'drivers/net/wireless/rt2x00/rt2x00pci.c') diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index 0f2590bc31ec..63cfe33e95da 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -38,9 +38,10 @@ int rt2x00pci_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 queue_entry_priv_pci_tx *priv_tx; + struct skb_frame_desc *skbdesc; + struct data_queue *queue; + struct queue_entry *entry; /* * Just in case mac80211 doesn't set this correctly, @@ -48,21 +49,22 @@ int rt2x00pci_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); + priv_tx = entry->priv_data; /* * Fill in skb descriptor */ - desc = get_skb_desc(skb); - desc->desc_len = ring->desc_size; - desc->data_len = skb->len; - desc->desc = entry->priv; - desc->data = skb->data; - desc->ring = ring; - desc->entry = entry; - - memcpy(entry->data_addr, skb->data, skb->len); + skbdesc = get_skb_frame_desc(skb); + memset(skbdesc, 0, sizeof(*skbdesc)); + skbdesc->data = skb->data; + skbdesc->data_len = queue->data_size; + skbdesc->desc = priv_tx->desc; + skbdesc->desc_len = queue->desc_size; + skbdesc->entry = entry; + + memcpy(priv_tx->data, skb->data, skb->len); rt2x00lib_write_tx_desc(rt2x00dev, skb, control); /* @@ -78,18 +80,18 @@ EXPORT_SYMBOL_GPL(rt2x00pci_beacon_update); * TX data handlers. */ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, - struct data_ring *ring, struct sk_buff *skb, + struct data_queue *queue, struct sk_buff *skb, struct ieee80211_tx_control *control) { - struct data_entry *entry = rt2x00_get_data_entry(ring); - __le32 *txd = entry->priv; - struct skb_desc *desc; + struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); + struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; + struct skb_frame_desc *skbdesc; u32 word; - if (rt2x00_ring_full(ring)) + if (rt2x00queue_full(queue)) return -EINVAL; - rt2x00_desc_read(txd, 0, &word); + rt2x00_desc_read(priv_tx->desc, 0, &word); if (rt2x00_get_field32(word, TXD_ENTRY_OWNER_NIC) || rt2x00_get_field32(word, TXD_ENTRY_VALID)) { @@ -103,18 +105,18 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, /* * Fill in skb descriptor */ - desc = get_skb_desc(skb); - desc->desc_len = ring->desc_size; - desc->data_len = skb->len; - desc->desc = entry->priv; - desc->data = skb->data; - desc->ring = ring; - desc->entry = entry; - - memcpy(entry->data_addr, skb->data, skb->len); + skbdesc = get_skb_frame_desc(skb); + memset(skbdesc, 0, sizeof(*skbdesc)); + skbdesc->data = skb->data; + skbdesc->data_len = queue->data_size; + skbdesc->desc = priv_tx->desc; + skbdesc->desc_len = queue->desc_size; + skbdesc->entry = entry; + + memcpy(priv_tx->data, skb->data, skb->len); rt2x00lib_write_tx_desc(rt2x00dev, skb, control); - rt2x00_ring_index_inc(ring); + rt2x00queue_index_inc(queue, Q_INDEX); return 0; } @@ -125,29 +127,28 @@ EXPORT_SYMBOL_GPL(rt2x00pci_write_tx_data); */ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) { - struct data_ring *ring = rt2x00dev->rx; - struct data_entry *entry; - struct sk_buff *skb; + struct data_queue *queue = rt2x00dev->rx; + struct queue_entry *entry; + struct queue_entry_priv_pci_rx *priv_rx; struct ieee80211_hdr *hdr; - struct skb_desc *skbdesc; - struct rxdata_entry_desc desc; + struct skb_frame_desc *skbdesc; + struct rxdone_entry_desc rxdesc; int header_size; - __le32 *rxd; int align; u32 word; while (1) { - entry = rt2x00_get_data_entry(ring); - rxd = entry->priv; - rt2x00_desc_read(rxd, 0, &word); + entry = rt2x00queue_get_entry(queue, Q_INDEX); + priv_rx = entry->priv_data; + rt2x00_desc_read(priv_rx->desc, 0, &word); if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC)) break; - memset(&desc, 0, sizeof(desc)); - rt2x00dev->ops->lib->fill_rxdone(entry, &desc); + memset(&rxdesc, 0, sizeof(rxdesc)); + rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc); - hdr = (struct ieee80211_hdr *)entry->data_addr; + hdr = (struct ieee80211_hdr *)priv_rx->data; header_size = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); @@ -161,66 +162,68 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) * Allocate the sk_buffer, initialize it and copy * all data into it. */ - skb = dev_alloc_skb(desc.size + align); - if (!skb) + entry->skb = dev_alloc_skb(rxdesc.size + align); + if (!entry->skb) return; - skb_reserve(skb, align); - memcpy(skb_put(skb, desc.size), entry->data_addr, desc.size); + skb_reserve(entry->skb, align); + memcpy(skb_put(entry->skb, rxdesc.size), + priv_rx->data, rxdesc.size); /* * Fill in skb descriptor */ - skbdesc = get_skb_desc(skb); - skbdesc->desc_len = entry->ring->desc_size; - skbdesc->data_len = skb->len; - skbdesc->desc = entry->priv; - skbdesc->data = skb->data; - skbdesc->ring = ring; + skbdesc = get_skb_frame_desc(entry->skb); + memset(skbdesc, 0, sizeof(*skbdesc)); + skbdesc->data = entry->skb->data; + skbdesc->data_len = queue->data_size; + skbdesc->desc = priv_rx->desc; + skbdesc->desc_len = queue->desc_size; skbdesc->entry = entry; /* * Send the frame to rt2x00lib for further processing. */ - rt2x00lib_rxdone(entry, skb, &desc); + rt2x00lib_rxdone(entry, &rxdesc); - if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) { + if (test_bit(DEVICE_ENABLED_RADIO, &queue->rt2x00dev->flags)) { rt2x00_set_field32(&word, RXD_ENTRY_OWNER_NIC, 1); - rt2x00_desc_write(rxd, 0, word); + rt2x00_desc_write(priv_rx->desc, 0, word); } - rt2x00_ring_index_inc(ring); + rt2x00queue_index_inc(queue, Q_INDEX); } } EXPORT_SYMBOL_GPL(rt2x00pci_rxdone); -void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct data_entry *entry, - const int tx_status, const int retry) +void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry, + struct txdone_entry_desc *txdesc) { + struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; u32 word; - rt2x00lib_txdone(entry, tx_status, retry); + txdesc->control = &priv_tx->control; + rt2x00lib_txdone(entry, txdesc); /* * Make this entry available for reuse. */ entry->flags = 0; - rt2x00_desc_read(entry->priv, 0, &word); + rt2x00_desc_read(priv_tx->desc, 0, &word); rt2x00_set_field32(&word, TXD_ENTRY_OWNER_NIC, 0); rt2x00_set_field32(&word, TXD_ENTRY_VALID, 0); - rt2x00_desc_write(entry->priv, 0, word); + rt2x00_desc_write(priv_tx->desc, 0, word); - rt2x00_ring_index_done_inc(entry->ring); + rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE); /* - * If the data ring was full before the txdone handler + * If the data queue was full before the txdone handler * we must make sure the packet queue in the mac80211 stack * is reenabled when the txdone handler has finished. */ - if (!rt2x00_ring_full(entry->ring)) - ieee80211_wake_queue(rt2x00dev->hw, - entry->tx_status.control.queue); + if (!rt2x00queue_full(entry->queue)) + ieee80211_wake_queue(rt2x00dev->hw, priv_tx->control.queue); } EXPORT_SYMBOL_GPL(rt2x00pci_txdone); @@ -228,73 +231,83 @@ EXPORT_SYMBOL_GPL(rt2x00pci_txdone); /* * Device initialization handlers. */ -#define priv_offset(__ring, __i) \ -({ \ - ring->data_addr + (i * ring->desc_size); \ +#define dma_size(__queue) \ +({ \ + (__queue)->limit * \ + ((__queue)->desc_size + (__queue)->data_size);\ }) -#define data_addr_offset(__ring, __i) \ -({ \ - (__ring)->data_addr + \ - ((__ring)->stats.limit * (__ring)->desc_size) + \ - ((__i) * (__ring)->data_size); \ +#define priv_offset(__queue, __base, __i) \ +({ \ + (__base) + ((__i) * (__queue)->desc_size); \ }) -#define data_dma_offset(__ring, __i) \ -({ \ - (__ring)->data_dma + \ - ((__ring)->stats.limit * (__ring)->desc_size) + \ - ((__i) * (__ring)->data_size); \ +#define data_addr_offset(__queue, __base, __i) \ +({ \ + (__base) + \ + ((__queue)->limit * (__queue)->desc_size) + \ + ((__i) * (__queue)->data_size); \ }) -static int rt2x00pci_alloc_dma(struct rt2x00_dev *rt2x00dev, - struct data_ring *ring) +#define data_dma_offset(__queue, __base, __i) \ +({ \ + (__base) + \ + ((__queue)->limit * (__queue)->desc_size) + \ + ((__i) * (__queue)->data_size); \ +}) + +static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev, + struct data_queue *queue) { + struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev); + struct queue_entry_priv_pci_tx *priv_tx; + void *data_addr; + dma_addr_t data_dma; unsigned int i; /* * Allocate DMA memory for descriptor and buffer. */ - ring->data_addr = pci_alloc_consistent(rt2x00dev_pci(rt2x00dev), - rt2x00_get_ring_size(ring), - &ring->data_dma); - if (!ring->data_addr) + data_addr = pci_alloc_consistent(pci_dev, dma_size(queue), &data_dma); + if (!data_addr) return -ENOMEM; /* - * Initialize all ring entries to contain valid - * addresses. + * Initialize all queue entries to contain valid addresses. */ - for (i = 0; i < ring->stats.limit; i++) { - ring->entry[i].priv = priv_offset(ring, i); - ring->entry[i].data_addr = data_addr_offset(ring, i); - ring->entry[i].data_dma = data_dma_offset(ring, i); + for (i = 0; i < queue->limit; i++) { + priv_tx = queue->entries[i].priv_data; + priv_tx->desc = priv_offset(queue, data_addr, i); + priv_tx->data = data_addr_offset(queue, data_addr, i); + priv_tx->dma = data_dma_offset(queue, data_dma, i); } return 0; } -static void rt2x00pci_free_dma(struct rt2x00_dev *rt2x00dev, - struct data_ring *ring) +static void rt2x00pci_free_queue_dma(struct rt2x00_dev *rt2x00dev, + struct data_queue *queue) { - if (ring->data_addr) - pci_free_consistent(rt2x00dev_pci(rt2x00dev), - rt2x00_get_ring_size(ring), - ring->data_addr, ring->data_dma); - ring->data_addr = NULL; + struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev); + struct queue_entry_priv_pci_tx *priv_tx = queue->entries[0].priv_data; + + if (priv_tx->data) + pci_free_consistent(pci_dev, dma_size(queue), + priv_tx->data, priv_tx->dma); + priv_tx->data = NULL; } int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev) { struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev); - struct data_ring *ring; + struct data_queue *queue; int status; /* * Allocate DMA */ - ring_for_each(rt2x00dev, ring) { - status = rt2x00pci_alloc_dma(rt2x00dev, ring); + queue_for_each(rt2x00dev, queue) { + status = rt2x00pci_alloc_queue_dma(rt2x00dev, queue); if (status) goto exit; } @@ -321,7 +334,7 @@ EXPORT_SYMBOL_GPL(rt2x00pci_initialize); void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev) { - struct data_ring *ring; + struct data_queue *queue; /* * Free irq line. @@ -331,8 +344,8 @@ void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev) /* * Free DMA */ - ring_for_each(rt2x00dev, ring) - rt2x00pci_free_dma(rt2x00dev, ring); + queue_for_each(rt2x00dev, queue) + rt2x00pci_free_queue_dma(rt2x00dev, queue); } EXPORT_SYMBOL_GPL(rt2x00pci_uninitialize); @@ -530,5 +543,5 @@ EXPORT_SYMBOL_GPL(rt2x00pci_resume); */ MODULE_AUTHOR(DRV_PROJECT); MODULE_VERSION(DRV_VERSION); -MODULE_DESCRIPTION("rt2x00 library"); +MODULE_DESCRIPTION("rt2x00 pci library"); MODULE_LICENSE("GPL"); -- cgit v1.2.2