diff options
author | Ivo van Doorn <ivdoorn@gmail.com> | 2008-02-10 16:46:52 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-02-29 15:37:17 -0500 |
commit | 9c9dd2c9a42e8eb38b67f6c743c3d214664b8e2b (patch) | |
tree | e1cd6cb9afb57c7e15c66cd9f11ec6627e5e281b /drivers/net/wireless/rt2x00/rt2x00pci.c | |
parent | 0d84d78db5bad848e385cbb1e4ae2ea1f5f27641 (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.c | 85 |
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 | ||
214 | static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev, | 216 | static 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 | ||
255 | int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev) | 290 | int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev) |