diff options
author | Stanislaw Gruszka <stf_xl@wp.pl> | 2013-07-28 07:17:22 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-07-29 14:39:44 -0400 |
commit | e2288b66fe7ff0288382b2af671b4da558b44472 (patch) | |
tree | d26d1e38df570e92077f849ada809d2dfce79c19 | |
parent | a538ae3189a9fa4095ca58c14bc6593622c89ab9 (diff) |
rt2x00: fix stop queue
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.
Cc: stable@vger.kernel.org
Signed-off-by: Stanislaw Gruszka <stf_xl@wp.pl>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00queue.c | 18 |
1 files changed, 11 insertions, 7 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 6c0a91ff963c..aa95c6cf3545 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c | |||
@@ -936,13 +936,8 @@ void rt2x00queue_index_inc(struct queue_entry *entry, enum queue_index index) | |||
936 | spin_unlock_irqrestore(&queue->index_lock, irqflags); | 936 | spin_unlock_irqrestore(&queue->index_lock, irqflags); |
937 | } | 937 | } |
938 | 938 | ||
939 | void rt2x00queue_pause_queue(struct data_queue *queue) | 939 | void rt2x00queue_pause_queue_nocheck(struct data_queue *queue) |
940 | { | 940 | { |
941 | if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) || | ||
942 | !test_bit(QUEUE_STARTED, &queue->flags) || | ||
943 | test_and_set_bit(QUEUE_PAUSED, &queue->flags)) | ||
944 | return; | ||
945 | |||
946 | switch (queue->qid) { | 941 | switch (queue->qid) { |
947 | case QID_AC_VO: | 942 | case QID_AC_VO: |
948 | case QID_AC_VI: | 943 | case QID_AC_VI: |
@@ -958,6 +953,15 @@ void rt2x00queue_pause_queue(struct data_queue *queue) | |||
958 | break; | 953 | break; |
959 | } | 954 | } |
960 | } | 955 | } |
956 | void rt2x00queue_pause_queue(struct data_queue *queue) | ||
957 | { | ||
958 | if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) || | ||
959 | !test_bit(QUEUE_STARTED, &queue->flags) || | ||
960 | test_and_set_bit(QUEUE_PAUSED, &queue->flags)) | ||
961 | return; | ||
962 | |||
963 | rt2x00queue_pause_queue_nocheck(queue); | ||
964 | } | ||
961 | EXPORT_SYMBOL_GPL(rt2x00queue_pause_queue); | 965 | EXPORT_SYMBOL_GPL(rt2x00queue_pause_queue); |
962 | 966 | ||
963 | void rt2x00queue_unpause_queue(struct data_queue *queue) | 967 | void rt2x00queue_unpause_queue(struct data_queue *queue) |
@@ -1019,7 +1023,7 @@ void rt2x00queue_stop_queue(struct data_queue *queue) | |||
1019 | return; | 1023 | return; |
1020 | } | 1024 | } |
1021 | 1025 | ||
1022 | rt2x00queue_pause_queue(queue); | 1026 | rt2x00queue_pause_queue_nocheck(queue); |
1023 | 1027 | ||
1024 | queue->rt2x00dev->ops->lib->stop_queue(queue); | 1028 | queue->rt2x00dev->ops->lib->stop_queue(queue); |
1025 | 1029 | ||