Commit 9fccc82e authored by Ido Reis's avatar Ido Reis Committed by Luciano Coelho

wl18xx: pad only last frame in aggregration buffer for PG2

In PG2 only the last frame in the aggregate buffer should be
aligned to the sdio block size. This frame's header msb should be
set to 0, while in all the previous frames in the aggregation
buffer, this bit should be set to 1.

[Add a HW op for setting the frame ctrl bit only for 18xx. Other minor
cleanups - Arik]

[Make the pre_pkt_send operation optional -- Luca]
Signed-off-by: default avatarIdo Reis <idor@ti.com>
Signed-off-by: default avatarArik Nemtsov <arik@wizery.com>
Signed-off-by: default avatarLuciano Coelho <coelho@ti.com>
parent f5755fe9
...@@ -1406,6 +1406,7 @@ static struct wlcore_ops wl12xx_ops = { ...@@ -1406,6 +1406,7 @@ static struct wlcore_ops wl12xx_ops = {
.debugfs_init = wl12xx_debugfs_add_files, .debugfs_init = wl12xx_debugfs_add_files,
.get_spare_blocks = wl12xx_get_spare_blocks, .get_spare_blocks = wl12xx_get_spare_blocks,
.set_key = wl12xx_set_key, .set_key = wl12xx_set_key,
.pre_pkt_send = NULL,
}; };
static struct ieee80211_sta_ht_cap wl12xx_ht_cap = { static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
......
...@@ -600,7 +600,8 @@ static int wl18xx_identify_chip(struct wl1271 *wl) ...@@ -600,7 +600,8 @@ static int wl18xx_identify_chip(struct wl1271 *wl)
wl->plt_fw_name = WL18XX_FW_NAME; wl->plt_fw_name = WL18XX_FW_NAME;
wl->quirks |= WLCORE_QUIRK_NO_ELP | wl->quirks |= WLCORE_QUIRK_NO_ELP |
WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED | WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED |
WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN; WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN |
WLCORE_QUIRK_TX_PAD_LAST_FRAME;
break; break;
case CHIP_ID_185x_PG10: case CHIP_ID_185x_PG10:
...@@ -847,7 +848,6 @@ wl18xx_set_tx_desc_blocks(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc, ...@@ -847,7 +848,6 @@ wl18xx_set_tx_desc_blocks(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc,
u32 blks, u32 spare_blks) u32 blks, u32 spare_blks)
{ {
desc->wl18xx_mem.total_mem_blocks = blks; desc->wl18xx_mem.total_mem_blocks = blks;
desc->wl18xx_mem.reserved = 0;
} }
static void static void
...@@ -856,6 +856,12 @@ wl18xx_set_tx_desc_data_len(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc, ...@@ -856,6 +856,12 @@ wl18xx_set_tx_desc_data_len(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc,
{ {
desc->length = cpu_to_le16(skb->len); desc->length = cpu_to_le16(skb->len);
/* if only the last frame is to be padded, we unset this bit on Tx */
if (wl->quirks & WLCORE_QUIRK_TX_PAD_LAST_FRAME)
desc->wl18xx_mem.ctrl = WL18XX_TX_CTRL_NOT_PADDED;
else
desc->wl18xx_mem.ctrl = 0;
wl1271_debug(DEBUG_TX, "tx_fill_hdr: hlid: %d " wl1271_debug(DEBUG_TX, "tx_fill_hdr: hlid: %d "
"len: %d life: %d mem: %d", desc->hlid, "len: %d life: %d mem: %d", desc->hlid,
le16_to_cpu(desc->length), le16_to_cpu(desc->length),
...@@ -1152,6 +1158,25 @@ static int wl18xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd, ...@@ -1152,6 +1158,25 @@ static int wl18xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
return ret; return ret;
} }
static u32 wl18xx_pre_pkt_send(struct wl1271 *wl,
u32 buf_offset, u32 last_len)
{
if (wl->quirks & WLCORE_QUIRK_TX_PAD_LAST_FRAME) {
struct wl1271_tx_hw_descr *last_desc;
/* get the last TX HW descriptor written to the aggr buf */
last_desc = (struct wl1271_tx_hw_descr *)(wl->aggr_buf +
buf_offset - last_len);
/* the last frame is padded up to an SDIO block */
last_desc->wl18xx_mem.ctrl &= ~WL18XX_TX_CTRL_NOT_PADDED;
return ALIGN(buf_offset, WL12XX_BUS_BLOCK_SIZE);
}
/* no modifications */
return buf_offset;
}
static struct wlcore_ops wl18xx_ops = { static struct wlcore_ops wl18xx_ops = {
.identify_chip = wl18xx_identify_chip, .identify_chip = wl18xx_identify_chip,
.boot = wl18xx_boot, .boot = wl18xx_boot,
...@@ -1176,6 +1201,7 @@ static struct wlcore_ops wl18xx_ops = { ...@@ -1176,6 +1201,7 @@ static struct wlcore_ops wl18xx_ops = {
.handle_static_data = wl18xx_handle_static_data, .handle_static_data = wl18xx_handle_static_data,
.get_spare_blocks = wl18xx_get_spare_blocks, .get_spare_blocks = wl18xx_get_spare_blocks,
.set_key = wl18xx_set_key, .set_key = wl18xx_set_key,
.pre_pkt_send = wl18xx_pre_pkt_send,
}; };
/* HT cap appropriate for wide channels */ /* HT cap appropriate for wide channels */
......
...@@ -32,6 +32,9 @@ ...@@ -32,6 +32,9 @@
#define WL18XX_TX_STATUS_DESC_ID_MASK 0x7F #define WL18XX_TX_STATUS_DESC_ID_MASK 0x7F
#define WL18XX_TX_STATUS_STAT_BIT_IDX 7 #define WL18XX_TX_STATUS_STAT_BIT_IDX 7
/* Indicates this TX HW frame is not padded to SDIO block size */
#define WL18XX_TX_CTRL_NOT_PADDED BIT(7)
/* /*
* The FW uses a special bit to indicate a wide channel should be used in * The FW uses a special bit to indicate a wide channel should be used in
* the rate policy. * the rate policy.
......
...@@ -188,4 +188,13 @@ wlcore_hw_set_key(struct wl1271 *wl, enum set_key_cmd cmd, ...@@ -188,4 +188,13 @@ wlcore_hw_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
return wl->ops->set_key(wl, cmd, vif, sta, key_conf); return wl->ops->set_key(wl, cmd, vif, sta, key_conf);
} }
static inline u32
wlcore_hw_pre_pkt_send(struct wl1271 *wl, u32 buf_offset, u32 last_len)
{
if (wl->ops->pre_pkt_send)
return wl->ops->pre_pkt_send(wl, buf_offset, last_len);
return buf_offset;
}
#endif #endif
...@@ -178,10 +178,11 @@ u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -178,10 +178,11 @@ u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif,
unsigned int wlcore_calc_packet_alignment(struct wl1271 *wl, unsigned int wlcore_calc_packet_alignment(struct wl1271 *wl,
unsigned int packet_length) unsigned int packet_length)
{ {
if (wl->quirks & WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN) if ((wl->quirks & WLCORE_QUIRK_TX_PAD_LAST_FRAME) ||
return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE); !(wl->quirks & WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN))
else
return ALIGN(packet_length, WL1271_TX_ALIGN_TO); return ALIGN(packet_length, WL1271_TX_ALIGN_TO);
else
return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE);
} }
EXPORT_SYMBOL(wlcore_calc_packet_alignment); EXPORT_SYMBOL(wlcore_calc_packet_alignment);
...@@ -662,7 +663,7 @@ void wl1271_tx_work_locked(struct wl1271 *wl) ...@@ -662,7 +663,7 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
struct wl12xx_vif *wlvif; struct wl12xx_vif *wlvif;
struct sk_buff *skb; struct sk_buff *skb;
struct wl1271_tx_hw_descr *desc; struct wl1271_tx_hw_descr *desc;
u32 buf_offset = 0; u32 buf_offset = 0, last_len = 0;
bool sent_packets = false; bool sent_packets = false;
unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0}; unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0};
int ret; int ret;
...@@ -686,6 +687,9 @@ void wl1271_tx_work_locked(struct wl1271 *wl) ...@@ -686,6 +687,9 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
* Flush buffer and try again. * Flush buffer and try again.
*/ */
wl1271_skb_queue_head(wl, wlvif, skb); wl1271_skb_queue_head(wl, wlvif, skb);
buf_offset = wlcore_hw_pre_pkt_send(wl, buf_offset,
last_len);
wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf, wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf,
buf_offset, true); buf_offset, true);
sent_packets = true; sent_packets = true;
...@@ -711,7 +715,8 @@ void wl1271_tx_work_locked(struct wl1271 *wl) ...@@ -711,7 +715,8 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
ieee80211_free_txskb(wl->hw, skb); ieee80211_free_txskb(wl->hw, skb);
goto out_ack; goto out_ack;
} }
buf_offset += ret; last_len = ret;
buf_offset += last_len;
wl->tx_packets_count++; wl->tx_packets_count++;
if (has_data) { if (has_data) {
desc = (struct wl1271_tx_hw_descr *) skb->data; desc = (struct wl1271_tx_hw_descr *) skb->data;
...@@ -721,6 +726,7 @@ void wl1271_tx_work_locked(struct wl1271 *wl) ...@@ -721,6 +726,7 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
out_ack: out_ack:
if (buf_offset) { if (buf_offset) {
buf_offset = wlcore_hw_pre_pkt_send(wl, buf_offset, last_len);
wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf, wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf,
buf_offset, true); buf_offset, true);
sent_packets = true; sent_packets = true;
......
...@@ -93,9 +93,9 @@ struct wl18xx_tx_mem { ...@@ -93,9 +93,9 @@ struct wl18xx_tx_mem {
u8 total_mem_blocks; u8 total_mem_blocks;
/* /*
* always zero * control bits
*/ */
u8 reserved; u8 ctrl;
} __packed; } __packed;
/* /*
......
...@@ -80,6 +80,7 @@ struct wlcore_ops { ...@@ -80,6 +80,7 @@ struct wlcore_ops {
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct ieee80211_sta *sta,
struct ieee80211_key_conf *key_conf); struct ieee80211_key_conf *key_conf);
u32 (*pre_pkt_send)(struct wl1271 *wl, u32 buf_offset, u32 last_len);
}; };
enum wlcore_partitions { enum wlcore_partitions {
...@@ -420,6 +421,9 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, ...@@ -420,6 +421,9 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
/* Some firmwares may not support ELP */ /* Some firmwares may not support ELP */
#define WLCORE_QUIRK_NO_ELP BIT(6) #define WLCORE_QUIRK_NO_ELP BIT(6)
/* pad only the last frame in the aggregate buffer */
#define WLCORE_QUIRK_TX_PAD_LAST_FRAME BIT(7)
/* extra header space is required for TKIP */ /* extra header space is required for TKIP */
#define WLCORE_QUIRK_TKIP_HEADER_SPACE BIT(8) #define WLCORE_QUIRK_TKIP_HEADER_SPACE BIT(8)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment