]> err.no Git - linux-2.6/commitdiff
rt2x00: Replace statically allocated DMA buffers with mapped skb's.
authorGertjan van Wingerde <gwingerde@kpnplanet.nl>
Mon, 16 Jun 2008 17:56:31 +0000 (19:56 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Thu, 26 Jun 2008 20:49:16 +0000 (16:49 -0400)
The current PCI drivers require a lot of pre-allocated DMA buffers. Reduce this
by using dynamically mapped skb's (using pci_map_single) instead of the pre-
allocated DMA buffers that are allocated at device start-up time.

At the same time move common RX path code into rt2x00lib from rt2x00pci and
rt2x00usb, as the RX paths now are now almost the same.

Signed-off-by: Gertjan van Wingerde <gwingerde@kpnplanet.nl>
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/rt2x00/rt2400pci.c
drivers/net/wireless/rt2x00/rt2500pci.c
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rt2x00/rt2x00pci.c
drivers/net/wireless/rt2x00/rt2x00pci.h
drivers/net/wireless/rt2x00/rt2x00queue.c
drivers/net/wireless/rt2x00/rt2x00queue.h
drivers/net/wireless/rt2x00/rt2x00usb.c
drivers/net/wireless/rt2x00/rt61pci.c

index 76ec1514fa44c046541c7cb6f7988455eaed387d..de2dd336f23d1e76e1886cc8711f2286d4a6ca5d 100644 (file)
@@ -632,15 +632,15 @@ static void rt2400pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
                                   struct queue_entry *entry)
 {
        struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
        u32 word;
 
        rt2x00_desc_read(entry_priv->desc, 2, &word);
-       rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH,
-                          entry->queue->data_size);
+       rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, entry->skb->len);
        rt2x00_desc_write(entry_priv->desc, 2, word);
 
        rt2x00_desc_read(entry_priv->desc, 1, &word);
-       rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, entry_priv->data_dma);
+       rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
        rt2x00_desc_write(entry_priv->desc, 1, word);
 
        rt2x00_desc_read(entry_priv->desc, 0, &word);
@@ -1012,7 +1012,7 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
         * Start writing the descriptor words.
         */
        rt2x00_desc_read(entry_priv->desc, 1, &word);
-       rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, entry_priv->data_dma);
+       rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
        rt2x00_desc_write(entry_priv->desc, 1, word);
 
        rt2x00_desc_read(txd, 2, &word);
@@ -1412,9 +1412,10 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev)
        rt2400pci_probe_hw_mode(rt2x00dev);
 
        /*
-        * This device requires the atim queue
+        * This device requires the atim queue and DMA-mapped skbs.
         */
        __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
+       __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
 
        /*
         * Set the rssi offset.
@@ -1526,7 +1527,7 @@ static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
         * Write entire beacon with descriptor to register,
         * and kick the beacon generator.
         */
-       memcpy(entry_priv->data, skb->data, skb->len);
+       rt2x00queue_map_txskb(rt2x00dev, intf->beacon->skb);
        rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
        rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
 
index 5f0117f9a88bf7d362d1f0d712f061dc45a683e0..5077b62dcc5aec838a3b870c3d04e32496de4f12 100644 (file)
@@ -727,10 +727,11 @@ static void rt2500pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
                                   struct queue_entry *entry)
 {
        struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
        u32 word;
 
        rt2x00_desc_read(entry_priv->desc, 1, &word);
-       rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, entry_priv->data_dma);
+       rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
        rt2x00_desc_write(entry_priv->desc, 1, word);
 
        rt2x00_desc_read(entry_priv->desc, 0, &word);
@@ -1171,7 +1172,7 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
         * Start writing the descriptor words.
         */
        rt2x00_desc_read(entry_priv->desc, 1, &word);
-       rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, entry_priv->data_dma);
+       rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
        rt2x00_desc_write(entry_priv->desc, 1, word);
 
        rt2x00_desc_read(txd, 2, &word);
@@ -1752,9 +1753,10 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev)
        rt2500pci_probe_hw_mode(rt2x00dev);
 
        /*
-        * This device requires the atim queue
+        * This device requires the atim queue and DMA-mapped skbs.
         */
        __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
+       __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
 
        /*
         * Set the rssi offset.
@@ -1842,7 +1844,7 @@ static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
         * Write entire beacon with descriptor to register,
         * and kick the beacon generator.
         */
