Commit 4158149c authored by Arik Nemtsov's avatar Arik Nemtsov Committed by Luciano Coelho

wlcore/wl12xx: add hw op for getting rx packet data length

There is a difference in the way chip families report the length of data
in a single Rx packet. Abstract this into a HW op. Refactor the Rx data
handling function to allocate the correct size for the data, and avoid
trimming the skb.
Signed-off-by: default avatarArik Nemtsov <arik@wizery.com>
Signed-off-by: default avatarLuciano Coelho <coelho@ti.com>
parent b14684a0
...@@ -776,6 +776,19 @@ wl12xx_get_rx_buf_align(struct wl1271 *wl, u32 rx_desc) ...@@ -776,6 +776,19 @@ wl12xx_get_rx_buf_align(struct wl1271 *wl, u32 rx_desc)
return WLCORE_RX_BUF_ALIGNED; return WLCORE_RX_BUF_ALIGNED;
} }
static u32 wl12xx_get_rx_packet_len(struct wl1271 *wl, void *rx_data,
u32 data_len)
{
struct wl1271_rx_descriptor *desc = rx_data;
/* invalid packet */
if (data_len < sizeof(*desc) ||
data_len < sizeof(*desc) + desc->pad_len)
return 0;
return data_len - sizeof(*desc) - desc->pad_len;
}
static bool wl12xx_mac_in_fuse(struct wl1271 *wl) static bool wl12xx_mac_in_fuse(struct wl1271 *wl)
{ {
bool supported = false; bool supported = false;
...@@ -848,6 +861,7 @@ static struct wlcore_ops wl12xx_ops = { ...@@ -848,6 +861,7 @@ static struct wlcore_ops wl12xx_ops = {
.set_tx_desc_blocks = wl12xx_set_tx_desc_blocks, .set_tx_desc_blocks = wl12xx_set_tx_desc_blocks,
.set_tx_desc_data_len = wl12xx_set_tx_desc_data_len, .set_tx_desc_data_len = wl12xx_set_tx_desc_data_len,
.get_rx_buf_align = wl12xx_get_rx_buf_align, .get_rx_buf_align = wl12xx_get_rx_buf_align,
.get_rx_packet_len = wl12xx_get_rx_packet_len,
.get_pg_ver = wl12xx_get_pg_ver, .get_pg_ver = wl12xx_get_pg_ver,
.get_mac = wl12xx_get_mac, .get_mac = wl12xx_get_mac,
}; };
......
...@@ -72,4 +72,13 @@ wlcore_hw_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len) ...@@ -72,4 +72,13 @@ wlcore_hw_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len)
wl->ops->prepare_read(wl, rx_desc, len); wl->ops->prepare_read(wl, rx_desc, len);
} }
static inline u32
wlcore_hw_get_rx_packet_len(struct wl1271 *wl, void *rx_data, u32 data_len)
{
if (!wl->ops->get_rx_packet_len)
BUG_ON(1);
return wl->ops->get_rx_packet_len(wl, rx_data, data_len);
}
#endif #endif
...@@ -110,6 +110,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, ...@@ -110,6 +110,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
u8 is_data = 0; u8 is_data = 0;
u8 reserved = 0; u8 reserved = 0;
u16 seq_num; u16 seq_num;
u32 pkt_data_len;
/* /*
* In PLT mode we seem to get frames and mac80211 warns about them, * In PLT mode we seem to get frames and mac80211 warns about them,
...@@ -118,6 +119,13 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, ...@@ -118,6 +119,13 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
if (unlikely(wl->plt)) if (unlikely(wl->plt))
return -EINVAL; return -EINVAL;
pkt_data_len = wlcore_hw_get_rx_packet_len(wl, data, length);
if (!pkt_data_len) {
wl1271_error("Invalid packet arrived from HW. length %d",
length);
return -EINVAL;
}
if (rx_align == WLCORE_RX_BUF_UNALIGNED) if (rx_align == WLCORE_RX_BUF_UNALIGNED)
reserved = NET_IP_ALIGN; reserved = NET_IP_ALIGN;
...@@ -147,8 +155,8 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, ...@@ -147,8 +155,8 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
return -EINVAL; return -EINVAL;
} }
/* skb length not included rx descriptor */ /* skb length not including rx descriptor */
skb = __dev_alloc_skb(length + reserved - sizeof(*desc), GFP_KERNEL); skb = __dev_alloc_skb(pkt_data_len + reserved, GFP_KERNEL);
if (!skb) { if (!skb) {
wl1271_error("Couldn't allocate RX frame"); wl1271_error("Couldn't allocate RX frame");
return -ENOMEM; return -ENOMEM;
...@@ -157,7 +165,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, ...@@ -157,7 +165,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
/* reserve the unaligned payload(if any) */ /* reserve the unaligned payload(if any) */
skb_reserve(skb, reserved); skb_reserve(skb, reserved);
buf = skb_put(skb, length - sizeof(*desc)); buf = skb_put(skb, pkt_data_len);
/* /*
* Copy packets from aggregation buffer to the skbs without rx * Copy packets from aggregation buffer to the skbs without rx
...@@ -165,7 +173,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, ...@@ -165,7 +173,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
* packets copy the packets in offset of 2 bytes guarantee IP header * packets copy the packets in offset of 2 bytes guarantee IP header
* payload aligned to 4 bytes. * payload aligned to 4 bytes.
*/ */
memcpy(buf, data + sizeof(*desc), length - sizeof(*desc)); memcpy(buf, data + sizeof(*desc), pkt_data_len);
if (rx_align == WLCORE_RX_BUF_PADDED) if (rx_align == WLCORE_RX_BUF_PADDED)
skb_pull(skb, NET_IP_ALIGN); skb_pull(skb, NET_IP_ALIGN);
...@@ -185,8 +193,6 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, ...@@ -185,8 +193,6 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
beacon ? "beacon" : "", beacon ? "beacon" : "",
seq_num, *hlid); seq_num, *hlid);
skb_trim(skb, skb->len - desc->pad_len);
skb_queue_tail(&wl->deferred_rx_queue, skb); skb_queue_tail(&wl->deferred_rx_queue, skb);
queue_work(wl->freezable_wq, &wl->netstack_work); queue_work(wl->freezable_wq, &wl->netstack_work);
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
/* forward declaration */ /* forward declaration */
struct wl1271_tx_hw_descr; struct wl1271_tx_hw_descr;
enum wl_rx_buf_align; enum wl_rx_buf_align;
struct wlcore_ops { struct wlcore_ops {
int (*identify_chip)(struct wl1271 *wl); int (*identify_chip)(struct wl1271 *wl);
int (*boot)(struct wl1271 *wl); int (*boot)(struct wl1271 *wl);
...@@ -48,6 +49,8 @@ struct wlcore_ops { ...@@ -48,6 +49,8 @@ struct wlcore_ops {
enum wl_rx_buf_align (*get_rx_buf_align)(struct wl1271 *wl, enum wl_rx_buf_align (*get_rx_buf_align)(struct wl1271 *wl,
u32 rx_desc); u32 rx_desc);
void (*prepare_read)(struct wl1271 *wl, u32 rx_desc, u32 len); void (*prepare_read)(struct wl1271 *wl, u32 rx_desc, u32 len);
u32 (*get_rx_packet_len)(struct wl1271 *wl, void *rx_data,
u32 data_len);
s8 (*get_pg_ver)(struct wl1271 *wl); s8 (*get_pg_ver)(struct wl1271 *wl);
void (*get_mac)(struct wl1271 *wl); void (*get_mac)(struct wl1271 *wl);
}; };
......
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