mirror of https://github.com/torvalds/linux.git
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:
parent
eff0c286aa
commit
eefb83790a
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue