misc: pci_endpoint_test: Add doorbell test case

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
This commit is contained in:
Frank Li 2025-07-10 15:13:53 -04:00 committed by Bjorn Helgaas
parent eff0c286aa
commit eefb83790a
2 changed files with 84 additions and 0 deletions

View File

@ -37,6 +37,8 @@
#define COMMAND_READ BIT(3) #define COMMAND_READ BIT(3)
#define COMMAND_WRITE BIT(4) #define COMMAND_WRITE BIT(4)
#define COMMAND_COPY BIT(5) #define COMMAND_COPY BIT(5)
#define COMMAND_ENABLE_DOORBELL BIT(6)
#define COMMAND_DISABLE_DOORBELL BIT(7)
#define PCI_ENDPOINT_TEST_STATUS 0x8 #define PCI_ENDPOINT_TEST_STATUS 0x8
#define STATUS_READ_SUCCESS BIT(0) #define STATUS_READ_SUCCESS BIT(0)
@ -48,6 +50,11 @@
#define STATUS_IRQ_RAISED BIT(6) #define STATUS_IRQ_RAISED BIT(6)
#define STATUS_SRC_ADDR_INVALID BIT(7) #define STATUS_SRC_ADDR_INVALID BIT(7)
#define STATUS_DST_ADDR_INVALID BIT(8) #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_LOWER_SRC_ADDR 0x0c
#define PCI_ENDPOINT_TEST_UPPER_SRC_ADDR 0x10 #define PCI_ENDPOINT_TEST_UPPER_SRC_ADDR 0x10
@ -62,6 +69,7 @@
#define PCI_ENDPOINT_TEST_IRQ_NUMBER 0x28 #define PCI_ENDPOINT_TEST_IRQ_NUMBER 0x28
#define PCI_ENDPOINT_TEST_FLAGS 0x2c #define PCI_ENDPOINT_TEST_FLAGS 0x2c
#define FLAG_USE_DMA BIT(0) #define FLAG_USE_DMA BIT(0)
#define PCI_ENDPOINT_TEST_CAPS 0x30 #define PCI_ENDPOINT_TEST_CAPS 0x30
@ -70,6 +78,10 @@
#define CAP_MSIX BIT(2) #define CAP_MSIX BIT(2)
#define CAP_INTX BIT(3) #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_AM654 0xb00c
#define PCI_DEVICE_ID_TI_J7200 0xb00f #define PCI_DEVICE_ID_TI_J7200 0xb00f
#define PCI_DEVICE_ID_TI_AM64 0xb010 #define PCI_DEVICE_ID_TI_AM64 0xb010
@ -100,6 +112,7 @@ enum pci_barno {
BAR_3, BAR_3,
BAR_4, BAR_4,
BAR_5, BAR_5,
NO_BAR = -1,
}; };
struct pci_endpoint_test { struct pci_endpoint_test {
@ -841,6 +854,73 @@ static int pci_endpoint_test_set_irq(struct pci_endpoint_test *test,
return 0; 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, static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
unsigned long arg) unsigned long arg)
{ {
@ -891,6 +971,9 @@ static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
case PCITEST_CLEAR_IRQ: case PCITEST_CLEAR_IRQ:
ret = pci_endpoint_test_clear_irq(test); ret = pci_endpoint_test_clear_irq(test);
break; break;
case PCITEST_DOORBELL:
ret = pci_endpoint_test_doorbell(test);
break;
} }
ret: ret:

View File

@ -21,6 +21,7 @@
#define PCITEST_SET_IRQTYPE _IOW('P', 0x8, int) #define PCITEST_SET_IRQTYPE _IOW('P', 0x8, int)
#define PCITEST_GET_IRQTYPE _IO('P', 0x9) #define PCITEST_GET_IRQTYPE _IO('P', 0x9)
#define PCITEST_BARS _IO('P', 0xa) #define PCITEST_BARS _IO('P', 0xa)
#define PCITEST_DOORBELL _IO('P', 0xb)
#define PCITEST_CLEAR_IRQ _IO('P', 0x10) #define PCITEST_CLEAR_IRQ _IO('P', 0x10)
#define PCITEST_IRQ_TYPE_UNDEFINED -1 #define PCITEST_IRQ_TYPE_UNDEFINED -1