From 9579a974d1018c7f1d42455c29aa3f0d512c99fe Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 8 Jul 2012 13:37:42 +0200 Subject: [PATCH 01/10] iommu/tegra: remove invalid reference to list iterator variable If list_for_each_entry, etc complete a traversal of the list, the iterator variable ends up pointing to an address at an offset from the list head, and not a meaningful structure. Thus this value should not be used after the end of the iterator. Replace c->dev by dev, which is the value that c->dev has been compared to. This problem was found using Coccinelle (http://coccinelle.lip6.fr/). Signed-off-by: Julia Lawall Acked-by: Stephen Warren Acked-by: Hiroshi DOYU Signed-off-by: Joerg Roedel --- drivers/iommu/tegra-smmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index 4ba325ab6262..a9bf4c30cd84 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -799,7 +799,7 @@ static void smmu_iommu_detach_dev(struct iommu_domain *domain, goto out; } } - dev_err(smmu->dev, "Couldn't find %s\n", dev_name(c->dev)); + dev_err(smmu->dev, "Couldn't find %s\n", dev_name(dev)); out: spin_unlock(&as->client_lock); } From d2900bd63f65bf1f40bf17f3c51457ae29fae6a8 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 24 Jul 2012 16:18:14 +0200 Subject: [PATCH 02/10] iommu/intel: add missing free_domain_mem Add missing free_domain_mem on failure path after alloc_domain. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @km exists@ local idexpression e; expression e1,e2,e3; type T,T1; identifier f; @@ * e = alloc_domain(...) ... when any when != e = e1 when != e1 = (T)e when != e1(...,(T)e,...) when != &e->f if(...) { ... when != e2(...,(T1)e,...) when != e3 = e when forall ( return <+...e...+>; | * return ...; ) } // Signed-off-by: Julia Lawall Signed-off-by: Joerg Roedel --- drivers/iommu/intel-iommu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 7469b5346643..0204b62480b0 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -2008,6 +2008,7 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw) if (!drhd) { printk(KERN_ERR "IOMMU: can't find DMAR for device %s\n", pci_name(pdev)); + free_domain_mem(domain); return NULL; } iommu = drhd->iommu; From 76582d0a68ab6c46987dd678165c26ad81c44cdb Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 25 Jul 2012 16:24:49 +0200 Subject: [PATCH 03/10] iommu: Include linux/types.h The linux/iommu.h header uses types defined in linux/types.h but doesn't include it. Signed-off-by: Thierry Reding Signed-off-by: Joerg Roedel --- include/linux/iommu.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 54d6d690073c..0a85199191b9 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -20,6 +20,7 @@ #define __LINUX_IOMMU_H #include +#include #define IOMMU_READ (1) #define IOMMU_WRITE (2) From ba1eabfade3272596000bf3c62b68ca375e48b08 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Fri, 3 Aug 2012 15:55:41 +0200 Subject: [PATCH 04/10] iommu: Add missing forward declaration in include file The 'struct notifier_block' is not used in linux/iommu.h but not declared anywhere. Add a forward declaration for it. Reported-by: Thierry Reding Signed-off-by: Joerg Roedel --- include/linux/iommu.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 0a85199191b9..7e83370e6fd2 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -31,6 +31,7 @@ struct iommu_group; struct bus_type; struct device; struct iommu_domain; +struct notifier_block; /* iommu fault flags */ #define IOMMU_FAULT_READ 0x0 From d2453b2c7875dac9b323bff5d21981c41de177b1 Mon Sep 17 00:00:00 2001 From: Hiroshi Doyu Date: Mon, 30 Jul 2012 08:39:18 +0300 Subject: [PATCH 05/10] iommu/tegra: smmu: Cleanup with lesser nest Small clean up with lesser nest for readability. Signed-off-by: Hiroshi Doyu Signed-off-by: Joerg Roedel --- drivers/iommu/tegra-smmu.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index a9bf4c30cd84..37669cc483b1 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -814,11 +814,14 @@ static int smmu_iommu_domain_init(struct iommu_domain *domain) /* Look for a free AS with lock held */ for (i = 0; i < smmu->num_as; i++) { as = &smmu->as[i]; - if (!as->pdir_page) { - err = alloc_pdir(as); - if (!err) - goto found; - } + + if (as->pdir_page) + continue; + + err = alloc_pdir(as); + if (!err) + goto found; + if (err != -EAGAIN) break; } From d1d076f16376066d0a51aa7d465f43059da71562 Mon Sep 17 00:00:00 2001 From: Hiroshi Doyu Date: Mon, 30 Jul 2012 08:39:19 +0300 Subject: [PATCH 06/10] iommu/tegra: smmu: Fix error initial value at domain_init err initial value should be -EAGAIN. Otherwise 2nd iteration always fails in the case as[0] is occupied. Signed-off-by: Hiroshi Doyu Signed-off-by: Joerg Roedel --- drivers/iommu/tegra-smmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index 37669cc483b1..2a4bb36bc688 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -806,7 +806,7 @@ out: static int smmu_iommu_domain_init(struct iommu_domain *domain) { - int i, err = -ENODEV; + int i, err = -EAGAIN; unsigned long flags; struct smmu_as *as; struct smmu_device *smmu = smmu_handle; From eb51637b6ec73ff5f8eaca57658a9945aa7bd45f Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Wed, 1 Aug 2012 14:35:17 +0530 Subject: [PATCH 07/10] iommu/exynos: Fix build error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following build error introduced by commit 3177bb76a8 ("iommu/exynos: Implement DOMAIN_ATTR_GEOMETRY attribute"): drivers/iommu/exynos-iommu.c: In function ‘exynos_iommu_domain_init’: drivers/iommu/exynos-iommu.c:735:2: error: ‘dom’ undeclared (first use in this function) Signed-off-by: Sachin Kamat Acked-by: Kukjin Kim Signed-off-by: Joerg Roedel --- drivers/iommu/exynos-iommu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 45350ff5e93c..80bad32aa463 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -732,9 +732,9 @@ static int exynos_iommu_domain_init(struct iommu_domain *domain) spin_lock_init(&priv->pgtablelock); INIT_LIST_HEAD(&priv->clients); - dom->geometry.aperture_start = 0; - dom->geometry.aperture_end = ~0UL; - dom->geometry.force_aperture = true; + domain->geometry.aperture_start = 0; + domain->geometry.aperture_end = ~0UL; + domain->geometry.force_aperture = true; domain->priv = priv; return 0; From 1adb7d31b051cd97fbb75c46772b00c13ec29c9e Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Mon, 6 Aug 2012 14:18:42 +0200 Subject: [PATCH 08/10] iommu/amd: Fix pci_request_acs() call-place The pci_request_acs() function needs to be called before PCI probing to be effective. So move it to another call-place to ensure that. Signed-off-by: Joerg Roedel --- drivers/iommu/amd_iommu_init.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 500e7f15f5c2..0a2ea317120a 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -1131,9 +1131,6 @@ static int __init amd_iommu_init_pci(void) break; } - /* Make sure ACS will be enabled */ - pci_request_acs(); - ret = amd_iommu_init_devices(); print_iommu_info(); @@ -1652,6 +1649,9 @@ static bool detect_ivrs(void) early_acpi_os_unmap_memory((char __iomem *)ivrs_base, ivrs_size); + /* Make sure ACS will be enabled during PCI probe */ + pci_request_acs(); + return true; } From a4ff1fc2ccbd81e83ac51ea44570caa361c666af Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Sat, 4 Aug 2012 12:08:55 -0600 Subject: [PATCH 09/10] iommu/intel: Fix ACS path checking SR-IOV can create buses without a bridge. There may be other cases where this happens as well. In these cases skip to the parent bus and continue testing devices there. Signed-off-by: Alex Williamson Tested-by: David Ahern Signed-off-by: Joerg Roedel --- drivers/iommu/intel-iommu.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 0204b62480b0..2297ec193eb4 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -4125,8 +4125,13 @@ static int intel_iommu_add_device(struct device *dev) } else dma_pdev = pci_dev_get(pdev); + /* Account for quirked devices */ swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev)); + /* + * If it's a multifunction device that does not support our + * required ACS flags, add to the same group as function 0. + */ if (dma_pdev->multifunction && !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)) swap_pci_ref(&dma_pdev, @@ -4134,14 +4139,28 @@ static int intel_iommu_add_device(struct device *dev) PCI_DEVFN(PCI_SLOT(dma_pdev->devfn), 0))); + /* + * Devices on the root bus go through the iommu. If that's not us, + * find the next upstream device and test ACS up to the root bus. + * Finding the next device may require skipping virtual buses. + */ while (!pci_is_root_bus(dma_pdev->bus)) { - if (pci_acs_path_enabled(dma_pdev->bus->self, - NULL, REQ_ACS_FLAGS)) + struct pci_bus *bus = dma_pdev->bus; + + while (!bus->self) { + if (!pci_is_root_bus(bus)) + bus = bus->parent; + else + goto root_bus; + } + + if (pci_acs_path_enabled(bus->self, NULL, REQ_ACS_FLAGS)) break; - swap_pci_ref(&dma_pdev, pci_dev_get(dma_pdev->bus->self)); + swap_pci_ref(&dma_pdev, pci_dev_get(bus->self)); } +root_bus: group = iommu_group_get(&dma_pdev->dev); pci_dev_put(dma_pdev); if (!group) { From 31fe943599b7e5870edb9decb7fbb9538b218f26 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Sat, 4 Aug 2012 12:09:03 -0600 Subject: [PATCH 10/10] iommu/amd: Fix ACS path checking SR-IOV can create buses without a bridge. There may be other cases where this happens as well. In these cases skip to the parent bus and continue testing devices there. Signed-off-by: Alex Williamson Signed-off-by: Joerg Roedel --- drivers/iommu/amd_iommu.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 6d1cbdfc9b2a..b64502dfa9f4 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -296,8 +296,13 @@ static int iommu_init_device(struct device *dev) } else dma_pdev = pci_dev_get(pdev); + /* Account for quirked devices */ swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev)); + /* + * If it's a multifunction device that does not support our + * required ACS flags, add to the same group as function 0. + */ if (dma_pdev->multifunction && !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)) swap_pci_ref(&dma_pdev, @@ -305,14 +310,28 @@ static int iommu_init_device(struct device *dev) PCI_DEVFN(PCI_SLOT(dma_pdev->devfn), 0))); + /* + * Devices on the root bus go through the iommu. If that's not us, + * find the next upstream device and test ACS up to the root bus. + * Finding the next device may require skipping virtual buses. + */ while (!pci_is_root_bus(dma_pdev->bus)) { - if (pci_acs_path_enabled(dma_pdev->bus->self, - NULL, REQ_ACS_FLAGS)) + struct pci_bus *bus = dma_pdev->bus; + + while (!bus->self) { + if (!pci_is_root_bus(bus)) + bus = bus->parent; + else + goto root_bus; + } + + if (pci_acs_path_enabled(bus->self, NULL, REQ_ACS_FLAGS)) break; - swap_pci_ref(&dma_pdev, pci_dev_get(dma_pdev->bus->self)); + swap_pci_ref(&dma_pdev, pci_dev_get(bus->self)); } +root_bus: group = iommu_group_get(&dma_pdev->dev); pci_dev_put(dma_pdev); if (!group) {