|
37 | 37 | #define COMMAND_READ BIT(3) |
38 | 38 | #define COMMAND_WRITE BIT(4) |
39 | 39 | #define COMMAND_COPY BIT(5) |
| 40 | +#define COMMAND_ENABLE_DOORBELL BIT(6) |
| 41 | +#define COMMAND_DISABLE_DOORBELL BIT(7) |
40 | 42 |
|
41 | 43 | #define PCI_ENDPOINT_TEST_STATUS 0x8 |
42 | 44 | #define STATUS_READ_SUCCESS BIT(0) |
|
48 | 50 | #define STATUS_IRQ_RAISED BIT(6) |
49 | 51 | #define STATUS_SRC_ADDR_INVALID BIT(7) |
50 | 52 | #define STATUS_DST_ADDR_INVALID BIT(8) |
| 53 | +#define STATUS_DOORBELL_SUCCESS BIT(9) |
| 54 | +#define STATUS_DOORBELL_ENABLE_SUCCESS BIT(10) |
| 55 | +#define STATUS_DOORBELL_ENABLE_FAIL BIT(11) |
| 56 | +#define STATUS_DOORBELL_DISABLE_SUCCESS BIT(12) |
| 57 | +#define STATUS_DOORBELL_DISABLE_FAIL BIT(13) |
51 | 58 |
|
52 | 59 | #define PCI_ENDPOINT_TEST_LOWER_SRC_ADDR 0x0c |
53 | 60 | #define PCI_ENDPOINT_TEST_UPPER_SRC_ADDR 0x10 |
|
62 | 69 | #define PCI_ENDPOINT_TEST_IRQ_NUMBER 0x28 |
63 | 70 |
|
64 | 71 | #define PCI_ENDPOINT_TEST_FLAGS 0x2c |
| 72 | + |
65 | 73 | #define FLAG_USE_DMA BIT(0) |
66 | 74 |
|
67 | 75 | #define PCI_ENDPOINT_TEST_CAPS 0x30 |
|
70 | 78 | #define CAP_MSIX BIT(2) |
71 | 79 | #define CAP_INTX BIT(3) |
72 | 80 |
|
| 81 | +#define PCI_ENDPOINT_TEST_DB_BAR 0x34 |
| 82 | +#define PCI_ENDPOINT_TEST_DB_OFFSET 0x38 |
| 83 | +#define PCI_ENDPOINT_TEST_DB_DATA 0x3c |
| 84 | + |
73 | 85 | #define PCI_DEVICE_ID_TI_AM654 0xb00c |
74 | 86 | #define PCI_DEVICE_ID_TI_J7200 0xb00f |
75 | 87 | #define PCI_DEVICE_ID_TI_AM64 0xb010 |
@@ -100,6 +112,7 @@ enum pci_barno { |
100 | 112 | BAR_3, |
101 | 113 | BAR_4, |
102 | 114 | BAR_5, |
| 115 | + NO_BAR = -1, |
103 | 116 | }; |
104 | 117 |
|
105 | 118 | struct pci_endpoint_test { |
@@ -841,6 +854,73 @@ static int pci_endpoint_test_set_irq(struct pci_endpoint_test *test, |
841 | 854 | return 0; |
842 | 855 | } |
843 | 856 |
|
| 857 | +static int pci_endpoint_test_doorbell(struct pci_endpoint_test *test) |
| 858 | +{ |
| 859 | + struct pci_dev *pdev = test->pdev; |
| 860 | + struct device *dev = &pdev->dev; |
| 861 | + int irq_type = test->irq_type; |
| 862 | + enum pci_barno bar; |
| 863 | + u32 data, status; |
| 864 | + u32 addr; |
| 865 | + int left; |
| 866 | + |
| 867 | + if (irq_type < PCITEST_IRQ_TYPE_INTX || |
| 868 | + irq_type > PCITEST_IRQ_TYPE_MSIX) { |
| 869 | + dev_err(dev, "Invalid IRQ type\n"); |
| 870 | + return -EINVAL; |
| 871 | + } |
| 872 | + |
| 873 | + pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type); |
| 874 | + pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1); |
| 875 | + pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND, |
| 876 | + COMMAND_ENABLE_DOORBELL); |
| 877 | + |
| 878 | + left = wait_for_completion_timeout(&test->irq_raised, msecs_to_jiffies(1000)); |
| 879 | + |
| 880 | + status = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_STATUS); |
| 881 | + if (!left || (status & STATUS_DOORBELL_ENABLE_FAIL)) { |
| 882 | + dev_err(dev, "Failed to enable doorbell\n"); |
| 883 | + return -EINVAL; |
| 884 | + } |
| 885 | + |
| 886 | + data = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_DB_DATA); |
| 887 | + addr = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_DB_OFFSET); |
| 888 | + bar = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_DB_BAR); |
| 889 | + |
| 890 | + pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type); |
| 891 | + pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1); |
| 892 | + |
| 893 | + pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_STATUS, 0); |
| 894 | + |
| 895 | + bar = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_DB_BAR); |
| 896 | + |
| 897 | + writel(data, test->bar[bar] + addr); |
| 898 | + |
| 899 | + left = wait_for_completion_timeout(&test->irq_raised, msecs_to_jiffies(1000)); |
| 900 | + |
| 901 | + status = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_STATUS); |
| 902 | + |
| 903 | + if (!left || !(status & STATUS_DOORBELL_SUCCESS)) |
| 904 | + dev_err(dev, "Failed to trigger doorbell in endpoint\n"); |
| 905 | + |
| 906 | + pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND, |
| 907 | + COMMAND_DISABLE_DOORBELL); |
| 908 | + |
| 909 | + wait_for_completion_timeout(&test->irq_raised, msecs_to_jiffies(1000)); |
| 910 | + |
| 911 | + status |= pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_STATUS); |
| 912 | + |
| 913 | + if (status & STATUS_DOORBELL_DISABLE_FAIL) { |
| 914 | + dev_err(dev, "Failed to disable doorbell\n"); |
| 915 | + return -EINVAL; |
| 916 | + } |
| 917 | + |
| 918 | + if (!(status & STATUS_DOORBELL_SUCCESS)) |
| 919 | + return -EINVAL; |
| 920 | + |
| 921 | + return 0; |
| 922 | +} |
| 923 | + |
844 | 924 | static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd, |
845 | 925 | unsigned long arg) |
846 | 926 | { |
@@ -891,6 +971,9 @@ static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd, |
891 | 971 | case PCITEST_CLEAR_IRQ: |
892 | 972 | ret = pci_endpoint_test_clear_irq(test); |
893 | 973 | break; |
| 974 | + case PCITEST_DOORBELL: |
| 975 | + ret = pci_endpoint_test_doorbell(test); |
| 976 | + break; |
894 | 977 | } |
895 | 978 |
|
896 | 979 | ret: |
|
0 commit comments