summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/ti/wl18xx
diff options
context:
space:
mode:
authorArik Nemtsov <arik@wizery.com>2012-05-10 09:13:27 (GMT)
committerLuciano Coelho <coelho@ti.com>2012-06-05 12:55:20 (GMT)
commit2fc28de5989e1c40fee4e92e2a8f3bdd47b1b34a (patch)
tree78db906825e679db86874d628881f0525e1ab8d3 /drivers/net/wireless/ti/wl18xx
parentb8422dcb865befc5d2d7c21e8427eedf32558fea (diff)
downloadlinux-fsl-qoriq-2fc28de5989e1c40fee4e92e2a8f3bdd47b1b34a.tar.xz
wlcore/wl18xx: add hw op for setting Tx HW checksum
Some chip families are capable of checksumming certain classes of Tx packets in HW. Indicate this fact in the netdev features and perform the HW checksum by protocol type for the 18xx family. Fix the location of the skb network header when we move it so we can rely on it when setting the checksum. Signed-off-by: Arik Nemtsov <arik@wizery.com> Signed-off-by: Luciano Coelho <coelho@ti.com>
Diffstat (limited to 'drivers/net/wireless/ti/wl18xx')
-rw-r--r--drivers/net/wireless/ti/wl18xx/acx.c26
-rw-r--r--drivers/net/wireless/ti/wl18xx/acx.h16
-rw-r--r--drivers/net/wireless/ti/wl18xx/main.c31
3 files changed, 73 insertions, 0 deletions
diff --git a/drivers/net/wireless/ti/wl18xx/acx.c b/drivers/net/wireless/ti/wl18xx/acx.c
index aed8d0d..3379db2 100644
--- a/drivers/net/wireless/ti/wl18xx/acx.c
+++ b/drivers/net/wireless/ti/wl18xx/acx.c
@@ -55,3 +55,29 @@ out:
return ret;
}
+
+int wl18xx_acx_set_checksum_state(struct wl1271 *wl)
+{
+ struct wl18xx_acx_checksum_state *acx;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx checksum state");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->checksum_state = CHECKSUM_OFFLOAD_ENABLED;
+
+ ret = wl1271_cmd_configure(wl, ACX_CHECKSUM_CONFIG, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("failed to set Tx checksum state: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
diff --git a/drivers/net/wireless/ti/wl18xx/acx.h b/drivers/net/wireless/ti/wl18xx/acx.h
index c8eebd8..544db6e 100644
--- a/drivers/net/wireless/ti/wl18xx/acx.h
+++ b/drivers/net/wireless/ti/wl18xx/acx.h
@@ -45,8 +45,24 @@ struct wl18xx_acx_host_config_bitmap {
} __packed;
+enum {
+ CHECKSUM_OFFLOAD_DISABLED = 0,
+ CHECKSUM_OFFLOAD_ENABLED = 1,
+ CHECKSUM_OFFLOAD_FAKE_RX = 2,
+ CHECKSUM_OFFLOAD_INVALID = 0xFF
+};
+
+struct wl18xx_acx_checksum_state {
+ struct acx_header header;
+
+ /* enum acx_checksum_state */
+ u8 checksum_state;
+ u8 pad[3];
+} __packed;
+
int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap,
u32 sdio_blk_size, u32 extra_mem_blks,
u32 len_field_size);
+int wl18xx_acx_set_checksum_state(struct wl1271 *wl);
#endif /* __WL12XX_ACX_H__ */
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
index 1e0719c..c47f52c 100644
--- a/drivers/net/wireless/ti/wl18xx/main.c
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -21,6 +21,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/ip.h>
#include "../wlcore/wlcore.h"
#include "../wlcore/debug.h"
@@ -501,9 +502,38 @@ static int wl18xx_hw_init(struct wl1271 *wl)
if (ret < 0)
return ret;
+ ret = wl18xx_acx_set_checksum_state(wl);
+ if (ret != 0)
+ return ret;
+
return ret;
}
+static void wl18xx_set_tx_desc_csum(struct wl1271 *wl,
+ struct wl1271_tx_hw_descr *desc,
+ struct sk_buff *skb)
+{
+ u32 ip_hdr_offset;
+ struct iphdr *ip_hdr;
+
+ if (skb->ip_summed != CHECKSUM_PARTIAL) {
+ desc->wl18xx_checksum_data = 0;
+ return;
+ }
+
+ ip_hdr_offset = skb_network_header(skb) - skb_mac_header(skb);
+ if (WARN_ON(ip_hdr_offset >= (1<<7))) {
+ desc->wl18xx_checksum_data = 0;
+ return;
+ }
+
+ desc->wl18xx_checksum_data = ip_hdr_offset << 1;
+
+ /* FW is interested only in the LSB of the protocol TCP=0 UDP=1 */
+ ip_hdr = (void *)skb_network_header(skb);
+ desc->wl18xx_checksum_data |= (ip_hdr->protocol & 0x01);
+}
+
static struct wlcore_ops wl18xx_ops = {
.identify_chip = wl18xx_identify_chip,
.boot = wl18xx_boot,
@@ -517,6 +547,7 @@ static struct wlcore_ops wl18xx_ops = {
.tx_immediate_compl = wl18xx_tx_immediate_completion,
.tx_delayed_compl = NULL,
.hw_init = wl18xx_hw_init,
+ .set_tx_desc_csum = wl18xx_set_tx_desc_csum,
};
int __devinit wl18xx_probe(struct platform_device *pdev)