ath10k: implement rx checksum offloading
authorMichal Kazior <michal.kazior@tieto.com>
Wed, 31 Jul 2013 08:47:56 +0000 (10:47 +0200)
committerKalle Valo <kvalo@qca.qualcomm.com>
Fri, 2 Aug 2013 06:28:39 +0000 (09:28 +0300)
HW supports L3/L4 rx checksum offloading.

This should reduce CPU load and improve
performance on slow host machines.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
drivers/net/wireless/ath/ath10k/htt_rx.c

index 04f08d946479362ff52bfceb1153c7f6f0f938fc..e784c40b904b55165a112df250c61351c606979b 100644 (file)
@@ -804,6 +804,37 @@ static bool ath10k_htt_rx_has_fcs_err(struct sk_buff *skb)
        return false;
 }
 
+static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb)
+{
+       struct htt_rx_desc *rxd;
+       u32 flags, info;
+       bool is_ip4, is_ip6;
+       bool is_tcp, is_udp;
+       bool ip_csum_ok, tcpudp_csum_ok;
+
+       rxd = (void *)skb->data - sizeof(*rxd);
+       flags = __le32_to_cpu(rxd->attention.flags);
+       info = __le32_to_cpu(rxd->msdu_start.info1);
+
+       is_ip4 = !!(info & RX_MSDU_START_INFO1_IPV4_PROTO);
+       is_ip6 = !!(info & RX_MSDU_START_INFO1_IPV6_PROTO);
+       is_tcp = !!(info & RX_MSDU_START_INFO1_TCP_PROTO);
+       is_udp = !!(info & RX_MSDU_START_INFO1_UDP_PROTO);
+       ip_csum_ok = !(flags & RX_ATTENTION_FLAGS_IP_CHKSUM_FAIL);
+       tcpudp_csum_ok = !(flags & RX_ATTENTION_FLAGS_TCP_UDP_CHKSUM_FAIL);
+
+       if (!is_ip4 && !is_ip6)
+               return CHECKSUM_NONE;
+       if (!is_tcp && !is_udp)
+               return CHECKSUM_NONE;
+       if (!ip_csum_ok)
+               return CHECKSUM_NONE;
+       if (!tcpudp_csum_ok)
+               return CHECKSUM_NONE;
+
+       return CHECKSUM_UNNECESSARY;
+}
+
 static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
                                  struct htt_rx_indication *rx)
 {
@@ -815,6 +846,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
        u8 *fw_desc;
        int i, j;
        int ret;
+       int ip_summed;
 
        memset(&info, 0, sizeof(info));
 
@@ -889,6 +921,11 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
                                continue;
                        }
 
+                       /* The skb is not yet processed and it may be
+                        * reallocated. Since the offload is in the original
+                        * skb extract the checksum now and assign it later */
+                       ip_summed = ath10k_htt_rx_get_csum_state(msdu_head);
+
                        info.skb     = msdu_head;
                        info.fcs_err = ath10k_htt_rx_has_fcs_err(msdu_head);
                        info.signal  = ATH10K_DEFAULT_NOISE_FLOOR;
@@ -914,6 +951,8 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
                        if (ath10k_htt_rx_hdr_is_amsdu((void *)info.skb->data))
                                ath10k_dbg(ATH10K_DBG_HTT, "htt mpdu is amsdu\n");
 
+                       info.skb->ip_summed = ip_summed;
+
                        ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt mpdu: ",
                                        info.skb->data, info.skb->len);
                        ath10k_process_rx(htt->ar, &info);
@@ -980,6 +1019,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
        info.status = HTT_RX_IND_MPDU_STATUS_OK;
        info.encrypt_type = MS(__le32_to_cpu(rxd->mpdu_start.info0),
                                RX_MPDU_START_INFO0_ENCRYPT_TYPE);
+       info.skb->ip_summed = ath10k_htt_rx_get_csum_state(info.skb);
 
        if (tkip_mic_err) {
                ath10k_warn("tkip mic error\n");