On Mon, Jun 09, 2025 at 12:34:18PM GMT, Frank Li wrote:
Add three registers: PCIE_ENDPOINT_TEST_DB_BAR, PCIE_ENDPOINT_TEST_DB_ADDR, and PCIE_ENDPOINT_TEST_DB_DATA.
Trigger the doorbell by writing data from PCI_ENDPOINT_TEST_DB_DATA to the address provided by PCI_ENDPOINT_TEST_DB_OFFSET and wait for endpoint feedback.
Add two command to COMMAND_ENABLE_DOORBELL and COMMAND_DISABLE_DOORBELL to enable EP side's doorbell support and avoid compatible problem, which host side driver miss-match with endpoint side function driver. See below table:
Host side new driver Host side old driver
EP: new driver S F EP: old driver F F
S: If EP side support MSI, 'pci_endpoint_test -f pcie_ep_doorbell' return success. If EP side doesn't support MSI, the same to 'F'.
F: 'pci_endpoint_test -f pcie_ep_doorbell' return failure, other case as usual.
Tested-by: Niklas Cassel cassel@kernel.org Signed-off-by: Frank Li Frank.Li@nxp.com
change from v14 to v16
- none
Change from v13 to v14
- update to use pci_endpoint_test -f pcie_ep_doorbell
- change ioctrl id to fix conflict
Change from v9 to v13
- none
Change from v8 to v9
- change PCITEST_DOORBELL to 0xa
Change form v6 to v8
- none
Change from v5 to v6
- %s/PCI_ENDPOINT_TEST_DB_ADDR/PCI_ENDPOINT_TEST_DB_OFFSET/g
Change from v4 to v5
- remove unused varible
- add irq_type at pci_endpoint_test_doorbell();
change from v3 to v4
- Add COMMAND_ENABLE_DOORBELL and COMMAND_DISABLE_DOORBELL.
- Remove new DID requirement.
drivers/misc/pci_endpoint_test.c | 82 ++++++++++++++++++++++++++++++++++++++++ include/uapi/linux/pcitest.h | 1 + 2 files changed, 83 insertions(+)
diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c index c4e5e2c977be2..0f3af7adea107 100644 --- a/drivers/misc/pci_endpoint_test.c +++ b/drivers/misc/pci_endpoint_test.c @@ -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) @@ -48,6 +50,11 @@ #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 @@ -70,6 +78,10 @@ #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,72 @@ 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;
- if (irq_type < PCITEST_IRQ_TYPE_INTX ||
irq_type > PCITEST_IRQ_TYPE_MSIX) {
dev_err(dev, "Invalid IRQ type option\n");
'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);
- wait_for_completion_timeout(&test->irq_raised, msecs_to_jiffies(1000));
You should check for the timeout here and below.
- status = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_STATUS);
- if (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);
- 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_SUCCESS))
dev_err(dev, "Endpoint have not received Doorbell\n");
'Failed to trigger doorbell in endpoint\n'
- Mani