diff options
| author | Frank Li <Frank.Li@nxp.com> | 2025-07-10 22:13:53 +0300 | 
|---|---|---|
| committer | Bjorn Helgaas <bhelgaas@google.com> | 2025-07-25 00:51:46 +0300 | 
| commit | eefb83790a0dda112d1755e4f5e213738d717e76 (patch) | |
| tree | 7a3d2f030eaca0af62804a9fd5de57f64476d406 /drivers/misc/pci_endpoint_test.c | |
| parent | eff0c286aa916221a69126a43eee7c218d6f4011 (diff) | |
| download | linux-eefb83790a0dda112d1755e4f5e213738d717e76.tar.xz | |
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
Diffstat (limited to 'drivers/misc/pci_endpoint_test.c')
| -rw-r--r-- | drivers/misc/pci_endpoint_test.c | 83 | 
1 files changed, 83 insertions, 0 deletions
diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c index c4e5e2c977be..1c156a3f845e 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,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:  | 
