ath10k: decouple HTT TX completions
[cascardo/linux.git] / drivers / net / wireless / ath / ath10k / htt_rx.c
index de058d7..62ea9c8 100644 (file)
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include "core.h"
 #include "htc.h"
 #include "htt.h"
 #include "txrx.h"
 #include "debug.h"
+#include "trace.h"
 
 #include <linux/log2.h>
 
@@ -500,7 +502,7 @@ int ath10k_htt_rx_attach(struct ath10k_htt *htt)
        if (__ath10k_htt_rx_ring_fill_n(htt, htt->rx_ring.fill_level))
                goto err_fill_ring;
 
-       ath10k_dbg(ATH10K_DBG_HTT, "HTT RX ring size: %d, fill_level: %d\n",
+       ath10k_dbg(ATH10K_DBG_BOOT, "htt rx ring size %d fill_level %d\n",
                   htt->rx_ring.size, htt->rx_ring.fill_level);
        return 0;
 
@@ -609,8 +611,7 @@ static int ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
                        RX_MPDU_START_INFO0_ENCRYPT_TYPE);
 
        /* FIXME: No idea what assumptions are safe here. Need logs */
-       if ((fmt == RX_MSDU_DECAP_RAW && skb->next) ||
-           (fmt == RX_MSDU_DECAP_8023_SNAP_LLC)) {
+       if ((fmt == RX_MSDU_DECAP_RAW && skb->next)) {
                ath10k_htt_rx_free_msdu_chain(skb->next);
                skb->next = NULL;
                return -ENOTSUPP;
@@ -658,6 +659,15 @@ static int ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
                        decap_hdr += roundup(crypto_len, 4);
                }
 
+               /* When fmt == RX_MSDU_DECAP_8023_SNAP_LLC:
+                *
+                * SNAP 802.3 consists of:
+                * [dst:6][src:6][len:2][dsap:1][ssap:1][ctl:1][snap:5]
+                * [data][fcs:4].
+                *
+                * Since this overlaps with A-MSDU header (da, sa, len)
+                * there's nothing extra to do. */
+
                if (fmt == RX_MSDU_DECAP_ETHERNET2_DIX) {
                        /* Ethernet2 decap inserts ethernet header in place of
                         * A-MSDU subframe header. */
@@ -803,6 +813,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)
 {
@@ -814,6 +855,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));
 
@@ -888,6 +930,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;
@@ -913,6 +960,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);
@@ -979,6 +1028,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");
@@ -1036,7 +1086,7 @@ end:
 
 void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
 {
-       struct ath10k_htt *htt = ar->htt;
+       struct ath10k_htt *htt = &ar->htt;
        struct htt_resp *resp = (struct htt_resp *)skb->data;
 
        /* confirm alignment */
@@ -1090,7 +1140,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
                        break;
                }
 
-               ath10k_txrx_tx_completed(htt, &tx_done);
+               ath10k_txrx_tx_unref(htt, &tx_done);
                break;
        }
        case HTT_T2H_MSG_TYPE_TX_COMPL_IND: {
@@ -1124,7 +1174,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
                for (i = 0; i < resp->data_tx_completion.num_msdus; i++) {
                        msdu_id = resp->data_tx_completion.msdus[i];
                        tx_done.msdu_id = __le16_to_cpu(msdu_id);
-                       ath10k_txrx_tx_completed(htt, &tx_done);
+                       ath10k_txrx_tx_unref(htt, &tx_done);
                }
                break;
        }
@@ -1149,8 +1199,10 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
        case HTT_T2H_MSG_TYPE_TEST:
                /* FIX THIS */
                break;
-       case HTT_T2H_MSG_TYPE_TX_INSPECT_IND:
        case HTT_T2H_MSG_TYPE_STATS_CONF:
+               trace_ath10k_htt_stats(skb->data, skb->len);
+               break;
+       case HTT_T2H_MSG_TYPE_TX_INSPECT_IND:
        case HTT_T2H_MSG_TYPE_RX_ADDBA:
        case HTT_T2H_MSG_TYPE_RX_DELBA:
        case HTT_T2H_MSG_TYPE_RX_FLUSH: