Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

pci-epf-test/pci_endpoint_test: Add MSI-X support

Add MSI-X support and update driver documentation accordingly.

Signed-off-by: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Acked-by: Kishon Vijay Abraham I <kishon@ti.com>

authored by

Gustavo Pimentel and committed by
Lorenzo Pieralisi
c2e00e31 9133e394

+79 -16
+2 -2
Documentation/PCI/endpoint/pci-endpoint.txt
··· 44 44 * clear_bar: ops to reset the BAR 45 45 * alloc_addr_space: ops to allocate in PCI controller address space 46 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 48 * start: ops to start the PCI link 49 49 * stop: ops to stop the PCI link 50 50 ··· 96 96 *) pci_epc_raise_irq() 97 97 98 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 101 *) pci_epc_mem_alloc_addr() 102 102
+3 -1
Documentation/PCI/endpoint/pci-test-function.txt
··· 36 36 Bitfield Description: 37 37 Bit 0 : raise legacy IRQ 38 38 Bit 1 : raise MSI IRQ 39 - Bit 2 : raise MSI-X IRQ (reserved for future implementation) 39 + Bit 2 : raise MSI-X IRQ 40 40 Bit 3 : read command (read data from RC buffer) 41 41 Bit 4 : write command (write data to RC buffer) 42 42 Bit 5 : copy command (copy data from one RC buffer to another ··· 75 75 Possible types: 76 76 - Legacy : 0 77 77 - MSI : 1 78 + - MSI-X : 2 78 79 79 80 *) PCI_ENDPOINT_TEST_IRQ_NUMBER 80 81 ··· 84 83 Admissible values: 85 84 - Legacy : 0 86 85 - MSI : [1 .. 32] 86 + - MSI-X : [1 .. 2048]
+19 -3
Documentation/PCI/endpoint/pci-test-howto.txt
··· 45 45 configurable fields. 46 46 47 47 # 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 51 51 52 52 The PCI endpoint function driver populates these entries with default values 53 53 when the device is bound to the driver. The pci-epf-test driver populates ··· 67 67 # echo 0x104c > functions/pci_epf_test/func1/vendorid 68 68 # echo 0xb500 > functions/pci_epf_test/func1/deviceid 69 69 # echo 16 > functions/pci_epf_test/func1/msi_interrupts 70 + # echo 8 > functions/pci_epf_test/func1/msix_interrupts 70 71 71 72 1.5 Binding pci-epf-test Device to EP Controller 72 73 ··· 154 153 MSI30: NOT OKAY 155 154 MSI31: NOT OKAY 156 155 MSI32: NOT OKAY 156 + MSIX1: OKAY 157 + MSIX2: OKAY 158 + MSIX3: OKAY 159 + MSIX4: OKAY 160 + MSIX5: OKAY 161 + MSIX6: OKAY 162 + MSIX7: OKAY 163 + MSIX8: OKAY 164 + MSIX9: NOT OKAY 165 + MSIX10: NOT OKAY 166 + MSIX11: NOT OKAY 167 + MSIX12: NOT OKAY 168 + MSIX13: NOT OKAY 169 + [...] 170 + MSIX2048: NOT OKAY 157 171 158 172 Read Tests 159 173
+1
Documentation/ioctl/ioctl-number.txt
··· 166 166 'P' all linux/soundcard.h conflict! 167 167 'P' 60-6F sound/sscape_ioctl.h conflict! 168 168 'P' 00-0F drivers/usb/class/usblp.c conflict! 169 + 'P' 01-07 drivers/misc/pci_endpoint_test.c conflict! 169 170 'Q' all linux/soundcard.h 170 171 'R' 00-1F linux/random.h conflict! 171 172 'R' 01 linux/rfkill.h conflict!
+3
Documentation/misc-devices/pci-endpoint-test.txt
··· 10 10 *) verifying addresses programmed in BAR 11 11 *) raise legacy IRQ 12 12 *) raise MSI IRQ 13 + *) raise MSI-X IRQ 13 14 *) read data 14 15 *) write data 15 16 *) copy data ··· 25 24 should be passed as argument. 26 25 PCITEST_LEGACY_IRQ: Tests legacy IRQ 27 26 PCITEST_MSI: Tests message signalled interrupts. The MSI number 27 + to be tested should be passed as argument. 28 + PCITEST_MSIX: Tests message signalled interrupts. The MSI-X number 28 29 to be tested should be passed as argument. 29 30 PCITEST_WRITE: Perform write tests. The size of the buffer should be passed 30 31 as argument.
+21 -8
drivers/misc/pci_endpoint_test.c
··· 39 39 40 40 #define IRQ_TYPE_LEGACY 0 41 41 #define IRQ_TYPE_MSI 1 42 + #define IRQ_TYPE_MSIX 2 42 43 43 44 #define PCI_ENDPOINT_TEST_MAGIC 0x0 44 45 45 46 #define PCI_ENDPOINT_TEST_COMMAND 0x4 46 47 #define COMMAND_RAISE_LEGACY_IRQ BIT(0) 47 48 #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) 49 50 #define COMMAND_READ BIT(3) 50 51 #define COMMAND_WRITE BIT(4) 51 52 #define COMMAND_COPY BIT(5) ··· 85 84 86 85 static int irq_type = IRQ_TYPE_MSI; 87 86 module_param(irq_type, int, 0444); 88 - MODULE_PARM_DESC(irq_type, "IRQ mode selection in pci_endpoint_test (0 - Legacy, 1 - MSI)"); 87 + MODULE_PARM_DESC(irq_type, "IRQ mode selection in pci_endpoint_test (0 - Legacy, 1 - MSI, 2 - MSI-X)"); 89 88 90 89 enum pci_barno { 91 90 BAR_0, ··· 203 202 } 204 203 205 204 static bool pci_endpoint_test_msi_irq(struct pci_endpoint_test *test, 206 - u8 msi_num) 205 + u16 msi_num, bool msix) 207 206 { 208 207 u32 val; 209 208 struct pci_dev *pdev = test->pdev; 210 209 211 210 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, 212 - IRQ_TYPE_MSI); 211 + msix == false ? IRQ_TYPE_MSI : 212 + IRQ_TYPE_MSIX); 213 213 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, msi_num); 214 214 pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND, 215 - COMMAND_RAISE_MSI_IRQ); 215 + msix == false ? COMMAND_RAISE_MSI_IRQ : 216 + COMMAND_RAISE_MSIX_IRQ); 216 217 val = wait_for_completion_timeout(&test->irq_raised, 217 218 msecs_to_jiffies(1000)); 218 219 if (!val) ··· 459 456 ret = pci_endpoint_test_legacy_irq(test); 460 457 break; 461 458 case PCITEST_MSI: 462 - ret = pci_endpoint_test_msi_irq(test, arg); 459 + case PCITEST_MSIX: 460 + ret = pci_endpoint_test_msi_irq(test, arg, cmd == PCITEST_MSIX); 463 461 break; 464 462 case PCITEST_WRITE: 465 463 ret = pci_endpoint_test_write(test, arg); ··· 546 542 dev_err(dev, "Failed to get MSI interrupts\n"); 547 543 test->num_irqs = irq; 548 544 break; 545 + case IRQ_TYPE_MSIX: 546 + irq = pci_alloc_irq_vectors(pdev, 1, 2048, PCI_IRQ_MSIX); 547 + if (irq < 0) 548 + dev_err(dev, "Failed to get MSI-X interrupts\n"); 549 + test->num_irqs = irq; 550 + break; 549 551 default: 550 552 dev_err(dev, "Invalid IRQ type selected\n"); 551 553 } ··· 568 558 pci_endpoint_test_irqhandler, 569 559 IRQF_SHARED, DRV_MODULE_NAME, test); 570 560 if (err) 571 - dev_err(dev, "failed to request IRQ %d for MSI %d\n", 572 - pci_irq_vector(pdev, i), i + 1); 561 + dev_err(dev, "Failed to request IRQ %d for MSI%s %d\n", 562 + pci_irq_vector(pdev, i), 563 + irq_type == IRQ_TYPE_MSIX ? "-X" : "", i + 1); 573 564 } 574 565 575 566 for (bar = BAR_0; bar <= BAR_5; bar++) { ··· 636 625 637 626 err_disable_msi: 638 627 pci_disable_msi(pdev); 628 + pci_disable_msix(pdev); 639 629 pci_release_regions(pdev); 640 630 641 631 err_disable_pdev: ··· 668 656 for (i = 0; i < test->num_irqs; i++) 669 657 devm_free_irq(&pdev->dev, pci_irq_vector(pdev, i), test); 670 658 pci_disable_msi(pdev); 659 + pci_disable_msix(pdev); 671 660 pci_release_regions(pdev); 672 661 pci_disable_device(pdev); 673 662 }
+1
drivers/pci/controller/dwc/pcie-designware-plat.c
··· 77 77 dw_pcie_ep_reset_bar(pci, bar); 78 78 79 79 epc->features |= EPC_FEATURE_NO_LINKUP_NOTIFIER; 80 + epc->features |= EPC_FEATURE_MSIX_AVAILABLE; 80 81 } 81 82 82 83 static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
+27 -2
drivers/pci/endpoint/functions/pci-epf-test.c
··· 20 20 21 21 #define IRQ_TYPE_LEGACY 0 22 22 #define IRQ_TYPE_MSI 1 23 + #define IRQ_TYPE_MSIX 2 23 24 24 25 #define COMMAND_RAISE_LEGACY_IRQ BIT(0) 25 26 #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) 27 28 #define COMMAND_READ BIT(3) 28 29 #define COMMAND_WRITE BIT(4) 29 30 #define COMMAND_COPY BIT(5) ··· 48 47 struct pci_epf *epf; 49 48 enum pci_barno test_reg_bar; 50 49 bool linkup_notifier; 50 + bool msix_available; 51 51 struct delayed_work cmd_handler; 52 52 }; 53 53 ··· 268 266 case IRQ_TYPE_MSI: 269 267 pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_MSI, irq); 270 268 break; 269 + case IRQ_TYPE_MSIX: 270 + pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_MSIX, irq); 271 + break; 271 272 default: 272 273 dev_err(dev, "Failed to raise IRQ, unknown type\n"); 273 274 break; ··· 297 292 reg->command = 0; 298 293 reg->status = 0; 299 294 300 - if (reg->irq_type > IRQ_TYPE_MSI) { 295 + if (reg->irq_type > IRQ_TYPE_MSIX) { 301 296 dev_err(dev, "Failed to detect IRQ type\n"); 302 297 goto reset_handler; 303 298 } ··· 347 342 goto reset_handler; 348 343 reg->status = STATUS_IRQ_RAISED; 349 344 pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_MSI, 345 + reg->irq_number); 346 + goto reset_handler; 347 + } 348 + 349 + if (command & COMMAND_RAISE_MSIX_IRQ) { 350 + count = pci_epc_get_msix(epc, epf->func_no); 351 + if (reg->irq_number > count || count <= 0) 352 + goto reset_handler; 353 + reg->status = STATUS_IRQ_RAISED; 354 + pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_MSIX, 350 355 reg->irq_number); 351 356 goto reset_handler; 352 357 } ··· 474 459 else 475 460 epf_test->linkup_notifier = true; 476 461 462 + epf_test->msix_available = epc->features & EPC_FEATURE_MSIX_AVAILABLE; 463 + 477 464 epf_test->test_reg_bar = EPC_FEATURE_GET_BAR(epc->features); 478 465 479 466 ret = pci_epc_write_header(epc, epf->func_no, header); ··· 496 479 if (ret) { 497 480 dev_err(dev, "MSI configuration failed\n"); 498 481 return ret; 482 + } 483 + 484 + if (epf_test->msix_available) { 485 + ret = pci_epc_set_msix(epc, epf->func_no, epf->msix_interrupts); 486 + if (ret) { 487 + dev_err(dev, "MSI-X configuration failed\n"); 488 + return ret; 489 + } 499 490 } 500 491 501 492 if (!epf_test->linkup_notifier)
+1
include/linux/pci-epc.h
··· 102 102 103 103 #define EPC_FEATURE_NO_LINKUP_NOTIFIER BIT(0) 104 104 #define EPC_FEATURE_BAR_MASK (BIT(1) | BIT(2) | BIT(3)) 105 + #define EPC_FEATURE_MSIX_AVAILABLE BIT(4) 105 106 #define EPC_FEATURE_SET_BAR(features, bar) \ 106 107 (features |= (EPC_FEATURE_BAR_MASK & (bar << 1))) 107 108 #define EPC_FEATURE_GET_BAR(features) \
+1
include/uapi/linux/pcitest.h
··· 16 16 #define PCITEST_WRITE _IOW('P', 0x4, unsigned long) 17 17 #define PCITEST_READ _IOW('P', 0x5, unsigned long) 18 18 #define PCITEST_COPY _IOW('P', 0x6, unsigned long) 19 + #define PCITEST_MSIX _IOW('P', 0x7, int) 19 20 20 21 #endif /* __UAPI_LINUX_PCITEST_H */