aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/wl1251
diff options
context:
space:
mode:
authorDavid Gnedt <david.gnedt@davizone.at>2011-01-30 14:10:46 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-02-03 16:42:44 -0500
commite7332a41442bde1c14550998cadceca34c967dfc (patch)
treeaa5902ac620f2fbab7d98bbdda079959b97f5bc5 /drivers/net/wireless/wl1251
parent172710bf8305c1b145796e34426c865480884024 (diff)
wl1251: fix queue stopping/waking for TX path
The queue stopping/waking functionality was broken in a way that could cause the TX to stall if the right circumstances are met. The problem was caused by tx_work, which is scheduled on each TX operation. If the firmware buffer is full, tx_work does nothing. In combinition with stopped queues or non-continues transfers, tx_work is never scheduled again. Moreover the low watermark introduced by 9df86e2e702c6d5547aced7f241addd2d698bb11 never takes effect because of some old code. Solve this by scheduling tx_work every time tx_queue is non-empty and firmware buffer is freed on tx_complete. This also solves a possible but unlikely case: If less frames than the high watermark are queued, but more than firmware buffer can hold. This results in queues staying awake but the only scheduled tx_work doesn't transfer all frames, so the remaining frames are stuck in the queue until more frames get queued and tx_work is scheduled again. Signed-off-by: David Gnedt <david.gnedt@davizone.at> Acked-by: Kalle Valo <kvalo@adurom.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/wl1251')
-rw-r--r--drivers/net/wireless/wl1251/tx.c48
1 files changed, 12 insertions, 36 deletions
diff --git a/drivers/net/wireless/wl1251/tx.c b/drivers/net/wireless/wl1251/tx.c
index 554b4f9a3d3e..10112de55493 100644
--- a/drivers/net/wireless/wl1251/tx.c
+++ b/drivers/net/wireless/wl1251/tx.c
@@ -368,7 +368,7 @@ static void wl1251_tx_packet_cb(struct wl1251 *wl,
368{ 368{
369 struct ieee80211_tx_info *info; 369 struct ieee80211_tx_info *info;
370 struct sk_buff *skb; 370 struct sk_buff *skb;
371 int hdrlen, ret; 371 int hdrlen;
372 u8 *frame; 372 u8 *frame;
373 373
374 skb = wl->tx_frames[result->id]; 374 skb = wl->tx_frames[result->id];
@@ -407,40 +407,12 @@ static void wl1251_tx_packet_cb(struct wl1251 *wl,
407 ieee80211_tx_status(wl->hw, skb); 407 ieee80211_tx_status(wl->hw, skb);
408 408
409 wl->tx_frames[result->id] = NULL; 409 wl->tx_frames[result->id] = NULL;
410
411 if (wl->tx_queue_stopped) {
412 wl1251_debug(DEBUG_TX, "cb: queue was stopped");
413
414 skb = skb_dequeue(&wl->tx_queue);
415
416 /* The skb can be NULL because tx_work might have been
417 scheduled before the queue was stopped making the
418 queue empty */
419
420 if (skb) {
421 ret = wl1251_tx_frame(wl, skb);
422 if (ret == -EBUSY) {
423 /* firmware buffer is still full */
424 wl1251_debug(DEBUG_TX, "cb: fw buffer "
425 "still full");
426 skb_queue_head(&wl->tx_queue, skb);
427 return;
428 } else if (ret < 0) {
429 dev_kfree_skb(skb);
430 return;
431 }
432 }
433
434 wl1251_debug(DEBUG_TX, "cb: waking queues");
435 ieee80211_wake_queues(wl->hw);
436 wl->tx_queue_stopped = false;
437 }
438} 410}
439 411
440/* Called upon reception of a TX complete interrupt */ 412/* Called upon reception of a TX complete interrupt */
441void wl1251_tx_complete(struct wl1251 *wl) 413void wl1251_tx_complete(struct wl1251 *wl)
442{ 414{
443 int i, result_index, num_complete = 0; 415 int i, result_index, num_complete = 0, queue_len;
444 struct tx_result result[FW_TX_CMPLT_BLOCK_SIZE], *result_ptr; 416 struct tx_result result[FW_TX_CMPLT_BLOCK_SIZE], *result_ptr;
445 unsigned long flags; 417 unsigned long flags;
446 418
@@ -471,18 +443,22 @@ void wl1251_tx_complete(struct wl1251 *wl)
471 } 443 }
472 } 444 }
473 445
474 if (wl->tx_queue_stopped 446 queue_len = skb_queue_len(&wl->tx_queue);
475 &&
476 skb_queue_len(&wl->tx_queue) <= WL1251_TX_QUEUE_LOW_WATERMARK){
477 447
478 /* firmware buffer has space, restart queues */ 448 if ((num_complete > 0) && (queue_len > 0)) {
449 /* firmware buffer has space, reschedule tx_work */
450 wl1251_debug(DEBUG_TX, "tx_complete: reschedule tx_work");
451 ieee80211_queue_work(wl->hw, &wl->tx_work);
452 }
453
454 if (wl->tx_queue_stopped &&
455 queue_len <= WL1251_TX_QUEUE_LOW_WATERMARK) {
456 /* tx_queue has space, restart queues */
479 wl1251_debug(DEBUG_TX, "tx_complete: waking queues"); 457 wl1251_debug(DEBUG_TX, "tx_complete: waking queues");
480 spin_lock_irqsave(&wl->wl_lock, flags); 458 spin_lock_irqsave(&wl->wl_lock, flags);
481 ieee80211_wake_queues(wl->hw); 459 ieee80211_wake_queues(wl->hw);
482 wl->tx_queue_stopped = false; 460 wl->tx_queue_stopped = false;
483 spin_unlock_irqrestore(&wl->wl_lock, flags); 461 spin_unlock_irqrestore(&wl->wl_lock, flags);
484 ieee80211_queue_work(wl->hw, &wl->tx_work);
485
486 } 462 }
487 463
488 /* Every completed frame needs to be acknowledged */ 464 /* Every completed frame needs to be acknowledged */