diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2025-03-27 13:14:46 -0500 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2025-03-27 13:14:46 -0500 |
commit | cc28c0e5e725165d19deccfd5cd6025384c9dbb1 (patch) | |
tree | 6b345467227190ad4c53ab1f528539a475d9303a /drivers | |
parent | a113afb84ae63ec4c893bc3204945ef6f3bb89f7 (diff) | |
parent | 08818c6d7f276eb5895959f34c491a3911ae7820 (diff) |
Merge branch 'pci/endpoint-test'
- Fix endpoint BAR testing so the test can skip disabled BARs instead of
reporting them as failures (Niklas Cassel)
- Verify that pci_endpoint interrupt tests set the correct IRQ type
(Kunihiko Hayashi)
- Fix interpretation of pci_endpoint_test_bars_read_bar() error returns
(Niklas Cassel)
- Fix potential string truncation in pci_endpoint_test_probe() (Niklas
Cassel)
- Increase endpoint test BAR size variable to accommodate BARs larger than
INT_MAX (Niklas Cassel)
- Release IRQs to avoid leak in pci_endpoint interrupt tests (Kunihiko
Hayashi)
- Log the correct IRQ type when pci_endpoint IRQ request test fails
(Kunihiko Hayashi)
- Remove pci_endpoint_test irq_type and no_msi globals; instead use
test->irq_type (Kunihiko Hayashi)
- Remove unnecessary use of managed IRQ functions in pci_endpoint_test
(Kunihiko Hayashi)
- Add and use IRQ_TYPE_* defines in pci_endpoint_test (Niklas Cassel)
- Add struct pci_epc_features.intx_capable and note that RK3568 and RK3588
can't raise INTx interrupts (Niklas Cassel)
- Expose supported IRQ types in CAPS so pci_endpoint_test can set
appropriate type (Niklas Cassel)
- Add PCITEST_IRQ_TYPE_AUTO to pci_endpoint_test for cases where the IRQ
type doesn't matter (Niklas Cassel)
* pci/endpoint-test:
misc: pci_endpoint_test: Add support for PCITEST_IRQ_TYPE_AUTO
PCI: endpoint: pci-epf-test: Expose supported IRQ types in CAPS register
PCI: dw-rockchip: Endpoint mode cannot raise INTx interrupts
PCI: endpoint: Add intx_capable to epc_features struct
selftests: pci_endpoint: Use IRQ_TYPE_* defines from UAPI header
misc: pci_endpoint_test: Use IRQ_TYPE_* defines from UAPI header
PCI: endpoint: pcitest: Add IRQ_TYPE_* defines to UAPI header
misc: pci_endpoint_test: Do not use managed IRQ functions
misc: pci_endpoint_test: Remove global 'irq_type' and 'no_msi'
misc: pci_endpoint_test: Fix 'irq_type' to convey the correct type
misc: pci_endpoint_test: Fix displaying 'irq_type' after 'request_irq' error
misc: pci_endpoint_test: Avoid issue of interrupts remaining after request_irq error
misc: pci_endpoint_test: Handle BAR sizes larger than INT_MAX
misc: pci_endpoint_test: Give disabled BARs a distinct error code
misc: pci_endpoint_test: Fix potential truncation in pci_endpoint_test_probe()
misc: pci_endpoint_test: Fix pci_endpoint_test_bars_read_bar() error handling
selftests: pci_endpoint: Add GET_IRQTYPE checks to each interrupt test
selftests: pci_endpoint: Skip disabled BARs
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/misc/pci_endpoint_test.c | 130 | ||||
-rw-r--r-- | drivers/pci/controller/dwc/pcie-dw-rockchip.c | 2 | ||||
-rw-r--r-- | drivers/pci/endpoint/functions/pci-epf-test.c | 12 |
3 files changed, 84 insertions, 60 deletions
diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c index d5ac71a49386..1b57850dea9f 100644 --- a/drivers/misc/pci_endpoint_test.c +++ b/drivers/misc/pci_endpoint_test.c @@ -28,11 +28,6 @@ #define DRV_MODULE_NAME "pci-endpoint-test" -#define IRQ_TYPE_UNDEFINED -1 -#define IRQ_TYPE_INTX 0 -#define IRQ_TYPE_MSI 1 -#define IRQ_TYPE_MSIX 2 - #define PCI_ENDPOINT_TEST_MAGIC 0x0 #define PCI_ENDPOINT_TEST_COMMAND 0x4 @@ -71,6 +66,9 @@ #define PCI_ENDPOINT_TEST_CAPS 0x30 #define CAP_UNALIGNED_ACCESS BIT(0) +#define CAP_MSI BIT(1) +#define CAP_MSIX BIT(2) +#define CAP_INTX BIT(3) #define PCI_DEVICE_ID_TI_AM654 0xb00c #define PCI_DEVICE_ID_TI_J7200 0xb00f @@ -96,14 +94,6 @@ static DEFINE_IDA(pci_endpoint_test_ida); #define to_endpoint_test(priv) container_of((priv), struct pci_endpoint_test, \ miscdev) -static bool no_msi; -module_param(no_msi, bool, 0444); -MODULE_PARM_DESC(no_msi, "Disable MSI interrupt in pci_endpoint_test"); - -static int irq_type = IRQ_TYPE_MSI; -module_param(irq_type, int, 0444); -MODULE_PARM_DESC(irq_type, "IRQ mode selection in pci_endpoint_test (0 - Legacy, 1 - MSI, 2 - MSI-X)"); - enum pci_barno { BAR_0, BAR_1, @@ -126,6 +116,7 @@ struct pci_endpoint_test { struct miscdevice miscdev; enum pci_barno test_reg_bar; size_t alignment; + u32 ep_caps; const char *name; }; @@ -166,7 +157,7 @@ static void pci_endpoint_test_free_irq_vectors(struct pci_endpoint_test *test) struct pci_dev *pdev = test->pdev; pci_free_irq_vectors(pdev); - test->irq_type = IRQ_TYPE_UNDEFINED; + test->irq_type = PCITEST_IRQ_TYPE_UNDEFINED; } static int pci_endpoint_test_alloc_irq_vectors(struct pci_endpoint_test *test, @@ -177,7 +168,7 @@ static int pci_endpoint_test_alloc_irq_vectors(struct pci_endpoint_test *test, struct device *dev = &pdev->dev; switch (type) { - case IRQ_TYPE_INTX: + case PCITEST_IRQ_TYPE_INTX: irq = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_INTX); if (irq < 0) { dev_err(dev, "Failed to get Legacy interrupt\n"); @@ -185,7 +176,7 @@ static int pci_endpoint_test_alloc_irq_vectors(struct pci_endpoint_test *test, } break; - case IRQ_TYPE_MSI: + case PCITEST_IRQ_TYPE_MSI: irq = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI); if (irq < 0) { dev_err(dev, "Failed to get MSI interrupts\n"); @@ -193,7 +184,7 @@ static int pci_endpoint_test_alloc_irq_vectors(struct pci_endpoint_test *test, } break; - case IRQ_TYPE_MSIX: + case PCITEST_IRQ_TYPE_MSIX: irq = pci_alloc_irq_vectors(pdev, 1, 2048, PCI_IRQ_MSIX); if (irq < 0) { dev_err(dev, "Failed to get MSI-X interrupts\n"); @@ -216,10 +207,9 @@ static void pci_endpoint_test_release_irq(struct pci_endpoint_test *test) { int i; struct pci_dev *pdev = test->pdev; - struct device *dev = &pdev->dev; for (i = 0; i < test->num_irqs; i++) - devm_free_irq(dev, pci_irq_vector(pdev, i), test); + free_irq(pci_irq_vector(pdev, i), test); test->num_irqs = 0; } @@ -232,9 +222,9 @@ static int pci_endpoint_test_request_irq(struct pci_endpoint_test *test) struct device *dev = &pdev->dev; for (i = 0; i < test->num_irqs; i++) { - ret = devm_request_irq(dev, pci_irq_vector(pdev, i), - pci_endpoint_test_irqhandler, - IRQF_SHARED, test->name, test); + ret = request_irq(pci_irq_vector(pdev, i), + pci_endpoint_test_irqhandler, IRQF_SHARED, + test->name, test); if (ret) goto fail; } @@ -242,23 +232,26 @@ static int pci_endpoint_test_request_irq(struct pci_endpoint_test *test) return 0; fail: - switch (irq_type) { - case IRQ_TYPE_INTX: + switch (test->irq_type) { + case PCITEST_IRQ_TYPE_INTX: dev_err(dev, "Failed to request IRQ %d for Legacy\n", pci_irq_vector(pdev, i)); break; - case IRQ_TYPE_MSI: + case PCITEST_IRQ_TYPE_MSI: dev_err(dev, "Failed to request IRQ %d for MSI %d\n", pci_irq_vector(pdev, i), i + 1); break; - case IRQ_TYPE_MSIX: + case PCITEST_IRQ_TYPE_MSIX: dev_err(dev, "Failed to request IRQ %d for MSI-X %d\n", pci_irq_vector(pdev, i), i + 1); break; } + test->num_irqs = i; + pci_endpoint_test_release_irq(test); + return ret; } @@ -272,9 +265,9 @@ static const u32 bar_test_pattern[] = { }; static int pci_endpoint_test_bar_memcmp(struct pci_endpoint_test *test, - enum pci_barno barno, int offset, - void *write_buf, void *read_buf, - int size) + enum pci_barno barno, + resource_size_t offset, void *write_buf, + void *read_buf, int size) { memset(write_buf, bar_test_pattern[barno], size); memcpy_toio(test->bar[barno] + offset, write_buf, size); @@ -287,16 +280,19 @@ static int pci_endpoint_test_bar_memcmp(struct pci_endpoint_test *test, static int pci_endpoint_test_bar(struct pci_endpoint_test *test, enum pci_barno barno) { - int j, bar_size, buf_size, iters; + resource_size_t bar_size, offset = 0; void *write_buf __free(kfree) = NULL; void *read_buf __free(kfree) = NULL; struct pci_dev *pdev = test->pdev; + int buf_size; + + bar_size = pci_resource_len(pdev, barno); + if (!bar_size) + return -ENODATA; if (!test->bar[barno]) return -ENOMEM; - bar_size = pci_resource_len(pdev, barno); - if (barno == test->test_reg_bar) bar_size = 0x4; @@ -314,11 +310,12 @@ static int pci_endpoint_test_bar(struct pci_endpoint_test *test, if (!read_buf) return -ENOMEM; - iters = bar_size / buf_size; - for (j = 0; j < iters; j++) - if (pci_endpoint_test_bar_memcmp(test, barno, buf_size * j, - write_buf, read_buf, buf_size)) + while (offset < bar_size) { + if (pci_endpoint_test_bar_memcmp(test, barno, offset, write_buf, + read_buf, buf_size)) return -EIO; + offset += buf_size; + } return 0; } @@ -382,7 +379,7 @@ static int pci_endpoint_test_bars_read_bar(struct pci_endpoint_test *test, static int pci_endpoint_test_bars(struct pci_endpoint_test *test) { enum pci_barno bar; - bool ret; + int ret; /* Write all BARs in order (without reading). */ for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) @@ -398,7 +395,7 @@ static int pci_endpoint_test_bars(struct pci_endpoint_test *test) for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) { if (test->bar[bar]) { ret = pci_endpoint_test_bars_read_bar(test, bar); - if (!ret) + if (ret) return ret; } } @@ -411,7 +408,7 @@ static int pci_endpoint_test_intx_irq(struct pci_endpoint_test *test) u32 val; pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, - IRQ_TYPE_INTX); + PCITEST_IRQ_TYPE_INTX); pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 0); pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND, COMMAND_RAISE_INTX_IRQ); @@ -431,7 +428,8 @@ static int pci_endpoint_test_msi_irq(struct pci_endpoint_test *test, int ret; pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, - msix ? IRQ_TYPE_MSIX : IRQ_TYPE_MSI); + msix ? PCITEST_IRQ_TYPE_MSIX : + PCITEST_IRQ_TYPE_MSI); pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, msi_num); pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND, msix ? COMMAND_RAISE_MSIX_IRQ : @@ -507,7 +505,8 @@ static int pci_endpoint_test_copy(struct pci_endpoint_test *test, if (use_dma) flags |= FLAG_USE_DMA; - if (irq_type < IRQ_TYPE_INTX || irq_type > IRQ_TYPE_MSIX) { + if (irq_type < PCITEST_IRQ_TYPE_INTX || + irq_type > PCITEST_IRQ_TYPE_MSIX) { dev_err(dev, "Invalid IRQ type option\n"); return -EINVAL; } @@ -639,7 +638,8 @@ static int pci_endpoint_test_write(struct pci_endpoint_test *test, if (use_dma) flags |= FLAG_USE_DMA; - if (irq_type < IRQ_TYPE_INTX || irq_type > IRQ_TYPE_MSIX) { + if (irq_type < PCITEST_IRQ_TYPE_INTX || + irq_type > PCITEST_IRQ_TYPE_MSIX) { dev_err(dev, "Invalid IRQ type option\n"); return -EINVAL; } @@ -735,7 +735,8 @@ static int pci_endpoint_test_read(struct pci_endpoint_test *test, if (use_dma) flags |= FLAG_USE_DMA; - if (irq_type < IRQ_TYPE_INTX || irq_type > IRQ_TYPE_MSIX) { + if (irq_type < PCITEST_IRQ_TYPE_INTX || + irq_type > PCITEST_IRQ_TYPE_MSIX) { dev_err(dev, "Invalid IRQ type option\n"); return -EINVAL; } @@ -805,11 +806,24 @@ static int pci_endpoint_test_set_irq(struct pci_endpoint_test *test, struct device *dev = &pdev->dev; int ret; - if (req_irq_type < IRQ_TYPE_INTX || req_irq_type > IRQ_TYPE_MSIX) { + if (req_irq_type < PCITEST_IRQ_TYPE_INTX || + req_irq_type > PCITEST_IRQ_TYPE_AUTO) { dev_err(dev, "Invalid IRQ type option\n"); return -EINVAL; } + if (req_irq_type == PCITEST_IRQ_TYPE_AUTO) { + if (test->ep_caps & CAP_MSI) + req_irq_type = PCITEST_IRQ_TYPE_MSI; + else if (test->ep_caps & CAP_MSIX) + req_irq_type = PCITEST_IRQ_TYPE_MSIX; + else if (test->ep_caps & CAP_INTX) + req_irq_type = PCITEST_IRQ_TYPE_INTX; + else + /* fallback to MSI if no caps defined */ + req_irq_type = PCITEST_IRQ_TYPE_MSI; + } + if (test->irq_type == req_irq_type) return 0; @@ -874,7 +888,7 @@ static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd, ret = pci_endpoint_test_set_irq(test, arg); break; case PCITEST_GET_IRQTYPE: - ret = irq_type; + ret = test->irq_type; break; case PCITEST_CLEAR_IRQ: ret = pci_endpoint_test_clear_irq(test); @@ -895,13 +909,12 @@ static void pci_endpoint_test_get_capabilities(struct pci_endpoint_test *test) { struct pci_dev *pdev = test->pdev; struct device *dev = &pdev->dev; - u32 caps; - caps = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_CAPS); - dev_dbg(dev, "PCI_ENDPOINT_TEST_CAPS: %#x\n", caps); + test->ep_caps = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_CAPS); + dev_dbg(dev, "PCI_ENDPOINT_TEST_CAPS: %#x\n", test->ep_caps); /* CAP_UNALIGNED_ACCESS is set if the EP can do unaligned access */ - if (caps & CAP_UNALIGNED_ACCESS) + if (test->ep_caps & CAP_UNALIGNED_ACCESS) test->alignment = 0; } @@ -910,7 +923,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, { int ret; int id; - char name[24]; + char name[29]; enum pci_barno bar; void __iomem *base; struct device *dev = &pdev->dev; @@ -929,17 +942,14 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, test->test_reg_bar = 0; test->alignment = 0; test->pdev = pdev; - test->irq_type = IRQ_TYPE_UNDEFINED; - - if (no_msi) - irq_type = IRQ_TYPE_INTX; + test->irq_type = PCITEST_IRQ_TYPE_UNDEFINED; data = (struct pci_endpoint_test_data *)ent->driver_data; if (data) { test_reg_bar = data->test_reg_bar; test->test_reg_bar = test_reg_bar; test->alignment = data->alignment; - irq_type = data->irq_type; + test->irq_type = data->irq_type; } init_completion(&test->irq_raised); @@ -961,7 +971,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, pci_set_master(pdev); - ret = pci_endpoint_test_alloc_irq_vectors(test, irq_type); + ret = pci_endpoint_test_alloc_irq_vectors(test, test->irq_type); if (ret) goto err_disable_irq; @@ -1083,23 +1093,23 @@ static void pci_endpoint_test_remove(struct pci_dev *pdev) static const struct pci_endpoint_test_data default_data = { .test_reg_bar = BAR_0, .alignment = SZ_4K, - .irq_type = IRQ_TYPE_MSI, + .irq_type = PCITEST_IRQ_TYPE_MSI, }; static const struct pci_endpoint_test_data am654_data = { .test_reg_bar = BAR_2, .alignment = SZ_64K, - .irq_type = IRQ_TYPE_MSI, + .irq_type = PCITEST_IRQ_TYPE_MSI, }; static const struct pci_endpoint_test_data j721e_data = { .alignment = 256, - .irq_type = IRQ_TYPE_MSI, + .irq_type = PCITEST_IRQ_TYPE_MSI, }; static const struct pci_endpoint_test_data rk3588_data = { .alignment = SZ_64K, - .irq_type = IRQ_TYPE_MSI, + .irq_type = PCITEST_IRQ_TYPE_MSI, }; /* diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index df2eaa35d045..3f664d75e33b 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -272,6 +272,7 @@ static const struct pci_epc_features rockchip_pcie_epc_features_rk3568 = { .linkup_notifier = true, .msi_capable = true, .msix_capable = true, + .intx_capable = false, .align = SZ_64K, .bar[BAR_0] = { .type = BAR_RESIZABLE, }, .bar[BAR_1] = { .type = BAR_RESIZABLE, }, @@ -292,6 +293,7 @@ static const struct pci_epc_features rockchip_pcie_epc_features_rk3588 = { .linkup_notifier = true, .msi_capable = true, .msix_capable = true, + .intx_capable = false, .align = SZ_64K, .bar[BAR_0] = { .type = BAR_RESIZABLE, }, .bar[BAR_1] = { .type = BAR_RESIZABLE, }, diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c index bce3ae2c0f65..ac3ec883cc71 100644 --- a/drivers/pci/endpoint/functions/pci-epf-test.c +++ b/drivers/pci/endpoint/functions/pci-epf-test.c @@ -45,6 +45,9 @@ #define TIMER_RESOLUTION 1 #define CAP_UNALIGNED_ACCESS BIT(0) +#define CAP_MSI BIT(1) +#define CAP_MSIX BIT(2) +#define CAP_INTX BIT(3) static struct workqueue_struct *kpcitest_workqueue; @@ -774,6 +777,15 @@ static void pci_epf_test_set_capabilities(struct pci_epf *epf) if (epc->ops->align_addr) caps |= CAP_UNALIGNED_ACCESS; + if (epf_test->epc_features->msi_capable) + caps |= CAP_MSI; + + if (epf_test->epc_features->msix_capable) + caps |= CAP_MSIX; + + if (epf_test->epc_features->intx_capable) + caps |= CAP_INTX; + reg->caps = cpu_to_le32(caps); } |