Re: DWC eDMA weirdness

Koichiro Den <[email protected]> Thu, 30 Jul 2026 17:39:46 +0900
Newsgroups org.kernel.vger.linux-pci
Message-ID <egai6rd3umstjhkuelrnemr2ywjlfccfk4tipaxodav426wxex@kuu76gvznusa>
On Wed, Jul 29, 2026 at 10:49:56PM +0200, Niklas Cassel wrote:
> On Wed, Jul 29, 2026 at 10:28:22PM +0200, Niklas Cassel wrote:
> > Getting two IRQs when we are only expecting a single IRQ is a very
> > serious error, and suggests that something is very wrong in the EPC
> > driver.
> > 
> > Scream loudly so that EPC driver developers can see the problem,
> > which might otherwise be very hard to detect.
> > 
> > Signed-off-by: Niklas Cassel <[email protected]>
> > ---
> >  drivers/misc/pci_endpoint_test.c | 13 +++++++++++++
> >  1 file changed, 13 insertions(+)
> > 
> > diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
> > index 3635741c3e7a..a212e53654c6 100644
> > --- a/drivers/misc/pci_endpoint_test.c
> > +++ b/drivers/misc/pci_endpoint_test.c
> > @@ -178,6 +178,19 @@ static irqreturn_t pci_endpoint_test_irqhandler(int irq, void *dev_id)
> >  	if (reg & STATUS_IRQ_RAISED) {
> >  		test->last_irq = irq;
> >  		complete(&test->irq_raised);
> > +		/*
> > +		 * The endpoint test driver performs all testing sequentially.
> > +		 * This means that test->irq_raised.done should never exceed 1.
> > +		 * If it does, then we received two IRQs in a row, without a
> > +		 * successful wait_for_completion_timeout() call in between.
> > +		 *
> > +		 * While complete() increases test->irq_raised.done by one,
> > +		 * wait_for_completion_timeout() reduces test->irq_raised.done
> > +		 * by one on success.
> > +		 *
> > +		 * Please debug your EPC driver if you see this warning.
> > +		 */
> > +		WARN_ON(test->irq_raised.done > 1);
> >  	}
> >  
> >  	return IRQ_HANDLED;
> > -- 
> > 2.55.0
> > 
> 
> Hello Koichiro,
> 
> I created this patch in response to a problem that I saw on v7.2-rc5.
> 
> When running the pci_endpoint selftest:
> # /pcitest
> (snip)
> #  RUN           pcie_ep_doorbell.DOORBELL_TEST ...
> [  215.256772] pci-endpoint-test 0000:01:00.0: Failed to trigger doorbell in endpoint
> #            OK  pcie_ep_doorbell.DOORBELL_TEST
> ok 23 pcie_ep_doorbell.DOORBELL_TEST
> # FAILED: 19 / 23 tests passed.
> # 2 skipped test(s) detected. Consider enabling relevant config options to improve coverage.
> # Totals: pass:17 fail:4 xfail:0 xpass:0 skip:2 error:0
> 
> 
> I saw the weird error:
> "Failed to trigger doorbell in endpoint"
> 
> Ignore that the test case leaves things to be desired, since it passes even
> though we see this warning.
> 
> 
> The problem seems to be that the embedded doorbell IRQ handler is executed twice,
> in response to a single writel() which rings the doorbell.
> 
> diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
> index 4802d4f80f78..7f4360579ffb 100644
> --- a/drivers/pci/endpoint/functions/pci-epf-test.c
> +++ b/drivers/pci/endpoint/functions/pci-epf-test.c
> @@ -714,6 +714,7 @@ static irqreturn_t pci_epf_test_doorbell_handler(int irq, void *data)
>  
>         status |= STATUS_DOORBELL_SUCCESS;
>         reg->status = cpu_to_le32(status);
> +       trace_printk("calling pci_epf_test_raise_irq()\n");
>         pci_epf_test_raise_irq(epf_test, reg);
>  
>         return IRQ_HANDLED;
> 
> 
> As you can see:
>  irq/58-pci-ep-t-221     [006] .....    58.601020: pci_epf_test_doorbell_handler: calling pci_epf_test_raise_irq()
>  irq/58-pci-ep-t-221     [006] .....    58.601421: pci_epf_test_doorbell_handler: calling pci_epf_test_raise_irq()
> 
> It is called twice for a single doorbell ring.
> 
> Note that you might need to run the whole selftest test a few times to trigger
> the WARN_ON(), even if you can see the trace printks every time.
> (Using printks instead of trace printks seems to affect the timing too much.)
> 
> 
> My first thought was that we should add reinit_completion() calls after each
> wait_for_completion_timeout() in pci_endpoint_test_doorbell(), but after
> reading up on complete() and wait_for_completion_timeout(), this should
> actually not be needed, and if we did, it would simply hide the read problem,
> which appears to be that the embedded doorbell IRQ handler on the EP side is
> called twice for a single writel() that rings the doorbell.

Hi Niklas,

I was struggling to reproduce this, but I think I figured out what triggers it.
It happens when the 'dma' variant runs before DOORBELL_TEST, e.g. when running
the full test suite with no arguments, or by running '-v dma' first.

I think the following patch fixes it:

diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index 89a4c498a17b..ec097c68cf5f 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -755,6 +755,7 @@ static int dw_edma_emul_irq_alloc(struct dw_edma *dw)
                return virq;

        irq_set_chip_and_handler(virq, &dw_edma_emul_irqchip, handle_level_irq);
+       irq_set_status_flags(virq, IRQ_LEVEL);
        irq_set_chip_data(virq, dw);
        irq_set_noprobe(virq);

Could you test this?

Best regards,
Koichiro

> 
> 
> Kind regards,
> Niklas