diff options
30 files changed, 763 insertions, 159 deletions
diff --git a/Documentation/PCI/endpoint/function/binding/pci-test.txt b/Documentation/PCI/endpoint/function/binding/pci-test.txt index 3b68b955fb50..cd76ba47394b 100644 --- a/Documentation/PCI/endpoint/function/binding/pci-test.txt +++ b/Documentation/PCI/endpoint/function/binding/pci-test.txt | |||
@@ -15,3 +15,5 @@ subsys_id : don't care | |||
15 | interrupt_pin : Should be 1 - INTA, 2 - INTB, 3 - INTC, 4 -INTD | 15 | interrupt_pin : Should be 1 - INTA, 2 - INTB, 3 - INTC, 4 -INTD |
16 | msi_interrupts : Should be 1 to 32 depending on the number of MSI interrupts | 16 | msi_interrupts : Should be 1 to 32 depending on the number of MSI interrupts |
17 | to test | 17 | to test |
18 | msix_interrupts : Should be 1 to 2048 depending on the number of MSI-X | ||
19 | interrupts to test | ||
diff --git a/Documentation/PCI/endpoint/pci-endpoint.txt b/Documentation/PCI/endpoint/pci-endpoint.txt index 9b1d66829290..e86a96b66a6a 100644 --- a/Documentation/PCI/endpoint/pci-endpoint.txt +++ b/Documentation/PCI/endpoint/pci-endpoint.txt | |||
@@ -44,7 +44,7 @@ by the PCI controller driver. | |||
44 | * clear_bar: ops to reset the BAR | 44 | * clear_bar: ops to reset the BAR |
45 | * alloc_addr_space: ops to allocate in PCI controller address space | 45 | * alloc_addr_space: ops to allocate in PCI controller address space |
46 | * free_addr_space: ops to free the allocated address space | 46 | * free_addr_space: ops to free the allocated address space |
47 | * raise_irq: ops to raise a legacy or MSI interrupt | 47 | * raise_irq: ops to raise a legacy, MSI or MSI-X interrupt |
48 | * start: ops to start the PCI link | 48 | * start: ops to start the PCI link |
49 | * stop: ops to stop the PCI link | 49 | * stop: ops to stop the PCI link |
50 | 50 | ||
@@ -96,7 +96,7 @@ by the PCI endpoint function driver. | |||
96 | *) pci_epc_raise_irq() | 96 | *) pci_epc_raise_irq() |
97 | 97 | ||
98 | The PCI endpoint function driver should use pci_epc_raise_irq() to raise | 98 | The PCI endpoint function driver should use pci_epc_raise_irq() to raise |
99 | Legacy Interrupt or MSI Interrupt. | 99 | Legacy Interrupt, MSI or MSI-X Interrupt. |
100 | 100 | ||
101 | *) pci_epc_mem_alloc_addr() | 101 | *) pci_epc_mem_alloc_addr() |
102 | 102 | ||
diff --git a/Documentation/PCI/endpoint/pci-test-function.txt b/Documentation/PCI/endpoint/pci-test-function.txt index 0c519c9bf94a..5916f1f592bb 100644 --- a/Documentation/PCI/endpoint/pci-test-function.txt +++ b/Documentation/PCI/endpoint/pci-test-function.txt | |||
@@ -20,6 +20,8 @@ The PCI endpoint test device has the following registers: | |||
20 | 5) PCI_ENDPOINT_TEST_DST_ADDR | 20 | 5) PCI_ENDPOINT_TEST_DST_ADDR |
21 | 6) PCI_ENDPOINT_TEST_SIZE | 21 | 6) PCI_ENDPOINT_TEST_SIZE |
22 | 7) PCI_ENDPOINT_TEST_CHECKSUM | 22 | 7) PCI_ENDPOINT_TEST_CHECKSUM |
23 | 8) PCI_ENDPOINT_TEST_IRQ_TYPE | ||
24 | 9) PCI_ENDPOINT_TEST_IRQ_NUMBER | ||
23 | 25 | ||
24 | *) PCI_ENDPOINT_TEST_MAGIC | 26 | *) PCI_ENDPOINT_TEST_MAGIC |
25 | 27 | ||
@@ -34,10 +36,10 @@ that the endpoint device must perform. | |||
34 | Bitfield Description: | 36 | Bitfield Description: |
35 | Bit 0 : raise legacy IRQ | 37 | Bit 0 : raise legacy IRQ |
36 | Bit 1 : raise MSI IRQ | 38 | Bit 1 : raise MSI IRQ |
37 | Bit 2 - 7 : MSI interrupt number | 39 | Bit 2 : raise MSI-X IRQ |
38 | Bit 8 : read command (read data from RC buffer) | 40 | Bit 3 : read command (read data from RC buffer) |
39 | Bit 9 : write command (write data to RC buffer) | 41 | Bit 4 : write command (write data to RC buffer) |
40 | Bit 10 : copy command (copy data from one RC buffer to another | 42 | Bit 5 : copy command (copy data from one RC buffer to another |
41 | RC buffer) | 43 | RC buffer) |
42 | 44 | ||
43 | *) PCI_ENDPOINT_TEST_STATUS | 45 | *) PCI_ENDPOINT_TEST_STATUS |
@@ -64,3 +66,22 @@ COPY/READ command. | |||
64 | 66 | ||
65 | This register contains the destination address (RC buffer address) for | 67 | This register contains the destination address (RC buffer address) for |
66 | the COPY/WRITE command. | 68 | the COPY/WRITE command. |
69 | |||
70 | *) PCI_ENDPOINT_TEST_IRQ_TYPE | ||
71 | |||
72 | This register contains the interrupt type (Legacy/MSI) triggered | ||
73 | for the READ/WRITE/COPY and raise IRQ (Legacy/MSI) commands. | ||
74 | |||
75 | Possible types: | ||
76 | - Legacy : 0 | ||
77 | - MSI : 1 | ||
78 | - MSI-X : 2 | ||
79 | |||
80 | *) PCI_ENDPOINT_TEST_IRQ_NUMBER | ||
81 | |||
82 | This register contains the triggered ID interrupt. | ||
83 | |||
84 | Admissible values: | ||
85 | - Legacy : 0 | ||
86 | - MSI : [1 .. 32] | ||
87 | - MSI-X : [1 .. 2048] | ||
diff --git a/Documentation/PCI/endpoint/pci-test-howto.txt b/Documentation/PCI/endpoint/pci-test-howto.txt index 75f48c3bb191..e40cf0fb58d7 100644 --- a/Documentation/PCI/endpoint/pci-test-howto.txt +++ b/Documentation/PCI/endpoint/pci-test-howto.txt | |||
@@ -45,9 +45,9 @@ The PCI endpoint framework populates the directory with the following | |||
45 | configurable fields. | 45 | configurable fields. |
46 | 46 | ||
47 | # ls functions/pci_epf_test/func1 | 47 | # ls functions/pci_epf_test/func1 |
48 | baseclass_code interrupt_pin revid subsys_vendor_id | 48 | baseclass_code interrupt_pin progif_code subsys_id |
49 | cache_line_size msi_interrupts subclass_code vendorid | 49 | cache_line_size msi_interrupts revid subsys_vendorid |
50 | deviceid progif_code subsys_id | 50 | deviceid msix_interrupts subclass_code vendorid |
51 | 51 | ||
52 | The PCI endpoint function driver populates these entries with default values | 52 | The PCI endpoint function driver populates these entries with default values |
53 | when the device is bound to the driver. The pci-epf-test driver populates | 53 | when the device is bound to the driver. The pci-epf-test driver populates |
@@ -67,6 +67,7 @@ device, the following commands can be used. | |||
67 | # echo 0x104c > functions/pci_epf_test/func1/vendorid | 67 | # echo 0x104c > functions/pci_epf_test/func1/vendorid |
68 | # echo 0xb500 > functions/pci_epf_test/func1/deviceid | 68 | # echo 0xb500 > functions/pci_epf_test/func1/deviceid |
69 | # echo 16 > functions/pci_epf_test/func1/msi_interrupts | 69 | # echo 16 > functions/pci_epf_test/func1/msi_interrupts |
70 | # echo 8 > functions/pci_epf_test/func1/msix_interrupts | ||
70 | 71 | ||
71 | 1.5 Binding pci-epf-test Device to EP Controller | 72 | 1.5 Binding pci-epf-test Device to EP Controller |
72 | 73 | ||
@@ -120,7 +121,9 @@ following commands. | |||
120 | 121 | ||
121 | Interrupt tests | 122 | Interrupt tests |
122 | 123 | ||
124 | SET IRQ TYPE TO LEGACY: OKAY | ||
123 | LEGACY IRQ: NOT OKAY | 125 | LEGACY IRQ: NOT OKAY |
126 | SET IRQ TYPE TO MSI: OKAY | ||
124 | MSI1: OKAY | 127 | MSI1: OKAY |
125 | MSI2: OKAY | 128 | MSI2: OKAY |
126 | MSI3: OKAY | 129 | MSI3: OKAY |
@@ -153,9 +156,30 @@ following commands. | |||
153 | MSI30: NOT OKAY | 156 | MSI30: NOT OKAY |
154 | MSI31: NOT OKAY | 157 | MSI31: NOT OKAY |
155 | MSI32: NOT OKAY | 158 | MSI32: NOT OKAY |
159 | SET IRQ TYPE TO MSI-X: OKAY | ||
160 | MSI-X1: OKAY | ||
161 | MSI-X2: OKAY | ||
162 | MSI-X3: OKAY | ||
163 | MSI-X4: OKAY | ||
164 | MSI-X5: OKAY | ||
165 | MSI-X6: OKAY | ||
166 | MSI-X7: OKAY | ||
167 | MSI-X8: OKAY | ||
168 | MSI-X9: NOT OKAY | ||
169 | MSI-X10: NOT OKAY | ||
170 | MSI-X11: NOT OKAY | ||
171 | MSI-X12: NOT OKAY | ||
172 | MSI-X13: NOT OKAY | ||
173 | MSI-X14: NOT OKAY | ||
174 | MSI-X15: NOT OKAY | ||
175 | MSI-X16: NOT OKAY | ||
176 | [...] | ||
177 | MSI-X2047: NOT OKAY | ||
178 | MSI-X2048: NOT OKAY | ||
156 | 179 | ||
157 | Read Tests | 180 | Read Tests |
158 | 181 | ||
182 | SET IRQ TYPE TO MSI: OKAY | ||
159 | READ ( 1 bytes): OKAY | 183 | READ ( 1 bytes): OKAY |
160 | READ ( 1024 bytes): OKAY | 184 | READ ( 1024 bytes): OKAY |
161 | READ ( 1025 bytes): OKAY | 185 | READ ( 1025 bytes): OKAY |
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 480c8609dc58..c15c4f3bdd82 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt | |||
@@ -166,6 +166,7 @@ Code Seq#(hex) Include File Comments | |||
166 | 'P' all linux/soundcard.h conflict! | 166 | 'P' all linux/soundcard.h conflict! |
167 | 'P' 60-6F sound/sscape_ioctl.h conflict! | 167 | 'P' 60-6F sound/sscape_ioctl.h conflict! |
168 | 'P' 00-0F drivers/usb/class/usblp.c conflict! | 168 | 'P' 00-0F drivers/usb/class/usblp.c conflict! |
169 | 'P' 01-09 drivers/misc/pci_endpoint_test.c conflict! | ||
169 | 'Q' all linux/soundcard.h | 170 | 'Q' all linux/soundcard.h |
170 | 'R' 00-1F linux/random.h conflict! | 171 | 'R' 00-1F linux/random.h conflict! |
171 | 'R' 01 linux/rfkill.h conflict! | 172 | 'R' 01 linux/rfkill.h conflict! |
diff --git a/Documentation/misc-devices/pci-endpoint-test.txt b/Documentation/misc-devices/pci-endpoint-test.txt index 4ebc3594b32c..58ccca4416b1 100644 --- a/Documentation/misc-devices/pci-endpoint-test.txt +++ b/Documentation/misc-devices/pci-endpoint-test.txt | |||
@@ -10,6 +10,7 @@ The PCI driver for the test device performs the following tests | |||
10 | *) verifying addresses programmed in BAR | 10 | *) verifying addresses programmed in BAR |
11 | *) raise legacy IRQ | 11 | *) raise legacy IRQ |
12 | *) raise MSI IRQ | 12 | *) raise MSI IRQ |
13 | *) raise MSI-X IRQ | ||
13 | *) read data | 14 | *) read data |
14 | *) write data | 15 | *) write data |
15 | *) copy data | 16 | *) copy data |
@@ -25,6 +26,11 @@ ioctl | |||
25 | PCITEST_LEGACY_IRQ: Tests legacy IRQ | 26 | PCITEST_LEGACY_IRQ: Tests legacy IRQ |
26 | PCITEST_MSI: Tests message signalled interrupts. The MSI number | 27 | PCITEST_MSI: Tests message signalled interrupts. The MSI number |
27 | to be tested should be passed as argument. | 28 | to be tested should be passed as argument. |
29 | PCITEST_MSIX: Tests message signalled interrupts. The MSI-X number | ||
30 | to be tested should be passed as argument. | ||
31 | PCITEST_SET_IRQTYPE: Changes driver IRQ type configuration. The IRQ type | ||
32 | should be passed as argument (0: Legacy, 1:MSI, 2:MSI-X). | ||
33 | PCITEST_GET_IRQTYPE: Gets driver IRQ type configuration. | ||
28 | PCITEST_WRITE: Perform write tests. The size of the buffer should be passed | 34 | PCITEST_WRITE: Perform write tests. The size of the buffer should be passed |
29 | as argument. | 35 | as argument. |
30 | PCITEST_READ: Perform read tests. The size of the buffer should be passed | 36 | PCITEST_READ: Perform read tests. The size of the buffer should be passed |
diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c index 7b370466a227..896e2df9400f 100644 --- a/drivers/misc/pci_endpoint_test.c +++ b/drivers/misc/pci_endpoint_test.c | |||
@@ -35,38 +35,45 @@ | |||
35 | 35 | ||
36 | #include <uapi/linux/pcitest.h> | 36 | #include <uapi/linux/pcitest.h> |
37 | 37 | ||
38 | #define DRV_MODULE_NAME "pci-endpoint-test" | 38 | #define DRV_MODULE_NAME "pci-endpoint-test" |
39 | 39 | ||
40 | #define PCI_ENDPOINT_TEST_MAGIC 0x0 | 40 | #define IRQ_TYPE_UNDEFINED -1 |
41 | 41 | #define IRQ_TYPE_LEGACY 0 | |
42 | #define PCI_ENDPOINT_TEST_COMMAND 0x4 | 42 | #define IRQ_TYPE_MSI 1 |
43 | #define COMMAND_RAISE_LEGACY_IRQ BIT(0) | 43 | #define IRQ_TYPE_MSIX 2 |
44 | #define COMMAND_RAISE_MSI_IRQ BIT(1) | 44 | |
45 | #define MSI_NUMBER_SHIFT 2 | 45 | #define PCI_ENDPOINT_TEST_MAGIC 0x0 |
46 | /* 6 bits for MSI number */ | 46 | |
47 | #define COMMAND_READ BIT(8) | 47 | #define PCI_ENDPOINT_TEST_COMMAND 0x4 |
48 | #define COMMAND_WRITE BIT(9) | 48 | #define COMMAND_RAISE_LEGACY_IRQ BIT(0) |
49 | #define COMMAND_COPY BIT(10) | 49 | #define COMMAND_RAISE_MSI_IRQ BIT(1) |
50 | 50 | #define COMMAND_RAISE_MSIX_IRQ BIT(2) | |
51 | #define PCI_ENDPOINT_TEST_STATUS 0x8 | 51 | #define COMMAND_READ BIT(3) |
52 | #define STATUS_READ_SUCCESS BIT(0) | 52 | #define COMMAND_WRITE BIT(4) |
53 | #define STATUS_READ_FAIL BIT(1) | 53 | #define COMMAND_COPY BIT(5) |
54 | #define STATUS_WRITE_SUCCESS BIT(2) | 54 | |
55 | #define STATUS_WRITE_FAIL BIT(3) | 55 | #define PCI_ENDPOINT_TEST_STATUS 0x8 |
56 | #define STATUS_COPY_SUCCESS BIT(4) | 56 | #define STATUS_READ_SUCCESS BIT(0) |
57 | #define STATUS_COPY_FAIL BIT(5) | 57 | #define STATUS_READ_FAIL BIT(1) |
58 | #define STATUS_IRQ_RAISED BIT(6) | 58 | #define STATUS_WRITE_SUCCESS BIT(2) |
59 | #define STATUS_SRC_ADDR_INVALID BIT(7) | 59 | #define STATUS_WRITE_FAIL BIT(3) |
60 | #define STATUS_DST_ADDR_INVALID BIT(8) | 60 | #define STATUS_COPY_SUCCESS BIT(4) |
61 | 61 | #define STATUS_COPY_FAIL BIT(5) | |
62 | #define PCI_ENDPOINT_TEST_LOWER_SRC_ADDR 0xc | 62 | #define STATUS_IRQ_RAISED BIT(6) |
63 | #define STATUS_SRC_ADDR_INVALID BIT(7) | ||
64 | #define STATUS_DST_ADDR_INVALID BIT(8) | ||
65 | |||
66 | #define PCI_ENDPOINT_TEST_LOWER_SRC_ADDR 0x0c | ||
63 | #define PCI_ENDPOINT_TEST_UPPER_SRC_ADDR 0x10 | 67 | #define PCI_ENDPOINT_TEST_UPPER_SRC_ADDR 0x10 |
64 | 68 | ||
65 | #define PCI_ENDPOINT_TEST_LOWER_DST_ADDR 0x14 | 69 | #define PCI_ENDPOINT_TEST_LOWER_DST_ADDR 0x14 |
66 | #define PCI_ENDPOINT_TEST_UPPER_DST_ADDR 0x18 | 70 | #define PCI_ENDPOINT_TEST_UPPER_DST_ADDR 0x18 |
67 | 71 | ||
68 | #define PCI_ENDPOINT_TEST_SIZE 0x1c | 72 | #define PCI_ENDPOINT_TEST_SIZE 0x1c |
69 | #define PCI_ENDPOINT_TEST_CHECKSUM 0x20 | 73 | #define PCI_ENDPOINT_TEST_CHECKSUM 0x20 |
74 | |||
75 | #define PCI_ENDPOINT_TEST_IRQ_TYPE 0x24 | ||
76 | #define PCI_ENDPOINT_TEST_IRQ_NUMBER 0x28 | ||
70 | 77 | ||
71 | static DEFINE_IDA(pci_endpoint_test_ida); | 78 | static DEFINE_IDA(pci_endpoint_test_ida); |
72 | 79 | ||
@@ -77,6 +84,10 @@ static bool no_msi; | |||
77 | module_param(no_msi, bool, 0444); | 84 | module_param(no_msi, bool, 0444); |
78 | MODULE_PARM_DESC(no_msi, "Disable MSI interrupt in pci_endpoint_test"); | 85 | MODULE_PARM_DESC(no_msi, "Disable MSI interrupt in pci_endpoint_test"); |
79 | 86 | ||
87 | static int irq_type = IRQ_TYPE_MSI; | ||
88 | module_param(irq_type, int, 0444); | ||
89 | MODULE_PARM_DESC(irq_type, "IRQ mode selection in pci_endpoint_test (0 - Legacy, 1 - MSI, 2 - MSI-X)"); | ||
90 | |||
80 | enum pci_barno { | 91 | enum pci_barno { |
81 | BAR_0, | 92 | BAR_0, |
82 | BAR_1, | 93 | BAR_1, |
@@ -103,7 +114,7 @@ struct pci_endpoint_test { | |||
103 | struct pci_endpoint_test_data { | 114 | struct pci_endpoint_test_data { |
104 | enum pci_barno test_reg_bar; | 115 | enum pci_barno test_reg_bar; |
105 | size_t alignment; | 116 | size_t alignment; |
106 | bool no_msi; | 117 | int irq_type; |
107 | }; | 118 | }; |
108 | 119 | ||
109 | static inline u32 pci_endpoint_test_readl(struct pci_endpoint_test *test, | 120 | static inline u32 pci_endpoint_test_readl(struct pci_endpoint_test *test, |
@@ -147,6 +158,100 @@ static irqreturn_t pci_endpoint_test_irqhandler(int irq, void *dev_id) | |||
147 | return IRQ_HANDLED; | 158 | return IRQ_HANDLED; |
148 | } | 159 | } |
149 | 160 | ||
161 | static void pci_endpoint_test_free_irq_vectors(struct pci_endpoint_test *test) | ||
162 | { | ||
163 | struct pci_dev *pdev = test->pdev; | ||
164 | |||
165 | pci_free_irq_vectors(pdev); | ||
166 | } | ||
167 | |||
168 | static bool pci_endpoint_test_alloc_irq_vectors(struct pci_endpoint_test *test, | ||
169 | int type) | ||
170 | { | ||
171 | int irq = -1; | ||
172 | struct pci_dev *pdev = test->pdev; | ||
173 | struct device *dev = &pdev->dev; | ||
174 | bool res = true; | ||
175 | |||
176 | switch (type) { | ||
177 | case IRQ_TYPE_LEGACY: | ||
178 | irq = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_LEGACY); | ||
179 | if (irq < 0) | ||
180 | dev_err(dev, "Failed to get Legacy interrupt\n"); | ||
181 | break; | ||
182 | case IRQ_TYPE_MSI: | ||
183 | irq = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI); | ||
184 | if (irq < 0) | ||
185 | dev_err(dev, "Failed to get MSI interrupts\n"); | ||
186 | break; | ||
187 | case IRQ_TYPE_MSIX: | ||
188 | irq = pci_alloc_irq_vectors(pdev, 1, 2048, PCI_IRQ_MSIX); | ||
189 | if (irq < 0) | ||
190 | dev_err(dev, "Failed to get MSI-X interrupts\n"); | ||
191 | break; | ||
192 | default: | ||
193 | dev_err(dev, "Invalid IRQ type selected\n"); | ||
194 | } | ||
195 | |||
196 | if (irq < 0) { | ||
197 | irq = 0; | ||
198 | res = false; | ||
199 | } | ||
200 | test->num_irqs = irq; | ||
201 | |||
202 | return res; | ||
203 | } | ||
204 | |||
205 | static void pci_endpoint_test_release_irq(struct pci_endpoint_test *test) | ||
206 | { | ||
207 | int i; | ||
208 | struct pci_dev *pdev = test->pdev; | ||
209 | struct device *dev = &pdev->dev; | ||
210 | |||
211 | for (i = 0; i < test->num_irqs; i++) | ||
212 | devm_free_irq(dev, pci_irq_vector(pdev, i), test); | ||
213 | |||
214 | test->num_irqs = 0; | ||
215 | } | ||
216 | |||
217 | static bool pci_endpoint_test_request_irq(struct pci_endpoint_test *test) | ||
218 | { | ||
219 | int i; | ||
220 | int err; | ||
221 | struct pci_dev *pdev = test->pdev; | ||
222 | struct device *dev = &pdev->dev; | ||
223 | |||
224 | for (i = 0; i < test->num_irqs; i++) { | ||
225 | err = devm_request_irq(dev, pci_irq_vector(pdev, i), | ||
226 | pci_endpoint_test_irqhandler, | ||
227 | IRQF_SHARED, DRV_MODULE_NAME, test); | ||
228 | if (err) | ||
229 | goto fail; | ||
230 | } | ||
231 | |||
232 | return true; | ||
233 | |||
234 | fail: | ||
235 | switch (irq_type) { | ||
236 | case IRQ_TYPE_LEGACY: | ||
237 | dev_err(dev, "Failed to request IRQ %d for Legacy\n", | ||
238 | pci_irq_vector(pdev, i)); | ||
239 | break; | ||
240 | case IRQ_TYPE_MSI: | ||
241 | dev_err(dev, "Failed to request IRQ %d for MSI %d\n", | ||
242 | pci_irq_vector(pdev, i), | ||
243 | i + 1); | ||
244 | break; | ||
245 | case IRQ_TYPE_MSIX: | ||
246 | dev_err(dev, "Failed to request IRQ %d for MSI-X %d\n", | ||
247 | pci_irq_vector(pdev, i), | ||
248 | i + 1); | ||
249 | break; | ||
250 | } | ||
251 | |||
252 | return false; | ||
253 | } | ||
254 | |||
150 | static bool pci_endpoint_test_bar(struct pci_endpoint_test *test, | 255 | static bool pci_endpoint_test_bar(struct pci_endpoint_test *test, |
151 | enum pci_barno barno) | 256 | enum pci_barno barno) |
152 | { | 257 | { |
@@ -179,6 +284,9 @@ static bool pci_endpoint_test_legacy_irq(struct pci_endpoint_test *test) | |||
179 | { | 284 | { |
180 | u32 val; | 285 | u32 val; |
181 | 286 | ||
287 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, | ||
288 | IRQ_TYPE_LEGACY); | ||
289 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 0); | ||
182 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND, | 290 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND, |
183 | COMMAND_RAISE_LEGACY_IRQ); | 291 | COMMAND_RAISE_LEGACY_IRQ); |
184 | val = wait_for_completion_timeout(&test->irq_raised, | 292 | val = wait_for_completion_timeout(&test->irq_raised, |
@@ -190,14 +298,18 @@ static bool pci_endpoint_test_legacy_irq(struct pci_endpoint_test *test) | |||
190 | } | 298 | } |
191 | 299 | ||
192 | static bool pci_endpoint_test_msi_irq(struct pci_endpoint_test *test, | 300 | static bool pci_endpoint_test_msi_irq(struct pci_endpoint_test *test, |
193 | u8 msi_num) | 301 | u16 msi_num, bool msix) |
194 | { | 302 | { |
195 | u32 val; | 303 | u32 val; |
196 | struct pci_dev *pdev = test->pdev; | 304 | struct pci_dev *pdev = test->pdev; |
197 | 305 | ||
306 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, | ||
307 | msix == false ? IRQ_TYPE_MSI : | ||
308 | IRQ_TYPE_MSIX); | ||
309 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, msi_num); | ||
198 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND, | 310 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND, |
199 | msi_num << MSI_NUMBER_SHIFT | | 311 | msix == false ? COMMAND_RAISE_MSI_IRQ : |
200 | COMMAND_RAISE_MSI_IRQ); | 312 | COMMAND_RAISE_MSIX_IRQ); |
201 | val = wait_for_completion_timeout(&test->irq_raised, | 313 | val = wait_for_completion_timeout(&test->irq_raised, |
202 | msecs_to_jiffies(1000)); | 314 | msecs_to_jiffies(1000)); |
203 | if (!val) | 315 | if (!val) |
@@ -230,6 +342,11 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size) | |||
230 | if (size > SIZE_MAX - alignment) | 342 | if (size > SIZE_MAX - alignment) |
231 | goto err; | 343 | goto err; |
232 | 344 | ||
345 | if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) { | ||
346 | dev_err(dev, "Invalid IRQ type option\n"); | ||
347 | goto err; | ||
348 | } | ||
349 | |||
233 | orig_src_addr = dma_alloc_coherent(dev, size + alignment, | 350 | orig_src_addr = dma_alloc_coherent(dev, size + alignment, |
234 | &orig_src_phys_addr, GFP_KERNEL); | 351 | &orig_src_phys_addr, GFP_KERNEL); |
235 | if (!orig_src_addr) { | 352 | if (!orig_src_addr) { |
@@ -281,8 +398,10 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size) | |||
281 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, | 398 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, |
282 | size); | 399 | size); |
283 | 400 | ||
401 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type); | ||
402 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1); | ||
284 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND, | 403 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND, |
285 | 1 << MSI_NUMBER_SHIFT | COMMAND_COPY); | 404 | COMMAND_COPY); |
286 | 405 | ||
287 | wait_for_completion(&test->irq_raised); | 406 | wait_for_completion(&test->irq_raised); |
288 | 407 | ||
@@ -318,6 +437,11 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size) | |||
318 | if (size > SIZE_MAX - alignment) | 437 | if (size > SIZE_MAX - alignment) |
319 | goto err; | 438 | goto err; |
320 | 439 | ||
440 | if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) { | ||
441 | dev_err(dev, "Invalid IRQ type option\n"); | ||
442 | goto err; | ||
443 | } | ||
444 | |||
321 | orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr, | 445 | orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr, |
322 | GFP_KERNEL); | 446 | GFP_KERNEL); |
323 | if (!orig_addr) { | 447 | if (!orig_addr) { |
@@ -348,8 +472,10 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size) | |||
348 | 472 | ||
349 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, size); | 473 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, size); |
350 | 474 | ||
475 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type); | ||
476 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1); | ||
351 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND, | 477 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND, |
352 | 1 << MSI_NUMBER_SHIFT | COMMAND_READ); | 478 | COMMAND_READ); |
353 | 479 | ||
354 | wait_for_completion(&test->irq_raised); | 480 | wait_for_completion(&test->irq_raised); |
355 | 481 | ||
@@ -379,6 +505,11 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size) | |||
379 | if (size > SIZE_MAX - alignment) | 505 | if (size > SIZE_MAX - alignment) |
380 | goto err; | 506 | goto err; |
381 | 507 | ||
508 | if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) { | ||
509 | dev_err(dev, "Invalid IRQ type option\n"); | ||
510 | goto err; | ||
511 | } | ||
512 | |||
382 | orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr, | 513 | orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr, |
383 | GFP_KERNEL); | 514 | GFP_KERNEL); |
384 | if (!orig_addr) { | 515 | if (!orig_addr) { |
@@ -403,8 +534,10 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size) | |||
403 | 534 | ||
404 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, size); | 535 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, size); |
405 | 536 | ||
537 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type); | ||
538 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1); | ||
406 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND, | 539 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND, |
407 | 1 << MSI_NUMBER_SHIFT | COMMAND_WRITE); | 540 | COMMAND_WRITE); |
408 | 541 | ||
409 | wait_for_completion(&test->irq_raised); | 542 | wait_for_completion(&test->irq_raised); |
410 | 543 | ||
@@ -417,6 +550,38 @@ err: | |||
417 | return ret; | 550 | return ret; |
418 | } | 551 | } |
419 | 552 | ||
553 | static bool pci_endpoint_test_set_irq(struct pci_endpoint_test *test, | ||
554 | int req_irq_type) | ||
555 | { | ||
556 | struct pci_dev *pdev = test->pdev; | ||
557 | struct device *dev = &pdev->dev; | ||
558 | |||
559 | if (req_irq_type < IRQ_TYPE_LEGACY || req_irq_type > IRQ_TYPE_MSIX) { | ||
560 | dev_err(dev, "Invalid IRQ type option\n"); | ||
561 | return false; | ||
562 | } | ||
563 | |||
564 | if (irq_type == req_irq_type) | ||
565 | return true; | ||
566 | |||
567 | pci_endpoint_test_release_irq(test); | ||
568 | pci_endpoint_test_free_irq_vectors(test); | ||
569 | |||
570 | if (!pci_endpoint_test_alloc_irq_vectors(test, req_irq_type)) | ||
571 | goto err; | ||
572 | |||
573 | if (!pci_endpoint_test_request_irq(test)) | ||
574 | goto err; | ||
575 | |||
576 | irq_type = req_irq_type; | ||
577 | return true; | ||
578 | |||
579 | err: | ||
580 | pci_endpoint_test_free_irq_vectors(test); | ||
581 | irq_type = IRQ_TYPE_UNDEFINED; | ||
582 | return false; | ||
583 | } | ||
584 | |||
420 | static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd, | 585 | static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd, |
421 | unsigned long arg) | 586 | unsigned long arg) |
422 | { | 587 | { |
@@ -436,7 +601,8 @@ static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd, | |||
436 | ret = pci_endpoint_test_legacy_irq(test); | 601 | ret = pci_endpoint_test_legacy_irq(test); |
437 | break; | 602 | break; |
438 | case PCITEST_MSI: | 603 | case PCITEST_MSI: |
439 | ret = pci_endpoint_test_msi_irq(test, arg); | 604 | case PCITEST_MSIX: |
605 | ret = pci_endpoint_test_msi_irq(test, arg, cmd == PCITEST_MSIX); | ||
440 | break; | 606 | break; |
441 | case PCITEST_WRITE: | 607 | case PCITEST_WRITE: |
442 | ret = pci_endpoint_test_write(test, arg); | 608 | ret = pci_endpoint_test_write(test, arg); |
@@ -447,6 +613,12 @@ static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd, | |||
447 | case PCITEST_COPY: | 613 | case PCITEST_COPY: |
448 | ret = pci_endpoint_test_copy(test, arg); | 614 | ret = pci_endpoint_test_copy(test, arg); |
449 | break; | 615 | break; |
616 | case PCITEST_SET_IRQTYPE: | ||
617 | ret = pci_endpoint_test_set_irq(test, arg); | ||
618 | break; | ||
619 | case PCITEST_GET_IRQTYPE: | ||
620 | ret = irq_type; | ||
621 | break; | ||
450 | } | 622 | } |
451 | 623 | ||
452 | ret: | 624 | ret: |
@@ -462,9 +634,7 @@ static const struct file_operations pci_endpoint_test_fops = { | |||
462 | static int pci_endpoint_test_probe(struct pci_dev *pdev, | 634 | static int pci_endpoint_test_probe(struct pci_dev *pdev, |
463 | const struct pci_device_id *ent) | 635 | const struct pci_device_id *ent) |
464 | { | 636 | { |
465 | int i; | ||
466 | int err; | 637 | int err; |
467 | int irq = 0; | ||
468 | int id; | 638 | int id; |
469 | char name[20]; | 639 | char name[20]; |
470 | enum pci_barno bar; | 640 | enum pci_barno bar; |
@@ -486,11 +656,14 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, | |||
486 | test->alignment = 0; | 656 | test->alignment = 0; |
487 | test->pdev = pdev; | 657 | test->pdev = pdev; |
488 | 658 | ||
659 | if (no_msi) | ||
660 | irq_type = IRQ_TYPE_LEGACY; | ||
661 | |||
489 | data = (struct pci_endpoint_test_data *)ent->driver_data; | 662 | data = (struct pci_endpoint_test_data *)ent->driver_data; |
490 | if (data) { | 663 | if (data) { |
491 | test_reg_bar = data->test_reg_bar; | 664 | test_reg_bar = data->test_reg_bar; |
492 | test->alignment = data->alignment; | 665 | test->alignment = data->alignment; |
493 | no_msi = data->no_msi; | 666 | irq_type = data->irq_type; |
494 | } | 667 | } |
495 | 668 | ||
496 | init_completion(&test->irq_raised); | 669 | init_completion(&test->irq_raised); |
@@ -510,28 +683,11 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, | |||
510 | 683 | ||
511 | pci_set_master(pdev); | 684 | pci_set_master(pdev); |
512 | 685 | ||
513 | if (!no_msi) { | 686 | if (!pci_endpoint_test_alloc_irq_vectors(test, irq_type)) |
514 | irq = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI); | 687 | goto err_disable_irq; |
515 | if (irq < 0) | ||
516 | dev_err(dev, "Failed to get MSI interrupts\n"); | ||
517 | test->num_irqs = irq; | ||
518 | } | ||
519 | |||
520 | err = devm_request_irq(dev, pdev->irq, pci_endpoint_test_irqhandler, | ||
521 | IRQF_SHARED, DRV_MODULE_NAME, test); | ||
522 | if (err) { | ||
523 | dev_err(dev, "Failed to request IRQ %d\n", pdev->irq); | ||
524 | goto err_disable_msi; | ||
525 | } | ||
526 | 688 | ||
527 | for (i = 1; i < irq; i++) { | 689 | if (!pci_endpoint_test_request_irq(test)) |
528 | err = devm_request_irq(dev, pci_irq_vector(pdev, i), | 690 | goto err_disable_irq; |
529 | pci_endpoint_test_irqhandler, | ||
530 | IRQF_SHARED, DRV_MODULE_NAME, test); | ||
531 | if (err) | ||
532 | dev_err(dev, "failed to request IRQ %d for MSI %d\n", | ||
533 | pci_irq_vector(pdev, i), i + 1); | ||
534 | } | ||
535 | 691 | ||
536 | for (bar = BAR_0; bar <= BAR_5; bar++) { | 692 | for (bar = BAR_0; bar <= BAR_5; bar++) { |
537 | if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) { | 693 | if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) { |
@@ -590,12 +746,10 @@ err_iounmap: | |||
590 | if (test->bar[bar]) | 746 | if (test->bar[bar]) |
591 | pci_iounmap(pdev, test->bar[bar]); | 747 | pci_iounmap(pdev, test->bar[bar]); |
592 | } | 748 | } |
749 | pci_endpoint_test_release_irq(test); | ||
593 | 750 | ||
594 | for (i = 0; i < irq; i++) | 751 | err_disable_irq: |
595 | devm_free_irq(&pdev->dev, pci_irq_vector(pdev, i), test); | 752 | pci_endpoint_test_free_irq_vectors(test); |
596 | |||
597 | err_disable_msi: | ||
598 | pci_disable_msi(pdev); | ||
599 | pci_release_regions(pdev); | 753 | pci_release_regions(pdev); |
600 | 754 | ||
601 | err_disable_pdev: | 755 | err_disable_pdev: |
@@ -607,7 +761,6 @@ err_disable_pdev: | |||
607 | static void pci_endpoint_test_remove(struct pci_dev *pdev) | 761 | static void pci_endpoint_test_remove(struct pci_dev *pdev) |
608 | { | 762 | { |
609 | int id; | 763 | int id; |
610 | int i; | ||
611 | enum pci_barno bar; | 764 | enum pci_barno bar; |
612 | struct pci_endpoint_test *test = pci_get_drvdata(pdev); | 765 | struct pci_endpoint_test *test = pci_get_drvdata(pdev); |
613 | struct miscdevice *misc_device = &test->miscdev; | 766 | struct miscdevice *misc_device = &test->miscdev; |
@@ -624,9 +777,10 @@ static void pci_endpoint_test_remove(struct pci_dev *pdev) | |||
624 | if (test->bar[bar]) | 777 | if (test->bar[bar]) |
625 | pci_iounmap(pdev, test->bar[bar]); | 778 | pci_iounmap(pdev, test->bar[bar]); |
626 | } | 779 | } |
627 | for (i = 0; i < test->num_irqs; i++) | 780 | |
628 | devm_free_irq(&pdev->dev, pci_irq_vector(pdev, i), test); | 781 | pci_endpoint_test_release_irq(test); |
629 | pci_disable_msi(pdev); | 782 | pci_endpoint_test_free_irq_vectors(test); |
783 | |||
630 | pci_release_regions(pdev); | 784 | pci_release_regions(pdev); |
631 | pci_disable_device(pdev); | 785 | pci_disable_device(pdev); |
632 | } | 786 | } |
diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c index 345aab56ce8b..ce9224a36f62 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c | |||
@@ -370,7 +370,7 @@ static void dra7xx_pcie_raise_msi_irq(struct dra7xx_pcie *dra7xx, | |||
370 | } | 370 | } |
371 | 371 | ||
372 | static int dra7xx_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no, | 372 | static int dra7xx_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no, |
373 | enum pci_epc_irq_type type, u8 interrupt_num) | 373 | enum pci_epc_irq_type type, u16 interrupt_num) |
374 | { | 374 | { |
375 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | 375 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); |
376 | struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci); | 376 | struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci); |
diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c index 4cc1e5df8c79..cee5f2f590e2 100644 --- a/drivers/pci/controller/dwc/pci-exynos.c +++ b/drivers/pci/controller/dwc/pci-exynos.c | |||
@@ -421,7 +421,6 @@ static int __init exynos_add_pcie_port(struct exynos_pcie *ep, | |||
421 | } | 421 | } |
422 | } | 422 | } |
423 | 423 | ||
424 | pp->root_bus_nr = -1; | ||
425 | pp->ops = &exynos_pcie_host_ops; | 424 | pp->ops = &exynos_pcie_host_ops; |
426 | 425 | ||
427 | ret = dw_pcie_host_init(pp); | 426 | ret = dw_pcie_host_init(pp); |
diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 80f604602783..4a9a673b4777 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c | |||
@@ -667,7 +667,6 @@ static int imx6_add_pcie_port(struct imx6_pcie *imx6_pcie, | |||
667 | } | 667 | } |
668 | } | 668 | } |
669 | 669 | ||
670 | pp->root_bus_nr = -1; | ||
671 | pp->ops = &imx6_pcie_host_ops; | 670 | pp->ops = &imx6_pcie_host_ops; |
672 | 671 | ||
673 | ret = dw_pcie_host_init(pp); | 672 | ret = dw_pcie_host_init(pp); |
diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 3722a5f31e5e..e88bd221fffe 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c | |||
@@ -347,7 +347,6 @@ static int __init ks_add_pcie_port(struct keystone_pcie *ks_pcie, | |||
347 | } | 347 | } |
348 | } | 348 | } |
349 | 349 | ||
350 | pp->root_bus_nr = -1; | ||
351 | pp->ops = &keystone_pcie_host_ops; | 350 | pp->ops = &keystone_pcie_host_ops; |
352 | ret = ks_dw_pcie_host_init(ks_pcie, ks_pcie->msi_intc_np); | 351 | ret = ks_dw_pcie_host_init(ks_pcie, ks_pcie->msi_intc_np); |
353 | if (ret) { | 352 | if (ret) { |
diff --git a/drivers/pci/controller/dwc/pcie-armada8k.c b/drivers/pci/controller/dwc/pcie-armada8k.c index 072fd7ecc29f..0c389a30ef5d 100644 --- a/drivers/pci/controller/dwc/pcie-armada8k.c +++ b/drivers/pci/controller/dwc/pcie-armada8k.c | |||
@@ -172,7 +172,6 @@ static int armada8k_add_pcie_port(struct armada8k_pcie *pcie, | |||
172 | struct device *dev = &pdev->dev; | 172 | struct device *dev = &pdev->dev; |
173 | int ret; | 173 | int ret; |
174 | 174 | ||
175 | pp->root_bus_nr = -1; | ||
176 | pp->ops = &armada8k_pcie_host_ops; | 175 | pp->ops = &armada8k_pcie_host_ops; |
177 | 176 | ||
178 | pp->irq = platform_get_irq(pdev, 0); | 177 | pp->irq = platform_get_irq(pdev, 0); |
diff --git a/drivers/pci/controller/dwc/pcie-artpec6.c b/drivers/pci/controller/dwc/pcie-artpec6.c index 321b56cfd5d0..dba83abfe764 100644 --- a/drivers/pci/controller/dwc/pcie-artpec6.c +++ b/drivers/pci/controller/dwc/pcie-artpec6.c | |||
@@ -399,7 +399,6 @@ static int artpec6_add_pcie_port(struct artpec6_pcie *artpec6_pcie, | |||
399 | } | 399 | } |
400 | } | 400 | } |
401 | 401 | ||
402 | pp->root_bus_nr = -1; | ||
403 | pp->ops = &artpec6_pcie_host_ops; | 402 | pp->ops = &artpec6_pcie_host_ops; |
404 | 403 | ||
405 | ret = dw_pcie_host_init(pp); | 404 | ret = dw_pcie_host_init(pp); |
@@ -428,7 +427,7 @@ static void artpec6_pcie_ep_init(struct dw_pcie_ep *ep) | |||
428 | } | 427 | } |
429 | 428 | ||
430 | static int artpec6_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no, | 429 | static int artpec6_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no, |
431 | enum pci_epc_irq_type type, u8 interrupt_num) | 430 | enum pci_epc_irq_type type, u16 interrupt_num) |
432 | { | 431 | { |
433 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | 432 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); |
434 | 433 | ||
diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 8650416f6f9e..1e7b02221eac 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c | |||
@@ -40,6 +40,39 @@ void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar) | |||
40 | __dw_pcie_ep_reset_bar(pci, bar, 0); | 40 | __dw_pcie_ep_reset_bar(pci, bar, 0); |
41 | } | 41 | } |
42 | 42 | ||
43 | static u8 __dw_pcie_ep_find_next_cap(struct dw_pcie *pci, u8 cap_ptr, | ||
44 | u8 cap) | ||
45 | { | ||
46 | u8 cap_id, next_cap_ptr; | ||
47 | u16 reg; | ||
48 | |||
49 | reg = dw_pcie_readw_dbi(pci, cap_ptr); | ||
50 | next_cap_ptr = (reg & 0xff00) >> 8; | ||
51 | cap_id = (reg & 0x00ff); | ||
52 | |||
53 | if (!next_cap_ptr || cap_id > PCI_CAP_ID_MAX) | ||
54 | return 0; | ||
55 | |||
56 | if (cap_id == cap) | ||
57 | return cap_ptr; | ||
58 | |||
59 | return __dw_pcie_ep_find_next_cap(pci, next_cap_ptr, cap); | ||
60 | } | ||
61 | |||
62 | static u8 dw_pcie_ep_find_capability(struct dw_pcie *pci, u8 cap) | ||
63 | { | ||
64 | u8 next_cap_ptr; | ||
65 | u16 reg; | ||
66 | |||
67 | reg = dw_pcie_readw_dbi(pci, PCI_CAPABILITY_LIST); | ||
68 | next_cap_ptr = (reg & 0x00ff); | ||
69 | |||
70 | if (!next_cap_ptr) | ||
71 | return 0; | ||
72 | |||
73 | return __dw_pcie_ep_find_next_cap(pci, next_cap_ptr, cap); | ||
74 | } | ||
75 | |||
43 | static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, | 76 | static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, |
44 | struct pci_epf_header *hdr) | 77 | struct pci_epf_header *hdr) |
45 | { | 78 | { |
@@ -213,36 +246,84 @@ static int dw_pcie_ep_map_addr(struct pci_epc *epc, u8 func_no, | |||
213 | 246 | ||
214 | static int dw_pcie_ep_get_msi(struct pci_epc *epc, u8 func_no) | 247 | static int dw_pcie_ep_get_msi(struct pci_epc *epc, u8 func_no) |
215 | { | 248 | { |
216 | int val; | ||
217 | struct dw_pcie_ep *ep = epc_get_drvdata(epc); | 249 | struct dw_pcie_ep *ep = epc_get_drvdata(epc); |
218 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | 250 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); |
251 | u32 val, reg; | ||
252 | |||
253 | if (!ep->msi_cap) | ||
254 | return -EINVAL; | ||
255 | |||
256 | reg = ep->msi_cap + PCI_MSI_FLAGS; | ||
257 | val = dw_pcie_readw_dbi(pci, reg); | ||
258 | if (!(val & PCI_MSI_FLAGS_ENABLE)) | ||
259 | return -EINVAL; | ||
260 | |||
261 | val = (val & PCI_MSI_FLAGS_QSIZE) >> 4; | ||
262 | |||
263 | return val; | ||
264 | } | ||
265 | |||
266 | static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 interrupts) | ||
267 | { | ||
268 | struct dw_pcie_ep *ep = epc_get_drvdata(epc); | ||
269 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | ||
270 | u32 val, reg; | ||
271 | |||
272 | if (!ep->msi_cap) | ||
273 | return -EINVAL; | ||
274 | |||
275 | reg = ep->msi_cap + PCI_MSI_FLAGS; | ||
276 | val = dw_pcie_readw_dbi(pci, reg); | ||
277 | val &= ~PCI_MSI_FLAGS_QMASK; | ||
278 | val |= (interrupts << 1) & PCI_MSI_FLAGS_QMASK; | ||
279 | dw_pcie_dbi_ro_wr_en(pci); | ||
280 | dw_pcie_writew_dbi(pci, reg, val); | ||
281 | dw_pcie_dbi_ro_wr_dis(pci); | ||
282 | |||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | static int dw_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no) | ||
287 | { | ||
288 | struct dw_pcie_ep *ep = epc_get_drvdata(epc); | ||
289 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | ||
290 | u32 val, reg; | ||
219 | 291 | ||
220 | val = dw_pcie_readw_dbi(pci, MSI_MESSAGE_CONTROL); | 292 | if (!ep->msix_cap) |
221 | if (!(val & MSI_CAP_MSI_EN_MASK)) | ||
222 | return -EINVAL; | 293 | return -EINVAL; |
223 | 294 | ||
224 | val = (val & MSI_CAP_MME_MASK) >> MSI_CAP_MME_SHIFT; | 295 | reg = ep->msix_cap + PCI_MSIX_FLAGS; |
296 | val = dw_pcie_readw_dbi(pci, reg); | ||
297 | if (!(val & PCI_MSIX_FLAGS_ENABLE)) | ||
298 | return -EINVAL; | ||
299 | |||
300 | val &= PCI_MSIX_FLAGS_QSIZE; | ||
301 | |||
225 | return val; | 302 | return val; |
226 | } | 303 | } |
227 | 304 | ||
228 | static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 encode_int) | 305 | static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts) |
229 | { | 306 | { |
230 | int val; | ||
231 | struct dw_pcie_ep *ep = epc_get_drvdata(epc); | 307 | struct dw_pcie_ep *ep = epc_get_drvdata(epc); |
232 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | 308 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); |
309 | u32 val, reg; | ||
310 | |||
311 | if (!ep->msix_cap) | ||
312 | return -EINVAL; | ||
233 | 313 | ||
234 | val = dw_pcie_readw_dbi(pci, MSI_MESSAGE_CONTROL); | 314 | reg = ep->msix_cap + PCI_MSIX_FLAGS; |
235 | val &= ~MSI_CAP_MMC_MASK; | 315 | val = dw_pcie_readw_dbi(pci, reg); |
236 | val |= (encode_int << MSI_CAP_MMC_SHIFT) & MSI_CAP_MMC_MASK; | 316 | val &= ~PCI_MSIX_FLAGS_QSIZE; |
317 | val |= interrupts; | ||
237 | dw_pcie_dbi_ro_wr_en(pci); | 318 | dw_pcie_dbi_ro_wr_en(pci); |
238 | dw_pcie_writew_dbi(pci, MSI_MESSAGE_CONTROL, val); | 319 | dw_pcie_writew_dbi(pci, reg, val); |
239 | dw_pcie_dbi_ro_wr_dis(pci); | 320 | dw_pcie_dbi_ro_wr_dis(pci); |
240 | 321 | ||
241 | return 0; | 322 | return 0; |
242 | } | 323 | } |
243 | 324 | ||
244 | static int dw_pcie_ep_raise_irq(struct pci_epc *epc, u8 func_no, | 325 | static int dw_pcie_ep_raise_irq(struct pci_epc *epc, u8 func_no, |
245 | enum pci_epc_irq_type type, u8 interrupt_num) | 326 | enum pci_epc_irq_type type, u16 interrupt_num) |
246 | { | 327 | { |
247 | struct dw_pcie_ep *ep = epc_get_drvdata(epc); | 328 | struct dw_pcie_ep *ep = epc_get_drvdata(epc); |
248 | 329 | ||
@@ -282,32 +363,52 @@ static const struct pci_epc_ops epc_ops = { | |||
282 | .unmap_addr = dw_pcie_ep_unmap_addr, | 363 | .unmap_addr = dw_pcie_ep_unmap_addr, |
283 | .set_msi = dw_pcie_ep_set_msi, | 364 | .set_msi = dw_pcie_ep_set_msi, |
284 | .get_msi = dw_pcie_ep_get_msi, | 365 | .get_msi = dw_pcie_ep_get_msi, |
366 | .set_msix = dw_pcie_ep_set_msix, | ||
367 | .get_msix = dw_pcie_ep_get_msix, | ||
285 | .raise_irq = dw_pcie_ep_raise_irq, | 368 | .raise_irq = dw_pcie_ep_raise_irq, |
286 | .start = dw_pcie_ep_start, | 369 | .start = dw_pcie_ep_start, |
287 | .stop = dw_pcie_ep_stop, | 370 | .stop = dw_pcie_ep_stop, |
288 | }; | 371 | }; |
289 | 372 | ||
373 | int dw_pcie_ep_raise_legacy_irq(struct dw_pcie_ep *ep, u8 func_no) | ||
374 | { | ||
375 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | ||
376 | struct device *dev = pci->dev; | ||
377 | |||
378 | dev_err(dev, "EP cannot trigger legacy IRQs\n"); | ||
379 | |||
380 | return -EINVAL; | ||
381 | } | ||
382 | |||
290 | int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, | 383 | int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, |
291 | u8 interrupt_num) | 384 | u8 interrupt_num) |
292 | { | 385 | { |
293 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | 386 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); |
294 | struct pci_epc *epc = ep->epc; | 387 | struct pci_epc *epc = ep->epc; |
295 | u16 msg_ctrl, msg_data; | 388 | u16 msg_ctrl, msg_data; |
296 | u32 msg_addr_lower, msg_addr_upper; | 389 | u32 msg_addr_lower, msg_addr_upper, reg; |
297 | u64 msg_addr; | 390 | u64 msg_addr; |
298 | bool has_upper; | 391 | bool has_upper; |
299 | int ret; | 392 | int ret; |
300 | 393 | ||
394 | if (!ep->msi_cap) | ||
395 | return -EINVAL; | ||
396 | |||
301 | /* Raise MSI per the PCI Local Bus Specification Revision 3.0, 6.8.1. */ | 397 | /* Raise MSI per the PCI Local Bus Specification Revision 3.0, 6.8.1. */ |
302 | msg_ctrl = dw_pcie_readw_dbi(pci, MSI_MESSAGE_CONTROL); | 398 | reg = ep->msi_cap + PCI_MSI_FLAGS; |
399 | msg_ctrl = dw_pcie_readw_dbi(pci, reg); | ||
303 | has_upper = !!(msg_ctrl & PCI_MSI_FLAGS_64BIT); | 400 | has_upper = !!(msg_ctrl & PCI_MSI_FLAGS_64BIT); |
304 | msg_addr_lower = dw_pcie_readl_dbi(pci, MSI_MESSAGE_ADDR_L32); | 401 | reg = ep->msi_cap + PCI_MSI_ADDRESS_LO; |
402 | msg_addr_lower = dw_pcie_readl_dbi(pci, reg); | ||
305 | if (has_upper) { | 403 | if (has_upper) { |
306 | msg_addr_upper = dw_pcie_readl_dbi(pci, MSI_MESSAGE_ADDR_U32); | 404 | reg = ep->msi_cap + PCI_MSI_ADDRESS_HI; |
307 | msg_data = dw_pcie_readw_dbi(pci, MSI_MESSAGE_DATA_64); | 405 | msg_addr_upper = dw_pcie_readl_dbi(pci, reg); |
406 | reg = ep->msi_cap + PCI_MSI_DATA_64; | ||
407 | msg_data = dw_pcie_readw_dbi(pci, reg); | ||
308 | } else { | 408 | } else { |
309 | msg_addr_upper = 0; | 409 | msg_addr_upper = 0; |
310 | msg_data = dw_pcie_readw_dbi(pci, MSI_MESSAGE_DATA_32); | 410 | reg = ep->msi_cap + PCI_MSI_DATA_32; |
411 | msg_data = dw_pcie_readw_dbi(pci, reg); | ||
311 | } | 412 | } |
312 | msg_addr = ((u64) msg_addr_upper) << 32 | msg_addr_lower; | 413 | msg_addr = ((u64) msg_addr_upper) << 32 | msg_addr_lower; |
313 | ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys, msg_addr, | 414 | ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys, msg_addr, |
@@ -322,6 +423,64 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, | |||
322 | return 0; | 423 | return 0; |
323 | } | 424 | } |
324 | 425 | ||
426 | int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, | ||
427 | u16 interrupt_num) | ||
428 | { | ||
429 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | ||
430 | struct pci_epc *epc = ep->epc; | ||
431 | u16 tbl_offset, bir; | ||
432 | u32 bar_addr_upper, bar_addr_lower; | ||
433 | u32 msg_addr_upper, msg_addr_lower; | ||
434 | u32 reg, msg_data, vec_ctrl; | ||
435 | u64 tbl_addr, msg_addr, reg_u64; | ||
436 | void __iomem *msix_tbl; | ||
437 | int ret; | ||
438 | |||
439 | reg = ep->msix_cap + PCI_MSIX_TABLE; | ||
440 | tbl_offset = dw_pcie_readl_dbi(pci, reg); | ||
441 | bir = (tbl_offset & PCI_MSIX_TABLE_BIR); | ||
442 | tbl_offset &= PCI_MSIX_TABLE_OFFSET; | ||
443 | tbl_offset >>= 3; | ||
444 | |||
445 | reg = PCI_BASE_ADDRESS_0 + (4 * bir); | ||
446 | bar_addr_upper = 0; | ||
447 | bar_addr_lower = dw_pcie_readl_dbi(pci, reg); | ||
448 | reg_u64 = (bar_addr_lower & PCI_BASE_ADDRESS_MEM_TYPE_MASK); | ||
449 | if (reg_u64 == PCI_BASE_ADDRESS_MEM_TYPE_64) | ||
450 | bar_addr_upper = dw_pcie_readl_dbi(pci, reg + 4); | ||
451 | |||
452 | tbl_addr = ((u64) bar_addr_upper) << 32 | bar_addr_lower; | ||
453 | tbl_addr += (tbl_offset + ((interrupt_num - 1) * PCI_MSIX_ENTRY_SIZE)); | ||
454 | tbl_addr &= PCI_BASE_ADDRESS_MEM_MASK; | ||
455 | |||
456 | msix_tbl = ioremap_nocache(ep->phys_base + tbl_addr, | ||
457 | PCI_MSIX_ENTRY_SIZE); | ||
458 | if (!msix_tbl) | ||
459 | return -EINVAL; | ||
460 | |||
461 | msg_addr_lower = readl(msix_tbl + PCI_MSIX_ENTRY_LOWER_ADDR); | ||
462 | msg_addr_upper = readl(msix_tbl + PCI_MSIX_ENTRY_UPPER_ADDR); | ||
463 | msg_addr = ((u64) msg_addr_upper) << 32 | msg_addr_lower; | ||
464 | msg_data = readl(msix_tbl + PCI_MSIX_ENTRY_DATA); | ||
465 | vec_ctrl = readl(msix_tbl + PCI_MSIX_ENTRY_VECTOR_CTRL); | ||
466 | |||
467 | iounmap(msix_tbl); | ||
468 | |||
469 | if (vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT) | ||
470 | return -EPERM; | ||
471 | |||
472 | ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys, msg_addr, | ||
473 | epc->mem->page_size); | ||
474 | if (ret) | ||
475 | return ret; | ||
476 | |||
477 | writel(msg_data, ep->msi_mem); | ||
478 | |||
479 | dw_pcie_ep_unmap_addr(epc, func_no, ep->msi_mem_phys); | ||
480 | |||
481 | return 0; | ||
482 | } | ||
483 | |||
325 | void dw_pcie_ep_exit(struct dw_pcie_ep *ep) | 484 | void dw_pcie_ep_exit(struct dw_pcie_ep *ep) |
326 | { | 485 | { |
327 | struct pci_epc *epc = ep->epc; | 486 | struct pci_epc *epc = ep->epc; |
@@ -386,15 +545,18 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) | |||
386 | return -ENOMEM; | 545 | return -ENOMEM; |
387 | ep->outbound_addr = addr; | 546 | ep->outbound_addr = addr; |
388 | 547 | ||
389 | if (ep->ops->ep_init) | ||
390 | ep->ops->ep_init(ep); | ||
391 | |||
392 | epc = devm_pci_epc_create(dev, &epc_ops); | 548 | epc = devm_pci_epc_create(dev, &epc_ops); |
393 | if (IS_ERR(epc)) { | 549 | if (IS_ERR(epc)) { |
394 | dev_err(dev, "Failed to create epc device\n"); | 550 | dev_err(dev, "Failed to create epc device\n"); |
395 | return PTR_ERR(epc); | 551 | return PTR_ERR(epc); |
396 | } | 552 | } |
397 | 553 | ||
554 | ep->epc = epc; | ||
555 | epc_set_drvdata(epc, ep); | ||
556 | |||
557 | if (ep->ops->ep_init) | ||
558 | ep->ops->ep_init(ep); | ||
559 | |||
398 | ret = of_property_read_u8(np, "max-functions", &epc->max_functions); | 560 | ret = of_property_read_u8(np, "max-functions", &epc->max_functions); |
399 | if (ret < 0) | 561 | if (ret < 0) |
400 | epc->max_functions = 1; | 562 | epc->max_functions = 1; |
@@ -409,15 +571,13 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) | |||
409 | ep->msi_mem = pci_epc_mem_alloc_addr(epc, &ep->msi_mem_phys, | 571 | ep->msi_mem = pci_epc_mem_alloc_addr(epc, &ep->msi_mem_phys, |
410 | epc->mem->page_size); | 572 | epc->mem->page_size); |
411 | if (!ep->msi_mem) { | 573 | if (!ep->msi_mem) { |
412 | dev_err(dev, "Failed to reserve memory for MSI\n"); | 574 | dev_err(dev, "Failed to reserve memory for MSI/MSI-X\n"); |
413 | return -ENOMEM; | 575 | return -ENOMEM; |
414 | } | 576 | } |
577 | ep->msi_cap = dw_pcie_ep_find_capability(pci, PCI_CAP_ID_MSI); | ||
415 | 578 | ||
416 | epc->features = EPC_FEATURE_NO_LINKUP_NOTIFIER; | 579 | ep->msix_cap = dw_pcie_ep_find_capability(pci, PCI_CAP_ID_MSIX); |
417 | EPC_FEATURE_SET_BAR(epc->features, BAR_0); | ||
418 | 580 | ||
419 | ep->epc = epc; | ||
420 | epc_set_drvdata(epc, ep); | ||
421 | dw_pcie_setup(pci); | 581 | dw_pcie_setup(pci); |
422 | 582 | ||
423 | return 0; | 583 | return 0; |
diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c index 5937fed4c938..c12bf794d69c 100644 --- a/drivers/pci/controller/dwc/pcie-designware-plat.c +++ b/drivers/pci/controller/dwc/pcie-designware-plat.c | |||
@@ -70,24 +70,29 @@ static const struct dw_pcie_ops dw_pcie_ops = { | |||
70 | static void dw_plat_pcie_ep_init(struct dw_pcie_ep *ep) | 70 | static void dw_plat_pcie_ep_init(struct dw_pcie_ep *ep) |
71 | { | 71 | { |
72 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | 72 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); |
73 | struct pci_epc *epc = ep->epc; | ||
73 | enum pci_barno bar; | 74 | enum pci_barno bar; |
74 | 75 | ||
75 | for (bar = BAR_0; bar <= BAR_5; bar++) | 76 | for (bar = BAR_0; bar <= BAR_5; bar++) |
76 | dw_pcie_ep_reset_bar(pci, bar); | 77 | dw_pcie_ep_reset_bar(pci, bar); |
78 | |||
79 | epc->features |= EPC_FEATURE_NO_LINKUP_NOTIFIER; | ||
80 | epc->features |= EPC_FEATURE_MSIX_AVAILABLE; | ||
77 | } | 81 | } |
78 | 82 | ||
79 | static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, | 83 | static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, |
80 | enum pci_epc_irq_type type, | 84 | enum pci_epc_irq_type type, |
81 | u8 interrupt_num) | 85 | u16 interrupt_num) |
82 | { | 86 | { |
83 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | 87 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); |
84 | 88 | ||
85 | switch (type) { | 89 | switch (type) { |
86 | case PCI_EPC_IRQ_LEGACY: | 90 | case PCI_EPC_IRQ_LEGACY: |
87 | dev_err(pci->dev, "EP cannot trigger legacy IRQs\n"); | 91 | return dw_pcie_ep_raise_legacy_irq(ep, func_no); |
88 | return -EINVAL; | ||
89 | case PCI_EPC_IRQ_MSI: | 92 | case PCI_EPC_IRQ_MSI: |
90 | return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num); | 93 | return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num); |
94 | case PCI_EPC_IRQ_MSIX: | ||
95 | return dw_pcie_ep_raise_msix_irq(ep, func_no, interrupt_num); | ||
91 | default: | 96 | default: |
92 | dev_err(pci->dev, "UNKNOWN IRQ type\n"); | 97 | dev_err(pci->dev, "UNKNOWN IRQ type\n"); |
93 | } | 98 | } |
@@ -118,7 +123,6 @@ static int dw_plat_add_pcie_port(struct dw_plat_pcie *dw_plat_pcie, | |||
118 | return pp->msi_irq; | 123 | return pp->msi_irq; |
119 | } | 124 | } |
120 | 125 | ||
121 | pp->root_bus_nr = -1; | ||
122 | pp->ops = &dw_plat_pcie_host_ops; | 126 | pp->ops = &dw_plat_pcie_host_ops; |
123 | 127 | ||
124 | ret = dw_pcie_host_init(pp); | 128 | ret = dw_pcie_host_init(pp); |
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index bee4e2535a61..96126fd8403c 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h | |||
@@ -96,17 +96,6 @@ | |||
96 | #define PCIE_GET_ATU_INB_UNR_REG_OFFSET(region) \ | 96 | #define PCIE_GET_ATU_INB_UNR_REG_OFFSET(region) \ |
97 | ((0x3 << 20) | ((region) << 9) | (0x1 << 8)) | 97 | ((0x3 << 20) | ((region) << 9) | (0x1 << 8)) |
98 | 98 | ||
99 | #define MSI_MESSAGE_CONTROL 0x52 | ||
100 | #define MSI_CAP_MMC_SHIFT 1 | ||
101 | #define MSI_CAP_MMC_MASK (7 << MSI_CAP_MMC_SHIFT) | ||
102 | #define MSI_CAP_MME_SHIFT 4 | ||
103 | #define MSI_CAP_MSI_EN_MASK 0x1 | ||
104 | #define MSI_CAP_MME_MASK (7 << MSI_CAP_MME_SHIFT) | ||
105 | #define MSI_MESSAGE_ADDR_L32 0x54 | ||
106 | #define MSI_MESSAGE_ADDR_U32 0x58 | ||
107 | #define MSI_MESSAGE_DATA_32 0x58 | ||
108 | #define MSI_MESSAGE_DATA_64 0x5C | ||
109 | |||
110 | #define MAX_MSI_IRQS 256 | 99 | #define MAX_MSI_IRQS 256 |
111 | #define MAX_MSI_IRQS_PER_CTRL 32 | 100 | #define MAX_MSI_IRQS_PER_CTRL 32 |
112 | #define MAX_MSI_CTRLS (MAX_MSI_IRQS / MAX_MSI_IRQS_PER_CTRL) | 101 | #define MAX_MSI_CTRLS (MAX_MSI_IRQS / MAX_MSI_IRQS_PER_CTRL) |
@@ -191,7 +180,7 @@ enum dw_pcie_as_type { | |||
191 | struct dw_pcie_ep_ops { | 180 | struct dw_pcie_ep_ops { |
192 | void (*ep_init)(struct dw_pcie_ep *ep); | 181 | void (*ep_init)(struct dw_pcie_ep *ep); |
193 | int (*raise_irq)(struct dw_pcie_ep *ep, u8 func_no, | 182 | int (*raise_irq)(struct dw_pcie_ep *ep, u8 func_no, |
194 | enum pci_epc_irq_type type, u8 interrupt_num); | 183 | enum pci_epc_irq_type type, u16 interrupt_num); |
195 | }; | 184 | }; |
196 | 185 | ||
197 | struct dw_pcie_ep { | 186 | struct dw_pcie_ep { |
@@ -208,6 +197,8 @@ struct dw_pcie_ep { | |||
208 | u32 num_ob_windows; | 197 | u32 num_ob_windows; |
209 | void __iomem *msi_mem; | 198 | void __iomem *msi_mem; |
210 | phys_addr_t msi_mem_phys; | 199 | phys_addr_t msi_mem_phys; |
200 | u8 msi_cap; /* MSI capability offset */ | ||
201 | u8 msix_cap; /* MSI-X capability offset */ | ||
211 | }; | 202 | }; |
212 | 203 | ||
213 | struct dw_pcie_ops { | 204 | struct dw_pcie_ops { |
@@ -357,8 +348,11 @@ static inline int dw_pcie_allocate_domains(struct pcie_port *pp) | |||
357 | void dw_pcie_ep_linkup(struct dw_pcie_ep *ep); | 348 | void dw_pcie_ep_linkup(struct dw_pcie_ep *ep); |
358 | int dw_pcie_ep_init(struct dw_pcie_ep *ep); | 349 | int dw_pcie_ep_init(struct dw_pcie_ep *ep); |
359 | void dw_pcie_ep_exit(struct dw_pcie_ep *ep); | 350 | void dw_pcie_ep_exit(struct dw_pcie_ep *ep); |
351 | int dw_pcie_ep_raise_legacy_irq(struct dw_pcie_ep *ep, u8 func_no); | ||
360 | int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, | 352 | int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, |
361 | u8 interrupt_num); | 353 | u8 interrupt_num); |
354 | int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, | ||
355 | u16 interrupt_num); | ||
362 | void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar); | 356 | void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar); |
363 | #else | 357 | #else |
364 | static inline void dw_pcie_ep_linkup(struct dw_pcie_ep *ep) | 358 | static inline void dw_pcie_ep_linkup(struct dw_pcie_ep *ep) |
@@ -374,12 +368,23 @@ static inline void dw_pcie_ep_exit(struct dw_pcie_ep *ep) | |||
374 | { | 368 | { |
375 | } | 369 | } |
376 | 370 | ||
371 | static inline int dw_pcie_ep_raise_legacy_irq(struct dw_pcie_ep *ep, u8 func_no) | ||
372 | { | ||
373 | return 0; | ||
374 | } | ||
375 | |||
377 | static inline int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, | 376 | static inline int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, |
378 | u8 interrupt_num) | 377 | u8 interrupt_num) |
379 | { | 378 | { |
380 | return 0; | 379 | return 0; |
381 | } | 380 | } |
382 | 381 | ||
382 | static inline int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, | ||
383 | u16 interrupt_num) | ||
384 | { | ||
385 | return 0; | ||
386 | } | ||
387 | |||
383 | static inline void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar) | 388 | static inline void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar) |
384 | { | 389 | { |
385 | } | 390 | } |
diff --git a/drivers/pci/controller/dwc/pcie-histb.c b/drivers/pci/controller/dwc/pcie-histb.c index 3611d6ce9a92..7b32e619b959 100644 --- a/drivers/pci/controller/dwc/pcie-histb.c +++ b/drivers/pci/controller/dwc/pcie-histb.c | |||
@@ -420,7 +420,6 @@ static int histb_pcie_probe(struct platform_device *pdev) | |||
420 | phy_init(hipcie->phy); | 420 | phy_init(hipcie->phy); |
421 | } | 421 | } |
422 | 422 | ||
423 | pp->root_bus_nr = -1; | ||
424 | pp->ops = &histb_pcie_host_ops; | 423 | pp->ops = &histb_pcie_host_ops; |
425 | 424 | ||
426 | platform_set_drvdata(pdev, hipcie); | 425 | platform_set_drvdata(pdev, hipcie); |
diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c index d2970a009eb5..5352e0c3be82 100644 --- a/drivers/pci/controller/dwc/pcie-kirin.c +++ b/drivers/pci/controller/dwc/pcie-kirin.c | |||
@@ -430,6 +430,9 @@ static int kirin_pcie_host_init(struct pcie_port *pp) | |||
430 | { | 430 | { |
431 | kirin_pcie_establish_link(pp); | 431 | kirin_pcie_establish_link(pp); |
432 | 432 | ||
433 | if (IS_ENABLED(CONFIG_PCI_MSI)) | ||
434 | dw_pcie_msi_init(pp); | ||
435 | |||
433 | return 0; | 436 | return 0; |
434 | } | 437 | } |
435 | 438 | ||
@@ -445,9 +448,34 @@ static const struct dw_pcie_host_ops kirin_pcie_host_ops = { | |||
445 | .host_init = kirin_pcie_host_init, | 448 | .host_init = kirin_pcie_host_init, |
446 | }; | 449 | }; |
447 | 450 | ||
451 | static int kirin_pcie_add_msi(struct dw_pcie *pci, | ||
452 | struct platform_device *pdev) | ||
453 | { | ||
454 | int irq; | ||
455 | |||
456 | if (IS_ENABLED(CONFIG_PCI_MSI)) { | ||
457 | irq = platform_get_irq(pdev, 0); | ||
458 | if (irq < 0) { | ||
459 | dev_err(&pdev->dev, | ||
460 | "failed to get MSI IRQ (%d)\n", irq); | ||
461 | return irq; | ||
462 | } | ||
463 | |||
464 | pci->pp.msi_irq = irq; | ||
465 | } | ||
466 | |||
467 | return 0; | ||
468 | } | ||
469 | |||
448 | static int __init kirin_add_pcie_port(struct dw_pcie *pci, | 470 | static int __init kirin_add_pcie_port(struct dw_pcie *pci, |
449 | struct platform_device *pdev) | 471 | struct platform_device *pdev) |
450 | { | 472 | { |
473 | int ret; | ||
474 | |||
475 | ret = kirin_pcie_add_msi(pci, pdev); | ||
476 | if (ret) | ||
477 | return ret; | ||
478 | |||
451 | pci->pp.ops = &kirin_pcie_host_ops; | 479 | pci->pp.ops = &kirin_pcie_host_ops; |
452 | 480 | ||
453 | return dw_pcie_host_init(&pci->pp); | 481 | return dw_pcie_host_init(&pci->pp); |
diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index a1d0198081a6..4352c1cb926d 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c | |||
@@ -1251,7 +1251,6 @@ static int qcom_pcie_probe(struct platform_device *pdev) | |||
1251 | if (ret) | 1251 | if (ret) |
1252 | return ret; | 1252 | return ret; |
1253 | 1253 | ||
1254 | pp->root_bus_nr = -1; | ||
1255 | pp->ops = &qcom_pcie_dw_ops; | 1254 | pp->ops = &qcom_pcie_dw_ops; |
1256 | 1255 | ||
1257 | if (IS_ENABLED(CONFIG_PCI_MSI)) { | 1256 | if (IS_ENABLED(CONFIG_PCI_MSI)) { |
diff --git a/drivers/pci/controller/dwc/pcie-spear13xx.c b/drivers/pci/controller/dwc/pcie-spear13xx.c index ecb58f7b7566..7d0cdfd8138b 100644 --- a/drivers/pci/controller/dwc/pcie-spear13xx.c +++ b/drivers/pci/controller/dwc/pcie-spear13xx.c | |||
@@ -210,7 +210,6 @@ static int spear13xx_add_pcie_port(struct spear13xx_pcie *spear13xx_pcie, | |||
210 | return ret; | 210 | return ret; |
211 | } | 211 | } |
212 | 212 | ||
213 | pp->root_bus_nr = -1; | ||
214 | pp->ops = &spear13xx_pcie_host_ops; | 213 | pp->ops = &spear13xx_pcie_host_ops; |
215 | 214 | ||
216 | ret = dw_pcie_host_init(pp); | 215 | ret = dw_pcie_host_init(pp); |
diff --git a/drivers/pci/controller/pcie-cadence-ep.c b/drivers/pci/controller/pcie-cadence-ep.c index 04fe76c3d59d..9e87dd7f9ac3 100644 --- a/drivers/pci/controller/pcie-cadence-ep.c +++ b/drivers/pci/controller/pcie-cadence-ep.c | |||
@@ -362,7 +362,8 @@ static int cdns_pcie_ep_send_msi_irq(struct cdns_pcie_ep *ep, u8 fn, | |||
362 | } | 362 | } |
363 | 363 | ||
364 | static int cdns_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn, | 364 | static int cdns_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn, |
365 | enum pci_epc_irq_type type, u8 interrupt_num) | 365 | enum pci_epc_irq_type type, |
366 | u16 interrupt_num) | ||
366 | { | 367 | { |
367 | struct cdns_pcie_ep *ep = epc_get_drvdata(epc); | 368 | struct cdns_pcie_ep *ep = epc_get_drvdata(epc); |
368 | 369 | ||
diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c index 6beba8ed7b84..b8163c56a142 100644 --- a/drivers/pci/controller/pcie-rockchip-ep.c +++ b/drivers/pci/controller/pcie-rockchip-ep.c | |||
@@ -472,7 +472,7 @@ static int rockchip_pcie_ep_send_msi_irq(struct rockchip_pcie_ep *ep, u8 fn, | |||
472 | 472 | ||
473 | static int rockchip_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn, | 473 | static int rockchip_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn, |
474 | enum pci_epc_irq_type type, | 474 | enum pci_epc_irq_type type, |
475 | u8 interrupt_num) | 475 | u16 interrupt_num) |
476 | { | 476 | { |
477 | struct rockchip_pcie_ep *ep = epc_get_drvdata(epc); | 477 | struct rockchip_pcie_ep *ep = epc_get_drvdata(epc); |
478 | 478 | ||
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c index 63ed706445b9..3e86fa3c7da3 100644 --- a/drivers/pci/endpoint/functions/pci-epf-test.c +++ b/drivers/pci/endpoint/functions/pci-epf-test.c | |||
@@ -18,13 +18,16 @@ | |||
18 | #include <linux/pci-epf.h> | 18 | #include <linux/pci-epf.h> |
19 | #include <linux/pci_regs.h> | 19 | #include <linux/pci_regs.h> |
20 | 20 | ||
21 | #define IRQ_TYPE_LEGACY 0 | ||
22 | #define IRQ_TYPE_MSI 1 | ||
23 | #define IRQ_TYPE_MSIX 2 | ||
24 | |||
21 | #define COMMAND_RAISE_LEGACY_IRQ BIT(0) | 25 | #define COMMAND_RAISE_LEGACY_IRQ BIT(0) |
22 | #define COMMAND_RAISE_MSI_IRQ BIT(1) | 26 | #define COMMAND_RAISE_MSI_IRQ BIT(1) |
23 | #define MSI_NUMBER_SHIFT 2 | 27 | #define COMMAND_RAISE_MSIX_IRQ BIT(2) |
24 | #define MSI_NUMBER_MASK (0x3f << MSI_NUMBER_SHIFT) | 28 | #define COMMAND_READ BIT(3) |
25 | #define COMMAND_READ BIT(8) | 29 | #define COMMAND_WRITE BIT(4) |
26 | #define COMMAND_WRITE BIT(9) | 30 | #define COMMAND_COPY BIT(5) |
27 | #define COMMAND_COPY BIT(10) | ||
28 | 31 | ||
29 | #define STATUS_READ_SUCCESS BIT(0) | 32 | #define STATUS_READ_SUCCESS BIT(0) |
30 | #define STATUS_READ_FAIL BIT(1) | 33 | #define STATUS_READ_FAIL BIT(1) |
@@ -45,6 +48,7 @@ struct pci_epf_test { | |||
45 | struct pci_epf *epf; | 48 | struct pci_epf *epf; |
46 | enum pci_barno test_reg_bar; | 49 | enum pci_barno test_reg_bar; |
47 | bool linkup_notifier; | 50 | bool linkup_notifier; |
51 | bool msix_available; | ||
48 | struct delayed_work cmd_handler; | 52 | struct delayed_work cmd_handler; |
49 | }; | 53 | }; |
50 | 54 | ||
@@ -56,6 +60,8 @@ struct pci_epf_test_reg { | |||
56 | u64 dst_addr; | 60 | u64 dst_addr; |
57 | u32 size; | 61 | u32 size; |
58 | u32 checksum; | 62 | u32 checksum; |
63 | u32 irq_type; | ||
64 | u32 irq_number; | ||
59 | } __packed; | 65 | } __packed; |
60 | 66 | ||
61 | static struct pci_epf_header test_header = { | 67 | static struct pci_epf_header test_header = { |
@@ -244,31 +250,42 @@ err: | |||
244 | return ret; | 250 | return ret; |
245 | } | 251 | } |
246 | 252 | ||
247 | static void pci_epf_test_raise_irq(struct pci_epf_test *epf_test, u8 irq) | 253 | static void pci_epf_test_raise_irq(struct pci_epf_test *epf_test, u8 irq_type, |
254 | u16 irq) | ||
248 | { | 255 | { |
249 | u8 msi_count; | ||
250 | struct pci_epf *epf = epf_test->epf; | 256 | struct pci_epf *epf = epf_test->epf; |
257 | struct device *dev = &epf->dev; | ||
251 | struct pci_epc *epc = epf->epc; | 258 | struct pci_epc *epc = epf->epc; |
252 | enum pci_barno test_reg_bar = epf_test->test_reg_bar; | 259 | enum pci_barno test_reg_bar = epf_test->test_reg_bar; |
253 | struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar]; | 260 | struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar]; |
254 | 261 | ||
255 | reg->status |= STATUS_IRQ_RAISED; | 262 | reg->status |= STATUS_IRQ_RAISED; |
256 | msi_count = pci_epc_get_msi(epc, epf->func_no); | 263 | |
257 | if (irq > msi_count || msi_count <= 0) | 264 | switch (irq_type) { |
265 | case IRQ_TYPE_LEGACY: | ||
258 | pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_LEGACY, 0); | 266 | pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_LEGACY, 0); |
259 | else | 267 | break; |
268 | case IRQ_TYPE_MSI: | ||
260 | pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_MSI, irq); | 269 | pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_MSI, irq); |
270 | break; | ||
271 | case IRQ_TYPE_MSIX: | ||
272 | pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_MSIX, irq); | ||
273 | break; | ||
274 | default: | ||
275 | dev_err(dev, "Failed to raise IRQ, unknown type\n"); | ||
276 | break; | ||
277 | } | ||
261 | } | 278 | } |
262 | 279 | ||
263 | static void pci_epf_test_cmd_handler(struct work_struct *work) | 280 | static void pci_epf_test_cmd_handler(struct work_struct *work) |
264 | { | 281 | { |
265 | int ret; | 282 | int ret; |
266 | u8 irq; | 283 | int count; |
267 | u8 msi_count; | ||
268 | u32 command; | 284 | u32 command; |
269 | struct pci_epf_test *epf_test = container_of(work, struct pci_epf_test, | 285 | struct pci_epf_test *epf_test = container_of(work, struct pci_epf_test, |
270 | cmd_handler.work); | 286 | cmd_handler.work); |
271 | struct pci_epf *epf = epf_test->epf; | 287 | struct pci_epf *epf = epf_test->epf; |
288 | struct device *dev = &epf->dev; | ||
272 | struct pci_epc *epc = epf->epc; | 289 | struct pci_epc *epc = epf->epc; |
273 | enum pci_barno test_reg_bar = epf_test->test_reg_bar; | 290 | enum pci_barno test_reg_bar = epf_test->test_reg_bar; |
274 | struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar]; | 291 | struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar]; |
@@ -280,7 +297,10 @@ static void pci_epf_test_cmd_handler(struct work_struct *work) | |||
280 | reg->command = 0; | 297 | reg->command = 0; |
281 | reg->status = 0; | 298 | reg->status = 0; |
282 | 299 | ||
283 | irq = (command & MSI_NUMBER_MASK) >> MSI_NUMBER_SHIFT; | 300 | if (reg->irq_type > IRQ_TYPE_MSIX) { |
301 | dev_err(dev, "Failed to detect IRQ type\n"); | ||
302 | goto reset_handler; | ||
303 | } | ||
284 | 304 | ||
285 | if (command & COMMAND_RAISE_LEGACY_IRQ) { | 305 | if (command & COMMAND_RAISE_LEGACY_IRQ) { |
286 | reg->status = STATUS_IRQ_RAISED; | 306 | reg->status = STATUS_IRQ_RAISED; |
@@ -294,7 +314,8 @@ static void pci_epf_test_cmd_handler(struct work_struct *work) | |||
294 | reg->status |= STATUS_WRITE_FAIL; | 314 | reg->status |= STATUS_WRITE_FAIL; |
295 | else | 315 | else |
296 | reg->status |= STATUS_WRITE_SUCCESS; | 316 | reg->status |= STATUS_WRITE_SUCCESS; |
297 | pci_epf_test_raise_irq(epf_test, irq); | 317 | pci_epf_test_raise_irq(epf_test, reg->irq_type, |
318 | reg->irq_number); | ||
298 | goto reset_handler; | 319 | goto reset_handler; |
299 | } | 320 | } |
300 | 321 | ||
@@ -304,7 +325,8 @@ static void pci_epf_test_cmd_handler(struct work_struct *work) | |||
304 | reg->status |= STATUS_READ_SUCCESS; | 325 | reg->status |= STATUS_READ_SUCCESS; |
305 | else | 326 | else |
306 | reg->status |= STATUS_READ_FAIL; | 327 | reg->status |= STATUS_READ_FAIL; |
307 | pci_epf_test_raise_irq(epf_test, irq); | 328 | pci_epf_test_raise_irq(epf_test, reg->irq_type, |
329 | reg->irq_number); | ||
308 | goto reset_handler; | 330 | goto reset_handler; |
309 | } | 331 | } |
310 | 332 | ||
@@ -314,16 +336,28 @@ static void pci_epf_test_cmd_handler(struct work_struct *work) | |||
314 | reg->status |= STATUS_COPY_SUCCESS; | 336 | reg->status |= STATUS_COPY_SUCCESS; |
315 | else | 337 | else |
316 | reg->status |= STATUS_COPY_FAIL; | 338 | reg->status |= STATUS_COPY_FAIL; |
317 | pci_epf_test_raise_irq(epf_test, irq); | 339 | pci_epf_test_raise_irq(epf_test, reg->irq_type, |
340 | reg->irq_number); | ||
318 | goto reset_handler; | 341 | goto reset_handler; |
319 | } | 342 | } |
320 | 343 | ||
321 | if (command & COMMAND_RAISE_MSI_IRQ) { | 344 | if (command & COMMAND_RAISE_MSI_IRQ) { |
322 | msi_count = pci_epc_get_msi(epc, epf->func_no); | 345 | count = pci_epc_get_msi(epc, epf->func_no); |
323 | if (irq > msi_count || msi_count <= 0) | 346 | if (reg->irq_number > count || count <= 0) |
324 | goto reset_handler; | 347 | goto reset_handler; |
325 | reg->status = STATUS_IRQ_RAISED; | 348 | reg->status = STATUS_IRQ_RAISED; |
326 | pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_MSI, irq); | 349 | pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_MSI, |
350 | reg->irq_number); | ||
351 | goto reset_handler; | ||
352 | } | ||
353 | |||
354 | if (command & COMMAND_RAISE_MSIX_IRQ) { | ||
355 | count = pci_epc_get_msix(epc, epf->func_no); | ||
356 | if (reg->irq_number > count || count <= 0) | ||
357 | goto reset_handler; | ||
358 | reg->status = STATUS_IRQ_RAISED; | ||
359 | pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_MSIX, | ||
360 | reg->irq_number); | ||
327 | goto reset_handler; | 361 | goto reset_handler; |
328 | } | 362 | } |
329 | 363 | ||
@@ -440,6 +474,8 @@ static int pci_epf_test_bind(struct pci_epf *epf) | |||
440 | else | 474 | else |
441 | epf_test->linkup_notifier = true; | 475 | epf_test->linkup_notifier = true; |
442 | 476 | ||
477 | epf_test->msix_available = epc->features & EPC_FEATURE_MSIX_AVAILABLE; | ||
478 | |||
443 | epf_test->test_reg_bar = EPC_FEATURE_GET_BAR(epc->features); | 479 | epf_test->test_reg_bar = EPC_FEATURE_GET_BAR(epc->features); |
444 | 480 | ||
445 | ret = pci_epc_write_header(epc, epf->func_no, header); | 481 | ret = pci_epc_write_header(epc, epf->func_no, header); |
@@ -457,8 +493,18 @@ static int pci_epf_test_bind(struct pci_epf *epf) | |||
457 | return ret; | 493 | return ret; |
458 | 494 | ||
459 | ret = pci_epc_set_msi(epc, epf->func_no, epf->msi_interrupts); | 495 | ret = pci_epc_set_msi(epc, epf->func_no, epf->msi_interrupts); |
460 | if (ret) | 496 | if (ret) { |
497 | dev_err(dev, "MSI configuration failed\n"); | ||
461 | return ret; | 498 | return ret; |
499 | } | ||
500 | |||
501 | if (epf_test->msix_available) { | ||
502 | ret = pci_epc_set_msix(epc, epf->func_no, epf->msix_interrupts); | ||
503 | if (ret) { | ||
504 | dev_err(dev, "MSI-X configuration failed\n"); | ||
505 | return ret; | ||
506 | } | ||
507 | } | ||
462 | 508 | ||
463 | if (!epf_test->linkup_notifier) | 509 | if (!epf_test->linkup_notifier) |
464 | queue_work(kpcitest_workqueue, &epf_test->cmd_handler.work); | 510 | queue_work(kpcitest_workqueue, &epf_test->cmd_handler.work); |
diff --git a/drivers/pci/endpoint/pci-ep-cfs.c b/drivers/pci/endpoint/pci-ep-cfs.c index 018ea3433cb5..d1288a0bd530 100644 --- a/drivers/pci/endpoint/pci-ep-cfs.c +++ b/drivers/pci/endpoint/pci-ep-cfs.c | |||
@@ -286,6 +286,28 @@ static ssize_t pci_epf_msi_interrupts_show(struct config_item *item, | |||
286 | to_pci_epf_group(item)->epf->msi_interrupts); | 286 | to_pci_epf_group(item)->epf->msi_interrupts); |
287 | } | 287 | } |
288 | 288 | ||
289 | static ssize_t pci_epf_msix_interrupts_store(struct config_item *item, | ||
290 | const char *page, size_t len) | ||
291 | { | ||
292 | u16 val; | ||
293 | int ret; | ||
294 | |||
295 | ret = kstrtou16(page, 0, &val); | ||
296 | if (ret) | ||
297 | return ret; | ||
298 | |||
299 | to_pci_epf_group(item)->epf->msix_interrupts = val; | ||
300 | |||
301 | return len; | ||
302 | } | ||
303 | |||
304 | static ssize_t pci_epf_msix_interrupts_show(struct config_item *item, | ||
305 | char *page) | ||
306 | { | ||
307 | return sprintf(page, "%d\n", | ||
308 | to_pci_epf_group(item)->epf->msix_interrupts); | ||
309 | } | ||
310 | |||
289 | PCI_EPF_HEADER_R(vendorid) | 311 | PCI_EPF_HEADER_R(vendorid) |
290 | PCI_EPF_HEADER_W_u16(vendorid) | 312 | PCI_EPF_HEADER_W_u16(vendorid) |
291 | 313 | ||
@@ -327,6 +349,7 @@ CONFIGFS_ATTR(pci_epf_, subsys_vendor_id); | |||
327 | CONFIGFS_ATTR(pci_epf_, subsys_id); | 349 | CONFIGFS_ATTR(pci_epf_, subsys_id); |
328 | CONFIGFS_ATTR(pci_epf_, interrupt_pin); | 350 | CONFIGFS_ATTR(pci_epf_, interrupt_pin); |
329 | CONFIGFS_ATTR(pci_epf_, msi_interrupts); | 351 | CONFIGFS_ATTR(pci_epf_, msi_interrupts); |
352 | CONFIGFS_ATTR(pci_epf_, msix_interrupts); | ||
330 | 353 | ||
331 | static struct configfs_attribute *pci_epf_attrs[] = { | 354 | static struct configfs_attribute *pci_epf_attrs[] = { |
332 | &pci_epf_attr_vendorid, | 355 | &pci_epf_attr_vendorid, |
@@ -340,6 +363,7 @@ static struct configfs_attribute *pci_epf_attrs[] = { | |||
340 | &pci_epf_attr_subsys_id, | 363 | &pci_epf_attr_subsys_id, |
341 | &pci_epf_attr_interrupt_pin, | 364 | &pci_epf_attr_interrupt_pin, |
342 | &pci_epf_attr_msi_interrupts, | 365 | &pci_epf_attr_msi_interrupts, |
366 | &pci_epf_attr_msix_interrupts, | ||
343 | NULL, | 367 | NULL, |
344 | }; | 368 | }; |
345 | 369 | ||
diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c index b0ee42739c3c..094dcc3203b8 100644 --- a/drivers/pci/endpoint/pci-epc-core.c +++ b/drivers/pci/endpoint/pci-epc-core.c | |||
@@ -131,13 +131,13 @@ EXPORT_SYMBOL_GPL(pci_epc_start); | |||
131 | * pci_epc_raise_irq() - interrupt the host system | 131 | * pci_epc_raise_irq() - interrupt the host system |
132 | * @epc: the EPC device which has to interrupt the host | 132 | * @epc: the EPC device which has to interrupt the host |
133 | * @func_no: the endpoint function number in the EPC device | 133 | * @func_no: the endpoint function number in the EPC device |
134 | * @type: specify the type of interrupt; legacy or MSI | 134 | * @type: specify the type of interrupt; legacy, MSI or MSI-X |
135 | * @interrupt_num: the MSI interrupt number | 135 | * @interrupt_num: the MSI or MSI-X interrupt number |
136 | * | 136 | * |
137 | * Invoke to raise an MSI or legacy interrupt | 137 | * Invoke to raise an legacy, MSI or MSI-X interrupt |
138 | */ | 138 | */ |
139 | int pci_epc_raise_irq(struct pci_epc *epc, u8 func_no, | 139 | int pci_epc_raise_irq(struct pci_epc *epc, u8 func_no, |
140 | enum pci_epc_irq_type type, u8 interrupt_num) | 140 | enum pci_epc_irq_type type, u16 interrupt_num) |
141 | { | 141 | { |
142 | int ret; | 142 | int ret; |
143 | unsigned long flags; | 143 | unsigned long flags; |
@@ -201,7 +201,8 @@ int pci_epc_set_msi(struct pci_epc *epc, u8 func_no, u8 interrupts) | |||
201 | u8 encode_int; | 201 | u8 encode_int; |
202 | unsigned long flags; | 202 | unsigned long flags; |
203 | 203 | ||
204 | if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) | 204 | if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions || |
205 | interrupts > 32) | ||
205 | return -EINVAL; | 206 | return -EINVAL; |
206 | 207 | ||
207 | if (!epc->ops->set_msi) | 208 | if (!epc->ops->set_msi) |
@@ -218,6 +219,63 @@ int pci_epc_set_msi(struct pci_epc *epc, u8 func_no, u8 interrupts) | |||
218 | EXPORT_SYMBOL_GPL(pci_epc_set_msi); | 219 | EXPORT_SYMBOL_GPL(pci_epc_set_msi); |
219 | 220 | ||
220 | /** | 221 | /** |
222 | * pci_epc_get_msix() - get the number of MSI-X interrupt numbers allocated | ||
223 | * @epc: the EPC device to which MSI-X interrupts was requested | ||
224 | * @func_no: the endpoint function number in the EPC device | ||
225 | * | ||
226 | * Invoke to get the number of MSI-X interrupts allocated by the RC | ||
227 | */ | ||
228 | int pci_epc_get_msix(struct pci_epc *epc, u8 func_no) | ||
229 | { | ||
230 | int interrupt; | ||
231 | unsigned long flags; | ||
232 | |||
233 | if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) | ||
234 | return 0; | ||
235 | |||
236 | if (!epc->ops->get_msix) | ||
237 | return 0; | ||
238 | |||
239 | spin_lock_irqsave(&epc->lock, flags); | ||
240 | interrupt = epc->ops->get_msix(epc, func_no); | ||
241 | spin_unlock_irqrestore(&epc->lock, flags); | ||
242 | |||
243 | if (interrupt < 0) | ||
244 | return 0; | ||
245 | |||
246 | return interrupt + 1; | ||
247 | } | ||
248 | EXPORT_SYMBOL_GPL(pci_epc_get_msix); | ||
249 | |||
250 | /** | ||
251 | * pci_epc_set_msix() - set the number of MSI-X interrupt numbers required | ||
252 | * @epc: the EPC device on which MSI-X has to be configured | ||
253 | * @func_no: the endpoint function number in the EPC device | ||
254 | * @interrupts: number of MSI-X interrupts required by the EPF | ||
255 | * | ||
256 | * Invoke to set the required number of MSI-X interrupts. | ||
257 | */ | ||
258 | int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts) | ||
259 | { | ||
260 | int ret; | ||
261 | unsigned long flags; | ||
262 | |||
263 | if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions || | ||
264 | interrupts < 1 || interrupts > 2048) | ||
265 | return -EINVAL; | ||
266 | |||
267 | if (!epc->ops->set_msix) | ||
268 | return 0; | ||
269 | |||
270 | spin_lock_irqsave(&epc->lock, flags); | ||
271 | ret = epc->ops->set_msix(epc, func_no, interrupts - 1); | ||
272 | spin_unlock_irqrestore(&epc->lock, flags); | ||
273 | |||
274 | return ret; | ||
275 | } | ||
276 | EXPORT_SYMBOL_GPL(pci_epc_set_msix); | ||
277 | |||
278 | /** | ||
221 | * pci_epc_unmap_addr() - unmap CPU address from PCI address | 279 | * pci_epc_unmap_addr() - unmap CPU address from PCI address |
222 | * @epc: the EPC device on which address is allocated | 280 | * @epc: the EPC device on which address is allocated |
223 | * @func_no: the endpoint function number in the EPC device | 281 | * @func_no: the endpoint function number in the EPC device |
diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h index 243eaa5a66ff..37dab8116901 100644 --- a/include/linux/pci-epc.h +++ b/include/linux/pci-epc.h | |||
@@ -17,6 +17,7 @@ enum pci_epc_irq_type { | |||
17 | PCI_EPC_IRQ_UNKNOWN, | 17 | PCI_EPC_IRQ_UNKNOWN, |
18 | PCI_EPC_IRQ_LEGACY, | 18 | PCI_EPC_IRQ_LEGACY, |
19 | PCI_EPC_IRQ_MSI, | 19 | PCI_EPC_IRQ_MSI, |
20 | PCI_EPC_IRQ_MSIX, | ||
20 | }; | 21 | }; |
21 | 22 | ||
22 | /** | 23 | /** |
@@ -30,7 +31,11 @@ enum pci_epc_irq_type { | |||
30 | * capability register | 31 | * capability register |
31 | * @get_msi: ops to get the number of MSI interrupts allocated by the RC from | 32 | * @get_msi: ops to get the number of MSI interrupts allocated by the RC from |
32 | * the MSI capability register | 33 | * the MSI capability register |
33 | * @raise_irq: ops to raise a legacy or MSI interrupt | 34 | * @set_msix: ops to set the requested number of MSI-X interrupts in the |
35 | * MSI-X capability register | ||
36 | * @get_msix: ops to get the number of MSI-X interrupts allocated by the RC | ||
37 | * from the MSI-X capability register | ||
38 | * @raise_irq: ops to raise a legacy, MSI or MSI-X interrupt | ||
34 | * @start: ops to start the PCI link | 39 | * @start: ops to start the PCI link |
35 | * @stop: ops to stop the PCI link | 40 | * @stop: ops to stop the PCI link |
36 | * @owner: the module owner containing the ops | 41 | * @owner: the module owner containing the ops |
@@ -48,8 +53,10 @@ struct pci_epc_ops { | |||
48 | phys_addr_t addr); | 53 | phys_addr_t addr); |
49 | int (*set_msi)(struct pci_epc *epc, u8 func_no, u8 interrupts); | 54 | int (*set_msi)(struct pci_epc *epc, u8 func_no, u8 interrupts); |
50 | int (*get_msi)(struct pci_epc *epc, u8 func_no); | 55 | int (*get_msi)(struct pci_epc *epc, u8 func_no); |
56 | int (*set_msix)(struct pci_epc *epc, u8 func_no, u16 interrupts); | ||
57 | int (*get_msix)(struct pci_epc *epc, u8 func_no); | ||
51 | int (*raise_irq)(struct pci_epc *epc, u8 func_no, | 58 | int (*raise_irq)(struct pci_epc *epc, u8 func_no, |
52 | enum pci_epc_irq_type type, u8 interrupt_num); | 59 | enum pci_epc_irq_type type, u16 interrupt_num); |
53 | int (*start)(struct pci_epc *epc); | 60 | int (*start)(struct pci_epc *epc); |
54 | void (*stop)(struct pci_epc *epc); | 61 | void (*stop)(struct pci_epc *epc); |
55 | struct module *owner; | 62 | struct module *owner; |
@@ -95,6 +102,7 @@ struct pci_epc { | |||
95 | 102 | ||
96 | #define EPC_FEATURE_NO_LINKUP_NOTIFIER BIT(0) | 103 | #define EPC_FEATURE_NO_LINKUP_NOTIFIER BIT(0) |
97 | #define EPC_FEATURE_BAR_MASK (BIT(1) | BIT(2) | BIT(3)) | 104 | #define EPC_FEATURE_BAR_MASK (BIT(1) | BIT(2) | BIT(3)) |
105 | #define EPC_FEATURE_MSIX_AVAILABLE BIT(4) | ||
98 | #define EPC_FEATURE_SET_BAR(features, bar) \ | 106 | #define EPC_FEATURE_SET_BAR(features, bar) \ |
99 | (features |= (EPC_FEATURE_BAR_MASK & (bar << 1))) | 107 | (features |= (EPC_FEATURE_BAR_MASK & (bar << 1))) |
100 | #define EPC_FEATURE_GET_BAR(features) \ | 108 | #define EPC_FEATURE_GET_BAR(features) \ |
@@ -144,8 +152,10 @@ void pci_epc_unmap_addr(struct pci_epc *epc, u8 func_no, | |||
144 | phys_addr_t phys_addr); | 152 | phys_addr_t phys_addr); |
145 | int pci_epc_set_msi(struct pci_epc *epc, u8 func_no, u8 interrupts); | 153 | int pci_epc_set_msi(struct pci_epc *epc, u8 func_no, u8 interrupts); |
146 | int pci_epc_get_msi(struct pci_epc *epc, u8 func_no); | 154 | int pci_epc_get_msi(struct pci_epc *epc, u8 func_no); |
155 | int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts); | ||
156 | int pci_epc_get_msix(struct pci_epc *epc, u8 func_no); | ||
147 | int pci_epc_raise_irq(struct pci_epc *epc, u8 func_no, | 157 | int pci_epc_raise_irq(struct pci_epc *epc, u8 func_no, |
148 | enum pci_epc_irq_type type, u8 interrupt_num); | 158 | enum pci_epc_irq_type type, u16 interrupt_num); |
149 | int pci_epc_start(struct pci_epc *epc); | 159 | int pci_epc_start(struct pci_epc *epc); |
150 | void pci_epc_stop(struct pci_epc *epc); | 160 | void pci_epc_stop(struct pci_epc *epc); |
151 | struct pci_epc *pci_epc_get(const char *epc_name); | 161 | struct pci_epc *pci_epc_get(const char *epc_name); |
diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h index 4e7764935fa8..ec02f58758c8 100644 --- a/include/linux/pci-epf.h +++ b/include/linux/pci-epf.h | |||
@@ -119,6 +119,7 @@ struct pci_epf { | |||
119 | struct pci_epf_header *header; | 119 | struct pci_epf_header *header; |
120 | struct pci_epf_bar bar[6]; | 120 | struct pci_epf_bar bar[6]; |
121 | u8 msi_interrupts; | 121 | u8 msi_interrupts; |
122 | u16 msix_interrupts; | ||
122 | u8 func_no; | 123 | u8 func_no; |
123 | 124 | ||
124 | struct pci_epc *epc; | 125 | struct pci_epc *epc; |
diff --git a/include/uapi/linux/pcitest.h b/include/uapi/linux/pcitest.h index 953cf036cb26..cbf422e56696 100644 --- a/include/uapi/linux/pcitest.h +++ b/include/uapi/linux/pcitest.h | |||
@@ -16,5 +16,8 @@ | |||
16 | #define PCITEST_WRITE _IOW('P', 0x4, unsigned long) | 16 | #define PCITEST_WRITE _IOW('P', 0x4, unsigned long) |
17 | #define PCITEST_READ _IOW('P', 0x5, unsigned long) | 17 | #define PCITEST_READ _IOW('P', 0x5, unsigned long) |
18 | #define PCITEST_COPY _IOW('P', 0x6, unsigned long) | 18 | #define PCITEST_COPY _IOW('P', 0x6, unsigned long) |
19 | #define PCITEST_MSIX _IOW('P', 0x7, int) | ||
20 | #define PCITEST_SET_IRQTYPE _IOW('P', 0x8, int) | ||
21 | #define PCITEST_GET_IRQTYPE _IO('P', 0x9) | ||
19 | 22 | ||
20 | #endif /* __UAPI_LINUX_PCITEST_H */ | 23 | #endif /* __UAPI_LINUX_PCITEST_H */ |
diff --git a/tools/pci/pcitest.c b/tools/pci/pcitest.c index 9074b477bff0..af146bb03b4d 100644 --- a/tools/pci/pcitest.c +++ b/tools/pci/pcitest.c | |||
@@ -31,12 +31,17 @@ | |||
31 | #define BILLION 1E9 | 31 | #define BILLION 1E9 |
32 | 32 | ||
33 | static char *result[] = { "NOT OKAY", "OKAY" }; | 33 | static char *result[] = { "NOT OKAY", "OKAY" }; |
34 | static char *irq[] = { "LEGACY", "MSI", "MSI-X" }; | ||
34 | 35 | ||
35 | struct pci_test { | 36 | struct pci_test { |
36 | char *device; | 37 | char *device; |
37 | char barnum; | 38 | char barnum; |
38 | bool legacyirq; | 39 | bool legacyirq; |
39 | unsigned int msinum; | 40 | unsigned int msinum; |
41 | unsigned int msixnum; | ||
42 | int irqtype; | ||
43 | bool set_irqtype; | ||
44 | bool get_irqtype; | ||
40 | bool read; | 45 | bool read; |
41 | bool write; | 46 | bool write; |
42 | bool copy; | 47 | bool copy; |
@@ -65,6 +70,24 @@ static int run_test(struct pci_test *test) | |||
65 | fprintf(stdout, "%s\n", result[ret]); | 70 | fprintf(stdout, "%s\n", result[ret]); |
66 | } | 71 | } |
67 | 72 | ||
73 | if (test->set_irqtype) { | ||
74 | ret = ioctl(fd, PCITEST_SET_IRQTYPE, test->irqtype); | ||
75 | fprintf(stdout, "SET IRQ TYPE TO %s:\t\t", irq[test->irqtype]); | ||
76 | if (ret < 0) | ||
77 | fprintf(stdout, "FAILED\n"); | ||
78 | else | ||
79 | fprintf(stdout, "%s\n", result[ret]); | ||
80 | } | ||
81 | |||
82 | if (test->get_irqtype) { | ||
83 | ret = ioctl(fd, PCITEST_GET_IRQTYPE); | ||
84 | fprintf(stdout, "GET IRQ TYPE:\t\t"); | ||
85 | if (ret < 0) | ||
86 | fprintf(stdout, "FAILED\n"); | ||
87 | else | ||
88 | fprintf(stdout, "%s\n", irq[ret]); | ||
89 | } | ||
90 | |||
68 | if (test->legacyirq) { | 91 | if (test->legacyirq) { |
69 | ret = ioctl(fd, PCITEST_LEGACY_IRQ, 0); | 92 | ret = ioctl(fd, PCITEST_LEGACY_IRQ, 0); |
70 | fprintf(stdout, "LEGACY IRQ:\t"); | 93 | fprintf(stdout, "LEGACY IRQ:\t"); |
@@ -83,6 +106,15 @@ static int run_test(struct pci_test *test) | |||
83 | fprintf(stdout, "%s\n", result[ret]); | 106 | fprintf(stdout, "%s\n", result[ret]); |
84 | } | 107 | } |
85 | 108 | ||
109 | if (test->msixnum > 0 && test->msixnum <= 2048) { | ||
110 | ret = ioctl(fd, PCITEST_MSIX, test->msixnum); | ||
111 | fprintf(stdout, "MSI-X%d:\t\t", test->msixnum); | ||
112 | if (ret < 0) | ||
113 | fprintf(stdout, "TEST FAILED\n"); | ||
114 | else | ||
115 | fprintf(stdout, "%s\n", result[ret]); | ||
116 | } | ||
117 | |||
86 | if (test->write) { | 118 | if (test->write) { |
87 | ret = ioctl(fd, PCITEST_WRITE, test->size); | 119 | ret = ioctl(fd, PCITEST_WRITE, test->size); |
88 | fprintf(stdout, "WRITE (%7ld bytes):\t\t", test->size); | 120 | fprintf(stdout, "WRITE (%7ld bytes):\t\t", test->size); |
@@ -133,7 +165,7 @@ int main(int argc, char **argv) | |||
133 | /* set default endpoint device */ | 165 | /* set default endpoint device */ |
134 | test->device = "/dev/pci-endpoint-test.0"; | 166 | test->device = "/dev/pci-endpoint-test.0"; |
135 | 167 | ||
136 | while ((c = getopt(argc, argv, "D:b:m:lrwcs:")) != EOF) | 168 | while ((c = getopt(argc, argv, "D:b:m:x:i:Ilrwcs:")) != EOF) |
137 | switch (c) { | 169 | switch (c) { |
138 | case 'D': | 170 | case 'D': |
139 | test->device = optarg; | 171 | test->device = optarg; |
@@ -151,6 +183,20 @@ int main(int argc, char **argv) | |||
151 | if (test->msinum < 1 || test->msinum > 32) | 183 | if (test->msinum < 1 || test->msinum > 32) |
152 | goto usage; | 184 | goto usage; |
153 | continue; | 185 | continue; |
186 | case 'x': | ||
187 | test->msixnum = atoi(optarg); | ||
188 | if (test->msixnum < 1 || test->msixnum > 2048) | ||
189 | goto usage; | ||
190 | continue; | ||
191 | case 'i': | ||
192 | test->irqtype = atoi(optarg); | ||
193 | if (test->irqtype < 0 || test->irqtype > 2) | ||
194 | goto usage; | ||
195 | test->set_irqtype = true; | ||
196 | continue; | ||
197 | case 'I': | ||
198 | test->get_irqtype = true; | ||
199 | continue; | ||
154 | case 'r': | 200 | case 'r': |
155 | test->read = true; | 201 | test->read = true; |
156 | continue; | 202 | continue; |
@@ -173,6 +219,9 @@ usage: | |||
173 | "\t-D <dev> PCI endpoint test device {default: /dev/pci-endpoint-test.0}\n" | 219 | "\t-D <dev> PCI endpoint test device {default: /dev/pci-endpoint-test.0}\n" |
174 | "\t-b <bar num> BAR test (bar number between 0..5)\n" | 220 | "\t-b <bar num> BAR test (bar number between 0..5)\n" |
175 | "\t-m <msi num> MSI test (msi number between 1..32)\n" | 221 | "\t-m <msi num> MSI test (msi number between 1..32)\n" |
222 | "\t-x <msix num> \tMSI-X test (msix number between 1..2048)\n" | ||
223 | "\t-i <irq type> \tSet IRQ type (0 - Legacy, 1 - MSI, 2 - MSI-X)\n" | ||
224 | "\t-I Get current IRQ type configured\n" | ||
176 | "\t-l Legacy IRQ test\n" | 225 | "\t-l Legacy IRQ test\n" |
177 | "\t-r Read buffer test\n" | 226 | "\t-r Read buffer test\n" |
178 | "\t-w Write buffer test\n" | 227 | "\t-w Write buffer test\n" |
diff --git a/tools/pci/pcitest.sh b/tools/pci/pcitest.sh index 77e8c85ef744..75ed48ff2990 100644 --- a/tools/pci/pcitest.sh +++ b/tools/pci/pcitest.sh | |||
@@ -16,7 +16,10 @@ echo | |||
16 | echo "Interrupt tests" | 16 | echo "Interrupt tests" |
17 | echo | 17 | echo |
18 | 18 | ||
19 | pcitest -i 0 | ||
19 | pcitest -l | 20 | pcitest -l |
21 | |||
22 | pcitest -i 1 | ||
20 | msi=1 | 23 | msi=1 |
21 | 24 | ||
22 | while [ $msi -lt 33 ] | 25 | while [ $msi -lt 33 ] |
@@ -26,9 +29,21 @@ do | |||
26 | done | 29 | done |
27 | echo | 30 | echo |
28 | 31 | ||
32 | pcitest -i 2 | ||
33 | msix=1 | ||
34 | |||
35 | while [ $msix -lt 2049 ] | ||
36 | do | ||
37 | pcitest -x $msix | ||
38 | msix=`expr $msix + 1` | ||
39 | done | ||
40 | echo | ||
41 | |||
29 | echo "Read Tests" | 42 | echo "Read Tests" |
30 | echo | 43 | echo |
31 | 44 | ||
45 | pcitest -i 1 | ||
46 | |||
32 | pcitest -r -s 1 | 47 | pcitest -r -s 1 |
33 | pcitest -r -s 1024 | 48 | pcitest -r -s 1024 |
34 | pcitest -r -s 1025 | 49 | pcitest -r -s 1025 |