diff options
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00usb.c | 66 |
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 | ||
233 | static void rt2x00usb_kick_tx_entry(struct queue_entry *entry) | 234 | static 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 | ||
284 | void rt2x00usb_kill_tx_queue(struct data_queue *queue) | 293 | void rt2x00usb_kill_tx_queue(struct data_queue *queue) |
@@ -290,8 +299,7 @@ EXPORT_SYMBOL_GPL(rt2x00usb_kill_tx_queue); | |||
290 | 299 | ||
291 | static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue) | 300 | static 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 | ||
340 | static void rt2x00usb_watchdog_tx_status(struct data_queue *queue) | 353 | static 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 | /* |