diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx/tx.c')
-rw-r--r-- | drivers/net/wireless/wl12xx/tx.c | 64 |
1 files changed, 45 insertions, 19 deletions
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index 5e9ef7d53e7e..e296f0a5fe27 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -132,6 +132,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, { struct wl1271_tx_hw_descr *desc; u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; + u32 len; u32 total_blocks; int id, ret = -EBUSY; @@ -145,14 +146,20 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, /* approximate the number of blocks required for this packet in the firmware */ - total_blocks = total_len + TX_HW_BLOCK_SIZE - 1; - total_blocks = total_blocks / TX_HW_BLOCK_SIZE + TX_HW_BLOCK_SPARE; + if (wl->block_size) + len = ALIGN(total_len, wl->block_size); + else + len = total_len; + + total_blocks = (len + TX_HW_BLOCK_SIZE - 1) / TX_HW_BLOCK_SIZE + + TX_HW_BLOCK_SPARE; + if (total_blocks <= wl->tx_blocks_available) { desc = (struct wl1271_tx_hw_descr *)skb_push( skb, total_len - skb->len); - desc->extra_mem_blocks = TX_HW_BLOCK_SPARE; - desc->total_mem_blocks = total_blocks; + desc->wl127x_mem.extra_blocks = TX_HW_BLOCK_SPARE; + desc->wl127x_mem.total_mem_blocks = total_blocks; desc->id = id; wl->tx_blocks_available -= total_blocks; @@ -178,7 +185,7 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, { struct timespec ts; struct wl1271_tx_hw_descr *desc; - int pad, ac, rate_idx; + int aligned_len, ac, rate_idx; s64 hosttime; u16 tx_attr; @@ -237,20 +244,32 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY; desc->reserved = 0; - /* align the length (and store in terms of words) */ - pad = ALIGN(skb->len, WL1271_TX_ALIGN_TO); - desc->length = cpu_to_le16(pad >> 2); + if (wl->block_size) { + aligned_len = ALIGN(skb->len, wl->block_size); + + desc->wl128x_mem.extra_bytes = aligned_len - skb->len; + desc->length = cpu_to_le16(aligned_len >> 2); + } else { + int pad; + + /* align the length (and store in terms of words) */ + aligned_len = ALIGN(skb->len, WL1271_TX_ALIGN_TO); + desc->length = cpu_to_le16(aligned_len >> 2); + + /* calculate number of padding bytes */ + pad = aligned_len - skb->len; + tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; - /* calculate number of padding bytes */ - pad = pad - skb->len; - tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; + wl1271_debug(DEBUG_TX, "tx_fill_hdr: padding: %d", pad); + } desc->tx_attr = cpu_to_le16(tx_attr); - wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d hlid: %d " - "tx_attr: 0x%x len: %d life: %d mem: %d", pad, desc->hlid, - le16_to_cpu(desc->tx_attr), le16_to_cpu(desc->length), - le16_to_cpu(desc->life_time), desc->total_mem_blocks); + wl1271_debug(DEBUG_TX, "tx_fill_hdr: hlid: %d tx_attr: 0x%x " + "len: %d life: %d mem: %d", + desc->hlid, le16_to_cpu(desc->tx_attr), + le16_to_cpu(desc->length), le16_to_cpu(desc->life_time), + desc->wl127x_mem.total_mem_blocks); } /* caller must hold wl->mutex */ @@ -305,11 +324,18 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, wl1271_tx_fill_hdr(wl, skb, extra, info, hlid); /* - * 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 + * 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. + * In special cases, we want to align to a specific block size + * (eg. for wl128x with SDIO we align to 256). */ - total_len = ALIGN(skb->len, WL1271_TX_ALIGN_TO); + if (wl->block_size) + total_len = ALIGN(skb->len, wl->block_size); + else + total_len = ALIGN(skb->len, WL1271_TX_ALIGN_TO); + memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len); memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len); |