From 4b57f309c7962bd00d2c413b3cda2ff8d1d7bbbd Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Thu, 9 Dec 2010 17:53:54 -0500 Subject: [PATCH] ioat2: catch and recover from broken vtd configurations v6 --- ...cover-from-broken-vtd-configurations.patch | 167 ++++++++++++++++++ kernel.spec | 9 + 2 files changed, 176 insertions(+) create mode 100644 ioat2-catch-and-recover-from-broken-vtd-configurations.patch diff --git a/ioat2-catch-and-recover-from-broken-vtd-configurations.patch b/ioat2-catch-and-recover-from-broken-vtd-configurations.patch new file mode 100644 index 000000000..1f395ed09 --- /dev/null +++ b/ioat2-catch-and-recover-from-broken-vtd-configurations.patch @@ -0,0 +1,167 @@ +From 547c01ae2608ffe89d18441ea209aff0540e83ec Mon Sep 17 00:00:00 2001 +From: Kyle McMartin +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: +Acked-by: David Woodhouse +Reported-by: Chris Li +Tested-by: Chris Li +Signed-off-by: Dan Williams + +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 + diff --git a/kernel.spec b/kernel.spec index d0ebb5e2f..0779ca963 100644 --- a/kernel.spec +++ b/kernel.spec @@ -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 +- ioat2-catch-and-recover-from-broken-vtd-configurations.patch: copy patch + from 2.6.35.y (#605845) [556ab45f] + * Thu Dec 09 2010 Kyle McMartin - Copy tpm-fix-stall-on-boot.patch from rawhide tree. (#530393)