All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] drm/radeon: add readonly flag to radeon_gart_set_page v2
@ 2014-07-10 12:33 Christian König
  2014-07-10 12:33 ` [PATCH 2/2] drm/radeon: add user pointer support v3 Christian König
  2014-07-10 13:41 ` [PATCH 1/2] drm/radeon: add readonly flag to radeon_gart_set_page v2 Alex Deucher
  0 siblings, 2 replies; 5+ messages in thread
From: Christian König @ 2014-07-10 12:33 UTC (permalink / raw)
  To: dri-devel

From: Christian König <christian.koenig@amd.com>

v2: use flag instead of boolean

Signed-off-by: Christian König <christian.koenig@amd.com>
---
 drivers/gpu/drm/radeon/r100.c        |  2 +-
 drivers/gpu/drm/radeon/r300.c        |  8 ++++++--
 drivers/gpu/drm/radeon/radeon.h      | 12 +++++++-----
 drivers/gpu/drm/radeon/radeon_asic.h |  8 ++++----
 drivers/gpu/drm/radeon/radeon_gart.c |  9 +++++----
 drivers/gpu/drm/radeon/radeon_ttm.c  |  4 ++--
 drivers/gpu/drm/radeon/rs400.c       |  9 +++++++--
 drivers/gpu/drm/radeon/rs600.c       |  8 ++++++--
 8 files changed, 38 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index a6f7d61..fa71121d7 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -650,7 +650,7 @@ void r100_pci_gart_disable(struct radeon_device *rdev)
 }
 
 void r100_pci_gart_set_page(struct radeon_device *rdev, unsigned i,
-			    uint64_t addr)
+			    uint64_t addr, uint32_t flags)
 {
 	u32 *gtt = rdev->gart.ptr;
 	gtt[i] = cpu_to_le32(lower_32_bits(addr));
diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c
index 8d14e66..b947f42 100644
--- a/drivers/gpu/drm/radeon/r300.c
+++ b/drivers/gpu/drm/radeon/r300.c
@@ -73,13 +73,17 @@ void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev)
 #define R300_PTE_READABLE  (1 << 3)
 
 void rv370_pcie_gart_set_page(struct radeon_device *rdev, unsigned i,
-			      uint64_t addr)
+			      uint64_t addr, uint32_t flags)
 {
 	void __iomem *ptr = rdev->gart.ptr;
 
 	addr = (lower_32_bits(addr) >> 8) |
 	       ((upper_32_bits(addr) & 0xff) << 24) |
-	       R300_PTE_WRITEABLE | R300_PTE_READABLE;
+	       R300_PTE_READABLE;
+
+	if (!(flags & RADEON_GART_PAGE_READONLY))
+		addr |= R300_PTE_WRITEABLE;
+
 	/* on x86 we want this to be CPU endian, on powerpc
 	 * on powerpc without HW swappers, it'll get swapped on way
 	 * into VRAM - so no need for cpu_to_le32 on VRAM tables */
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index c5318cac..86fdfa30 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -592,6 +592,8 @@ struct radeon_mc;
 #define RADEON_GPU_PAGE_SHIFT 12
 #define RADEON_GPU_PAGE_ALIGN(a) (((a) + RADEON_GPU_PAGE_MASK) & ~RADEON_GPU_PAGE_MASK)
 
+#define RADEON_GART_PAGE_READONLY	1
+
 struct radeon_gart {
 	dma_addr_t			table_addr;
 	struct radeon_bo		*robj;
@@ -616,7 +618,7 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset,
 			int pages);
 int radeon_gart_bind(struct radeon_device *rdev, unsigned offset,
 		     int pages, struct page **pagelist,
-		     dma_addr_t *dma_addr);
+		     dma_addr_t *dma_addr, uint32_t flags);
 
 
 /*
@@ -854,8 +856,8 @@ struct radeon_mec {
 #define R600_PTE_FRAG_256KB	(6 << 7)
 
 /* flags used for GART page table entries on R600+ */
-#define R600_PTE_GART	( R600_PTE_VALID | R600_PTE_SYSTEM | R600_PTE_SNOOPED \
-			| R600_PTE_READABLE | R600_PTE_WRITEABLE)
+#define R600_PTE_GART	( R600_PTE_VALID | R600_PTE_SYSTEM | \
+			  R600_PTE_SNOOPED | R600_PTE_READABLE )
 
 struct radeon_vm_pt {
 	struct radeon_bo		*bo;
@@ -1775,7 +1777,7 @@ struct radeon_asic {
 	struct {
 		void (*tlb_flush)(struct radeon_device *rdev);
 		void (*set_page)(struct radeon_device *rdev, unsigned i,
-				 uint64_t addr);
+				 uint64_t addr, uint32_t flags);
 	} gart;
 	struct {
 		int (*init)(struct radeon_device *rdev);
@@ -2703,7 +2705,7 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v);
 #define radeon_vga_set_state(rdev, state) (rdev)->asic->vga_set_state((rdev), (state))
 #define radeon_asic_reset(rdev) (rdev)->asic->asic_reset((rdev))
 #define radeon_gart_tlb_flush(rdev) (rdev)->asic->gart.tlb_flush((rdev))
-#define radeon_gart_set_page(rdev, i, p) (rdev)->asic->gart.set_page((rdev), (i), (p))
+#define radeon_gart_set_page(rdev, i, p, r) (rdev)->asic->gart.set_page((rdev), (i), (p), (r))
 #define radeon_asic_vm_init(rdev) (rdev)->asic->vm.init((rdev))
 #define radeon_asic_vm_fini(rdev) (rdev)->asic->vm.fini((rdev))
 #define radeon_asic_vm_set_page(rdev, ib, pe, addr, count, incr, flags) ((rdev)->asic->vm.set_page((rdev), (ib), (pe), (addr), (count), (incr), (flags)))
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 7531b5e..f7d7c33 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -68,7 +68,7 @@ int r100_asic_reset(struct radeon_device *rdev);
 u32 r100_get_vblank_counter(struct radeon_device *rdev, int crtc);
 void r100_pci_gart_tlb_flush(struct radeon_device *rdev);
 void r100_pci_gart_set_page(struct radeon_device *rdev, unsigned i,
-			    uint64_t addr);
+			    uint64_t addr, uint32_t flags);
 void r100_ring_start(struct radeon_device *rdev, struct radeon_ring *ring);
 int r100_irq_set(struct radeon_device *rdev);
 int r100_irq_process(struct radeon_device *rdev);
@@ -172,7 +172,7 @@ extern void r300_fence_ring_emit(struct radeon_device *rdev,
 extern int r300_cs_parse(struct radeon_cs_parser *p);
 extern void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev);
 extern void rv370_pcie_gart_set_page(struct radeon_device *rdev, unsigned i,
-				     uint64_t addr);
+				     uint64_t addr, uint32_t flags);
 extern void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes);
 extern int rv370_get_pcie_lanes(struct radeon_device *rdev);
 extern void r300_set_reg_safe(struct radeon_device *rdev);
@@ -208,7 +208,7 @@ extern int rs400_suspend(struct radeon_device *rdev);
 extern int rs400_resume(struct radeon_device *rdev);
 void rs400_gart_tlb_flush(struct radeon_device *rdev);
 void rs400_gart_set_page(struct radeon_device *rdev, unsigned i,
-			 uint64_t addr);
+			 uint64_t addr, uint32_t flags);
 uint32_t rs400_mc_rreg(struct radeon_device *rdev, uint32_t reg);
 void rs400_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
 int rs400_gart_init(struct radeon_device *rdev);
@@ -232,7 +232,7 @@ void rs600_irq_disable(struct radeon_device *rdev);
 u32 rs600_get_vblank_counter(struct radeon_device *rdev, int crtc);
 void rs600_gart_tlb_flush(struct radeon_device *rdev);
 void rs600_gart_set_page(struct radeon_device *rdev, unsigned i,
-			 uint64_t addr);
+			 uint64_t addr, uint32_t flags);
 uint32_t rs600_mc_rreg(struct radeon_device *rdev, uint32_t reg);
 void rs600_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
 void rs600_bandwidth_update(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c
index b7d3e84..b26c0b2 100644
--- a/drivers/gpu/drm/radeon/radeon_gart.c
+++ b/drivers/gpu/drm/radeon/radeon_gart.c
@@ -243,7 +243,7 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset,
 			page_base = rdev->gart.pages_addr[p];
 			for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) {
 				if (rdev->gart.ptr) {
-					radeon_gart_set_page(rdev, t, page_base);
+					radeon_gart_set_page(rdev, t, page_base, 0);
 				}
 				page_base += RADEON_GPU_PAGE_SIZE;
 			}
@@ -266,8 +266,9 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset,
  * (all asics).
  * Returns 0 for success, -EINVAL for failure.
  */
-int radeon_gart_bind(struct radeon_device *rdev, unsigned offset,
-		     int pages, struct page **pagelist, dma_addr_t *dma_addr)
+int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, int pages,
+		     struct page **pagelist, dma_addr_t *dma_addr,
+		     uint32_t flags)
 {
 	unsigned t;
 	unsigned p;
@@ -287,7 +288,7 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset,
 		if (rdev->gart.ptr) {
 			page_base = rdev->gart.pages_addr[p];
 			for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) {
-				radeon_gart_set_page(rdev, t, page_base);
+				radeon_gart_set_page(rdev, t, page_base, flags);
 				page_base += RADEON_GPU_PAGE_SIZE;
 			}
 		}
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
index c8a8a51..19d662f 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -528,8 +528,8 @@ static int radeon_ttm_backend_bind(struct ttm_tt *ttm,
 		WARN(1, "nothing to bind %lu pages for mreg %p back %p!\n",
 		     ttm->num_pages, bo_mem, ttm);
 	}
-	r = radeon_gart_bind(gtt->rdev, gtt->offset,
-			     ttm->num_pages, ttm->pages, gtt->ttm.dma_address);
+	r = radeon_gart_bind(gtt->rdev, gtt->offset, ttm->num_pages,
+			     ttm->pages, gtt->ttm.dma_address, 0);
 	if (r) {
 		DRM_ERROR("failed to bind %lu pages at 0x%08X\n",
 			  ttm->num_pages, (unsigned)gtt->offset);
diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c
index 4519f9c..5164544 100644
--- a/drivers/gpu/drm/radeon/rs400.c
+++ b/drivers/gpu/drm/radeon/rs400.c
@@ -211,14 +211,19 @@ void rs400_gart_fini(struct radeon_device *rdev)
 #define RS400_PTE_WRITEABLE (1 << 2)
 #define RS400_PTE_READABLE  (1 << 3)
 
-void rs400_gart_set_page(struct radeon_device *rdev, unsigned i, uint64_t addr)
+void rs400_gart_set_page(struct radeon_device *rdev, unsigned i,
+			 uint64_t addr, uint32_t flags)
 {
 	uint32_t entry;
 	u32 *gtt = rdev->gart.ptr;
 
 	entry = (lower_32_bits(addr) & PAGE_MASK) |
 		((upper_32_bits(addr) & 0xff) << 4) |
-		RS400_PTE_WRITEABLE | RS400_PTE_READABLE;
+		RS400_PTE_READABLE;
+
+	if (!(flags & RADEON_GART_PAGE_READONLY))
+		entry |= RS400_PTE_WRITEABLE;
+
 	entry = cpu_to_le32(entry);
 	gtt[i] = entry;
 }
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
index cd7b4b0..3cba999 100644
--- a/drivers/gpu/drm/radeon/rs600.c
+++ b/drivers/gpu/drm/radeon/rs600.c
@@ -611,15 +611,19 @@ static void rs600_gart_fini(struct radeon_device *rdev)
 	radeon_gart_table_vram_free(rdev);
 }
 
