浏览代码

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>
Maya Erez 9 年之前
父节点
当前提交
34b8886e50
共有 1 个文件被更改,包括 14 次插入0 次删除
  1. 14 0
      drivers/net/wireless/ath/wil6210/txrx.c

+ 14 - 0
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;
 					&vring->va[vring->swtail].tx;
 
 
 			ctx = &vring->ctx[vring->swtail];
 			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;
 			*d = *_d;
 			wil_txdesc_unmap(dev, d, ctx);
 			wil_txdesc_unmap(dev, d, ctx);
 			if (ctx->skb)
 			if (ctx->skb)
@@ -975,6 +982,13 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
 	txdata->dot1x_open = false;
 	txdata->dot1x_open = false;
 	txdata->enabled = 0; /* no Tx can be in progress or start anew */
 	txdata->enabled = 0; /* no Tx can be in progress or start anew */
 	spin_unlock_bh(&txdata->lock);
 	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 */
 	/* make sure NAPI won't touch this vring */
 	if (test_bit(wil_status_napi_en, wil->status))
 	if (test_bit(wil_status_napi_en, wil->status))
 		napi_synchronize(&wil->napi_tx);
 		napi_synchronize(&wil->napi_tx);