>From a08aa07afb2607f9dea152dc738864c4babe7d4d Mon Sep 17 00:00:00 2001 From: Ido Yariv <[email protected]> Date: Thu, 30 Sep 2010 13:28:28 +0200 Subject: [PATCH 13/26] wl1271: Support firmware TX packet aggregation
Instead of sending one packet at a time to the firmware, try to send all available packets at once. This optimization decreases the number of transactions, which saves CPU cycles and increases network throughput. Signed-off-by: Ido Yariv <[email protected]> Tested-by: Juuso Oikarinen <[email protected]> Signed-off-by: Luciano Coelho <[email protected]> Signed-off-by: Claude Brouat <[email protected]> --- drivers/net/wireless/wl12xx/wl1271_tx.c | 99 ++++++++++++------------------- 1 files changed, 37 insertions(+), 62 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c index 62db795..89145d2 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.c +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c @@ -42,13 +42,17 @@ static int wl1271_tx_id(struct wl1271 *wl, struct sk_buff *skb) return -EBUSY; } -static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra) +static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, + u32 buf_offset) { struct wl1271_tx_hw_descr *desc; u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; u32 total_blocks; int id, ret = -EBUSY; + if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE) + return -EBUSY; + /* allocate free identifier for the packet */ id = wl1271_tx_id(wl, skb); if (id < 0) @@ -79,7 +83,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra) return ret; } -static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, +static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, u32 extra, struct ieee80211_tx_info *control) { struct timespec ts; @@ -130,59 +134,17 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, desc->tx_attr = cpu_to_le16(tx_attr); wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d", pad); - return 0; -} - -static int wl1271_tx_send_packet(struct wl1271 *wl, struct sk_buff *skb, - struct ieee80211_tx_info *control) -{ - - struct wl1271_tx_hw_descr *desc; - int len; - - /* FIXME: This is a workaround for getting non-aligned packets. - This happens at least with EAPOL packets from the user space. - Our DMA requires packets to be aligned on a 4-byte boundary. - */ - if (unlikely((long)skb->data & 0x03)) { - int offset = (4 - (long)skb->data) & 0x03; - wl1271_debug(DEBUG_TX, "skb offset %d", offset); - - /* check whether the current skb can be used */ - if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) { - unsigned char *src = skb->data; - - /* align the buffer on a 4-byte boundary */ - skb_reserve(skb, offset); - memmove(skb->data, src, skb->len); - } else { - wl1271_info("No handler, fixme!"); - return -EINVAL; - } - } - - len = WL1271_TX_ALIGN(skb->len); - - /* perform a fixed address block write with the packet */ - wl1271_write(wl, WL1271_SLV_MEM_DATA, skb->data, len, true); - - /* write packet new counter into the write access register */ - wl->tx_packets_count++; - - desc = (struct wl1271_tx_hw_descr *) skb->data; - wl1271_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u (%u words)", - desc->id, skb, len, desc->length); - - return 0; } /* caller must hold wl->mutex */ -static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb) +static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, + u32 buf_offset) { struct ieee80211_tx_info *info; u32 extra = 0; int ret = 0; u8 idx; + u32 total_len; if (!skb) return -EINVAL; @@ -205,19 +167,22 @@ static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb) } } - ret = wl1271_tx_allocate(wl, skb, extra); + ret = wl1271_tx_allocate(wl, skb, extra, buf_offset); if (ret < 0) return ret; - ret = wl1271_tx_fill_hdr(wl, skb, extra, info); - if (ret < 0) - return ret; + wl1271_tx_fill_hdr(wl, skb, extra, info); - ret = wl1271_tx_send_packet(wl, skb, info); - if (ret < 0) - return ret; + /* + * The length of each packet is stored in terms of words. Thus, we must + * pad the skb data to make sure its length is aligned. + * The number of padding bytes is computed and set in wl1271_tx_fill_hdr + */ + total_len = WL1271_TX_ALIGN(skb->len); + memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len); + memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len); - return ret; + return total_len; } u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) @@ -242,7 +207,7 @@ void wl1271_tx_work(struct work_struct *work) struct sk_buff *skb; bool woken_up = false; u32 sta_rates = 0; - u32 prev_tx_packets_count; + u32 buf_offset; int ret; /* check if the rates supported by the AP have changed */ @@ -259,14 +224,15 @@ void wl1271_tx_work(struct work_struct *work) if (unlikely(wl->state == WL1271_STATE_OFF)) goto out; - prev_tx_packets_count = wl->tx_packets_count; - /* if rates have changed, re-configure the rate policy */ if (unlikely(sta_rates)) { wl->rate_set = wl1271_tx_enabled_rates_get(wl, sta_rates); wl1271_acx_rate_policies(wl); } + /* Prepare the transfer buffer, by aggregating all + * available packets */ + buf_offset = 0; while ((skb = skb_dequeue(&wl->tx_queue))) { if (!woken_up) { ret = wl1271_ps_elp_wakeup(wl, false); @@ -275,21 +241,30 @@ void wl1271_tx_work(struct work_struct *work) woken_up = true; } - ret = wl1271_tx_frame(wl, skb); + ret = wl1271_prepare_tx_frame(wl, skb, buf_offset); if (ret == -EBUSY) { - /* firmware buffer is full, lets stop transmitting. */ + /* + * Either the firmware buffer is full, or the + * aggregation buffer is. + * Queue back last skb, and stop aggregating. + */ skb_queue_head(&wl->tx_queue, skb); goto out_ack; } else if (ret < 0) { dev_kfree_skb(skb); goto out_ack; } + buf_offset += ret; + wl->tx_packets_count++; } out_ack: - /* interrupt the firmware with the new packets */ - if (prev_tx_packets_count != wl->tx_packets_count) + if (buf_offset) { + wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, + buf_offset, true); + /* interrupt the firmware with the new packets */ wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count); + } out: if (woken_up) -- 1.6.3.3 Claude BROUAT UMG/MIPE/WSIV System Integrator Office: +33 (0)1 72 21 04 54 mailto: mailto:[email protected] Intel Corp. SAS 134, av du Général Eisenhower BP 73586 31100 TOULOUSE France --------------------------------------------------------------------- Intel Corporation SAS (French simplified joint stock company) Registered headquarters: "Les Montalets"- 2, rue de Paris, 92196 Meudon Cedex, France Registration Number: 302 456 199 R.C.S. NANTERRE Capital: 4,572,000 Euros This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). Any review or distribution by others is strictly prohibited. If you are not the intended recipient, please contact the sender and delete all copies.
0013-wl1271-Support-firmware-TX-packet-aggregation.patch
Description: 0013-wl1271-Support-firmware-TX-packet-aggregation.patch
_______________________________________________ Meego-kernel mailing list [email protected] http://lists.meego.com/listinfo/meego-kernel
