>> + vma->vm_pgoff = amdgpu_bo_mmap_offset(bo) >> PAGE_SHIFT; > Maybe better use "vma->vm_pgoff += amdgpu_bo_mmap_offset(bo) >> PAGE_SHIFT;", but I'm not sure. > How other drivers handle this? This is a good catch. Looks like pgoff is honored during prime mmap, not a fake offset here. >> + dma_buf->ops = &amdgpu_dmabuf_ops; > This isn't race free and needs to be fixed. > Better add callbacks to drm_prime.c similar to drm_gem_dmabuf_mmap(). What do you mean "This isn't race free"? Regards, Sam On 2017-09-15 11:05 AM, Christian König wrote: > Am 14.09.2017 um 00:39 schrieb Samuel Li: >> v2: drop hdp invalidate/flush. >> >> Signed-off-by: Samuel Li <Samuel.Li at amd.com> >> --- >> drivers/gpu/drm/amd/amdgpu/amdgpu.h | 3 ++ >> drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 3 +- >> drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c | 77 ++++++++++++++++++++++++++++++- >> 3 files changed, 81 insertions(+), 2 deletions(-) >> >> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h >> index d2aaad7..188b705 100644 >> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h >> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h >> @@ -395,11 +395,14 @@ amdgpu_gem_prime_import_sg_table(struct drm_device *dev, >> struct dma_buf *amdgpu_gem_prime_export(struct drm_device *dev, >> struct drm_gem_object *gobj, >> int flags); >> +struct drm_gem_object *amdgpu_gem_prime_import(struct drm_device *dev, >> + struct dma_buf *dma_buf); >> int amdgpu_gem_prime_pin(struct drm_gem_object *obj); >> void amdgpu_gem_prime_unpin(struct drm_gem_object *obj); >> struct reservation_object *amdgpu_gem_prime_res_obj(struct drm_gem_object *); >> void *amdgpu_gem_prime_vmap(struct drm_gem_object *obj); >> void amdgpu_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr); >> +int amdgpu_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma); >> int amdgpu_gem_debugfs_init(struct amdgpu_device *adev); >> /* sub-allocation manager, it has to be protected by another lock. >> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c >> index 2cdf844..9b63ac5 100644 >> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c >> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c >> @@ -835,7 +835,7 @@ static struct drm_driver kms_driver = { >> .prime_handle_to_fd = drm_gem_prime_handle_to_fd, >> .prime_fd_to_handle = drm_gem_prime_fd_to_handle, >> .gem_prime_export = amdgpu_gem_prime_export, >> - .gem_prime_import = drm_gem_prime_import, >> + .gem_prime_import = amdgpu_gem_prime_import, >> .gem_prime_pin = amdgpu_gem_prime_pin, >> .gem_prime_unpin = amdgpu_gem_prime_unpin, >> .gem_prime_res_obj = amdgpu_gem_prime_res_obj, >> @@ -843,6 +843,7 @@ static struct drm_driver kms_driver = { >> .gem_prime_import_sg_table = amdgpu_gem_prime_import_sg_table, >> .gem_prime_vmap = amdgpu_gem_prime_vmap, >> .gem_prime_vunmap = amdgpu_gem_prime_vunmap, >> + .gem_prime_mmap = amdgpu_gem_prime_mmap, >> .name = DRIVER_NAME, >> .desc = DRIVER_DESC, >> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c >> index 5b3f928..13c977a 100644 >> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c >> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c >> @@ -57,6 +57,40 @@ void amdgpu_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr) >> ttm_bo_kunmap(&bo->dma_buf_vmap); >> } >> +int amdgpu_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) >> +{ >> + struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); >> + struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); >> + unsigned asize = amdgpu_bo_size(bo); >> + int ret; >> + >> + if (!vma->vm_file) >> + return -ENODEV; >> + >> + if (adev == NULL) >> + return -ENODEV; >> + >> + /* Check for valid size. */ >> + if (asize < vma->vm_end - vma->vm_start) >> + return -EINVAL; >> + >> + if (amdgpu_ttm_tt_get_usermm(bo->tbo.ttm) || >> + (bo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS)) { >> + return -EPERM; >> + } >> + vma->vm_pgoff = amdgpu_bo_mmap_offset(bo) >> PAGE_SHIFT; > > Maybe better use "vma->vm_pgoff += amdgpu_bo_mmap_offset(bo) >> PAGE_SHIFT;", but I'm not sure. > > How other drivers handle this? > >> + >> + /* prime mmap does not need to check access, so allow here */ >> + ret = drm_vma_node_allow(&obj->vma_node, vma->vm_file->private_data); >> + if (ret) >> + return ret; >> + >> + ret = ttm_bo_mmap(vma->vm_file, vma, &adev->mman.bdev); >> + drm_vma_node_revoke(&obj->vma_node, vma->vm_file->private_data); >> + >> + return ret; >> +} >> + >> struct drm_gem_object * >> amdgpu_gem_prime_import_sg_table(struct drm_device *dev, >> struct dma_buf_attachment *attach, >> @@ -130,14 +164,55 @@ struct reservation_object *amdgpu_gem_prime_res_obj(struct drm_gem_object *obj) >> return bo->tbo.resv; >> } >> +static int amdgpu_gem_begin_cpu_access(struct dma_buf *dma_buf, enum dma_data_direction direction) >> +{ >> + return amdgpu_gem_prime_pin(dma_buf->priv); >> +} >> + >> +static int amdgpu_gem_end_cpu_access(struct dma_buf *dma_buf, enum dma_data_direction direction) >> +{ >> + amdgpu_gem_prime_unpin(dma_buf->priv); >> + >> + return 0; >> +} >> + >> +static struct dma_buf_ops amdgpu_dmabuf_ops; >> + >> struct dma_buf *amdgpu_gem_prime_export(struct drm_device *dev, >> struct drm_gem_object *gobj, >> int flags) >> { >> struct amdgpu_bo *bo = gem_to_amdgpu_bo(gobj); >> + struct dma_buf *dma_buf; >> if (amdgpu_ttm_tt_get_usermm(bo->tbo.ttm)) >> return ERR_PTR(-EPERM); >> - return drm_gem_prime_export(dev, gobj, flags); >> + dma_buf = drm_gem_prime_export(dev, gobj, flags); >> + amdgpu_dmabuf_ops = *(dma_buf->ops); >> + amdgpu_dmabuf_ops.begin_cpu_access = amdgpu_gem_begin_cpu_access; >> + amdgpu_dmabuf_ops.end_cpu_access = amdgpu_gem_end_cpu_access; >> + dma_buf->ops = &amdgpu_dmabuf_ops; > > This isn't race free and needs to be fixed. > > Better add callbacks to drm_prime.c similar to drm_gem_dmabuf_mmap(). > > Alternative you could just completely drop amdgpu_gem_begin_cpu_access() and amdgpu_gem_end_cpu_access() as well. > > When the buffer is shared between device it is pinned anyway and when it isn't shared ttm_bo_mmap() is able to handle VRAM mappings as well. > > Regards, > Christian. > >> + >> + return dma_buf; >> +} >> + >> +struct drm_gem_object *amdgpu_gem_prime_import(struct drm_device *dev, >> + struct dma_buf *dma_buf) >> +{ >> + struct drm_gem_object *obj; >> + >> + if (dma_buf->ops == &amdgpu_dmabuf_ops) { >> + obj = dma_buf->priv; >> + if (obj->dev == dev) { >> + /* >> + * Importing dmabuf exported from out own gem increases >> + * refcount on gem itself instead of f_count of dmabuf. >> + */ >> + drm_gem_object_get(obj); >> + return obj; >> + } >> + } >> + >> + return drm_gem_prime_import(dev, dma_buf); >> } > >