aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArik Nemtsov <arik@wizery.com>2011-06-24 06:03:37 -0400
committerLuciano Coelho <coelho@ti.com>2011-07-05 14:33:44 -0400
commit708bb3cf58a9bc90f3171ba64f30601f690e5aaa (patch)
treebb64ac4a73af18a37e0290bf9a8642e0ed5d43fd
parent787b2dc44aa1ae2524f022659c6c6b2d3c979e04 (diff)
wl12xx: implement Tx watermarks per AC
Each AC is stopped when its queue is filled up to the high watermark, and restarted when its queue it lower than the low watermark. This ensures congested ACs are not able to starve other ACs. Signed-off-by: Arik Nemtsov <arik@wizery.com> Signed-off-by: Luciano Coelho <coelho@ti.com>
-rw-r--r--drivers/net/wireless/wl12xx/main.c13
-rw-r--r--drivers/net/wireless/wl12xx/tx.c20
-rw-r--r--drivers/net/wireless/wl12xx/tx.h16
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx.h1
4 files changed, 37 insertions, 13 deletions
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 08eb81e698fa..d7a74597fd59 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -1497,10 +1497,11 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
1497{ 1497{
1498 struct wl1271 *wl = hw->priv; 1498 struct wl1271 *wl = hw->priv;
1499 unsigned long flags; 1499 unsigned long flags;
1500 int q; 1500 int q, mapping;
1501 u8 hlid = 0; 1501 u8 hlid = 0;
1502 1502
1503 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 1503 mapping = skb_get_queue_mapping(skb);
1504 q = wl1271_tx_get_queue(mapping);
1504 1505
1505 if (wl->bss_type == BSS_TYPE_AP_BSS) 1506 if (wl->bss_type == BSS_TYPE_AP_BSS)
1506 hlid = wl1271_tx_get_hlid(skb); 1507 hlid = wl1271_tx_get_hlid(skb);
@@ -1513,10 +1514,10 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
1513 * 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
1514 * the queue here, otherwise the queue will get too long. 1515 * the queue here, otherwise the queue will get too long.
1515 */ 1516 */
1516 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) { 1517 if (skb_queue_len(&wl->tx_queue[q]) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1517 wl1271_debug(DEBUG_TX, "op_tx: stopping queues"); 1518 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1518 ieee80211_stop_queues(wl->hw); 1519 ieee80211_stop_queue(wl->hw, mapping);
1519 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags); 1520 set_bit(q, &wl->stopped_queues_map);
1520 } 1521 }
1521 1522
1522 /* queue the packet */ 1523 /* queue the packet */
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index e6e5f54b8e49..75984dc81a8d 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -444,14 +444,19 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set)
444void wl1271_handle_tx_low_watermark(struct wl1271 *wl) 444void wl1271_handle_tx_low_watermark(struct wl1271 *wl)
445{ 445{
446 unsigned long flags; 446 unsigned long flags;
447 int i;
447 448
448 if (test_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags) && 449 for (i = 0; i < NUM_TX_QUEUES; i++) {
449 wl->tx_queue_count <= WL1271_TX_QUEUE_LOW_WATERMARK) { 450 if (test_bit(i, &wl->stopped_queues_map) &&
450 /* firmware buffer has space, restart queues */ 451 skb_queue_len(&wl->tx_queue[i]) <=
451 spin_lock_irqsave(&wl->wl_lock, flags); 452 WL1271_TX_QUEUE_LOW_WATERMARK) {
452 ieee80211_wake_queues(wl->hw); 453 /* firmware buffer has space, restart queues */
453 clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags); 454 spin_lock_irqsave(&wl->wl_lock, flags);
454 spin_unlock_irqrestore(&wl->wl_lock, flags); 455 ieee80211_wake_queue(wl->hw,
456 wl1271_tx_get_mac80211_queue(i));
457 clear_bit(i, &wl->stopped_queues_map);
458 spin_unlock_irqrestore(&wl->wl_lock, flags);
459 }
455 } 460 }
456} 461}
457 462
@@ -863,6 +868,7 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
863 } 868 }
864 869
865 wl->tx_queue_count = 0; 870 wl->tx_queue_count = 0;
871 wl->stopped_queues_map = 0;
866 872
867 /* 873 /*
868 * Make sure the driver is at a consistent state, in case this 874 * Make sure the driver is at a consistent state, in case this
diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h
index 7ed3c01f3651..6b7bf3150ec4 100644
--- a/drivers/net/wireless/wl12xx/tx.h
+++ b/drivers/net/wireless/wl12xx/tx.h
@@ -182,6 +182,22 @@ static inline int wl1271_tx_get_queue(int queue)
182 } 182 }
183} 183}
184 184
185static inline int wl1271_tx_get_mac80211_queue(int queue)
186{
187 switch (queue) {
188 case CONF_TX_AC_VO:
189 return 0;
190 case CONF_TX_AC_VI:
191 return 1;
192 case CONF_TX_AC_BE:
193 return 2;
194 case CONF_TX_AC_BK:
195 return 3;
196 default:
197 return 2;
198 }
199}
200
185void wl1271_tx_work(struct work_struct *work); 201void wl1271_tx_work(struct work_struct *work);
186void wl1271_tx_work_locked(struct wl1271 *wl); 202void wl1271_tx_work_locked(struct wl1271 *wl);
187void wl1271_tx_complete(struct wl1271 *wl); 203void wl1271_tx_complete(struct wl1271 *wl);
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 000dfcd22556..94bfc0a25d57 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -439,6 +439,7 @@ struct wl1271 {
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;
442 long stopped_queues_map;
442 443
443 /* Frames received, not handled yet by mac80211 */ 444 /* Frames received, not handled yet by mac80211 */
444 struct sk_buff_head deferred_rx_queue; 445 struct sk_buff_head deferred_rx_queue;