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 |