-       memcpy(entry_priv->data, skb->data, skb->len);
+       rt2x00queue_map_txskb(rt2x00dev, intf->beacon->skb);
        rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
        rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
 
index 08e8b0a005a64b7b76082829a4da508db5f10ebf..28c9026bb568bad73426d1c837813d28b1da9fa2 100644 (file)
@@ -601,6 +601,7 @@ enum rt2x00_flags {
        DRIVER_REQUIRE_BEACON_GUARD,
        DRIVER_REQUIRE_ATIM_QUEUE,
        DRIVER_REQUIRE_SCHEDULED,
+       DRIVER_REQUIRE_DMA,
 
        /*
         * Driver configuration
@@ -899,16 +900,33 @@ static inline u16 get_duration_res(const unsigned int size, const u8 rate)
 }
 
 /**
- * rt2x00queue_alloc_skb - allocate a skb.
+ * rt2x00queue_alloc_rxskb - allocate a skb for RX purposes.
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
  * @queue: The queue for which the skb will be applicable.
  */
-struct sk_buff *rt2x00queue_alloc_skb(struct data_queue *queue);
+struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev,
+                                       struct queue_entry *entry);
+
+/**
+ * rt2x00queue_map_txskb - Map a skb into DMA for TX purposes.
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ * @skb: The skb to map.
+ */
+void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
+
+/**
+ * rt2x00queue_unmap_skb - Unmap a skb from DMA.
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ * @skb: The skb to unmap.
+ */
+void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
 
 /**
  * rt2x00queue_free_skb - free a skb
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
  * @skb: The skb to free.
  */
-void rt2x00queue_free_skb(struct sk_buff *skb);
+void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
 
 /**
  * rt2x00queue_create_tx_descriptor - Create TX descriptor from mac80211 input
@@ -977,8 +995,8 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index);
 void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev);
 void rt2x00lib_txdone(struct queue_entry *entry,
                      struct txdone_entry_desc *txdesc);
-void rt2x00lib_rxdone(struct queue_entry *entry,
-                     struct rxdone_entry_desc *rxdesc);
+void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
+                     struct queue_entry *entry);
 
 /*
  * mac80211 handlers.
index b8e0c4c3ed0a92a59b35963a8c9d13b42a75b12f..99b14ba99d97e3190a0674a6a73c85e1fd0c94f1 100644 (file)
@@ -468,6 +468,7 @@ static void rt2x00lib_intf_scheduled(struct work_struct *work)
 static void rt2x00lib_beacondone_iter(void *data, u8 *mac,
                                      struct ieee80211_vif *vif)
 {
+       struct rt2x00_dev *rt2x00dev = data;
        struct rt2x00_intf *intf = vif_to_intf(vif);
 
        if (vif->type != IEEE80211_IF_TYPE_AP &&
@@ -477,7 +478,7 @@ static void rt2x00lib_beacondone_iter(void *data, u8 *mac,
        /*
         * Clean up the beacon skb.
         */
-       dev_kfree_skb_irq(intf->beacon->skb);
+       rt2x00queue_free_skb(rt2x00dev, intf->beacon->skb);
        intf->beacon->skb = NULL;
 
        spin_lock(&intf->lock);
@@ -555,34 +556,55 @@ void rt2x00lib_txdone(struct queue_entry *entry,
 }
 EXPORT_SYMBOL_GPL(rt2x00lib_txdone);
 
-void rt2x00lib_rxdone(struct queue_entry *entry,
-                     struct rxdone_entry_desc *rxdesc)
+void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
+                     struct queue_entry *entry)
 {
-       struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+       struct rxdone_entry_desc rxdesc;
+       struct sk_buff *skb;
        struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status;
-       unsigned int header_size = ieee80211_get_hdrlen_from_skb(entry->skb);
        struct ieee80211_supported_band *sband;
        struct ieee80211_hdr *hdr;
        const struct rt2x00_rate *rate;
+       unsigned int header_size;
        unsigned int align;
        unsigned int i;
        int idx = -1;
 
+       /*
+        * Allocate a new sk_buffer. If no new buffer available, drop the
+        * received frame and reuse the existing buffer.
+        */
+       skb = rt2x00queue_alloc_rxskb(rt2x00dev, entry);
+       if (!skb)
+               return;
+
+       /*
+        * Unmap the skb.
+        */
+       rt2x00queue_unmap_skb(rt2x00dev, entry->skb);
+
+       /*
+        * Extract the RXD details.
+        */
+       memset(&rxdesc, 0, sizeof(rxdesc));
+       rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc);
+
        /*
         * The data behind the ieee80211 header must be
         * aligned on a 4 byte boundary.
         */
