summary refs log tree commit diff
path: root/drivers/net/wireless/ath/wil6210/txrx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath/wil6210/txrx.c')
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c205
1 files changed, 121 insertions, 84 deletions
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index 797024507c71..d240b24e1ccf 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -22,6 +22,7 @@
 #include "wil6210.h"
 #include "wmi.h"
 #include "txrx.h"
+#include "trace.h"
 
 static bool rtap_include_phy_info;
 module_param(rtap_include_phy_info, bool, S_IRUGO);
@@ -89,8 +90,8 @@ static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring)
 	 * we can use any
 	 */
 	for (i = 0; i < vring->size; i++) {
-		volatile struct vring_tx_desc *d = &(vring->va[i].tx);
-		d->dma.status = TX_DMA_STATUS_DU;
+		volatile struct vring_tx_desc *_d = &(vring->va[i].tx);
+		_d->dma.status = TX_DMA_STATUS_DU;
 	}
 
 	wil_dbg_misc(wil, "vring[%d] 0x%p:0x%016llx 0x%p\n", vring->size,
@@ -106,30 +107,39 @@ static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring,
 	size_t sz = vring->size * sizeof(vring->va[0]);
 
 	while (!wil_vring_is_empty(vring)) {
+		dma_addr_t pa;
+		struct sk_buff *skb;
+		u16 dmalen;
+
 		if (tx) {
-			volatile struct vring_tx_desc *d =
+			struct vring_tx_desc dd, *d = &dd;
+			volatile struct vring_tx_desc *_d =
 					&vring->va[vring->swtail].tx;
-			dma_addr_t pa = d->dma.addr_low |
-					((u64)d->dma.addr_high << 32);
-			struct sk_buff *skb = vring->ctx[vring->swtail];
+
+			*d = *_d;
+			pa = wil_desc_addr(&d->dma.addr);
+			dmalen = le16_to_cpu(d->dma.length);
+			skb = vring->ctx[vring->swtail];
 			if (skb) {
-				dma_unmap_single(dev, pa, d->dma.length,
+				dma_unmap_single(dev, pa, dmalen,
 						 DMA_TO_DEVICE);
 				dev_kfree_skb_any(skb);
 				vring->ctx[vring->swtail] = NULL;
 			} else {
-				dma_unmap_page(dev, pa, d->dma.length,
+				dma_unmap_page(dev, pa, dmalen,
 					       DMA_TO_DEVICE);
 			}
 			vring->swtail = wil_vring_next_tail(vring);
 		} else { /* rx */
-			volatile struct vring_rx_desc *d =
+			struct vring_rx_desc dd, *d = &dd;
+			volatile struct vring_rx_desc *_d =
 					&vring->va[vring->swtail].rx;
-			dma_addr_t pa = d->dma.addr_low |
-					((u64)d->dma.addr_high << 32);
-			struct sk_buff *skb = vring->ctx[vring->swhead];
-			dma_unmap_single(dev, pa, d->dma.length,
-					 DMA_FROM_DEVICE);
+
+			*d = *_d;
+			pa = wil_desc_addr(&d->dma.addr);
+			dmalen = le16_to_cpu(d->dma.length);
+			skb = vring->ctx[vring->swhead];
+			dma_unmap_single(dev, pa, dmalen, DMA_FROM_DEVICE);
 			kfree_skb(skb);
 			wil_vring_advance_head(vring, 1);
 		}
@@ -151,7 +161,8 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring,
 {
 	struct device *dev = wil_to_dev(wil);
 	unsigned int sz = RX_BUF_LEN;
-	volatile struct vring_rx_desc *d = &(vring->va[i].rx);
+	struct vring_rx_desc dd, *d = &dd;
+	volatile struct vring_rx_desc *_d = &(vring->va[i].rx);
 	dma_addr_t pa;
 
 	/* TODO align */
@@ -169,13 +180,13 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring,
 	}
 
 	d->dma.d0 = BIT(9) | RX_DMA_D0_CMD_DMA_IT;
-	d->dma.addr_low = lower_32_bits(pa);
-	d->dma.addr_high = (u16)upper_32_bits(pa);
+	wil_desc_addr_set(&d->dma.addr, pa);
 	/* ip_length don't care */
 	/* b11 don't care */
 	/* error don't care */
 	d->dma.status = 0; /* BIT(0) should be 0 for HW_OWNED */
-	d->dma.length = sz;
+	d->dma.length = cpu_to_le16(sz);
+	*_d = *d;
 	vring->ctx[i] = skb;
 
 	return 0;
@@ -321,11 +332,12 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
 {
 	struct device *dev = wil_to_dev(wil);
 	struct net_device *ndev = wil_to_ndev(wil);
-	volatile struct vring_rx_desc *d;
-	struct vring_rx_desc *d1;
+	volatile struct vring_rx_desc *_d;
+	struct vring_rx_desc *d;
 	struct sk_buff *skb;
 	dma_addr_t pa;
 	unsigned int sz = RX_BUF_LEN;
+	u16 dmalen;
 	u8 ftype;
 	u8 ds_bits;
 
@@ -334,32 +346,44 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
 	if (wil_vring_is_empty(vring))
 		return NULL;
 
-	d = &(vring->va[vring->swhead].rx);
-	if (!(d->dma.status & RX_DMA_STATUS_DU)) {
+	_d = &(vring->va[vring->swhead].rx);
+	if (!(_d->dma.status & RX_DMA_STATUS_DU)) {
 		/* it is not error, we just reached end of Rx done area */
 		return NULL;
 	}
 
-	pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32);
 	skb = vring->ctx[vring->swhead];
+	d = wil_skb_rxdesc(skb);
+	*d = *_d;
+	pa = wil_desc_addr(&d->dma.addr);
+	vring->ctx[vring->swhead] = NULL;
+	wil_vring_advance_head(vring, 1);
+
 	dma_unmap_single(dev, pa, sz, DMA_FROM_DEVICE);
-	skb_trim(skb, d->dma.length);
+	dmalen = le16_to_cpu(d->dma.length);
+
+	trace_wil6210_rx(vring->swhead, d);
+	wil_dbg_txrx(wil, "Rx[%3d] : %d bytes\n", vring->swhead, dmalen);
+	wil_hex_dump_txrx("Rx ", DUMP_PREFIX_NONE, 32, 4,
+			  (const void *)d, sizeof(*d), false);
+
+	if (dmalen > sz) {
+		wil_err(wil, "Rx size too large: %d bytes!\n", dmalen);
+		kfree_skb(skb);
+		return NULL;
+	}
+	skb_trim(skb, dmalen);
+
+	wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1,
+			  skb->data, skb_headlen(skb), false);
 
-	d1 = wil_skb_rxdesc(skb);
-	*d1 = *d;
 
-	wil->stats.last_mcs_rx = wil_rxdesc_mcs(d1);
+	wil->stats.last_mcs_rx = wil_rxdesc_mcs(d);
 
 	/* use radiotap header only if required */
 	if (ndev->type == ARPHRD_IEEE80211_RADIOTAP)
 		wil_rx_add_radiotap_header(wil, skb);
 
-	wil_dbg_txrx(wil, "Rx[%3d] : %d bytes\n", vring->swhead, d->dma.length);
-	wil_hex_dump_txrx("Rx ", DUMP_PREFIX_NONE, 32, 4,
-			  (const void *)d, sizeof(*d), false);
-
-	wil_vring_advance_head(vring, 1);
-
 	/* no extra checks if in sniffer mode */
 	if (ndev->type != ARPHRD_ETHER)
 		return skb;
@@ -368,7 +392,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
 	 * 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(d1) << 2;
+	ftype = wil_rxdesc_ftype(d) << 2;
 	if (ftype != IEEE80211_FTYPE_DATA) {
 		wil_dbg_txrx(wil, "Non-data frame ftype 0x%08x\n", ftype);
 		/* TODO: process it */
@@ -383,7 +407,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
 		return NULL;
 	}
 
-	ds_bits = wil_rxdesc_ds_bits(d1);
+	ds_bits = wil_rxdesc_ds_bits(d);
 	if (ds_bits == 1) {
 		/*
 		 * HW bug - in ToDS mode, i.e. Rx on AP side,
@@ -425,6 +449,7 @@ static int wil_rx_refill(struct wil6210_priv *wil, int count)
 
 /*
  * Pass Rx packet to the netif. Update statistics.
+ * Called in softirq context (NAPI poll).
  */
 static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
 {
@@ -433,10 +458,7 @@ static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
 
 	skb_orphan(skb);
 
-	if (in_interrupt())
-		rc = netif_rx(skb);
-	else
-		rc = netif_rx_ni(skb);
+	rc = netif_receive_skb(skb);
 
 	if (likely(rc == NET_RX_SUCCESS)) {
 		ndev->stats.rx_packets++;
@@ -450,9 +472,9 @@ static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
 /**
  * Proceed all completed skb's from Rx VRING
  *
- * Safe to call from IRQ
+ * Safe to call from NAPI poll, i.e. softirq with interrupts enabled
  */
-void wil_rx_handle(struct wil6210_priv *wil)
+void wil_rx_handle(struct wil6210_priv *wil, int *quota)
 {
 	struct net_device *ndev = wil_to_ndev(wil);
 	struct vring *v = &wil->vring_rx;
@@ -463,9 +485,8 @@ void wil_rx_handle(struct wil6210_priv *wil)
 		return;
 	}
 	wil_dbg_txrx(wil, "%s()\n", __func__);
-	while (NULL != (skb = wil_vring_reap_rx(wil, v))) {
-		wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1,
-				  skb->data, skb_headlen(skb), false);
+	while ((*quota > 0) && (NULL != (skb = wil_vring_reap_rx(wil, v)))) {
+		(*quota)--;
 
 		if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) {
 			skb->dev = ndev;
@@ -600,18 +621,17 @@ static struct vring *wil_find_tx_vring(struct wil6210_priv *wil,
 	return NULL;
 }
 
-static int wil_tx_desc_map(volatile struct vring_tx_desc *d,
-			   dma_addr_t pa, u32 len)
+static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len,
+			   int vring_index)
 {
-	d->dma.addr_low = lower_32_bits(pa);
-	d->dma.addr_high = (u16)upper_32_bits(pa);
+	wil_desc_addr_set(&d->dma.addr, pa);
 	d->dma.ip_length = 0;
 	/* 0..6: mac_length; 7:ip_version 0-IP6 1-IP4*/
 	d->dma.b11 = 0/*14 | BIT(7)*/;
 	d->dma.error = 0;
 	d->dma.status = 0; /* BIT(0) should be 0 for HW_OWNED */
-	d->dma.length = len;
-	d->dma.d0 = 0;
+	d->dma.length = cpu_to_le16((u16)len);
+	d->dma.d0 = (vring_index << DMA_CFG_DESC_TX_0_QID_POS);
 	d->mac.d[0] = 0;
 	d->mac.d[1] = 0;
 	d->mac.d[2] = 0;
@@ -630,7 +650,8 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
 			struct sk_buff *skb)
 {
 	struct device *dev = wil_to_dev(wil);
-	volatile struct vring_tx_desc *d;
+	struct vring_tx_desc dd, *d = &dd;
+	volatile struct vring_tx_desc *_d;
 	u32 swhead = vring->swhead;
 	int avail = wil_vring_avail_tx(vring);
 	int nr_frags = skb_shinfo(skb)->nr_frags;
@@ -648,7 +669,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
 			1 + nr_frags);
 		return -ENOMEM;
 	}
-	d = &(vring->va[i].tx);
+	_d = &(vring->va[i].tx);
 
 	/* FIXME FW can accept only unicast frames for the peer */
 	memcpy(skb->data, wil->dst_addr[vring_index], ETH_ALEN);
@@ -664,28 +685,32 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
 	if (unlikely(dma_mapping_error(dev, pa)))
 		return -EINVAL;
 	/* 1-st segment */
-	wil_tx_desc_map(d, pa, skb_headlen(skb));
+	wil_tx_desc_map(d, pa, skb_headlen(skb), vring_index);
 	d->mac.d[2] |= ((nr_frags + 1) <<
 		       MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS);
+	if (nr_frags)
+		*_d = *d;
+
 	/* middle segments */
 	for (f = 0; f < nr_frags; f++) {
 		const struct skb_frag_struct *frag =
 				&skb_shinfo(skb)->frags[f];
 		int len = skb_frag_size(frag);
 		i = (swhead + f + 1) % vring->size;
-		d = &(vring->va[i].tx);
+		_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)))
 			goto dma_error;
-		wil_tx_desc_map(d, pa, len);
+		wil_tx_desc_map(d, pa, len, vring_index);
 		vring->ctx[i] = NULL;
+		*_d = *d;
 	}
 	/* for the last seg only */
 	d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_EOP_POS);
-	d->dma.d0 |= BIT(9); /* BUG: undocumented bit */
+	d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_MARK_WB_POS);
 	d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS);
