Intel IOMMU fixes from 2.6.39.2

This commit is contained in:
Chuck Ebbert 2011-06-25 06:40:39 -04:00
parent b67156cd9e
commit 198deb8acf
9 changed files with 376 additions and 0 deletions

View File

@ -0,0 +1,37 @@
From 8519dc4401ddf8a5399f979870bbeeadbc111186 Mon Sep 17 00:00:00 2001
From: Mike Habeck <habeck@sgi.com>
Date: Sat, 28 May 2011 13:15:07 -0500
Subject: intel-iommu: Add domain check in domain_remove_one_dev_info
From: Mike Habeck <habeck@sgi.com>
commit 8519dc4401ddf8a5399f979870bbeeadbc111186 upstream.
The comment in domain_remove_one_dev_info() states "No need to compare
PCI domain; it has to be the same". But for the si_domain that isn't
going to be true, as it consists of all the PCI devices that are
identity mapped thus multiple PCI domains can be in si_domain. The
code needs to validate the PCI domain too.
Signed-off-by: Mike Habeck <habeck@sgi.com>
Signed-off-by: Mike Travis <travis@sgi.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/pci/intel-iommu.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -3398,8 +3398,8 @@ static void domain_remove_one_dev_info(s
spin_lock_irqsave(&device_domain_lock, flags);
list_for_each_safe(entry, tmp, &domain->devices) {
info = list_entry(entry, struct device_domain_info, link);
- /* No need to compare PCI domain; it has to be the same */
- if (info->bus == pdev->bus->number &&
+ if (info->segment == pci_domain_nr(pdev->bus) &&
+ info->bus == pdev->bus->number &&
info->devfn == pdev->devfn) {
list_del(&info->link);
list_del(&info->global);

View File

@ -0,0 +1,53 @@
From 8fcc5372fbac085199d84a880503ed67aba3fe49 Mon Sep 17 00:00:00 2001
From: Chris Wright <chrisw@sous-sol.org>
Date: Sat, 28 May 2011 13:15:02 -0500
Subject: intel-iommu: Check for identity mapping candidate using
system dma mask
From: Chris Wright <chrisw@sous-sol.org>
commit 8fcc5372fbac085199d84a880503ed67aba3fe49 upstream.
The identity mapping code appears to make the assumption that if the
devices dma_mask is greater than 32bits the device can use identity
mapping. But that is not true: take the case where we have a 40bit
device in a 44bit architecture. The device can potentially receive a
physical address that it will truncate and cause incorrect addresses
to be used.
Instead check to see if the device's dma_mask is large enough
to address the system's dma_mask.
Signed-off-by: Mike Travis <travis@sgi.com>
Reviewed-by: Mike Habeck <habeck@sgi.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/pci/intel-iommu.c | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -2190,8 +2190,19 @@ static int iommu_should_identity_map(str
* Assume that they will -- if they turn out not to be, then we can
* take them out of the 1:1 domain later.
*/
- if (!startup)
- return pdev->dma_mask > DMA_BIT_MASK(32);
+ if (!startup) {
+ /*
+ * If the device's dma_mask is less than the system's memory
+ * size then this is not a candidate for identity mapping.
+ */
+ u64 dma_mask = pdev->dma_mask;
+
+ if (pdev->dev.coherent_dma_mask &&
+ pdev->dev.coherent_dma_mask < dma_mask)
+ dma_mask = pdev->dev.coherent_dma_mask;
+
+ return dma_mask >= dma_get_required_mask(&pdev->dev);
+ }
return 1;
}

View File

@ -0,0 +1,60 @@
From 1c9fc3d11b84fbd0c4f4aa7855702c2a1f098ebb Mon Sep 17 00:00:00 2001
From: Chris Wright <chrisw@sous-sol.org>
Date: Sat, 28 May 2011 13:15:04 -0500
Subject: intel-iommu: Dont cache iova above 32bit
From: Chris Wright <chrisw@sous-sol.org>
commit 1c9fc3d11b84fbd0c4f4aa7855702c2a1f098ebb upstream.
Mike Travis and Mike Habeck reported an issue where iova allocation
would return a range that was larger than a device's dma mask.
https://lkml.org/lkml/2011/3/29/423
The dmar initialization code will reserve all PCI MMIO regions and copy
those reservations into a domain specific iova tree. It is possible for
one of those regions to be above the dma mask of a device. It is typical
to allocate iovas with a 32bit mask (despite device's dma mask possibly
being larger) and cache the result until it exhausts the lower 32bit
address space. Freeing the iova range that is >= the last iova in the
lower 32bit range when there is still an iova above the 32bit range will
corrupt the cached iova by pointing it to a region that is above 32bit.
If that region is also larger than the device's dma mask, a subsequent
allocation will return an unusable iova and cause dma failure.
Simply don't cache an iova that is above the 32bit caching boundary.
Reported-by: Mike Travis <travis@sgi.com>
Reported-by: Mike Habeck <habeck@sgi.com>
Acked-by: Mike Travis <travis@sgi.com>
Tested-by: Mike Habeck <habeck@sgi.com>
Signed-off-by: Chris Wright <chrisw@sous-sol.org>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/pci/iova.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
--- a/drivers/pci/iova.c
+++ b/drivers/pci/iova.c
@@ -63,8 +63,16 @@ __cached_rbnode_delete_update(struct iov
curr = iovad->cached32_node;
cached_iova = container_of(curr, struct iova, node);
- if (free->pfn_lo >= cached_iova->pfn_lo)
- iovad->cached32_node = rb_next(&free->node);
+ if (free->pfn_lo >= cached_iova->pfn_lo) {
+ struct rb_node *node = rb_next(&free->node);
+ struct iova *iova = container_of(node, struct iova, node);
+
+ /* only cache if it's below 32bit pfn */
+ if (node && iova->pfn_lo < iovad->dma_32bit_pfn)
+ iovad->cached32_node = node;
+ else
+ iovad->cached32_node = NULL;
+ }
}
/* Computes the padding size required, to make the

View File

@ -0,0 +1,36 @@
From 7b668357810ecb5fdda4418689d50f5d95aea6a8 Mon Sep 17 00:00:00 2001
From: Alex Williamson <alex.williamson@redhat.com>
Date: Tue, 24 May 2011 12:02:41 +0100
Subject: intel-iommu: Flush unmaps at domain_exit
From: Alex Williamson <alex.williamson@redhat.com>
commit 7b668357810ecb5fdda4418689d50f5d95aea6a8 upstream.
We typically batch unmaps to be lazily flushed out at
regular intervals. When we destroy a domain, we need
to force a flush of these lazy unmaps to be sure none
reference the domain we're about to free.
Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=35062
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/pci/intel-iommu.c | 4 ++++
1 file changed, 4 insertions(+)
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -1416,6 +1416,10 @@ static void domain_exit(struct dmar_doma
if (!domain)
return;
+ /* Flush any lazy unmaps that may reference this domain */
+ if (!intel_iommu_strict)
+ flush_unmaps_timeout(0);
+
domain_remove_dev_info(domain);
/* destroy iovas */
put_iova_domain(&domain->iovad);

View File

@ -0,0 +1,48 @@
From 9b4554b21ed07e8556405510638171f0c787742a Mon Sep 17 00:00:00 2001
From: Alex Williamson <alex.williamson@redhat.com>
Date: Tue, 24 May 2011 12:19:04 -0400
Subject: intel-iommu: Only unlink device domains from iommu
From: Alex Williamson <alex.williamson@redhat.com>
commit 9b4554b21ed07e8556405510638171f0c787742a upstream.
Commit a97590e5 added unlinking domains from iommus to reciprocate the
iommu from domains unlinking that was already done. We actually want
to only do this for device domains and never for the static
identity map domain or VM domains. The SI domain is special and
never freed, while VM domain->id lives in their own special address
space, separate from iommu->domain_ids.
In the current code, a VM can get domain->id zero, then mark that
domain unused when unbound from pci-stub. This leads to DMAR
write faults when the device is re-bound to the host driver.
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/pci/intel-iommu.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -3422,10 +3422,13 @@ static void domain_remove_one_dev_info(s
domain_update_iommu_cap(domain);
spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags);
- spin_lock_irqsave(&iommu->lock, tmp_flags);
- clear_bit(domain->id, iommu->domain_ids);
- iommu->domains[domain->id] = NULL;
- spin_unlock_irqrestore(&iommu->lock, tmp_flags);
+ if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
+ !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)) {
+ spin_lock_irqsave(&iommu->lock, tmp_flags);
+ clear_bit(domain->id, iommu->domain_ids);
+ iommu->domains[domain->id] = NULL;
+ spin_unlock_irqrestore(&iommu->lock, tmp_flags);
+ }
}
spin_unlock_irqrestore(&device_domain_lock, flags);

View File

@ -0,0 +1,44 @@
From 825507d6d059f1cbe2503e0e5a3926225b983aec Mon Sep 17 00:00:00 2001
From: Mike Travis <travis@sgi.com>
Date: Sat, 28 May 2011 13:15:06 -0500
Subject: intel-iommu: Remove Host Bridge devices from identity
mapping
From: Mike Travis <travis@sgi.com>
commit 825507d6d059f1cbe2503e0e5a3926225b983aec upstream.
When using the 1:1 (identity) PCI DMA remapping, PCI Host Bridge devices
that do not use the IOMMU causes a kernel panic. Fix that by not
inserting those devices into the si_domain.
Signed-off-by: Mike Travis <travis@sgi.com>
Reviewed-by: Mike Habeck <habeck@sgi.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/pci/intel-iommu.c | 5 +++++
1 file changed, 5 insertions(+)
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -46,6 +46,8 @@
#define ROOT_SIZE VTD_PAGE_SIZE
#define CONTEXT_SIZE VTD_PAGE_SIZE
+#define IS_BRIDGE_HOST_DEVICE(pdev) \
+ ((pdev->class >> 8) == PCI_CLASS_BRIDGE_HOST)
#define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
#define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA)
#define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e)
@@ -2217,6 +2219,9 @@ static int __init iommu_prepare_static_i
return -EFAULT;
for_each_pci_dev(pdev) {
+ /* Skip Host/PCI Bridge devices */
+ if (IS_BRIDGE_HOST_DEVICE(pdev))
+ continue;
if (iommu_should_identity_map(pdev, 1)) {
printk(KERN_INFO "IOMMU: %s identity mapping for device %s\n",
hw ? "hardware" : "software", pci_name(pdev));

View File

@ -0,0 +1,43 @@
From cb452a4040bb051d92e85d6e7eb60c11734c1781 Mon Sep 17 00:00:00 2001
From: Mike Travis <travis@sgi.com>
Date: Sat, 28 May 2011 13:15:03 -0500
Subject: intel-iommu: Speed up processing of the identity_mapping
function
From: Mike Travis <travis@sgi.com>
commit cb452a4040bb051d92e85d6e7eb60c11734c1781 upstream.
When there are a large count of PCI devices, and the pass through
option for iommu is set, much time is spent in the identity_mapping
function hunting though the iommu domains to check if a specific
device is "identity mapped".
Speed up the function by checking the cached info to see if
it's mapped to the static identity domain.
Signed-off-by: Mike Travis <travis@sgi.com>
Reviewed-by: Mike Habeck <habeck@sgi.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/pci/intel-iommu.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -2109,10 +2109,10 @@ static int identity_mapping(struct pci_d
if (likely(!iommu_identity_mapping))
return 0;
+ info = pdev->dev.archdata.iommu;
+ if (info && info != DUMMY_DEVICE_DOMAIN_INFO)
+ return (info->domain == si_domain);
- list_for_each_entry(info, &si_domain->devices, link)
- if (info->dev == pdev)
- return 1;
return 0;
}

View File

@ -0,0 +1,35 @@
From c681d0ba1252954208220ad32248a3e8e2fc98e4 Mon Sep 17 00:00:00 2001
From: Mike Travis <travis@sgi.com>
Date: Sat, 28 May 2011 13:15:05 -0500
Subject: intel-iommu: Use coherent DMA mask when requested
From: Mike Travis <travis@sgi.com>
commit c681d0ba1252954208220ad32248a3e8e2fc98e4 upstream.
The __intel_map_single function is not honoring the passed in DMA mask.
This results in not using the coherent DMA mask when called from
intel_alloc_coherent().
Signed-off-by: Mike Travis <travis@sgi.com>
Acked-by: Chris Wright <chrisw@sous-sol.org>
Reviewed-by: Mike Habeck <habeck@sgi.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/pci/intel-iommu.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -2606,8 +2606,7 @@ static dma_addr_t __intel_map_single(str
iommu = domain_get_iommu(domain);
size = aligned_nrpages(paddr, size);
- iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size),
- pdev->dma_mask);
+ iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size), dma_mask);
if (!iova)
goto error;

