Skip to content

Commit c2e00e3

Browse files
gustavoSNPSLorenzo Pieralisi
authored andcommitted
pci-epf-test/pci_endpoint_test: Add MSI-X support
Add MSI-X support and update driver documentation accordingly. Signed-off-by: Gustavo Pimentel <[email protected]> Signed-off-by: Lorenzo Pieralisi <[email protected]> Acked-by: Kishon Vijay Abraham I <[email protected]>
1 parent 9133e39 commit c2e00e3

File tree

10 files changed

+79
-16
lines changed

10 files changed

+79
-16
lines changed

Documentation/PCI/endpoint/pci-endpoint.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ by the PCI controller driver.
4444
* clear_bar: ops to reset the BAR
4545
* alloc_addr_space: ops to allocate in PCI controller address space
4646
* 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
4848
* start: ops to start the PCI link
4949
* stop: ops to stop the PCI link
5050

@@ -96,7 +96,7 @@ by the PCI endpoint function driver.
9696
*) pci_epc_raise_irq()
9797

9898
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.
100100

101101
*) pci_epc_mem_alloc_addr()
102102

Documentation/PCI/endpoint/pci-test-function.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ that the endpoint device must perform.
3636
Bitfield Description:
3737
Bit 0 : raise legacy IRQ
3838
Bit 1 : raise MSI IRQ
39-
Bit 2 : raise MSI-X IRQ (reserved for future implementation)
39+
Bit 2 : raise MSI-X IRQ
4040
Bit 3 : read command (read data from RC buffer)
4141
Bit 4 : write command (write data to RC buffer)
4242
Bit 5 : copy command (copy data from one RC buffer to another
@@ -75,6 +75,7 @@ for the READ/WRITE/COPY and raise IRQ (Legacy/MSI) commands.
7575
Possible types:
7676
- Legacy : 0
7777
- MSI : 1
78+
- MSI-X : 2
7879

7980
*) PCI_ENDPOINT_TEST_IRQ_NUMBER
8081

@@ -83,3 +84,4 @@ This register contains the triggered ID interrupt.
8384
Admissible values:
8485
- Legacy : 0
8586
- MSI : [1 .. 32]
87+
- MSI-X : [1 .. 2048]

Documentation/PCI/endpoint/pci-test-howto.txt

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@ The PCI endpoint framework populates the directory with the following
4545
configurable fields.
4646

4747
# ls functions/pci_epf_test/func1
48-
baseclass_code interrupt_pin revid subsys_vendor_id
49-
cache_line_size msi_interrupts subclass_code vendorid
50-
deviceid progif_code subsys_id
48+
baseclass_code interrupt_pin progif_code subsys_id
49+
cache_line_size msi_interrupts revid subsys_vendorid
50+
deviceid msix_interrupts subclass_code vendorid
5151

5252
The PCI endpoint function driver populates these entries with default values
5353
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.
6767
# echo 0x104c > functions/pci_epf_test/func1/vendorid
6868
# echo 0xb500 > functions/pci_epf_test/func1/deviceid
6969
# echo 16 > functions/pci_epf_test/func1/msi_interrupts
70+
# echo 8 > functions/pci_epf_test/func1/msix_interrupts
7071

7172
1.5 Binding pci-epf-test Device to EP Controller
7273

@@ -153,6 +154,21 @@ following commands.
153154
MSI30: NOT OKAY
154155
MSI31: NOT OKAY
155156
MSI32: NOT OKAY
157+
MSIX1: OKAY
158+
MSIX2: OKAY
159+
MSIX3: OKAY
160+
MSIX4: OKAY
161+
MSIX5: OKAY
162+
MSIX6: OKAY
163+
MSIX7: OKAY
164+
MSIX8: OKAY
165+
MSIX9: NOT OKAY
166+
MSIX10: NOT OKAY
167+
MSIX11: NOT OKAY
168+
MSIX12: NOT OKAY
169+
MSIX13: NOT OKAY
170+
[...]
171+
MSIX2048: NOT OKAY
156172

157173
Read Tests
158174

Documentation/ioctl/ioctl-number.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ Code Seq#(hex) Include File Comments
166166
'P' all linux/soundcard.h conflict!
167167
'P' 60-6F sound/sscape_ioctl.h conflict!
168168
'P' 00-0F drivers/usb/class/usblp.c conflict!
169+
'P' 01-07 drivers/misc/pci_endpoint_test.c conflict!
169170
'Q' all linux/soundcard.h
170171
'R' 00-1F linux/random.h conflict!
171172
'R' 01 linux/rfkill.h conflict!