-	d->dma.d0 |= (vring_index << DMA_CFG_DESC_TX_0_QID_POS);
+	*_d = *d;
 
 	wil_hex_dump_txrx("Tx ", DUMP_PREFIX_NONE, 32, 4,
 			  (const void *)d, sizeof(*d), false);
@@ -693,6 +718,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
 	/* advance swhead */
 	wil_vring_advance_head(vring, nr_frags + 1);
 	wil_dbg_txrx(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead);
+	trace_wil6210_tx(vring_index, swhead, skb->len, nr_frags);
 	iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail));
 	/* hold reference to skb
 	 * to prevent skb release before accounting
@@ -705,14 +731,18 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
 	/* unmap what we have mapped */
 	/* Note: increment @f to operate with positive index */
 	for (f++; f > 0; f--) {
+		u16 dmalen;
+
 		i = (swhead + f) % vring->size;
-		d = &(vring->va[i].tx);
-		d->dma.status = TX_DMA_STATUS_DU;
-		pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32);
+		_d = &(vring->va[i].tx);
+		*d = *_d;
+		_d->dma.status = TX_DMA_STATUS_DU;
+		pa = wil_desc_addr(&d->dma.addr);
+		dmalen = le16_to_cpu(d->dma.length);
 		if (vring->ctx[i])