-void rs600_gart_set_page(struct radeon_device *rdev, unsigned i, uint64_t addr)
+void rs600_gart_set_page(struct radeon_device *rdev, unsigned i,
+			 uint64_t addr, uint32_t flags)
 {
 	void __iomem *ptr = (void *)rdev->gart.ptr;
 
 	addr = addr & 0xFFFFFFFFFFFFF000ULL;
 	if (addr == rdev->dummy_page.addr)
 		addr |= R600_PTE_SYSTEM | R600_PTE_SNOOPED;
-	else
+	else {
 		addr |= R600_PTE_GART;
+		if (!(flags & RADEON_GART_PAGE_READONLY))
+			addr |= R600_PTE_WRITEABLE;
+	}
 	writeq(addr, ptr + (i * 8));
 }
 
-- 
1.9.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/2] drm/radeon: add user pointer support v3
  2014-07-10 12:33 [PATCH 1/2] drm/radeon: add readonly flag to radeon_gart_set_page v2 Christian König
@ 2014-07-10 12:33 ` Christian König
  2014-07-10 13:48   ` Alex Deucher
  2014-07-10 13:41 ` [PATCH 1/2] drm/radeon: add readonly flag to radeon_gart_set_page v2 Alex Deucher
  1 sibling, 1 reply; 5+ messages in thread
From: Christian König @ 2014-07-10 12:33 UTC (permalink / raw)
  To: dri-devel

From: Christian König <christian.koenig@amd.com>

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

Signed-off-by: Christian König <christian.koenig@amd.com>
---
 drivers/gpu/drm/radeon/radeon.h        |   4 ++
 drivers/gpu/drm/radeon/radeon_cs.c     |  25 +++++++-
 drivers/gpu/drm/radeon/radeon_drv.c    |   5 +-
 drivers/gpu/drm/radeon/radeon_gem.c    |  67 +++++++++++++++++++++
 drivers/gpu/drm/radeon/radeon_kms.c    |   1 +
 drivers/gpu/drm/radeon/radeon_object.c |   3 +
 drivers/gpu/drm/radeon/radeon_prime.c  |  10 +++
 drivers/gpu/drm/radeon/radeon_ttm.c    | 107 ++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/radeon/radeon_vm.c     |   3 +
 include/uapi/drm/radeon_drm.h          |  11 ++++
 10 files changed, 232 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 86fdfa30..55c996e 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -2111,6 +2111,8 @@ int radeon_gem_info_ioctl(struct drm_device *dev, void *data,
 			  struct drm_file *filp);
 int radeon_gem_create_ioctl(struct drm_device *dev, void *data,
 			    struct drm_file *filp);
+int radeon_gem_import_ioctl(struct drm_device *dev, void *data,
+			    struct drm_file *filp);
 int radeon_gem_pin_ioctl(struct drm_device *dev, void *data,
 			 struct drm_file *file_priv);
 int radeon_gem_unpin_ioctl(struct drm_device *dev, void *data,
@@ -2803,6 +2805,8 @@ extern void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enabl
 extern void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable);
 extern void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain);
 extern bool radeon_ttm_bo_is_radeon_bo(struct ttm_buffer_object *bo);
+extern int radeon_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t userptr);
+extern bool radeon_ttm_tt_has_userptr(struct ttm_tt *ttm);
 extern void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64 base);
 extern void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
 extern 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 71a1434..be65311 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)
 	struct radeon_cs_chunk *chunk;
 	struct radeon_cs_buckets buckets;
 	unsigned i, j;
-	bool duplicate;
+	bool duplicate, need_mmap_lock = false;
+	int r;
 
 	if (p->chunk_relocs_idx == -1) {
 		return 0;
@@ -164,6 +165,19 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
 			p->relocs[i].allowed_domains = domain;
 		}
 
+		if (radeon_ttm_tt_has_userptr(p->relocs[i].robj->tbo.ttm)) {
+			uint32_t domain = p->relocs[i].prefered_domains;
+			if (!(domain & RADEON_GEM_DOMAIN_GTT)) {
+				DRM_ERROR("Only RADEON_GEM_DOMAIN_GTT is "
+					  "allowed for userptr BOs\n");
+				return -EINVAL;
+			}
+			need_mmap_lock = true;
+			domain = RADEON_GEM_DOMAIN_GTT;
+			p->relocs[i].prefered_domains = domain;
+			p->relocs[i].allowed_domains = domain;
+		}
+
 		p->relocs[i].tv.bo = &p->relocs[i].robj->tbo;
 		p->relocs[i].handle = r->handle;
 
@@ -176,8 +190,15 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
 	if (p->cs_flags & RADEON_CS_USE_VM)
 		p->vm_bos = radeon_vm_get_bos(p->rdev, p->ib.vm,
 					      &p->validated);
+	if (need_mmap_lock)
+		down_read(&current->mm->mmap_sem);
+
+	r = radeon_bo_list_validate(p->rdev, &p->ticket, &p->validated, p->ring);
 
-	return radeon_bo_list_validate(p->rdev, &p->ticket, &p->validated, p->ring);
+	if (need_mmap_lock)
+		up_read(&current->mm->mmap_sem);
+
+	return r;
 }
 
 static 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 cb14213..bf91879 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -112,6 +112,9 @@ int radeon_gem_object_open(struct drm_gem_object *obj,
 				struct drm_file *file_priv);
 void radeon_gem_object_close(struct drm_gem_object *obj,
 				struct drm_file *file_priv);
+struct dma_buf *radeon_gem_prime_export(struct drm_device *dev,
+					struct drm_gem_object *gobj,
+					int flags);
 extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc,
 				      unsigned int flags,
 				      int *vpos, int *hpos, ktime_t *stime,
@@ -562,7 +565,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 = drm_gem_prime_export,
+	.gem_prime_export = radeon_gem_prime_export,
 	.gem_prime_import = drm_gem_prime_import,
 	.gem_prime_pin = radeon_gem_prime_pin,
 	.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 d09650c..2464c65 100644
--- a/drivers/gpu/drm/radeon/radeon_gem.c
+++ b/drivers/gpu/drm/radeon/radeon_gem.c
@@ -272,6 +272,64 @@ int radeon_gem_create_ioctl(struct drm_device *dev, void *data,
 	return 0;
 }
 
+int radeon_gem_import_ioctl(struct drm_device *dev, void *data,
+			    struct drm_file *filp)
+{
+	struct radeon_device *rdev = dev->dev_private;
+	struct drm_radeon_gem_import *args = data;
+	struct drm_gem_object *gobj;
+	struct radeon_bo *bo;
+	uint32_t handle;
+	int r;
+
+	if (offset_in_page(args->addr | args->size))
+		return -EINVAL;
+
+	/* we only support read only mappings for now */
+	if (!(args->flags & RADEON_GEM_IMPORT_READONLY))
+		return -EACCES;
+
+	/* readonly pages not tested on older hardware */
+	if (rdev->family < CHIP_R600)
+		return -EINVAL;
+
+	if (!access_ok(VERIFY_READ, (char __user *)args->addr, args->size))
+		return -EFAULT;
+
+	down_read(&rdev->exclusive_lock);
+
+	/* create a gem object to contain this object in */
+	r = radeon_gem_object_create(rdev, args->size, 0,
+				     RADEON_GEM_DOMAIN_CPU,
+				     false, false, &gobj);
+	if (r)
+		goto handle_lockup;
+
+	bo = gem_to_radeon_bo(gobj);
+	r = radeon_ttm_tt_set_userptr(bo->tbo.ttm, args->addr);
+	if (r)
+		goto release_object;
+
+	r = drm_gem_handle_create(filp, gobj, &handle);
+	/* drop reference from allocate - handle holds it now */
+	drm_gem_object_unreference_unlocked(gobj);
+	if (r)
+		goto handle_lockup;
+
+	args->handle = handle;
+	up_read(&rdev->exclusive_lock);
+	return 0;
+
+release_object:
+	drm_gem_object_unreference_unlocked(gobj);
+
+handle_lockup:
+	up_read(&rdev->exclusive_lock);
+	r = radeon_gem_handle_lockup(rdev, r);
+
+	return r;
+}
+
 int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data,
 				struct drm_file *filp)
 {
@@ -315,6 +373,10 @@ int radeon_mode_dumb_mmap(struct drm_file *filp,
 		return -ENOENT;
 	}
 	robj = gem_to_radeon_bo(gobj);
+	if (radeon_ttm_tt_has_userptr(robj->tbo.ttm)) {
+		drm_gem_object_unreference_unlocked(gobj);
+		return -EPERM;
+	}
 	*offset_p = radeon_bo_mmap_offset(robj);
 	drm_gem_object_unreference_unlocked(gobj);
 	return 0;
@@ -535,6 +597,11 @@ int radeon_gem_op_ioctl(struct drm_device *dev, void *data,
 		return -ENOENT;
 	}
 	robj = gem_to_radeon_bo(gobj);
+
+	r = -EPERM;
+	if (radeon_ttm_tt_has_userptr(robj->tbo.ttm))
+		goto out;
+
 	r = radeon_bo_reserve(robj, false);
 	if (unlikely(r))
 		goto out;
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c
index 35d9318..39e8a5c 100644
--- a/drivers/gpu/drm/radeon/radeon_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_kms.c
@@ -874,5 +874,6 @@ const struct drm_ioctl_desc radeon_ioctls_kms[] = {
 	DRM_IOCTL_DEF_DRV(RADEON_GEM_BUSY, radeon_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF_DRV(RADEON_GEM_VA, radeon_gem_va_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF_DRV(RADEON_GEM_OP, radeon_gem_op_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
+	DRM_IOCTL_DEF_DRV(RADEON_GEM_IMPORT, radeon_gem_import_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
 };
 int radeon_max_kms_ioctl = ARRAY_SIZE(radeon_ioctls_kms);
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
index 6c717b2..c1f826b 100644
--- a/drivers/gpu/drm/radeon/radeon_object.c
+++ b/drivers/gpu/drm/radeon/radeon_object.c
@@ -253,6 +253,9 @@ int radeon_bo_pin_restricted(struct radeon_bo *bo, u32 domain, u64 max_offset,
 {
 	int r, i;
 
+	if (radeon_ttm_tt_has_userptr(bo->tbo.ttm))
+		return -EPERM;
+
 	if (bo->pin_count) {
 		bo->pin_count++;
 		if (gpu_addr)
diff --git a/drivers/gpu/drm/radeon/radeon_prime.c b/drivers/gpu/drm/radeon/radeon_prime.c
index 2007456..1f0d8f7 100644
--- a/drivers/gpu/drm/radeon/radeon_prime.c
+++ b/drivers/gpu/drm/radeon/radeon_prime.c
@@ -103,3 +103,13 @@ void radeon_gem_prime_unpin(struct drm_gem_object *obj)
 	radeon_bo_unpin(bo);
 	radeon_bo_unreserve(bo);
 }
+
+struct dma_buf *radeon_gem_prime_export(struct drm_device *dev,
+					struct drm_gem_object *gobj,
+					int flags)
+{
+	struct radeon_bo *bo = gem_to_radeon_bo(gobj);
+	if (radeon_ttm_tt_has_userptr(bo->tbo.ttm))
+		return ERR_PTR(-EPERM);
+	return drm_gem_prime_export(dev, gobj, flags);
+}
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
index 19d662f..fee6018 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -515,12 +515,16 @@ struct radeon_ttm_tt {
 	struct ttm_dma_tt		ttm;
 	struct radeon_device		*rdev;
 	u64				offset;
+
+	uint64_t			userptr;
+	struct mm_struct		*usermm;
 };
 
 static int radeon_ttm_backend_bind(struct ttm_tt *ttm,
 				   struct ttm_mem_reg *bo_mem)
 {
 	struct radeon_ttm_tt *gtt = (void*)ttm;
+	uint32_t flags = gtt->userptr ? RADEON_GART_PAGE_READONLY : 0;
 	int r;
 
 	gtt->offset = (unsigned long)(bo_mem->start << PAGE_SHIFT);
@@ -529,7 +533,7 @@ static int radeon_ttm_backend_bind(struct ttm_tt *ttm,
 		     ttm->num_pages, bo_mem, ttm);
 	}
 	r = radeon_gart_bind(gtt->rdev, gtt->offset, ttm->num_pages,
-			     ttm->pages, gtt->ttm.dma_address, 0);
+			     ttm->pages, gtt->ttm.dma_address, flags);
 	if (r) {
 		DRM_ERROR("failed to bind %lu pages at 0x%08X\n",
 			  ttm->num_pages, (unsigned)gtt->offset);
@@ -588,6 +592,73 @@ static struct ttm_tt *radeon_ttm_tt_create(struct ttm_bo_device *bdev,
 	return &gtt->ttm.ttm;
 }
 
+static int radeon_ttm_tt_pin_userptr(struct ttm_tt *ttm)
+{
+	struct radeon_device *rdev = radeon_get_rdev(ttm->bdev);
+	struct radeon_ttm_tt *gtt = (void *)ttm;
+	unsigned pinned = 0, nents;
+	int r;
+
+	/* prepare the sg table with the user pages */
+	if (current->mm != gtt->usermm)
+		return -EPERM;
+
+	do {
+		unsigned num_pages = ttm->num_pages - pinned;
+		uint64_t userptr = gtt->userptr + pinned * PAGE_SIZE;
+		struct page **pages = ttm->pages + pinned;
+
+		r = get_user_pages(current, current->mm, userptr, num_pages,
+				   0, 0, pages, NULL);
+		if (r < 0) {
+			release_pages(ttm->pages, pinned, 0);
+			return r;
+		}
+		pinned += r;
+
+	} while (pinned < ttm->num_pages);
+
+	r = -ENOMEM;
+	ttm->sg = kcalloc(1, sizeof(struct sg_table), GFP_KERNEL);
+	if (!ttm->sg)
+		goto release_pages;
+
+	r = sg_alloc_table_from_pages(ttm->sg, ttm->pages, ttm->num_pages, 0,
+				      ttm->num_pages << PAGE_SHIFT,
+				      GFP_KERNEL);
+	if (r)
+		goto release_sg;
+
+	r = -ENOMEM;
+	nents = dma_map_sg(rdev->dev, ttm->sg->sgl, ttm->sg->nents,
+			   DMA_TO_DEVICE);
+	if (nents != ttm->sg->nents)
+		goto release_sg;
+
+	return 0;
+
+release_sg:
+	kfree(ttm->sg);
+
+release_pages:
+	release_pages(ttm->pages, pinned, 0);
+	return r;
+}
+
+static void radeon_ttm_tt_unpin_userptr(struct ttm_tt *ttm)
+{
+	struct radeon_device *rdev = radeon_get_rdev(ttm->bdev);
+
+	/* free the sg table and pages again */
+	dma_unmap_sg(rdev->dev, ttm->sg->sgl,
+		     ttm->sg->nents, DMA_TO_DEVICE);
+
+	sg_free_table(ttm->sg);
+	kfree(ttm->sg);
+
+	release_pages(ttm->pages, ttm->num_pages, 0);
+}
+
 static int radeon_ttm_tt_populate(struct ttm_tt *ttm)
 {
 	struct radeon_device *rdev;
@@ -599,6 +670,13 @@ static int radeon_ttm_tt_populate(struct ttm_tt *ttm)
 	if (ttm->state != tt_unpopulated)
 		return 0;
 
+	if (gtt->userptr) {
+		r = radeon_ttm_tt_pin_userptr(ttm);
+		if (r)
+			return r;
+		slave = true;
+	}
+
 	if (slave && ttm->sg) {
 		drm_prime_sg_to_page_addr_arrays(ttm->sg, ttm->pages,
 						 gtt->ttm.dma_address, ttm->num_pages);
@@ -648,6 +726,11 @@ static void radeon_ttm_tt_unpopulate(struct ttm_tt *ttm)
 	unsigned i;
 	bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);
 
+	if (gtt->userptr) {
+		radeon_ttm_tt_unpin_userptr(ttm);
+		return;
+	}
+
 	if (slave)
 		return;
 
@@ -676,6 +759,28 @@ static void radeon_ttm_tt_unpopulate(struct ttm_tt *ttm)
 	ttm_pool_unpopulate(ttm);
 }
 
+int radeon_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t userptr)
+{
+	struct radeon_ttm_tt *gtt = (void *)ttm;
+
+	if (gtt == NULL)
+		return -EINVAL;
+
+	gtt->userptr = userptr;
+	gtt->usermm = current->mm;
+	return 0;
+}
+
+bool radeon_ttm_tt_has_userptr(struct ttm_tt *ttm)
+{
+	struct radeon_ttm_tt *gtt = (void *)ttm;
+
+	if (gtt == NULL)
+		return false;
+
+	return !!gtt->userptr;
+}
+
 static struct ttm_bo_driver radeon_bo_driver = {
 	.ttm_tt_create = &radeon_ttm_tt_create,
 	.ttm_tt_populate = &radeon_ttm_tt_populate,
diff --git a/drivers/gpu/drm/radeon/radeon_vm.c b/drivers/gpu/drm/radeon/radeon_vm.c
index eecff6b..99663a8 100644
--- a/drivers/gpu/drm/radeon/radeon_vm.c
+++ b/drivers/gpu/drm/radeon/radeon_vm.c
@@ -850,6 +850,9 @@ int radeon_vm_bo_update(struct radeon_device *rdev,
 
 	bo_va->flags &= ~RADEON_VM_PAGE_VALID;
 	bo_va->flags &= ~RADEON_VM_PAGE_SYSTEM;
+	if (radeon_ttm_tt_has_userptr(bo->tbo.ttm))
+		bo_va->flags &= ~RADEON_VM_PAGE_WRITEABLE;
+
 	if (mem) {
 		addr = mem->start << PAGE_SHIFT;
 		if (mem->mem_type != TTM_PL_SYSTEM) {
diff --git a/include/uapi/drm/radeon_drm.h b/include/uapi/drm/radeon_drm.h
index 1cc0b61..64ef99c 100644
--- a/include/uapi/drm/radeon_drm.h
+++ b/include/uapi/drm/radeon_drm.h
@@ -511,6 +511,7 @@ typedef struct {
 #define DRM_RADEON_GEM_BUSY		0x2a
 #define DRM_RADEON_GEM_VA		0x2b
 #define DRM_RADEON_GEM_OP		0x2c
+#define DRM_RADEON_GEM_IMPORT		0x2d
 
 #define DRM_IOCTL_RADEON_CP_INIT    DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_CP_INIT, drm_radeon_init_t)
 #define DRM_IOCTL_RADEON_CP_START   DRM_IO(  DRM_COMMAND_BASE + DRM_RADEON_CP_START)
@@ -554,6 +555,7 @@ typedef struct {
 #define DRM_IOCTL_RADEON_GEM_BUSY	DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_BUSY, struct drm_radeon_gem_busy)
 #define DRM_IOCTL_RADEON_GEM_VA		DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_VA, struct drm_radeon_gem_va)
 #define DRM_IOCTL_RADEON_GEM_OP		DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_OP, struct drm_radeon_gem_op)
+#define DRM_IOCTL_RADEON_GEM_IMPORT	DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_IMPORT, struct drm_radeon_gem_import)
 
 typedef struct drm_radeon_init {
 	enum {
@@ -806,6 +808,15 @@ struct drm_radeon_gem_create {
 	uint32_t	flags;
 };
 
+#define RADEON_GEM_IMPORT_READONLY	0x1
+
+struct drm_radeon_gem_import {
+	uint64_t		addr;
+	uint64_t		size;
+	uint32_t		flags;
+	uint32_t		handle;
+};
+
 #define RADEON_TILING_MACRO				0x1
 #define RADEON_TILING_MICRO				0x2
 #define RADEON_TILING_SWAP_16BIT			0x4
-- 
1.9.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/2] drm/radeon: add readonly flag to radeon_gart_set_page v2
  2014-07-10 12:33 [PATCH 1/2] drm/radeon: add readonly flag to radeon_gart_set_page v2 Christian König
  2014-07-10 12:33 ` [PATCH 2/2] drm/radeon: add user pointer support v3 Christian König
