aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorArik Nemtsov <arik@wizery.com>2011-07-07 07:25:23 -0400
committerLuciano Coelho <coelho@ti.com>2011-07-08 02:39:47 -0400
commitf1a46384ad568f72c11edbe2a3ec284bf32f2dbd (patch)
tree2d303dfdcbf970db11aa858b1a02fb7d29ef4d4f /drivers/net
parent097f882153f0ec13617074fa3bdb683b8215e20c (diff)
wl12xx: start/stop queues according to global per-AC counters
Split tx_queue_count to count per-AC skb's queued, instead of relying on the skb-queue len. The skb queues used were only valid in STA-mode, as AP-mode uses per-link queues. This fixes a major regression in AP-mode, caused by the patch "wl12xx: implement Tx watermarks per AC". With that patch applied, we effectively had no regulation of Tx queues in AP-mode. Therefore a sustained high rate of Tx could cause exhaustion of the skb memory pool. Signed-off-by: Arik Nemtsov <arik@wizery.com> Signed-off-by: Luciano Coelho <coelho@ti.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/wl12xx/debugfs.c8
-rw-r--r--drivers/net/wireless/wl12xx/main.c13
-rw-r--r--drivers/net/wireless/wl12xx/ps.c9
-rw-r--r--drivers/net/wireless/wl12xx/tx.c33
-rw-r--r--drivers/net/wireless/wl12xx/tx.h10
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx.h2
6 files changed, 51 insertions, 24 deletions
diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c
index 4d9c8cc076ec..37934b5601cd 100644
--- a/drivers/net/wireless/wl12xx/debugfs.c
+++ b/drivers/net/wireless/wl12xx/debugfs.c
@@ -30,6 +30,7 @@
30#include "acx.h" 30#include "acx.h"
31#include "ps.h" 31#include "ps.h"
32#include "io.h" 32#include "io.h"
33#include "tx.h"
33 34
34/* ms */ 35/* ms */
35#define WL1271_DEBUGFS_STATS_LIFETIME 1000 36#define WL1271_DEBUGFS_STATS_LIFETIME 1000
@@ -233,7 +234,7 @@ static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf,
233 char buf[20]; 234 char buf[20];
234 int res; 235 int res;
235 236
236 queue_len = wl->tx_queue_count; 237 queue_len = wl1271_tx_total_queue_count(wl);
237 238
238 res = scnprintf(buf, sizeof(buf), "%u\n", queue_len); 239 res = scnprintf(buf, sizeof(buf), "%u\n", queue_len);
239 return simple_read_from_buffer(userbuf, count, ppos, buf, res); 240 return simple_read_from_buffer(userbuf, count, ppos, buf, res);
@@ -344,7 +345,10 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,
344 DRIVER_STATE_PRINT_INT(tx_allocated_blocks[3]); 345 DRIVER_STATE_PRINT_INT(tx_allocated_blocks[3]);
345 DRIVER_STATE_PRINT_INT(tx_frames_cnt); 346 DRIVER_STATE_PRINT_INT(tx_frames_cnt);
346 DRIVER_STATE_PRINT_LHEX(tx_frames_map[0]); 347 DRIVER_STATE_PRINT_LHEX(tx_frames_map[0]);
347 DRIVER_STATE_PRINT_INT(tx_queue_count); 348 DRIVER_STATE_PRINT_INT(tx_queue_count[0]);
349 DRIVER_STATE_PRINT_INT(tx_queue_count[1]);
350 DRIVER_STATE_PRINT_INT(tx_queue_count[2]);
351 DRIVER_STATE_PRINT_INT(tx_queue_count[3]);
348 DRIVER_STATE_PRINT_INT(tx_packets_count); 352 DRIVER_STATE_PRINT_INT(tx_packets_count);
349 DRIVER_STATE_PRINT_INT(tx_results_count); 353 DRIVER_STATE_PRINT_INT(tx_results_count);
350 DRIVER_STATE_PRINT_LHEX(flags); 354 DRIVER_STATE_PRINT_LHEX(flags);
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 526b1ac2dd80..e58c22d21e39 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -992,7 +992,7 @@ irqreturn_t wl1271_irq(int irq, void *cookie)
992 /* Check if any tx blocks were freed */ 992 /* Check if any tx blocks were freed */
993 spin_lock_irqsave(&wl->wl_lock, flags); 993 spin_lock_irqsave(&wl->wl_lock, flags);
994 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) && 994 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
995 wl->tx_queue_count) { 995 wl1271_tx_total_queue_count(wl) > 0) {
996 spin_unlock_irqrestore(&wl->wl_lock, flags); 996 spin_unlock_irqrestore(&wl->wl_lock, flags);
997 /* 997 /*
998 * In order to avoid starvation of the TX path, 998 * In order to avoid starvation of the TX path,
@@ -1040,7 +1040,7 @@ out:
1040 /* In case TX was not handled here, queue TX work */ 1040 /* In case TX was not handled here, queue TX work */
1041 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags); 1041 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
1042 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) && 1042 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1043 wl->tx_queue_count) 1043 wl1271_tx_total_queue_count(wl) > 0)
1044 ieee80211_queue_work(wl->hw, &wl->tx_work); 1044 ieee80211_queue_work(wl->hw, &wl->tx_work);
1045 spin_unlock_irqrestore(&wl->wl_lock, flags); 1045 spin_unlock_irqrestore(&wl->wl_lock, flags);
1046 1046
@@ -1508,13 +1508,13 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
1508 1508
1509 spin_lock_irqsave(&wl->wl_lock, flags); 1509 spin_lock_irqsave(&wl->wl_lock, flags);
1510 1510
1511 wl->tx_queue_count++; 1511 wl->tx_queue_count[q]++;
1512 1512
1513 /* 1513 /*
1514 * The workqueue is slow to process the tx_queue and we need stop 1514 * The workqueue is slow to process the tx_queue and we need stop
1515 * the queue here, otherwise the queue will get too long. 1515 * the queue here, otherwise the queue will get too long.
1516 */ 1516 */
1517 if (skb_queue_len(&wl->tx_queue[q]) >= WL1271_TX_QUEUE_HIGH_WATERMARK) { 1517 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1518 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q); 1518 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1519 ieee80211_stop_queue(wl->hw, mapping); 1519 ieee80211_stop_queue(wl->hw, mapping);
1520 set_bit(q, &wl->stopped_queues_map); 1520 set_bit(q, &wl->stopped_queues_map);
@@ -1543,10 +1543,11 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
1543int wl1271_tx_dummy_packet(struct wl1271 *wl) 1543int wl1271_tx_dummy_packet(struct wl1271 *wl)
1544{ 1544{
1545 unsigned long flags; 1545 unsigned long flags;
1546 int q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
1546 1547
1547 spin_lock_irqsave(&wl->wl_lock, flags); 1548 spin_lock_irqsave(&wl->wl_lock, flags);
1548 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); 1549 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
1549 wl->tx_queue_count++; 1550 wl->tx_queue_count[q]++;
1550 spin_unlock_irqrestore(&wl->wl_lock, flags); 1551 spin_unlock_irqrestore(&wl->wl_lock, flags);
1551 1552
1552 /* The FW is low on RX memory blocks, so send the dummy packet asap */ 1553 /* The FW is low on RX memory blocks, so send the dummy packet asap */
@@ -3752,7 +3753,7 @@ static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
3752 goto out; 3753 goto out;
3753 3754
3754 /* packets are considered pending if in the TX queue or the FW */ 3755 /* packets are considered pending if in the TX queue or the FW */
3755 ret = (wl->tx_queue_count > 0) || (wl->tx_frames_cnt > 0); 3756 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
3756 3757
3757 /* the above is appropriate for STA mode for PS purposes */ 3758 /* the above is appropriate for STA mode for PS purposes */
3758 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS); 3759 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c
index 3e68a664c9de..3548377ab9c2 100644
--- a/drivers/net/wireless/wl12xx/ps.c
+++ b/drivers/net/wireless/wl12xx/ps.c
@@ -193,24 +193,27 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
193 193
194static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid) 194static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid)
195{ 195{
196 int i, filtered = 0; 196 int i;
197 struct sk_buff *skb; 197 struct sk_buff *skb;
198 struct ieee80211_tx_info *info; 198 struct ieee80211_tx_info *info;
199 unsigned long flags; 199 unsigned long flags;
200 int filtered[NUM_TX_QUEUES];
200 201
201 /* filter all frames currently the low level queus for this hlid */ 202 /* filter all frames currently the low level queus for this hlid */
202 for (i = 0; i < NUM_TX_QUEUES; i++) { 203 for (i = 0; i < NUM_TX_QUEUES; i++) {
204 filtered[i] = 0;
203 while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) { 205 while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) {
204 info = IEEE80211_SKB_CB(skb); 206 info = IEEE80211_SKB_CB(skb);
205 info->flags |= IEEE80211_TX_STAT_TX_FILTERED; 207 info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
206 info->status.rates[0].idx = -1; 208 info->status.rates[0].idx = -1;
207 ieee80211_tx_status_ni(wl->hw, skb); 209 ieee80211_tx_status_ni(wl->hw, skb);
208 filtered++; 210 filtered[i]++;
209 } 211 }
210 } 212 }
211 213
212 spin_lock_irqsave(&wl->wl_lock, flags); 214 spin_lock_irqsave(&wl->wl_lock, flags);
213 wl->tx_queue_count -= filtered; 215 for (i = 0; i < NUM_TX_QUEUES; i++)
216 wl->tx_queue_count[i] -= filtered[i];
214 spin_unlock_irqrestore(&wl->wl_lock, flags); 217 spin_unlock_irqrestore(&wl->wl_lock, flags);
215 218
216 wl1271_handle_tx_low_watermark(wl); 219 wl1271_handle_tx_low_watermark(wl);
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 75984dc81a8d..48fde96ce0d4 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -448,8 +448,7 @@ void wl1271_handle_tx_low_watermark(struct wl1271 *wl)
448 448
449 for (i = 0; i < NUM_TX_QUEUES; i++) { 449 for (i = 0; i < NUM_TX_QUEUES; i++) {
450 if (test_bit(i, &wl->stopped_queues_map) && 450 if (test_bit(i, &wl->stopped_queues_map) &&
451 skb_queue_len(&wl->tx_queue[i]) <= 451 wl->tx_queue_count[i] <= WL1271_TX_QUEUE_LOW_WATERMARK) {
452 WL1271_TX_QUEUE_LOW_WATERMARK) {
453 /* firmware buffer has space, restart queues */ 452 /* firmware buffer has space, restart queues */
454 spin_lock_irqsave(&wl->wl_lock, flags); 453 spin_lock_irqsave(&wl->wl_lock, flags);
455 ieee80211_wake_queue(wl->hw, 454 ieee80211_wake_queue(wl->hw,
@@ -498,8 +497,9 @@ static struct sk_buff *wl1271_sta_skb_dequeue(struct wl1271 *wl)
498 497
499out: 498out:
500 if (skb) { 499 if (skb) {
500 int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
501 spin_lock_irqsave(&wl->wl_lock, flags); 501 spin_lock_irqsave(&wl->wl_lock, flags);
502 wl->tx_queue_count--; 502 wl->tx_queue_count[q]--;
503 spin_unlock_irqrestore(&wl->wl_lock, flags); 503 spin_unlock_irqrestore(&wl->wl_lock, flags);
504 } 504 }
505 505
@@ -535,9 +535,10 @@ static struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl)
535 } 535 }
536 536
537 if (skb) { 537 if (skb) {
538 int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
538 wl->last_tx_hlid = h; 539 wl->last_tx_hlid = h;
539 spin_lock_irqsave(&wl->wl_lock, flags); 540 spin_lock_irqsave(&wl->wl_lock, flags);
540 wl->tx_queue_count--; 541 wl->tx_queue_count[q]--;
541 spin_unlock_irqrestore(&wl->wl_lock, flags); 542 spin_unlock_irqrestore(&wl->wl_lock, flags);
542 } else { 543 } else {
543 wl->last_tx_hlid = 0; 544 wl->last_tx_hlid = 0;
@@ -558,9 +559,12 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl)
558 559
559 if (!skb && 560 if (!skb &&
560 test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) { 561 test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) {
562 int q;
563
561 skb = wl->dummy_packet; 564 skb = wl->dummy_packet;
565 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
562 spin_lock_irqsave(&wl->wl_lock, flags); 566 spin_lock_irqsave(&wl->wl_lock, flags);
563 wl->tx_queue_count--; 567 wl->tx_queue_count[q]--;
564 spin_unlock_irqrestore(&wl->wl_lock, flags); 568 spin_unlock_irqrestore(&wl->wl_lock, flags);
565 } 569 }
566 570
@@ -585,7 +589,7 @@ static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb)
585 } 589 }
586 590
587 spin_lock_irqsave(&wl->wl_lock, flags); 591 spin_lock_irqsave(&wl->wl_lock, flags);
588 wl->tx_queue_count++; 592 wl->tx_queue_count[q]++;
589 spin_unlock_irqrestore(&wl->wl_lock, flags); 593 spin_unlock_irqrestore(&wl->wl_lock, flags);
590} 594}
591 595
@@ -813,23 +817,26 @@ void wl1271_tx_complete(struct wl1271 *wl)
813void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid) 817void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid)
814{ 818{
815 struct sk_buff *skb; 819 struct sk_buff *skb;
816 int i, total = 0; 820 int i;
817 unsigned long flags; 821 unsigned long flags;
818 struct ieee80211_tx_info *info; 822 struct ieee80211_tx_info *info;
823 int total[NUM_TX_QUEUES];
819 824
820 for (i = 0; i < NUM_TX_QUEUES; i++) { 825 for (i = 0; i < NUM_TX_QUEUES; i++) {
826 total[i] = 0;
821 while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) { 827 while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) {
822 wl1271_debug(DEBUG_TX, "link freeing skb 0x%p", skb); 828 wl1271_debug(DEBUG_TX, "link freeing skb 0x%p", skb);
823 info = IEEE80211_SKB_CB(skb); 829 info = IEEE80211_SKB_CB(skb);
824 info->status.rates[0].idx = -1; 830 info->status.rates[0].idx = -1;
825 info->status.rates[0].count = 0; 831 info->status.rates[0].count = 0;
826 ieee80211_tx_status_ni(wl->hw, skb); 832 ieee80211_tx_status_ni(wl->hw, skb);
827 total++; 833 total[i]++;
828 } 834 }
829 } 835 }
830 836
831 spin_lock_irqsave(&wl->wl_lock, flags); 837 spin_lock_irqsave(&wl->wl_lock, flags);
832 wl->tx_queue_count -= total; 838 for (i = 0; i < NUM_TX_QUEUES; i++)
839 wl->tx_queue_count[i] -= total[i];
833 spin_unlock_irqrestore(&wl->wl_lock, flags); 840 spin_unlock_irqrestore(&wl->wl_lock, flags);
834 841
835 wl1271_handle_tx_low_watermark(wl); 842 wl1271_handle_tx_low_watermark(wl);
@@ -864,10 +871,10 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
864 ieee80211_tx_status_ni(wl->hw, skb); 871 ieee80211_tx_status_ni(wl->hw, skb);
865 } 872 }
866 } 873 }
874 wl->tx_queue_count[i] = 0;
867 } 875 }
868 } 876 }
869 877
870 wl->tx_queue_count = 0;
871 wl->stopped_queues_map = 0; 878 wl->stopped_queues_map = 0;
872 879
873 /* 880 /*
@@ -921,8 +928,10 @@ void wl1271_tx_flush(struct wl1271 *wl)
921 while (!time_after(jiffies, timeout)) { 928 while (!time_after(jiffies, timeout)) {
922 mutex_lock(&wl->mutex); 929 mutex_lock(&wl->mutex);
923 wl1271_debug(DEBUG_TX, "flushing tx buffer: %d %d", 930 wl1271_debug(DEBUG_TX, "flushing tx buffer: %d %d",
924 wl->tx_frames_cnt, wl->tx_queue_count); 931 wl->tx_frames_cnt,
925 if ((wl->tx_frames_cnt == 0) && (wl->tx_queue_count == 0)) { 932 wl1271_tx_total_queue_count(wl));
933 if ((wl->tx_frames_cnt == 0) &&
934 (wl1271_tx_total_queue_count(wl) == 0)) {
926 mutex_unlock(&wl->mutex); 935 mutex_unlock(&wl->mutex);
927 return; 936 return;
928 } 937 }
diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h
index 6b7bf3150ec4..5d719b5a3d1d 100644
--- a/drivers/net/wireless/wl12xx/tx.h
+++ b/drivers/net/wireless/wl12xx/tx.h
@@ -198,6 +198,16 @@ static inline int wl1271_tx_get_mac80211_queue(int queue)
198 } 198 }
199} 199}
200 200
201static inline int wl1271_tx_total_queue_count(struct wl1271 *wl)
202{
203 int i, count = 0;
204
205 for (i = 0; i < NUM_TX_QUEUES; i++)
206 count += wl->tx_queue_count[i];
207
208 return count;
209}
210
201void wl1271_tx_work(struct work_struct *work); 211void wl1271_tx_work(struct work_struct *work);
202void wl1271_tx_work_locked(struct wl1271 *wl); 212void wl1271_tx_work_locked(struct wl1271 *wl);
203void wl1271_tx_complete(struct wl1271 *wl); 213void wl1271_tx_complete(struct wl1271 *wl);
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 94bfc0a25d57..1a8751eb8140 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -438,7 +438,7 @@ struct wl1271 {
438 438
439 /* Frames scheduled for transmission, not handled yet */ 439 /* Frames scheduled for transmission, not handled yet */
440 struct sk_buff_head tx_queue[NUM_TX_QUEUES]; 440 struct sk_buff_head tx_queue[NUM_TX_QUEUES];
441 int tx_queue_count; 441 int tx_queue_count[NUM_TX_QUEUES];
442 long stopped_queues_map; 442 long stopped_queues_map;
443 443
444 /* Frames received, not handled yet by mac80211 */ 444 /* Frames received, not handled yet by mac80211 */