aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArik Nemtsov <arik@wizery.com>2011-02-22 17:22:26 -0500
committerLuciano Coelho <coelho@ti.com>2011-02-23 04:14:56 -0500
commita8c0ddb5ba2889e1e11a033ccbadfc600f236a91 (patch)
tree6daf6085a8e8cd176f8e4d1a823399353caa6f21
parent99a2775d02a7accf4cc661a65c76fd7b379d1c7a (diff)
wl12xx: AP-mode - TX queue per link in AC
When operating in AP-mode we require a per link tx-queue. This allows us to implement HW assisted PS mode for links, as well as regulate per-link FW TX blocks consumption. Split each link into ACs to support future QoS for AP-mode. AC queues are emptied in priority and per-link queues are scheduled in a simple round-robin fashion. Signed-off-by: Arik Nemtsov <arik@wizery.com> Signed-off-by: Luciano Coelho <coelho@ti.com>
-rw-r--r--drivers/net/wireless/wl12xx/main.c17
-rw-r--r--drivers/net/wireless/wl12xx/tx.c130
-rw-r--r--drivers/net/wireless/wl12xx/tx.h3
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx.h14
4 files changed, 151 insertions, 13 deletions
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 9bb9ad31c2f5..3a4f6069be60 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -984,6 +984,7 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
984 struct wl1271 *wl = hw->priv; 984 struct wl1271 *wl = hw->priv;
985 unsigned long flags; 985 unsigned long flags;
986 int q; 986 int q;
987 u8 hlid = 0;
987 988
988 spin_lock_irqsave(&wl->wl_lock, flags); 989 spin_lock_irqsave(&wl->wl_lock, flags);
989 wl->tx_queue_count++; 990 wl->tx_queue_count++;
@@ -1002,7 +1003,13 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
1002 1003
1003 /* queue the packet */ 1004 /* queue the packet */
1004 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 1005 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
1005 skb_queue_tail(&wl->tx_queue[q], skb); 1006 if (wl->bss_type == BSS_TYPE_AP_BSS) {
1007 hlid = wl1271_tx_get_hlid(skb);
1008 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1009 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1010 } else {
1011 skb_queue_tail(&wl->tx_queue[q], skb);
1012 }
1006 1013
1007 /* 1014 /*
1008 * The chip specific setup must run before the first TX packet - 1015 * The chip specific setup must run before the first TX packet -
@@ -2643,6 +2650,7 @@ static void wl1271_free_hlid(struct wl1271 *wl, u8 hlid)
2643 int id = hlid - WL1271_AP_STA_HLID_START; 2650 int id = hlid - WL1271_AP_STA_HLID_START;
2644 2651
2645 __clear_bit(id, wl->ap_hlid_map); 2652 __clear_bit(id, wl->ap_hlid_map);
2653 wl1271_tx_reset_link_queues(wl, hlid);
2646} 2654}
2647 2655
2648static int wl1271_op_sta_add(struct ieee80211_hw *hw, 2656static int wl1271_op_sta_add(struct ieee80211_hw *hw,
@@ -3270,7 +3278,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
3270 struct ieee80211_hw *hw; 3278 struct ieee80211_hw *hw;
3271 struct platform_device *plat_dev = NULL; 3279 struct platform_device *plat_dev = NULL;
3272 struct wl1271 *wl; 3280 struct wl1271 *wl;
3273 int i, ret; 3281 int i, j, ret;
3274 unsigned int order; 3282 unsigned int order;
3275 3283
3276 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops); 3284 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
@@ -3298,6 +3306,10 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
3298 for (i = 0; i < NUM_TX_QUEUES; i++) 3306 for (i = 0; i < NUM_TX_QUEUES; i++)
3299 skb_queue_head_init(&wl->tx_queue[i]); 3307 skb_queue_head_init(&wl->tx_queue[i]);
3300 3308
3309 for (i = 0; i < NUM_TX_QUEUES; i++)
3310 for (j = 0; j < AP_MAX_LINKS; j++)
3311 skb_queue_head_init(&wl->links[j].tx_queue[i]);
3312
3301 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work); 3313 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
3302 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work); 3314 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
3303 INIT_WORK(&wl->irq_work, wl1271_irq_work); 3315 INIT_WORK(&wl->irq_work, wl1271_irq_work);
@@ -3323,6 +3335,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
3323 wl->bss_type = MAX_BSS_TYPE; 3335 wl->bss_type = MAX_BSS_TYPE;
3324 wl->set_bss_type = MAX_BSS_TYPE; 3336 wl->set_bss_type = MAX_BSS_TYPE;
3325 wl->fw_bss_type = MAX_BSS_TYPE; 3337 wl->fw_bss_type = MAX_BSS_TYPE;
3338 wl->last_tx_hlid = 0;
3326 3339
3327 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map)); 3340 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
3328 for (i = 0; i < ACX_TX_DESCRIPTORS; i++) 3341 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 0bb57daac889..8c769500ec5d 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -86,6 +86,27 @@ static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl,
86 wl1271_acx_set_inconnection_sta(wl, hdr->addr1); 86 wl1271_acx_set_inconnection_sta(wl, hdr->addr1);
87} 87}
88 88
89u8 wl1271_tx_get_hlid(struct sk_buff *skb)
90{
91 struct ieee80211_tx_info *control = IEEE80211_SKB_CB(skb);
92
93 if (control->control.sta) {
94 struct wl1271_station *wl_sta;
95
96 wl_sta = (struct wl1271_station *)
97 control->control.sta->drv_priv;
98 return wl_sta->hlid;
99 } else {
100 struct ieee80211_hdr *hdr;
101
102 hdr = (struct ieee80211_hdr *)skb->data;
103 if (ieee80211_is_mgmt(hdr->frame_control))
104 return WL1271_AP_GLOBAL_HLID;
105 else
106 return WL1271_AP_BROADCAST_HLID;
107 }
108}
109
89static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, 110static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
90 u32 buf_offset) 111 u32 buf_offset)
91{ 112{
@@ -298,7 +319,7 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set)
298 return enabled_rates; 319 return enabled_rates;
299} 320}
300 321
301static void handle_tx_low_watermark(struct wl1271 *wl) 322void wl1271_handle_tx_low_watermark(struct wl1271 *wl)
302{ 323{
303 unsigned long flags; 324 unsigned long flags;
304 325
@@ -312,7 +333,7 @@ static void handle_tx_low_watermark(struct wl1271 *wl)
312 } 333 }
313} 334}
314 335
315static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl) 336static struct sk_buff *wl1271_sta_skb_dequeue(struct wl1271 *wl)
316{ 337{
317 struct sk_buff *skb = NULL; 338 struct sk_buff *skb = NULL;
318 unsigned long flags; 339 unsigned long flags;
@@ -338,12 +359,69 @@ out:
338 return skb; 359 return skb;
339} 360}
340 361
362static struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl)
363{
364 struct sk_buff *skb = NULL;
365 unsigned long flags;
366 int i, h, start_hlid;
367
368 /* start from the link after the last one */
369 start_hlid = (wl->last_tx_hlid + 1) % AP_MAX_LINKS;
370
371 /* dequeue according to AC, round robin on each link */
372 for (i = 0; i < AP_MAX_LINKS; i++) {
373 h = (start_hlid + i) % AP_MAX_LINKS;
374
375 skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_VO]);
376 if (skb)
377 goto out;
378 skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_VI]);
379 if (skb)
380 goto out;
381 skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_BE]);
382 if (skb)
383 goto out;
384 skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_BK]);
385 if (skb)
386 goto out;
387 }
388
389out:
390 if (skb) {
391 wl->last_tx_hlid = h;
392 spin_lock_irqsave(&wl->wl_lock, flags);
393 wl->tx_queue_count--;
394 spin_unlock_irqrestore(&wl->wl_lock, flags);
395 } else {
396 wl->last_tx_hlid = 0;
397 }
398
399 return skb;
400}
401
402static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl)
403{
404 if (wl->bss_type == BSS_TYPE_AP_BSS)
405 return wl1271_ap_skb_dequeue(wl);
406
407 return wl1271_sta_skb_dequeue(wl);
408}
409
341static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb) 410static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb)
342{ 411{
343 unsigned long flags; 412 unsigned long flags;
344 int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 413 int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
345 414
346 skb_queue_head(&wl->tx_queue[q], skb); 415 if (wl->bss_type == BSS_TYPE_AP_BSS) {
416 u8 hlid = wl1271_tx_get_hlid(skb);
417 skb_queue_head(&wl->links[hlid].tx_queue[q], skb);
418
419 /* make sure we dequeue the same packet next time */
420 wl->last_tx_hlid = (hlid + AP_MAX_LINKS - 1) % AP_MAX_LINKS;
421 } else {
422 skb_queue_head(&wl->tx_queue[q], skb);
423 }
424
347 spin_lock_irqsave(&wl->wl_lock, flags); 425 spin_lock_irqsave(&wl->wl_lock, flags);
348 wl->tx_queue_count++; 426 wl->tx_queue_count++;
349 spin_unlock_irqrestore(&wl->wl_lock, flags); 427 spin_unlock_irqrestore(&wl->wl_lock, flags);
@@ -406,7 +484,7 @@ out_ack:
406 if (sent_packets) { 484 if (sent_packets) {
407 /* interrupt the firmware with the new packets */ 485 /* interrupt the firmware with the new packets */
408 wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count); 486 wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count);
409 handle_tx_low_watermark(wl); 487 wl1271_handle_tx_low_watermark(wl);
410 } 488 }
411 489
412out: 490out:
@@ -523,6 +601,27 @@ void wl1271_tx_complete(struct wl1271 *wl)
523 } 601 }
524} 602}
525 603
604void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid)
605{
606 struct sk_buff *skb;
607 int i, total = 0;
608 unsigned long flags;
609
610 for (i = 0; i < NUM_TX_QUEUES; i++) {
611 while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) {
612 wl1271_debug(DEBUG_TX, "link freeing skb 0x%p", skb);
613 ieee80211_tx_status(wl->hw, skb);
614 total++;
615 }
616 }
617
618 spin_lock_irqsave(&wl->wl_lock, flags);
619 wl->tx_queue_count -= total;
620 spin_unlock_irqrestore(&wl->wl_lock, flags);
621
622 wl1271_handle_tx_low_watermark(wl);
623}
624
526/* caller must hold wl->mutex */ 625/* caller must hold wl->mutex */
527void wl1271_tx_reset(struct wl1271 *wl) 626void wl1271_tx_reset(struct wl1271 *wl)
528{ 627{
@@ -530,19 +629,28 @@ void wl1271_tx_reset(struct wl1271 *wl)
530 struct sk_buff *skb; 629 struct sk_buff *skb;
531 630
532 /* TX failure */ 631 /* TX failure */
533 for (i = 0; i < NUM_TX_QUEUES; i++) { 632 if (wl->bss_type == BSS_TYPE_AP_BSS) {
534 while ((skb = skb_dequeue(&wl->tx_queue[i]))) { 633 for (i = 0; i < AP_MAX_LINKS; i++)
535 wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); 634 wl1271_tx_reset_link_queues(wl, i);
536 ieee80211_tx_status(wl->hw, skb); 635
636 wl->last_tx_hlid = 0;
637 } else {
638 for (i = 0; i < NUM_TX_QUEUES; i++) {
639 while ((skb = skb_dequeue(&wl->tx_queue[i]))) {
640 wl1271_debug(DEBUG_TX, "freeing skb 0x%p",
641 skb);
642 ieee80211_tx_status(wl->hw, skb);
643 }
537 } 644 }
538 } 645 }
646
539 wl->tx_queue_count = 0; 647 wl->tx_queue_count = 0;
540 648
541 /* 649 /*
542 * Make sure the driver is at a consistent state, in case this 650 * Make sure the driver is at a consistent state, in case this
543 * function is called from a context other than interface removal. 651 * function is called from a context other than interface removal.
544 */ 652 */
545 handle_tx_low_watermark(wl); 653 wl1271_handle_tx_low_watermark(wl);
546 654
547 for (i = 0; i < ACX_TX_DESCRIPTORS; i++) 655 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
548 if (wl->tx_frames[i] != NULL) { 656 if (wl->tx_frames[i] != NULL) {
@@ -563,8 +671,8 @@ void wl1271_tx_flush(struct wl1271 *wl)
563 671
564 while (!time_after(jiffies, timeout)) { 672 while (!time_after(jiffies, timeout)) {
565 mutex_lock(&wl->mutex); 673 mutex_lock(&wl->mutex);
566 wl1271_debug(DEBUG_TX, "flushing tx buffer: %d", 674 wl1271_debug(DEBUG_TX, "flushing tx buffer: %d %d",
567 wl->tx_frames_cnt); 675 wl->tx_frames_cnt, wl->tx_queue_count);
568 if ((wl->tx_frames_cnt == 0) && (wl->tx_queue_count == 0)) { 676 if ((wl->tx_frames_cnt == 0) && (wl->tx_queue_count == 0)) {
569 mutex_unlock(&wl->mutex); 677 mutex_unlock(&wl->mutex);
570 return; 678 return;
diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h
index db88f58707a3..02f07fa66e82 100644
--- a/drivers/net/wireless/wl12xx/tx.h
+++ b/drivers/net/wireless/wl12xx/tx.h
@@ -150,5 +150,8 @@ void wl1271_tx_flush(struct wl1271 *wl);
150u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); 150u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
151u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set); 151u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set);
152u32 wl1271_tx_min_rate_get(struct wl1271 *wl); 152u32 wl1271_tx_min_rate_get(struct wl1271 *wl);
153u8 wl1271_tx_get_hlid(struct sk_buff *skb);
154void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid);
155void wl1271_handle_tx_low_watermark(struct wl1271 *wl);
153 156
154#endif 157#endif
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 1d6c94304b1a..9ffac80d3988 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -319,6 +319,11 @@ enum wl12xx_flags {
319 WL1271_FLAG_AP_STARTED 319 WL1271_FLAG_AP_STARTED
320}; 320};
321 321
322struct wl1271_link {
323 /* AP-mode - TX queue per AC in link */
324 struct sk_buff_head tx_queue[NUM_TX_QUEUES];
325};
326
322struct wl1271 { 327struct wl1271 {
323 struct platform_device *plat_dev; 328 struct platform_device *plat_dev;
324 struct ieee80211_hw *hw; 329 struct ieee80211_hw *hw;
@@ -498,6 +503,15 @@ struct wl1271 {
498 /* RX BA constraint value */ 503 /* RX BA constraint value */
499 bool ba_support; 504 bool ba_support;
500 u8 ba_rx_bitmap; 505 u8 ba_rx_bitmap;
506
507 /*
508 * AP-mode - links indexed by HLID. The global and broadcast links
509 * are always active.
510 */
511 struct wl1271_link links[AP_MAX_LINKS];
512
513 /* the hlid of the link where the last transmitted skb came from */
514 int last_tx_hlid;
501}; 515};
502 516
503struct wl1271_station { 517struct wl1271_station {