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/tegra: gem: Don't attach dma-bufs when not needed

The dma-buf import code currently attaches and maps all imported
dma-bufs to the drm device to get their sgt for mapping to the
directly managed IOMMU domain.

In many cases, like for newer chips (Tegra186+), the directly
managed IOMMU domain is, however, not used. Mapping to the drm
device can also cause issues e.g. with swiotlb since it is not
a real device.

To improve the situation, only attach and map imported dma-bufs
when required.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240424051335.2872574-2-cyndis@kapsi.fi

authored by

Mikko Perttunen and committed by
Thierry Reding
f5b8794e 4ed09565

+58 -31
+37 -31
drivers/gpu/drm/tegra/gem.c
··· 76 76 /* 77 77 * Imported buffers need special treatment to satisfy the semantics of DMA-BUF. 78 78 */ 79 - if (gem->import_attach) { 80 - struct dma_buf *buf = gem->import_attach->dmabuf; 79 + if (obj->dma_buf) { 80 + struct dma_buf *buf = obj->dma_buf; 81 81 82 82 map->attach = dma_buf_attach(buf, dev); 83 83 if (IS_ERR(map->attach)) { ··· 184 184 if (obj->vaddr) 185 185 return obj->vaddr; 186 186 187 - if (obj->gem.import_attach) { 188 - ret = dma_buf_vmap_unlocked(obj->gem.import_attach->dmabuf, &map); 187 + if (obj->dma_buf) { 188 + ret = dma_buf_vmap_unlocked(obj->dma_buf, &map); 189 189 if (ret < 0) 190 190 return ERR_PTR(ret); 191 191 ··· 208 208 if (obj->vaddr) 209 209 return; 210 210 211 - if (obj->gem.import_attach) 212 - return dma_buf_vunmap_unlocked(obj->gem.import_attach->dmabuf, &map); 211 + if (obj->dma_buf) 212 + return dma_buf_vunmap_unlocked(obj->dma_buf, &map); 213 213 214 214 vunmap(addr); 215 215 } ··· 465 465 if (IS_ERR(bo)) 466 466 return bo; 467 467 468 - attach = dma_buf_attach(buf, drm->dev); 469 - if (IS_ERR(attach)) { 470 - err = PTR_ERR(attach); 471 - goto free; 472 - } 473 - 474 - get_dma_buf(buf); 475 - 476 - bo->sgt = dma_buf_map_attachment_unlocked(attach, DMA_TO_DEVICE); 477 - if (IS_ERR(bo->sgt)) { 478 - err = PTR_ERR(bo->sgt); 479 - goto detach; 480 - } 481 - 468 + /* 469 + * If we need to use IOMMU API to map the dma-buf into the internally managed 470 + * domain, map it first to the DRM device to get an sgt. 471 + */ 482 472 if (tegra->domain) { 473 + attach = dma_buf_attach(buf, drm->dev); 474 + if (IS_ERR(attach)) { 475 + err = PTR_ERR(attach); 476 + goto free; 477 + } 478 + 479 + bo->sgt = dma_buf_map_attachment_unlocked(attach, DMA_TO_DEVICE); 480 + if (IS_ERR(bo->sgt)) { 481 + err = PTR_ERR(bo->sgt); 482 + goto detach; 483 + } 484 + 483 485 err = tegra_bo_iommu_map(tegra, bo); 484 486 if (err < 0) 485 487 goto detach; 488 + 489 + bo->gem.import_attach = attach; 486 490 } 487 491 488 - bo->gem.import_attach = attach; 492 + get_dma_buf(buf); 493 + bo->dma_buf = buf; 489 494 490 495 return bo; 491 496 ··· 521 516 dev_name(mapping->dev)); 522 517 } 523 518 524 - if (tegra->domain) 519 + if (tegra->domain) { 525 520 tegra_bo_iommu_unmap(tegra, bo); 526 521 527 - if (gem->import_attach) { 528 - struct dma_buf *dmabuf = gem->import_attach->dmabuf; 529 - 530 - dma_buf_unmap_attachment_unlocked(gem->import_attach, bo->sgt, 531 - DMA_TO_DEVICE); 532 - dma_buf_detach(dmabuf, gem->import_attach); 533 - dma_buf_put(dmabuf); 534 - } else { 535 - tegra_bo_free(gem->dev, bo); 522 + if (gem->import_attach) { 523 + dma_buf_unmap_attachment_unlocked(gem->import_attach, bo->sgt, 524 + DMA_TO_DEVICE); 525 + dma_buf_detach(gem->import_attach->dmabuf, gem->import_attach); 526 + } 536 527 } 528 + 529 + tegra_bo_free(gem->dev, bo); 530 + 531 + if (bo->dma_buf) 532 + dma_buf_put(bo->dma_buf); 537 533 538 534 drm_gem_object_release(gem); 539 535 kfree(bo);
+21
drivers/gpu/drm/tegra/gem.h
··· 32 32 enum tegra_bo_sector_layout sector_layout; 33 33 }; 34 34 35 + /* 36 + * How memory is referenced within a tegra_bo: 37 + * 38 + * Buffer source | Mapping API(*) | Fields 39 + * ---------------+-----------------+--------------- 40 + * Allocated here | DMA API | iova (IOVA mapped to drm->dev), vaddr (CPU VA) 41 + * 42 + * Allocated here | IOMMU API | pages/num_pages (Phys. memory), sgt (Mapped to drm->dev), 43 + * | iova/size (Mapped to domain) 44 + * 45 + * Imported | DMA API | dma_buf (Imported dma_buf) 46 + * 47 + * Imported | IOMMU API | dma_buf (Imported dma_buf), 48 + * | gem->import_attach (Attachment on drm->dev), 49 + * | sgt (Mapped to drm->dev) 50 + * | iova/size (Mapped to domain) 51 + * 52 + * (*) If tegra->domain is set, i.e. TegraDRM IOMMU domain is directly managed through IOMMU API, 53 + * this is IOMMU API. Otherwise DMA API. 54 + */ 35 55 struct tegra_bo { 36 56 struct drm_gem_object gem; 37 57 struct host1x_bo base; ··· 59 39 struct sg_table *sgt; 60 40 dma_addr_t iova; 61 41 void *vaddr; 42 + struct dma_buf *dma_buf; 62 43 63 44 struct drm_mm_node *mm; 64 45 unsigned long num_pages;