aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJuuso Oikarinen <juuso.oikarinen@nokia.com>2010-12-13 02:52:37 -0500
committerLuciano Coelho <luciano.coelho@nokia.com>2010-12-15 08:41:37 -0500
commit6742f554db14da94172da9eb1875a1aa944a827f (patch)
tree2c82e2a54f3184bb12ee78c72cdccbf1f469002b /drivers
parent17c1755c24d83f9fd0509b64c76cc43fc60cc642 (diff)
wl12xx: Change TX queue to be per AC
With the current single-queue implementation traffic priorization is not working correctly - when using multiple BE streams and one, say VI stream, the VI stream will share bandwidth almost equally with the BE streams. To fix the issue, implement per AC queues, which are emptied in priority order to the firmware. To keep it relatively simple, maintain a global buffer count and global queue stop/wake instead of per-AC. With these changes, priorization appears to work just fine. Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com> Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/wl12xx/debugfs.c2
-rw-r--r--drivers/net/wireless/wl12xx/main.c12
-rw-r--r--drivers/net/wireless/wl12xx/tx.c60
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx.h3
4 files changed, 60 insertions, 17 deletions
diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c
index c2cd58074372..ec6077760157 100644
--- a/drivers/net/wireless/wl12xx/debugfs.c
+++ b/drivers/net/wireless/wl12xx/debugfs.c
@@ -225,7 +225,7 @@ static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf,
225 char buf[20]; 225 char buf[20];
226 int res; 226 int res;
227 227
228 queue_len = skb_queue_len(&wl->tx_queue); 228 queue_len = wl->tx_queue_count;
229 229
230 res = scnprintf(buf, sizeof(buf), "%u\n", queue_len); 230 res = scnprintf(buf, sizeof(buf), "%u\n", queue_len);
231 return simple_read_from_buffer(userbuf, count, ppos, buf, res); 231 return simple_read_from_buffer(userbuf, count, ppos, buf, res);
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 8c50d3b3fabb..062247ef3ad2 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -570,7 +570,7 @@ static void wl1271_irq_work(struct work_struct *work)
570 570
571 /* Check if any tx blocks were freed */ 571 /* Check if any tx blocks were freed */
572 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) && 572 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
573 !skb_queue_empty(&wl->tx_queue)) { 573 wl->tx_queue_count) {
574 /* 574 /*
575 * In order to avoid starvation of the TX path, 575 * In order to avoid starvation of the TX path,
576 * call the work function directly. 576 * call the work function directly.
@@ -891,6 +891,7 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
891 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb); 891 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
892 struct ieee80211_sta *sta = txinfo->control.sta; 892 struct ieee80211_sta *sta = txinfo->control.sta;
893 unsigned long flags; 893 unsigned long flags;
894 int q;
894 895
895 /* 896 /*
896 * peek into the rates configured in the STA entry. 897 * peek into the rates configured in the STA entry.
@@ -918,10 +919,12 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
918 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags); 919 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
919 } 920 }
920#endif 921#endif
922 wl->tx_queue_count++;
921 spin_unlock_irqrestore(&wl->wl_lock, flags); 923 spin_unlock_irqrestore(&wl->wl_lock, flags);
922 924
923 /* queue the packet */ 925 /* queue the packet */
924 skb_queue_tail(&wl->tx_queue, skb); 926 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
927 skb_queue_tail(&wl->tx_queue[q], skb);
925 928
926 /* 929 /*
927 * The chip specific setup must run before the first TX packet - 930 * The chip specific setup must run before the first TX packet -
@@ -935,7 +938,7 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
935 * The workqueue is slow to process the tx_queue and we need stop 938 * The workqueue is slow to process the tx_queue and we need stop
936 * the queue here, otherwise the queue will get too long. 939 * the queue here, otherwise the queue will get too long.
937 */ 940 */
938 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) { 941 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
939 wl1271_debug(DEBUG_TX, "op_tx: stopping queues"); 942 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
940 943
941 spin_lock_irqsave(&wl->wl_lock, flags); 944 spin_lock_irqsave(&wl->wl_lock, flags);
@@ -2719,7 +2722,8 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
2719 wl->hw = hw; 2722 wl->hw = hw;
2720 wl->plat_dev = plat_dev; 2723 wl->plat_dev = plat_dev;
2721 2724
2722 skb_queue_head_init(&wl->tx_queue); 2725 for (i = 0; i < NUM_TX_QUEUES; i++)
2726 skb_queue_head_init(&wl->tx_queue[i]);
2723 2727
2724 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work); 2728 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
2725 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work); 2729 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index d332b3f6d0fa..b44c75cd8c1e 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -125,7 +125,6 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
125 /* queue (we use same identifiers for tid's and ac's */ 125 /* queue (we use same identifiers for tid's and ac's */
126 ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 126 ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
127 desc->tid = ac; 127 desc->tid = ac;
128
129 desc->aid = TX_HW_DEFAULT_AID; 128 desc->aid = TX_HW_DEFAULT_AID;
130 desc->reserved = 0; 129 desc->reserved = 0;
131 130
@@ -228,7 +227,7 @@ static void handle_tx_low_watermark(struct wl1271 *wl)
228 unsigned long flags; 227 unsigned long flags;
229 228
230 if (test_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags) && 229 if (test_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags) &&
231 skb_queue_len(&wl->tx_queue) <= WL1271_TX_QUEUE_LOW_WATERMARK) { 230 wl->tx_queue_count <= WL1271_TX_QUEUE_LOW_WATERMARK) {
232 /* firmware buffer has space, restart queues */ 231 /* firmware buffer has space, restart queues */
233 spin_lock_irqsave(&wl->wl_lock, flags); 232 spin_lock_irqsave(&wl->wl_lock, flags);
234 ieee80211_wake_queues(wl->hw); 233 ieee80211_wake_queues(wl->hw);
@@ -237,6 +236,43 @@ static void handle_tx_low_watermark(struct wl1271 *wl)
237 } 236 }
238} 237}
239 238
239static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl)
240{
241 struct sk_buff *skb = NULL;
242 unsigned long flags;
243
244 skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_VO]);
245 if (skb)
246 goto out;
247 skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_VI]);
248 if (skb)
249 goto out;
250 skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_BE]);
251 if (skb)
252 goto out;
253 skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_BK]);
254
255out:
256 if (skb) {
257 spin_lock_irqsave(&wl->wl_lock, flags);
258 wl->tx_queue_count--;
259 spin_unlock_irqrestore(&wl->wl_lock, flags);
260 }
261
262 return skb;
263}
264
265static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb)
266{
267 unsigned long flags;
268 int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
269
270 skb_queue_head(&wl->tx_queue[q], skb);
271 spin_lock_irqsave(&wl->wl_lock, flags);
272 wl->tx_queue_count++;
273 spin_unlock_irqrestore(&wl->wl_lock, flags);
274}
275
240void wl1271_tx_work_locked(struct wl1271 *wl) 276void wl1271_tx_work_locked(struct wl1271 *wl)
241{ 277{
242 struct sk_buff *skb; 278 struct sk_buff *skb;
@@ -270,7 +306,7 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
270 wl1271_acx_rate_policies(wl); 306 wl1271_acx_rate_policies(wl);
271 } 307 }
272 308
273 while ((skb = skb_dequeue(&wl->tx_queue))) { 309 while ((skb = wl1271_skb_dequeue(wl))) {
274 if (!woken_up) { 310 if (!woken_up) {
275 ret = wl1271_ps_elp_wakeup(wl, false); 311 ret = wl1271_ps_elp_wakeup(wl, false);
276 if (ret < 0) 312 if (ret < 0)
@@ -284,9 +320,9 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
284 * Aggregation buffer is full. 320 * Aggregation buffer is full.
285 * Flush buffer and try again. 321 * Flush buffer and try again.
286 */ 322 */
287 skb_queue_head(&wl->tx_queue, skb); 323 wl1271_skb_queue_head(wl, skb);
288 wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, 324 wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf,
289 buf_offset, true); 325 buf_offset, true);
290 sent_packets = true; 326 sent_packets = true;
291 buf_offset = 0; 327 buf_offset = 0;
292 continue; 328 continue;
@@ -295,7 +331,7 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
295 * Firmware buffer is full. 331 * Firmware buffer is full.
296 * Queue back last skb, and stop aggregating. 332 * Queue back last skb, and stop aggregating.
297 */ 333 */
298 skb_queue_head(&wl->tx_queue, skb); 334 wl1271_skb_queue_head(wl, skb);
299 /* No work left, avoid scheduling redundant tx work */ 335 /* No work left, avoid scheduling redundant tx work */
300 set_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); 336 set_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
301 goto out_ack; 337 goto out_ack;
@@ -440,10 +476,13 @@ void wl1271_tx_reset(struct wl1271 *wl)
440 struct sk_buff *skb; 476 struct sk_buff *skb;
441 477
442 /* TX failure */ 478 /* TX failure */
443 while ((skb = skb_dequeue(&wl->tx_queue))) { 479 for (i = 0; i < NUM_TX_QUEUES; i++) {
444 wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); 480 while ((skb = skb_dequeue(&wl->tx_queue[i]))) {
445 ieee80211_tx_status(wl->hw, skb); 481 wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb);
482 ieee80211_tx_status(wl->hw, skb);
483 }
446 } 484 }
485 wl->tx_queue_count = 0;
447 486
448 /* 487 /*
449 * Make sure the driver is at a consistent state, in case this 488 * Make sure the driver is at a consistent state, in case this
@@ -472,8 +511,7 @@ void wl1271_tx_flush(struct wl1271 *wl)
472 mutex_lock(&wl->mutex); 511 mutex_lock(&wl->mutex);
473 wl1271_debug(DEBUG_TX, "flushing tx buffer: %d", 512 wl1271_debug(DEBUG_TX, "flushing tx buffer: %d",
474 wl->tx_frames_cnt); 513 wl->tx_frames_cnt);
475 if ((wl->tx_frames_cnt == 0) && 514 if ((wl->tx_frames_cnt == 0) && (wl->tx_queue_count == 0)) {
476 skb_queue_empty(&wl->tx_queue)) {
477 mutex_unlock(&wl->mutex); 515 mutex_unlock(&wl->mutex);
478 return; 516 return;
479 } 517 }
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 07c2297b89a2..ce3d31f98c55 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -292,7 +292,8 @@ struct wl1271 {
292 int session_counter; 292 int session_counter;
293 293
294 /* Frames scheduled for transmission, not handled yet */ 294 /* Frames scheduled for transmission, not handled yet */
295 struct sk_buff_head tx_queue; 295 struct sk_buff_head tx_queue[NUM_TX_QUEUES];
296 int tx_queue_count;
296 297
297 struct work_struct tx_work; 298 struct work_struct tx_work;
298 299