aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/wil6210
diff options
context:
space:
mode:
authorVladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>2013-05-12 07:43:36 -0400
committerJohn W. Linville <linville@tuxdriver.com>2013-05-22 15:08:35 -0400
commite0287c4ab87905dd4a2e45cf791f8e0a87fe602e (patch)
treeedd55224fb599e71c7752c3df57e65b4dcffde81 /drivers/net/wireless/ath/wil6210
parent98658095623109bdace46f21bece028c904fb900 (diff)
wil6210: use NAPI
Introduce NAPI for Rx and Tx completion. This fixes packet reordering that happens when Rx handled right in the IRQ: netif_rx puts packet in 'percpu' queue, then network stack fetches packets from 'percpu' queues for processing, with different pattern of queue switching. As result, network stack see packets in different order. This causes hard to understand TCP throughput degradation in about 30min Complete polling if only one packet was processed - this eliminates empty polls that would be otherwise done at the end of each burst Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/wil6210')
-rw-r--r--drivers/net/wireless/ath/wil6210/interrupt.c23
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c6
-rw-r--r--drivers/net/wireless/ath/wil6210/netdev.c54
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c23
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h16
5 files changed, 94 insertions, 28 deletions
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c
index 5fe985cd3dfd..8205d3e4ab66 100644
--- a/drivers/net/wireless/ath/wil6210/interrupt.c
+++ b/drivers/net/wireless/ath/wil6210/interrupt.c
@@ -104,14 +104,14 @@ static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil)
104 clear_bit(wil_status_irqen, &wil->status); 104 clear_bit(wil_status_irqen, &wil->status);
105} 105}
106 106
107static void wil6210_unmask_irq_tx(struct wil6210_priv *wil) 107void wil6210_unmask_irq_tx(struct wil6210_priv *wil)
108{ 108{
109 iowrite32(WIL6210_IMC_TX, wil->csr + 109 iowrite32(WIL6210_IMC_TX, wil->csr +
110 HOSTADDR(RGF_DMA_EP_TX_ICR) + 110 HOSTADDR(RGF_DMA_EP_TX_ICR) +
111 offsetof(struct RGF_ICR, IMC)); 111 offsetof(struct RGF_ICR, IMC));
112} 112}
113 113
114static void wil6210_unmask_irq_rx(struct wil6210_priv *wil) 114void wil6210_unmask_irq_rx(struct wil6210_priv *wil)
115{ 115{
116 iowrite32(WIL6210_IMC_RX, wil->csr + 116 iowrite32(WIL6210_IMC_RX, wil->csr +
117 HOSTADDR(RGF_DMA_EP_RX_ICR) + 117 HOSTADDR(RGF_DMA_EP_RX_ICR) +
@@ -182,13 +182,14 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
182 if (isr & BIT_DMA_EP_RX_ICR_RX_DONE) { 182 if (isr & BIT_DMA_EP_RX_ICR_RX_DONE) {
183 wil_dbg_irq(wil, "RX done\n"); 183 wil_dbg_irq(wil, "RX done\n");
184 isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE; 184 isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE;
185 wil_rx_handle(wil); 185 wil_dbg_txrx(wil, "NAPI schedule\n");
186 napi_schedule(&wil->napi_rx);
186 } 187 }
187 188
188 if (isr) 189 if (isr)
189 wil_err(wil, "un-handled RX ISR bits 0x%08x\n", isr); 190 wil_err(wil, "un-handled RX ISR bits 0x%08x\n", isr);
190 191
191 wil6210_unmask_irq_rx(wil); 192 /* Rx IRQ will be enabled when NAPI processing finished */
192 193
193 return IRQ_HANDLED; 194 return IRQ_HANDLED;
194} 195}
@@ -211,23 +212,17 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
211 wil6210_mask_irq_tx(wil); 212 wil6210_mask_irq_tx(wil);
212 213
213 if (isr & BIT_DMA_EP_TX_ICR_TX_DONE) { 214 if (isr & BIT_DMA_EP_TX_ICR_TX_DONE) {
214 uint i;
215 wil_dbg_irq(wil, "TX done\n"); 215 wil_dbg_irq(wil, "TX done\n");
216 napi_schedule(&wil->napi_tx);
216 isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE; 217 isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE;
217 for (i = 0; i < 24; i++) { 218 /* clear also all VRING interrupts */
218 u32 mask = BIT_DMA_EP_TX_ICR_TX_DONE_N(i); 219 isr &= ~(BIT(25) - 1UL);
219 if (isr & mask) {
220 isr &= ~mask;
221 wil_dbg_irq(wil, "TX done(%i)\n", i);
222 wil_tx_complete(wil, i);
223 }
224 }
225 } 220 }
226 221
227 if (isr) 222 if (isr)
228 wil_err(wil, "un-handled TX ISR bits 0x%08x\n", isr); 223 wil_err(wil, "un-handled TX ISR bits 0x%08x\n", isr);
229 224
230 wil6210_unmask_irq_tx(wil); 225 /* Tx IRQ will be enabled when NAPI processing finished */
231 226
232 return IRQ_HANDLED; 227 return IRQ_HANDLED;
233} 228}
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index a0478e2f6868..ea49c8a18e15 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -365,6 +365,9 @@ static int __wil_up(struct wil6210_priv *wil)
365 /* Rx VRING. After MAC and beacon */ 365 /* Rx VRING. After MAC and beacon */
366 wil_rx_init(wil); 366 wil_rx_init(wil);
367 367
368 napi_enable(&wil->napi_rx);
369 napi_enable(&wil->napi_tx);
370
368 return 0; 371 return 0;
369} 372}
370 373
@@ -381,6 +384,9 @@ int wil_up(struct wil6210_priv *wil)
381 384
382static int __wil_down(struct wil6210_priv *wil) 385static int __wil_down(struct wil6210_priv *wil)
383{ 386{
387 napi_disable(&wil->napi_rx);
388 napi_disable(&wil->napi_tx);
389
384 if (wil->scan_request) { 390 if (wil->scan_request) {
385 cfg80211_scan_done(wil->scan_request, true); 391 cfg80211_scan_done(wil->scan_request, true);
386 wil->scan_request = NULL; 392 wil->scan_request = NULL;
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
index 098a8ec6b841..29dd1e58cb17 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -40,6 +40,55 @@ static const struct net_device_ops wil_netdev_ops = {
40 .ndo_validate_addr = eth_validate_addr, 40 .ndo_validate_addr = eth_validate_addr,
41}; 41};
42 42
43static int wil6210_netdev_poll_rx(struct napi_struct *napi, int budget)
44{
45 struct wil6210_priv *wil = container_of(napi, struct wil6210_priv,
46 napi_rx);
47 int quota = budget;
48 int done;
49
50 wil_rx_handle(wil, &quota);
51 done = budget - quota;
52
53 if (done <= 1) { /* burst ends - only one packet processed */
54 napi_complete(napi);
55 wil6210_unmask_irq_rx(wil);
56 wil_dbg_txrx(wil, "NAPI RX complete\n");
57 }
58
59 wil_dbg_txrx(wil, "NAPI RX poll(%d) done %d\n", budget, done);
60
61 return done;
62}
63
64static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget)
65{
66 struct wil6210_priv *wil = container_of(napi, struct wil6210_priv,
67 napi_tx);
68 int tx_done = 0;
69 uint i;
70
71 /* always process ALL Tx complete, regardless budget - it is fast */
72 for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
73 struct vring *vring = &wil->vring_tx[i];
74
75 if (!vring->va)
76 continue;
77
78 tx_done += wil_tx_complete(wil, i);
79 }
80
81 if (tx_done <= 1) { /* burst ends - only one packet processed */
82 napi_complete(napi);
83 wil6210_unmask_irq_tx(wil);
84 wil_dbg_txrx(wil, "NAPI TX complete\n");
85 }
86
87 wil_dbg_txrx(wil, "NAPI TX poll(%d) done %d\n", budget, tx_done);
88
89 return min(tx_done, budget);
90}
91
43void *wil_if_alloc(struct device *dev, void __iomem *csr) 92void *wil_if_alloc(struct device *dev, void __iomem *csr)
44{ 93{
45 struct net_device *ndev; 94 struct net_device *ndev;
@@ -81,6 +130,11 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr)
81 SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); 130 SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
82 wdev->netdev = ndev; 131 wdev->netdev = ndev;
83 132
133 netif_napi_add(ndev, &wil->napi_rx, wil6210_netdev_poll_rx,
134 WIL6210_NAPI_BUDGET);
135 netif_napi_add(ndev, &wil->napi_tx, wil6210_netdev_poll_tx,
136 WIL6210_NAPI_BUDGET);
137
84 wil_link_off(wil); 138 wil_link_off(wil);
85 139
86 return wil; 140 return wil;
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index dc183d573c08..bab50117383a 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -440,6 +440,7 @@ static int wil_rx_refill(struct wil6210_priv *wil, int count)
440 440
441/* 441/*
442 * Pass Rx packet to the netif. Update statistics. 442 * Pass Rx packet to the netif. Update statistics.
443 * Called in softirq context (NAPI poll).
443 */ 444 */
444static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) 445static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
445{ 446{
@@ -448,10 +449,7 @@ static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
448 449
449 skb_orphan(skb); 450 skb_orphan(skb);
450 451
451 if (in_interrupt()) 452 rc = netif_receive_skb(skb);
452 rc = netif_rx(skb);
453 else
454 rc = netif_rx_ni(skb);
455 453
456 if (likely(rc == NET_RX_SUCCESS)) { 454 if (likely(rc == NET_RX_SUCCESS)) {
457 ndev->stats.rx_packets++; 455 ndev->stats.rx_packets++;
@@ -465,9 +463,9 @@ static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
465/** 463/**
466 * Proceed all completed skb's from Rx VRING 464 * Proceed all completed skb's from Rx VRING
467 * 465 *
468 * Safe to call from IRQ 466 * Safe to call from NAPI poll, i.e. softirq with interrupts enabled
469 */ 467 */
470void wil_rx_handle(struct wil6210_priv *wil) 468void wil_rx_handle(struct wil6210_priv *wil, int *quota)
471{ 469{
472 struct net_device *ndev = wil_to_ndev(wil); 470 struct net_device *ndev = wil_to_ndev(wil);
473 struct vring *v = &wil->vring_rx; 471 struct vring *v = &wil->vring_rx;
@@ -478,7 +476,8 @@ void wil_rx_handle(struct wil6210_priv *wil)
478 return; 476 return;
479 } 477 }
480 wil_dbg_txrx(wil, "%s()\n", __func__); 478 wil_dbg_txrx(wil, "%s()\n", __func__);
481 while (NULL != (skb = wil_vring_reap_rx(wil, v))) { 479 while ((*quota > 0) && (NULL != (skb = wil_vring_reap_rx(wil, v)))) {
480 (*quota)--;
482 481
483 if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) { 482 if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) {
484 skb->dev = ndev; 483 skb->dev = ndev;
@@ -788,17 +787,20 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
788/** 787/**
789 * Clean up transmitted skb's from the Tx VRING 788 * Clean up transmitted skb's from the Tx VRING
790 * 789 *
790 * Return number of descriptors cleared
791 *
791 * Safe to call from IRQ 792 * Safe to call from IRQ
792 */ 793 */
793void wil_tx_complete(struct wil6210_priv *wil, int ringid) 794int wil_tx_complete(struct wil6210_priv *wil, int ringid)
794{ 795{
795 struct net_device *ndev = wil_to_ndev(wil); 796 struct net_device *ndev = wil_to_ndev(wil);
796 struct device *dev = wil_to_dev(wil); 797 struct device *dev = wil_to_dev(wil);
797 struct vring *vring = &wil->vring_tx[ringid]; 798 struct vring *vring = &wil->vring_tx[ringid];
799 int done = 0;
798 800
799 if (!vring->va) { 801 if (!vring->va) {
800 wil_err(wil, "Tx irq[%d]: vring not initialized\n", ringid); 802 wil_err(wil, "Tx irq[%d]: vring not initialized\n", ringid);
801 return; 803 return 0;
802 } 804 }
803 805
804 wil_dbg_txrx(wil, "%s(%d)\n", __func__, ringid); 806 wil_dbg_txrx(wil, "%s(%d)\n", __func__, ringid);
@@ -847,7 +849,10 @@ void wil_tx_complete(struct wil6210_priv *wil, int ringid)
847 d->dma.length = 0; 849 d->dma.length = 0;
848 d->dma.status = TX_DMA_STATUS_DU; 850 d->dma.status = TX_DMA_STATUS_DU;
849 vring->swtail = wil_vring_next_tail(vring); 851 vring->swtail = wil_vring_next_tail(vring);
852 done++;
850 } 853 }
851 if (wil_vring_avail_tx(vring) > vring->size/4) 854 if (wil_vring_avail_tx(vring) > vring->size/4)
852 netif_tx_wake_all_queues(wil_to_ndev(wil)); 855 netif_tx_wake_all_queues(wil_to_ndev(wil));
856
857 return done;
853} 858}
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 484446e66c5a..2e3c26e1c975 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -34,9 +34,11 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1)
34 34
35#define WIL6210_MEM_SIZE (2*1024*1024UL) 35#define WIL6210_MEM_SIZE (2*1024*1024UL)
36 36
37#define WIL6210_RX_RING_SIZE (128) 37#define WIL6210_RX_RING_SIZE (128)
38#define WIL6210_TX_RING_SIZE (128) 38#define WIL6210_TX_RING_SIZE (128)
39#define WIL6210_MAX_TX_RINGS (24) 39#define WIL6210_MAX_TX_RINGS (24) /* HW limit */
40#define WIL6210_MAX_CID (8) /* HW limit */
41#define WIL6210_NAPI_BUDGET (16) /* arbitrary */
40 42
41/* Hardware definitions begin */ 43/* Hardware definitions begin */
42 44
@@ -239,6 +241,8 @@ struct wil6210_priv {
239 * - consumed in thread by wmi_event_worker 241 * - consumed in thread by wmi_event_worker
240 */ 242 */
241 spinlock_t wmi_ev_lock; 243 spinlock_t wmi_ev_lock;
244 struct napi_struct napi_rx;
245 struct napi_struct napi_tx;
242 /* DMA related */ 246 /* DMA related */
243 struct vring vring_rx; 247 struct vring vring_rx;
244 struct vring vring_tx[WIL6210_MAX_TX_RINGS]; 248 struct vring vring_tx[WIL6210_MAX_TX_RINGS];
@@ -360,10 +364,12 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
360void wil_vring_fini_tx(struct wil6210_priv *wil, int id); 364void wil_vring_fini_tx(struct wil6210_priv *wil, int id);
361 365
362netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev); 366netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev);
363void wil_tx_complete(struct wil6210_priv *wil, int ringid); 367int wil_tx_complete(struct wil6210_priv *wil, int ringid);
368void wil6210_unmask_irq_tx(struct wil6210_priv *wil);
364 369
365/* RX API */ 370/* RX API */
366void wil_rx_handle(struct wil6210_priv *wil); 371void wil_rx_handle(struct wil6210_priv *wil, int *quota);
372void wil6210_unmask_irq_rx(struct wil6210_priv *wil);
367 373
368int wil_iftype_nl2wmi(enum nl80211_iftype type); 374int wil_iftype_nl2wmi(enum nl80211_iftype type);
369 375