aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/wl12xx
diff options
context:
space:
mode:
authorArik Nemtsov <arik@wizery.com>2011-08-14 06:17:33 -0400
committerLuciano Coelho <coelho@ti.com>2011-08-22 05:35:30 -0400
commit742246f8bc16c3a1a556c68ca2fabca162d14c24 (patch)
treefe1bca1893ba3eaf87316ec9a74e2ca8068aed3e /drivers/net/wireless/wl12xx
parentbf54e301671a6ece6c94550294dc7faf14158cd3 (diff)
wl12xx: schedule TX packets according to FW packet occupancy
When selecting packets for transmission, prefer the ACs that are least occupied in the FW. When packets for multiple ACs are present in the FW, it decides which to transmit according to WMM QoS parameters. With these changes, lower priority ACs should not be starved when higher priority traffic is present. Signed-off-by: Arik Nemtsov <arik@wizery.com> Signed-off-by: Eliad Peller <eliad@wizery.com> Signed-off-by: Luciano Coelho <coelho@ti.com>
Diffstat (limited to 'drivers/net/wireless/wl12xx')
-rw-r--r--drivers/net/wireless/wl12xx/debugfs.c4
-rw-r--r--drivers/net/wireless/wl12xx/main.c7
-rw-r--r--drivers/net/wireless/wl12xx/tx.c71
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx.h2
4 files changed, 57 insertions, 27 deletions
diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c
index 3102652c7625..d59354f53702 100644
--- a/drivers/net/wireless/wl12xx/debugfs.c
+++ b/drivers/net/wireless/wl12xx/debugfs.c
@@ -340,6 +340,10 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,
340 340
341 DRIVER_STATE_PRINT_INT(tx_blocks_available); 341 DRIVER_STATE_PRINT_INT(tx_blocks_available);
342 DRIVER_STATE_PRINT_INT(tx_allocated_blocks); 342 DRIVER_STATE_PRINT_INT(tx_allocated_blocks);
343 DRIVER_STATE_PRINT_INT(tx_allocated_pkts[0]);
344 DRIVER_STATE_PRINT_INT(tx_allocated_pkts[1]);
345 DRIVER_STATE_PRINT_INT(tx_allocated_pkts[2]);
346 DRIVER_STATE_PRINT_INT(tx_allocated_pkts[3]);
343 DRIVER_STATE_PRINT_INT(tx_frames_cnt); 347 DRIVER_STATE_PRINT_INT(tx_frames_cnt);
344 DRIVER_STATE_PRINT_LHEX(tx_frames_map[0]); 348 DRIVER_STATE_PRINT_LHEX(tx_frames_map[0]);
345 DRIVER_STATE_PRINT_INT(tx_queue_count[0]); 349 DRIVER_STATE_PRINT_INT(tx_queue_count[0]);
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 09cecb336d53..027b6742a151 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -827,7 +827,7 @@ static void wl12xx_fw_status(struct wl1271 *wl,
827 827
828 for (i = 0; i < NUM_TX_QUEUES; i++) { 828 for (i = 0; i < NUM_TX_QUEUES; i++) {
829 /* prevent wrap-around in freed-packets counter */ 829 /* prevent wrap-around in freed-packets counter */
830 wl->tx_allocated_pkts -= 830 wl->tx_allocated_pkts[i] -=
831 (status->tx_released_pkts[i] - 831 (status->tx_released_pkts[i] -
832 wl->tx_pkts_freed[i]) & 0xff; 832 wl->tx_pkts_freed[i]) & 0xff;
833 833
@@ -2060,9 +2060,10 @@ deinit:
2060 2060
2061 wl->tx_blocks_freed = 0; 2061 wl->tx_blocks_freed = 0;
2062 2062
2063 wl->tx_allocated_pkts = 0; 2063 for (i = 0; i < NUM_TX_QUEUES; i++) {
2064 for (i = 0; i < NUM_TX_QUEUES; i++)
2065 wl->tx_pkts_freed[i] = 0; 2064 wl->tx_pkts_freed[i] = 0;
2065 wl->tx_allocated_pkts[i] = 0;
2066 }
2066 2067
2067 wl1271_debugfs_reset(wl); 2068 wl1271_debugfs_reset(wl);
2068 2069
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 7dd6d8b94f64..ccbcd0a4d2bf 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -205,7 +205,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
205 u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; 205 u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra;
206 u32 len; 206 u32 len;
207 u32 total_blocks; 207 u32 total_blocks;
208 int id, ret = -EBUSY; 208 int id, ret = -EBUSY, ac;
209 209
210 /* we use 1 spare block */ 210 /* we use 1 spare block */
211 u32 spare_blocks = 1; 211 u32 spare_blocks = 1;
@@ -242,7 +242,8 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
242 wl->tx_blocks_available -= total_blocks; 242 wl->tx_blocks_available -= total_blocks;
243 wl->tx_allocated_blocks += total_blocks; 243 wl->tx_allocated_blocks += total_blocks;
244 244
245 wl->tx_allocated_pkts++; 245 ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
246 wl->tx_allocated_pkts[ac]++;
246 247
247 if (wl->bss_type == BSS_TYPE_AP_BSS) 248 if (wl->bss_type == BSS_TYPE_AP_BSS)
248 wl->links[hlid].allocated_blks += total_blocks; 249 wl->links[hlid].allocated_blks += total_blocks;
@@ -485,21 +486,45 @@ void wl1271_handle_tx_low_watermark(struct wl1271 *wl)
485 } 486 }
486} 487}
487 488
489static struct sk_buff_head *wl1271_select_queue(struct wl1271 *wl,
490 struct sk_buff_head *queues)
491{
492 int i, q = -1, ac;
493 u32 min_pkts = 0xffffffff;
494
495 /*
496 * Find a non-empty ac where:
497 * 1. There are packets to transmit
498 * 2. The FW has the least allocated blocks
499 *
500 * We prioritize the ACs according to VO>VI>BE>BK
501 */
502 for (i = 0; i < NUM_TX_QUEUES; i++) {
503 ac = wl1271_tx_get_queue(i);
504 if (!skb_queue_empty(&queues[ac]) &&
505 (wl->tx_allocated_pkts[ac] < min_pkts)) {
506 q = ac;
507 min_pkts = wl->tx_allocated_pkts[q];
508 }
509 }
510
511 if (q == -1)
512 return NULL;
513
514 return &queues[q];
515}
516
488static struct sk_buff *wl1271_sta_skb_dequeue(struct wl1271 *wl) 517static struct sk_buff *wl1271_sta_skb_dequeue(struct wl1271 *wl)
489{ 518{
490 struct sk_buff *skb = NULL; 519 struct sk_buff *skb = NULL;
491 unsigned long flags; 520 unsigned long flags;
521 struct sk_buff_head *queue;
492 522
493 skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_VO]); 523 queue = wl1271_select_queue(wl, wl->tx_queue);
494 if (skb) 524 if (!queue)
495 goto out; 525 goto out;
496 skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_VI]); 526
497 if (skb) 527 skb = skb_dequeue(queue);
498 goto out;
499 skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_BE]);
500 if (skb)
501 goto out;
502 skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_BK]);
503 528
504out: 529out:
505 if (skb) { 530 if (skb) {
@@ -517,6 +542,7 @@ static struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl)
517 struct sk_buff *skb = NULL; 542 struct sk_buff *skb = NULL;
518 unsigned long flags; 543 unsigned long flags;
519 int i, h, start_hlid; 544 int i, h, start_hlid;
545 struct sk_buff_head *queue;
520 546
521 /* start from the link after the last one */ 547 /* start from the link after the last one */
522 start_hlid = (wl->last_tx_hlid + 1) % AP_MAX_LINKS; 548 start_hlid = (wl->last_tx_hlid + 1) % AP_MAX_LINKS;
@@ -525,21 +551,20 @@ static struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl)
525 for (i = 0; i < AP_MAX_LINKS; i++) { 551 for (i = 0; i < AP_MAX_LINKS; i++) {
526 h = (start_hlid + i) % AP_MAX_LINKS; 552 h = (start_hlid + i) % AP_MAX_LINKS;
527 553
528 skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_VO]); 554 /* only consider connected stations */
529 if (skb) 555 if (h >= WL1271_AP_STA_HLID_START &&
530 goto out; 556 !test_bit(h - WL1271_AP_STA_HLID_START, wl->ap_hlid_map))
531 skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_VI]); 557 continue;
532 if (skb) 558
533 goto out; 559 queue = wl1271_select_queue(wl, wl->links[h].tx_queue);
534 skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_BE]); 560 if (!queue)
535 if (skb) 561 continue;
536 goto out; 562
537 skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_BK]); 563 skb = skb_dequeue(queue);
538 if (skb) 564 if (skb)
539 goto out; 565 break;
540 } 566 }
541 567
542out:
543 if (skb) { 568 if (skb) {
544 int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 569 int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
545 wl->last_tx_hlid = h; 570 wl->last_tx_hlid = h;
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 24b40251535b..6118df5b742d 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -424,7 +424,7 @@ struct wl1271 {
424 424
425 /* Accounting for allocated / available Tx packets in HW */ 425 /* Accounting for allocated / available Tx packets in HW */
426 u32 tx_pkts_freed[NUM_TX_QUEUES]; 426 u32 tx_pkts_freed[NUM_TX_QUEUES];
427 u32 tx_allocated_pkts; 427 u32 tx_allocated_pkts[NUM_TX_QUEUES];
428 428
429 /* Transmitted TX packets counter for chipset interface */ 429 /* Transmitted TX packets counter for chipset interface */
430 u32 tx_packets_count; 430 u32 tx_packets_count;