Skip to content

Commit

Permalink
wl12xx: schedule TX packets according to FW packet occupancy
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Arik Nemtsov authored and Luciano Coelho committed Aug 22, 2011
1 parent bf54e30 commit 742246f
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 27 deletions.
4 changes: 4 additions & 0 deletions drivers/net/wireless/wl12xx/debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
Expand Down
7 changes: 4 additions & 3 deletions drivers/net/wireless/wl12xx/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -2060,9 +2060,10 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,

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);

Expand Down
71 changes: 48 additions & 23 deletions drivers/net/wireless/wl12xx/tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand All @@ -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;
Expand All @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/wireless/wl12xx/wl12xx.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 742246f

Please sign in to comment.