aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorIvo van Doorn <ivdoorn@gmail.com>2010-08-30 15:15:51 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-08-31 14:22:25 -0400
commitcd35a3912188d006f251fff1028d84e1d1649ca2 (patch)
treeb7b919047ae7e155c3601bce453cd3a235a7baff /drivers/net/wireless
parent652a9dd2a0c07251e328519cc23f1316ab13ed51 (diff)
rt2x00: Cleanup rt2x00usb_watchdog_reset_tx
rt2x00usb_watchdog_reset_tx performs the same task as rt2x00usb_kill_tx_queue, with the only difference is that it waits for all entries to be returned to the driver and for all frames the status has been reported to mac80211. We can easily split this task by calling rt2x00usb_kill_tx_queue, sleep for a short period and invoke the TX status reporting function. By adding the sleep() to the kill_entry we make sure that even during shutdown we guarentee the entry has been killed when the function returns. To make this work correctly the interrupt handlers have to be updated to prevent checking for the RADIO_ENABLED flag too early which prevents the ownership of the entry to be reset. Additionally a check for the DEVICE_PRESENT flag is not required but is nice to prevent race conditions when the device was unplugged. Additionally rather then calling rt2x00usb_work_txdone() for status reporting we let the driver perform the TX status reporting first. If this is not sufficient then rt2x00usb_work_txdone() will still be used to cleanup the mess. Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com> Acked-by: Gertjan van Wingerde <gwingerde@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.c66
1 files changed, 40 insertions, 26 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index aec6440d364a..4c5ae3d45625 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -208,8 +208,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
208 struct queue_entry *entry = (struct queue_entry *)urb->context; 208 struct queue_entry *entry = (struct queue_entry *)urb->context;
209 struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; 209 struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
210 210
211 if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) || 211 if (!__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
212 !__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
213 return; 212 return;
214 213
215 /* 214 /*
@@ -227,7 +226,9 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
227 * Schedule the delayed work for reading the TX status 226 * Schedule the delayed work for reading the TX status
228 * from the device. 227 * from the device.
229 */ 228 */
230 ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->txdone_work); 229 if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
230 test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
231 ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->txdone_work);
231} 232}
232 233
233static void rt2x00usb_kick_tx_entry(struct queue_entry *entry) 234static void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
@@ -279,6 +280,14 @@ static void rt2x00usb_kill_tx_entry(struct queue_entry *entry)
279 if ((entry->queue->qid == QID_BEACON) && 280 if ((entry->queue->qid == QID_BEACON) &&
280 (test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags))) 281 (test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags)))
281 usb_kill_urb(bcn_priv->guardian_urb); 282 usb_kill_urb(bcn_priv->guardian_urb);
283
284 /*
285 * We need a short delay here to wait for
286 * the URB to be canceled
287 */
288 do {
289 udelay(100);
290 } while (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags));
282} 291}
283 292
284void rt2x00usb_kill_tx_queue(struct data_queue *queue) 293void rt2x00usb_kill_tx_queue(struct data_queue *queue)
@@ -290,8 +299,7 @@ EXPORT_SYMBOL_GPL(rt2x00usb_kill_tx_queue);
290 299
291static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue) 300static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue)
292{ 301{
293 struct queue_entry *entry; 302 struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
294 struct queue_entry_priv_usb *entry_priv;
295 unsigned short threshold = queue->threshold; 303 unsigned short threshold = queue->threshold;
296 304
297 WARNING(queue->rt2x00dev, "TX queue %d DMA timed out," 305 WARNING(queue->rt2x00dev, "TX queue %d DMA timed out,"
@@ -305,28 +313,33 @@ static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue)
305 * queue from being enabled during the txdone handler. 313 * queue from being enabled during the txdone handler.
306 */ 314 */
307 queue->threshold = queue->limit; 315 queue->threshold = queue->limit;
308 ieee80211_stop_queue(queue->rt2x00dev->hw, queue->qid); 316 ieee80211_stop_queue(rt2x00dev->hw, queue->qid);
309 317
310 /* 318 /*
311 * Reset all currently uploaded TX frames. 319 * Kill all entries in the queue, afterwards we need to
320 * wait a bit for all URBs to be cancelled.
312 */ 321 */
313 while (!rt2x00queue_empty(queue)) { 322 rt2x00usb_kill_tx_queue(queue);
314 entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
315 entry_priv = entry->priv_data;
316 usb_kill_urb(entry_priv->urb);
317 323
318 /* 324 /*
319 * We need a short delay here to wait for 325 * In case that a driver has overriden the txdone_work
320 * the URB to be canceled 326 * function, we invoke the TX done through there.
321 */ 327 */
322 do { 328 rt2x00dev->txdone_work.func(&rt2x00dev->txdone_work);
323 udelay(100);
324 } while (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags));
325 329
326 /* 330 /*
327 * Invoke the TX done handler 331 * Security measure: if the driver did override the
328 */ 332 * txdone_work function, and the hardware did arrive
329 rt2x00usb_work_txdone_entry(entry); 333 * in a state which causes it to malfunction, it is
334 * possible that the driver couldn't handle the txdone
335 * event correctly. So after giving the driver the
336 * chance to cleanup, we now force a cleanup of any
337 * leftovers.
338 */
339 if (!rt2x00queue_empty(queue)) {
340 WARNING(queue->rt2x00dev, "TX queue %d DMA timed out,"
341 " status handling failed, invoke hard reset", queue->qid);
342 rt2x00usb_work_txdone(&rt2x00dev->txdone_work);
330 } 343 }
331 344
332 /* 345 /*
@@ -334,7 +347,7 @@ static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue)
334 * queue again. 347 * queue again.
335 */ 348 */
336 queue->threshold = threshold; 349 queue->threshold = threshold;
337 ieee80211_wake_queue(queue->rt2x00dev->hw, queue->qid); 350 ieee80211_wake_queue(rt2x00dev->hw, queue->qid);
338} 351}
339 352
340static void rt2x00usb_watchdog_tx_status(struct data_queue *queue) 353static void rt2x00usb_watchdog_tx_status(struct data_queue *queue)
@@ -394,8 +407,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
394 struct queue_entry *entry = (struct queue_entry *)urb->context; 407 struct queue_entry *entry = (struct queue_entry *)urb->context;
395 struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; 408 struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
396 409
397 if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) || 410 if (!__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
398 !__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
399 return; 411 return;
400 412
401 /* 413 /*
@@ -415,7 +427,9 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
415 * Schedule the delayed work for reading the RX status 427 * Schedule the delayed work for reading the RX status
416 * from the device. 428 * from the device.
417 */ 429 */
418 ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->rxdone_work); 430 if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
431 test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
432 ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->rxdone_work);
419} 433}
420 434
421/* 435/*