+       header_size = ieee80211_get_hdrlen_from_skb(entry->skb);
        align = ((unsigned long)(entry->skb->data + header_size)) & 3;
 
        if (align) {
                skb_push(entry->skb, align);
                /* Move entire frame in 1 command */
                memmove(entry->skb->data, entry->skb->data + align,
-                       rxdesc->size);
+                       rxdesc.size);
        }
 
        /* Update data pointers, trim buffer to correct size */
-       skb_trim(entry->skb, rxdesc->size);
+       skb_trim(entry->skb, rxdesc.size);
 
        /*
         * Update RX statistics.
@@ -591,10 +613,10 @@ void rt2x00lib_rxdone(struct queue_entry *entry,
        for (i = 0; i < sband->n_bitrates; i++) {
                rate = rt2x00_get_rate(sband->bitrates[i].hw_value);
 
-               if (((rxdesc->dev_flags & RXDONE_SIGNAL_PLCP) &&
-                    (rate->plcp == rxdesc->signal)) ||
-                   (!(rxdesc->dev_flags & RXDONE_SIGNAL_PLCP) &&
-                     (rate->bitrate == rxdesc->signal))) {
+               if (((rxdesc.dev_flags & RXDONE_SIGNAL_PLCP) &&
+                    (rate->plcp == rxdesc.signal)) ||
+                   (!(rxdesc.dev_flags & RXDONE_SIGNAL_PLCP) &&
+                     (rate->bitrate == rxdesc.signal))) {
                        idx = i;
                        break;
                }
@@ -602,8 +624,8 @@ void rt2x00lib_rxdone(struct queue_entry *entry,
 
        if (idx < 0) {
                WARNING(rt2x00dev, "Frame received with unrecognized signal,"
-                       "signal=0x%.2x, plcp=%d.\n", rxdesc->signal,
-                       !!(rxdesc->dev_flags & RXDONE_SIGNAL_PLCP));
+                       "signal=0x%.2x, plcp=%d.\n", rxdesc.signal,
+                       !!(rxdesc.dev_flags & RXDONE_SIGNAL_PLCP));
                idx = 0;
        }
 
@@ -612,16 +634,16 @@ void rt2x00lib_rxdone(struct queue_entry *entry,
         */
        hdr = (struct ieee80211_hdr *)entry->skb->data;
        if (ieee80211_is_beacon(hdr->frame_control) &&
-           (rxdesc->dev_flags & RXDONE_MY_BSS))
-               rt2x00lib_update_link_stats(&rt2x00dev->link, rxdesc->rssi);
+           (rxdesc.dev_flags & RXDONE_MY_BSS))
+               rt2x00lib_update_link_stats(&rt2x00dev->link, rxdesc.rssi);
 
        rt2x00dev->link.qual.rx_success++;
 
        rx_status->rate_idx = idx;
        rx_status->qual =
-           rt2x00lib_calculate_link_signal(rt2x00dev, rxdesc->rssi);
-       rx_status->signal = rxdesc->rssi;
-       rx_status->flag = rxdesc->flags;
+           rt2x00lib_calculate_link_signal(rt2x00dev, rxdesc.rssi);
+       rx_status->signal = rxdesc.rssi;
+       rx_status->flag = rxdesc.flags;
        rx_status->antenna = rt2x00dev->link.ant.active.rx;
 
        /*
@@ -630,7 +652,11 @@ void rt2x00lib_rxdone(struct queue_entry *entry,
         */
        rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb);
        ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb, rx_status);
-       entry->skb = NULL;
+
+       /*
+        * Replace the skb with the freshly allocated one.
+        */
+       entry->skb = skb;
 }
 EXPORT_SYMBOL_GPL(rt2x00lib_rxdone);
 
index e7e3a459b66a6b8196f0626fcb03ae332019e999..f9d0d76f87064a6a708c663267dd1441e5f6875e 100644 (file)
@@ -65,7 +65,7 @@ int rt2x00pci_write_tx_data(struct queue_entry *entry)
        skbdesc->desc_len = entry->queue->desc_size;
        skbdesc->entry = entry;
 
