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 <ha...@chelsio.com>
> Signed-off-by: Robin Murphy <robin.mur...@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;

_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Reply via email to