summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/wil6210/txrx.c
diff options
context:
space:
mode:
authorMaya Erez <qca_merez@qca.qualcomm.com>2016-05-16 21:23:32 +0200
committerKalle Valo <kvalo@qca.qualcomm.com>2016-05-28 10:19:17 +0200
commit34b8886e502a62d1355ccc0420044aa2749a24cd (patch)
treee87a31e3f8a4571cc4b50ee8673f36b7c2051805 /drivers/net/wireless/ath/wil6210/txrx.c
parentwil6210: guarantee safe access to rx descriptors shared memory (diff)
downloadlinux-34b8886e502a62d1355ccc0420044aa2749a24cd.tar.xz
linux-34b8886e502a62d1355ccc0420044aa2749a24cd.zip
wil6210: protect wil_vring_fini_tx in parallel to tx completions
napi_synchronize is called before releasing the vring, with the assumption that setting txdata->enabled to 0 will prevent handling of this vring in the next scheduled napi. To guarantee this assumption, a memory barrier is added after disabling the txdata. In addition, as the ctx is zeroed in wil_tx_complete after this descriptor is handled (protected by wmb), ctx needs to be checked before releasing this descriptor in wil_vring_free. Signed-off-by: Maya Erez <qca_merez@qca.qualcomm.com> Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Diffstat (limited to 'drivers/net/wireless/ath/wil6210/txrx.c')
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c14
1 files changed, 14 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index 3909af171bad..483e0634041c 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -184,6 +184,13 @@ static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring,
&vring->va[vring->swtail].tx;
ctx = &vring->ctx[vring->swtail];
+ if (!ctx) {
+ wil_dbg_txrx(wil,
+ "ctx(%d) was already completed\n",
+ vring->swtail);
+ vring->swtail = wil_vring_next_tail(vring);
+ continue;
+ }
*d = *_d;
wil_txdesc_unmap(dev, d, ctx);
if (ctx->skb)
@@ -975,6 +982,13 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
txdata->dot1x_open = false;
txdata->enabled = 0; /* no Tx can be in progress or start anew */
spin_unlock_bh(&txdata->lock);
+ /* napi_synchronize waits for completion of the current NAPI but will
+ * not prevent the next NAPI run.
+ * Add a memory barrier to guarantee that txdata->enabled is zeroed
+ * before napi_synchronize so that the next scheduled NAPI will not
+ * handle this vring
+ */
+ wmb();
/* make sure NAPI won't touch this vring */
if (test_bit(wil_status_napi_en, wil->status))
napi_synchronize(&wil->napi_tx);