-       memcpy(entry_priv->data, entry->skb->data, entry->skb->len);
+       rt2x00queue_map_txskb(entry->queue->rt2x00dev, entry->skb);
 
        return 0;
 }
@@ -74,59 +74,12 @@ EXPORT_SYMBOL_GPL(rt2x00pci_write_tx_data);
 /*
  * TX/RX data handlers.
  */
-static void rt2x00pci_rxdone_entry(struct rt2x00_dev *rt2x00dev,
-                                  struct queue_entry *entry)
-{
-       struct sk_buff *skb;
-       struct skb_frame_desc *skbdesc;
-       struct rxdone_entry_desc rxdesc;
-       struct queue_entry_priv_pci *entry_priv = entry->priv_data;
-
-       /*
-        * Allocate a new sk_buffer. If no new buffer available, drop the
-        * received frame and reuse the existing buffer.
-        */
-       skb = rt2x00queue_alloc_skb(entry->queue);
-       if (!skb)
-               return;
-
-       /*
-        * Extract the RXD details.
-        */
-       memset(&rxdesc, 0, sizeof(rxdesc));
-       rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc);
-
-       /*
-        * Copy the received data to the entries' skb.
-        */
-       memcpy(entry->skb->data, entry_priv->data, rxdesc.size);
-       skb_trim(entry->skb, rxdesc.size);
-
-       /*
-        * Fill in skb descriptor
-        */
-       skbdesc = get_skb_frame_desc(entry->skb);
-       memset(skbdesc, 0, sizeof(*skbdesc));
-       skbdesc->desc = entry_priv->desc;
-       skbdesc->desc_len = entry->queue->desc_size;
-       skbdesc->entry = entry;
-
-       /*
-        * Send the frame to rt2x00lib for further processing.
-        */
-       rt2x00lib_rxdone(entry, &rxdesc);
-
-       /*
-        * Replace the entries' skb with the newly allocated one.
-        */
-       entry->skb = skb;
-}
-
 void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
 {
        struct data_queue *queue = rt2x00dev->rx;
        struct queue_entry *entry;
        struct queue_entry_priv_pci *entry_priv;
+       struct skb_frame_desc *skbdesc;
        u32 word;
 
        while (1) {
@@ -137,12 +90,22 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
                if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC))
                        break;
 
-               rt2x00pci_rxdone_entry(rt2x00dev, entry);
+               /*
+                * Fill in desc fields of the skb descriptor
+                */
+               skbdesc = get_skb_frame_desc(entry->skb);
+               skbdesc->desc = entry_priv->desc;
+               skbdesc->desc_len = entry->queue->desc_size;
+
+               /*
+                * Send the frame to rt2x00lib for further processing.
+                */
+               rt2x00lib_rxdone(rt2x00dev, entry);
 
-               if (test_bit(DEVICE_ENABLED_RADIO, &queue->rt2x00dev->flags)) {
-                       rt2x00_set_field32(&word, RXD_ENTRY_OWNER_NIC, 1);
-                       rt2x00_desc_write(entry_priv->desc, 0, word);
-               }
+               /*
+                * Reset the RXD for this entry.
+                */
+               rt2x00dev->ops->lib->init_rxentry(rt2x00dev, entry);
 
                rt2x00queue_index_inc(queue, Q_INDEX);
        }
@@ -156,6 +119,11 @@ void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry,
        enum data_queue_qid qid = skb_get_queue_mapping(entry->skb);
        u32 word;
 
+       /*
+        * Unmap the skb.
+        */
+       rt2x00queue_unmap_skb(rt2x00dev, entry->skb);
+
        rt2x00lib_txdone(entry, txdesc);
 
        /*
@@ -185,33 +153,6 @@ EXPORT_SYMBOL_GPL(rt2x00pci_txdone);
 /*
  * Device initialization handlers.
  */
