Skip to content

Commit f5b8794

Browse files
cyndisthierryreding
authored andcommitted
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
1 parent 4ed0956 commit f5b8794

File tree

2 files changed

+57
-30
lines changed

2 files changed

+57
-30
lines changed

drivers/gpu/drm/tegra/gem.c

Lines changed: 36 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ static struct host1x_bo_mapping *tegra_bo_pin(struct device *dev, struct host1x_
7676
/*
7777
* Imported buffers need special treatment to satisfy the semantics of DMA-BUF.
7878
*/
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;
8181

8282
map->attach = dma_buf_attach(buf, dev);
8383
if (IS_ERR(map->attach)) {
@@ -184,8 +184,8 @@ static void *tegra_bo_mmap(struct host1x_bo *bo)
184184
if (obj->vaddr)
185185
return obj->vaddr;
186186

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);
189189
if (ret < 0)
190190
return ERR_PTR(ret);
191191

@@ -208,8 +208,8 @@ static void tegra_bo_munmap(struct host1x_bo *bo, void *addr)
208208
if (obj->vaddr)
209209
return;
210210

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);
213213

214214
vunmap(addr);
215215
}
@@ -465,27 +465,32 @@ static struct tegra_bo *tegra_bo_import(struct drm_device *drm,
465465
if (IS_ERR(bo))
466466
return bo;
467467

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);
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+
*/
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+
}
475478

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-
}
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+
}
481484

482-
if (tegra->domain) {
483485
err = tegra_bo_iommu_map(tegra, bo);
484486
if (err < 0)
485487
goto detach;
488+
489+
bo->gem.import_attach = attach;
486490
}
487491

488-
bo->gem.import_attach = attach;
492+
get_dma_buf(buf);
493+
bo->dma_buf = buf;
489494

490495
return bo;
491496

@@ -516,20 +521,21 @@ void tegra_bo_free_object(struct drm_gem_object *gem)
516521
dev_name(mapping->dev));
517522
}
518523

519-
if (tegra->domain)
524+
if (tegra->domain) {
520525
tegra_bo_iommu_unmap(tegra, bo);
521526

522-
if (gem->import_attach) {
523-
struct dma_buf *dmabuf = gem->import_attach->dmabuf;
524-
525-
dma_buf_unmap_attachment_unlocked(gem->import_attach, bo->sgt,
526-
DMA_TO_DEVICE);
527-
dma_buf_detach(dmabuf, gem->import_attach);
528-
dma_buf_put(dmabuf);
529-
} else {
530-
tegra_bo_free(gem->dev, bo);
527+
if (gem->import_attach) {
528+
dma_buf_unmap_attachment_unlocked(gem->import_attach, bo->sgt,
529+
DMA_TO_DEVICE);
530+
dma_buf_detach(gem->import_attach->dmabuf, gem->import_attach);
531+
}
531532
}
532533

534+
tegra_bo_free(gem->dev, bo);
535+
536+
if (bo->dma_buf)
537+
dma_buf_put(bo->dma_buf);
538+
533539
drm_gem_object_release(gem);
534540
kfree(bo);
535541
}

drivers/gpu/drm/tegra/gem.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,34 @@ struct tegra_bo_tiling {
3232
enum tegra_bo_sector_layout sector_layout;
3333
};
3434

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+
*/
3555
struct tegra_bo {
3656
struct drm_gem_object gem;
3757
struct host1x_bo base;
3858
unsigned long flags;
3959
struct sg_table *sgt;
4060
dma_addr_t iova;
4161
void *vaddr;
62+
struct dma_buf *dma_buf;
4263

4364
struct drm_mm_node *mm;
4465
unsigned long num_pages;

0 commit comments

Comments
 (0)