diff --git a/pci.c b/pci.c index 155f463..c4de554 100644 --- a/pci.c +++ b/pci.c @@ -593,44 +593,32 @@ static void rtw89_pci_isr_rxd_unavail(struct rtw89_dev *rtwdev, } } -static void rtw89_pci_clear_intrs(struct rtw89_dev *rtwdev, - struct rtw89_pci *rtwpci) -{ - rtw89_write32(rtwdev, R_AX_HISR0, rtwpci->halt_c2h_isrs); - rtw89_write32(rtwdev, R_AX_PCIE_HISR00, rtwpci->isrs[0]); - rtw89_write32(rtwdev, R_AX_PCIE_HISR10, rtwpci->isrs[1]); -} - static void rtw89_pci_recognize_intrs(struct rtw89_dev *rtwdev, - struct rtw89_pci *rtwpci) + struct rtw89_pci *rtwpci, + struct rtw89_pci_isrs *isrs) { - rtwpci->halt_c2h_isrs = rtw89_read32(rtwdev, R_AX_HISR0) & rtwpci->halt_c2h_intrs; - rtwpci->isrs[0] = rtw89_read32(rtwdev, R_AX_PCIE_HISR00) & rtwpci->intrs[0]; - rtwpci->isrs[1] = rtw89_read32(rtwdev, R_AX_PCIE_HISR10) & rtwpci->intrs[1]; + isrs->halt_c2h_isrs = rtw89_read32(rtwdev, R_AX_HISR0) & rtwpci->halt_c2h_intrs; + isrs->isrs[0] = rtw89_read32(rtwdev, R_AX_PCIE_HISR00) & rtwpci->intrs[0]; + isrs->isrs[1] = rtw89_read32(rtwdev, R_AX_PCIE_HISR10) & rtwpci->intrs[1]; + + rtw89_write32(rtwdev, R_AX_HISR0, isrs->halt_c2h_isrs); + rtw89_write32(rtwdev, R_AX_PCIE_HISR00, isrs->isrs[0]); + rtw89_write32(rtwdev, R_AX_PCIE_HISR10, isrs->isrs[1]); } static void rtw89_pci_enable_intr(struct rtw89_dev *rtwdev, - struct rtw89_pci *rtwpci) + struct rtw89_pci *rtwpci, bool exclude_rx) { + if (exclude_rx || test_bit(RTW89_PCI_FLAG_DOING_RX, rtwpci->flags)) + rtwpci->intrs[0] &= ~B_AX_RXDMA_INTS_MASK; + else + rtwpci->intrs[0] |= B_AX_RXDMA_INTS_MASK; + rtw89_write32(rtwdev, R_AX_HIMR0, rtwpci->halt_c2h_intrs); rtw89_write32(rtwdev, R_AX_PCIE_HIMR00, rtwpci->intrs[0]); rtw89_write32(rtwdev, R_AX_PCIE_HIMR10, rtwpci->intrs[1]); } -static void rtw89_pci_enable_intr_unmask0(struct rtw89_dev *rtwdev, - struct rtw89_pci *rtwpci, u32 unmask0) -{ - rtwpci->intrs[0] &= ~unmask0; - rtw89_pci_enable_intr(rtwdev, rtwpci); -} - -static void rtw89_pci_enable_intr_mask0(struct rtw89_dev *rtwdev, - struct rtw89_pci *rtwpci, u32 mask0) -{ - rtwpci->intrs[0] |= mask0; - rtw89_pci_enable_intr(rtwdev, rtwpci); -} - static void rtw89_pci_disable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci) { @@ -639,54 +627,45 @@ static void rtw89_pci_disable_intr(struct rtw89_dev *rtwdev, rtw89_write32(rtwdev, R_AX_PCIE_HIMR10, 0); } -static void rtw89_pci_try_napi_schedule(struct rtw89_dev *rtwdev, u32 *unmask0_rx) -{ - if (*unmask0_rx && !napi_reschedule(&rtwdev->napi)) { - /* if can't invoke napi, RX_IMR must be off already */ - *unmask0_rx = 0; - } -} - static irqreturn_t rtw89_pci_interrupt_threadfn(int irq, void *dev) { struct rtw89_dev *rtwdev = dev; struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; - u32 isrs[2]; + struct rtw89_pci_isrs isrs; unsigned long flags; - u32 unmask0_rx = 0; + bool rx = false; - isrs[0] = rtwpci->isrs[0]; - isrs[1] = rtwpci->isrs[1]; + spin_lock_irqsave(&rtwpci->irq_lock, flags); + rtw89_pci_recognize_intrs(rtwdev, rtwpci, &isrs); + spin_unlock_irqrestore(&rtwpci->irq_lock, flags); /* TX ISR */ - if (isrs[0] & B_AX_TXDMA_CH12_INT) + if (isrs.isrs[0] & B_AX_TXDMA_CH12_INT) rtw89_pci_isr_txch_dma(rtwdev, rtwpci, RTW89_TXCH_CH12); /* RX ISR */ - if (isrs[0] & (B_AX_RXDMA_INT | B_AX_RXP1DMA_INT)) - unmask0_rx = B_AX_RXDMA_INTS_MASK; - if (isrs[0] & B_AX_RPQDMA_INT) + if (isrs.isrs[0] & (B_AX_RXDMA_INT | B_AX_RXP1DMA_INT)) + rx = true; + if (isrs.isrs[0] & B_AX_RPQDMA_INT) rtw89_pci_isr_rpq_dma(rtwdev, rtwpci); - if (isrs[0] & B_AX_RDU_INT) { + if (isrs.isrs[0] & B_AX_RDU_INT) { rtw89_pci_isr_rxd_unavail(rtwdev, rtwpci); - unmask0_rx = B_AX_RXDMA_INTS_MASK; + rx = true; } - if (rtwpci->halt_c2h_isrs & B_AX_HALT_C2H_INT_EN) + if (isrs.halt_c2h_isrs & B_AX_HALT_C2H_INT_EN) rtw89_ser_notify(rtwdev, rtw89_mac_get_err_status(rtwdev)); - /* invoke napi and disable rx_imr within bh_disable, because we must - * ensure napi_poll re-enable rx_imr after this. - */ - local_bh_disable(); spin_lock_irqsave(&rtwpci->irq_lock, flags); - rtw89_pci_try_napi_schedule(rtwdev, &unmask0_rx); - if (rtwpci->running) { - rtw89_pci_clear_intrs(rtwdev, rtwpci); - rtw89_pci_enable_intr_unmask0(rtwdev, rtwpci, unmask0_rx); - } + if (likely(rtwpci->running)) + rtw89_pci_enable_intr(rtwdev, rtwpci, rx); spin_unlock_irqrestore(&rtwpci->irq_lock, flags); - local_bh_enable(); + + if (likely(rtwpci->running) && rx) { + local_bh_disable(); + napi_schedule(&rtwdev->napi); + local_bh_enable(); + } return IRQ_HANDLED; } @@ -696,22 +675,23 @@ static irqreturn_t rtw89_pci_interrupt_handler(int irq, void *dev) struct rtw89_dev *rtwdev = dev; struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; unsigned long flags; + irqreturn_t irqret = IRQ_WAKE_THREAD; + + spin_lock_irqsave(&rtwpci->irq_lock, flags); /* If interrupt event is on the road, it is still trigger interrupt * even we have done pci_stop() to turn off IMR. */ - if (!rtwpci->running) - return IRQ_HANDLED; + if (unlikely(!rtwpci->running)) { + irqret = IRQ_HANDLED; + goto exit; + } - /* Disable interrupt here to avoid more interrupts being issued before - * the threadfn ends. - */ - spin_lock_irqsave(&rtwpci->irq_lock, flags); rtw89_pci_disable_intr(rtwdev, rtwpci); - rtw89_pci_recognize_intrs(rtwdev, rtwpci); +exit: spin_unlock_irqrestore(&rtwpci->irq_lock, flags); - return IRQ_WAKE_THREAD; + return irqret; } #define case_TXCHADDRS(txch) \ @@ -1197,7 +1177,8 @@ static int rtw89_pci_ops_start(struct rtw89_dev *rtwdev) spin_lock_irqsave(&rtwpci->irq_lock, flags); rtwpci->running = true; - rtw89_pci_enable_intr_mask0(rtwdev, rtwpci, B_AX_RXDMA_INTS_MASK); + clear_bit(RTW89_PCI_FLAG_DOING_RX, rtwpci->flags); + rtw89_pci_enable_intr(rtwdev, rtwpci, false); spin_unlock_irqrestore(&rtwpci->irq_lock, flags); return 0; @@ -2808,6 +2789,8 @@ static int rtw89_pci_napi_poll(struct napi_struct *napi, int budget) u32 cnt; int ret; + set_bit(RTW89_PCI_FLAG_DOING_RX, rtwpci->flags); + ret = rtw89_pci_poll_rxq_dma(rtwdev, rtwpci, budget); if (ret < budget) { napi_complete_done(napi, ret); @@ -2817,10 +2800,9 @@ static int rtw89_pci_napi_poll(struct napi_struct *napi, int budget) return ret; spin_lock_irqsave(&rtwpci->irq_lock, flags); - if (rtwpci->running) { - rtw89_pci_clear_intrs(rtwdev, rtwpci); - rtw89_pci_enable_intr_mask0(rtwdev, rtwpci, B_AX_RXDMA_INTS_MASK); - } + clear_bit(RTW89_PCI_FLAG_DOING_RX, rtwpci->flags); + if (likely(rtwpci->running)) + rtw89_pci_enable_intr(rtwdev, rtwpci, false); spin_unlock_irqrestore(&rtwpci->irq_lock, flags); } diff --git a/pci.h b/pci.h index 353ecc6..cdc1f0c 100644 --- a/pci.h +++ b/pci.h @@ -356,6 +356,12 @@ enum rtw89_pcie_clkdly_hw { PCIE_CLKDLY_HW_200US = 0x5 }; +enum rtw89_pci_flags { + RTW89_PCI_FLAG_DOING_RX, + + NUM_OF_RTW89_PCI_FLAGS +}; + struct rtw89_pci_bd_ram { u8 start_idx; u8 max_num; @@ -491,6 +497,11 @@ struct rtw89_pci_rx_ring { struct rtw89_rx_desc_info diliver_desc; }; +struct rtw89_pci_isrs { + u32 halt_c2h_isrs; + u32 isrs[2]; +}; + struct rtw89_pci { struct pci_dev *pdev; @@ -499,14 +510,13 @@ struct rtw89_pci { /* protect TRX resources (exclude RXQ) */ spinlock_t trx_lock; bool running; + DECLARE_BITMAP(flags, NUM_OF_RTW89_PCI_FLAGS); struct rtw89_pci_tx_ring tx_rings[RTW89_TXCH_NUM]; struct rtw89_pci_rx_ring rx_rings[RTW89_RXCH_NUM]; struct sk_buff_head h2c_queue; - u32 halt_c2h_isrs; u32 halt_c2h_intrs; u32 intrs[2]; - u32 isrs[2]; u16 link_ctrl; void __iomem *mmap; };