wil6210: Add proper handling for invalid frames on Rx
authorVladimir Kondratiev <QCA_vkondrat@QCA.qualcomm.com>
Sun, 4 Oct 2015 07:23:19 +0000 (10:23 +0300)
committerKalle Valo <kvalo@qca.qualcomm.com>
Fri, 9 Oct 2015 08:39:05 +0000 (11:39 +0300)
On Rx, when invalid frame is received and dropped,
reaping of next frames from Rx ring is stopped.

This stops NAPI polling and re-enables the Rx interrupt.

However, in cases where no more frames received,
interrupt will not be triggered and rest of Rx frames
will not be processed.

Skip bad frames and continue to reap Rx packets when
such frames are encountered, and add statistics for
such frames for debug.

Signed-off-by: Hamad Kadmany <qca_hkadmany@qca.qualcomm.com>
Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
drivers/net/wireless/ath/wil6210/debugfs.c
drivers/net/wireless/ath/wil6210/txrx.c
drivers/net/wireless/ath/wil6210/wil6210.h

index d1a1e160ef31132f35d56ace1e7dd12a13b267e6..97bc186f9728247a0048476065d17fe0021a3573 100644 (file)
@@ -1373,6 +1373,12 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
                                }
                        }
                        spin_unlock_bh(&p->tid_rx_lock);
+                       seq_printf(s,
+                                  "Rx invalid frame: non-data %lu, short %lu, large %lu\n",
+                                  p->stats.rx_non_data_frame,
+                                  p->stats.rx_short_frame,
+                                  p->stats.rx_large_frame);
+
                        seq_puts(s, "Rx/MCS:");
                        for (mcs = 0; mcs < ARRAY_SIZE(p->stats.rx_per_mcs);
                             mcs++)
index 6229110d558a1a043566091859144b582c34c6c9..8ba271f685f420cae557d86ed189f81975677606 100644 (file)
@@ -379,14 +379,16 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
        u16 dmalen;
        u8 ftype;
        int cid;
-       int i = (int)vring->swhead;
+       int i;
        struct wil_net_stats *stats;
 
        BUILD_BUG_ON(sizeof(struct vring_rx_desc) > sizeof(skb->cb));
 
+again:
        if (unlikely(wil_vring_is_empty(vring)))
                return NULL;
 
+       i = (int)vring->swhead;
        _d = &vring->va[i].rx;
        if (unlikely(!(_d->dma.status & RX_DMA_STATUS_DU))) {
                /* it is not error, we just reached end of Rx done area */
@@ -398,7 +400,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
        wil_vring_advance_head(vring, 1);
        if (!skb) {
                wil_err(wil, "No Rx skb at [%d]\n", i);
-               return NULL;
+               goto again;
        }
        d = wil_skb_rxdesc(skb);
        *d = *_d;
@@ -412,10 +414,14 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
        wil_hex_dump_txrx("Rx ", DUMP_PREFIX_NONE, 32, 4,
                          (const void *)d, sizeof(*d), false);
 
+       cid = wil_rxdesc_cid(d);
+       stats = &wil->sta[cid].stats;
+
        if (unlikely(dmalen > sz)) {
                wil_err(wil, "Rx size too large: %d bytes!\n", dmalen);
+               stats->rx_large_frame++;
                kfree_skb(skb);
-               return NULL;
+               goto again;
        }
        skb_trim(skb, dmalen);
 
@@ -424,8 +430,6 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
        wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1,
                          skb->data, skb_headlen(skb), false);
 
-       cid = wil_rxdesc_cid(d);
-       stats = &wil->sta[cid].stats;
        stats->last_mcs_rx = wil_rxdesc_mcs(d);
        if (stats->last_mcs_rx < ARRAY_SIZE(stats->rx_per_mcs))
                stats->rx_per_mcs[stats->last_mcs_rx]++;
@@ -446,15 +450,17 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
        if (unlikely(ftype != IEEE80211_FTYPE_DATA)) {
                wil_dbg_txrx(wil, "Non-data frame ftype 0x%08x\n", ftype);
                /* TODO: process it */
+               stats->rx_non_data_frame++;
                kfree_skb(skb);
-               return NULL;
+               goto again;
        }
 
        if (unlikely(skb->len < ETH_HLEN + snaplen)) {
                wil_err(wil, "Short frame, len = %d\n", skb->len);
                /* TODO: process it (i.e. BAR) */
+               stats->rx_short_frame++;
                kfree_skb(skb);
-               return NULL;
+               goto again;
        }
 
        /* L4 IDENT is on when HW calculated checksum, check status
index dd4ea926b8e31eb8721a8c8e2f2a209fd7f0017b..e405bef10433ab8bec99dd70159efafbfb518a78 100644 (file)
@@ -465,6 +465,9 @@ struct wil_net_stats {
        unsigned long   tx_bytes;
        unsigned long   tx_errors;
        unsigned long   rx_dropped;
+       unsigned long   rx_non_data_frame;
+       unsigned long   rx_short_frame;
+       unsigned long   rx_large_frame;
        u16 last_mcs_rx;
        u64 rx_per_mcs[WIL_MCS_MAX + 1];
 };