ioat2: catch and recover from broken vtd configurations v6

This commit is contained in:
Kyle McMartin 2010-12-09 17:53:54 -05:00
parent 4038895354
commit 4b57f309c7
2 changed files with 176 additions and 0 deletions

View File

@ -0,0 +1,167 @@
From 547c01ae2608ffe89d18441ea209aff0540e83ec Mon Sep 17 00:00:00 2001
From: Kyle McMartin <kyle@mcmartin.ca>
Date: Thu, 9 Dec 2010 17:45:58 -0500
Subject: ioat2: catch and recover from broken vtd configurations v6
On some platforms (MacPro3,1) the BIOS assigns the ioatdma device to the
incorrect iommu causing faults when the driver initializes. Add a quirk
to catch this misconfiguration and try falling back to untranslated
operation (which works in the MacPro3,1 case).
Assuming there are other platforms with misconfigured iommus teach the
ioatdma driver to treat initialization failures as non-fatal (just fail
the driver load and emit a warning instead of triggering a BUG_ON).
This can be classified as a boot regression since 2.6.32 on affected
platforms since the ioatdma module did not autoload prior to that
kernel.
Cc: <stable@kernel.org>
Acked-by: David Woodhouse <David.Woodhouse@intel.com>
Reported-by: Chris Li <lkml@chrisli.org>
Tested-by: Chris Li <lkml@chrisli.org>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Conflicts:
drivers/dma/ioat/dma.h
---
drivers/dma/ioat/dma.h | 1 +
drivers/dma/ioat/dma_v2.c | 24 ++++++++++++++++++++++--
drivers/dma/ioat/dma_v3.c | 5 ++++-
drivers/pci/intel-iommu.c | 28 ++++++++++++++++++++++++++++
4 files changed, 55 insertions(+), 3 deletions(-)
diff --git a/drivers/dma/ioat/dma.h b/drivers/dma/ioat/dma.h
index 86b97ac..f7619e9 100644
--- a/drivers/dma/ioat/dma.h
+++ b/drivers/dma/ioat/dma.h
@@ -96,6 +96,7 @@ struct ioat_chan_common {
#define IOAT_COMPLETION_ACK 1
#define IOAT_RESET_PENDING 2
#define IOAT_KOBJ_INIT_FAIL 3
+ #define IOAT_RUN 4
struct timer_list timer;
#define COMPLETION_TIMEOUT msecs_to_jiffies(100)
#define IDLE_TIMEOUT msecs_to_jiffies(2000)
diff --git a/drivers/dma/ioat/dma_v2.c b/drivers/dma/ioat/dma_v2.c
index b5ae56c..63e6929 100644
--- a/drivers/dma/ioat/dma_v2.c
+++ b/drivers/dma/ioat/dma_v2.c
@@ -304,7 +304,10 @@ void ioat2_timer_event(unsigned long data)
chanerr = readl(chan->reg_base + IOAT_CHANERR_OFFSET);
dev_err(to_dev(chan), "%s: Channel halted (%x)\n",
__func__, chanerr);
- BUG_ON(is_ioat_bug(chanerr));
+ if (test_bit(IOAT_RUN, &chan->state))
+ BUG_ON(is_ioat_bug(chanerr));
+ else /* we never got off the ground */
+ return;
}
/* if we haven't made progress and we have already
@@ -496,6 +499,8 @@ static struct ioat_ring_ent **ioat2_alloc_ring(struct dma_chan *c, int order, gf
return ring;
}
+void ioat2_free_chan_resources(struct dma_chan *c);
+
/* ioat2_alloc_chan_resources - allocate/initialize ioat2 descriptor ring
* @chan: channel to be initialized
*/
@@ -504,6 +509,7 @@ int ioat2_alloc_chan_resources(struct dma_chan *c)
struct ioat2_dma_chan *ioat = to_ioat2_chan(c);
struct ioat_chan_common *chan = &ioat->base;
struct ioat_ring_ent **ring;
+ u64 status;
int order;
/* have we already been set up? */
@@ -542,7 +548,20 @@ int ioat2_alloc_chan_resources(struct dma_chan *c)
tasklet_enable(&chan->cleanup_task);
ioat2_start_null_desc(ioat);
- return 1 << ioat->alloc_order;
+ /* check that we got off the ground */
+ udelay(5);
+ status = ioat_chansts(chan);
+ if (is_ioat_active(status) || is_ioat_idle(status)) {
+ set_bit(IOAT_RUN, &chan->state);
+ return 1 << ioat->alloc_order;
+ } else {
+ u32 chanerr = readl(chan->reg_base + IOAT_CHANERR_OFFSET);
+
+ dev_WARN(to_dev(chan),
+ "failed to start channel chanerr: %#x\n", chanerr);
+ ioat2_free_chan_resources(c);
+ return -EFAULT;
+ }
}
bool reshape_ring(struct ioat2_dma_chan *ioat, int order)
@@ -776,6 +795,7 @@ void ioat2_free_chan_resources(struct dma_chan *c)
del_timer_sync(&chan->timer);
device->cleanup_fn((unsigned long) c);
device->reset_hw(chan);
+ clear_bit(IOAT_RUN, &chan->state);
spin_lock_bh(&ioat->ring_lock);
descs = ioat2_ring_space(ioat);
diff --git a/drivers/dma/ioat/dma_v3.c b/drivers/dma/ioat/dma_v3.c
index 6740e31..52b1e3d 100644
--- a/drivers/dma/ioat/dma_v3.c
+++ b/drivers/dma/ioat/dma_v3.c
@@ -401,7 +401,10 @@ static void ioat3_timer_event(unsigned long data)
chanerr = readl(chan->reg_base + IOAT_CHANERR_OFFSET);
dev_err(to_dev(chan), "%s: Channel halted (%x)\n",
__func__, chanerr);
- BUG_ON(is_ioat_bug(chanerr));
+ if (test_bit(IOAT_RUN, &chan->state))
+ BUG_ON(is_ioat_bug(chanerr));
+ else /* we never got off the ground */
+ return;
}
/* if we haven't made progress and we have already
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
index 4173125..f4ba2e5 100644
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -3032,6 +3032,34 @@ static void __init iommu_exit_mempool(void)
}
+static void quirk_ioat_snb_local_iommu(struct pci_dev *pdev)
+{
+ struct dmar_drhd_unit *drhd;
+ u32 vtbar;
+ int rc;
+
+ /* We know that this device on this chipset has its own IOMMU.
+ * If we find it under a different IOMMU, then the BIOS is lying
+ * to us. Hope that the IOMMU for this device is actually
+ * disabled, and it needs no translation...
+ */
+ rc = pci_bus_read_config_dword(pdev->bus, PCI_DEVFN(0, 0), 0xb0, &vtbar);
+ if (rc) {
+ /* "can't" happen */
+ dev_info(&pdev->dev, "failed to run vt-d quirk\n");
+ return;
+ }
+ vtbar &= 0xffff0000;
+
+ /* we know that the this iommu should be at offset 0xa000 from vtbar */
+ drhd = dmar_find_matched_drhd_unit(pdev);
+ if (WARN_TAINT_ONCE(!drhd || drhd->reg_base_addr - vtbar != 0xa000,
+ TAINT_FIRMWARE_WORKAROUND,
+ "BIOS assigned incorrect VT-d unit for Intel(R) QuickData Technology device\n"))
+ pdev->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
+}
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB, quirk_ioat_snb_local_iommu);
+
static void __init init_no_remapping_devices(void)
{
struct dmar_drhd_unit *drhd;
--
1.7.3.3

View File

@ -875,6 +875,8 @@ Patch13802: xfs-properly-account-for-reclaimed-inodes.patch
Patch13900: ima-allow-it-to-be-completely-disabled-and-default-off.patch
Patch13901: ioat2-catch-and-recover-from-broken-vtd-configurations.patch
%endif
BuildRoot: %{_tmppath}/kernel-%{KVERREL}-root
@ -1673,6 +1675,9 @@ ApplyPatch xfs-properly-account-for-reclaimed-inodes.patch
# disable IMA by default as we did in F-14
ApplyPatch ima-allow-it-to-be-completely-disabled-and-default-off.patch
# rhbz605845 [556ab45f]
ApplyPatch ioat2-catch-and-recover-from-broken-vtd-configurations.patch
# END OF PATCH APPLICATIONS
%endif
@ -2294,6 +2299,10 @@ fi
%changelog
* Thu Dec 09 2010 Kyle McMartin <kyle@redhat.com>
- ioat2-catch-and-recover-from-broken-vtd-configurations.patch: copy patch
from 2.6.35.y (#605845) [556ab45f]
* Thu Dec 09 2010 Kyle McMartin <kyle@redhat.com>
- Copy tpm-fix-stall-on-boot.patch from rawhide tree. (#530393)