aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGertjan van Wingerde <gwingerde@kpnplanet.nl>2008-06-16 19:56:31 +0200
committerJohn W. Linville <linville@tuxdriver.com>2008-06-26 16:49:16 -0400
commitc4da004857056e6ee034c4110ccdcba659077b7e (patch)
tree641f8d9ddab7b8b6ba41fefc57a517abce15e8e6
parent30caa6e3d586442f7c3ad081260ee1b22bb123de (diff)
rt2x00: Replace statically allocated DMA buffers with mapped skb's.
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>
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c13
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c10
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h28
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c64
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.c125
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.h3
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.c85
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.h16
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.c27
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c9
10 files changed, 204 insertions, 176 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 76ec1514fa4..de2dd336f23 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -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);
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 5f0117f9a88..5077b62dcc5 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -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);
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 08e8b0a005a..28c9026bb56 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -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.
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index b8e0c4c3ed0..99b14ba99d9 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -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);
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index e7e3a459b66..f9d0d76f870 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -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)
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h
index 87c4a0cd78d..7e5708dca73 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.h
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.h
@@ -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;
};
/**
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 278f1a1ac92..29d2b912853 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -25,21 +25,24 @@
#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);
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index fcf52520b01..192b6e789a7 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -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;
};
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index 29dba86c8cf..552f0e94f80 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -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;
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 2a7f3062035..c9f6d484413 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -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.