@ 2014-07-10 13:41 ` Alex Deucher
  1 sibling, 0 replies; 5+ messages in thread
From: Alex Deucher @ 2014-07-10 13:41 UTC (permalink / raw)
  To: Christian König; +Cc: Maling list - DRI developers

On Thu, Jul 10, 2014 at 8:33 AM, Christian König
<deathsimple@vodafone.de> wrote:
> From: Christian König <christian.koenig@amd.com>
>
> v2: use flag instead of boolean
>
> Signed-off-by: Christian König <christian.koenig@amd.com>
> ---
>  drivers/gpu/drm/radeon/r100.c        |  2 +-
>  drivers/gpu/drm/radeon/r300.c        |  8 ++++++--
>  drivers/gpu/drm/radeon/radeon.h      | 12 +++++++-----
>  drivers/gpu/drm/radeon/radeon_asic.h |  8 ++++----
>  drivers/gpu/drm/radeon/radeon_gart.c |  9 +++++----
>  drivers/gpu/drm/radeon/radeon_ttm.c  |  4 ++--
>  drivers/gpu/drm/radeon/rs400.c       |  9 +++++++--
>  drivers/gpu/drm/radeon/rs600.c       |  8 ++++++--
>  8 files changed, 38 insertions(+), 22 deletions(-)
>
> diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
> index a6f7d61..fa71121d7 100644
> --- a/drivers/gpu/drm/radeon/r100.c
> +++ b/drivers/gpu/drm/radeon/r100.c
> @@ -650,7 +650,7 @@ void r100_pci_gart_disable(struct radeon_device *rdev)
>  }
>
>  void r100_pci_gart_set_page(struct radeon_device *rdev, unsigned i,
> -                           uint64_t addr)
> +                           uint64_t addr, uint32_t flags)
>  {
>         u32 *gtt = rdev->gart.ptr;
>         gtt[i] = cpu_to_le32(lower_32_bits(addr));
> diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c
> index 8d14e66..b947f42 100644
> --- a/drivers/gpu/drm/radeon/r300.c
> +++ b/drivers/gpu/drm/radeon/r300.c
> @@ -73,13 +73,17 @@ void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev)
>  #define R300_PTE_READABLE  (1 << 3)
>
>  void rv370_pcie_gart_set_page(struct radeon_device *rdev, unsigned i,
> -                             uint64_t addr)
> +                             uint64_t addr, uint32_t flags)
>  {
>         void __iomem *ptr = rdev->gart.ptr;
>
>         addr = (lower_32_bits(addr) >> 8) |
>                ((upper_32_bits(addr) & 0xff) << 24) |
> -              R300_PTE_WRITEABLE | R300_PTE_READABLE;
> +              R300_PTE_READABLE;
> +
> +       if (!(flags & RADEON_GART_PAGE_READONLY))
> +               addr |= R300_PTE_WRITEABLE;
> +
>         /* on x86 we want this to be CPU endian, on powerpc
>          * on powerpc without HW swappers, it'll get swapped on way
>          * into VRAM - so no need for cpu_to_le32 on VRAM tables */
> diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
> index c5318cac..86fdfa30 100644
> --- a/drivers/gpu/drm/radeon/radeon.h
> +++ b/drivers/gpu/drm/radeon/radeon.h
> @@ -592,6 +592,8 @@ struct radeon_mc;
>  #define RADEON_GPU_PAGE_SHIFT 12
>  #define RADEON_GPU_PAGE_ALIGN(a) (((a) + RADEON_GPU_PAGE_MASK) & ~RADEON_GPU_PAGE_MASK)
>
> +#define RADEON_GART_PAGE_READONLY      1
> +
>  struct radeon_gart {
>         dma_addr_t                      table_addr;
>         struct radeon_bo                *robj;
> @@ -616,7 +618,7 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset,
>                         int pages);
>  int radeon_gart_bind(struct radeon_device *rdev, unsigned offset,
>                      int pages, struct page **pagelist,
> -                    dma_addr_t *dma_addr);
> +                    dma_addr_t *dma_addr, uint32_t flags);
>
>
>  /*
> @@ -854,8 +856,8 @@ struct radeon_mec {
>  #define R600_PTE_FRAG_256KB    (6 << 7)
>
>  /* flags used for GART page table entries on R600+ */
> -#define R600_PTE_GART  ( R600_PTE_VALID | R600_PTE_SYSTEM | R600_PTE_SNOOPED \
> -                       | R600_PTE_READABLE | R600_PTE_WRITEABLE)
> +#define R600_PTE_GART  ( R600_PTE_VALID | R600_PTE_SYSTEM | \
> +                         R600_PTE_SNOOPED | R600_PTE_READABLE )
>

This will disable the gart/GPUVM update optimization in most cases.
Might be better to just leave this define as is and use the individual
flags in the set_page() functions.  I realize this is just a proof of
concept.  Just pointing it out for future reference.

Alex

>  struct radeon_vm_pt {
>         struct radeon_bo                *bo;
> @@ -1775,7 +1777,7 @@ struct radeon_asic {
>         struct {
>                 void (*tlb_flush)(struct radeon_device *rdev);
>                 void (*set_page)(struct radeon_device *rdev, unsigned i,
> -                                uint64_t addr);
> +                                uint64_t addr, uint32_t flags);
>         } gart;
>         struct {
>                 int (*init)(struct radeon_device *rdev);
> @@ -2703,7 +2705,7 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v);
>  #define radeon_vga_set_state(rdev, state) (rdev)->asic->vga_set_state((rdev), (state))
>  #define radeon_asic_reset(rdev) (rdev)->asic->asic_reset((rdev))
>  #define radeon_gart_tlb_flush(rdev) (rdev)->asic->gart.tlb_flush((rdev))
> -#define radeon_gart_set_page(rdev, i, p) (rdev)->asic->gart.set_page((rdev), (i), (p))
> +#define radeon_gart_set_page(rdev, i, p, r) (rdev)->asic->gart.set_page((rdev), (i), (p), (r))
>  #define radeon_asic_vm_init(rdev) (rdev)->asic->vm.init((rdev))
>  #define radeon_asic_vm_fini(rdev) (rdev)->asic->vm.fini((rdev))
>  #define radeon_asic_vm_set_page(rdev, ib, pe, addr, count, incr, flags) ((rdev)->asic->vm.set_page((rdev), (ib), (pe), (addr), (count), (incr), (flags)))
> diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
> index 7531b5e..f7d7c33 100644
> --- a/drivers/gpu/drm/radeon/radeon_asic.h
> +++ b/drivers/gpu/drm/radeon/radeon_asic.h
> @@ -68,7 +68,7 @@ int r100_asic_reset(struct radeon_device *rdev);
>  u32 r100_get_vblank_counter(struct radeon_device *rdev, int crtc);
>  void r100_pci_gart_tlb_flush(struct radeon_device *rdev);
>  void r100_pci_gart_set_page(struct radeon_device *rdev, unsigned i,
> -                           uint64_t addr);
> +                           uint64_t addr, uint32_t flags);
>  void r100_ring_start(struct radeon_device *rdev, struct radeon_ring *ring);
>  int r100_irq_set(struct radeon_device *rdev);
>  int r100_irq_process(struct radeon_device *rdev);
> @@ -172,7 +172,7 @@ extern void r300_fence_ring_emit(struct radeon_device *rdev,
>  extern int r300_cs_parse(struct radeon_cs_parser *p);
>  extern void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev);
>  extern void rv370_pcie_gart_set_page(struct radeon_device *rdev, unsigned i,
> -                                    uint64_t addr);
> +                                    uint64_t addr, uint32_t flags);
>  extern void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes);
>  extern int rv370_get_pcie_lanes(struct radeon_device *rdev);
>  extern void r300_set_reg_safe(struct radeon_device *rdev);
> @@ -208,7 +208,7 @@ extern int rs400_suspend(struct radeon_device *rdev);
>  extern int rs400_resume(struct radeon_device *rdev);
>  void rs400_gart_tlb_flush(struct radeon_device *rdev);
>  void rs400_gart_set_page(struct radeon_device *rdev, unsigned i,
> -                        uint64_t addr);
> +                        uint64_t addr, uint32_t flags);
>  uint32_t rs400_mc_rreg(struct radeon_device *rdev, uint32_t reg);
>  void rs400_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
>  int rs400_gart_init(struct radeon_device *rdev);
> @@ -232,7 +232,7 @@ void rs600_irq_disable(struct radeon_device *rdev);
>  u32 rs600_get_vblank_counter(struct radeon_device *rdev, int crtc);
>  void rs600_gart_tlb_flush(struct radeon_device *rdev);
>  void rs600_gart_set_page(struct radeon_device *rdev, unsigned i,
> -                        uint64_t addr);
> +                        uint64_t addr, uint32_t flags);
>  uint32_t rs600_mc_rreg(struct radeon_device *rdev, uint32_t reg);
>  void rs600_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
>  void rs600_bandwidth_update(struct radeon_device *rdev);
> diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c
> index b7d3e84..b26c0b2 100644
> --- a/drivers/gpu/drm/radeon/radeon_gart.c
> +++ b/drivers/gpu/drm/radeon/radeon_gart.c
> @@ -243,7 +243,7 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset,
>                         page_base = rdev->gart.pages_addr[p];
>                         for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) {
>                                 if (rdev->gart.ptr) {
> -                                       radeon_gart_set_page(rdev, t, page_base);
> +                                       radeon_gart_set_page(rdev, t, page_base, 0);
>                                 }
>                                 page_base += RADEON_GPU_PAGE_SIZE;
>                         }
> @@ -266,8 +266,9 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset,
>   * (all asics).
>   * Returns 0 for success, -EINVAL for failure.
>   */
> -int radeon_gart_bind(struct radeon_device *rdev, unsigned offset,
> -                    int pages, struct page **pagelist, dma_addr_t *dma_addr)
> +int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, int pages,
> +                    struct page **pagelist, dma_addr_t *dma_addr,
> +                    uint32_t flags)
>  {
>         unsigned t;
>         unsigned p;
> @@ -287,7 +288,7 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset,
>                 if (rdev->gart.ptr) {
>                         page_base = rdev->gart.pages_addr[p];
>                         for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) {
> -                               radeon_gart_set_page(rdev, t, page_base);
> +                               radeon_gart_set_page(rdev, t, page_base, flags);
>                                 page_base += RADEON_GPU_PAGE_SIZE;
>                         }
>                 }
> diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
> index c8a8a51..19d662f 100644
> --- a/drivers/gpu/drm/radeon/radeon_ttm.c
> +++ b/drivers/gpu/drm/radeon/radeon_ttm.c
> @@ -528,8 +528,8 @@ static int radeon_ttm_backend_bind(struct ttm_tt *ttm,
>                 WARN(1, "nothing to bind %lu pages for mreg %p back %p!\n",
>                      ttm->num_pages, bo_mem, ttm);
>         }
> -       r = radeon_gart_bind(gtt->rdev, gtt->offset,
> -                            ttm->num_pages, ttm->pages, gtt->ttm.dma_address);
> +       r = radeon_gart_bind(gtt->rdev, gtt->offset, ttm->num_pages,
> +                            ttm->pages, gtt->ttm.dma_address, 0);
>         if (r) {
>                 DRM_ERROR("failed to bind %lu pages at 0x%08X\n",
>                           ttm->num_pages, (unsigned)gtt->offset);
> diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c
> index 4519f9c..5164544 100644
> --- a/drivers/gpu/drm/radeon/rs400.c
> +++ b/drivers/gpu/drm/radeon/rs400.c
> @@ -211,14 +211,19 @@ void rs400_gart_fini(struct radeon_device *rdev)
>  #define RS400_PTE_WRITEABLE (1 << 2)
>  #define RS400_PTE_READABLE  (1 << 3)
>
> -void rs400_gart_set_page(struct radeon_device *rdev, unsigned i, uint64_t addr)
> +void rs400_gart_set_page(struct radeon_device *rdev, unsigned i,
> +                        uint64_t addr, uint32_t flags)
>  {
>         uint32_t entry;
>         u32 *gtt = rdev->gart.ptr;
>
>         entry = (lower_32_bits(addr) & PAGE_MASK) |
>                 ((upper_32_bits(addr) & 0xff) << 4) |
> -               RS400_PTE_WRITEABLE | RS400_PTE_READABLE;
> +               RS400_PTE_READABLE;
> +
> +       if (!(flags & RADEON_GART_PAGE_READONLY))
> +               entry |= RS400_PTE_WRITEABLE;
> +
>         entry = cpu_to_le32(entry);
>         gtt[i] = entry;
>  }
> diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
> index cd7b4b0..3cba999 100644
> --- a/drivers/gpu/drm/radeon/rs600.c
> +++ b/drivers/gpu/drm/radeon/rs600.c
> @@ -611,15 +611,19 @@ static void rs600_gart_fini(struct radeon_device *rdev)
>         radeon_gart_table_vram_free(rdev);
>  }
>
> -void rs600_gart_set_page(struct radeon_device *rdev, unsigned i, uint64_t addr)
> +void rs600_gart_set_page(struct radeon_device *rdev, unsigned i,
> +                        uint64_t addr, uint32_t flags)
>  {
>         void __iomem *ptr = (void *)rdev->gart.ptr;
>
>         addr = addr & 0xFFFFFFFFFFFFF000ULL;
>         if (addr == rdev->dummy_page.addr)
>                 addr |= R600_PTE_SYSTEM | R600_PTE_SNOOPED;
> -       else
> +       else {
>                 addr |= R600_PTE_GART;
> +               if (!(flags & RADEON_GART_PAGE_READONLY))
> +                       addr |= R600_PTE_WRITEABLE;
> +       }
>         writeq(addr, ptr + (i * 8));
>  }
>
> --
> 1.9.1
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/2] drm/radeon: add user pointer support v3
  2014-07-10 12:33 ` [PATCH 2/2] drm/radeon: add user pointer support v3 Christian König
