aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGustavo Pimentel <gustavo.pimentel@synopsys.com>2018-07-19 04:32:20 -0400
committerLorenzo Pieralisi <lorenzo.pieralisi@arm.com>2018-07-19 06:46:57 -0400
commite03327122e2c8e6ae4565ef5b3d3cbe4364546a1 (patch)
tree99dfa547dc2e84beac39eeea61192cc80ba46004
parentc2e00e31087e58f6c49b90b4702fc3df4fad6a83 (diff)
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>
-rw-r--r--Documentation/ioctl/ioctl-number.txt2
-rw-r--r--Documentation/misc-devices/pci-endpoint-test.txt3
-rw-r--r--drivers/misc/pci_endpoint_test.c206
-rw-r--r--include/uapi/linux/pcitest.h2
4 files changed, 165 insertions, 48 deletions
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 65259d459fd1..c15c4f3bdd82 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -166,7 +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-07 drivers/misc/pci_endpoint_test.c conflict! 169'P' 01-09 drivers/misc/pci_endpoint_test.c conflict!
170'Q' all linux/soundcard.h 170'Q' all linux/soundcard.h
171'R' 00-1F linux/random.h conflict! 171'R' 00-1F linux/random.h conflict!
172'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 fdfa0f66d3d0..58ccca4416b1 100644
--- a/Documentation/misc-devices/pci-endpoint-test.txt
+++ b/Documentation/misc-devices/pci-endpoint-test.txt
@@ -28,6 +28,9 @@ ioctl
28 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 29 PCITEST_MSIX: Tests message signalled interrupts. The MSI-X number
30 to be tested should be passed as argument. 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 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
32 as argument. 35 as argument.
33 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 f4fef108caff..896e2df9400f 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -37,6 +37,7 @@
37 37
38#define DRV_MODULE_NAME "pci-endpoint-test" 38#define DRV_MODULE_NAME "pci-endpoint-test"
39 39
40#define IRQ_TYPE_UNDEFINED -1
40#define IRQ_TYPE_LEGACY 0 41#define IRQ_TYPE_LEGACY 0
41#define IRQ_TYPE_MSI 1 42#define IRQ_TYPE_MSI 1
42#define IRQ_TYPE_MSIX 2 43#define IRQ_TYPE_MSIX 2
@@ -157,6 +158,100 @@ static irqreturn_t pci_endpoint_test_irqhandler(int irq, void *dev_id)
157 return IRQ_HANDLED; 158 return IRQ_HANDLED;
158} 159}
159 160
161static 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
168static 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
205static 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
217static 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
234fail:
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
160static bool pci_endpoint_test_bar(struct pci_endpoint_test *test, 255static bool pci_endpoint_test_bar(struct pci_endpoint_test *test,
161 enum pci_barno barno) 256 enum pci_barno barno)
162{ 257{
@@ -247,6 +342,11 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size)
247 if (size > SIZE_MAX - alignment) 342 if (size > SIZE_MAX - alignment)
248 goto err; 343 goto err;
249 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
250 orig_src_addr = dma_alloc_coherent(dev, size + alignment, 350 orig_src_addr = dma_alloc_coherent(dev, size + alignment,
251 &orig_src_phys_addr, GFP_KERNEL); 351 &orig_src_phys_addr, GFP_KERNEL);
252 if (!orig_src_addr) { 352 if (!orig_src_addr) {
@@ -337,6 +437,11 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size)
337 if (size > SIZE_MAX - alignment) 437 if (size > SIZE_MAX - alignment)
338 goto err; 438 goto err;
339 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
340 orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr, 445 orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr,
341 GFP_KERNEL); 446 GFP_KERNEL);
342 if (!orig_addr) { 447 if (!orig_addr) {
@@ -400,6 +505,11 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size)
400 if (size > SIZE_MAX - alignment) 505 if (size > SIZE_MAX - alignment)
401 goto err; 506 goto err;
402 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
403 orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr, 513 orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr,
404 GFP_KERNEL); 514 GFP_KERNEL);
405 if (!orig_addr) { 515 if (!orig_addr) {
@@ -440,6 +550,38 @@ err:
440 return ret; 550 return ret;
441} 551}
442 552
553static 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
579err:
580 pci_endpoint_test_free_irq_vectors(test);
581 irq_type = IRQ_TYPE_UNDEFINED;
582 return false;
583}
584
443static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd, 585static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
444 unsigned long arg) 586 unsigned long arg)
445{ 587{
@@ -471,6 +613,12 @@ static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
471 case PCITEST_COPY: 613 case PCITEST_COPY:
472 ret = pci_endpoint_test_copy(test, arg); 614 ret = pci_endpoint_test_copy(test, arg);
473 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;
474 } 622 }
475 623
476ret: 624ret:
@@ -486,9 +634,7 @@ static const struct file_operations pci_endpoint_test_fops = {
486static int pci_endpoint_test_probe(struct pci_dev *pdev, 634static int pci_endpoint_test_probe(struct pci_dev *pdev,
487 const struct pci_device_id *ent) 635 const struct pci_device_id *ent)
488{ 636{
489 int i;
490 int err; 637 int err;
491 int irq = 0;
492 int id; 638 int id;
493 char name[20]; 639 char name[20];
494 enum pci_barno bar; 640 enum pci_barno bar;
@@ -537,41 +683,11 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
537 683
538 pci_set_master(pdev); 684 pci_set_master(pdev);
539 685
540 switch (irq_type) { 686 if (!pci_endpoint_test_alloc_irq_vectors(test, irq_type))
541 case IRQ_TYPE_LEGACY: 687 goto err_disable_irq;
542 break;
543 case IRQ_TYPE_MSI:
544 irq = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI);
545 if (irq < 0)
546 dev_err(dev, "Failed to get MSI interrupts\n");
547 test->num_irqs = irq;
548 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;
555 default:
556 dev_err(dev, "Invalid IRQ type selected\n");
557 }
558 688
559 err = devm_request_irq(dev, pdev->irq, pci_endpoint_test_irqhandler, 689 if (!pci_endpoint_test_request_irq(test))
560 IRQF_SHARED, DRV_MODULE_NAME, test); 690 goto err_disable_irq;
561 if (err) {
562 dev_err(dev, "Failed to request IRQ %d\n", pdev->irq);
563 goto err_disable_msi;
564 }
565
566 for (i = 1; i < irq; i++) {
567 err = devm_request_irq(dev, pci_irq_vector(pdev, i),
568 pci_endpoint_test_irqhandler,
569 IRQF_SHARED, DRV_MODULE_NAME, test);
570 if (err)
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);
574 }
575 691
576 for (bar = BAR_0; bar <= BAR_5; bar++) { 692 for (bar = BAR_0; bar <= BAR_5; bar++) {
577 if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) { 693 if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) {
@@ -630,13 +746,10 @@ err_iounmap:
630 if (test->bar[bar]) 746 if (test->bar[bar])
631 pci_iounmap(pdev, test->bar[bar]); 747 pci_iounmap(pdev, test->bar[bar]);
632 } 748 }
749 pci_endpoint_test_release_irq(test);
633 750
634 for (i = 0; i < irq; i++) 751err_disable_irq:
635 devm_free_irq(&pdev->dev, pci_irq_vector(pdev, i), test); 752 pci_endpoint_test_free_irq_vectors(test);
636
637err_disable_msi:
638 pci_disable_msi(pdev);
639 pci_disable_msix(pdev);
640 pci_release_regions(pdev); 753 pci_release_regions(pdev);
641 754
642err_disable_pdev: 755err_disable_pdev:
@@ -648,7 +761,6 @@ err_disable_pdev:
648static void pci_endpoint_test_remove(struct pci_dev *pdev) 761static void pci_endpoint_test_remove(struct pci_dev *pdev)
649{ 762{
650 int id; 763 int id;
651 int i;
652 enum pci_barno bar; 764 enum pci_barno bar;
653 struct pci_endpoint_test *test = pci_get_drvdata(pdev); 765 struct pci_endpoint_test *test = pci_get_drvdata(pdev);
654 struct miscdevice *misc_device = &test->miscdev; 766 struct miscdevice *misc_device = &test->miscdev;
@@ -665,10 +777,10 @@ static void pci_endpoint_test_remove(struct pci_dev *pdev)
665 if (test->bar[bar]) 777 if (test->bar[bar])
666 pci_iounmap(pdev, test->bar[bar]); 778 pci_iounmap(pdev, test->bar[bar]);
667 } 779 }
668 for (i = 0; i < test->num_irqs; i++) 780
669 devm_free_irq(&pdev->dev, pci_irq_vector(pdev, i), test); 781 pci_endpoint_test_release_irq(test);
670 pci_disable_msi(pdev); 782 pci_endpoint_test_free_irq_vectors(test);
671 pci_disable_msix(pdev); 783
672 pci_release_regions(pdev); 784 pci_release_regions(pdev);
673 pci_disable_device(pdev); 785 pci_disable_device(pdev);
674} 786}
diff --git a/include/uapi/linux/pcitest.h b/include/uapi/linux/pcitest.h
index d746fb159dcd..cbf422e56696 100644
--- a/include/uapi/linux/pcitest.h
+++ b/include/uapi/linux/pcitest.h
@@ -17,5 +17,7 @@
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) 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#endif /* __UAPI_LINUX_PCITEST_H */ 23#endif /* __UAPI_LINUX_PCITEST_H */