Documentation/misc-devices/pci-endpoint-test.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ The PCI driver for the test device performs the following tests
1010
*) verifying addresses programmed in BAR
1111
*) raise legacy IRQ
1212
*) raise MSI IRQ
13+
*) raise MSI-X IRQ
1314
*) read data
1415
*) write data
1516
*) copy data
@@ -25,6 +26,8 @@ ioctl
2526
PCITEST_LEGACY_IRQ: Tests legacy IRQ
2627
PCITEST_MSI: Tests message signalled interrupts. The MSI number
2728
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.
2831
PCITEST_WRITE: Perform write tests. The size of the buffer should be passed
2932
as argument.
3033
PCITEST_READ: Perform read tests. The size of the buffer should be passed

drivers/misc/pci_endpoint_test.c

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,14 @@
3939

4040
#define IRQ_TYPE_LEGACY 0
4141
#define IRQ_TYPE_MSI 1
42+
#define IRQ_TYPE_MSIX 2
4243

4344
#define PCI_ENDPOINT_TEST_MAGIC 0x0
4445

4546
#define PCI_ENDPOINT_TEST_COMMAND 0x4
4647
#define COMMAND_RAISE_LEGACY_IRQ BIT(0)
4748
#define COMMAND_RAISE_MSI_IRQ BIT(1)
48-
/* BIT(2) is reserved for raising MSI-X IRQ command */
49+
#define COMMAND_RAISE_MSIX_IRQ BIT(2)
4950
#define COMMAND_READ BIT(3)
5051
#define COMMAND_WRITE BIT(4)
5152
#define COMMAND_COPY BIT(5)
@@ -84,7 +85,7 @@ MODULE_PARM_DESC(no_msi, "Disable MSI interrupt in pci_endpoint_test");
8485

8586
static int irq_type = IRQ_TYPE_MSI;
8687
module_param(irq_type, int, 0444);
87-
MODULE_PARM_DESC(irq_type, "IRQ mode selection in pci_endpoint_test (0 - Legacy, 1 - MSI)");
88+
MODULE_PARM_DESC(irq_type, "IRQ mode selection in pci_endpoint_test (0 - Legacy, 1 - MSI, 2 - MSI-X)");
8889

8990
enum pci_barno {
9091
BAR_0,
@@ -202,16 +203,18 @@ static bool pci_endpoint_test_legacy_irq(struct pci_endpoint_test *test)
202203
}
203204

204205
static bool pci_endpoint_test_msi_irq(struct pci_endpoint_test *test,
205-
u8 msi_num)
206+
u16 msi_num, bool msix)
206207
{
207208
u32 val;
208209
struct pci_dev *pdev = test->pdev;
209210

210211
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE,
211-
IRQ_TYPE_MSI);
212+
msix == false ? IRQ_TYPE_MSI :
213+
IRQ_TYPE_MSIX);
212214
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, msi_num);
213215
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
214-
COMMAND_RAISE_MSI_IRQ);
216+
msix == false ? COMMAND_RAISE_MSI_IRQ :
217+
COMMAND_RAISE_MSIX_IRQ);
215218
val = wait_for_completion_timeout(&test->irq_raised,
216219
msecs_to_jiffies(1000));
217220
if (!val)
@@ -456,7 +459,8 @@ static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
456459
ret = pci_endpoint_test_legacy_irq(test);
457460
break;
458461
case PCITEST_MSI:
459-
ret = pci_endpoint_test_msi_irq(test, arg);
462+
case PCITEST_MSIX:
463+
ret = pci_endpoint_test_msi_irq(test, arg, cmd == PCITEST_MSIX);
460464
break;
461465
case PCITEST_WRITE:
462466
ret = pci_endpoint_test_write(test, arg);
@@ -542,6 +546,12 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
542546
dev_err(dev, "Failed to get MSI interrupts\n");
543547
test->num_irqs = irq;
544548
break;
549+
case IRQ_TYPE_MSIX:
550+
irq = pci_alloc_irq_vectors(pdev, 1, 2048, PCI_IRQ_MSIX);
551+
if (irq < 0)
552+
dev_err(dev, "Failed to get MSI-X interrupts\n");
553+
test->num_irqs = irq;
554+
break;
545555
default:
546556
dev_err(dev, "Invalid IRQ type selected\n");
547557
}
@@ -558,8 +568,9 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
558568
pci_endpoint_test_irqhandler,
559569
IRQF_SHARED, DRV_MODULE_NAME, test);
560570
if (err)
561-
dev_err(dev, "failed to request IRQ %d for MSI %d\n",
562-
pci_irq_vector(pdev, i), i + 1);
571+
dev_err(dev, "Failed to request IRQ %d for MSI%s %d\n",
572+
pci_irq_vector(pdev, i),
573+
irq_type == IRQ_TYPE_MSIX ? "-X" : "", i + 1);
563574
}
564575

