[PATCH v2] powerpc/iommu: DMA address offset is incorrectly calculated with 2MB TCEs
Michael Ellerman
mpe at ellerman.id.au
Fri Apr 21 01:21:51 AEST 2023
Gaurav Batra <gbatra at linux.vnet.ibm.com> writes:
> When DMA window is backed by 2MB TCEs, the DMA address for the mapped
> page should be the offset of the page relative to the 2MB TCE. The code
> was incorrectly setting the DMA address to the beginning of the TCE
> range.
>
> Mellanox driver is reporting timeout trying to ENABLE_HCA for an SR-IOV
> ethernet port, when DMA window is backed by 2MB TCEs.
I assume this is similar or related to the bug Srikar reported?
https://lore.kernel.org/linuxppc-dev/20230323095333.GI1005120@linux.vnet.ibm.com/
In that thread Alexey suggested a patch, have you tried his patch? He
suggested rounding up the allocation size, rather than adjusting the
dma_handle.
> Fixes: 3872731187141d5d0a5c4fb30007b8b9ec36a44d
That's not the right syntax, it's described in the documentation how to
generate it.
It should be:
Fixes: 387273118714 ("powerps/pseries/dma: Add support for 2M IOMMU page size")
cheers
> diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
> index ee95937bdaf1..ca57526ce47a 100644
> --- a/arch/powerpc/kernel/iommu.c
> +++ b/arch/powerpc/kernel/iommu.c
> @@ -517,7 +517,7 @@ int ppc_iommu_map_sg(struct device *dev, struct iommu_table *tbl,
> /* Convert entry to a dma_addr_t */
> entry += tbl->it_offset;
> dma_addr = entry << tbl->it_page_shift;
> - dma_addr |= (s->offset & ~IOMMU_PAGE_MASK(tbl));
> + dma_addr |= (vaddr & ~IOMMU_PAGE_MASK(tbl));
>
> DBG(" - %lu pages, entry: %lx, dma_addr: %lx\n",
> npages, entry, dma_addr);
> @@ -904,6 +904,7 @@ void *iommu_alloc_coherent(struct device *dev, struct iommu_table *tbl,
> unsigned int order;
> unsigned int nio_pages, io_order;
> struct page *page;
> + int tcesize = (1 << tbl->it_page_shift);
>
> size = PAGE_ALIGN(size);
> order = get_order(size);
> @@ -930,7 +931,8 @@ void *iommu_alloc_coherent(struct device *dev, struct iommu_table *tbl,
> memset(ret, 0, size);
>
> /* Set up tces to cover the allocated range */
> - nio_pages = size >> tbl->it_page_shift;
> + nio_pages = IOMMU_PAGE_ALIGN(size, tbl) >> tbl->it_page_shift;
> +
> io_order = get_iommu_order(size, tbl);
> mapping = iommu_alloc(dev, tbl, ret, nio_pages, DMA_BIDIRECTIONAL,
> mask >> tbl->it_page_shift, io_order, 0);
> @@ -938,7 +940,8 @@ void *iommu_alloc_coherent(struct device *dev, struct iommu_table *tbl,
> free_pages((unsigned long)ret, order);
> return NULL;
> }
> - *dma_handle = mapping;
> +
> + *dma_handle = mapping | ((u64)ret & (tcesize - 1));
> return ret;
> }
>
> --
More information about the Linuxppc-dev
mailing list