-#define desc_size(__queue)                     \
-({                                             \
-        ((__queue)->limit * (__queue)->desc_size);\
-})
-
-#define data_size(__queue)                     \
-({                                             \
-        ((__queue)->limit * (__queue)->data_size);\
-})
-
-#define dma_size(__queue)                      \
-({                                             \
-       data_size(__queue) + desc_size(__queue);\
-})
-
-#define desc_offset(__queue, __base, __i)      \
-({                                             \
-       (__base) + data_size(__queue) +         \
-           ((__i) * (__queue)->desc_size);     \
-})
-
-#define data_offset(__queue, __base, __i)      \
-({                                             \
-       (__base) +                              \
-           ((__i) * (__queue)->data_size);     \
-})
-
 static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev,
                                     struct data_queue *queue)
 {
@@ -223,22 +164,21 @@ static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev,
        /*
         * Allocate DMA memory for descriptor and buffer.
         */
-       addr = dma_alloc_coherent(rt2x00dev->dev, dma_size(queue), &dma,
-                                 GFP_KERNEL | GFP_DMA);
+       addr = dma_alloc_coherent(rt2x00dev->dev,
+                                 queue->limit * queue->desc_size,
+                                 &dma, GFP_KERNEL | GFP_DMA);
        if (!addr)
                return -ENOMEM;
 
-       memset(addr, 0, dma_size(queue));
+       memset(addr, 0, queue->limit * queue->desc_size);
 
        /*
         * Initialize all queue entries to contain valid addresses.
         */
        for (i = 0; i < queue->limit; i++) {
                entry_priv = queue->entries[i].priv_data;
-               entry_priv->desc = desc_offset(queue, addr, i);
-               entry_priv->desc_dma = desc_offset(queue, dma, i);
-               entry_priv->data = data_offset(queue, addr, i);
-               entry_priv->data_dma = data_offset(queue, dma, i);
+               entry_priv->desc = addr + i * queue->desc_size;
+               entry_priv->desc_dma = dma + i * queue->desc_size;
        }
 
        return 0;
@@ -250,10 +190,11 @@ static void rt2x00pci_free_queue_dma(struct rt2x00_dev *rt2x00dev,
        struct queue_entry_priv_pci *entry_priv =
            queue->entries[0].priv_data;
 
-       if (entry_priv->data)
-               dma_free_coherent(rt2x00dev->dev, dma_size(queue),
-                                 entry_priv->data, entry_priv->data_dma);
-       entry_priv->data = NULL;
+       if (entry_priv->desc)
+               dma_free_coherent(rt2x00dev->dev,
+                                 queue->limit * queue->desc_size,
+                                 entry_priv->desc, entry_priv->desc_dma);
+       entry_priv->desc = NULL;
 }
 
 int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev)
index 87c4a0cd78db13c6e835d5ec2a23ef9cfcb7f47a..7e5708dca73109bbca12c07c086607bfc5ecfc6b 100644 (file)
@@ -107,9 +107,6 @@ int rt2x00pci_write_tx_data(struct queue_entry *entry);
 struct queue_entry_priv_pci {
        __le32 *desc;
        dma_addr_t desc_dma;
-
-       void *data;
-       dma_addr_t data_dma;
 };
 
 /**
index 278f1a1ac92661a42f7d2cd22f9f0a49f60bbab8..29d2b912853395a132d81e7183cb0068c338f586 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/dma-mapping.h>
 
 #include "rt2x00.h"
 #include "rt2x00lib.h"
 
-struct sk_buff *rt2x00queue_alloc_skb(struct data_queue *queue)
+struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev,
+                                       struct queue_entry *entry)
 {
-       struct sk_buff *skb;
        unsigned int frame_size;
        unsigned int reserved_size;
+       struct sk_buff *skb;
+       struct skb_frame_desc *skbdesc;
 
        /*
         * The frame size includes descriptor size, because the
         * hardware directly receive the frame into the skbuffer.
         */
-       frame_size = queue->data_size + queue->desc_size;
+       frame_size = entry->queue->data_size + entry->queue->desc_size;
 
        /*
         * Reserve a few bytes extra headroom to allow drivers some moving
@@ -57,12 +60,67 @@ struct sk_buff *rt2x00queue_alloc_skb(struct data_queue *queue)
        skb_reserve(skb, reserved_size);
        skb_put(skb, frame_size);
 
+       /*
+        * Populate skbdesc.
+        */
+       skbdesc = get_skb_frame_desc(skb);
+       memset(skbdesc, 0, sizeof(*skbdesc));
+       skbdesc->entry = entry;
+
+       if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags)) {
+               skbdesc->skb_dma = dma_map_single(rt2x00dev->dev,
+                                                 skb->data,
+                                                 skb->len,
+                                                 DMA_FROM_DEVICE);
+               skbdesc->flags |= SKBDESC_DMA_MAPPED_RX;
+       }
+
        return skb;
 }
