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

Configure Feed

Select the types of activity you want to include in your feed.

drm/panfrost: Handle page mapping failure

When mapping the pages of a BO, either a heap type at page fault time or
else a non-heap BO at object creation time, if the ARM page table mapping
function fails, we unmap what had been mapped so far and bail out.

Reviewed-by: Steven Price <steven.price@arm.com>
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: Adrián Larumbe <adrian.larumbe@collabora.com>
Link: https://lore.kernel.org/r/20251019145225.3621989-7-adrian.larumbe@collabora.com
Signed-off-by: Steven Price <steven.price@arm.com>

authored by

Adrián Larumbe and committed by
Steven Price
4da352cf 3d7c6267

+44 -5
+44 -5
drivers/gpu/drm/panfrost/panfrost_mmu.c
··· 395 395 pm_runtime_put_autosuspend(pfdev->base.dev); 396 396 } 397 397 398 + static void mmu_unmap_range(struct panfrost_mmu *mmu, u64 iova, size_t len) 399 + { 400 + struct io_pgtable_ops *ops = mmu->pgtbl_ops; 401 + size_t pgsize, unmapped_len = 0; 402 + size_t unmapped_page, pgcount; 403 + 404 + while (unmapped_len < len) { 405 + pgsize = get_pgsize(iova, len - unmapped_len, &pgcount); 406 + 407 + unmapped_page = ops->unmap_pages(ops, iova, pgsize, pgcount, NULL); 408 + WARN_ON(unmapped_page != pgsize * pgcount); 409 + 410 + iova += pgsize * pgcount; 411 + unmapped_len += pgsize * pgcount; 412 + } 413 + } 414 + 398 415 static int mmu_map_sg(struct panfrost_device *pfdev, struct panfrost_mmu *mmu, 399 416 u64 iova, int prot, struct sg_table *sgt) 400 417 { 401 418 unsigned int count; 402 419 struct scatterlist *sgl; 403 420 struct io_pgtable_ops *ops = mmu->pgtbl_ops; 421 + size_t total_mapped = 0; 404 422 u64 start_iova = iova; 423 + int ret; 405 424 406 425 for_each_sgtable_dma_sg(sgt, sgl, count) { 407 426 unsigned long paddr = sg_dma_address(sgl); ··· 434 415 size_t pgcount, mapped = 0; 435 416 size_t pgsize = get_pgsize(iova | paddr, len, &pgcount); 436 417 437 - ops->map_pages(ops, iova, paddr, pgsize, pgcount, prot, 418 + ret = ops->map_pages(ops, iova, paddr, pgsize, pgcount, prot, 438 419 GFP_KERNEL, &mapped); 420 + if (ret) 421 + goto err_unmap_pages; 422 + 439 423 /* Don't get stuck if things have gone wrong */ 440 424 mapped = max(mapped, pgsize); 425 + total_mapped += mapped; 441 426 iova += mapped; 442 427 paddr += mapped; 443 428 len -= mapped; ··· 451 428 panfrost_mmu_flush_range(pfdev, mmu, start_iova, iova - start_iova); 452 429 453 430 return 0; 431 + 432 + err_unmap_pages: 433 + mmu_unmap_range(mmu, start_iova, total_mapped); 434 + return ret; 454 435 } 455 436 456 437 int panfrost_mmu_map(struct panfrost_gem_mapping *mapping) ··· 465 438 struct panfrost_device *pfdev = to_panfrost_device(obj->dev); 466 439 struct sg_table *sgt; 467 440 int prot = IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE; 441 + int ret; 468 442 469 443 if (WARN_ON(mapping->active)) 470 444 return 0; ··· 477 449 if (WARN_ON(IS_ERR(sgt))) 478 450 return PTR_ERR(sgt); 479 451 480 - mmu_map_sg(pfdev, mapping->mmu, mapping->mmnode.start << PAGE_SHIFT, 481 - prot, sgt); 452 + ret = mmu_map_sg(pfdev, mapping->mmu, mapping->mmnode.start << PAGE_SHIFT, 453 + prot, sgt); 454 + if (ret) 455 + goto err_put_pages; 456 + 482 457 mapping->active = true; 483 458 484 459 return 0; 460 + 461 + err_put_pages: 462 + drm_gem_shmem_put_pages_locked(shmem); 463 + return ret; 485 464 } 486 465 487 466 void panfrost_mmu_unmap(struct panfrost_gem_mapping *mapping) ··· 673 638 if (ret) 674 639 goto err_map; 675 640 676 - mmu_map_sg(pfdev, bomapping->mmu, addr, 677 - IOMMU_WRITE | IOMMU_READ | IOMMU_CACHE | IOMMU_NOEXEC, sgt); 641 + ret = mmu_map_sg(pfdev, bomapping->mmu, addr, 642 + IOMMU_WRITE | IOMMU_READ | IOMMU_CACHE | IOMMU_NOEXEC, sgt); 643 + if (ret) 644 + goto err_mmu_map_sg; 678 645 679 646 bomapping->active = true; 680 647 bo->heap_rss_size += SZ_2M; ··· 690 653 691 654 return 0; 692 655 656 + err_mmu_map_sg: 657 + dma_unmap_sgtable(pfdev->base.dev, sgt, DMA_BIDIRECTIONAL, 0); 693 658 err_map: 694 659 sg_free_table(sgt); 695 660 err_unlock: