diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-08-08 13:01:45 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-08-08 13:01:45 -0400 |
| commit | 7f46f9c13041c8fde331142791f3994a8fdbec6f (patch) | |
| tree | da24c058773a1392cf82b1a31ec6867f83803af6 | |
| parent | 6666cabf5af309c1c3e63a36e2580879fb40e827 (diff) | |
| parent | 31fe943599b7e5870edb9decb7fbb9538b218f26 (diff) | |
Merge tag 'iommu-fixes-v3.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu
Pull IOMMU fixes from Joerg Roedel:
"These patches fix a couple of issues. First of all a few problems
with ACS on x86 introduced in the last merge window, where ACS did not
work on AMD and a NULL pointer dereference when there ran against
SR-IOV devices.
The patches fallen out of coccinelle checks fix a possible invalid
memory reference and a possible memory leak. The other patches mostly
fix build errors and warnings and a wrong return value."
* tag 'iommu-fixes-v3.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu:
iommu/amd: Fix ACS path checking
iommu/intel: Fix ACS path checking
iommu/amd: Fix pci_request_acs() call-place
iommu/exynos: Fix build error
iommu/tegra: smmu: Fix error initial value at domain_init
iommu/tegra: smmu: Cleanup with lesser nest
iommu: Add missing forward declaration in include file
iommu: Include linux/types.h
iommu/intel: add missing free_domain_mem
iommu/tegra: remove invalid reference to list iterator variable
| -rw-r--r-- | drivers/iommu/amd_iommu.c | 25 | ||||
| -rw-r--r-- | drivers/iommu/amd_iommu_init.c | 6 | ||||
| -rw-r--r-- | drivers/iommu/exynos-iommu.c | 6 | ||||
| -rw-r--r-- | drivers/iommu/intel-iommu.c | 26 | ||||
| -rw-r--r-- | drivers/iommu/tegra-smmu.c | 17 | ||||
| -rw-r--r-- | include/linux/iommu.h | 2 |
6 files changed, 63 insertions, 19 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) | |||
| 296 | } else | 296 | } else |
| 297 | dma_pdev = pci_dev_get(pdev); | 297 | dma_pdev = pci_dev_get(pdev); |
| 298 | 298 | ||
| 299 | /* Account for quirked devices */ | ||
| 299 | swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev)); | 300 | swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev)); |
| 300 | 301 | ||
| 302 | /* | ||
| 303 | * If it's a multifunction device that does not support our | ||
| 304 | * required ACS flags, add to the same group as function 0. | ||
| 305 | */ | ||
| 301 | if (dma_pdev->multifunction && | 306 | if (dma_pdev->multifunction && |
| 302 | !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)) | 307 | !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)) |
| 303 | swap_pci_ref(&dma_pdev, | 308 | swap_pci_ref(&dma_pdev, |
| @@ -305,14 +310,28 @@ static int iommu_init_device(struct device *dev) | |||
| 305 | PCI_DEVFN(PCI_SLOT(dma_pdev->devfn), | 310 | PCI_DEVFN(PCI_SLOT(dma_pdev->devfn), |
| 306 | 0))); | 311 | 0))); |
| 307 | 312 | ||
| 313 | /* | ||
| 314 | * Devices on the root bus go through the iommu. If that's not us, | ||
| 315 | * find the next upstream device and test ACS up to the root bus. | ||
| 316 | * Finding the next device may require skipping virtual buses. | ||
| 317 | */ | ||
| 308 | while (!pci_is_root_bus(dma_pdev->bus)) { | 318 | while (!pci_is_root_bus(dma_pdev->bus)) { |
| 309 | if (pci_acs_path_enabled(dma_pdev->bus->self, | 319 | struct pci_bus *bus = dma_pdev->bus; |
| 310 | NULL, REQ_ACS_FLAGS)) | 320 | |
| 321 | while (!bus->self) { | ||
| 322 | if (!pci_is_root_bus(bus)) | ||
| 323 | bus = bus->parent; | ||
| 324 | else | ||
| 325 | goto root_bus; | ||
| 326 | } | ||
| 327 | |||
| 328 | if (pci_acs_path_enabled(bus->self, NULL, REQ_ACS_FLAGS)) | ||
| 311 | break; | 329 | break; |
| 312 | 330 | ||
| 313 | swap_pci_ref(&dma_pdev, pci_dev_get(dma_pdev->bus->self)); | 331 | swap_pci_ref(&dma_pdev, pci_dev_get(bus->self)); |
| 314 | } | 332 | } |
| 315 | 333 | ||
| 334 | root_bus: | ||
| 316 | group = iommu_group_get(&dma_pdev->dev); | 335 | group = iommu_group_get(&dma_pdev->dev); |
| 317 | pci_dev_put(dma_pdev); | 336 | pci_dev_put(dma_pdev); |
| 318 | if (!group) { | 337 | if (!group) { |
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) | |||
| 1131 | break; | 1131 | break; |
| 1132 | } | 1132 | } |
| 1133 | 1133 | ||
| 1134 | /* Make sure ACS will be enabled */ | ||
| 1135 | pci_request_acs(); | ||
| 1136 | |||
| 1137 | ret = amd_iommu_init_devices(); | 1134 | ret = amd_iommu_init_devices(); |
| 1138 | 1135 | ||
| 1139 | print_iommu_info(); | 1136 | print_iommu_info(); |
| @@ -1652,6 +1649,9 @@ static bool detect_ivrs(void) | |||
| 1652 | 1649 | ||
| 1653 | early_acpi_os_unmap_memory((char __iomem *)ivrs_base, ivrs_size); | 1650 | early_acpi_os_unmap_memory((char __iomem *)ivrs_base, ivrs_size); |
| 1654 | 1651 | ||
| 1652 | /* Make sure ACS will be enabled during PCI probe */ | ||
| 1653 | pci_request_acs(); | ||
| 1654 | |||
| 1655 | return true; | 1655 | return true; |
| 1656 | } | 1656 | } |
| 1657 | 1657 | ||
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) | |||
| 732 | spin_lock_init(&priv->pgtablelock); | 732 | spin_lock_init(&priv->pgtablelock); |
| 733 | INIT_LIST_HEAD(&priv->clients); | 733 | INIT_LIST_HEAD(&priv->clients); |
| 734 | 734 | ||
| 735 | dom->geometry.aperture_start = 0; | 735 | domain->geometry.aperture_start = 0; |
| 736 | dom->geometry.aperture_end = ~0UL; | 736 | domain->geometry.aperture_end = ~0UL; |
| 737 | dom->geometry.force_aperture = true; | 737 | domain->geometry.force_aperture = true; |
| 738 | 738 | ||
| 739 | domain->priv = priv; | 739 | domain->priv = priv; |
| 740 | return 0; | 740 | return 0; |
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 7469b5346643..2297ec193eb4 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) | |||
| 2008 | if (!drhd) { | 2008 | if (!drhd) { |
| 2009 | printk(KERN_ERR "IOMMU: can't find DMAR for device %s\n", | 2009 | printk(KERN_ERR "IOMMU: can't find DMAR for device %s\n", |
| 2010 | pci_name(pdev)); | 2010 | pci_name(pdev)); |
| 2011 | free_domain_mem(domain); | ||
| 2011 | return NULL; | 2012 | return NULL; |
| 2012 | } | 2013 | } |
| 2013 | iommu = drhd->iommu; | 2014 | iommu = drhd->iommu; |
| @@ -4124,8 +4125,13 @@ static int intel_iommu_add_device(struct device *dev) | |||
| 4124 | } else | 4125 | } else |
| 4125 | dma_pdev = pci_dev_get(pdev); | 4126 | dma_pdev = pci_dev_get(pdev); |
| 4126 | 4127 | ||
| 4128 | /* Account for quirked devices */ | ||
| 4127 | swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev)); | 4129 | swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev)); |
| 4128 | 4130 | ||
| 4131 | /* | ||
| 4132 | * If it's a multifunction device that does not support our | ||
| 4133 | * required ACS flags, add to the same group as function 0. | ||
| 4134 | */ | ||
| 4129 | if (dma_pdev->multifunction && | 4135 | if (dma_pdev->multifunction && |
| 4130 | !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)) | 4136 | !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)) |
| 4131 | swap_pci_ref(&dma_pdev, | 4137 | swap_pci_ref(&dma_pdev, |
| @@ -4133,14 +4139,28 @@ static int intel_iommu_add_device(struct device *dev) | |||
| 4133 | PCI_DEVFN(PCI_SLOT(dma_pdev->devfn), | 4139 | PCI_DEVFN(PCI_SLOT(dma_pdev->devfn), |
| 4134 | 0))); | 4140 | 0))); |
| 4135 | 4141 | ||
| 4142 | /* | ||
| 4143 | * Devices on the root bus go through the iommu. If that's not us, | ||
| 4144 | * find the next upstream device and test ACS up to the root bus. | ||
| 4145 | * Finding the next device may require skipping virtual buses. | ||
| 4146 | */ | ||
| 4136 | while (!pci_is_root_bus(dma_pdev->bus)) { | 4147 | while (!pci_is_root_bus(dma_pdev->bus)) { |
| 4137 | if (pci_acs_path_enabled(dma_pdev->bus->self, | 4148 | struct pci_bus *bus = dma_pdev->bus; |
| 4138 | NULL, REQ_ACS_FLAGS)) | 4149 | |
| 4150 | while (!bus->self) { | ||
| 4151 | if (!pci_is_root_bus(bus)) | ||
| 4152 | bus = bus->parent; | ||
| 4153 | else | ||
| 4154 | goto root_bus; | ||
| 4155 | } | ||
| 4156 | |||
| 4157 | if (pci_acs_path_enabled(bus->self, NULL, REQ_ACS_FLAGS)) | ||
| 4139 | break; | 4158 | break; |
| 4140 | 4159 | ||
| 4141 | swap_pci_ref(&dma_pdev, pci_dev_get(dma_pdev->bus->self)); | 4160 | swap_pci_ref(&dma_pdev, pci_dev_get(bus->self)); |
| 4142 | } | 4161 | } |
| 4143 | 4162 | ||
| 4163 | root_bus: | ||
| 4144 | group = iommu_group_get(&dma_pdev->dev); | 4164 | group = iommu_group_get(&dma_pdev->dev); |
| 4145 | pci_dev_put(dma_pdev); | 4165 | pci_dev_put(dma_pdev); |
| 4146 | if (!group) { | 4166 | if (!group) { |
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index 4ba325ab6262..2a4bb36bc688 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c | |||
| @@ -799,14 +799,14 @@ static void smmu_iommu_detach_dev(struct iommu_domain *domain, | |||
| 799 | goto out; | 799 | goto out; |
| 800 | } | 800 | } |
| 801 | } | 801 | } |
| 802 | dev_err(smmu->dev, "Couldn't find %s\n", dev_name(c->dev)); | 802 | dev_err(smmu->dev, "Couldn't find %s\n", dev_name(dev)); |
| 803 | out: | 803 | out: |
| 804 | spin_unlock(&as->client_lock); | 804 | spin_unlock(&as->client_lock); |
| 805 | } | 805 | } |
| 806 | 806 | ||
| 807 | static int smmu_iommu_domain_init(struct iommu_domain *domain) | 807 | static int smmu_iommu_domain_init(struct iommu_domain *domain) |
| 808 | { | 808 | { |
| 809 | int i, err = -ENODEV; | 809 | int i, err = -EAGAIN; |
| 810 | unsigned long flags; | 810 | unsigned long flags; |
| 811 | struct smmu_as *as; | 811 | struct smmu_as *as; |
| 812 | struct smmu_device *smmu = smmu_handle; | 812 | struct smmu_device *smmu = smmu_handle; |
| @@ -814,11 +814,14 @@ static int smmu_iommu_domain_init(struct iommu_domain *domain) | |||
| 814 | /* Look for a free AS with lock held */ | 814 | /* Look for a free AS with lock held */ |
| 815 | for (i = 0; i < smmu->num_as; i++) { | 815 | for (i = 0; i < smmu->num_as; i++) { |
| 816 | as = &smmu->as[i]; | 816 | as = &smmu->as[i]; |
| 817 | if (!as->pdir_page) { | 817 | |
| 818 | err = alloc_pdir(as); | 818 | if (as->pdir_page) |
| 819 | if (!err) | 819 | continue; |
| 820 | goto found; | 820 | |
| 821 | } | 821 | err = alloc_pdir(as); |
| 822 | if (!err) | ||
| 823 | goto found; | ||
| 824 | |||
| 822 | if (err != -EAGAIN) | 825 | if (err != -EAGAIN) |
| 823 | break; | 826 | break; |
| 824 | } | 827 | } |
diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 54d6d690073c..7e83370e6fd2 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #define __LINUX_IOMMU_H | 20 | #define __LINUX_IOMMU_H |
| 21 | 21 | ||
| 22 | #include <linux/errno.h> | 22 | #include <linux/errno.h> |
| 23 | #include <linux/types.h> | ||
| 23 | 24 | ||
| 24 | #define IOMMU_READ (1) | 25 | #define IOMMU_READ (1) |
| 25 | #define IOMMU_WRITE (2) | 26 | #define IOMMU_WRITE (2) |
| @@ -30,6 +31,7 @@ struct iommu_group; | |||
| 30 | struct bus_type; | 31 | struct bus_type; |
| 31 | struct device; | 32 | struct device; |
| 32 | struct iommu_domain; | 33 | struct iommu_domain; |
| 34 | struct notifier_block; | ||
| 33 | 35 | ||
| 34 | /* iommu fault flags */ | 36 | /* iommu fault flags */ |
| 35 | #define IOMMU_FAULT_READ 0x0 | 37 | #define IOMMU_FAULT_READ 0x0 |
