summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rt2x00/rt2x00pci.c
diff options
context:
space:
mode:
authorIvo van Doorn <ivdoorn@gmail.com>2008-02-10 22:46:52 +0100
committerJohn W. Linville <linville@tuxdriver.com>2008-02-29 21:37:17 +0100
commit9c9dd2c9a42e8eb38b67f6c743c3d214664b8e2b (patch)
treee1cd6cb9afb57c7e15c66cd9f11ec6627e5e281b /drivers/net/wireless/rt2x00/rt2x00pci.c
parentwireless: rt2x00: fix driver menu indenting (diff)
downloadlinux-9c9dd2c9a42e8eb38b67f6c743c3d214664b8e2b.tar.xz
linux-9c9dd2c9a42e8eb38b67f6c743c3d214664b8e2b.zip
rt2x00: Fix invalid DMA free
Be more strict when using the queue_entry_priv_pci_rx and queue_entry_priv_pci_tx structures. Only use a particular type that matches the queue type. When freeing the DMA the priv_tx->data and priv_tx->dma was used. This is incorrect since the start of the DMA was in fact the priv_tx->desc pointer. Instead of recalculating the dma_addr_t for the DMA start this patch will swap the data and descriptor part of the allocated memory. Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2x00pci.c')
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.c85
1 files changed, 60 insertions, 25 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index 275c8a1e6638..238f1c1e4ad0 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -186,38 +186,44 @@ EXPORT_SYMBOL_GPL(rt2x00pci_txdone);
/*
* Device initialization handlers.
*/
-#define dma_size(__queue) \
-({ \
- (__queue)->limit * \
- ((__queue)->desc_size + (__queue)->data_size);\
+#define desc_size(__queue) \
+({ \
+ ((__queue)->limit * (__queue)->desc_size);\
})
-#define priv_offset(__queue, __base, __i) \
-({ \
- (__base) + ((__i) * (__queue)->desc_size); \
+#define data_size(__queue) \
+({ \
+ ((__queue)->limit * (__queue)->data_size);\
})
-#define data_addr_offset(__queue, __base, __i) \
-({ \
- (__base) + \
- ((__queue)->limit * (__queue)->desc_size) + \
- ((__i) * (__queue)->data_size); \
+#define dma_size(__queue) \
+({ \
+ data_size(__queue) + desc_size(__queue);\
})
-#define data_dma_offset(__queue, __base, __i) \
-({ \
- (__base) + \
- ((__queue)->limit * (__queue)->desc_size) + \
- ((__i) * (__queue)->data_size); \
+#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)
{
struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
+ struct queue_entry_priv_pci_rx *priv_rx;
struct queue_entry_priv_pci_tx *priv_tx;
+ void *desc;
void *data_addr;
+ void *data;
dma_addr_t data_dma;
+ dma_addr_t dma;
unsigned int i;
/*
@@ -227,14 +233,27 @@ static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev,
if (!data_addr)
return -ENOMEM;
+ memset(data_addr, 0, dma_size(queue));
+
/*
* Initialize all queue entries to contain valid addresses.
*/
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);
+ desc = desc_offset(queue, data_addr, i);
+ data = data_offset(queue, data_addr, i);
+ dma = data_offset(queue, data_dma, i);
+
+ if (queue->qid == QID_RX) {
+ priv_rx = queue->entries[i].priv_data;
+ priv_rx->desc = desc;
+ priv_rx->data = data;
+ priv_rx->dma = dma;
+ } else {
+ priv_tx = queue->entries[i].priv_data;
+ priv_tx->desc = desc;
+ priv_tx->data = data;
+ priv_tx->dma = dma;
+ }
}
return 0;
@@ -244,12 +263,28 @@ static void rt2x00pci_free_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 = queue->entries[0].priv_data;
+ struct queue_entry_priv_pci_rx *priv_rx;
+ struct queue_entry_priv_pci_tx *priv_tx;
+ void *data_addr;
+ dma_addr_t data_dma;
+
+ if (queue->qid == QID_RX) {
+ priv_rx = queue->entries[0].priv_data;
+ data_addr = priv_rx->data;
+ data_dma = priv_rx->dma;
+
+ priv_rx->data = NULL;
+ } else {
+ priv_tx = queue->entries[0].priv_data;
+ data_addr = priv_tx->data;
+ data_dma = priv_tx->dma;
+
+ priv_tx->data = NULL;
+ }
- if (priv_tx->data)
+ if (data_addr)
pci_free_consistent(pci_dev, dma_size(queue),
- priv_tx->data, priv_tx->dma);
- priv_tx->data = NULL;
+ data_addr, data_dma);
}
int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev)