aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian König <christian.koenig@amd.com>2014-08-07 03:36:00 -0400
committerAlex Deucher <alexander.deucher@amd.com>2014-08-11 11:04:23 -0400
commitf72a113a71ab08c4df8a5f80ab2f8a140feb81f6 (patch)
tree6d1453a5ffef6dfab8fdf1bc2e85b9abc531ed9a
parent7963e9db1b1f842fdc53309baa8714d38e9f5681 (diff)
drm/radeon: add userptr support v8
This patch adds an IOCTL for turning a pointer supplied by userspace into a buffer object. It imposes several restrictions upon the memory being mapped: 1. It must be page aligned (both start/end addresses, i.e ptr and size). 2. It must be normal system memory, not a pointer into another map of IO space (e.g. it must not be a GTT mmapping of another object). 3. The BO is mapped into GTT, so the maximum amount of memory mapped at all times is still the GTT limit. 4. The BO is only mapped readonly for now, so no write support. 5. List of backing pages is only acquired once, so they represent a snapshot of the first use. Exporting and sharing as well as mapping of buffer objects created by this function is forbidden and results in an -EPERM. v2: squash all previous changes into first public version v3: fix tabs, map readonly, don't use MM callback any more v4: set TTM_PAGE_FLAG_SG so that TTM never messes with the pages, pin/unpin pages on bind/unbind instead of populate/unpopulate v5: rebased on 3.17-wip, IOCTL renamed to userptr, reject any unknown flags, better handle READONLY flag, improve permission check v6: fix ptr cast warning, use set_page_dirty/mark_page_accessed on unpin v7: add warning about it's availability in the API definition v8: drop access_ok check, fix VM mapping bits Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> (v4) Reviewed-by: Jérôme Glisse <jglisse@redhat.com> (v4) Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
-rw-r--r--drivers/gpu/drm/radeon/radeon.h6
-rw-r--r--drivers/gpu/drm/radeon/radeon_cs.c25
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.c5
-rw-r--r--drivers/gpu/drm/radeon/radeon_gem.c68
-rw-r--r--drivers/gpu/drm/radeon/radeon_kms.c1
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.c3
-rw-r--r--drivers/gpu/drm/radeon/radeon_prime.c10
-rw-r--r--drivers/gpu/drm/radeon/radeon_ttm.c145
-rw-r--r--drivers/gpu/drm/radeon/radeon_vm.c3
-rw-r--r--include/uapi/drm/radeon_drm.h16
10 files changed, 279 insertions, 3 deletions
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 9e1732eb402c..6f38a23a5810 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -2138,6 +2138,8 @@ int radeon_gem_info_ioctl(struct drm_device *dev, void *data,
2138 struct drm_file *filp); 2138 struct drm_file *filp);
2139int radeon_gem_create_ioctl(struct drm_device *dev, void *data, 2139int radeon_gem_create_ioctl(struct drm_device *dev, void *data,
2140 struct drm_file *filp); 2140 struct drm_file *filp);
2141int radeon_gem_userptr_ioctl(struct drm_device *dev, void *data,
2142 struct drm_file *filp);
2141int radeon_gem_pin_ioctl(struct drm_device *dev, void *data, 2143int radeon_gem_pin_ioctl(struct drm_device *dev, void *data,
2142 struct drm_file *file_priv); 2144 struct drm_file *file_priv);
2143int radeon_gem_unpin_ioctl(struct drm_device *dev, void *data, 2145int radeon_gem_unpin_ioctl(struct drm_device *dev, void *data,
@@ -2871,6 +2873,10 @@ extern void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enabl
2871extern void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable); 2873extern void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable);
2872extern void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain); 2874extern void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain);
2873extern bool radeon_ttm_bo_is_radeon_bo(struct ttm_buffer_object *bo); 2875extern bool radeon_ttm_bo_is_radeon_bo(struct ttm_buffer_object *bo);
2876extern int radeon_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr,
2877 uint32_t flags);
2878extern bool radeon_ttm_tt_has_userptr(struct ttm_tt *ttm);
2879extern bool radeon_ttm_tt_is_readonly(struct ttm_tt *ttm);
2874extern void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64 base); 2880extern void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64 base);
2875extern void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc); 2881extern void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
2876extern int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon); 2882extern int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon);
diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c
index ee712c199b25..1321491cf499 100644
--- a/drivers/gpu/drm/radeon/radeon_cs.c
+++ b/drivers/gpu/drm/radeon/radeon_cs.c
@@ -78,7 +78,8 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
78 struct radeon_cs_chunk *chunk; 78 struct radeon_cs_chunk *chunk;
79 struct radeon_cs_buckets buckets; 79 struct radeon_cs_buckets buckets;
80 unsigned i, j; 80 unsigned i, j;
81 bool duplicate; 81 bool duplicate, need_mmap_lock = false;
82 int r;
82 83
83 if (p->chunk_relocs_idx == -1) { 84 if (p->chunk_relocs_idx == -1) {
84 return 0; 85 return 0;
@@ -164,6 +165,19 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
164 p->relocs[i].allowed_domains = domain; 165 p->relocs[i].allowed_domains = domain;
165 } 166 }
166 167
168 if (radeon_ttm_tt_has_userptr(p->relocs[i].robj->tbo.ttm)) {
169 uint32_t domain = p->relocs[i].prefered_domains;
170 if (!(domain & RADEON_GEM_DOMAIN_GTT)) {
171 DRM_ERROR("Only RADEON_GEM_DOMAIN_GTT is "
172 "allowed for userptr BOs\n");
173 return -EINVAL;
174 }
175 need_mmap_lock = true;
176 domain = RADEON_GEM_DOMAIN_GTT;
177 p->relocs[i].prefered_domains = domain;
178 p->relocs[i].allowed_domains = domain;
179 }
180
167 p->relocs[i].tv.bo = &p->relocs[i].robj->tbo; 181 p->relocs[i].tv.bo = &p->relocs[i].robj->tbo;
168 p->relocs[i].handle = r->handle; 182 p->relocs[i].handle = r->handle;
169 183
@@ -176,8 +190,15 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
176 if (p->cs_flags & RADEON_CS_USE_VM) 190 if (p->cs_flags & RADEON_CS_USE_VM)
177 p->vm_bos = radeon_vm_get_bos(p->rdev, p->ib.vm, 191 p->vm_bos = radeon_vm_get_bos(p->rdev, p->ib.vm,
178 &p->validated); 192 &p->validated);
193 if (need_mmap_lock)
194 down_read(&current->mm->mmap_sem);
195
196 r = radeon_bo_list_validate(p->rdev, &p->ticket, &p->validated, p->ring);
179 197
180 return radeon_bo_list_validate(p->rdev, &p->ticket, &p->validated, p->ring); 198 if (need_mmap_lock)
199 up_read(&current->mm->mmap_sem);
200
201 return r;
181} 202}
182 203
183static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority) 204static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority)
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index a773830c6c40..5b18af926527 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -114,6 +114,9 @@ int radeon_gem_object_open(struct drm_gem_object *obj,
114 struct drm_file *file_priv); 114 struct drm_file *file_priv);
115void radeon_gem_object_close(struct drm_gem_object *obj, 115void radeon_gem_object_close(struct drm_gem_object *obj,
116 struct drm_file *file_priv); 116 struct drm_file *file_priv);
117struct dma_buf *radeon_gem_prime_export(struct drm_device *dev,
118 struct drm_gem_object *gobj,
119 int flags);
117extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, 120extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc,
118 unsigned int flags, 121 unsigned int flags,
119 int *vpos, int *hpos, ktime_t *stime, 122 int *vpos, int *hpos, ktime_t *stime,
@@ -568,7 +571,7 @@ static struct drm_driver kms_driver = {
568 571
569 .prime_handle_to_fd = drm_gem_prime_handle_to_fd, 572 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
570 .prime_fd_to_handle = drm_gem_prime_fd_to_handle, 573 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
571 .gem_prime_export = drm_gem_prime_export, 574 .gem_prime_export = radeon_gem_prime_export,
572 .gem_prime_import = drm_gem_prime_import, 575 .gem_prime_import = drm_gem_prime_import,
573 .gem_prime_pin = radeon_gem_prime_pin, 576 .gem_prime_pin = radeon_gem_prime_pin,
574 .gem_prime_unpin = radeon_gem_prime_unpin, 577 .gem_prime_unpin = radeon_gem_prime_unpin,
diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c
index bfd7e1b0ff3f..993ab223b503 100644
--- a/drivers/gpu/drm/radeon/radeon_gem.c
+++ b/drivers/gpu/drm/radeon/radeon_gem.c
@@ -272,6 +272,65 @@ int radeon_gem_create_ioctl(struct drm_device *dev, void *data,
272 return 0; 272 return 0;
273} 273}
274 274
275int radeon_gem_userptr_ioctl(struct drm_device *dev, void *data,
276 struct drm_file *filp)
277{
278 struct radeon_device *rdev = dev->dev_private;
279 struct drm_radeon_gem_userptr *args = data;
280 struct drm_gem_object *gobj;
281 struct radeon_bo *bo;
282 uint32_t handle;
283 int r;
284
285 if (offset_in_page(args->addr | args->size))
286 return -EINVAL;
287
288 /* we only support read only mappings for now */
289 if (!(args->flags & RADEON_GEM_USERPTR_READONLY))
290 return -EACCES;
291
292 /* reject unknown flag values */
293 if (args->flags & ~RADEON_GEM_USERPTR_READONLY)
294 return -EINVAL;
295
296 /* readonly pages not tested on older hardware */
297 if (rdev->family < CHIP_R600)
298 return -EINVAL;
299
300 down_read(&rdev->exclusive_lock);
301
302 /* create a gem object to contain this object in */
303 r = radeon_gem_object_create(rdev, args->size, 0,
304 RADEON_GEM_DOMAIN_CPU, 0,
305 false, &gobj);
306 if (r)
307 goto handle_lockup;
308
309 bo = gem_to_radeon_bo(gobj);
310 r = radeon_ttm_tt_set_userptr(bo->tbo.ttm, args->addr, args->flags);
311 if (r)
312 goto release_object;
313
314 r = drm_gem_handle_create(filp, gobj, &handle);
315 /* drop reference from allocate - handle holds it now */
316 drm_gem_object_unreference_unlocked(gobj);
317 if (r)
318 goto handle_lockup;
319