From 37ddcce6904c20c6a7debe4751f6a82f218c3bae Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Thu, 30 Jul 2026 14:20:47 +0200 Subject: [PATCH 1/2] misc: pci_endpoint_test: Check SUCCESS bit for doorbell status The pci-epf driver sets STATUS_DOORBELL_ENABLE_SUCCESS as the final step of pci_epf_test_enable_doorbell(), and STATUS_DOORBELL_DISABLE_SUCCESS as the final step of pci_epf_test_disable_doorbell(). A missing SUCCESS bit therefore unambiguously means that the operation did not complete, whereas the FAIL bit is only set on an explicit failure path. The host side test in pci_endpoint_test_doorbell() currently keys off the FAIL bit. That covers explicit failures but misses two cases. The first case is when the wait for the completion IRQ times out. No IRQ arrives, the Endpoint never updates STATUS, and neither SUCCESS nor FAIL is set. The enable path already handles this correctly because it also fails when the wait times out without an IRQ. The disable path does not have that extra guard and would wrongly treat the timeout as success. The second is a buggy EPC that raises two IRQs in response to a single DOORBELL_ENABLE command. The second wait_for_completion_timeout() returns immediately with 'left' non zero, but the endpoint has not yet written STATUS, so SUCCESS is clear and FAIL is also clear. The current FAIL only check treats this as success. So check the SUCCESS bit instead. That matches the Endpoint's contract because SUCCESS is the last write on the success path, and it correctly reports failure for both timeouts and the spurious IRQ case without relying on the FAIL bit being set. Fixes: eefb83790a0d ("misc: pci_endpoint_test: Add doorbell test case") Signed-off-by: Niklas Cassel [mani: commit log] Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20260730122045.1382749-5-cassel@kernel.org --- drivers/misc/pci_endpoint_test.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c index 3635741c3e7a..26ab9252251f 100644 --- a/drivers/misc/pci_endpoint_test.c +++ b/drivers/misc/pci_endpoint_test.c @@ -1071,6 +1071,7 @@ static int pci_endpoint_test_doorbell(struct pci_endpoint_test *test) struct pci_dev *pdev = test->pdev; struct device *dev = &pdev->dev; int irq_type = test->irq_type; + int ret = 0; enum pci_barno bar; u32 data, status; u32 addr; @@ -1119,8 +1120,11 @@ static int pci_endpoint_test_doorbell(struct pci_endpoint_test *test) status = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_STATUS); - if (!left || !(status & STATUS_DOORBELL_SUCCESS)) + if (!left || !(status & STATUS_DOORBELL_SUCCESS)) { dev_err(dev, "Failed to trigger doorbell in endpoint\n"); + /* Store error code, but continue to disable doorbell. */ + ret = -EINVAL; + } pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND, COMMAND_DISABLE_DOORBELL); @@ -1134,10 +1138,7 @@ static int pci_endpoint_test_doorbell(struct pci_endpoint_test *test) return -EINVAL; } - if (!(status & STATUS_DOORBELL_SUCCESS)) - return -EINVAL; - - return 0; + return ret; } static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd, From 0a6f72eda328c773324555491e1ad7f0b0153155 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Thu, 30 Jul 2026 14:20:48 +0200 Subject: [PATCH 2/2] misc: pci_endpoint_test: Fail doorbell test when the trigger IRQ is missed The doorbell test case was observed to pass even when the Endpoint had clearly failed to handle the doorbell trigger. pci-endpoint-test 0000:01:00.0: Failed to trigger doorbell in endpoint ok 23 pcie_ep_doorbell.DOORBELL_TEST The root cause turned out to be a buggy EPC driver that raised two IRQs in response to a single ENABLE DOORBELL command. The extra IRQ left test->irq_raised.done at a non zero value, so the next wait_for_completion_timeout() after the writel() that rings the doorbell returned immediately, before the Endpoint had set STATUS_DOORBELL_SUCCESS and raised the IRQ that belongs to that write. The status readback that followed therefore did not yet reflect the doorbell trigger, and the test logged the failure but did not fail the test case. Later on, after the doorbell was disabled, the status was read again and STATUS_DOORBELL_SUCCESS had by then been set by the Endpoint for the earlier trigger. The final check saw the bit set and reported the test as passed. Make the trigger step actually fail the test case when it detects a problem. Record the failure in a local variable, keep going so that the doorbell is still disabled and the Endpoint is left in a clean state, and return the stored error at the end. The disable path still returns its own error immediately when its wait times out, which is unchanged. Signed-off-by: Niklas Cassel [mani: change log] Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20260730122045.1382749-6-cassel@kernel.org --- drivers/misc/pci_endpoint_test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c index 26ab9252251f..1019bcd0628f 100644 --- a/drivers/misc/pci_endpoint_test.c +++ b/drivers/misc/pci_endpoint_test.c @@ -1094,7 +1094,7 @@ static int pci_endpoint_test_doorbell(struct pci_endpoint_test *test) left = wait_for_completion_timeout(&test->irq_raised, msecs_to_jiffies(1000)); status = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_STATUS); - if (!left || (status & STATUS_DOORBELL_ENABLE_FAIL)) { + if (!left || !(status & STATUS_DOORBELL_ENABLE_SUCCESS)) { dev_err(dev, "Failed to enable doorbell\n"); return -EINVAL; } @@ -1133,7 +1133,7 @@ static int pci_endpoint_test_doorbell(struct pci_endpoint_test *test) status |= pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_STATUS); - if (status & STATUS_DOORBELL_DISABLE_FAIL) { + if (!(status & STATUS_DOORBELL_DISABLE_SUCCESS)) { dev_err(dev, "Failed to disable doorbell\n"); return -EINVAL; }