Skip to content

Commit 3c0468d

Browse files
LeoBrasmpe
authored andcommitted
powerpc/kernel/iommu: Align size for IOMMU_PAGE_SIZE() to save TCEs
Currently both iommu_alloc_coherent() and iommu_free_coherent() align the desired allocation size to PAGE_SIZE, and gets system pages and IOMMU mappings (TCEs) for that value. When IOMMU_PAGE_SIZE < PAGE_SIZE, this behavior may cause unnecessary TCEs to be created for mapping the whole system page. Example: - PAGE_SIZE = 64k, IOMMU_PAGE_SIZE() = 4k - iommu_alloc_coherent() is called for 128 bytes - 1 system page (64k) is allocated - 16 IOMMU pages (16 x 4k) are allocated (16 TCEs used) It would be enough to use a single TCE for this, so 15 TCEs are wasted in the process. Update iommu_*_coherent() to make sure the size alignment happens only for IOMMU_PAGE_SIZE() before calling iommu_alloc() and iommu_free(). Also, on iommu_range_alloc(), replace ALIGN(n, 1 << tbl->it_page_shift) with IOMMU_PAGE_ALIGN(n, tbl), which is easier to read and does the same. Signed-off-by: Leonardo Bras <[email protected]> Reviewed-by: Alexey Kardashevskiy <[email protected]> Signed-off-by: Michael Ellerman <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent ee6b25f commit 3c0468d

File tree

1 file changed

+6
-5
lines changed

1 file changed

+6
-5
lines changed

arch/powerpc/kernel/iommu.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -889,6 +889,7 @@ void *iommu_alloc_coherent(struct device *dev, struct iommu_table *tbl,
889889
unsigned int order;
890890
unsigned int nio_pages, io_order;
891891
struct page *page;
892+
size_t size_io = size;
892893

893894
size = PAGE_ALIGN(size);
894895
order = get_order(size);
@@ -915,8 +916,9 @@ void *iommu_alloc_coherent(struct device *dev, struct iommu_table *tbl,
915916
memset(ret, 0, size);
916917

917918
/* Set up tces to cover the allocated range */
918-
nio_pages = size >> tbl->it_page_shift;
919-
io_order = get_iommu_order(size, tbl);
919+
size_io = IOMMU_PAGE_ALIGN(size_io, tbl);
920+
nio_pages = size_io >> tbl->it_page_shift;
921+
io_order = get_iommu_order(size_io, tbl);
920922
mapping = iommu_alloc(dev, tbl, ret, nio_pages, DMA_BIDIRECTIONAL,
921923
mask >> tbl->it_page_shift, io_order, 0);
922924
if (mapping == DMA_MAPPING_ERROR) {
@@ -931,10 +933,9 @@ void iommu_free_coherent(struct iommu_table *tbl, size_t size,
931933
void *vaddr, dma_addr_t dma_handle)
932934
{
933935
if (tbl) {
934-
unsigned int nio_pages;
936+
size_t size_io = IOMMU_PAGE_ALIGN(size, tbl);
937+
unsigned int nio_pages = size_io >> tbl->it_page_shift;
935938

936-
size = PAGE_ALIGN(size);
937-
nio_pages = size >> tbl->it_page_shift;
938939
iommu_free(tbl, dma_handle, nio_pages);
939940
size = PAGE_ALIGN(size);
940941
free_pages((unsigned long)vaddr, get_order(size));

0 commit comments

Comments
 (0)