]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
misc: pci_endpoint_test: Add doorbell test case
authorFrank Li <Frank.Li@nxp.com>
Thu, 10 Jul 2025 19:13:53 +0000 (15:13 -0400)
committerBjorn Helgaas <bhelgaas@google.com>
Thu, 24 Jul 2025 21:51:46 +0000 (16:51 -0500)
Add doorbell support with the help of three new registers:
PCIE_ENDPOINT_TEST_DB_BAR, PCIE_ENDPOINT_TEST_DB_ADDR, and
PCIE_ENDPOINT_TEST_DB_DATA.

The testcase works by triggering the doorbell in Endpoint by writing the
value from PCI_ENDPOINT_TEST_DB_DATA register to the address provided by
PCI_ENDPOINT_TEST_DB_OFFSET register of the BAR indicated by the
PCIE_ENDPOINT_TEST_DB_BAR register and waiting for the completion status
from the Endpoint.

Signed-off-by: Frank Li <Frank.Li@nxp.com>
[mani: removed one spurious change and reworded the commit message]
Signed-off-by: Manivannan Sadhasivam <mani@kernel.org>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Tested-by: Niklas Cassel <cassel@kernel.org>
Link: https://patch.msgid.link/20250710-ep-msi-v21-7-57683fc7fb25@nxp.com
drivers/misc/pci_endpoint_test.c
include/uapi/linux/pcitest.h

index c4e5e2c977be27adf1451b67ee10cc3ae6fb0cef..1c156a3f845e112ed7f658acdf7aae1bc44290ed 100644 (file)
@@ -37,6 +37,8 @@
 #define COMMAND_READ                           BIT(3)
 #define COMMAND_WRITE                          BIT(4)
 #define COMMAND_COPY                           BIT(5)
+#define COMMAND_ENABLE_DOORBELL                        BIT(6)
+#define COMMAND_DISABLE_DOORBELL               BIT(7)
 
 #define PCI_ENDPOINT_TEST_STATUS               0x8
 #define STATUS_READ_SUCCESS                    BIT(0)
 #define STATUS_IRQ_RAISED                      BIT(6)
 #define STATUS_SRC_ADDR_INVALID                        BIT(7)
 #define STATUS_DST_ADDR_INVALID                        BIT(8)
+#define STATUS_DOORBELL_SUCCESS                        BIT(9)
+#define STATUS_DOORBELL_ENABLE_SUCCESS         BIT(10)
+#define STATUS_DOORBELL_ENABLE_FAIL            BIT(11)
+#define STATUS_DOORBELL_DISABLE_SUCCESS                BIT(12)
+#define STATUS_DOORBELL_DISABLE_FAIL           BIT(13)
 
 #define PCI_ENDPOINT_TEST_LOWER_SRC_ADDR       0x0c
 #define PCI_ENDPOINT_TEST_UPPER_SRC_ADDR       0x10
@@ -62,6 +69,7 @@
 #define PCI_ENDPOINT_TEST_IRQ_NUMBER           0x28
 
 #define PCI_ENDPOINT_TEST_FLAGS                        0x2c
+
 #define FLAG_USE_DMA                           BIT(0)
 
 #define PCI_ENDPOINT_TEST_CAPS                 0x30
 #define CAP_MSIX                               BIT(2)
 #define CAP_INTX                               BIT(3)
 
+#define PCI_ENDPOINT_TEST_DB_BAR               0x34
+#define PCI_ENDPOINT_TEST_DB_OFFSET            0x38
+#define PCI_ENDPOINT_TEST_DB_DATA              0x3c
+
 #define PCI_DEVICE_ID_TI_AM654                 0xb00c
 #define PCI_DEVICE_ID_TI_J7200                 0xb00f
 #define PCI_DEVICE_ID_TI_AM64                  0xb010
@@ -100,6 +112,7 @@ enum pci_barno {
        BAR_3,
        BAR_4,
        BAR_5,
+       NO_BAR = -1,
 };
 
 struct pci_endpoint_test {
@@ -841,6 +854,73 @@ static int pci_endpoint_test_set_irq(struct pci_endpoint_test *test,
        return 0;
 }
 
+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;
+       enum pci_barno bar;
+       u32 data, status;
+       u32 addr;
+       int left;
+
+       if (irq_type < PCITEST_IRQ_TYPE_INTX ||
+           irq_type > PCITEST_IRQ_TYPE_MSIX) {
+               dev_err(dev, "Invalid IRQ type\n");
+               return -EINVAL;
+       }
+
+       pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
+       pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
+       pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
+                                COMMAND_ENABLE_DOORBELL);
+
+       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)) {
+               dev_err(dev, "Failed to enable doorbell\n");
+               return -EINVAL;
+       }
+
+       data = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_DB_DATA);
+       addr = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_DB_OFFSET);
+       bar = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_DB_BAR);
+
+       pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
+       pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
+
+       pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_STATUS, 0);
+
+       bar = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_DB_BAR);
+
+       writel(data, test->bar[bar] + addr);
+
+       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_SUCCESS))
+               dev_err(dev, "Failed to trigger doorbell in endpoint\n");
+
+       pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
+                                COMMAND_DISABLE_DOORBELL);
+
+       wait_for_completion_timeout(&test->irq_raised, msecs_to_jiffies(1000));
+
+       status |= pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_STATUS);
+
+       if (status & STATUS_DOORBELL_DISABLE_FAIL) {
+               dev_err(dev, "Failed to disable doorbell\n");
+               return -EINVAL;
+       }
+
+       if (!(status & STATUS_DOORBELL_SUCCESS))
+               return -EINVAL;
+
+       return 0;
+}
+
 static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
                                    unsigned long arg)
 {
@@ -891,6 +971,9 @@ static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
        case PCITEST_CLEAR_IRQ:
                ret = pci_endpoint_test_clear_irq(test);
                break;
+       case PCITEST_DOORBELL:
+               ret = pci_endpoint_test_doorbell(test);
+               break;
        }
 
 ret:
index d3aa8715a525ea47485db734a42d13d333399112..d6023a45a9d03416e220c98643c4e86d144898ae 100644 (file)
@@ -21,6 +21,7 @@
 #define PCITEST_SET_IRQTYPE    _IOW('P', 0x8, int)
 #define PCITEST_GET_IRQTYPE    _IO('P', 0x9)
 #define PCITEST_BARS           _IO('P', 0xa)
+#define PCITEST_DOORBELL       _IO('P', 0xb)
 #define PCITEST_CLEAR_IRQ      _IO('P', 0x10)
 
 #define PCITEST_IRQ_TYPE_UNDEFINED     -1