wlcore/wl12xx: add hw op for getting rx packet data length
authorArik Nemtsov <arik@wizery.com>
Mon, 12 Dec 2011 10:18:17 +0000 (12:18 +0200)
committerLuciano Coelho <coelho@ti.com>
Thu, 12 Apr 2012 05:44:00 +0000 (08:44 +0300)
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: Arik Nemtsov <arik@wizery.com>
Signed-off-by: Luciano Coelho <coelho@ti.com>
drivers/net/wireless/ti/wl12xx/main.c
drivers/net/wireless/ti/wlcore/hw_ops.h
drivers/net/wireless/ti/wlcore/rx.c
drivers/net/wireless/ti/wlcore/wlcore.h

index e4fab2662662e1639e7e2d7b87c184bb990e07ba..5f81aaf19d97f1e3c0f533f78ca60cb0ebc7d859 100644 (file)
@@ -776,6 +776,19 @@ wl12xx_get_rx_buf_align(struct wl1271 *wl, u32 rx_desc)
        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)
 {
        bool supported = false;
@@ -848,6 +861,7 @@ static struct wlcore_ops wl12xx_ops = {
        .set_tx_desc_blocks     = wl12xx_set_tx_desc_blocks,
        .set_tx_desc_data_len   = wl12xx_set_tx_desc_data_len,
        .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_mac                = wl12xx_get_mac,
 };
index 148dc4ee29b135292228836f58ab8717f4e22271..22615a8f1a403a3e641b9d90e47a311c18d6d5ec 100644 (file)
@@ -72,4 +72,13 @@ wlcore_hw_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 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
index 3f504d151e54371e8991fa2f5eb398fae3d1f147..6bde6e2fce0c50ac06082e75009b6be9eeca896a 100644 (file)
@@ -110,6 +110,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
        u8 is_data = 0;
        u8 reserved = 0;
        u16 seq_num;
+       u32 pkt_data_len;
 
        /*
         * 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,
        if (unlikely(wl->plt))
                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)
                reserved = NET_IP_ALIGN;
 
@@ -147,8 +155,8 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
                return -EINVAL;
        }
 
-       /* skb length not included rx descriptor */
-       skb = __dev_alloc_skb(length + reserved - sizeof(*desc), GFP_KERNEL);
+       /* skb length not including rx descriptor */
+       skb = __dev_alloc_skb(pkt_data_len + reserved, GFP_KERNEL);
        if (!skb) {
                wl1271_error("Couldn't allocate RX frame");
                return -ENOMEM;
@@ -157,7 +165,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
        /* reserve the unaligned payload(if any) */
        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
@@ -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
         * 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)
                skb_pull(skb, NET_IP_ALIGN);
 
@@ -185,8 +193,6 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
                     beacon ? "beacon" : "",
                     seq_num, *hlid);
 
-       skb_trim(skb, skb->len - desc->pad_len);
-
        skb_queue_tail(&wl->deferred_rx_queue, skb);
        queue_work(wl->freezable_wq, &wl->netstack_work);
 
index 79ab84eb8f7bb2fc5d8c63a20054ed3cab65903c..664df3216bbfaf900b988f1935ac1bb331391ed3 100644 (file)
@@ -33,6 +33,7 @@
 /* forward declaration */
 struct wl1271_tx_hw_descr;
 enum wl_rx_buf_align;
+
 struct wlcore_ops {
        int (*identify_chip)(struct wl1271 *wl);
        int (*boot)(struct wl1271 *wl);
@@ -48,6 +49,8 @@ struct wlcore_ops {
        enum wl_rx_buf_align (*get_rx_buf_align)(struct wl1271 *wl,
                                                 u32 rx_desc);
        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);
        void (*get_mac)(struct wl1271 *wl);
 };