From 834b9051992580ac8fd3966d023b911ad77d5b8d Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Fri, 18 Aug 2017 20:28:05 +0530 Subject: misc: pci_endpoint_test: Add support for PCI_ENDPOINT_TEST regs to be mapped to any BAR pci_endpoint_test driver assumes the PCI_ENDPOINT_TEST registers will always be mapped to BAR_0. This need not always be the case like in TI's K2G where BAR_0 is mapped to PCI controller application registers. Add support so that PCI_ENDPOINT_TEST registers can be mapped to any BAR. Change the bar_size used for BAR test accordingly. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Bjorn Helgaas --- drivers/misc/pci_endpoint_test.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c index 09c10f426b64..5fc0f6c6a9e5 100644 --- a/drivers/misc/pci_endpoint_test.c +++ b/drivers/misc/pci_endpoint_test.c @@ -90,9 +90,14 @@ struct pci_endpoint_test { /* mutex to protect the ioctls */ struct mutex mutex; struct miscdevice miscdev; + enum pci_barno test_reg_bar; }; -static int bar_size[] = { 4, 512, 1024, 16384, 131072, 1048576 }; +struct pci_endpoint_test_data { + enum pci_barno test_reg_bar; +}; + +static int bar_size[] = { 512, 512, 1024, 16384, 131072, 1048576 }; static inline u32 pci_endpoint_test_readl(struct pci_endpoint_test *test, u32 offset) @@ -147,6 +152,9 @@ static bool pci_endpoint_test_bar(struct pci_endpoint_test *test, size = bar_size[barno]; + if (barno == test->test_reg_bar) + size = 0x4; + for (j = 0; j < size; j += 4) pci_endpoint_test_bar_writel(test, barno, j, 0xA0A0A0A0); @@ -390,6 +398,8 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, void __iomem *base; struct device *dev = &pdev->dev; struct pci_endpoint_test *test; + struct pci_endpoint_test_data *data; + enum pci_barno test_reg_bar = BAR_0; struct miscdevice *misc_device; if (pci_is_bridge(pdev)) @@ -399,7 +409,13 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, if (!test) return -ENOMEM; + test->test_reg_bar = 0; test->pdev = pdev; + + data = (struct pci_endpoint_test_data *)ent->driver_data; + if (data) + test_reg_bar = data->test_reg_bar; + init_completion(&test->irq_raised); mutex_init(&test->mutex); @@ -441,14 +457,15 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, base = pci_ioremap_bar(pdev, bar); if (!base) { dev_err(dev, "failed to read BAR%d\n", bar); - WARN_ON(bar == BAR_0); + WARN_ON(bar == test_reg_bar); } test->bar[bar] = base; } - test->base = test->bar[0]; + test->base = test->bar[test_reg_bar]; if (!test->base) { - dev_err(dev, "Cannot perform PCI test without BAR0\n"); + dev_err(dev, "Cannot perform PCI test without BAR%d\n", + test_reg_bar); goto err_iounmap; } -- cgit v1.2.3 From 13107c60681f19fec25af93de86442ac9373e43f Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Fri, 18 Aug 2017 20:28:06 +0530 Subject: misc: pci_endpoint_test: Add support to provide aligned buffer addresses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some platforms like TI's K2G have a restriction that the host side buffer address should be aligned to either 1MB/2MB/4MB or 8MB (Ref: 11.14.4.9.1 Outbound Address Translation in K2G TRM SPRUHY8F January 2016 – Revised May 2017) addresses depending on how it is configured in the endpoint. Add support to provide such aligned address here so that pci_endpoint_test driver can be used to test K2G EP. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Bjorn Helgaas --- drivers/misc/pci_endpoint_test.c | 91 +++++++++++++++++++++++++++++++++------- 1 file changed, 76 insertions(+), 15 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c index 5fc0f6c6a9e5..5f6bd23ab657 100644 --- a/drivers/misc/pci_endpoint_test.c +++ b/drivers/misc/pci_endpoint_test.c @@ -91,10 +91,12 @@ struct pci_endpoint_test { struct mutex mutex; struct miscdevice miscdev; enum pci_barno test_reg_bar; + size_t alignment; }; struct pci_endpoint_test_data { enum pci_barno test_reg_bar; + size_t alignment; }; static int bar_size[] = { 512, 512, 1024, 16384, 131072, 1048576 }; @@ -210,16 +212,32 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size) dma_addr_t dst_phys_addr; struct pci_dev *pdev = test->pdev; struct device *dev = &pdev->dev; + void *orig_src_addr; + dma_addr_t orig_src_phys_addr; + void *orig_dst_addr; + dma_addr_t orig_dst_phys_addr; + size_t offset; + size_t alignment = test->alignment; u32 src_crc32; u32 dst_crc32; - src_addr = dma_alloc_coherent(dev, size, &src_phys_addr, GFP_KERNEL); - if (!src_addr) { + orig_src_addr = dma_alloc_coherent(dev, size + alignment, + &orig_src_phys_addr, GFP_KERNEL); + if (!orig_src_addr) { dev_err(dev, "failed to allocate source buffer\n"); ret = false; goto err; } + if (alignment && !IS_ALIGNED(orig_src_phys_addr, alignment)) { + src_phys_addr = PTR_ALIGN(orig_src_phys_addr, alignment); + offset = src_phys_addr - orig_src_phys_addr; + src_addr = orig_src_addr + offset; + } else { + src_phys_addr = orig_src_phys_addr; + src_addr = orig_src_addr; + } + pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_SRC_ADDR, lower_32_bits(src_phys_addr)); @@ -229,11 +247,21 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size) get_random_bytes(src_addr, size); src_crc32 = crc32_le(~0, src_addr, size); - dst_addr = dma_alloc_coherent(dev, size, &dst_phys_addr, GFP_KERNEL); - if (!dst_addr) { + orig_dst_addr = dma_alloc_coherent(dev, size + alignment, + &orig_dst_phys_addr, GFP_KERNEL); + if (!orig_dst_addr) { dev_err(dev, "failed to allocate destination address\n"); ret = false; - goto err_src_addr; + goto err_orig_src_addr; + } + + if (alignment && !IS_ALIGNED(orig_dst_phys_addr, alignment)) { + dst_phys_addr = PTR_ALIGN(orig_dst_phys_addr, alignment); + offset = dst_phys_addr - orig_dst_phys_addr; + dst_addr = orig_dst_addr + offset; + } else { + dst_phys_addr = orig_dst_phys_addr; + dst_addr = orig_dst_addr; } pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_DST_ADDR, @@ -253,10 +281,12 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size) if (dst_crc32 == src_crc32) ret = true; - dma_free_coherent(dev, size, dst_addr, dst_phys_addr); + dma_free_coherent(dev, size + alignment, orig_dst_addr, + orig_dst_phys_addr); -err_src_addr: - dma_free_coherent(dev, size, src_addr, src_phys_addr); +err_orig_src_addr: + dma_free_coherent(dev, size + alignment, orig_src_addr, + orig_src_phys_addr); err: return ret; @@ -270,15 +300,29 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size) dma_addr_t phys_addr; struct pci_dev *pdev = test->pdev; struct device *dev = &pdev->dev; + void *orig_addr; + dma_addr_t orig_phys_addr; + size_t offset; + size_t alignment = test->alignment; u32 crc32; - addr = dma_alloc_coherent(dev, size, &phys_addr, GFP_KERNEL); - if (!addr) { + orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr, + GFP_KERNEL); + if (!orig_addr) { dev_err(dev, "failed to allocate address\n"); ret = false; goto err; } + if (alignment && !IS_ALIGNED(orig_phys_addr, alignment)) { + phys_addr = PTR_ALIGN(orig_phys_addr, alignment); + offset = phys_addr - orig_phys_addr; + addr = orig_addr + offset; + } else { + phys_addr = orig_phys_addr; + addr = orig_addr; + } + get_random_bytes(addr, size); crc32 = crc32_le(~0, addr, size); @@ -301,7 +345,7 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size) if (reg & STATUS_READ_SUCCESS) ret = true; - dma_free_coherent(dev, size, addr, phys_addr); + dma_free_coherent(dev, size + alignment, orig_addr, orig_phys_addr); err: return ret; @@ -314,15 +358,29 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size) dma_addr_t phys_addr; struct pci_dev *pdev = test->pdev; struct device *dev = &pdev->dev; + void *orig_addr; + dma_addr_t orig_phys_addr; + size_t offset; + size_t alignment = test->alignment; u32 crc32; - addr = dma_alloc_coherent(dev, size, &phys_addr, GFP_KERNEL); - if (!addr) { + orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr, + GFP_KERNEL); + if (!orig_addr) { dev_err(dev, "failed to allocate destination address\n"); ret = false; goto err; } + if (alignment && !IS_ALIGNED(orig_phys_addr, alignment)) { + phys_addr = PTR_ALIGN(orig_phys_addr, alignment); + offset = phys_addr - orig_phys_addr; + addr = orig_addr + offset; + } else { + phys_addr = orig_phys_addr; + addr = orig_addr; + } + pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_DST_ADDR, lower_32_bits(phys_addr)); pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_UPPER_DST_ADDR, @@ -339,7 +397,7 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size) if (crc32 == pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_CHECKSUM)) ret = true; - dma_free_coherent(dev, size, addr, phys_addr); + dma_free_coherent(dev, size + alignment, orig_addr, orig_phys_addr); err: return ret; } @@ -410,11 +468,14 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, return -ENOMEM; test->test_reg_bar = 0; + test->alignment = 0; test->pdev = pdev; data = (struct pci_endpoint_test_data *)ent->driver_data; - if (data) + if (data) { test_reg_bar = data->test_reg_bar; + test->alignment = data->alignment; + } init_completion(&test->irq_raised); mutex_init(&test->mutex); -- cgit v1.2.3 From 0b91516adc581636770ea4fb3efc022de057d074 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Fri, 18 Aug 2017 20:28:07 +0530 Subject: misc: pci_endpoint_test: Add support to not enable MSI interrupts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some platforms like TI's K2G have a restriction that the host side buffer address should be aligned to either 1MB/2MB/4MB or 8MB addresses depending on how it is configured in the endpoint (Ref: 11.14.4.9.1 Outbound Address Translation in K2G TRM SPRUHY8F January 2016 – Revised May 2017). This restriction also applies to the MSI addresses provided by the RC. However it's not possible for the RC to know about this restriction and it may not provide 1MB/2MB/4MB or 8MB aligned address. So MSI interrupts should be disabled even if the K2G EP has MSI capabiltiy register. Add support to not enable MSI interrupts in pci_endpoint_test driver so that it can be used to test K2G EP. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Bjorn Helgaas --- drivers/misc/pci_endpoint_test.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c index 5f6bd23ab657..5cbb25cf276c 100644 --- a/drivers/misc/pci_endpoint_test.c +++ b/drivers/misc/pci_endpoint_test.c @@ -97,6 +97,7 @@ struct pci_endpoint_test { struct pci_endpoint_test_data { enum pci_barno test_reg_bar; size_t alignment; + bool no_msi; }; static int bar_size[] = { 512, 512, 1024, 16384, 131072, 1048576 }; @@ -449,8 +450,9 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, { int i; int err; - int irq; + int irq = 0; int id; + bool no_msi = false; char name[20]; enum pci_barno bar; void __iomem *base; @@ -475,6 +477,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, if (data) { test_reg_bar = data->test_reg_bar; test->alignment = data->alignment; + no_msi = data->no_msi; } init_completion(&test->irq_raised); @@ -494,9 +497,11 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, pci_set_master(pdev); - irq = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI); - if (irq < 0) - dev_err(dev, "failed to get MSI interrupts\n"); + if (!no_msi) { + irq = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI); + if (irq < 0) + dev_err(dev, "failed to get MSI interrupts\n"); + } err = devm_request_irq(dev, pdev->irq, pci_endpoint_test_irqhandler, IRQF_SHARED, DRV_MODULE_NAME, test); -- cgit v1.2.3 From cda370ec6d1f7b2567ef6f692d0df9358746ad5a Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Fri, 18 Aug 2017 20:28:08 +0530 Subject: misc: pci_endpoint_test: Avoid using hard-coded BAR sizes BAR sizes are hard-coded in pci_endpoint_test driver corresponding to the sizes used in pci-epf-test function driver. This might break if the sizes in pci-epf-test function driver are modified (and the corresponding change is not done in pci_endpoint_test PCI driver). To avoid hard coding BAR sizes, use pci_resource_len() API. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Bjorn Helgaas --- drivers/misc/pci_endpoint_test.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c index 5cbb25cf276c..1f37ad39b169 100644 --- a/drivers/misc/pci_endpoint_test.c +++ b/drivers/misc/pci_endpoint_test.c @@ -100,8 +100,6 @@ struct pci_endpoint_test_data { bool no_msi; }; -static int bar_size[] = { 512, 512, 1024, 16384, 131072, 1048576 }; - static inline u32 pci_endpoint_test_readl(struct pci_endpoint_test *test, u32 offset) { @@ -149,11 +147,12 @@ static bool pci_endpoint_test_bar(struct pci_endpoint_test *test, int j; u32 val; int size; + struct pci_dev *pdev = test->pdev; if (!test->bar[barno]) return false; - size = bar_size[barno]; + size = pci_resource_len(pdev, barno); if (barno == test->test_reg_bar) size = 0x4; -- cgit v1.2.3 From 0c8a5f9d89b988ecb612a53d9439db899866bf8b Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Fri, 18 Aug 2017 20:28:09 +0530 Subject: misc: pci_endpoint_test: Enable/Disable MSI using module param In certain platforms like TI's DRA7 SoCs, use of legacy PCI interrupt is exclusive with use of MSI (Section 24.9.4.6.2.1 Legacy PCI Interrupts in http://www.ti.com/lit/ug/spruhz6i/spruhz6i.pdf). However pci_endpoint_test driver enables MSI by default in probe. In order for pci_endpoint_test to be able to test legacy interrupt, MSI should be disabled. Add a module param 'no_msi' to disable MSI (only when legacy interrupt has to be tested). Signed-off-by: Kishon Vijay Abraham I [bhelgaas: folded in static fix from Colin Ian King ] Signed-off-by: Bjorn Helgaas --- drivers/misc/pci_endpoint_test.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c index 1f37ad39b169..deb203026496 100644 --- a/drivers/misc/pci_endpoint_test.c +++ b/drivers/misc/pci_endpoint_test.c @@ -72,6 +72,11 @@ 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"); + enum pci_barno { BAR_0, BAR_1, @@ -451,7 +456,6 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, int err; int irq = 0; int id; - bool no_msi = false; char name[20]; enum pci_barno bar; void __iomem *base; -- cgit v1.2.3