wl12xx_get_fuse_mac(wl);
 }
 
+static void wl12xx_set_tx_desc_csum(struct wl1271 *wl,
+                                   struct wl1271_tx_hw_descr *desc,
+                                   struct sk_buff *skb)
+{
+       desc->wl12xx_reserved = 0;
+}
+
 static struct wlcore_ops wl12xx_ops = {
        .identify_chip          = wl12xx_identify_chip,
        .identify_fw            = wl12xx_identify_fw,
        .sta_get_ap_rate_mask   = wl12xx_sta_get_ap_rate_mask,
        .get_pg_ver             = wl12xx_get_pg_ver,
        .get_mac                = wl12xx_get_mac,
+       .set_tx_desc_csum       = wl12xx_set_tx_desc_csum,
 };
 
 static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
 
 
        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;
+}
 
 
 } __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__ */
 
 
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/ip.h>
 
 #include "../wlcore/wlcore.h"
 #include "../wlcore/debug.h"
        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,
        .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)
 
        ACX_CONFIG_HANGOVER              = 0x0042,
        ACX_FEATURE_CFG                  = 0x0043,
        ACX_PROTECTION_CFG               = 0x0044,
+       ACX_CHECKSUM_CONFIG              = 0x0045,
 };
 
 
 
        return 0;
 }
 
+static inline void
+wlcore_hw_set_tx_desc_csum(struct wl1271 *wl,
+                          struct wl1271_tx_hw_descr *desc,
+                          struct sk_buff *skb)
+{
+       if (!wl->ops->set_tx_desc_csum)
+               BUG_ON(1);
+
+       wl->ops->set_tx_desc_csum(wl, desc, skb);
+}
+
 #endif
 
        if (extra) {
                int hdrlen = ieee80211_hdrlen(frame_control);
                memmove(frame_start, hdr, hdrlen);
+               skb_set_network_header(skb, skb_network_offset(skb) + extra);
        }
 
        /* configure packet life time */
            ieee80211_has_protected(frame_control))
                tx_attr |= TX_HW_ATTR_HOST_ENCRYPT;
 
-       desc->reserved = 0;
        desc->tx_attr = cpu_to_le16(tx_attr);
 
+       wlcore_hw_set_tx_desc_csum(wl, desc, skb);
        wlcore_hw_set_tx_desc_data_len(wl, desc, skb);
 }
 
 
        u8 tid;
        /* host link ID (HLID) */
        u8 hlid;
-       u8 reserved;
+
+       union {
+               u8 wl12xx_reserved;
+
+               /*
+                * bit 0   -> 0 = udp, 1 = tcp
+                * bit 1:7 -> IP header offset
+                */
+               u8 wl18xx_checksum_data;
+       } __packed;
 } __packed;
 
 enum wl1271_tx_hw_res_status {
 
                                    struct wl12xx_vif *wlvif);
        s8 (*get_pg_ver)(struct wl1271 *wl);
        void (*get_mac)(struct wl1271 *wl);
+       void (*set_tx_desc_csum)(struct wl1271 *wl,
+                                struct wl1271_tx_hw_descr *desc,
+                                struct sk_buff *skb);
 };
 
 enum wlcore_partitions {