Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0fef1818 authored by Vladimir Kondratiev's avatar Vladimir Kondratiev Committed by John W. Linville
Browse files

wil6210: Fix kernel oops in reset flow



wil_reset() removes vring's
At the same time NAPI may be active performing Rx/Tx completion.
If this happens, Rx/Tx polling functions going to access already removed vrings

Make sure NAPI is idle and won't be started prior to vring removal.
For this, track NAPI enabled state

Signed-off-by: default avatarVladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 8bf6adb9
Loading
Loading
Loading
Loading
+12 −3
Original line number Diff line number Diff line
@@ -195,8 +195,12 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
	if (isr & BIT_DMA_EP_RX_ICR_RX_DONE) {
		wil_dbg_irq(wil, "RX done\n");
		isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE;
		wil_dbg_txrx(wil, "NAPI schedule\n");
		if (test_bit(wil_status_reset_done, &wil->status)) {
			wil_dbg_txrx(wil, "NAPI(Rx) schedule\n");
			napi_schedule(&wil->napi_rx);
		} else {
			wil_err(wil, "Got Rx interrupt while in reset\n");
		}
	}

	if (isr)
@@ -226,10 +230,15 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie)

	if (isr & BIT_DMA_EP_TX_ICR_TX_DONE) {
		wil_dbg_irq(wil, "TX done\n");
		napi_schedule(&wil->napi_tx);
		isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE;
		/* clear also all VRING interrupts */
		isr &= ~(BIT(25) - 1UL);
		if (test_bit(wil_status_reset_done, &wil->status)) {
			wil_dbg_txrx(wil, "NAPI(Tx) schedule\n");
			napi_schedule(&wil->napi_tx);
		} else {
			wil_err(wil, "Got Tx interrupt while in reset\n");
		}
	}

	if (isr)
+8 −1
Original line number Diff line number Diff line
@@ -329,11 +329,16 @@ int wil_reset(struct wil6210_priv *wil)
{
	int rc;

	wil->status = 0; /* prevent NAPI from being scheduled */
	if (test_bit(wil_status_napi_en, &wil->status)) {
		napi_synchronize(&wil->napi_rx);
		napi_synchronize(&wil->napi_tx);
	}

	cancel_work_sync(&wil->disconnect_worker);
	wil6210_disconnect(wil, NULL);

	wil6210_disable_irq(wil);
	wil->status = 0;

	wmi_event_flush(wil);

@@ -426,6 +431,7 @@ static int __wil_up(struct wil6210_priv *wil)

	napi_enable(&wil->napi_rx);
	napi_enable(&wil->napi_tx);
	set_bit(wil_status_napi_en, &wil->status);

	return 0;
}
@@ -443,6 +449,7 @@ int wil_up(struct wil6210_priv *wil)

static int __wil_down(struct wil6210_priv *wil)
{
	clear_bit(wil_status_napi_en, &wil->status);
	napi_disable(&wil->napi_rx);
	napi_disable(&wil->napi_tx);

+1 −0
Original line number Diff line number Diff line
@@ -249,6 +249,7 @@ enum { /* for wil6210_priv.status */
	wil_status_dontscan,
	wil_status_reset_done,
	wil_status_irqen, /* FIXME: interrupts enabled - for debug */
	wil_status_napi_en, /* NAPI enabled protected by wil->mutex */
};

struct pci_dev;