diff options
| author | Jakub Kicinski <kuba@kernel.org> | 2025-12-01 14:30:09 -0800 |
|---|---|---|
| committer | Jakub Kicinski <kuba@kernel.org> | 2025-12-01 14:30:09 -0800 |
| commit | 4e3583cb61a9e1306bbc8146c891292405003d9e (patch) | |
| tree | 672598495c6221dd7dac84278640f5e04d43f217 | |
| parent | aee0f01b4f118844cb126a5f27e91c2adf087c59 (diff) | |
| parent | ab96af7004c76de5fdca077b1e3732a7ec96f69b (diff) | |
Merge branch 'amd-xgbe-schedule-napi-on-rbu-event'
Raju Rangoju says:
====================
amd-xgbe: schedule NAPI on RBU event
During the RX overload the Rx buffers may not be refilled, trying to
schedule the NAPI when an Rx Buffer Unavailable is signaled may help in
improving the such situation, in case we missed an IRQ.
====================
Link: https://patch.msgid.link/20251129175016.3034185-1-Raju.Rangoju@amd.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
| -rw-r--r-- | drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 71 |
1 files changed, 51 insertions, 20 deletions
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 0653e69f0ef7..3ddd896d6987 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -367,10 +367,11 @@ static irqreturn_t xgbe_ecc_isr(int irq, void *data) static void xgbe_isr_bh_work(struct work_struct *work) { struct xgbe_prv_data *pdata = from_work(pdata, work, dev_bh_work); + unsigned int mac_isr, mac_tssr, mac_mdioisr; struct xgbe_hw_if *hw_if = &pdata->hw_if; - struct xgbe_channel *channel; + bool per_ch_irq, ti, ri, rbu, fbe; unsigned int dma_isr, dma_ch_isr; - unsigned int mac_isr, mac_tssr, mac_mdioisr; + struct xgbe_channel *channel; unsigned int i; /* The DMA interrupt status register also reports MAC and MTL @@ -384,43 +385,73 @@ static void xgbe_isr_bh_work(struct work_struct *work) netif_dbg(pdata, intr, pdata->netdev, "DMA_ISR=%#010x\n", dma_isr); for (i = 0; i < pdata->channel_count; i++) { + bool schedule_napi = false; + struct napi_struct *napi; + if (!(dma_isr & (1 << i))) continue; channel = pdata->channel[i]; dma_ch_isr = XGMAC_DMA_IOREAD(channel, DMA_CH_SR); + + /* Precompute flags once */ + ti = !!XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, TI); + ri = !!XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, RI); + rbu = !!XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, RBU); + fbe = !!XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, FBE); + netif_dbg(pdata, intr, pdata->netdev, "DMA_CH%u_ISR=%#010x\n", i, dma_ch_isr); - /* The TI or RI interrupt bits may still be set even if using - * per channel DMA interrupts. Check to be sure those are not - * enabled before using the private data napi structure. + per_ch_irq = pdata->per_channel_irq; + + /* + * Decide which NAPI to use and whether to schedule: + * - When not using per-channel IRQs: schedule on global NAPI + * if TI or RI are set. + * - RBU should also trigger NAPI (either per-channel or global) + * to allow refill. */ - if (!pdata->per_channel_irq && - (XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, TI) || - XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, RI))) { - if (napi_schedule_prep(&pdata->napi)) { - /* Disable Tx and Rx interrupts */ - xgbe_disable_rx_tx_ints(pdata); + if (!per_ch_irq && (ti || ri)) + schedule_napi = true; - /* Turn on polling */ - __napi_schedule(&pdata->napi); + if (rbu) { + schedule_napi = true; + pdata->ext_stats.rx_buffer_unavailable++; + } + + napi = per_ch_irq ? &channel->napi : &pdata->napi; + + if (schedule_napi && napi_schedule_prep(napi)) { + /* Disable interrupts appropriately before polling */ + if (per_ch_irq) { + if (pdata->channel_irq_mode) + xgbe_disable_rx_tx_int(pdata, channel); + else + disable_irq_nosync(channel->dma_irq); + } else { + xgbe_disable_rx_tx_ints(pdata); } + + /* Turn on polling */ + __napi_schedule(napi); } else { - /* Don't clear Rx/Tx status if doing per channel DMA - * interrupts, these will be cleared by the ISR for - * per channel DMA interrupts. + /* + * Don't clear Rx/Tx status if doing per-channel DMA + * interrupts; those bits will be serviced/cleared by + * the per-channel ISR/NAPI. In non-per-channel mode + * when we're not scheduling NAPI here, ensure we don't + * accidentally clear TI/RI in HW: zero them in the + * local copy so that the eventual write-back does not + * clear TI/RI. */ XGMAC_SET_BITS(dma_ch_isr, DMA_CH_SR, TI, 0); XGMAC_SET_BITS(dma_ch_isr, DMA_CH_SR, RI, 0); } - if (XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, RBU)) - pdata->ext_stats.rx_buffer_unavailable++; - /* Restart the device on a Fatal Bus Error */ - if (XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, FBE)) + if (fbe) schedule_work(&pdata->restart_work); /* Clear interrupt signals */ |
