Re: [net-next PATCH v2 4/4] netdev: use napi_schedule bool instead of napi_schedule_prep/__napi_schedule

From: Christian Marangi
Date: Fri Oct 06 2023 - 14:49:50 EST


On Thu, Oct 05, 2023 at 06:16:26PM +0200, Eric Dumazet wrote:
> On Tue, Oct 3, 2023 at 8:36 PM Christian Marangi <ansuelsmth@xxxxxxxxx> wrote:
> >
> > Replace if condition of napi_schedule_prep/__napi_schedule and use bool
> > from napi_schedule directly where possible.
> >
> > Signed-off-by: Christian Marangi <ansuelsmth@xxxxxxxxx>
> > ---
> > drivers/net/ethernet/atheros/atlx/atl1.c | 4 +---
> > drivers/net/ethernet/toshiba/tc35815.c | 4 +---
> > drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 4 +---
> > 3 files changed, 3 insertions(+), 9 deletions(-)
> >
> > diff --git a/drivers/net/ethernet/atheros/atlx/atl1.c b/drivers/net/ethernet/atheros/atlx/atl1.c
> > index 02aa6fd8ebc2..a9014d7932db 100644
> > --- a/drivers/net/ethernet/atheros/atlx/atl1.c
> > +++ b/drivers/net/ethernet/atheros/atlx/atl1.c
> > @@ -2446,7 +2446,7 @@ static int atl1_rings_clean(struct napi_struct *napi, int budget)
> >
> > static inline int atl1_sched_rings_clean(struct atl1_adapter* adapter)
> > {
> > - if (!napi_schedule_prep(&adapter->napi))
> > + if (!napi_schedule(&adapter->napi))
> > /* It is possible in case even the RX/TX ints are disabled via IMR
> > * register the ISR bits are set anyway (but do not produce IRQ).
> > * To handle such situation the napi functions used to check is
> > @@ -2454,8 +2454,6 @@ static inline int atl1_sched_rings_clean(struct atl1_adapter* adapter)
> > */
> > return 0;
> >
> > - __napi_schedule(&adapter->napi);
> > -
> > /*
> > * Disable RX/TX ints via IMR register if it is
> > * allowed. NAPI handler must reenable them in same
> > diff --git a/drivers/net/ethernet/toshiba/tc35815.c b/drivers/net/ethernet/toshiba/tc35815.c
> > index 14cf6ecf6d0d..a8b8a0e13f9a 100644
> > --- a/drivers/net/ethernet/toshiba/tc35815.c
> > +++ b/drivers/net/ethernet/toshiba/tc35815.c
> > @@ -1436,9 +1436,7 @@ static irqreturn_t tc35815_interrupt(int irq, void *dev_id)
> > if (!(dmactl & DMA_IntMask)) {
> > /* disable interrupts */
> > tc_writel(dmactl | DMA_IntMask, &tr->DMA_Ctl);
> > - if (napi_schedule_prep(&lp->napi))
> > - __napi_schedule(&lp->napi);
> > - else {
> > + if (!napi_schedule(&lp->napi)) {
> > printk(KERN_ERR "%s: interrupt taken in poll\n",
> > dev->name);
> > BUG();
>
> Hmmm... could you also remove this BUG() ? I think this code path can be taken
> if some applications are using busy polling.
>
> Or simply rewrite this with the traditional
>
> if (napi_schedule_prep(&lp->napi)) {
> /* disable interrupts */
> tc_writel(dmactl | DMA_IntMask, &tr->DMA_Ctl);
> __napi_schedule(&lp->napi);
> }
>
>

Mhhh is it safe to do so? I mean it seems very wrong to print a warning
and BUG() instead of disabling the interrupt only if napi can be
scheduled... Maybe is very old code? The more I see this the more I see
problem... (randomly disabling the interrupt and then make the kernel
die)

>
> > diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
> > index 23b5a0adcbd6..146bc7bd14fb 100644
> > --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
> > +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
> > @@ -1660,9 +1660,7 @@ irqreturn_t iwl_pcie_irq_rx_msix_handler(int irq, void *dev_id)
> > IWL_DEBUG_ISR(trans, "[%d] Got interrupt\n", entry->entry);
> >
> > local_bh_disable();
> > - if (napi_schedule_prep(&rxq->napi))
> > - __napi_schedule(&rxq->napi);
> > - else
> > + if (!napi_schedule(&rxq->napi))
> > iwl_pcie_clear_irq(trans, entry->entry);
>
> Same remark here about twisted logic.
>

Ehhh here we need to be careful... We can do the usual prep/__schedule
with the DMA disable in between...

>From the comments of iwl_pcie_clear_irq.

/*
* Before sending the interrupt the HW disables it to prevent
* a nested interrupt. This is done by writing 1 to the corresponding
* bit in the mask register. After handling the interrupt, it should be
* re-enabled by clearing this bit. This register is defined as
* write 1 clear (W1C) register, meaning that it's being clear
* by writing 1 to the bit.
*/

So the device disable the interrupt after being fired and the bit needs
to set again for the interrupt to be reenabled. So the function
correctly reenable the irq if a napi can't be scheduled... Think there
isn't another way to handle this.

> > local_bh_enable();
> >
> > --
> > 2.40.1
> >

--
Ansuel