-			dma_unmap_single(dev, pa, d->dma.length, DMA_TO_DEVICE);
+			dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE);
 		else
-			dma_unmap_page(dev, pa, d->dma.length, DMA_TO_DEVICE);
+			dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE);
 	}
 
 	return -EINVAL;
@@ -738,18 +768,16 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 		wil_err(wil, "Xmit in monitor mode not supported\n");
 		goto drop;
 	}
-	if (skb->protocol == cpu_to_be16(ETH_P_PAE)) {
-		rc = wmi_tx_eapol(wil, skb);
-	} else {
-		/* find vring */
-		vring = wil_find_tx_vring(wil, skb);
-		if (!vring) {
-			wil_err(wil, "No Tx VRING available\n");
-			goto drop;
-		}
-		/* set up vring entry */
-		rc = wil_tx_vring(wil, vring, skb);
+
+	/* find vring */
+	vring = wil_find_tx_vring(wil, skb);
+	if (!vring) {
+		wil_err(wil, "No Tx VRING available\n");
+		goto drop;
 	}
+	/* set up vring entry */
+	rc = wil_tx_vring(wil, vring, skb);
+
 	switch (rc) {
 	case 0:
 		/* statistics will be updated on the tx_complete */
@@ -761,7 +789,6 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 		break; /* goto drop; */
 	}
  drop:
-	netif_tx_stop_all_queues(ndev);
 	ndev->stats.tx_dropped++;
 	dev_kfree_skb_any(skb);
 
@@ -771,41 +798,48 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 /**
  * Clean up transmitted skb's from the Tx VRING
  *
+ * Return number of descriptors cleared
+ *
  * Safe to call from IRQ
  */
-void wil_tx_complete(struct wil6210_priv *wil, int ringid)
+int wil_tx_complete(struct wil6210_priv *wil, int ringid)
 {
 	struct net_device *ndev = wil_to_ndev(wil);
 	struct device *dev = wil_to_dev(wil);
 	struct vring *vring = &wil->vring_tx[ringid];
+	int done = 0;
 
 	if (!vring->va) {
 		wil_err(wil, "Tx irq[%d]: vring not initialized\n", ringid);
-		return;
+		return 0;
 	}
 
 	wil_dbg_txrx(wil, "%s(%d)\n", __func__, ringid);
 
 	while (!wil_vring_is_empty(vring)) {
-		volatile struct vring_tx_desc *d1 =
+		volatile struct vring_tx_desc *_d =
 					      &vring->va[vring->swtail].tx;
 		struct vring_tx_desc dd, *d = &dd;
 		dma_addr_t pa;
 		struct sk_buff *skb;
+		u16 dmalen;
 
-		dd = *d1;
+		*d = *_d;
 
 		if (!(d->dma.status & TX_DMA_STATUS_DU))
 			break;
 
+		dmalen = le16_to_cpu(d->dma.length);
+		trace_wil6210_tx_done(ringid, vring->swtail, dmalen,
+				      d->dma.error);
 		wil_dbg_txrx(wil,
 			     "Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n",
-			     vring->swtail, d->dma.length, d->dma.status,
+			     vring->swtail, dmalen, d->dma.status,
 			     d->dma.error);
 		wil_hex_dump_txrx("TxC ", DUMP_PREFIX_NONE, 32, 4,
 				  (const void *)d, sizeof(*d), false);
 
-		pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32);
+		pa = wil_desc_addr(&d->dma.addr);
 		skb = vring->ctx[vring->swtail];
 		if (skb) {
 			if (d->dma.error == 0) {
@@ -815,18 +849,21 @@ void wil_tx_complete(struct wil6210_priv *wil, int ringid)
 				ndev->stats.tx_errors++;
 			}
 
-			dma_unmap_single(dev, pa, d->dma.length, DMA_TO_DEVICE);
+			dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE);
 			dev_kfree_skb_any(skb);
 			vring->ctx[vring->swtail] = NULL;
 		} else {
-			dma_unmap_page(dev, pa, d->dma.length, DMA_TO_DEVICE);
+			dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE);
 		}
-		d->dma.addr_low = 0;
-		d->dma.addr_high = 0;
+		d->dma.addr.addr_low = 0;
+		d->dma.addr.addr_high = 0;
 		d->dma.length = 0;
 		d->dma.status = TX_DMA_STATUS_DU;
 		vring->swtail = wil_vring_next_tail(vring);
+		done++;
 	}
 	if (wil_vring_avail_tx(vring) > vring->size/4)
 		netif_tx_wake_all_queues(wil_to_ndev(wil));
+
+	return done;
 }