]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/net/wireless/ath/wil6210/txrx.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/ide
[karo-tx-linux.git] / drivers / net / wireless / ath / wil6210 / txrx.c
index 6229110d558a1a043566091859144b582c34c6c9..3bc9bc0efbaccacd4ea4ded29e859a92b358b624 100644 (file)
@@ -358,6 +358,13 @@ static void wil_rx_add_radiotap_header(struct wil6210_priv *wil,
        }
 }
 
+/* similar to ieee80211_ version, but FC contain only 1-st byte */
+static inline int wil_is_back_req(u8 fc)
+{
+       return (fc & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) ==
+              (IEEE80211_FTYPE_CTL | IEEE80211_STYPE_BACK_REQ);
+}
+
 /**
  * reap 1 frame from @swhead
  *
@@ -379,14 +386,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 +407,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;
@@ -409,13 +418,17 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
 
        trace_wil6210_rx(i, d);
        wil_dbg_txrx(wil, "Rx[%3d] : %d bytes\n", i, dmalen);
-       wil_hex_dump_txrx("Rx ", DUMP_PREFIX_NONE, 32, 4,
+       wil_hex_dump_txrx("RxD ", 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 +437,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]++;
@@ -437,24 +448,47 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
        /* no extra checks if in sniffer mode */
        if (ndev->type != ARPHRD_ETHER)
                return skb;
-       /*
-        * Non-data frames may be delivered through Rx DMA channel (ex: BAR)
+       /* Non-data frames may be delivered through Rx DMA channel (ex: BAR)
         * Driver should recognize it by frame type, that is found
         * in Rx descriptor. If type is not data, it is 802.11 frame as is
         */
        ftype = wil_rxdesc_ftype(d) << 2;
        if (unlikely(ftype != IEEE80211_FTYPE_DATA)) {
-               wil_dbg_txrx(wil, "Non-data frame ftype 0x%08x\n", ftype);
-               /* TODO: process it */
+               u8 fc1 = wil_rxdesc_fc1(d);
+               int mid = wil_rxdesc_mid(d);
+               int tid = wil_rxdesc_tid(d);
+               u16 seq = wil_rxdesc_seq(d);
+
+               wil_dbg_txrx(wil,
+                            "Non-data frame FC[7:0] 0x%02x MID %d CID %d TID %d Seq 0x%03x\n",
+                            fc1, mid, cid, tid, seq);
+               stats->rx_non_data_frame++;
+               if (wil_is_back_req(fc1)) {
+                       wil_dbg_txrx(wil,
+                                    "BAR: MID %d CID %d TID %d Seq 0x%03x\n",
+                                    mid, cid, tid, seq);
+                       wil_rx_bar(wil, cid, tid, seq);
+               } else {
+                       /* print again all info. One can enable only this
+                        * without overhead for printing every Rx frame
+                        */
+                       wil_dbg_txrx(wil,
+                                    "Unhandled non-data frame FC[7:0] 0x%02x MID %d CID %d TID %d Seq 0x%03x\n",
+                                    fc1, mid, cid, tid, seq);
+                       wil_hex_dump_txrx("RxD ", DUMP_PREFIX_NONE, 32, 4,
+                                         (const void *)d, sizeof(*d), false);
+                       wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1,
+                                         skb->data, skb_headlen(skb), false);
+               }
                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
@@ -1208,6 +1242,7 @@ static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct vring *vring,
        int tcp_hdr_len;
        int skb_net_hdr_len;
        int gso_type;
+       int rc = -EINVAL;
 
        wil_dbg_txrx(wil, "%s() %d bytes to vring %d\n",
                     __func__, skb->len, vring_index);
@@ -1299,8 +1334,9 @@ static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct vring *vring,
                                     len, rem_data, descs_used);
 
                        if (descs_used == avail)  {
-                               wil_err(wil, "TSO: ring overflow\n");
-                               goto dma_error;
+                               wil_err_ratelimited(wil, "TSO: ring overflow\n");
+                               rc = -ENOMEM;
+                               goto mem_error;
                        }
 
                        lenmss = min_t(int, rem_data, len);
@@ -1322,8 +1358,10 @@ static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct vring *vring,
                                headlen -= lenmss;
                        }
 
-                       if (unlikely(dma_mapping_error(dev, pa)))
-                               goto dma_error;
+                       if (unlikely(dma_mapping_error(dev, pa))) {
+                               wil_err(wil, "TSO: DMA map page error\n");
+                               goto mem_error;
+                       }
 
                        _desc = &vring->va[i].tx;
 
@@ -1422,8 +1460,8 @@ static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct vring *vring,
        }
 
        /* advance swhead */
-       wil_dbg_txrx(wil, "TSO: Tx swhead %d -> %d\n", swhead, vring->swhead);
        wil_vring_advance_head(vring, descs_used);
+       wil_dbg_txrx(wil, "TSO: Tx swhead %d -> %d\n", swhead, vring->swhead);
 
        /* make sure all writes to descriptors (shared memory) are done before
         * committing them to HW
@@ -1433,8 +1471,7 @@ static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct vring *vring,
        wil_w(wil, vring->hwtail, vring->swhead);
        return 0;
 
-dma_error:
-       wil_err(wil, "TSO: DMA map page error\n");
+mem_error:
        while (descs_used > 0) {
                struct wil_ctx *ctx;
 
@@ -1445,14 +1482,11 @@ dma_error:
                _desc->dma.status = TX_DMA_STATUS_DU;
                ctx = &vring->ctx[i];
                wil_txdesc_unmap(dev, d, ctx);
-               if (ctx->skb)
-                       dev_kfree_skb_any(ctx->skb);
                memset(ctx, 0, sizeof(*ctx));
                descs_used--;
        }
-
 err_exit:
-       return -EINVAL;
+       return rc;
 }
 
 static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
@@ -1528,8 +1562,11 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
                _d = &vring->va[i].tx;
                pa = skb_frag_dma_map(dev, frag, 0, skb_frag_size(frag),
                                      DMA_TO_DEVICE);
-               if (unlikely(dma_mapping_error(dev, pa)))
+               if (unlikely(dma_mapping_error(dev, pa))) {
+                       wil_err(wil, "Tx[%2d] failed to map fragment\n",
+                               vring_index);
                        goto dma_error;
+               }
                vring->ctx[i].mapped_as = wil_mapped_as_page;
                wil_tx_desc_map(d, pa, len, vring_index);
                /* no need to check return code -
@@ -1589,9 +1626,6 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
                _d->dma.status = TX_DMA_STATUS_DU;
                wil_txdesc_unmap(dev, d, ctx);
 
-               if (ctx->skb)
-                       dev_kfree_skb_any(ctx->skb);
-
                memset(ctx, 0, sizeof(*ctx));
        }
 
@@ -1633,7 +1667,7 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                goto drop;
        }
        if (unlikely(!test_bit(wil_status_fwconnected, wil->status))) {
-               wil_err(wil, "FW not connected\n");
+               wil_err_ratelimited(wil, "FW not connected\n");
                goto drop;
        }
        if (unlikely(wil->wdev->iftype == NL80211_IFTYPE_MONITOR)) {