Skip to content

Commit f44ffd6

Browse files
drm/amdgpu: add support for exporting VRAM using DMA-buf v3
We should be able to do this now after checking all the prerequisites. v2: fix entrie count in the sgt v3: manually construct the sg Signed-off-by: Christian König <[email protected]> Acked-by: Daniel Vetter <[email protected]> Acked-by: Sumit Semwal <[email protected]> Link: https://patchwork.freedesktop.org/patch/359295
1 parent 48262cd commit f44ffd6

File tree

3 files changed

+153
-14
lines changed

3 files changed

+153
-14
lines changed

drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -276,14 +276,21 @@ static struct sg_table *amdgpu_dma_buf_map(struct dma_buf_attachment *attach,
276276
struct dma_buf *dma_buf = attach->dmabuf;
277277
struct drm_gem_object *obj = dma_buf->priv;
278278
struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
279+
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
279280
struct sg_table *sgt;
280281
long r;
281282

282283
if (!bo->pin_count) {
283-
/* move buffer into GTT */
284+
/* move buffer into GTT or VRAM */
284285
struct ttm_operation_ctx ctx = { false, false };
286+
unsigned domains = AMDGPU_GEM_DOMAIN_GTT;
285287

286-
amdgpu_bo_placement_from_domain(bo, AMDGPU_GEM_DOMAIN_GTT);
288+
if (bo->preferred_domains & AMDGPU_GEM_DOMAIN_VRAM &&
289+
attach->peer2peer) {
290+
bo->flags |= AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED;
291+
domains |= AMDGPU_GEM_DOMAIN_VRAM;
292+
}
293+
amdgpu_bo_placement_from_domain(bo, domains);
287294
r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
288295
if (r)
289296
return ERR_PTR(r);
@@ -293,20 +300,34 @@ static struct sg_table *amdgpu_dma_buf_map(struct dma_buf_attachment *attach,
293300
return ERR_PTR(-EBUSY);
294301
}
295302

296-
sgt = drm_prime_pages_to_sg(bo->tbo.ttm->pages, bo->tbo.num_pages);
297-
if (IS_ERR(sgt))
298-
return sgt;
299-
300-
if (!dma_map_sg_attrs(attach->dev, sgt->sgl, sgt->nents, dir,
301-
DMA_ATTR_SKIP_CPU_SYNC))
302-
goto error_free;
303+
switch (bo->tbo.mem.mem_type) {
304+
case TTM_PL_TT:
305+
sgt = drm_prime_pages_to_sg(bo->tbo.ttm->pages,
306+
bo->tbo.num_pages);
307+
if (IS_ERR(sgt))
308+
return sgt;
309+
310+
if (!dma_map_sg_attrs(attach->dev, sgt->sgl, sgt->nents, dir,
311+
DMA_ATTR_SKIP_CPU_SYNC))
312+
goto error_free;
313+
break;
314+
315+
case TTM_PL_VRAM:
316+
r = amdgpu_vram_mgr_alloc_sgt(adev, &bo->tbo.mem, attach->dev,
317+
dir, &sgt);
318+
if (r)
319+
return ERR_PTR(r);
320+
break;
321+
default:
322+
return ERR_PTR(-EINVAL);
323+
}
303324

304325
return sgt;
305326

306327
error_free:
307328
sg_free_table(sgt);
308329
kfree(sgt);
309-
return ERR_PTR(-ENOMEM);
330+
return ERR_PTR(-EBUSY);
310331
}
311332

312333
/**
@@ -322,9 +343,18 @@ static void amdgpu_dma_buf_unmap(struct dma_buf_attachment *attach,
322343
struct sg_table *sgt,
323344
enum dma_data_direction dir)
324345
{
325-
dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents, dir);
326-
sg_free_table(sgt);
327-
kfree(sgt);
346+
struct dma_buf *dma_buf = attach->dmabuf;
347+
struct drm_gem_object *obj = dma_buf->priv;
348+
struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
349+
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
350+
351+
if (sgt->sgl->page_link) {
352+
dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents, dir);
353+
sg_free_table(sgt);
354+
kfree(sgt);
355+
} else {
356+
amdgpu_vram_mgr_free_sgt(adev, attach->dev, dir, sgt);
357+
}
328358
}
329359

330360
/**

drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,9 @@
2424
#ifndef __AMDGPU_TTM_H__
2525
#define __AMDGPU_TTM_H__
2626

27-
#include "amdgpu.h"
27+
#include <linux/dma-direction.h>
2828
#include <drm/gpu_scheduler.h>
29+
#include "amdgpu.h"
2930

3031
#define AMDGPU_PL_GDS (TTM_PL_PRIV + 0)
3132
#define AMDGPU_PL_GWS (TTM_PL_PRIV + 1)
@@ -74,6 +75,15 @@ uint64_t amdgpu_gtt_mgr_usage(struct ttm_mem_type_manager *man);
7475
int amdgpu_gtt_mgr_recover(struct ttm_mem_type_manager *man);
7576

7677
u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo);
78+
int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev,
79+
struct ttm_mem_reg *mem,
80+
struct device *dev,
81+
enum dma_data_direction dir,
82+
struct sg_table **sgt);
83+
void amdgpu_vram_mgr_free_sgt(struct amdgpu_device *adev,
84+
struct device *dev,
85+
enum dma_data_direction dir,
86+
struct sg_table *sgt);
7787
uint64_t amdgpu_vram_mgr_usage(struct ttm_mem_type_manager *man);
7888
uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_mem_type_manager *man);
7989

drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
* Authors: Christian König
2323
*/
2424

25+
#include <linux/dma-mapping.h>
2526
#include "amdgpu.h"
2627
#include "amdgpu_vm.h"
2728
#include "amdgpu_atomfirmware.h"
@@ -458,6 +459,104 @@ static void amdgpu_vram_mgr_del(struct ttm_mem_type_manager *man,
458459
mem->mm_node = NULL;
459460
}
460461

462+
/**
463+
* amdgpu_vram_mgr_alloc_sgt - allocate and fill a sg table
464+
*
465+
* @adev: amdgpu device pointer
466+
* @mem: TTM memory object
467+
* @dev: the other device
468+
* @dir: dma direction
469+
* @sgt: resulting sg table
470+
*
471+
* Allocate and fill a sg table from a VRAM allocation.
472+
*/
473+
int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev,
474+
struct ttm_mem_reg *mem,
475+
struct device *dev,
476+
enum dma_data_direction dir,
477+
struct sg_table **sgt)
478+
{
479+
struct drm_mm_node *node;
480+
struct scatterlist *sg;
481+
int num_entries = 0;
482+
unsigned int pages;
483+
int i, r;
484+
485+
*sgt = kmalloc(sizeof(*sg), GFP_KERNEL);
486+
if (!*sgt)
487+
return -ENOMEM;
488+
489+
for (pages = mem->num_pages, node = mem->mm_node;
490+
pages; pages -= node->size, ++node)
491+
++num_entries;
492+
493+
r = sg_alloc_table(*sgt, num_entries, GFP_KERNEL);
494+
if (r)
495+
goto error_free;
496+
497+
for_each_sg((*sgt)->sgl, sg, num_entries, i)
498+
sg->length = 0;
499+
500+
node = mem->mm_node;
501+
for_each_sg((*sgt)->sgl, sg, num_entries, i) {
502+
phys_addr_t phys = (node->start << PAGE_SHIFT) +
503+
adev->gmc.aper_base;
504+
size_t size = node->size << PAGE_SHIFT;
505+
dma_addr_t addr;
506+
507+
++node;
508+
addr = dma_map_resource(dev, phys, size, dir,
509+
DMA_ATTR_SKIP_CPU_SYNC);
510+
r = dma_mapping_error(dev, addr);
511+
if (r)
512+
goto error_unmap;
513+
514+
sg_set_page(sg, NULL, size, 0);
515+
sg_dma_address(sg) = addr;
516+
sg_dma_len(sg) = size;
517+
}
518+
return 0;
519+
520+
error_unmap:
521+
for_each_sg((*sgt)->sgl, sg, num_entries, i) {
522+
if (!sg->length)
523+
continue;
524+
525+
dma_unmap_resource(dev, sg->dma_address,
526+
sg->length, dir,
527+
DMA_ATTR_SKIP_CPU_SYNC);
528+
}
529+
sg_free_table(*sgt);
530+
531+
error_free:
532+
kfree(*sgt);
533+
return r;
534+
}
535+
536+
/**
537+
* amdgpu_vram_mgr_alloc_sgt - allocate and fill a sg table
538+
*
539+
* @adev: amdgpu device pointer
540+
* @sgt: sg table to free
541+
*
542+
* Free a previously allocate sg table.
543+
*/
544+
void amdgpu_vram_mgr_free_sgt(struct amdgpu_device *adev,
545+
struct device *dev,
546+
enum dma_data_direction dir,
547+
struct sg_table *sgt)
548+
{
549+
struct scatterlist *sg;
550+
int i;
551+
552+
for_each_sg(sgt->sgl, sg, sgt->nents, i)
553+
dma_unmap_resource(dev, sg->dma_address,
554+
sg->length, dir,
555+
DMA_ATTR_SKIP_CPU_SYNC);
556+
sg_free_table(sgt);
557+
kfree(sgt);
558+
}
559+
461560
/**
462561
* amdgpu_vram_mgr_usage - how many bytes are used in this domain
463562
*

0 commit comments

Comments
 (0)