View File

@ -708,6 +708,14 @@ Patch1842: drm-radeon-pageflip-oops-fix.patch
Patch1843: drm-radeon-update3.patch
Patch1900: linux-2.6-intel-iommu-igfx.patch
Patch1901: intel-iommu-flush-unmaps-at-domain_exit.patch
Patch1902: intel-iommu-only-unlink-device-domains-from-iommu.patch
Patch1903: intel-iommu-check-for-identity-mapping-candidate-using.patch
Patch1904: intel-iommu-speed-up-processing-of-the-identity_mapping.patch
Patch1905: intel-iommu-dont-cache-iova-above-32bit.patch
Patch1906: intel-iommu-use-coherent-dma-mask-when-requested.patch
Patch1907: intel-iommu-remove-host-bridge-devices-from-identity.patch
Patch1908: intel-iommu-add-domain-check-in-domain_remove_one_dev_info.patch
# linux1394 git patches
Patch2200: linux-2.6-firewire-git-update.patch
@ -1231,6 +1239,15 @@ ApplyPatch x86-dumpstack-correct-stack-dump-info-when-frame-pointer-is-available
#
# Intel IOMMU
#
# from 2.6.39.2
ApplyPatch intel-iommu-flush-unmaps-at-domain_exit.patch
ApplyPatch intel-iommu-only-unlink-device-domains-from-iommu.patch
ApplyPatch intel-iommu-check-for-identity-mapping-candidate-using.patch
ApplyPatch intel-iommu-speed-up-processing-of-the-identity_mapping.patch
ApplyPatch intel-iommu-dont-cache-iova-above-32bit.patch
ApplyPatch intel-iommu-use-coherent-dma-mask-when-requested.patch
ApplyPatch intel-iommu-remove-host-bridge-devices-from-identity.patch
ApplyPatch intel-iommu-add-domain-check-in-domain_remove_one_dev_info.patch
#
# PowerPC
@ -2049,6 +2066,9 @@ fi
# and build.
%changelog
* Sat Jun 25 2011 Chuck Ebbert <cebbert@redhat.com>
- Intel IOMMU fixes from 2.6.39.2
* Fri Jun 24 2011 Chuck Ebbert <cebbert@redhat.com>
- Minor cleanup: use upstream patch to export block_{get,put}_queue
- block-blkdev_get-should-access-bd_disk-only-after.patch: