Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
[cascardo/linux.git] / drivers / net / wireless / wl12xx / rx.c
index 0450fb4..dee4cfe 100644 (file)
 #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;
-       }
-}