aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rt2x00/rt2x00pci.c
diff options
context:
space:
mode:
authorIvo van Doorn <ivdoorn@gmail.com>2008-02-10 16:46:52 -0500
committerJohn W. Linville <linville@tuxdriver.com>2008-02-29 15:37:17 -0500
commit9c9dd2c9a42e8eb38b67f6c743c3d214664b8e2b (patch)
treee1cd6cb9afb57c7e15c66cd9f11ec6627e5e281b /drivers/net/wireless/rt2x00/rt2x00pci.c
parent0d84d78db5bad848e385cbb1e4ae2ea1f5f27641 (diff)
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);
186/* 186/*
187 * Device initialization handlers. 187 * Device initialization handlers.
188 */ 188 */
189#define dma_size(__queue) \ 189#define desc_size(__queue) \
190({ \ 190({ \
191 (__queue)->limit * \ 191 ((__queue)->limit * (__queue)->desc_size);\
192 ((__queue)->desc_size + (__queue)->data_size);\
193}) 192})
194 193
195#define priv_offset(__queue, __base, __i) \ 194#define data_size(__queue) \
196({ \ 195({ \
197 (__base) + ((__i) * (__queue)->desc_size); \ 196 ((__queue)->limit * (__queue)->data_size);\
198}) 197})
199 198
200#define data_addr_offset(__queue, __base, __i) \ 199#define dma_size(__queue) \
201({ \ 200({ \
202 (__base) + \ 201 data_size(__queue) + desc_size(__queue);\
203 ((__queue)->limit * (__queue)->desc_size) + \
204 ((__i) * (__queue)->data_size); \
205}) 202})
206 203
207#define data_dma_offset(__queue, __base, __i) \ 204#define desc_offset(__queue, __base, __i) \
208({ \ 205({ \
209 (__base) + \ 206 (__base) + data_size(__queue) + \
210 ((__queue)->limit * (__queue)->desc_size) + \ 207 ((__i) * (__queue)->desc_size); \
211 ((__i) * (__queue)->data_size); \ 208})
209
210#define data_offset(__queue, __base, __i) \
211({ \
212 (__base) + \
213 ((__i) * (__queue)->data_size); \
212}) 214})
213 215
214static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev, 216static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev,
215 struct data_queue *queue) 217 struct data_queue *queue)
216{ 218{
217 struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev); 219 struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
220 struct queue_entry_priv_pci_rx *priv_rx;
218 struct queue_entry_priv_pci_tx *priv_tx; 221 struct queue_entry_priv_pci_tx *priv_tx;
222 void *desc;
219 void *data_addr; 223 void *data_addr;
224 void *data;
220 dma_addr_t data_dma; 225 dma_addr_t data_dma;
226 dma_addr_t dma;
221 unsigned int i; 227 unsigned int i;
222 228
223 /* 229 /*
@@ -227,14 +233,27 @@ static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev,
227 if (!data_addr) 233 if (!data_addr)
228 return -ENOMEM; 234 return -ENOMEM;
229 235
236 memset(data_addr, 0, dma_size(queue));
237
230 /* 238 /*
231 * Initialize all queue entries to contain valid addresses. 239 * Initialize all queue entries to contain valid addresses.
232 */ 240 */
233 for (i = 0; i < queue->limit; i++) { 241 for (i = 0; i < queue->limit; i++) {
234 priv_tx = queue->entries[i].priv_data; 242 desc = desc_offset(queue, data_addr, i);
235 priv_tx->desc = priv_offset(queue, data_addr, i); 243 data = data_offset(queue, data_addr, i);
236 priv_tx->data = data_addr_offset(queue, data_addr, i); 244 dma = data_offset(queue, data_dma, i);
237 priv_tx->dma = data_dma_offset(queue, data_dma, i); 245
246 if (queue->qid == QID_RX) {
247 priv_rx = queue->entries[i].priv_data;
248 priv_rx->desc = desc;
249 priv_rx->data = data;
250 priv_rx->dma = dma;
251 } else {
252 priv_tx = queue->entries[i].priv_data;
253 priv_tx->desc = desc;
254 priv_tx->data = data;
255 priv_tx->dma = dma;
256 }
238 } 257 }
239 258
240 return 0; 259 return 0;
@@ -244,12 +263,28 @@ static void rt2x00pci_free_queue_dma(struct rt2x00_dev *rt2x00dev,
244 struct data_queue *queue) 263 struct data_queue *queue)
245{ 264{
246 struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev); 265 struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
247 struct queue_entry_priv_pci_tx *priv_tx = queue->entries[0].priv_data; 266 struct queue_entry_priv_pci_rx *priv_rx;
267 struct queue_entry_priv_pci_tx *priv_tx;
268 void *data_addr;
269 dma_addr_t data_dma;
270
271 if (queue->qid == QID_RX) {
272 priv_rx = queue->entries[0].priv_data;
273 data_addr = priv_rx->data;
274 data_dma = priv_rx->dma;
275
276 priv_rx->data = NULL;
277 } else {
278 priv_tx = queue->entries[0].priv_data;
279 data_addr = priv_tx->data;
280 data_dma = priv_tx->dma;
281
282 priv_tx->data = NULL;
283 }
248 284
249 if (priv_tx->data) 285 if (data_addr)
250 pci_free_consistent(pci_dev, dma_size(queue), 286 pci_free_consistent(pci_dev, dma_size(queue),
251 priv_tx->data, priv_tx->dma); 287 data_addr, data_dma);
252 priv_tx->data = NULL;
253} 288}
254 289
255int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev) 290int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev)