]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
wl12xx: schedule TX packets according to FW packet occupancy
authorArik Nemtsov <arik@wizery.com>
Sun, 14 Aug 2011 10:17:33 +0000 (13:17 +0300)
committerLuciano Coelho <coelho@ti.com>
Mon, 22 Aug 2011 09:35:30 +0000 (12:35 +0300)
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>
drivers/net/wireless/wl12xx/debugfs.c
drivers/net/wireless/wl12xx/main.c
drivers/net/wireless/wl12xx/tx.c
drivers/net/wireless/wl12xx/wl12xx.h

index 3102652c7625b4a3f81e22c26d8d1a14ae79fa81..d59354f537021f7b6ebbfeb5c4a77bf25c762a5e 100644 (file)
@@ -340,6 +340,10 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,
 
        DRIVER_STATE_PRINT_INT(tx_blocks_available);
        DRIVER_STATE_PRINT_INT(tx_allocated_blocks);
+       DRIVER_STATE_PRINT_INT(tx_allocated_pkts[0]);
+       DRIVER_STATE_PRINT_INT(tx_allocated_pkts[1]);
+       DRIVER_STATE_PRINT_INT(tx_allocated_pkts[2]);
+       DRIVER_STATE_PRINT_INT(tx_allocated_pkts[3]);
        DRIVER_STATE_PRINT_INT(tx_frames_cnt);
        DRIVER_STATE_PRINT_LHEX(tx_frames_map[0]);
        DRIVER_STATE_PRINT_INT(tx_queue_count[0]);
index 09cecb336d5398f59ddcf78f38db3424657b12b6..027b6742a1511d4ccfd2cc78aa9a0ea8fc62fe3f 100644 (file)
@@ -827,7 +827,7 @@ static void wl12xx_fw_status(struct wl1271 *wl,
 
        for (i = 0; i < NUM_TX_QUEUES; i++) {
                /* prevent wrap-around in freed-packets counter */
-               wl->tx_allocated_pkts -=
+               wl->tx_allocated_pkts[i] -=
                                (status->tx_released_pkts[i] -
                                wl->tx_pkts_freed[i]) & 0xff;
 
@@ -2060,9 +2060,10 @@ deinit:
 
        wl->tx_blocks_freed = 0;
 
-       wl->tx_allocated_pkts = 0;
-       for (i = 0; i < NUM_TX_QUEUES; i++)
+       for (i = 0; i < NUM_TX_QUEUES; i++) {
                wl->tx_pkts_freed[i] = 0;
+               wl->tx_allocated_pkts[i] = 0;
+       }
 
        wl1271_debugfs_reset(wl);
 
index 7dd6d8b94f649c8e5f474186bac5451c3c7bd4cd..ccbcd0a4d2bf221e44d5277abac197aecebf49dc 100644 (file)
@@ -205,7 +205,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
        u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra;
        u32 len;
        u32 total_blocks;
-       int id, ret = -EBUSY;
+       int id, ret = -EBUSY, ac;
 
        /* we use 1 spare block */
        u32 spare_blocks = 1;
@@ -242,7 +242,8 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
                wl->tx_blocks_available -= total_blocks;
                wl->tx_allocated_blocks += total_blocks;
 
-               wl->tx_allocated_pkts++;
+               ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
+               wl->tx_allocated_pkts[ac]++;
 
                if (wl->bss_type == BSS_TYPE_AP_BSS)
                        wl->links[hlid].allocated_blks += total_blocks;
@@ -485,21 +486,45 @@ void wl1271_handle_tx_low_watermark(struct wl1271 *wl)
        }
 }
 
+static struct sk_buff_head *wl1271_select_queue(struct wl1271 *wl,
+                                               struct sk_buff_head *queues)
+{
+       int i, q = -1, ac;
+       u32 min_pkts = 0xffffffff;
+
+       /*
+        * Find a non-empty ac where:
+        * 1. There are packets to transmit
+        * 2. The FW has the least allocated blocks
+        *
+        * We prioritize the ACs according to VO>VI>BE>BK
+        */
+       for (i = 0; i < NUM_TX_QUEUES; i++) {
+               ac = wl1271_tx_get_queue(i);
+               if (!skb_queue_empty(&queues[ac]) &&
+                   (wl->tx_allocated_pkts[ac] < min_pkts)) {
+                       q = ac;
+                       min_pkts = wl->tx_allocated_pkts[q];
+               }
+       }
+
+       if (q == -1)
+               return NULL;
+
+       return &queues[q];
+}
+
 static struct sk_buff *wl1271_sta_skb_dequeue(struct wl1271 *wl)
 {
        struct sk_buff *skb = NULL;
        unsigned long flags;
+       struct sk_buff_head *queue;
 
-       skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_VO]);
-       if (skb)
+       queue = wl1271_select_queue(wl, wl->tx_queue);
+       if (!queue)
                goto out;
-       skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_VI]);
-       if (skb)
-               goto out;
-       skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_BE]);
-       if (skb)
-               goto out;
-       skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_BK]);
+
+       skb = skb_dequeue(queue);
 
 out:
        if (skb) {
@@ -517,6 +542,7 @@ static struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl)
        struct sk_buff *skb = NULL;
        unsigned long flags;
        int i, h, start_hlid;
+       struct sk_buff_head *queue;
 
        /* start from the link after the last one */
        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)
        for (i = 0; i < AP_MAX_LINKS; i++) {
                h = (start_hlid + i) % AP_MAX_LINKS;
 
-               skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_VO]);
-               if (skb)
-                       goto out;
-               skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_VI]);
-               if (skb)
-                       goto out;
-               skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_BE]);
-               if (skb)
-                       goto out;
-               skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_BK]);
+               /* only consider connected stations */
+               if (h >= WL1271_AP_STA_HLID_START &&
+                   !test_bit(h - WL1271_AP_STA_HLID_START, wl->ap_hlid_map))
+                       continue;
+
+               queue = wl1271_select_queue(wl, wl->links[h].tx_queue);
+               if (!queue)
+                       continue;
+
+               skb = skb_dequeue(queue);
                if (skb)
-                       goto out;
+                       break;
        }
 
-out:
        if (skb) {
                int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
                wl->last_tx_hlid = h;
index 24b40251535b5717a6d03503a938d6cf16c00ee6..6118df5b742d56351fc9e77f1adb26853c31c580 100644 (file)
@@ -424,7 +424,7 @@ struct wl1271 {
 
        /* Accounting for allocated / available Tx packets in HW */
        u32 tx_pkts_freed[NUM_TX_QUEUES];
-       u32 tx_allocated_pkts;
+       u32 tx_allocated_pkts[NUM_TX_QUEUES];
 
        /* Transmitted TX packets counter for chipset interface */
        u32 tx_packets_count;