| From e2288b66fe7ff0288382b2af671b4da558b44472 Mon Sep 17 00:00:00 2001 |
| From: Stanislaw Gruszka <stf_xl@wp.pl> |
| Date: Sun, 28 Jul 2013 13:17:22 +0200 |
| Subject: rt2x00: fix stop queue |
| |
| From: Stanislaw Gruszka <stf_xl@wp.pl> |
| |
| commit e2288b66fe7ff0288382b2af671b4da558b44472 upstream. |
| |
| Since we clear QUEUE_STARTED in rt2x00queue_stop_queue(), following |
| call to rt2x00queue_pause_queue() reduce to noop, i.e we do not |
| stop queue in mac80211. |
| |
| To fix that introduce rt2x00queue_pause_queue_nocheck() function, |
| which will stop queue in mac80211 directly. |
| |
| Note that rt2x00_start_queue() explicitly set QUEUE_PAUSED bit. |
| |
| Note also that reordering operations i.e. first call to |
| rt2x00queue_pause_queue() and then clear QUEUE_STARTED bit, will race |
| with rt2x00queue_unpause_queue(), so calling ieee80211_stop_queue() |
| directly is the only available solution to fix the problem without |
| major rework. |
| |
| Signed-off-by: Stanislaw Gruszka <stf_xl@wp.pl> |
| Signed-off-by: John W. Linville <linville@tuxdriver.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/net/wireless/rt2x00/rt2x00queue.c | 18 +++++++++++------- |
| 1 file changed, 11 insertions(+), 7 deletions(-) |
| |
| --- a/drivers/net/wireless/rt2x00/rt2x00queue.c |
| +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c |
| @@ -848,13 +848,8 @@ void rt2x00queue_index_inc(struct queue_ |
| spin_unlock_irqrestore(&queue->index_lock, irqflags); |
| } |
| |
| -void rt2x00queue_pause_queue(struct data_queue *queue) |
| +void rt2x00queue_pause_queue_nocheck(struct data_queue *queue) |
| { |
| - if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) || |
| - !test_bit(QUEUE_STARTED, &queue->flags) || |
| - test_and_set_bit(QUEUE_PAUSED, &queue->flags)) |
| - return; |
| - |
| switch (queue->qid) { |
| case QID_AC_VO: |
| case QID_AC_VI: |
| @@ -870,6 +865,15 @@ void rt2x00queue_pause_queue(struct data |
| break; |
| } |
| } |
| +void rt2x00queue_pause_queue(struct data_queue *queue) |
| +{ |
| + if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) || |
| + !test_bit(QUEUE_STARTED, &queue->flags) || |
| + test_and_set_bit(QUEUE_PAUSED, &queue->flags)) |
| + return; |
| + |
| + rt2x00queue_pause_queue_nocheck(queue); |
| +} |
| EXPORT_SYMBOL_GPL(rt2x00queue_pause_queue); |
| |
| void rt2x00queue_unpause_queue(struct data_queue *queue) |
| @@ -931,7 +935,7 @@ void rt2x00queue_stop_queue(struct data_ |
| return; |
| } |
| |
| - rt2x00queue_pause_queue(queue); |
| + rt2x00queue_pause_queue_nocheck(queue); |
| |
| queue->rt2x00dev->ops->lib->stop_queue(queue); |
| |