summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/wl12xx/rx.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-10-25 11:25:22 (GMT)
committerLinus Torvalds <torvalds@linux-foundation.org>2011-10-25 11:25:22 (GMT)
commit8a9ea3237e7eb5c25f09e429ad242ae5a3d5ea22 (patch)
treea0a63398a9983667d52cbbbf4e2405b4f22b1d83 /drivers/net/wireless/wl12xx/rx.c
parent1be025d3cb40cd295123af2c394f7229ef9b30ca (diff)
parent8b3408f8ee994973869d8ba32c5bf482bc4ddca4 (diff)
downloadlinux-fsl-qoriq-8a9ea3237e7eb5c25f09e429ad242ae5a3d5ea22.tar.xz
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1745 commits) dp83640: free packet queues on remove dp83640: use proper function to free transmit time stamping packets ipv6: Do not use routes from locally generated RAs |PATCH net-next] tg3: add tx_dropped counter be2net: don't create multiple RX/TX rings in multi channel mode be2net: don't create multiple TXQs in BE2 be2net: refactor VF setup/teardown code into be_vf_setup/clear() be2net: add vlan/rx-mode/flow-control config to be_setup() net_sched: cls_flow: use skb_header_pointer() ipv4: avoid useless call of the function check_peer_pmtu TCP: remove TCP_DEBUG net: Fix driver name for mdio-gpio.c ipv4: tcp: fix TOS value in ACK messages sent from TIME_WAIT rtnetlink: Add missing manual netlink notification in dev_change_net_namespaces ipv4: fix ipsec forward performance regression jme: fix irq storm after suspend/resume route: fix ICMP redirect validation net: hold sock reference while processing tx timestamps tcp: md5: add more const attributes Add ethtool -g support to virtio_net ... Fix up conflicts in: - drivers/net/Kconfig: The split-up generated a trivial conflict with removal of a stale reference to Documentation/networking/net-modules.txt. Remove it from the new location instead. - fs/sysfs/dir.c: Fairly nasty conflicts with the sysfs rb-tree usage, conflicting with Eric Biederman's changes for tagged directories.
Diffstat (limited to 'drivers/net/wireless/wl12xx/rx.c')
-rw-r--r--drivers/net/wireless/wl12xx/rx.c69
1 files changed, 41 insertions, 28 deletions
diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c
index 0450fb4..dee4cfe 100644
--- a/drivers/net/wireless/wl12xx/rx.c
+++ b/drivers/net/wireless/wl12xx/rx.c
@@ -30,20 +30,28 @@
#include "rx.h"
#include "io.h"
-static u8 wl1271_rx_get_mem_block(struct wl1271_fw_common_status *status,
+static u8 wl12xx_rx_get_mem_block(struct wl12xx_fw_status *status,
u32 drv_rx_counter)
{
return le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) &
RX_MEM_BLOCK_MASK;
}
-static u32 wl1271_rx_get_buf_size(struct wl1271_fw_common_status *status,
+static u32 wl12xx_rx_get_buf_size(struct wl12xx_fw_status *status,
u32 drv_rx_counter)
{
return (le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) &
RX_BUF_SIZE_MASK) >> RX_BUF_SIZE_SHIFT_DIV;
}
+static bool wl12xx_rx_get_unaligned(struct wl12xx_fw_status *status,
+ u32 drv_rx_counter)
+{
+ /* Convert the value to bool */
+ return !!(le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) &
+ RX_BUF_UNALIGNED_PAYLOAD);
+}
+
static void wl1271_rx_status(struct wl1271 *wl,
struct wl1271_rx_descriptor *desc,
struct ieee80211_rx_status *status,
@@ -58,11 +66,9 @@ static void wl1271_rx_status(struct wl1271 *wl,
status->rate_idx = wl1271_rate_to_idx(desc->rate, status->band);
-#ifdef CONFIG_WL12XX_HT
/* 11n support */
if (desc->rate <= CONF_HW_RXTX_RATE_MCS0)
status->flag |= RX_FLAG_HT;
-#endif
status->signal = desc->rssi;
@@ -89,7 +95,8 @@ static void wl1271_rx_status(struct wl1271 *wl,
}
}
-static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
+static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
+ bool unaligned)
{
struct wl1271_rx_descriptor *desc;
struct sk_buff *skb;
@@ -97,6 +104,8 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
u8 *buf;
u8 beacon = 0;
u8 is_data = 0;
+ u8 reserved = unaligned ? NET_IP_ALIGN : 0;
+ u16 seq_num;
/*
* In PLT mode we seem to get frames and mac80211 warns about them,
@@ -131,17 +140,25 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
return -EINVAL;
}
- skb = __dev_alloc_skb(length, GFP_KERNEL);
+ /* skb length not included rx descriptor */
+ skb = __dev_alloc_skb(length + reserved - sizeof(*desc), GFP_KERNEL);
if (!skb) {
wl1271_error("Couldn't allocate RX frame");
return -ENOMEM;
}
- buf = skb_put(skb, length);
- memcpy(buf, data, length);
+ /* reserve the unaligned payload(if any) */
+ skb_reserve(skb, reserved);
- /* now we pull the descriptor out of the buffer */
- skb_pull(skb, sizeof(*desc));
+ buf = skb_put(skb, length - sizeof(*desc));
+
+ /*
+ * Copy packets from aggregation buffer to the skbs without rx
+ * descriptor and with packet payload aligned care. In case of unaligned
+ * packets copy the packets in offset of 2 bytes guarantee IP header
+ * payload aligned to 4 bytes.
+ */
+ memcpy(buf, data + sizeof(*desc), length - sizeof(*desc));
hdr = (struct ieee80211_hdr *)skb->data;
if (ieee80211_is_beacon(hdr->frame_control))
@@ -151,9 +168,11 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon);
- wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb,
+ seq_num = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
+ wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s seq %d", skb,
skb->len - desc->pad_len,
- beacon ? "beacon" : "");
+ beacon ? "beacon" : "",
+ seq_num);
skb_trim(skb, skb->len - desc->pad_len);
@@ -163,7 +182,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
return is_data;
}
-void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
+void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status)
{
struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map;
u32 buf_size;
@@ -175,12 +194,13 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
u32 pkt_offset;
bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
bool had_data = false;
+ bool unaligned = false;
while (drv_rx_counter != fw_rx_counter) {
buf_size = 0;
rx_counter = drv_rx_counter;
while (rx_counter != fw_rx_counter) {
- pkt_length = wl1271_rx_get_buf_size(status, rx_counter);
+ pkt_length = wl12xx_rx_get_buf_size(status, rx_counter);
if (buf_size + pkt_length > WL1271_AGGR_BUFFER_SIZE)
break;
buf_size += pkt_length;
@@ -199,7 +219,7 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
* For aggregated packets, only the first memory block
* should be retrieved. The FW takes care of the rest.
*/
- mem_block = wl1271_rx_get_mem_block(status,
+ mem_block = wl12xx_rx_get_mem_block(status,
drv_rx_counter);
wl->rx_mem_pool_addr.addr = (mem_block << 8) +
@@ -220,8 +240,12 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
/* Split data into separate packets */
pkt_offset = 0;
while (pkt_offset < buf_size) {
- pkt_length = wl1271_rx_get_buf_size(status,
+ pkt_length = wl12xx_rx_get_buf_size(status,
drv_rx_counter);
+
+ unaligned = wl12xx_rx_get_unaligned(status,
+ drv_rx_counter);
+
/*
* the handle data call can only fail in memory-outage
* conditions, in that case the received frame will just
@@ -229,7 +253,7 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
*/
if (wl1271_rx_handle_data(wl,
wl->aggr_buf + pkt_offset,
- pkt_length) == 1)
+ pkt_length, unaligned) == 1)
had_data = true;
wl->rx_counter++;
@@ -260,14 +284,3 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
jiffies + msecs_to_jiffies(timeout));
}
}
-
-void wl1271_set_default_filters(struct wl1271 *wl)
-{
- if (wl->bss_type == BSS_TYPE_AP_BSS) {
- wl->rx_config = WL1271_DEFAULT_AP_RX_CONFIG;
- wl->rx_filter = WL1271_DEFAULT_AP_RX_FILTER;
- } else {
- wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
- wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
- }
-}