lkml.org 
[lkml]   [2017]   [Sep]   [29]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    SubjectRe: [PATCH] iommu/vt-d: Fix scatterlist offset handling
    From
    Date
    Robin,

    I tried running patch on our test setup.

    With "intel_iommu=on" : I can see single occurrence of DMAR Write failure on perf traffic with 10 thread.

        [  749.616480] perf: interrupt took too long (3203 > 3202), lowering kernel.perf_event_max_sample_rate to 62000
    [  852.500671] DMAR: DRHD: handling fault status reg 2
    [  852.506039] DMAR: [DMA Write] Request device [02:00.4] fault addr ef919000 [fault reason 05] PTE Write access is not set
    [root@heptagon linux_t4_build]# cat /proc/cmdline
    BOOT_IMAGE=/vmlinuz-4.9.51+ root=UUID=ccbb7f18-b3f0-43df-89de-07521e9c02fe ro intel_iommu=on crashkernel=auto rhgb quiet rhgb quiet console=ttyS0,115200, console=tty0 LANG=en_US.UTF-8

    With intel_iommu=sp_off : It works fine for more than 30 minutes without any issues.


    On 28-09-2017 19:44, Robin Murphy wrote:
    > The intel-iommu DMA ops fail to correctly handle scatterlists where
    > sg->offset is greater than PAGE_SIZE - the IOVA allocation is computed
    > appropriately based on the page-aligned portion of the offset, but the
    > mapping is set up relative to sg->page, which means it fails to actually
    > cover the whole buffer (and in the worst case doesn't cover it at all):
    >
    > (sg->dma_address + sg->dma_len) ----+
    > sg->dma_address ---------+ |
    > iov_pfn------+ | |
    > | | |
    > v v v
    > iova: a b c d e f
    > |--------|--------|--------|--------|--------|
    > <...calculated....>
    > [_____mapped______]
    > pfn: 0 1 2 3 4 5
    > |--------|--------|--------|--------|--------|
    > ^ ^ ^
    > | | |
    > sg->page ----+ | |
    > sg->offset --------------+ |
    > (sg->offset + sg->length) ----------+
    >
    > As a result, the caller ends up overrunning the mapping into whatever
    > lies beyond, which usually goes badly:
    >
    > [ 429.645492] DMAR: DRHD: handling fault status reg 2
    > [ 429.650847] DMAR: [DMA Write] Request device [02:00.4] fault addr f2682000 ...
    >
    > Whilst this is a fairly rare occurrence, it can happen from the result
    > of intermediate scatterlist processing such as scatterwalk_ffwd() in the
    > crypto layer. Whilst that particular site could be fixed up, it still
    > seems worthwhile to bring intel-iommu in line with other DMA API
    > implementations in handling this robustly.
    >
    > To that end, fix the intel_map_sg() path to line up the mapping
    > correctly (in units of MM pages rather than VT-d pages to match the
    > aligned_nrpages() calculation) regardless of the offset, and use
    > sg_phys() consistently for clarity.
    >
    > Reported-by: Harsh Jain <Harsh@chelsio.com>
    > Signed-off-by: Robin Murphy <robin.murphy@arm.com>
    > ---
    > drivers/iommu/intel-iommu.c | 8 +++++---
    > 1 file changed, 5 insertions(+), 3 deletions(-)
    >
    > diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
    > index 6784a05dd6b2..83f3d4831f94 100644
    > --- a/drivers/iommu/intel-iommu.c
    > +++ b/drivers/iommu/intel-iommu.c
    > @@ -2254,10 +2254,12 @@ static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
    > uint64_t tmp;
    >
    > if (!sg_res) {
    > + unsigned int pgoff = sg->offset & ~PAGE_MASK;
    > +
    > sg_res = aligned_nrpages(sg->offset, sg->length);
    > - sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + sg->offset;
    > + sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + pgoff;
    > sg->dma_length = sg->length;
    > - pteval = page_to_phys(sg_page(sg)) | prot;
    > + pteval = (sg_phys(sg) - pgoff) | prot;
    > phys_pfn = pteval >> VTD_PAGE_SHIFT;
    > }
    >
    > @@ -3790,7 +3792,7 @@ static int intel_nontranslate_map_sg(struct device *hddev,
    >
    > for_each_sg(sglist, sg, nelems, i) {
    > BUG_ON(!sg_page(sg));
    > - sg->dma_address = page_to_phys(sg_page(sg)) + sg->offset;
    > + sg->dma_address = sg_phys(sg);
    > sg->dma_length = sg->length;
    > }
    > return nelems;

    \
     
     \ /
      Last update: 2017-09-29 10:16    [W:5.550 / U:0.228 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site