summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/realtek/rtw88/pci.c
diff options
context:
space:
mode:
authorPo-Hao Huang <phhuang@realtek.com>2021-04-15 16:47:03 +0800
committerKalle Valo <kvalo@codeaurora.org>2021-04-21 12:37:50 +0300
commit7bd3760c71f7a18485d2c10ea0887e1d41519f4e (patch)
treea6a1e9d7a062704bfbec60d1442ca788029562a0 /drivers/net/wireless/realtek/rtw88/pci.c
parenta548909d7ad7e334c6c923a71f0b694d60980232 (diff)
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: 9e2fd29864c5 ("rtw88: add napi support") Signed-off-by: Po-Hao Huang <phhuang@realtek.com> Signed-off-by: Ping-Ke Shih <pkshih@realtek.com> Signed-off-by: Kalle Valo <kvalo@codeaurora.org> Link: https://lore.kernel.org/r/20210415084703.27255-4-pkshih@realtek.com
Diffstat (limited to 'drivers/net/wireless/realtek/rtw88/pci.c')
-rw-r--r--drivers/net/wireless/realtek/rtw88/pci.c19
1 files changed, 14 insertions, 5 deletions
diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c
index adea3c7551ab..f59a4c462e3b 100644
--- a/drivers/net/wireless/realtek/rtw88/pci.c
+++ b/drivers/net/wireless/realtek/rtw88/pci.c
@@ -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