-EXPORT_SYMBOL_GPL(rt2x00queue_alloc_skb);
+EXPORT_SYMBOL_GPL(rt2x00queue_alloc_rxskb);
 
-void rt2x00queue_free_skb(struct sk_buff *skb)
+void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
 {
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
+
+       skbdesc->skb_dma = dma_map_single(rt2x00dev->dev, skb->data, skb->len,
+                                         DMA_TO_DEVICE);
+       skbdesc->flags |= SKBDESC_DMA_MAPPED_TX;
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb);
+
+void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
+{
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
+
+       if (skbdesc->flags & SKBDESC_DMA_MAPPED_RX) {
+               dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len,
+                                DMA_FROM_DEVICE);
+               skbdesc->flags &= ~SKBDESC_DMA_MAPPED_RX;
+       }
+
+       if (skbdesc->flags & SKBDESC_DMA_MAPPED_TX) {
+               dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len,
+                                DMA_TO_DEVICE);
+               skbdesc->flags &= ~SKBDESC_DMA_MAPPED_TX;
+       }
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_unmap_skb);
+
+void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
+{
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
+
+       if (skbdesc->flags & SKBDESC_DMA_MAPPED_RX) {
+               dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len,
+                                DMA_FROM_DEVICE);
+       }
+
+       if (skbdesc->flags & SKBDESC_DMA_MAPPED_TX) {
+               dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len,
+                                DMA_TO_DEVICE);
+       }
+
        dev_kfree_skb_any(skb);
 }
 EXPORT_SYMBOL_GPL(rt2x00queue_free_skb);
@@ -421,7 +479,8 @@ static int rt2x00queue_alloc_entries(struct data_queue *queue,
        return 0;
 }
 
-static void rt2x00queue_free_skbs(struct data_queue *queue)
+static void rt2x00queue_free_skbs(struct rt2x00_dev *rt2x00dev,
+                                 struct data_queue *queue)
 {
        unsigned int i;
 
@@ -430,27 +489,27 @@ static void rt2x00queue_free_skbs(struct data_queue *queue)
 
        for (i = 0; i < queue->limit; i++) {
                if (queue->entries[i].skb)
-                       rt2x00queue_free_skb(queue->entries[i].skb);
+                       rt2x00queue_free_skb(rt2x00dev, queue->entries[i].skb);
        }
 }
 
-static int rt2x00queue_alloc_skbs(struct data_queue *queue)
+static int rt2x00queue_alloc_rxskbs(struct rt2x00_dev *rt2x00dev,
+                                   struct data_queue *queue)
 {
        unsigned int i;
        struct sk_buff *skb;
 
        for (i = 0; i < queue->limit; i++) {
-               skb = rt2x00queue_alloc_skb(queue);
+               skb = rt2x00queue_alloc_rxskb(rt2x00dev, &queue->entries[i]);
                if (!skb)
                        goto exit;
-
                queue->entries[i].skb = skb;
        }
 
        return 0;
 
 exit:
-       rt2x00queue_free_skbs(queue);
+       rt2x00queue_free_skbs(rt2x00dev, queue);
 
        return -ENOMEM;
 }
@@ -481,7 +540,7 @@ int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev)
                        goto exit;
        }
 
-       status = rt2x00queue_alloc_skbs(rt2x00dev->rx);
+       status = rt2x00queue_alloc_rxskbs(rt2x00dev, rt2x00dev->rx);
        if (status)
                goto exit;
 