@ 2014-07-10 13:48   ` Alex Deucher
  2014-07-10 14:20     ` Jerome Glisse
  0 siblings, 1 reply; 5+ messages in thread
From: Alex Deucher @ 2014-07-10 13:48 UTC (permalink / raw)
  To: Christian König; +Cc: Maling list - DRI developers

On Thu, Jul 10, 2014 at 8:33 AM, Christian König
<deathsimple@vodafone.de> wrote:
> From: Christian König <christian.koenig@amd.com>
>
> 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
>
> Signed-off-by: Christian König <christian.koenig@amd.com>

Reviewed-by: Alex Deucher <alexander.deucher@amd.com>

> ---
>  drivers/gpu/drm/radeon/radeon.h        |   4 ++
>  drivers/gpu/drm/radeon/radeon_cs.c     |  25 +++++++-
>  drivers/gpu/drm/radeon/radeon_drv.c    |   5 +-
>  drivers/gpu/drm/radeon/radeon_gem.c    |  67 +++++++++++++++++++++
>  drivers/gpu/drm/radeon/radeon_kms.c    |   1 +
>  drivers/gpu/drm/radeon/radeon_object.c |   3 +
>  drivers/gpu/drm/radeon/radeon_prime.c  |  10 +++
>  drivers/gpu/drm/radeon/radeon_ttm.c    | 107 ++++++++++++++++++++++++++++++++-
>  drivers/gpu/drm/radeon/radeon_vm.c     |   3 +
>  include/uapi/drm/radeon_drm.h          |  11 ++++
>  10 files changed, 232 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
> index 86fdfa30..55c996e 100644
> --- a/drivers/gpu/drm/radeon/radeon.h
> +++ b/drivers/gpu/drm/radeon/radeon.h
> @@ -2111,6 +2111,8 @@ int radeon_gem_info_ioctl(struct drm_device *dev, void *data,
>                           struct drm_file *filp);
>  int radeon_gem_create_ioctl(struct drm_device *dev, void *data,
>                             struct drm_file *filp);
> +int radeon_gem_import_ioctl(struct drm_device *dev, void *data,
> +                           struct drm_file *filp);
>  int radeon_gem_pin_ioctl(struct drm_device *dev, void *data,
>                          struct drm_file *file_priv);
>  int radeon_gem_unpin_ioctl(struct drm_device *dev, void *data,
> @@ -2803,6 +2805,8 @@ extern void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enabl
>  extern void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable);
>  extern void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain);
>  extern bool radeon_ttm_bo_is_radeon_bo(struct ttm_buffer_object *bo);
> +extern int radeon_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t userptr);
> +extern bool radeon_ttm_tt_has_userptr(struct ttm_tt *ttm);
>  extern void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64 base);
>  extern void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
>  extern 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 71a1434..be65311 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)
>         struct radeon_cs_chunk *chunk;
>         struct radeon_cs_buckets buckets;
>         unsigned i, j;
> -       bool duplicate;
> +       bool duplicate, need_mmap_lock = false;
> +       int r;
>
>         if (p->chunk_relocs_idx == -1) {
>                 return 0;
> @@ -164,6 +165,19 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
>                         p->relocs[i].allowed_domains = domain;
>                 }
>
> +               if (radeon_ttm_tt_has_userptr(p->relocs[i].robj->tbo.ttm)) {
> +                       uint32_t domain = p->relocs[i].prefered_domains;
> +                       if (!(domain & RADEON_GEM_DOMAIN_GTT)) {
> +                               DRM_ERROR("Only RADEON_GEM_DOMAIN_GTT is "
> +                                         "allowed for userptr BOs\n");
> +                               return -EINVAL;
> +                       }
> +                       need_mmap_lock = true;
> +                       domain = RADEON_GEM_DOMAIN_GTT;
> +                       p->relocs[i].prefered_domains = domain;
> +                       p->relocs[i].allowed_domains = domain;
> +               }
> +
>                 p->relocs[i].tv.bo = &p->relocs[i].robj->tbo;
>                 p->relocs[i].handle = r->handle;
>
> @@ -176,8 +190,15 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
>         if (p->cs_flags & RADEON_CS_USE_VM)
>                 p->vm_bos = radeon_vm_get_bos(p->rdev, p->ib.vm,
>                                               &p->validated);
> +       if (need_mmap_lock)
> +               down_read(&current->mm->mmap_sem);
> +
> +       r = radeon_bo_list_validate(p->rdev, &p->ticket, &p->validated, p->ring);
>
> -       return radeon_bo_list_validate(p->rdev, &p->ticket, &p->validated, p->ring);
> +       if (need_mmap_lock)
> +               up_read(&current->mm->mmap_sem);
> +
> +       return r;
>  }
>
>  static 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 cb14213..bf91879 100644
> --- a/drivers/gpu/drm/radeon/radeon_drv.c
> +++ b/drivers/gpu/drm/radeon/radeon_drv.c
> @@ -112,6 +112,9 @@ int radeon_gem_object_open(struct drm_gem_object *obj,
>                                 struct drm_file *file_priv);
>  void radeon_gem_object_close(struct drm_gem_object *obj,
>                                 struct drm_file *file_priv);
> +struct dma_buf *radeon_gem_prime_export(struct drm_device *dev,
> +                                       struct drm_gem_object *gobj,
> +                                       int flags);
>  extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc,
>                                       unsigned int flags,
>                                       int *vpos, int *hpos, ktime_t *stime,
> @@ -562,7 +565,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 = drm_gem_prime_export,
> +       .gem_prime_export = radeon_gem_prime_export,
>         .gem_prime_import = drm_gem_prime_import,
>         .gem_prime_pin = radeon_gem_prime_pin,
>         .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 d09650c..2464c65 100644
> --- a/drivers/gpu/drm/radeon/radeon_gem.c
> +++ b/drivers/gpu/drm/radeon/radeon_gem.c
> @@ -272,6 +272,64 @@ int radeon_gem_create_ioctl(struct drm_device *dev, void *data,
>         return 0;
>  }
>
> +int radeon_gem_import_ioctl(struct drm_device *dev, void *data,
> +                           struct drm_file *filp)
> +{
> +       struct radeon_device *rdev = dev->dev_private;
> +       struct drm_radeon_gem_import *args = data;
> +       struct drm_gem_object *gobj;
> +       struct radeon_bo *bo;
> +       uint32_t handle;
> +       int r;
> +
> +       if (offset_in_page(args->addr | args->size))
> +               return -EINVAL;
> +
> +       /* we only support read only mappings for now */
> +       if (!(args->flags & RADEON_GEM_IMPORT_READONLY))
> +               return -EACCES;
> +
> +       /* readonly pages not tested on older hardware */
> +       if (rdev->family < CHIP_R600)
> +               return -EINVAL;
> +
> +       if (!access_ok(VERIFY_READ, (char __user *)args->addr, args->size))
> +               return -EFAULT;
> +
> +       down_read(&rdev->exclusive_lock);
> +
> +       /* create a gem object to contain this object in */
> +       r = radeon_gem_object_create(rdev, args->size, 0,
> +                                    RADEON_GEM_DOMAIN_CPU,
> +                                    false, false, &gobj);
> +       if (r)
> +               goto handle_lockup;
> +
> +       bo = gem_to_radeon_bo(gobj);
> +       r = radeon_ttm_tt_set_userptr(bo->tbo.ttm, args->addr);
> +       if (r)
> +               goto release_object;
> +
> +       r = drm_gem_handle_create(filp, gobj, &handle);
> +       /* drop reference from allocate - handle holds it now */
> +       drm_gem_object_unreference_unlocked(gobj);
> +       if (r)
> +               goto handle_lockup;
> +
> +       args->handle = handle;
> +       up_read(&rdev->exclusive_lock);
> +       return 0;
> +
> +release_object:
> +       drm_gem_object_unreference_unlocked(gobj);
> +
> +handle_lockup:
> +       up_read(&rdev->exclusive_lock);
> +       r = radeon_gem_handle_lockup(rdev, r);
> +
> +       return r;
> +}
> +
>  int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data,
>                                 struct drm_file *filp)
>  {
> @@ -315,6 +373,10 @@ int radeon_mode_dumb_mmap(struct drm_file *filp,
>                 return -ENOENT;
>         }
>         robj = gem_to_radeon_bo(gobj);
> +       if (radeon_ttm_tt_has_userptr(robj->tbo.ttm)) {
> +               drm_gem_object_unreference_unlocked(gobj);
> +               return -EPERM;
> +       }
>         *offset_p = radeon_bo_mmap_offset(robj);
>         drm_gem_object_unreference_unlocked(gobj);
>         return 0;
> @@ -535,6 +597,11 @@ int radeon_gem_op_ioctl(struct drm_device *dev, void *data,
>                 return -ENOENT;
>         }
>         robj = gem_to_radeon_bo(gobj);
> +
> +       r = -EPERM;
> +       if (radeon_ttm_tt_has_userptr(robj->tbo.ttm))
> +               goto out;
> +
>         r = radeon_bo_reserve(robj, false);
>         if (unlikely(r))
>                 goto out;
> diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c
> index 35d9318..39e8a5c 100644
> --- a/drivers/gpu/drm/radeon/radeon_kms.c
> +++ b/drivers/gpu/drm/radeon/radeon_kms.c
> @@ -874,5 +874,6 @@ const struct drm_ioctl_desc radeon_ioctls_kms[] = {
>         DRM_IOCTL_DEF_DRV(RADEON_GEM_BUSY, radeon_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
>         DRM_IOCTL_DEF_DRV(RADEON_GEM_VA, radeon_gem_va_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
>         DRM_IOCTL_DEF_DRV(RADEON_GEM_OP, radeon_gem_op_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
> +       DRM_IOCTL_DEF_DRV(RADEON_GEM_IMPORT, radeon_gem_import_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
>  };
>  int radeon_max_kms_ioctl = ARRAY_SIZE(radeon_ioctls_kms);
> diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
> index 6c717b2..c1f826b 100644
> --- a/drivers/gpu/drm/radeon/radeon_object.c
> +++ b/drivers/gpu/drm/radeon/radeon_object.c
> @@ -253,6 +253,9 @@ int radeon_bo_pin_restricted(struct radeon_bo *bo, u32 domain, u64 max_offset,
>  {
>         int r, i;
>
> +       if (radeon_ttm_tt_has_userptr(bo->tbo.ttm))
> +               return -EPERM;
> +
>         if (bo->pin_count) {
>                 bo->pin_count++;
>                 if (gpu_addr)
> diff --git a/drivers/gpu/drm/radeon/radeon_prime.c b/drivers/gpu/drm/radeon/radeon_prime.c
> index 2007456..1f0d8f7 100644
> --- a/drivers/gpu/drm/radeon/radeon_prime.c
> +++ b/drivers/gpu/drm/radeon/radeon_prime.c
> @@ -103,3 +103,13 @@ void radeon_gem_prime_unpin(struct drm_gem_object *obj)
>         radeon_bo_unpin(bo);
>         radeon_bo_unreserve(bo);
>  }
> +
> +struct dma_buf *radeon_gem_prime_export(struct drm_device *dev,
> +                                       struct drm_gem_object *gobj,
> +                                       int flags)
> +{
> +       struct radeon_bo *bo = gem_to_radeon_bo(gobj);
> +       if (radeon_ttm_tt_has_userptr(bo->tbo.ttm))
> +               return ERR_PTR(-EPERM);
> +       return drm_gem_prime_export(dev, gobj, flags);
> +}
> diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
> index 19d662f..fee6018 100644
> --- a/drivers/gpu/drm/radeon/radeon_ttm.c
> +++ b/drivers/gpu/drm/radeon/radeon_ttm.c
> @@ -515,12 +515,16 @@ struct radeon_ttm_tt {
>         struct ttm_dma_tt               ttm;
>         struct radeon_device            *rdev;
>         u64                             offset;
> +
> +       uint64_t                        userptr;
> +       struct mm_struct                *usermm;
>  };
>
>  static int radeon_ttm_backend_bind(struct ttm_tt *ttm,
>                                    struct ttm_mem_reg *bo_mem)
>  {
>         struct radeon_ttm_tt *gtt = (void*)ttm;
> +       uint32_t flags = gtt->userptr ? RADEON_GART_PAGE_READONLY : 0;
>         int r;
>
>         gtt->offset = (unsigned long)(bo_mem->start << PAGE_SHIFT);
> @@ -529,7 +533,7 @@ static int radeon_ttm_backend_bind(struct ttm_tt *ttm,
>                      ttm->num_pages, bo_mem, ttm);
>         }
>         r = radeon_gart_bind(gtt->rdev, gtt->offset, ttm->num_pages,
> -                            ttm->pages, gtt->ttm.dma_address, 0);
> +                            ttm->pages, gtt->ttm.dma_address, flags);
>         if (r) {
>                 DRM_ERROR("failed to bind %lu pages at 0x%08X\n",
>                           ttm->num_pages, (unsigned)gtt->offset);
> @@ -588,6 +592,73 @@ static struct ttm_tt *radeon_ttm_tt_create(struct ttm_bo_device *bdev,
>         return &gtt->ttm.ttm;
>  }
>
> +static int radeon_ttm_tt_pin_userptr(struct ttm_tt *ttm)
> +{
> +       struct radeon_device *rdev = radeon_get_rdev(ttm->bdev);
> +       struct radeon_ttm_tt *gtt = (void *)ttm;
> +       unsigned pinned = 0, nents;
> +       int r;
> +
> +       /* prepare the sg table with the user pages */
> +       if (current->mm != gtt->usermm)
> +               return -EPERM;
> +
> +       do {
> +               unsigned num_pages = ttm->num_pages - pinned;
> +               uint64_t userptr = gtt->userptr + pinned * PAGE_SIZE;
> +               struct page **pages = ttm->pages + pinned;
> +
> +               r = get_user_pages(current, current->mm, userptr, num_pages,
> +                                  0, 0, pages, NULL);
> +               if (r < 0) {
> +                       release_pages(ttm->pages, pinned, 0);
> +                       return r;
> +               }
> +               pinned += r;
> +
> +       } while (pinned < ttm->num_pages);
> +
> +       r = -ENOMEM;
> +       ttm->sg = kcalloc(1, sizeof(struct sg_table), GFP_KERNEL);
> +       if (!ttm->sg)
> +               goto release_pages;
> +
> +       r = sg_alloc_table_from_pages(ttm->sg, ttm->pages, ttm->num_pages, 0,
> +                                     ttm->num_pages << PAGE_SHIFT,
> +                                     GFP_KERNEL);
> +       if (r)
> +               goto release_sg;
> +
> +       r = -ENOMEM;
> +       nents = dma_map_sg(rdev->dev, ttm->sg->sgl, ttm->sg->nents,
> +                          DMA_TO_DEVICE);
> +       if (nents != ttm->sg->nents)
> +               goto release_sg;
> +
> +       return 0;
> +
> +release_sg:
> +       kfree(ttm->sg);
> +
> +release_pages:
> +       release_pages(ttm->pages, pinned, 0);
> +       return r;
> +}
> +
> +static void radeon_ttm_tt_unpin_userptr(struct ttm_tt *ttm)
> +{
> +       struct radeon_device *rdev = radeon_get_rdev(ttm->bdev);
> +
> +       /* free the sg table and pages again */
> +       dma_unmap_sg(rdev->dev, ttm->sg->sgl,
> +                    ttm->sg->nents, DMA_TO_DEVICE);
> +
> +       sg_free_table(ttm->sg);
> +       kfree(ttm->sg);
> +
> +       release_pages(ttm->pages, ttm->num_pages, 0);
> +}
> +
>  static int radeon_ttm_tt_populate(struct ttm_tt *ttm)
>  {
>         struct radeon_device *rdev;
> @@ -599,6 +670,13 @@ static int radeon_ttm_tt_populate(struct ttm_tt *ttm)
>         if (ttm->state != tt_unpopulated)
>                 return 0;
>
> +       if (gtt->userptr) {
> +               r = radeon_ttm_tt_pin_userptr(ttm);
> +               if (r)
> +                       return r;
> +               slave = true;
> +       }
> +
>         if (slave && ttm->sg) {
>                 drm_prime_sg_to_page_addr_arrays(ttm->sg, ttm->pages,
>                                                  gtt->ttm.dma_address, ttm->num_pages);
> @@ -648,6 +726,11 @@ static void radeon_ttm_tt_unpopulate(struct ttm_tt *ttm)
>         unsigned i;
>         bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);
>
> +       if (gtt->userptr) {
> +               radeon_ttm_tt_unpin_userptr(ttm);
> +               return;
> +       }
> +
>         if (slave)
>                 return;
>
> @@ -676,6 +759,28 @@ static void radeon_ttm_tt_unpopulate(struct ttm_tt *ttm)
>         ttm_pool_unpopulate(ttm);
>  }
>
> +int radeon_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t userptr)
> +{
> +       struct radeon_ttm_tt *gtt = (void *)ttm;
> +
> +       if (gtt == NULL)
> +               return -EINVAL;
> +
> +       gtt->userptr = userptr;
> +       gtt->usermm = current->mm;
> +       return 0;
> +}
> +
> +bool radeon_ttm_tt_has_userptr(struct ttm_tt *ttm)
> +{
> +       struct radeon_ttm_tt *gtt = (void *)ttm;
> +
> +       if (gtt == NULL)
> +               return false;
> +
> +       return !!gtt->userptr;
> +}
> +
>  static struct ttm_bo_driver radeon_bo_driver = {
>         .ttm_tt_create = &radeon_ttm_tt_create,
>         .ttm_tt_populate = &radeon_ttm_tt_populate,
> diff --git a/drivers/gpu/drm/radeon/radeon_vm.c b/drivers/gpu/drm/radeon/radeon_vm.c
> index eecff6b..99663a8 100644
> --- a/drivers/gpu/drm/radeon/radeon_vm.c
> +++ b/drivers/gpu/drm/radeon/radeon_vm.c
> @@ -850,6 +850,9 @@ int radeon_vm_bo_update(struct radeon_device *rdev,
>
>         bo_va->flags &= ~RADEON_VM_PAGE_VALID;
>         bo_va->flags &= ~RADEON_VM_PAGE_SYSTEM;
> +       if (radeon_ttm_tt_has_userptr(bo->tbo.ttm))
> +               bo_va->flags &= ~RADEON_VM_PAGE_WRITEABLE;
> +
>         if (mem) {
>                 addr = mem->start << PAGE_SHIFT;
>                 if (mem->mem_type != TTM_PL_SYSTEM) {
> diff --git a/include/uapi/drm/radeon_drm.h b/include/uapi/drm/radeon_drm.h
> index 1cc0b61..64ef99c 100644
> --- a/include/uapi/drm/radeon_drm.h
> +++ b/include/uapi/drm/radeon_drm.h
> @@ -511,6 +511,7 @@ typedef struct {
>  #define DRM_RADEON_GEM_BUSY            0x2a
>  #define DRM_RADEON_GEM_VA              0x2b
>  #define DRM_RADEON_GEM_OP              0x2c
> +#define DRM_RADEON_GEM_IMPORT          0x2d
>
>  #define DRM_IOCTL_RADEON_CP_INIT    DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_CP_INIT, drm_radeon_init_t)
>  #define DRM_IOCTL_RADEON_CP_START   DRM_IO(  DRM_COMMAND_BASE + DRM_RADEON_CP_START)
> @@ -554,6 +555,7 @@ typedef struct {
>  #define DRM_IOCTL_RADEON_GEM_BUSY      DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_BUSY, struct drm_radeon_gem_busy)
>  #define DRM_IOCTL_RADEON_GEM_VA                DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_VA, struct drm_radeon_gem_va)
>  #define DRM_IOCTL_RADEON_GEM_OP                DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_OP, struct drm_radeon_gem_op)
> +#define DRM_IOCTL_RADEON_GEM_IMPORT    DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_IMPORT, struct drm_radeon_gem_import)
>
>  typedef struct drm_radeon_init {
>         enum {
> @@ -806,6 +808,15 @@ struct drm_radeon_gem_create {
>         uint32_t        flags;
>  };
>
> +#define RADEON_GEM_IMPORT_READONLY     0x1
> +
> +struct drm_radeon_gem_import {
> +       uint64_t                addr;
> +       uint64_t                size;
> +       uint32_t                flags;
> +       uint32_t                handle;
> +};
> +
>  #define RADEON_TILING_MACRO                            0x1
>  #define RADEON_TILING_MICRO                            0x2
>  #define RADEON_TILING_SWAP_16BIT                       0x4
> --
> 1.9.1
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/2] drm/radeon: add user pointer support v3
  2014-07-10 13:48   ` Alex Deucher
@ 2014-07-10 14:20     ` Jerome Glisse
  0 siblings, 0 replies; 5+ messages in thread
From: Jerome Glisse @ 2014-07-10 14:20 UTC (permalink / raw)
  To: Alex Deucher; +Cc: Maling list - DRI developers

On Thu, Jul 10, 2014 at 09:48:49AM -0400, Alex Deucher wrote:
> On Thu, Jul 10, 2014 at 8:33 AM, Christian König
> <deathsimple@vodafone.de> wrote:
> > From: Christian König <christian.koenig@amd.com>
> >
> > 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
> >
> > Signed-off-by: Christian König <christian.koenig@amd.com>
> 
> Reviewed-by: Alex Deucher <alexander.deucher@amd.com>

Well i am not oppose to userptr even if i dislike it and this version
do not have the crazy mmu_notifier thing so.

Reviewed-by: Jérôme Glisse <jglisse@redhat.com>

> 
> > ---
> >  drivers/gpu/drm/radeon/radeon.h        |   4 ++
> >  drivers/gpu/drm/radeon/radeon_cs.c     |  25 +++++++-
> >  drivers/gpu/drm/radeon/radeon_drv.c    |   5 +-
> >  drivers/gpu/drm/radeon/radeon_gem.c    |  67 +++++++++++++++++++++
> >  drivers/gpu/drm/radeon/radeon_kms.c    |   1 +
> >  drivers/gpu/drm/radeon/radeon_object.c |   3 +
> >  drivers/gpu/drm/radeon/radeon_prime.c  |  10 +++
> >  drivers/gpu/drm/radeon/radeon_ttm.c    | 107 ++++++++++++++++++++++++++++++++-
> >  drivers/gpu/drm/radeon/radeon_vm.c     |   3 +
> >  include/uapi/drm/radeon_drm.h          |  11 ++++
> >  10 files changed, 232 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
> > index 86fdfa30..55c996e 100644
> > --- a/drivers/gpu/drm/radeon/radeon.h
> > +++ b/drivers/gpu/drm/radeon/radeon.h
> > @@ -2111,6 +2111,8 @@ int radeon_gem_info_ioctl(struct drm_device *dev, void *data,
> >                           struct drm_file *filp);
> >  int radeon_gem_create_ioctl(struct drm_device *dev, void *data,
> >                             struct drm_file *filp);
> > +int radeon_gem_import_ioctl(struct drm_device *dev, void *data,
> > +                           struct drm_file *filp);
> >  int radeon_gem_pin_ioctl(struct drm_device *dev, void *data,
> >                          struct drm_file *file_priv);
> >  int radeon_gem_unpin_ioctl(struct drm_device *dev, void *data,
> > @@ -2803,6 +2805,8 @@ extern void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enabl
> >  extern void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable);
> >  extern void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain);
> >  extern bool radeon_ttm_bo_is_radeon_bo(struct ttm_buffer_object *bo);
> > +extern int radeon_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t userptr);
> > +extern bool radeon_ttm_tt_has_userptr(struct ttm_tt *ttm);
> >  extern void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64 base);
> >  extern void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
> >  extern 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 71a1434..be65311 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)
> >         struct radeon_cs_chunk *chunk;
> >         struct radeon_cs_buckets buckets;
> >         unsigned i, j;
> > -       bool duplicate;
> > +       bool duplicate, need_mmap_lock = false;
> > +       int r;
> >
> >         if (p->chunk_relocs_idx == -1) {
> >                 return 0;
> > @@ -164,6 +165,19 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
> >                         p->relocs[i].allowed_domains = domain;
> >                 }
> >
> > +               if (radeon_ttm_tt_has_userptr(p->relocs[i].robj->tbo.ttm)) {
> > +                       uint32_t domain = p->relocs[i].prefered_domains;
> > +                       if (!(domain & RADEON_GEM_DOMAIN_GTT)) {
> > +                               DRM_ERROR("Only RADEON_GEM_DOMAIN_GTT is "
> > +                                         "allowed for userptr BOs\n");
> > +                               return -EINVAL;
> > +                       }
> > +                       need_mmap_lock = true;
> > +                       domain = RADEON_GEM_DOMAIN_GTT;
> > +                       p->relocs[i].prefered_domains = domain;
> > +                       p->relocs[i].allowed_domains = domain;
> > +               }
> > +
> >                 p->relocs[i].tv.bo = &p->relocs[i].robj->tbo;
> >                 p->relocs[i].handle = r->handle;
> >
> > @@ -176,8 +190,15 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
> >         if (p->cs_flags & RADEON_CS_USE_VM)
> >                 p->vm_bos = radeon_vm_get_bos(p->rdev, p->ib.vm,
> >                                               &p->validated);
> > +       if (need_mmap_lock)
> > +               down_read(&current->mm->mmap_sem);
> > +
> > +       r = radeon_bo_list_validate(p->rdev, &p->ticket, &p->validated, p->ring);
> >
> > -       return radeon_bo_list_validate(p->rdev, &p->ticket, &p->validated, p->ring);
> > +       if (need_mmap_lock)
> > +               up_read(&current->mm->mmap_sem);
> > +
> > +       return r;
> >  }
> >
> >  static 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 cb14213..bf91879 100644
> > --- a/drivers/gpu/drm/radeon/radeon_drv.c
> > +++ b/drivers/gpu/drm/radeon/radeon_drv.c
> > @@ -112,6 +112,9 @@ int radeon_gem_object_open(struct drm_gem_object *obj,
> >                                 struct drm_file *file_priv);
> >  void radeon_gem_object_close(struct drm_gem_object *obj,
> >                                 struct drm_file *file_priv);
> > +struct dma_buf *radeon_gem_prime_export(struct drm_device *dev,
> > +                                       struct drm_gem_object *gobj,
> > +                                       int flags);
> >  extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc,
> >                                       unsigned int flags,
> >                                       int *vpos, int *hpos, ktime_t *stime,
> > @@ -562,7 +565,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 = drm_gem_prime_export,
> > +       .gem_prime_export = radeon_gem_prime_export,
> >         .gem_prime_import = drm_gem_prime_import,
> >         .gem_prime_pin = radeon_gem_prime_pin,
> >         .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 d09650c..2464c65 100644
> > --- a/drivers/gpu/drm/radeon/radeon_gem.c
> > +++ b/drivers/gpu/drm/radeon/radeon_gem.c
> > @@ -272,6 +272,64 @@ int radeon_gem_create_ioctl(struct drm_device *dev, void *data,
> >         return 0;
> >  }
> >
> > +int radeon_gem_import_ioctl(struct drm_device *dev, void *data,
> > +                           struct drm_file *filp)
> > +{
> > +       struct radeon_device *rdev = dev->dev_private;
> > +       struct drm_radeon_gem_import *args = data;
> > +       struct drm_gem_object *gobj;
> > +       struct radeon_bo *bo;
> > +       uint32_t handle;
> > +       int r;
> > +
> > +       if (offset_in_page(args->addr | args->size))
> > +               return -EINVAL;
> > +
> > +       /* we only support read only mappings for now */
> > +       if (!(args->flags & RADEON_GEM_IMPORT_READONLY))
> > +               return -EACCES;
> > +
> > +       /* readonly pages not tested on older hardware */
> > +       if (rdev->family < CHIP_R600)
> > +               return -EINVAL;
> > +
> > +       if (!access_ok(VERIFY_READ, (char __user *)args->addr, args->size))
> > +               return -EFAULT;
> > +
> > +       down_read(&rdev->exclusive_lock);
> > +
> > +       /* create a gem object to contain this object in */
> > +       r = radeon_gem_object_create(rdev, args->size, 0,
> > +                                    RADEON_GEM_DOMAIN_CPU,
> > +                                    false, false, &gobj);
> > +       if (r)
> > +               goto handle_lockup;
> > +
> > +       bo = gem_to_radeon_bo(gobj);
> > +       r = radeon_ttm_tt_set_userptr(bo->tbo.ttm, args->addr);
> > +       if (r)
> > +               goto release_object;
> > +
> > +       r = drm_gem_handle_create(filp, gobj, &handle);
> > +       /* drop reference from allocate - handle holds it now */
> > +       drm_gem_object_unreference_unlocked(gobj);
> > +       if (r)
> > +               goto handle_lockup;
> > +
> > +       args->handle = handle;
> > +       up_read(&rdev->exclusive_lock);
> > +       return 0;
> > +
> > +release_object:
> > +       drm_gem_object_unreference_unlocked(gobj);
> > +
> > +handle_lockup:
> > +       up_read(&rdev->exclusive_lock);
> > +       r = radeon_gem_handle_lockup(rdev, r);
> > +
> > +       return r;
> > +}
> > +
> >  int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data,
> >                                 struct drm_file *filp)
> >  {
> > @@ -315,6 +373,10 @@ int radeon_mode_dumb_mmap(struct drm_file *filp,
> >                 return -ENOENT;
> >         }
> >         robj = gem_to_radeon_bo(gobj);
> > +       if (radeon_ttm_tt_has_userptr(robj->tbo.ttm)) {
> > +               drm_gem_object_unreference_unlocked(gobj);
> > +               return -EPERM;
> > +       }
> >         *offset_p = radeon_bo_mmap_offset(robj);
> >         drm_gem_object_unreference_unlocked(gobj);
> >         return 0;
> > @@ -535,6 +597,11 @@ int radeon_gem_op_ioctl(struct drm_device *dev, void *data,
> >                 return -ENOENT;
> >         }
> >         robj = gem_to_radeon_bo(gobj);
> > +
> > +       r = -EPERM;
> > +       if (radeon_ttm_tt_has_userptr(robj->tbo.ttm))
> > +               goto out;
> > +
> >         r = radeon_bo_reserve(robj, false);
> >         if (unlikely(r))
> >                 goto out;
> > diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c
> > index 35d9318..39e8a5c 100644
> > --- a/drivers/gpu/drm/radeon/radeon_kms.c
> > +++ b/drivers/gpu/drm/radeon/radeon_kms.c
> > @@ -874,5 +874,6 @@ const struct drm_ioctl_desc radeon_ioctls_kms[] = {
> >         DRM_IOCTL_DEF_DRV(RADEON_GEM_BUSY, radeon_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
> >         DRM_IOCTL_DEF_DRV(RADEON_GEM_VA, radeon_gem_va_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
> >         DRM_IOCTL_DEF_DRV(RADEON_GEM_OP, radeon_gem_op_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
> > +       DRM_IOCTL_DEF_DRV(RADEON_GEM_IMPORT, radeon_gem_import_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
> >  };
> >  int radeon_max_kms_ioctl = ARRAY_SIZE(radeon_ioctls_kms);
> > diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
> > index 6c717b2..c1f826b 100644
> > --- a/drivers/gpu/drm/radeon/radeon_object.c
> > +++ b/drivers/gpu/drm/radeon/radeon_object.c
> > @@ -253,6 +253,9 @@ int radeon_bo_pin_restricted(struct radeon_bo *bo, u32 domain, u64 max_offset,
> >  {
> >         int r, i;
> >
> > +       if (radeon_ttm_tt_has_userptr(bo->tbo.ttm))
> > +               return -EPERM;
> > +
> >         if (bo->pin_count) {
> >                 bo->pin_count++;
> >                 if (gpu_addr)
> > diff --git a/drivers/gpu/drm/radeon/radeon_prime.c b/drivers/gpu/drm/radeon/radeon_prime.c
> > index 2007456..1f0d8f7 100644
> > --- a/drivers/gpu/drm/radeon/radeon_prime.c
> > +++ b/drivers/gpu/drm/radeon/radeon_prime.c
> > @@ -103,3 +103,13 @@ void radeon_gem_prime_unpin(struct drm_gem_object *obj)
> >         radeon_bo_unpin(bo);
> >         radeon_bo_unreserve(bo);
> >  }
> > +
> > +struct dma_buf *radeon_gem_prime_export(struct drm_device *dev,
> > +                                       struct drm_gem_object *gobj,
> > +                                       int flags)
> > +{
> > +       struct radeon_bo *bo = gem_to_radeon_bo(gobj);
> > +       if (radeon_ttm_tt_has_userptr(bo->tbo.ttm))
> > +               return ERR_PTR(-EPERM);
> > +       return drm_gem_prime_export(dev, gobj, flags);
> > +}
> > diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
> > index 19d662f..fee6018 100644
> > --- a/drivers/gpu/drm/radeon/radeon_ttm.c
> > +++ b/drivers/gpu/drm/radeon/radeon_ttm.c
> > @@ -515,12 +515,16 @@ struct radeon_ttm_tt {
> >         struct ttm_dma_tt               ttm;
> >         struct radeon_device            *rdev;
> >         u64                             offset;
> > +
> > +       uint64_t                        userptr;
> > +       struct mm_struct                *usermm;
> >  };
> >
> >  static int radeon_ttm_backend_bind(struct ttm_tt *ttm,
> >                                    struct ttm_mem_reg *bo_mem)
> >  {
> >         struct radeon_ttm_tt *gtt = (void*)ttm;
> > +       uint32_t flags = gtt->userptr ? RADEON_GART_PAGE_READONLY : 0;
> >         int r;
> >
> >         gtt->offset = (unsigned long)(bo_mem->start << PAGE_SHIFT);
> > @@ -529,7 +533,7 @@ static int radeon_ttm_backend_bind(struct ttm_tt *ttm,
> >                      ttm->num_pages, bo_mem, ttm);
> >         }
> >         r = radeon_gart_bind(gtt->rdev, gtt->offset, ttm->num_pages,
> > -                            ttm->pages, gtt->ttm.dma_address, 0);
> > +                            ttm->pages, gtt->ttm.dma_address, flags);
> >         if (r) {
> >                 DRM_ERROR("failed to bind %lu pages at 0x%08X\n",
> >                           ttm->num_pages, (unsigned)gtt->offset);
> > @@ -588,6 +592,73 @@ static struct ttm_tt *radeon_ttm_tt_create(struct ttm_bo_device *bdev,
> >         return &gtt->ttm.ttm;
> >  }
> >
> > +static int radeon_ttm_tt_pin_userptr(struct ttm_tt *ttm)
> > +{
> > +       struct radeon_device *rdev = radeon_get_rdev(ttm->bdev);
> > +       struct radeon_ttm_tt *gtt = (void *)ttm;
> > +       unsigned pinned = 0, nents;
> > +       int r;
> > +
> > +       /* prepare the sg table with the user pages */
> > +       if (current->mm != gtt->usermm)
> > +               return -EPERM;
> > +
> > +       do {
> > +               unsigned num_pages = ttm->num_pages - pinned;
> > +               uint64_t userptr = gtt->userptr + pinned * PAGE_SIZE;
> > +               struct page **pages = ttm->pages + pinned;
> > +
> > +               r = get_user_pages(current, current->mm, userptr, num_pages,
> > +                                  0, 0, pages, NULL);
> > +               if (r < 0) {
> > +                       release_pages(ttm->pages, pinned, 0);
> > +                       return r;
> > +               }
> > +               pinned += r;
> > +
> > +       } while (pinned < ttm->num_pages);
> > +
> > +       r = -ENOMEM;
> > +       ttm->sg = kcalloc(1, sizeof(struct sg_table), GFP_KERNEL);
> > +       if (!ttm->sg)
> > +               goto release_pages;
> > +
> > +       r = sg_alloc_table_from_pages(ttm->sg, ttm->pages, ttm->num_pages, 0,
> > +                                     ttm->num_pages << PAGE_SHIFT,
> > +                                     GFP_KERNEL);
> > +       if (r)
> > +               goto release_sg;
> > +
> > +       r = -ENOMEM;
> > +       nents = dma_map_sg(rdev->dev, ttm->sg->sgl, ttm->sg->nents,
> > +                          DMA_TO_DEVICE);
> > +       if (nents != ttm->sg->nents)
> > +               goto release_sg;
> > +
> > +       return 0;
> > +
> > +release_sg:
> > +       kfree(ttm->sg);
> > +
> > +release_pages:
> > +       release_pages(ttm->pages, pinned, 0);
> > +       return r;
> > +}
> > +
> > +static void radeon_ttm_tt_unpin_userptr(struct ttm_tt *ttm)
> > +{
> > +       struct radeon_device *rdev = radeon_get_rdev(ttm->bdev);
> > +
> > +       /* free the sg table and pages again */
> > +       dma_unmap_sg(rdev->dev, ttm->sg->sgl,
> > +                    ttm->sg->nents, DMA_TO_DEVICE);
> > +
> > +       sg_free_table(ttm->sg);
> > +       kfree(ttm->sg);
> > +
> > +       release_pages(ttm->pages, ttm->num_pages, 0);
> > +}
> > +
> >  static int radeon_ttm_tt_populate(struct ttm_tt *ttm)
> >  {
> >         struct radeon_device *rdev;
> > @@ -599,6 +670,13 @@ static int radeon_ttm_tt_populate(struct ttm_tt *ttm)
> >         if (ttm->state != tt_unpopulated)
> >                 return 0;
> >
> > +       if (gtt->userptr) {
> > +               r = radeon_ttm_tt_pin_userptr(ttm);
> > +               if (r)
> > +                       return r;
> > +               slave = true;
> > +       }
> > +
> >         if (slave && ttm->sg) {
> >                 drm_prime_sg_to_page_addr_arrays(ttm->sg, ttm->pages,
> >                                                  gtt->ttm.dma_address, ttm->num_pages);
> > @@ -648,6 +726,11 @@ static void radeon_ttm_tt_unpopulate(struct ttm_tt *ttm)
> >         unsigned i;
> >         bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);
> >
> > +       if (gtt->userptr) {
> > +               radeon_ttm_tt_unpin_userptr(ttm);
> > +               return;
> > +       }
> > +
> >         if (slave)
> >                 return;
> >
> > @@ -676,6 +759,28 @@ static void radeon_ttm_tt_unpopulate(struct ttm_tt *ttm)
> >         ttm_pool_unpopulate(ttm);
> >  }
> >
> > +int radeon_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t userptr)
> > +{
> > +       struct radeon_ttm_tt *gtt = (void *)ttm;
> > +
> > +       if (gtt == NULL)
> > +               return -EINVAL;
> > +
> > +       gtt->userptr = userptr;
> > +       gtt->usermm = current->mm;
> > +       return 0;
> > +}
> > +
> > +bool radeon_ttm_tt_has_userptr(struct ttm_tt *ttm)
> > +{
> > +       struct radeon_ttm_tt *gtt = (void *)ttm;
> > +
> > +       if (gtt == NULL)
> > +               return false;
> > +
> > +       return !!gtt->userptr;
> > +}
> > +
> >  static struct ttm_bo_driver radeon_bo_driver = {
> >         .ttm_tt_create = &radeon_ttm_tt_create,
> >         .ttm_tt_populate = &radeon_ttm_tt_populate,
> > diff --git a/drivers/gpu/drm/radeon/radeon_vm.c b/drivers/gpu/drm/radeon/radeon_vm.c
> > index eecff6b..99663a8 100644
> > --- a/drivers/gpu/drm/radeon/radeon_vm.c
> > +++ b/drivers/gpu/drm/radeon/radeon_vm.c
> > @@ -850,6 +850,9 @@ int radeon_vm_bo_update(struct radeon_device *rdev,
> >
> >         bo_va->flags &= ~RADEON_VM_PAGE_VALID;
> >         bo_va->flags &= ~RADEON_VM_PAGE_SYSTEM;
> > +       if (radeon_ttm_tt_has_userptr(bo->tbo.ttm))
> > +               bo_va->flags &= ~RADEON_VM_PAGE_WRITEABLE;
> > +
> >         if (mem) {
> >                 addr = mem->start << PAGE_SHIFT;
> >                 if (mem->mem_type != TTM_PL_SYSTEM) {
> > diff --git a/include/uapi/drm/radeon_drm.h b/include/uapi/drm/radeon_drm.h
> > index 1cc0b61..64ef99c 100644
> > --- a/include/uapi/drm/radeon_drm.h
> > +++ b/include/uapi/drm/radeon_drm.h
> > @@ -511,6 +511,7 @@ typedef struct {
> >  #define DRM_RADEON_GEM_BUSY            0x2a
> >  #define DRM_RADEON_GEM_VA              0x2b
> >  #define DRM_RADEON_GEM_OP              0x2c
> > +#define DRM_RADEON_GEM_IMPORT          0x2d
> >
> >  #define DRM_IOCTL_RADEON_CP_INIT    DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_CP_INIT, drm_radeon_init_t)
> >  #define DRM_IOCTL_RADEON_CP_START   DRM_IO(  DRM_COMMAND_BASE + DRM_RADEON_CP_START)
> > @@ -554,6 +555,7 @@ typedef struct {
> >  #define DRM_IOCTL_RADEON_GEM_BUSY      DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_BUSY, struct drm_radeon_gem_busy)
> >  #define DRM_IOCTL_RADEON_GEM_VA                DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_VA, struct drm_radeon_gem_va)
> >  #define DRM_IOCTL_RADEON_GEM_OP                DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_OP, struct drm_radeon_gem_op)
> > +#define DRM_IOCTL_RADEON_GEM_IMPORT    DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_IMPORT, struct drm_radeon_gem_import)
> >
> >  typedef struct drm_radeon_init {
> >         enum {
> > @@ -806,6 +808,15 @@ struct drm_radeon_gem_create {
> >         uint32_t        flags;
> >  };
> >
> > +#define RADEON_GEM_IMPORT_READONLY     0x1
> > +
> > +struct drm_radeon_gem_import {
> > +       uint64_t                addr;
> > +       uint64_t                size;
> > +       uint32_t                flags;
> > +       uint32_t                handle;
> > +};
> > +
> >  #define RADEON_TILING_MACRO                            0x1
> >  #define RADEON_TILING_MICRO                            0x2
> >  #define RADEON_TILING_SWAP_16BIT                       0x4
> > --
> > 1.9.1
> >
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel@lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/dri-devel
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2014-07-10 14:21 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-07-10 12:33 [PATCH 1/2] drm/radeon: add readonly flag to radeon_gart_set_page v2 Christian König
2014-07-10 12:33 ` [PATCH 2/2] drm/radeon: add user pointer support v3 Christian König
2014-07-10 13:48   ` Alex Deucher
2014-07-10 14:20     ` Jerome Glisse
2014-07-10 13:41 ` [PATCH 1/2] drm/radeon: add readonly flag to radeon_gart_set_page v2 Alex Deucher

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.