lkml.org 
[lkml]   [2010]   [Aug]   [11]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[31/67] ioat2: catch and recover from broken vtd configurations v6
    2.6.35-stable review patch.  If anyone has any objections, please let us know.

    ------------------

    From: Dan Williams <dan.j.williams@intel.com>

    commit 556ab45f9a775bfa4762bacc0a4afb5b44b067bc upstream.

    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.

    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>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

    ---
    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(-)

    --- a/drivers/dma/ioat/dma.h
    +++ b/drivers/dma/ioat/dma.h
    @@ -97,6 +97,7 @@ struct ioat_chan_common {
    #define IOAT_RESET_PENDING 2
    #define IOAT_KOBJ_INIT_FAIL 3
    #define IOAT_RESHAPE_PENDING 4
    + #define IOAT_RUN 5
    struct timer_list timer;
    #define COMPLETION_TIMEOUT msecs_to_jiffies(100)
    #define IDLE_TIMEOUT msecs_to_jiffies(2000)
    --- a/drivers/dma/ioat/dma_v2.c
    +++ b/drivers/dma/ioat/dma_v2.c
    @@ -287,7 +287,10 @@ void ioat2_timer_event(unsigned long dat
    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
    @@ -492,6 +495,8 @@ static struct ioat_ring_ent **ioat2_allo
    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
    */
    @@ -500,6 +505,7 @@ int ioat2_alloc_chan_resources(struct dm
    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? */
    @@ -540,7 +546,20 @@ int ioat2_alloc_chan_resources(struct dm
    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)
    @@ -778,6 +797,7 @@ void ioat2_free_chan_resources(struct dm
    del_timer_sync(&chan->timer);
    device->cleanup_fn((unsigned long) c);
    device->reset_hw(chan);
    + clear_bit(IOAT_RUN, &chan->state);

    spin_lock_bh(&chan->cleanup_lock);
    spin_lock_bh(&ioat->prep_lock);
    --- a/drivers/dma/ioat/dma_v3.c
    +++ b/drivers/dma/ioat/dma_v3.c
    @@ -361,7 +361,10 @@ static void ioat3_timer_event(unsigned l
    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
    --- a/drivers/pci/intel-iommu.c
    +++ b/drivers/pci/intel-iommu.c
    @@ -3030,6 +3030,34 @@ static void __init iommu_exit_mempool(vo

    }

    +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;



    \
     
     \ /
      Last update: 2010-08-12 02:17    [W:2.310 / U:0.460 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site