From 7f6db1717235bd45d265766dad53c10d30899d41 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Thu, 15 Aug 2013 11:59:23 -0600 Subject: iommu: Add event tracing feature to iommu Add tracing feature to iommu to report various iommu events. Classes iommu_group, iommu_device, and iommu_map_unmap are defined. iommu_group class events can be enabled to trigger when devices get added to and removed from an iommu group. Trace information includes iommu group id and device name. iommu:add_device_to_group iommu:remove_device_from_group iommu_device class events can be enabled to trigger when devices are attached to and detached from a domain. Trace information includes device name. iommu:attach_device_to_domain iommu:detach_device_from_domain iommu_map_unmap class events can be enabled to trigger when iommu map and unmap iommu ops. Trace information includes iova, physical address (map event only), and size. iommu:map iommu:unmap Signed-off-by: Shuah Khan Signed-off-by: Joerg Roedel --- drivers/iommu/Makefile | 1 + drivers/iommu/iommu-traces.c | 24 ++++++++++++++++++++++++ drivers/iommu/iommu.c | 1 + 3 files changed, 26 insertions(+) create mode 100644 drivers/iommu/iommu-traces.c (limited to 'drivers/iommu') diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile index 14c1f474cf11..5d58bf16e9e3 100644 --- a/drivers/iommu/Makefile +++ b/drivers/iommu/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_IOMMU_API) += iommu.o +obj-$(CONFIG_IOMMU_API) += iommu-traces.o obj-$(CONFIG_OF_IOMMU) += of_iommu.o obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o msm_iommu_dev.o obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o diff --git a/drivers/iommu/iommu-traces.c b/drivers/iommu/iommu-traces.c new file mode 100644 index 000000000000..a2af60f31810 --- /dev/null +++ b/drivers/iommu/iommu-traces.c @@ -0,0 +1,24 @@ +/* + * iommu trace points + * + * Copyright (C) 2013 Shuah Khan + * + */ + +#include +#include + +#define CREATE_TRACE_POINTS +#include + +/* iommu_group_event */ +EXPORT_TRACEPOINT_SYMBOL_GPL(add_device_to_group); +EXPORT_TRACEPOINT_SYMBOL_GPL(remove_device_from_group); + +/* iommu_device_event */ +EXPORT_TRACEPOINT_SYMBOL_GPL(attach_device_to_domain); +EXPORT_TRACEPOINT_SYMBOL_GPL(detach_device_from_domain); + +/* iommu_map_unmap */ +EXPORT_TRACEPOINT_SYMBOL_GPL(map); +EXPORT_TRACEPOINT_SYMBOL_GPL(unmap); diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index fbe9ca734f8f..58f6a16b2e1a 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -29,6 +29,7 @@ #include #include #include +#include static struct kset *iommu_group_kset; static struct ida iommu_group_ida; -- cgit v1.2.3 From d1cf7e822746b5e755f5a893ffeced1f6311c0cf Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Thu, 15 Aug 2013 11:59:24 -0600 Subject: iommu: Change iommu driver to call add_device_to_group trace event Change iommu driver to call add_device_to_group trace event. This iommu_group class event can be enabled to trigger when devices get added to an iommu group. Trace information includes iommu group id and device name. Testing: The following is trace is generated when intel-iommu driver adds devices to to iommu groups during boot-time during its initialization: swapper/0-1 [003] .... 1.854793: add_device_to_group: IOMMU: groupID=0 device=0000:00:00.0 swapper/0-1 [003] .... 1.854797: add_device_to_group: IOMMU: groupID=1 device=0000:00:02.0 Signed-off-by: Shuah Khan Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/iommu') diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 58f6a16b2e1a..349c92dfce05 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -364,6 +364,8 @@ rename: /* Notify any listeners about change to group. */ blocking_notifier_call_chain(&group->notifier, IOMMU_GROUP_NOTIFY_ADD_DEVICE, dev); + + trace_add_device_to_group(group->id, dev); return 0; } EXPORT_SYMBOL_GPL(iommu_group_add_device); -- cgit v1.2.3 From 2e757086bdfdc9450dc2e4a5d2ec5431520a02c8 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Thu, 15 Aug 2013 11:59:25 -0600 Subject: iommu: Change iommu driver to call remove_device_to_group trace event Change iommu driver to call remove_device_to_group trace event. This iommu_group class event can be enabled to trigger when devices get removed from an iommu group. Trace information includes iommu group id and device name. Testing: Added trace calls to iommu_prepare_identity_map() for testing some of the conditions that are hard to trigger. Here is the trace from the testing: swapper/0-1 [003] .... 1.854101: remove_device_from_group: IOMMU: groupID=0 device=0000:00:02.0 Signed-off-by: Shuah Khan Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/iommu') diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 349c92dfce05..278055bd0715 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -402,6 +402,8 @@ void iommu_group_remove_device(struct device *dev) sysfs_remove_link(group->devices_kobj, device->name); sysfs_remove_link(&dev->kobj, "iommu_group"); + trace_remove_device_from_group(group->id, dev); + kfree(device->name); kfree(device); dev->iommu_group = NULL; -- cgit v1.2.3 From b54db778858bc83f9231e5b358cb978f559f7016 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Thu, 15 Aug 2013 11:59:26 -0600 Subject: iommu: Change iommu driver to call attach_device_to_domain trace event Change iommu driver to call attach_device_to_domain trace event. This iommu_device class event can be enabled to trigger when devices are attached to a domain. Trace information includes device name. Testing: Added trace calls to iommu_prepare_identity_map() for testing some of the conditions that are hard to trigger. Here is the trace from the testing: swapper/0-1 [003] .... 1.854102: attach_device_to_domain: IOMMU: device=0000:00:02.0 Signed-off-by: Shuah Khan Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/iommu') diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 278055bd0715..74c371c53ee4 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -685,10 +685,14 @@ EXPORT_SYMBOL_GPL(iommu_domain_free); int iommu_attach_device(struct iommu_domain *domain, struct device *dev) { + int ret; if (unlikely(domain->ops->attach_dev == NULL)) return -ENODEV; - return domain->ops->attach_dev(domain, dev); + ret = domain->ops->attach_dev(domain, dev); + if (!ret) + trace_attach_device_to_domain(dev); + return ret; } EXPORT_SYMBOL_GPL(iommu_attach_device); -- cgit v1.2.3 From 699806302d8ac7dfb7d46e20da0ecd4317418d1d Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Thu, 15 Aug 2013 11:59:27 -0600 Subject: iommu: Change iommu driver to call detach_device_to_domain trace event Change iommu driver to call detach_device_to_domain trace event. This iommu_device class event can be enabled to trigger when devices are detached from a domain. Trace information includes device name. Testing: Added trace calls to iommu_prepare_identity_map() for testing some of the conditions that are hard to trigger. Here is the trace from the testing: swapper/0-1 [003] .... 1.854102: detach_device_from_domain: IOMMU: device=0000:00:02.0 Signed-off-by: Shuah Khan Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/iommu') diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 74c371c53ee4..b6307545124c 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -702,6 +702,7 @@ void iommu_detach_device(struct iommu_domain *domain, struct device *dev) return; domain->ops->detach_dev(domain, dev); + trace_detach_device_from_domain(dev); } EXPORT_SYMBOL_GPL(iommu_detach_device); -- cgit v1.2.3 From e0be7c867882320b65714a4386760382196dc7e8 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Thu, 15 Aug 2013 11:59:28 -0600 Subject: iommu: Change iommu driver to call map trace event Change iommu driver to call map trace event. This iommu_map_unmap class event can be enabled to trigger when iommu map iommu ops is called. Trace information includes iova, physical address (map event only), and size. Testing: Added trace calls to iommu_prepare_identity_map() for testing some of the conditions that are hard to trigger. Here is the trace from the testing: swapper/0-1 [003] .... 1.854102: map: IOMMU: iova=0x00000000cb800000 paddr=0x00000000cf9fffff size=0x400 Signed-off-by: Shuah Khan Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/iommu') diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index b6307545124c..ea49fe814026 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -842,6 +842,8 @@ int iommu_map(struct iommu_domain *domain, unsigned long iova, /* unroll mapping in case something went wrong */ if (ret) iommu_unmap(domain, orig_iova, orig_size - size); + else + trace_map(iova, paddr, size); return ret; } -- cgit v1.2.3 From 3a50639ca4684476a69314811d89622d78c09448 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Thu, 15 Aug 2013 11:59:29 -0600 Subject: iommu: Change iommu driver to call unmap trace event Change iommu driver to call unmap trace event. This iommu_map_unmap class event can be enabled to trigger when iommu unmap iommu ops is called. Trace information includes iova, physical address (map event only), and size. Testing: Added trace calls to iommu_prepare_identity_map() for testing some of the conditions that are hard to trigger. Here is the trace from the testing: swapper/0-1 [003] .... 1.854102: unmap: IOMMU: iova=0x00000000cb800000 size=0x400 Signed-off-by: Shuah Khan Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/iommu') diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index ea49fe814026..d8c53c7a7ec1 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -892,6 +892,7 @@ size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) unmapped += unmapped_page; } + trace_unmap(iova, 0, size); return unmapped; } EXPORT_SYMBOL_GPL(iommu_unmap); -- cgit v1.2.3 From abedb049c52ef77ce7b11b915a4e7e6abd3985cb Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 22 Aug 2013 10:25:42 -0300 Subject: iommu: No need to pass '0x' when '%pa' is used Commit 6197ca82 (iommu: Use %pa and %zx instead of casting) introduced the usage of '%pa', but still kept the '0x', which leads to printing '0x0x'. Remove the '0x' when '%pa' is used. Signed-off-by: Fabio Estevam Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/iommu') diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index fbe9ca734f8f..06d36a0b1001 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -807,17 +807,17 @@ int iommu_map(struct iommu_domain *domain, unsigned long iova, * size of the smallest page supported by the hardware */ if (!IS_ALIGNED(iova | paddr | size, min_pagesz)) { - pr_err("unaligned: iova 0x%lx pa 0x%pa size 0x%zx min_pagesz 0x%x\n", + pr_err("unaligned: iova 0x%lx pa %pa size 0x%zx min_pagesz 0x%x\n", iova, &paddr, size, min_pagesz); return -EINVAL; } - pr_debug("map: iova 0x%lx pa 0x%pa size 0x%zx\n", iova, &paddr, size); + pr_debug("map: iova 0x%lx pa %pa size 0x%zx\n", iova, &paddr, size); while (size) { size_t pgsize = iommu_pgsize(domain, iova | paddr, size); - pr_debug("mapping: iova 0x%lx pa 0x%pa pgsize 0x%zx\n", + pr_debug("mapping: iova 0x%lx pa %pa pgsize 0x%zx\n", iova, &paddr, pgsize); ret = domain->ops->map(domain, iova, paddr, pgsize, prot); -- cgit v1.2.3 From e56b3dab34d41804b57b900f5b7e7837ece0367b Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 17 Sep 2013 10:19:31 +0200 Subject: iommu/tegra: Print phys_addr_t using %pa When enabling LPAE on ARM, phys_addr_t becomes 64 bits wide and printing a variable of that type using a simple %x format specifier causes the compiler to complain. Change the format specifier to %pa, which is used specifically for variables of type phys_addr_t. Signed-off-by: Thierry Reding Acked-by: Olof Johansson Signed-off-by: Joerg Roedel --- drivers/iommu/tegra-gart.c | 6 +++--- drivers/iommu/tegra-smmu.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/iommu') diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c index 108c0e9c24d9..8993999fd2f4 100644 --- a/drivers/iommu/tegra-gart.c +++ b/drivers/iommu/tegra-gart.c @@ -252,7 +252,7 @@ static int gart_iommu_map(struct iommu_domain *domain, unsigned long iova, spin_lock_irqsave(&gart->pte_lock, flags); pfn = __phys_to_pfn(pa); if (!pfn_valid(pfn)) { - dev_err(gart->dev, "Invalid page: %08x\n", pa); + dev_err(gart->dev, "Invalid page: %pa\n", &pa); spin_unlock_irqrestore(&gart->pte_lock, flags); return -EINVAL; } @@ -295,8 +295,8 @@ static phys_addr_t gart_iommu_iova_to_phys(struct iommu_domain *domain, pa = (pte & GART_PAGE_MASK); if (!pfn_valid(__phys_to_pfn(pa))) { - dev_err(gart->dev, "No entry for %08llx:%08x\n", - (unsigned long long)iova, pa); + dev_err(gart->dev, "No entry for %08llx:%pa\n", + (unsigned long long)iova, &pa); gart_dump_table(gart); return -EINVAL; } diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index e0665603afd9..34374b3bc13b 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -731,7 +731,7 @@ static int smmu_iommu_map(struct iommu_domain *domain, unsigned long iova, unsigned long pfn = __phys_to_pfn(pa); unsigned long flags; - dev_dbg(as->smmu->dev, "[%d] %08lx:%08x\n", as->asid, iova, pa); + dev_dbg(as->smmu->dev, "[%d] %08lx:%pa\n", as->asid, iova, &pa); if (!pfn_valid(pfn)) return -ENOMEM; -- cgit v1.2.3 From d0c5b2579509b86c1b4a4fa7508428aa44bddd3b Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 24 Sep 2013 11:40:24 +0800 Subject: iommu/tegra: gart: cleanup devm_* functions usage The devm_[kzalloc|ioremap] functions allocates data that are released when a driver detaches. Thus, there is no reason to explicitly call devm_[kfree|iounmap] in probe or remove functions. Signed-off-by: Wei Yongjun Acked-by: Hiroshi Doyu Signed-off-by: Joerg Roedel --- drivers/iommu/tegra-gart.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) (limited to 'drivers/iommu') diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c index 8993999fd2f4..f75483a3a2ef 100644 --- a/drivers/iommu/tegra-gart.c +++ b/drivers/iommu/tegra-gart.c @@ -351,7 +351,6 @@ static int tegra_gart_probe(struct platform_device *pdev) struct gart_device *gart; struct resource *res, *res_remap; void __iomem *gart_regs; - int err; struct device *dev = &pdev->dev; if (gart_handle) @@ -376,8 +375,7 @@ static int tegra_gart_probe(struct platform_device *pdev) gart_regs = devm_ioremap(dev, res->start, resource_size(res)); if (!gart_regs) { dev_err(dev, "failed to remap GART registers\n"); - err = -ENXIO; - goto fail; + return -ENXIO; } gart->dev = &pdev->dev; @@ -391,8 +389,7 @@ static int tegra_gart_probe(struct platform_device *pdev) gart->savedata = vmalloc(sizeof(u32) * gart->page_count); if (!gart->savedata) { dev_err(dev, "failed to allocate context save area\n"); - err = -ENOMEM; - goto fail; + return -ENOMEM; } platform_set_drvdata(pdev, gart); @@ -401,27 +398,15 @@ static int tegra_gart_probe(struct platform_device *pdev) gart_handle = gart; bus_set_iommu(&platform_bus_type, &gart_iommu_ops); return 0; - -fail: - if (gart_regs) - devm_iounmap(dev, gart_regs); - if (gart && gart->savedata) - vfree(gart->savedata); - devm_kfree(dev, gart); - return err; } static int tegra_gart_remove(struct platform_device *pdev) { struct gart_device *gart = platform_get_drvdata(pdev); - struct device *dev = gart->dev; writel(0, gart->regs + GART_CONFIG); if (gart->savedata) vfree(gart->savedata); - if (gart->regs) - devm_iounmap(dev, gart->regs); - devm_kfree(dev, gart); gart_handle = NULL; return 0; } -- cgit v1.2.3 From 04fa2f7f837601903e5fe0f93bc2af8559d8c035 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Tue, 24 Sep 2013 15:21:19 -0600 Subject: iommu: Add iommu_error class event to iommu trace iommu_error class event can be enabled to trigger when an iommu error occurs. This trace event is intended to be called to report the error information. Trace information includes driver name, device name, iova, and flags. iommu_error:io_page_fault Signed-off-by: Shuah Khan Signed-off-by: Joerg Roedel --- drivers/iommu/iommu-traces.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/iommu') diff --git a/drivers/iommu/iommu-traces.c b/drivers/iommu/iommu-traces.c index a2af60f31810..bf3b317ff0c1 100644 --- a/drivers/iommu/iommu-traces.c +++ b/drivers/iommu/iommu-traces.c @@ -22,3 +22,6 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(detach_device_from_domain); /* iommu_map_unmap */ EXPORT_TRACEPOINT_SYMBOL_GPL(map); EXPORT_TRACEPOINT_SYMBOL_GPL(unmap); + +/* iommu_error */ +EXPORT_TRACEPOINT_SYMBOL_GPL(io_page_fault); -- cgit v1.2.3 From 05104a4e8713b27291c7bb49c1e7e68b4e243571 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Fri, 27 Sep 2013 12:53:35 -0400 Subject: iommu: Remove stack trace from broken irq remapping warning The warning for the irq remapping broken check in intel_irq_remapping.c is pretty pointless. We need the warning, but we know where its comming from, the stack trace will always be the same, and it needlessly triggers things like Abrt. This changes the warning to just print a text warning about BIOS being broken, without the stack trace, then sets the appropriate taint bit. Since we automatically disable irq remapping, theres no need to contiue making Abrt jump at this problem Signed-off-by: Neil Horman CC: Joerg Roedel CC: Bjorn Helgaas CC: Andy Lutomirski CC: Konrad Rzeszutek Wilk CC: Sebastian Andrzej Siewior Signed-off-by: Joerg Roedel --- drivers/iommu/intel_irq_remapping.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/iommu') diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c index f71673dbb23d..b97d70b1abe0 100644 --- a/drivers/iommu/intel_irq_remapping.c +++ b/drivers/iommu/intel_irq_remapping.c @@ -525,12 +525,13 @@ static int __init intel_irq_remapping_supported(void) if (disable_irq_remap) return 0; if (irq_remap_broken) { - WARN_TAINT(1, TAINT_FIRMWARE_WORKAROUND, - "This system BIOS has enabled interrupt remapping\n" - "on a chipset that contains an erratum making that\n" - "feature unstable. To maintain system stability\n" - "interrupt remapping is being disabled. Please\n" - "contact your BIOS vendor for an update\n"); + printk(KERN_WARNING + "This system BIOS has enabled interrupt remapping\n" + "on a chipset that contains an erratum making that\n" + "feature unstable. To maintain system stability\n" + "interrupt remapping is being disabled. Please\n" + "contact your BIOS vendor for an update\n"); + add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK); disable_irq_remap = 1; return 0; } -- cgit v1.2.3 From 8a7f431221602fcde573dfdba26de1990ec195a0 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 19 Aug 2013 12:20:37 +0100 Subject: iommu/arm-smmu: replace devm_request_and_ioremap by devm_ioremap_resource Use devm_ioremap_resource instead of devm_request_and_ioremap. This was partly done using the semantic patch scripts/coccinelle/api/devm_ioremap_resource.cocci The error-handling code on the call to platform_get_resource was removed manually, and the initialization of smmu->size was manually moved lower, to take advantage of the NULL test on res performed by devm_ioremap_resource. Signed-off-by: Julia Lawall Signed-off-by: Will Deacon --- drivers/iommu/arm-smmu.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers/iommu') diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 181c9ba929cd..abe83c3757ab 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1781,15 +1781,10 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) smmu->dev = dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "missing base address/size\n"); - return -ENODEV; - } - + smmu->base = devm_ioremap_resource(dev, res); + if (IS_ERR(smmu->base)) + return PTR_ERR(smmu->base); smmu->size = resource_size(res); - smmu->base = devm_request_and_ioremap(dev, res); - if (!smmu->base) - return -EADDRNOTAVAIL; if (of_property_read_u32(dev->of_node, "#global-interrupts", &smmu->num_global_irqs)) { -- cgit v1.2.3 From 25724841dfaed05f23a3ddaaaed5c9b61ceea7bd Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Wed, 21 Aug 2013 13:49:53 +0100 Subject: iommu/arm-smmu: use relaxed accessors where possible Apart from fault handling and page table manipulation, we don't care about memory ordering between SMMU control registers and normal, cacheable memory, so use the _relaxed I/O accessors wherever possible. Signed-off-by: Will Deacon --- drivers/iommu/arm-smmu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/iommu') diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index abe83c3757ab..293192150f5a 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -778,7 +778,7 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain) #ifdef __BIG_ENDIAN reg |= SCTLR_E; #endif - writel(reg, cb_base + ARM_SMMU_CB_SCTLR); + writel_relaxed(reg, cb_base + ARM_SMMU_CB_SCTLR); } static int arm_smmu_init_domain_context(struct iommu_domain *domain, @@ -1595,7 +1595,7 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu) /* Push the button */ arm_smmu_tlb_sync(smmu); - writel(scr0, gr0_base + ARM_SMMU_GR0_sCR0); + writel_relaxed(scr0, gr0_base + ARM_SMMU_GR0_sCR0); } static int arm_smmu_id_size_to_bits(int size) @@ -1928,7 +1928,7 @@ static int arm_smmu_device_remove(struct platform_device *pdev) free_irq(smmu->irqs[i], smmu); /* Turn the thing off */ - writel(sCR0_CLIENTPD, ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_sCR0); + writel_relaxed(sCR0_CLIENTPD, ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_sCR0); return 0; } -- cgit v1.2.3 From b1950b2796da80b66df02db39cc3417266b73767 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Tue, 1 Oct 2013 13:39:05 +0100 Subject: iommu/arm-smmu: Switch to subsys_initcall for driver registration This should ensure that arm-smmu is initialized before other drivers start handling devices that propably need smmu support. Signed-off-by: Andreas Herrmann Signed-off-by: Will Deacon --- drivers/iommu/arm-smmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/iommu') diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 293192150f5a..878a5b926fe5 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1976,7 +1976,7 @@ static void __exit arm_smmu_exit(void) return platform_driver_unregister(&arm_smmu_driver); } -module_init(arm_smmu_init); +subsys_initcall(arm_smmu_init); module_exit(arm_smmu_exit); MODULE_DESCRIPTION("IOMMU API for ARM architected SMMU implementations"); -- cgit v1.2.3 From c55af7f719cbb0f0b28f42b3f98f662278f063c2 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Tue, 1 Oct 2013 13:39:06 +0100 Subject: iommu/arm-smmu: Refine check for proper size of mapped region There is already a check to print a warning if the size of SMMU address space (calculated from SMMU register values) is greater than the size of the mapped memory region (e.g. passed via DT to the driver). Adapt this check to print also a warning in case the mapped region is larger than the SMMU address space. Such a mismatch could be intentional (to fix wrong register values). If its not intentional (e.g. due to wrong DT information) this will very likely cause a malfunction of the driver as SMMU_CB_BASE is derived from the size of the mapped region. The warning helps to identify the root cause in this case. Signed-off-by: Andreas Herrmann Signed-off-by: Will Deacon --- drivers/iommu/arm-smmu.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/iommu') diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 878a5b926fe5..1f79daa5f4b1 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1700,13 +1700,12 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) id = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID1); smmu->pagesize = (id & ID1_PAGESIZE) ? SZ_64K : SZ_4K; - /* Check that we ioremapped enough */ + /* Check for size mismatch of SMMU address space from mapped region */ size = 1 << (((id >> ID1_NUMPAGENDXB_SHIFT) & ID1_NUMPAGENDXB_MASK) + 1); size *= (smmu->pagesize << 1); - if (smmu->size < size) - dev_warn(smmu->dev, - "device is 0x%lx bytes but only mapped 0x%lx!\n", - size, smmu->size); + if (smmu->size != size) + dev_warn(smmu->dev, "SMMU address space size (0x%lx) differs " + "from mapped region size (0x%lx)!\n", size, smmu->size); smmu->num_s2_context_banks = (id >> ID1_NUMS2CB_SHIFT) & ID1_NUMS2CB_MASK; -- cgit v1.2.3 From 44a08de2aaf7f4cf86dfcf04bee32536e4a2b5b8 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Tue, 1 Oct 2013 13:39:07 +0100 Subject: iommu/arm-smmu: Check for num_context_irqs > 0 to avoid divide by zero exception With the right (or wrong;-) definition of v1 SMMU node in DTB it is possible to trigger a division by zero in arm_smmu_init_domain_context (if number of context irqs is 0): if (smmu->version == 1) { root_cfg->irptndx = atomic_inc_return(&smmu->irptndx); => root_cfg->irptndx %= smmu->num_context_irqs; } else { Avoid this by checking for num_context_irqs > 0 when probing for SMMU devices. Signed-off-by: Andreas Herrmann [will: changed to dev_err on probe failure path] Signed-off-by: Will Deacon --- drivers/iommu/arm-smmu.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/iommu') diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 1f79daa5f4b1..e4693cee5f2c 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1798,12 +1798,11 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) smmu->num_context_irqs++; } - if (num_irqs < smmu->num_global_irqs) { - dev_warn(dev, "found %d interrupts but expected at least %d\n", - num_irqs, smmu->num_global_irqs); - smmu->num_global_irqs = num_irqs; + if (!smmu->num_context_irqs) { + dev_err(dev, "found %d interrupts but expected at least %d\n", + num_irqs, smmu->num_global_irqs + 1); + return -ENODEV; } - smmu->num_context_irqs = num_irqs - smmu->num_global_irqs; smmu->irqs = devm_kzalloc(dev, sizeof(*smmu->irqs) * num_irqs, GFP_KERNEL); -- cgit v1.2.3 From 2ef0f03120ea2ad64d0e70f032a58e6c13603cdc Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Tue, 1 Oct 2013 13:39:08 +0100 Subject: iommu/arm-smmu: Print context fault information Print context fault information when the fault was not handled by report_iommu_fault. Signed-off-by: Andreas Herrmann [will: fixed string formatting] Signed-off-by: Will Deacon --- drivers/iommu/arm-smmu.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/iommu') diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index e4693cee5f2c..a984e08eb084 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -590,6 +590,9 @@ static irqreturn_t arm_smmu_context_fault(int irq, void *dev) ret = IRQ_HANDLED; resume = RESUME_RETRY; } else { + dev_err_ratelimited(smmu->dev, + "Unhandled context fault: iova=0x%08lx, fsynr=0x%x, cb=%d\n", + iova, fsynr, root_cfg->cbndx); ret = IRQ_NONE; resume = RESUME_TERMINATE; } -- cgit v1.2.3 From 659db6f6beacae6fe49b5566debc4e82f678ff63 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Tue, 1 Oct 2013 13:39:09 +0100 Subject: iommu/arm-smmu: Clear global and context bank fault status registers After reset these registers have unknown values. This might cause problems when evaluating SMMU_GFSR and/or SMMU_CB_FSR in handlers for combined interrupts. Signed-off-by: Andreas Herrmann Signed-off-by: Will Deacon --- drivers/iommu/arm-smmu.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) (limited to 'drivers/iommu') diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index a984e08eb084..0f45a489ccf9 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1562,9 +1562,13 @@ static struct iommu_ops arm_smmu_ops = { static void arm_smmu_device_reset(struct arm_smmu_device *smmu) { void __iomem *gr0_base = ARM_SMMU_GR0(smmu); - void __iomem *sctlr_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB_SCTLR; + void __iomem *cb_base; int i = 0; - u32 scr0 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sCR0); + u32 reg; + + /* Clear Global FSR */ + reg = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSR); + writel(reg, gr0_base + ARM_SMMU_GR0_sGFSR); /* Mark all SMRn as invalid and all S2CRn as bypass */ for (i = 0; i < smmu->num_mapping_groups; ++i) { @@ -1572,33 +1576,38 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu) writel_relaxed(S2CR_TYPE_BYPASS, gr0_base + ARM_SMMU_GR0_S2CR(i)); } - /* Make sure all context banks are disabled */ - for (i = 0; i < smmu->num_context_banks; ++i) - writel_relaxed(0, sctlr_base + ARM_SMMU_CB(smmu, i)); + /* Make sure all context banks are disabled and clear CB_FSR */ + for (i = 0; i < smmu->num_context_banks; ++i) { + cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, i); + writel_relaxed(0, cb_base + ARM_SMMU_CB_SCTLR); + writel_relaxed(FSR_FAULT, cb_base + ARM_SMMU_CB_FSR); + } /* Invalidate the TLB, just in case */ writel_relaxed(0, gr0_base + ARM_SMMU_GR0_STLBIALL); writel_relaxed(0, gr0_base + ARM_SMMU_GR0_TLBIALLH); writel_relaxed(0, gr0_base + ARM_SMMU_GR0_TLBIALLNSNH); + reg = readl_relaxed(gr0_base + ARM_SMMU_GR0_sCR0); + /* Enable fault reporting */ - scr0 |= (sCR0_GFRE | sCR0_GFIE | sCR0_GCFGFRE | sCR0_GCFGFIE); + reg |= (sCR0_GFRE | sCR0_GFIE | sCR0_GCFGFRE | sCR0_GCFGFIE); /* Disable TLB broadcasting. */ - scr0 |= (sCR0_VMIDPNE | sCR0_PTM); + reg |= (sCR0_VMIDPNE | sCR0_PTM); /* Enable client access, but bypass when no mapping is found */ - scr0 &= ~(sCR0_CLIENTPD | sCR0_USFCFG); + reg &= ~(sCR0_CLIENTPD | sCR0_USFCFG); /* Disable forced broadcasting */ - scr0 &= ~sCR0_FB; + reg &= ~sCR0_FB; /* Don't upgrade barriers */ - scr0 &= ~(sCR0_BSU_MASK << sCR0_BSU_SHIFT); + reg &= ~(sCR0_BSU_MASK << sCR0_BSU_SHIFT); /* Push the button */ arm_smmu_tlb_sync(smmu); - writel_relaxed(scr0, gr0_base + ARM_SMMU_GR0_sCR0); + writel_relaxed(reg, gr0_base + ARM_SMMU_GR0_sCR0); } static int arm_smmu_id_size_to_bits(int size) -- cgit v1.2.3 From f9423606ade08653dd8a43334f0a7fb45504c5cc Mon Sep 17 00:00:00 2001 From: Julian Stecklina Date: Wed, 9 Oct 2013 10:03:52 +0200 Subject: iommu/vt-d: Fixed interaction of VFIO_IOMMU_MAP_DMA with IOMMU address limits The BUG_ON in drivers/iommu/intel-iommu.c:785 can be triggered from userspace via VFIO by calling the VFIO_IOMMU_MAP_DMA ioctl on a vfio device with any address beyond the addressing capabilities of the IOMMU. The problem is that the ioctl code calls iommu_iova_to_phys before it calls iommu_map. iommu_map handles the case that it gets addresses beyond the addressing capabilities of its IOMMU. intel_iommu_iova_to_phys does not. This patch fixes iommu_iova_to_phys to return NULL for addresses beyond what the IOMMU can handle. This in turn causes the ioctl call to fail in iommu_map and (correctly) return EFAULT to the user with a helpful warning message in the kernel log. Signed-off-by: Julian Stecklina Acked-by: Alex Williamson Signed-off-by: Joerg Roedel --- drivers/iommu/intel-iommu.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/iommu') diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 15e9b57e9cf0..40203ada635e 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -782,7 +782,11 @@ static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain, int offset; BUG_ON(!domain->pgd); - BUG_ON(addr_width < BITS_PER_LONG && pfn >> addr_width); + + if (addr_width < BITS_PER_LONG && pfn >> addr_width) + /* Address beyond IOMMU's addressing capabilities. */ + return NULL; + parent = domain->pgd; while (level > 0) { -- cgit v1.2.3 From 8b161f0ee911369232b5b5c18f84b5072f5bd09e Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Thu, 31 Oct 2013 17:25:16 +0800 Subject: iommu/vt-d: Use for_each_drhd_unit() instead of list_for_each_entry() Use for_each_drhd_unit() instead of list_for_each_entry for better readability. Signed-off-by: Yijing Wang Signed-off-by: Joerg Roedel --- drivers/iommu/dmar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/iommu') diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index 785675a56a10..da2d0d926e40 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -403,7 +403,7 @@ dmar_find_matched_drhd_unit(struct pci_dev *dev) dev = pci_physfn(dev); - list_for_each_entry(dmaru, &dmar_drhd_units, list) { + for_each_drhd_unit(dmaru) { drhd = container_of(dmaru->hdr, struct acpi_dmar_hardware_unit, header); -- cgit v1.2.3 From bca2b916f3d5c5bcb3d9d38fc1e4cb4d83b1d8a8 Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Thu, 31 Oct 2013 17:26:04 +0800 Subject: iommu/vt-d: Use list_for_each_entry_safe() for dmar_domain->devices traversal Replace list_for_each_safe() + list_entry() with the simpler list_for_each_entry_safe(). Signed-off-by: Yijing Wang Signed-off-by: Joerg Roedel --- drivers/iommu/intel-iommu.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/iommu') diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 40203ada635e..43b9bfea48fa 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -3781,11 +3781,10 @@ static void iommu_detach_dependent_devices(struct intel_iommu *iommu, static void domain_remove_one_dev_info(struct dmar_domain *domain, struct pci_dev *pdev) { - struct device_domain_info *info; + struct device_domain_info *info, *tmp; struct intel_iommu *iommu; unsigned long flags; int found = 0; - struct list_head *entry, *tmp; iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number, pdev->devfn); @@ -3793,8 +3792,7 @@ static void domain_remove_one_dev_info(struct dmar_domain *domain, return; spin_lock_irqsave(&device_domain_lock, flags); - list_for_each_safe(entry, tmp, &domain->devices) { - info = list_entry(entry, struct device_domain_info, link); + list_for_each_entry_safe(info, tmp, &domain->devices, link) { if (info->segment == pci_domain_nr(pdev->bus) && info->bus == pdev->bus->number && info->devfn == pdev->devfn) { -- cgit v1.2.3 From 8a788659af75ec0d82412cdca81953482529b342 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 8 Oct 2013 16:21:03 +0530 Subject: iommu/tegra-gart: Staticize tegra_gart_pm_ops 'tegra_gart_pm_ops' is local to this file. Make it static. Signed-off-by: Sachin Kamat Acked-by: Hiroshi Doyu Signed-off-by: Joerg Roedel --- drivers/iommu/tegra-gart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/iommu') diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c index f75483a3a2ef..dba1a9fd5070 100644 --- a/drivers/iommu/tegra-gart.c +++ b/drivers/iommu/tegra-gart.c @@ -411,7 +411,7 @@ static int tegra_gart_remove(struct platform_device *pdev) return 0; } -const struct dev_pm_ops tegra_gart_pm_ops = { +static const struct dev_pm_ops tegra_gart_pm_ops = { .suspend = tegra_gart_suspend, .resume = tegra_gart_resume, }; -- cgit v1.2.3 From a33a97c5c72cd0ffe292c0fd4c5f9c8957431a04 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 8 Oct 2013 16:21:04 +0530 Subject: iommu/tegra-smmu: Staticize tegra_smmu_pm_ops 'tegra_smmu_pm_ops' is used only in this file. Make it static. Signed-off-by: Sachin Kamat Acked-by: Hiroshi Doyu Signed-off-by: Joerg Roedel --- drivers/iommu/tegra-smmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/iommu') diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index 34374b3bc13b..605b5b46a903 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -1254,7 +1254,7 @@ static int tegra_smmu_remove(struct platform_device *pdev) return 0; } -const struct dev_pm_ops tegra_smmu_pm_ops = { +static const struct dev_pm_ops tegra_smmu_pm_ops = { .suspend = tegra_smmu_suspend, .resume = tegra_smmu_resume, }; -- cgit v1.2.3 From 7d02c4d64dbbc7dc1996d32171067d3ad8f06ae9 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 29 Oct 2013 23:37:40 +0100 Subject: iommu/shmobile: Enable the driver on all ARM platforms Renesas ARM platforms are transitioning from single-platform to multi-platform kernels using the new ARCH_SHMOBILE_MULTI. Make the driver available on all ARM platforms to enable it on both ARCH_SHMOBILE and ARCH_SHMOBILE_MULTI, and increase build testing coverage with COMPILE_TEST. Cc: Joerg Roedel Cc: iommu@lists.linux-foundation.org Signed-off-by: Laurent Pinchart Acked-by: Simon Horman Signed-off-by: Joerg Roedel --- drivers/iommu/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/iommu') diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index c880ebaf1553..9fd51e51e78b 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -206,7 +206,7 @@ config SHMOBILE_IPMMU_TLB config SHMOBILE_IOMMU bool "IOMMU for Renesas IPMMU/IPMMUI" default n - depends on (ARM && ARCH_SHMOBILE) + depends on ARM || COMPILE_TEST select IOMMU_API select ARM_DMA_USE_IOMMU select SHMOBILE_IPMMU -- cgit v1.2.3