565576
for (bar = BAR_0; bar <= BAR_5; bar++) {
@@ -625,6 +636,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
625636

626637
err_disable_msi:
627638
pci_disable_msi(pdev);
639+
pci_disable_msix(pdev);
628640
pci_release_regions(pdev);
629641

630642
err_disable_pdev:
@@ -656,6 +668,7 @@ static void pci_endpoint_test_remove(struct pci_dev *pdev)
656668
for (i = 0; i < test->num_irqs; i++)
657669
devm_free_irq(&pdev->dev, pci_irq_vector(pdev, i), test);
658670
pci_disable_msi(pdev);
671+
pci_disable_msix(pdev);
659672
pci_release_regions(pdev);
660673
pci_disable_device(pdev);
661674
}

drivers/pci/controller/dwc/pcie-designware-plat.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ static void dw_plat_pcie_ep_init(struct dw_pcie_ep *ep)
7777
dw_pcie_ep_reset_bar(pci, bar);
7878

7979
epc->features |= EPC_FEATURE_NO_LINKUP_NOTIFIER;
80+
epc->features |= EPC_FEATURE_MSIX_AVAILABLE;
8081
}
8182

8283
static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,

drivers/pci/endpoint/functions/pci-epf-test.c

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@
2020

2121
#define IRQ_TYPE_LEGACY 0
2222
#define IRQ_TYPE_MSI 1
23+
#define IRQ_TYPE_MSIX 2
2324

2425
#define COMMAND_RAISE_LEGACY_IRQ BIT(0)
2526
#define COMMAND_RAISE_MSI_IRQ BIT(1)
26-
/* BIT(2) is reserved for raising MSI-X IRQ command */
27+
#define COMMAND_RAISE_MSIX_IRQ BIT(2)
2728
#define COMMAND_READ BIT(3)
2829
#define COMMAND_WRITE BIT(4)
2930
#define COMMAND_COPY BIT(5)
@@ -47,6 +48,7 @@ struct pci_epf_test {
4748
struct pci_epf *epf;
4849
enum pci_barno test_reg_bar;
4950
bool linkup_notifier;
51+
bool msix_available;
5052
struct delayed_work cmd_handler;
5153
};
5254

@@ -266,6 +268,9 @@ static void pci_epf_test_raise_irq(struct pci_epf_test *epf_test, u8 irq_type,
266268
case IRQ_TYPE_MSI:
267269
pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_MSI, irq);
268270
break;
271+
case IRQ_TYPE_MSIX:
272+
pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_MSIX, irq);
273+
break;
269274
default:
270275
dev_err(dev, "Failed to raise IRQ, unknown type\n");
271276
break;
@@ -292,7 +297,7 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
292297
reg->command = 0;
293298
reg->status = 0;
294299

295-
if (reg->irq_type > IRQ_TYPE_MSI) {
300+
if (reg->irq_type > IRQ_TYPE_MSIX) {
296301
dev_err(dev, "Failed to detect IRQ type\n");
297302
goto reset_handler;
298303
}
@@ -346,6 +351,16 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
346351
goto reset_handler;
347352
}
348353

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);
361+
goto reset_handler;
362+
}
363+
349364
reset_handler:
350365
queue_delayed_work(kpcitest_workqueue, &epf_test->cmd_handler,
351366
msecs_to_jiffies(1));
@@ -459,6 +474,8 @@ static int pci_epf_test_bind(struct pci_epf *epf)
459474
else
460475
epf_test->linkup_notifier = true;
461476

477+
epf_test->msix_available = epc->features & EPC_FEATURE_MSIX_AVAILABLE;
478+
462479
epf_test->test_reg_bar = EPC_FEATURE_GET_BAR(epc->features);
463480

464481
ret = pci_epc_write_header(epc, epf->func_no, header);
@@ -481,6 +498,14 @@ static int pci_epf_test_bind(struct pci_epf *epf)
481498
return ret;
482499
}
483500

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+
}
508+
484509
if (!epf_test->linkup_notifier)
485510
queue_work(kpcitest_workqueue, &epf_test->cmd_handler.work);
486511

include/linux/pci-epc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ struct pci_epc {
102102

103103
#define EPC_FEATURE_NO_LINKUP_NOTIFIER BIT(0)
104104
#define EPC_FEATURE_BAR_MASK (BIT(1) | BIT(2) | BIT(3))
105+
#define EPC_FEATURE_MSIX_AVAILABLE BIT(4)
105106
#define EPC_FEATURE_SET_BAR(features, bar) \
106107
(features |= (EPC_FEATURE_BAR_MASK & (bar << 1)))
107108
#define EPC_FEATURE_GET_BAR(features) \

include/uapi/linux/pcitest.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,6 @@
1616
#define PCITEST_WRITE _IOW('P', 0x4, unsigned long)
1717
#define PCITEST_READ _IOW('P', 0x5, unsigned long)
1818
#define PCITEST_COPY _IOW('P', 0x6, unsigned long)
19+
#define PCITEST_MSIX _IOW('P', 0x7, int)
1920

2021
#endif /* __UAPI_LINUX_PCITEST_H */

0 commit comments

Comments
 (0)