@@ -499,7 +558,7 @@ void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev)
 {
        struct data_queue *queue;
 
-       rt2x00queue_free_skbs(rt2x00dev->rx);
+       rt2x00queue_free_skbs(rt2x00dev, rt2x00dev->rx);
 
        queue_for_each(rt2x00dev, queue) {
                kfree(queue->entries);
index fcf52520b016724070e32021776938a3a2f25168..192b6e789a7f2902ac4a515d4041c5e42a4fa415 100644 (file)
@@ -83,9 +83,10 @@ enum data_queue_qid {
  * enum skb_frame_desc_flags: Flags for &struct skb_frame_desc
  *
  */
-//enum skb_frame_desc_flags {
-//     TEMPORARILY EMPTY
-//};
+enum skb_frame_desc_flags {
+       SKBDESC_DMA_MAPPED_RX = (1 << 0),
+       SKBDESC_DMA_MAPPED_TX = (1 << 1),
+};
 
 /**
  * struct skb_frame_desc: Descriptor information for the skb buffer
@@ -94,19 +95,20 @@ enum data_queue_qid {
  * this structure should not exceed the size of that array (40 bytes).
  *
  * @flags: Frame flags, see &enum skb_frame_desc_flags.
- * @data: Pointer to data part of frame (Start of ieee80211 header).
+ * @desc_len: Length of the frame descriptor.
  * @desc: Pointer to descriptor part of the frame.
  *     Note that this pointer could point to something outside
  *     of the scope of the skb->data pointer.
- * @data_len: Length of the frame data.
- * @desc_len: Length of the frame descriptor.
+ * @skb_dma: (PCI-only) the DMA address associated with the sk buffer.
  * @entry: The entry to which this sk buffer belongs.
  */
 struct skb_frame_desc {
        unsigned int flags;
 
-       void *desc;
        unsigned int desc_len;
+       void *desc;
+
+       dma_addr_t skb_dma;
 
        struct queue_entry *entry;
 };
index 29dba86c8cf03df439cb36448b7f44c1a24a7538..552f0e94f800d321eeff96ae54bbdc4229ea43ab 100644 (file)
@@ -266,9 +266,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
 {
        struct queue_entry *entry = (struct queue_entry *)urb->context;
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-       struct sk_buff *skb;
-       struct skb_frame_desc *skbdesc;
-       struct rxdone_entry_desc rxdesc;
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
        u8 rxd[32];
 
        if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
@@ -284,36 +282,19 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
                goto skip_entry;
 
        /*
-        * Fill in skb descriptor
+        * Fill in desc fields of the skb descriptor
         */
-       skbdesc = get_skb_frame_desc(entry->skb);
-       memset(skbdesc, 0, sizeof(*skbdesc));
-       skbdesc->entry = entry;
        skbdesc->desc = rxd;
        skbdesc->desc_len = entry->queue->desc_size;
 
-       memset(&rxdesc, 0, sizeof(rxdesc));
-       rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc);
-
-       /*
-        * Allocate a new sk buffer to replace the current one.
-        * If allocation fails, we should drop the current frame
-        * so we can recycle the existing sk buffer for the new frame.
-        */
-       skb = rt2x00queue_alloc_skb(entry->queue);
-       if (!skb)
-               goto skip_entry;
-
        /*
         * Send the frame to rt2x00lib for further processing.
         */
-       rt2x00lib_rxdone(entry, &rxdesc);
+       rt2x00lib_rxdone(rt2x00dev, entry);
 
        /*
-        * Replace current entry's skb with the newly allocated one,
-        * and reinitialize the urb.
+        * Reinitialize the urb.
         */
-       entry->skb = skb;
        urb->transfer_buffer = entry->skb->data;
        urb->transfer_buffer_length = entry->skb->len;
 
index 2a7f3062035626648667af2f74aea05e53ef512a..c9f6d484413955ed854c52e99572671413a018d9 100644 (file)
@@ -1030,11 +1030,12 @@ static void rt61pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
                                 struct queue_entry *entry)
 {
        struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
        u32 word;
 
        rt2x00_desc_read(entry_priv->desc, 5, &word);
        rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS,
-                          entry_priv->data_dma);
+                          skbdesc->skb_dma);
        rt2x00_desc_write(entry_priv->desc, 5, word);
 
        rt2x00_desc_read(entry_priv->desc, 0, &word);
@@ -1522,7 +1523,6 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                                    struct txentry_desc *txdesc)
 {
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
        __le32 *txd = skbdesc->desc;
        u32 word;
 
@@ -1557,7 +1557,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 
        rt2x00_desc_read(txd, 6, &word);
        rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS,
-                          entry_priv->data_dma);
+                          skbdesc->skb_dma);
        rt2x00_desc_write(txd, 6, word);
 
        if (skbdesc->desc_len > TXINFO_SIZE) {
@@ -2302,9 +2302,10 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
        rt61pci_probe_hw_mode(rt2x00dev);
 
        /*
-        * This device requires firmware.
+        * This device requires firmware and DMA mapped skbs.
         */
        __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
+       __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
 
        /*
         * Set the rssi offset.