Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

arm64/dma-mapping: Fix sizes in __iommu_{alloc,free}_attrs

The iommu-dma layer does its own size-alignment for coherent DMA
allocations based on IOMMU page sizes, but we still need to consider
CPU page sizes for the cases where a non-cacheable CPU mapping is
created. Whilst everything on the alloc/map path seems to implicitly
align things enough to make it work, some functions used by the
corresponding unmap/free path do not, which leads to problems freeing
odd-sized allocations. Either way it's something we really should be
handling explicitly, so do that to make both paths suitably robust.

Reported-by: Yong Wu <yong.wu@mediatek.com>
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>

authored by

Robin Murphy and committed by
Catalin Marinas
bd1c6ff7 8005c49d

+13 -6
+13 -6
arch/arm64/mm/dma-mapping.c
··· 552 552 { 553 553 bool coherent = is_device_dma_coherent(dev); 554 554 int ioprot = dma_direction_to_prot(DMA_BIDIRECTIONAL, coherent); 555 + size_t iosize = size; 555 556 void *addr; 556 557 557 558 if (WARN(!dev, "cannot create IOMMU mapping for unknown device\n")) 558 559 return NULL; 560 + 561 + size = PAGE_ALIGN(size); 562 + 559 563 /* 560 564 * Some drivers rely on this, and we probably don't want the 561 565 * possibility of stale kernel data being read by devices anyway. ··· 570 566 struct page **pages; 571 567 pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL, coherent); 572 568 573 - pages = iommu_dma_alloc(dev, size, gfp, ioprot, handle, 569 + pages = iommu_dma_alloc(dev, iosize, gfp, ioprot, handle, 574 570 flush_page); 575 571 if (!pages) 576 572 return NULL; ··· 578 574 addr = dma_common_pages_remap(pages, size, VM_USERMAP, prot, 579 575 __builtin_return_address(0)); 580 576 if (!addr) 581 - iommu_dma_free(dev, pages, size, handle); 577 + iommu_dma_free(dev, pages, iosize, handle); 582 578 } else { 583 579 struct page *page; 584 580 /* ··· 595 591 if (!addr) 596 592 return NULL; 597 593 598 - *handle = iommu_dma_map_page(dev, page, 0, size, ioprot); 594 + *handle = iommu_dma_map_page(dev, page, 0, iosize, ioprot); 599 595 if (iommu_dma_mapping_error(dev, *handle)) { 600 596 if (coherent) 601 597 __free_pages(page, get_order(size)); ··· 610 606 static void __iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr, 611 607 dma_addr_t handle, struct dma_attrs *attrs) 612 608 { 609 + size_t iosize = size; 610 + 611 + size = PAGE_ALIGN(size); 613 612 /* 614 613 * @cpu_addr will be one of 3 things depending on how it was allocated: 615 614 * - A remapped array of pages from iommu_dma_alloc(), for all ··· 624 617 * Hence how dodgy the below logic looks... 625 618 */ 626 619 if (__in_atomic_pool(cpu_addr, size)) { 627 - iommu_dma_unmap_page(dev, handle, size, 0, NULL); 620 + iommu_dma_unmap_page(dev, handle, iosize, 0, NULL); 628 621 __free_from_pool(cpu_addr, size); 629 622 } else if (is_vmalloc_addr(cpu_addr)){ 630 623 struct vm_struct *area = find_vm_area(cpu_addr); 631 624 632 625 if (WARN_ON(!area || !area->pages)) 633 626 return; 634 - iommu_dma_free(dev, area->pages, size, &handle); 627 + iommu_dma_free(dev, area->pages, iosize, &handle); 635 628 dma_common_free_remap(cpu_addr, size, VM_USERMAP); 636 629 } else { 637 - iommu_dma_unmap_page(dev, handle, size, 0, NULL); 630 + iommu_dma_unmap_page(dev, handle, iosize, 0, NULL); 638 631 __free_pages(virt_to_page(cpu_addr), get_order(size)); 639 632 } 640 633 }