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

pci_endpoint_test: Add 2 ioctl commands

Add MSI-X support and update driver documentation accordingly.

Add 2 new IOCTL commands:
- Allow to reconfigure driver IRQ type in runtime.
- Allow to retrieve current driver IRQ type configured.

Add IRQ type validation before executing the READ/WRITE/COPY tests.

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
e0332712 c2e00e31

+165 -48
+1 -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 + 'P' 01-09 drivers/misc/pci_endpoint_test.c conflict! 170 170 'Q' all linux/soundcard.h 171 171 'R' 00-1F linux/random.h conflict! 172 172 'R' 01 linux/rfkill.h conflict!
+3
Documentation/misc-devices/pci-endpoint-test.txt
··· 28 28 to be tested should be passed as argument. 29 29 PCITEST_MSIX: Tests message signalled interrupts. The MSI-X number 30 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. 31 34 PCITEST_WRITE: Perform write tests. The size of the buffer should be passed 32 35 as argument. 33 36 PCITEST_READ: Perform read tests. The size of the buffer should be passed
+159 -47
drivers/misc/pci_endpoint_test.c
··· 37 37 38 38 #define DRV_MODULE_NAME "pci-endpoint-test" 39 39 40 + #define IRQ_TYPE_UNDEFINED -1 40 41 #define IRQ_TYPE_LEGACY 0 41 42 #define IRQ_TYPE_MSI 1 42 43 #define IRQ_TYPE_MSIX 2 ··· 158 157 return IRQ_HANDLED; 159 158 } 160 159 160 + static void pci_endpoint_test_free_irq_vectors(struct pci_endpoint_test *test) 161 + { 162 + struct pci_dev *pdev = test->pdev; 163 + 164 + pci_free_irq_vectors(pdev); 165 + } 166 + 167 + static bool pci_endpoint_test_alloc_irq_vectors(struct pci_endpoint_test *test, 168 + int type) 169 + { 170 + int irq = -1; 171 + struct pci_dev *pdev = test->pdev; 172 + struct device *dev = &pdev->dev; 173 + bool res = true; 174 + 175 + switch (type) { 176 + case IRQ_TYPE_LEGACY: 177 + irq = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_LEGACY); 178 + if (irq < 0) 179 + dev_err(dev, "Failed to get Legacy interrupt\n"); 180 + break; 181 + case IRQ_TYPE_MSI: 182 + irq = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI); 183 + if (irq < 0) 184 + dev_err(dev, "Failed to get MSI interrupts\n"); 185 + break; 186 + case IRQ_TYPE_MSIX: 187 + irq = pci_alloc_irq_vectors(pdev, 1, 2048, PCI_IRQ_MSIX); 188 + if (irq < 0) 189 + dev_err(dev, "Failed to get MSI-X interrupts\n"); 190 + break; 191 + default: 192 + dev_err(dev, "Invalid IRQ type selected\n"); 193 + } 194 + 195 + if (irq < 0) { 196 + irq = 0; 197 + res = false; 198 + } 199 + test->num_irqs = irq; 200 + 201 + return res; 202 + } 203 + 204 + static void pci_endpoint_test_release_irq(struct pci_endpoint_test *test) 205 + { 206 + int i; 207 + struct pci_dev *pdev = test->pdev; 208 + struct device *dev = &pdev->dev; 209 + 210 + for (i = 0; i < test->num_irqs; i++) 211 + devm_free_irq(dev, pci_irq_vector(pdev, i), test); 212 + 213 + test->num_irqs = 0; 214 + } 215 + 216 + static bool pci_endpoint_test_request_irq(struct pci_endpoint_test *test) 217 + { 218 + int i; 219 + int err; 220 + struct pci_dev *pdev = test->pdev; 221 + struct device *dev = &pdev->dev; 222 + 223 + for (i = 0; i < test->num_irqs; i++) { 224 + err = devm_request_irq(dev, pci_irq_vector(pdev, i), 225 + pci_endpoint_test_irqhandler, 226 + IRQF_SHARED, DRV_MODULE_NAME, test); 227 + if (err) 228 + goto fail; 229 + } 230 + 231 + return true; 232 + 233 + fail: 234 + switch (irq_type) { 235 + case IRQ_TYPE_LEGACY: 236 + dev_err(dev, "Failed to request IRQ %d for Legacy\n", 237 + pci_irq_vector(pdev, i)); 238 + break; 239 + case IRQ_TYPE_MSI: 240 + dev_err(dev, "Failed to request IRQ %d for MSI %d\n", 241 + pci_irq_vector(pdev, i), 242 + i + 1); 243 + break; 244 + case IRQ_TYPE_MSIX: 245 + dev_err(dev, "Failed to request IRQ %d for MSI-X %d\n", 246 + pci_irq_vector(pdev, i), 247 + i + 1); 248 + break; 249 + } 250 + 251 + return false; 252 + } 253 + 161 254 static bool pci_endpoint_test_bar(struct pci_endpoint_test *test, 162 255 enum pci_barno barno) 163 256 { ··· 341 246 342 247 if (size > SIZE_MAX - alignment) 343 248 goto err; 249 + 250 + if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) { 251 + dev_err(dev, "Invalid IRQ type option\n"); 252 + goto err; 253 + } 344 254 345 255 orig_src_addr = dma_alloc_coherent(dev, size + alignment, 346 256 &orig_src_phys_addr, GFP_KERNEL); ··· 437 337 if (size > SIZE_MAX - alignment) 438 338 goto err; 439 339 340 + if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) { 341 + dev_err(dev, "Invalid IRQ type option\n"); 342 + goto err; 343 + } 344 + 440 345 orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr, 441 346 GFP_KERNEL); 442 347 if (!orig_addr) { ··· 505 400 if (size > SIZE_MAX - alignment) 506 401 goto err; 507 402 403 + if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) { 404 + dev_err(dev, "Invalid IRQ type option\n"); 405 + goto err; 406 + } 407 + 508 408 orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr, 509 409 GFP_KERNEL); 510 410 if (!orig_addr) { ··· 550 440 return ret; 551 441 } 552 442 443 + static bool pci_endpoint_test_set_irq(struct pci_endpoint_test *test, 444 + int req_irq_type) 445 + { 446 + struct pci_dev *pdev = test->pdev; 447 + struct device *dev = &pdev->dev; 448 + 449 + if (req_irq_type < IRQ_TYPE_LEGACY || req_irq_type > IRQ_TYPE_MSIX) { 450 + dev_err(dev, "Invalid IRQ type option\n"); 451 + return false; 452 + } 453 + 454 + if (irq_type == req_irq_type) 455 + return true; 456 + 457 + pci_endpoint_test_release_irq(test); 458 + pci_endpoint_test_free_irq_vectors(test); 459 + 460 + if (!pci_endpoint_test_alloc_irq_vectors(test, req_irq_type)) 461 + goto err; 462 + 463 + if (!pci_endpoint_test_request_irq(test)) 464 + goto err; 465 + 466 + irq_type = req_irq_type; 467 + return true; 468 + 469 + err: 470 + pci_endpoint_test_free_irq_vectors(test); 471 + irq_type = IRQ_TYPE_UNDEFINED; 472 + return false; 473 + } 474 + 553 475 static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd, 554 476 unsigned long arg) 555 477 { ··· 613 471 case PCITEST_COPY: 614 472 ret = pci_endpoint_test_copy(test, arg); 615 473 break; 474 + case PCITEST_SET_IRQTYPE: 475 + ret = pci_endpoint_test_set_irq(test, arg); 476 + break; 477 + case PCITEST_GET_IRQTYPE: 478 + ret = irq_type; 479 + break; 616 480 } 617 481 618 482 ret: ··· 634 486 static int pci_endpoint_test_probe(struct pci_dev *pdev, 635 487 const struct pci_device_id *ent) 636 488 { 637 - int i; 638 489 int err; 639 - int irq = 0; 640 490 int id; 641 491 char name[20]; 642 492 enum pci_barno bar; ··· 683 537 684 538 pci_set_master(pdev); 685 539 686 - switch (irq_type) { 687 - case IRQ_TYPE_LEGACY: 688 - break; 689 - case IRQ_TYPE_MSI: 690 - irq = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI); 691 - if (irq < 0) 692 - dev_err(dev, "Failed to get MSI interrupts\n"); 693 - test->num_irqs = irq; 694 - break; 695 - case IRQ_TYPE_MSIX: 696 - irq = pci_alloc_irq_vectors(pdev, 1, 2048, PCI_IRQ_MSIX); 697 - if (irq < 0) 698 - dev_err(dev, "Failed to get MSI-X interrupts\n"); 699 - test->num_irqs = irq; 700 - break; 701 - default: 702 - dev_err(dev, "Invalid IRQ type selected\n"); 703 - } 540 + if (!pci_endpoint_test_alloc_irq_vectors(test, irq_type)) 541 + goto err_disable_irq; 704 542 705 - err = devm_request_irq(dev, pdev->irq, pci_endpoint_test_irqhandler, 706 - IRQF_SHARED, DRV_MODULE_NAME, test); 707 - if (err) { 708 - dev_err(dev, "Failed to request IRQ %d\n", pdev->irq); 709 - goto err_disable_msi; 710 - } 711 - 712 - for (i = 1; i < irq; i++) { 713 - err = devm_request_irq(dev, pci_irq_vector(pdev, i), 714 - pci_endpoint_test_irqhandler, 715 - IRQF_SHARED, DRV_MODULE_NAME, test); 716 - if (err) 717 - dev_err(dev, "Failed to request IRQ %d for MSI%s %d\n", 718 - pci_irq_vector(pdev, i), 719 - irq_type == IRQ_TYPE_MSIX ? "-X" : "", i + 1); 720 - } 543 + if (!pci_endpoint_test_request_irq(test)) 544 + goto err_disable_irq; 721 545 722 546 for (bar = BAR_0; bar <= BAR_5; bar++) { 723 547 if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) { ··· 746 630 if (test->bar[bar]) 747 631 pci_iounmap(pdev, test->bar[bar]); 748 632 } 633 + pci_endpoint_test_release_irq(test); 749 634 750 - for (i = 0; i < irq; i++) 751 - devm_free_irq(&pdev->dev, pci_irq_vector(pdev, i), test); 752 - 753 - err_disable_msi: 754 - pci_disable_msi(pdev); 755 - pci_disable_msix(pdev); 635 + err_disable_irq: 636 + pci_endpoint_test_free_irq_vectors(test); 756 637 pci_release_regions(pdev); 757 638 758 639 err_disable_pdev: ··· 761 648 static void pci_endpoint_test_remove(struct pci_dev *pdev) 762 649 { 763 650 int id; 764 - int i; 765 651 enum pci_barno bar; 766 652 struct pci_endpoint_test *test = pci_get_drvdata(pdev); 767 653 struct miscdevice *misc_device = &test->miscdev; ··· 777 665 if (test->bar[bar]) 778 666 pci_iounmap(pdev, test->bar[bar]); 779 667 } 780 - for (i = 0; i < test->num_irqs; i++) 781 - devm_free_irq(&pdev->dev, pci_irq_vector(pdev, i), test); 782 - pci_disable_msi(pdev); 783 - pci_disable_msix(pdev); 668 + 669 + pci_endpoint_test_release_irq(test); 670 + pci_endpoint_test_free_irq_vectors(test); 671 + 784 672 pci_release_regions(pdev); 785 673 pci_disable_device(pdev); 786 674 }
+2
include/uapi/linux/pcitest.h
··· 17 17 #define PCITEST_READ _IOW('P', 0x5, unsigned long) 18 18 #define PCITEST_COPY _IOW('P', 0x6, unsigned long) 19 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) 20 22 21 23 #endif /* __UAPI_LINUX_PCITEST_H */