Commit 7bd3760c authored by Po-Hao Huang's avatar Po-Hao Huang Committed by Kalle Valo

rtw88: refine napi deinit flow

We used to stop napi before disabling irqs. And it turns out
to cause some problem when we try to stop device while interrupt arrives.

To safely stop pci, we do three steps:
1. disable interrupt
2. synchronize_irq
3. stop_napi
Since step 2 and 3 may not finish as expected when interrupt is enabled,
use rtwpci->running to decide whether interrupt should be re-enabled at
the time.

Fixes: 9e2fd298 ("rtw88: add napi support")
Signed-off-by: default avatarPo-Hao Huang <phhuang@realtek.com>
Signed-off-by: default avatarPing-Ke Shih <pkshih@realtek.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/20210415084703.27255-4-pkshih@realtek.com
parent a548909d
......@@ -581,23 +581,30 @@ static int rtw_pci_start(struct rtw_dev *rtwdev)
{
struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
rtw_pci_napi_start(rtwdev);
spin_lock_bh(&rtwpci->irq_lock);
rtwpci->running = true;
rtw_pci_enable_interrupt(rtwdev, rtwpci, false);
spin_unlock_bh(&rtwpci->irq_lock);
rtw_pci_napi_start(rtwdev);
return 0;
}
static void rtw_pci_stop(struct rtw_dev *rtwdev)
{
struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
struct pci_dev *pdev = rtwpci->pdev;
spin_lock_bh(&rtwpci->irq_lock);
rtwpci->running = false;
rtw_pci_disable_interrupt(rtwdev, rtwpci);
spin_unlock_bh(&rtwpci->irq_lock);
synchronize_irq(pdev->irq);
rtw_pci_napi_stop(rtwdev);
spin_lock_bh(&rtwpci->irq_lock);
rtw_pci_disable_interrupt(rtwdev, rtwpci);
rtw_pci_dma_release(rtwdev, rtwpci);
spin_unlock_bh(&rtwpci->irq_lock);
}
......@@ -1212,7 +1219,8 @@ static irqreturn_t rtw_pci_interrupt_threadfn(int irq, void *dev)
rtw_fw_c2h_cmd_isr(rtwdev);
/* all of the jobs for this interrupt have been done */
rtw_pci_enable_interrupt(rtwdev, rtwpci, rx);
if (rtwpci->running)
rtw_pci_enable_interrupt(rtwdev, rtwpci, rx);
spin_unlock_bh(&rtwpci->irq_lock);
return IRQ_HANDLED;
......@@ -1633,7 +1641,8 @@ static int rtw_pci_napi_poll(struct napi_struct *napi, int budget)
if (work_done < budget) {
napi_complete_done(napi, work_done);
spin_lock_bh(&rtwpci->irq_lock);
rtw_pci_enable_interrupt(rtwdev, rtwpci, false);
if (rtwpci->running)
rtw_pci_enable_interrupt(rtwdev, rtwpci, false);
spin_unlock_bh(&rtwpci->irq_lock);
/* When ISR happens during polling and before napi_complete
* while no further data is received. Data on the dma_ring will
......
......@@ -211,6 +211,7 @@ struct rtw_pci {
spinlock_t irq_lock;
u32 irq_mask[4];
bool irq_enabled;
bool running;
/* napi structure */
struct net_device netdev;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment