maarten.lankhorst at canonical.com
2013-Nov-12  12:34 UTC
[Nouveau] [PATCH 1/7] drm/nouveau: fix m2mf copy to tiled gart
From: Maarten Lankhorst <maarten.lankhorst at canonical.com>
Commit de7b7d59d54852c introduced tiled GART, but a linear copy is
still performed. This may result in errors on eviction, fix it by
checking tiling from memtype.
Signed-off-by: Maarten Lankhorst <maarten.lankhorst at canonical.com>
Cc: stable at vger.kernel.org #3.10+
---
 drivers/gpu/drm/nouveau/nouveau_bo.c | 33 ++++++++-------------------------
 1 file changed, 8 insertions(+), 25 deletions(-)
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c
b/drivers/gpu/drm/nouveau/nouveau_bo.c
index f5b0201..639d7cd 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -803,25 +803,25 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct
ttm_buffer_object *bo,
 		  struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem)
 {
 	struct nouveau_mem *node = old_mem->mm_node;
-	struct nouveau_bo *nvbo = nouveau_bo(bo);
 	u64 length = (new_mem->num_pages << PAGE_SHIFT);
 	u64 src_offset = node->vma[0].offset;
 	u64 dst_offset = node->vma[1].offset;
+	int src_tiled = !!node->memtype;
+	int dst_tiled = !!((struct nouveau_mem *)new_mem->mm_node)->memtype;
 	int ret;
 
 	while (length) {
 		u32 amount, stride, height;
 
+		ret = RING_SPACE(chan, 18 + 6 * (src_tiled + dst_tiled));
+		if (ret)
+			return ret;
+
 		amount  = min(length, (u64)(4 * 1024 * 1024));
 		stride  = 16 * 4;
 		height  = amount / stride;
 
-		if (old_mem->mem_type == TTM_PL_VRAM &&
-		    nouveau_bo_tile_layout(nvbo)) {
-			ret = RING_SPACE(chan, 8);
-			if (ret)
-				return ret;
-
+		if (src_tiled) {
 			BEGIN_NV04(chan, NvSubCopy, 0x0200, 7);
 			OUT_RING  (chan, 0);
 			OUT_RING  (chan, 0);
@@ -831,19 +831,10 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct
ttm_buffer_object *bo,
 			OUT_RING  (chan, 0);
 			OUT_RING  (chan, 0);
 		} else {
-			ret = RING_SPACE(chan, 2);
-			if (ret)
-				return ret;
-
 			BEGIN_NV04(chan, NvSubCopy, 0x0200, 1);
 			OUT_RING  (chan, 1);
 		}
-		if (new_mem->mem_type == TTM_PL_VRAM &&
-		    nouveau_bo_tile_layout(nvbo)) {
-			ret = RING_SPACE(chan, 8);
-			if (ret)
-				return ret;
-
+		if (dst_tiled) {
 			BEGIN_NV04(chan, NvSubCopy, 0x021c, 7);
 			OUT_RING  (chan, 0);
 			OUT_RING  (chan, 0);
@@ -853,18 +844,10 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct
ttm_buffer_object *bo,
 			OUT_RING  (chan, 0);
 			OUT_RING  (chan, 0);
 		} else {
-			ret = RING_SPACE(chan, 2);
-			if (ret)
-				return ret;
-
 			BEGIN_NV04(chan, NvSubCopy, 0x021c, 1);
 			OUT_RING  (chan, 1);
 		}
 
-		ret = RING_SPACE(chan, 14);
-		if (ret)
-			return ret;
-
 		BEGIN_NV04(chan, NvSubCopy, 0x0238, 2);
 		OUT_RING  (chan, upper_32_bits(src_offset));
 		OUT_RING  (chan, upper_32_bits(dst_offset));
-- 
1.8.4
maarten.lankhorst at canonical.com
2013-Nov-12  12:34 UTC
[Nouveau] [PATCH 2/7] drm/nv50-: untile mmap'd bo's
From: Maarten Lankhorst <maarten.lankhorst at canonical.com>
Map the GART to the bar and use that mapping, to hide all the tiling details
from users.
Signed-off-by: Maarten Lankhorst <maarten.lankhorst at canonical.com>
---
 drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c |  5 ++++-
 drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c |  5 ++++-
 drivers/gpu/drm/nouveau/nouveau_bo.c           | 20 +++++++++++++++++---
 3 files changed, 25 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c
b/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c
index 160d27f..9907a25 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c
@@ -67,7 +67,10 @@ nv50_bar_umap(struct nouveau_bar *bar, struct nouveau_mem
*mem,
 	if (ret)
 		return ret;
 
-	nouveau_vm_map(vma, mem);
+	if (mem->pages)
+		nouveau_vm_map_sg(vma, 0, mem->size << 12, mem);
+	else
+		nouveau_vm_map(vma, mem);
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c
b/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c
index b2ec741..badd835 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c
@@ -66,7 +66,10 @@ nvc0_bar_umap(struct nouveau_bar *bar, struct nouveau_mem
*mem,
 	if (ret)
 		return ret;
 
-	nouveau_vm_map(vma, mem);
+	if (mem->pages)
+		nouveau_vm_map_sg(vma, 0, mem->size << 12, mem);
+	else
+		nouveau_vm_map(vma, mem);
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c
b/drivers/gpu/drm/nouveau/nouveau_bo.c
index 639d7cd..9ecb874 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -1259,6 +1259,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev,
struct ttm_mem_reg *mem)
 {
 	struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
 	struct nouveau_drm *drm = nouveau_bdev(bdev);
+	struct nouveau_mem *node = mem->mm_node;
 	struct drm_device *dev = drm->dev;
 	int ret;
 
@@ -1281,14 +1282,16 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev,
struct ttm_mem_reg *mem)
 			mem->bus.is_iomem = !dev->agp->cant_use_aperture;
 		}
 #endif
-		break;
+		if (!node->memtype)
+			/* untiled */
+			break;
+		/* fallthrough, tiled memory */
 	case TTM_PL_VRAM:
 		mem->bus.offset = mem->start << PAGE_SHIFT;
 		mem->bus.base = pci_resource_start(dev->pdev, 1);
 		mem->bus.is_iomem = true;
 		if (nv_device(drm->device)->card_type >= NV_50) {
 			struct nouveau_bar *bar = nouveau_bar(drm->device);
-			struct nouveau_mem *node = mem->mm_node;
 
 			ret = bar->umap(bar, node, NV_MEM_ACCESS_RW,
 					&node->bar_vma);
@@ -1324,6 +1327,7 @@ nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object
*bo)
 	struct nouveau_bo *nvbo = nouveau_bo(bo);
 	struct nouveau_device *device = nv_device(drm->device);
 	u32 mappable = pci_resource_len(device->pdev, 1) >> PAGE_SHIFT;
+	int ret;
 
 	/* as long as the bo isn't in vram, and isn't tiled, we've got
 	 * nothing to do here.
@@ -1332,10 +1336,20 @@ nouveau_ttm_fault_reserve_notify(struct
ttm_buffer_object *bo)
 		if (nv_device(drm->device)->card_type < NV_50 ||
 		    !nouveau_bo_tile_layout(nvbo))
 			return 0;
+
+		if (bo->mem.mem_type == TTM_PL_SYSTEM) {
+			nouveau_bo_placement_set(nvbo, TTM_PL_TT, 0);
+
+			ret = nouveau_bo_validate(nvbo, false, false);
+			if (ret)
+				return ret;
+		}
+		return 0;
 	}
 
 	/* make sure bo is in mappable vram */
-	if (bo->mem.start + bo->mem.num_pages < mappable)
+	if (nv_device(drm->device)->card_type >= NV_50 ||
+	    bo->mem.start + bo->mem.num_pages < mappable)
 		return 0;
 
 
-- 
1.8.4
maarten.lankhorst at canonical.com
2013-Nov-12  12:34 UTC
[Nouveau] [PATCH 3/7] drm/nouveau: fixup locking inversion between mmap_sem and reservations
From: Maarten Lankhorst <maarten.lankhorst at canonical.com>
Allocate and copy all kernel memory before doing reservations. This prevents a
locking
inversion between mmap_sem and reservation_class, and allows us to drop the
trylocking
in ttm_bo_vm_fault without upsetting lockdep.
Relocations are handled by trying with __copy_from_user_inatomic first. If that
fails
all validation will be undone, memory copied from userspace and all validations
retried.
Signed-off-by: Maarten Lankhorst <maarten.lankhorst at canonical.com>
---
 drivers/gpu/drm/nouveau/nouveau_gem.c | 188 +++++++++++++++++++++-------------
 1 file changed, 119 insertions(+), 69 deletions(-)
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c
b/drivers/gpu/drm/nouveau/nouveau_gem.c
index f32b712..41a4bf6 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -464,8 +464,6 @@ validate_list(struct nouveau_channel *chan, struct
nouveau_cli *cli,
 	      uint64_t user_pbbo_ptr)
 {
 	struct nouveau_drm *drm = chan->drm;
-	struct drm_nouveau_gem_pushbuf_bo __user *upbbo -				(void __force __user
*)(uintptr_t)user_pbbo_ptr;
 	struct nouveau_bo *nvbo;
 	int ret, relocs = 0;
 
@@ -499,7 +497,7 @@ validate_list(struct nouveau_channel *chan, struct
nouveau_cli *cli,
 			return ret;
 		}
 
-		if (nv_device(drm->device)->card_type < NV_50) {
+		if (nv_device(drm->device)->card_type < NV_50 && !relocs) {
 			if (nvbo->bo.offset == b->presumed.offset &&
 			    ((nvbo->bo.mem.mem_type == TTM_PL_VRAM &&
 			      b->presumed.domain & NOUVEAU_GEM_DOMAIN_VRAM) ||
@@ -507,32 +505,53 @@ validate_list(struct nouveau_channel *chan, struct
nouveau_cli *cli,
 			      b->presumed.domain & NOUVEAU_GEM_DOMAIN_GART)))
 				continue;
 
-			if (nvbo->bo.mem.mem_type == TTM_PL_TT)
-				b->presumed.domain = NOUVEAU_GEM_DOMAIN_GART;
-			else
-				b->presumed.domain = NOUVEAU_GEM_DOMAIN_VRAM;
-			b->presumed.offset = nvbo->bo.offset;
-			b->presumed.valid = 0;
-			relocs++;
-
-			if (DRM_COPY_TO_USER(&upbbo[nvbo->pbbo_index].presumed,
-					     &b->presumed, sizeof(b->presumed)))
-				return -EFAULT;
+			relocs = 1;
 		}
 	}
 
 	return relocs;
 }
 
+static inline void *
+u_memcpya(uint64_t user, unsigned nmemb, unsigned size, unsigned inatomic)
+{
+	void *mem;
+	void __user *userptr = (void __force __user *)(uintptr_t)user;
+
+	mem = drm_malloc_ab(size, nmemb);
+	if (!mem)
+		return ERR_PTR(-ENOMEM);
+	size *= nmemb;
+
+	if (inatomic && (!access_ok(VERIFY_READ, userptr, size) ||
+	    __copy_from_user_inatomic(mem, userptr, size))) {
+		drm_free_large(mem);
+		return ERR_PTR(-EFAULT);
+	} else if (!inatomic && copy_from_user(mem, userptr, size)) {
+		drm_free_large(mem);
+		return ERR_PTR(-EFAULT);
+	}
+
+	return mem;
+}
+
+static int
+nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli,
+				struct drm_nouveau_gem_pushbuf *req,
+				struct drm_nouveau_gem_pushbuf_bo *bo,
+				struct drm_nouveau_gem_pushbuf_reloc *reloc);
+
 static int
 nouveau_gem_pushbuf_validate(struct nouveau_channel *chan,
 			     struct drm_file *file_priv,
 			     struct drm_nouveau_gem_pushbuf_bo *pbbo,
+			     struct drm_nouveau_gem_pushbuf *req,
 			     uint64_t user_buffers, int nr_buffers,
-			     struct validate_op *op, int *apply_relocs)
+			     struct validate_op *op, int *do_reloc)
 {
 	struct nouveau_cli *cli = nouveau_cli(file_priv);
 	int ret, relocs = 0;
+	struct drm_nouveau_gem_pushbuf_reloc *reloc = NULL;
 
 	INIT_LIST_HEAD(&op->vram_list);
 	INIT_LIST_HEAD(&op->gart_list);
@@ -541,19 +560,19 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan,
 	if (nr_buffers == 0)
 		return 0;
 
+restart:
 	ret = validate_init(chan, file_priv, pbbo, nr_buffers, op);
 	if (unlikely(ret)) {
 		if (ret != -ERESTARTSYS)
 			NV_ERROR(cli, "validate_init\n");
-		return ret;
+		goto err;
 	}
 
 	ret = validate_list(chan, cli, &op->vram_list, pbbo, user_buffers);
 	if (unlikely(ret < 0)) {
 		if (ret != -ERESTARTSYS)
 			NV_ERROR(cli, "validate vram_list\n");
-		validate_fini(op, NULL);
-		return ret;
+		goto err_fini;
 	}
 	relocs += ret;
 
@@ -561,8 +580,7 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan,
 	if (unlikely(ret < 0)) {
 		if (ret != -ERESTARTSYS)
 			NV_ERROR(cli, "validate gart_list\n");
-		validate_fini(op, NULL);
-		return ret;
+		goto err_fini;
 	}
 	relocs += ret;
 
@@ -570,58 +588,90 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan,
 	if (unlikely(ret < 0)) {
 		if (ret != -ERESTARTSYS)
 			NV_ERROR(cli, "validate both_list\n");
-		validate_fini(op, NULL);
-		return ret;
+		goto err_fini;
 	}
 	relocs += ret;
+	if (relocs) {
+		if (!reloc)
+			reloc = u_memcpya(req->relocs, req->nr_relocs, sizeof(*reloc), 1);
+		if (IS_ERR(reloc)) {
+			validate_fini(op, NULL);
+
+			if (PTR_ERR(reloc) == -EFAULT) {
+				reloc = u_memcpya(req->relocs, req->nr_relocs, sizeof(*reloc), 0);
+				if (!IS_ERR(reloc))
+					goto restart;
+			}
+
+			return PTR_ERR(reloc);
+		}
+
+		ret = nouveau_gem_pushbuf_reloc_apply(cli, req, pbbo, reloc);
+		if (ret) {
+			NV_ERROR(cli, "reloc apply: %d\n", ret);
+			goto err_fini;
+		}
+		drm_free_large(reloc);
+		*do_reloc = 1;
+	}
 
-	*apply_relocs = relocs;
 	return 0;
-}
 
-static inline void
-u_free(void *addr)
-{
-	if (!is_vmalloc_addr(addr))
-		kfree(addr);
-	else
-		vfree(addr);
+err_fini:
+	validate_fini(op, NULL);
+err:
+	drm_free_large(reloc);
+	return ret;
 }
 
-static inline void *
-u_memcpya(uint64_t user, unsigned nmemb, unsigned size)
+static int
+nouveau_gem_pushbuf_reloc_copy_to_user(struct drm_nouveau_gem_pushbuf *req,
+				       struct drm_nouveau_gem_pushbuf_bo *bo)
 {
-	void *mem;
-	void __user *userptr = (void __force __user *)(uintptr_t)user;
-
-	size *= nmemb;
+	struct drm_nouveau_gem_pushbuf_bo __user *upbbo +				 (void __force __user
*)(uintptr_t)req->buffers;
+	unsigned i;
 
-	mem = kmalloc(size, GFP_KERNEL | __GFP_NOWARN);
-	if (!mem)
-		mem = vmalloc(size);
-	if (!mem)
-		return ERR_PTR(-ENOMEM);
+	for (i = 0; i < req->nr_buffers; ++i) {
+		struct drm_nouveau_gem_pushbuf_bo *b = &bo[i];
 
-	if (DRM_COPY_FROM_USER(mem, userptr, size)) {
-		u_free(mem);
-		return ERR_PTR(-EFAULT);
+		if (!b->presumed.valid &&
+		    copy_to_user(&upbbo[i].presumed, &b->presumed,
sizeof(b->presumed)))
+			return -EFAULT;
 	}
-
-	return mem;
+	return 0;
 }
 
 static int
 nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli,
 				struct drm_nouveau_gem_pushbuf *req,
-				struct drm_nouveau_gem_pushbuf_bo *bo)
+				struct drm_nouveau_gem_pushbuf_bo *bo,
+				struct drm_nouveau_gem_pushbuf_reloc *reloc)
 {
-	struct drm_nouveau_gem_pushbuf_reloc *reloc = NULL;
 	int ret = 0;
 	unsigned i;
 
-	reloc = u_memcpya(req->relocs, req->nr_relocs, sizeof(*reloc));
-	if (IS_ERR(reloc))
-		return PTR_ERR(reloc);
+	for (i = 0; i < req->nr_buffers; ++i) {
+		struct drm_nouveau_gem_pushbuf_bo *b = &bo[i];
+		struct nouveau_bo *nvbo = (void *)(unsigned long)
+			bo[i].user_priv;
+
+		if (nvbo->bo.offset == b->presumed.offset &&
+		    ((nvbo->bo.mem.mem_type == TTM_PL_VRAM &&
+		      b->presumed.domain & NOUVEAU_GEM_DOMAIN_VRAM) ||
+		     (nvbo->bo.mem.mem_type == TTM_PL_TT &&
+		      b->presumed.domain & NOUVEAU_GEM_DOMAIN_GART))) {
+			b->presumed.valid = 1;
+			continue;
+		}
+
+		if (nvbo->bo.mem.mem_type == TTM_PL_TT)
+			b->presumed.domain = NOUVEAU_GEM_DOMAIN_GART;
+		else
+			b->presumed.domain = NOUVEAU_GEM_DOMAIN_VRAM;
+		b->presumed.offset = nvbo->bo.offset;
+		b->presumed.valid = 0;
+	}
 
 	for (i = 0; i < req->nr_relocs; i++) {
 		struct drm_nouveau_gem_pushbuf_reloc *r = &reloc[i];
@@ -688,8 +738,6 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli,
 
 		nouveau_bo_wr32(nvbo, r->reloc_bo_offset >> 2, data);
 	}
-
-	u_free(reloc);
 	return ret;
 }
 
@@ -745,13 +793,13 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void
*data,
 		return nouveau_abi16_put(abi16, -EINVAL);
 	}
 
-	push = u_memcpya(req->push, req->nr_push, sizeof(*push));
+	push = u_memcpya(req->push, req->nr_push, sizeof(*push), 0);
 	if (IS_ERR(push))
 		return nouveau_abi16_put(abi16, PTR_ERR(push));
 
-	bo = u_memcpya(req->buffers, req->nr_buffers, sizeof(*bo));
+	bo = u_memcpya(req->buffers, req->nr_buffers, sizeof(*bo), 0);
 	if (IS_ERR(bo)) {
-		u_free(push);
+		drm_free_large(push);
 		return nouveau_abi16_put(abi16, PTR_ERR(bo));
 	}
 
@@ -765,7 +813,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void
*data,
 	}
 
 	/* Validate buffer list */
-	ret = nouveau_gem_pushbuf_validate(chan, file_priv, bo, req->buffers,
+	ret = nouveau_gem_pushbuf_validate(chan, file_priv, bo, req, req->buffers,
 					   req->nr_buffers, &op, &do_reloc);
 	if (ret) {
 		if (ret != -ERESTARTSYS)
@@ -773,15 +821,6 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void
*data,
 		goto out_prevalid;
 	}
 
-	/* Apply any relocations that are required */
-	if (do_reloc) {
-		ret = nouveau_gem_pushbuf_reloc_apply(cli, req, bo);
-		if (ret) {
-			NV_ERROR(cli, "reloc apply: %d\n", ret);
-			goto out;
-		}
-	}
-
 	if (chan->dma.ib_max) {
 		ret = nouveau_dma_wait(chan, req->nr_push + 1, 16);
 		if (ret) {
@@ -861,9 +900,20 @@ out:
 	validate_fini(&op, fence);
 	nouveau_fence_unref(&fence);
 
+	if (do_reloc && !ret) {
+		ret = nouveau_gem_pushbuf_reloc_copy_to_user(req, bo);
+		if (ret) {
+			NV_ERROR(cli, "error copying presumed back to userspace: %d\n",
ret);
+			/*
+			 * XXX: We return -EFAULT, but command submission
+			 * has already been completed.
+			 */
+		}
+	}
+
 out_prevalid:
-	u_free(bo);
-	u_free(push);
+	drm_free_large(bo);
+	drm_free_large(push);
 
 out_next:
 	if (chan->dma.ib_max) {
-- 
1.8.4
maarten.lankhorst at canonical.com
2013-Nov-12  12:34 UTC
[Nouveau] [PATCH 4/7] drm/nvc0-/gr: shift wrapping bug in nvc0_grctx_generate_r406800
From: Dan Carpenter <dan.carpenter at oracle.com> We care about the upper 32 bits here so we have to use 1ULL instead of 1 to avoid a shift wrapping bug. Signed-off-by: Dan Carpenter <dan.carpenter at oracle.com> Signed-off-by: Maarten Lankhorst <maarten.lankhorst at canonical.com> --- drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c index 64dca26..fe67415 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c @@ -1039,7 +1039,7 @@ nvc0_grctx_generate_r406800(struct nvc0_graph_priv *priv) } while (!tpcnr[gpc]); tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--; - tpc_set |= 1 << ((gpc * 8) + tpc); + tpc_set |= 1ULL << ((gpc * 8) + tpc); } nv_wr32(priv, 0x406800 + (i * 0x20), lower_32_bits(tpc_set)); -- 1.8.4
maarten.lankhorst at canonical.com
2013-Nov-12  12:34 UTC
[Nouveau] [PATCH 5/7] drm/nouveau: do not map evicted vram buffers in nouveau_bo_vma_add
From: Maarten Lankhorst <maarten.lankhorst at canonical.com>
Signed-off-by: Maarten Lankhorst <maarten.lankhorst at canonical.com>
---
 drivers/gpu/drm/nouveau/nouveau_bo.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c
b/drivers/gpu/drm/nouveau/nouveau_bo.c
index 9ecb874..bb3734d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -1549,7 +1549,8 @@ nouveau_bo_vma_add(struct nouveau_bo *nvbo, struct
nouveau_vm *vm,
 
 	if (nvbo->bo.mem.mem_type == TTM_PL_VRAM)
 		nouveau_vm_map(vma, nvbo->bo.mem.mm_node);
-	else if (nvbo->bo.mem.mem_type == TTM_PL_TT) {
+	else if (nvbo->bo.mem.mem_type == TTM_PL_TT &&
+		 nvbo->page_shift == vma->vm->vmm->spg_shift) {
 		if (node->sg)
 			nouveau_vm_map_sg_table(vma, 0, size, node);
 		else
-- 
1.8.4
maarten.lankhorst at canonical.com
2013-Nov-12  12:34 UTC
[Nouveau] [PATCH 6/7] drm/nouveau: more paranoia in nouveau_bo_fixup_align
From: Maarten Lankhorst <maarten.lankhorst at canonical.com>
Make sure that buffers are always aligned.
Signed-off-by: Maarten Lankhorst <maarten.lankhorst at canonical.com>
---
 drivers/gpu/drm/nouveau/nouveau_bo.c | 40 +++++++++++++++++++-----------------
 1 file changed, 21 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c
b/drivers/gpu/drm/nouveau/nouveau_bo.c
index bb3734d..635a192 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -160,24 +160,20 @@ nouveau_bo_fixup_align(struct nouveau_bo *nvbo, u32 flags,
 	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
 	struct nouveau_device *device = nv_device(drm->device);
 
-	if (device->card_type < NV_50) {
-		if (nvbo->tile_mode) {
-			if (device->chipset >= 0x40) {
-				*align = 65536;
-				*size = roundup(*size, 64 * nvbo->tile_mode);
-
-			} else if (device->chipset >= 0x30) {
-				*align = 32768;
-				*size = roundup(*size, 64 * nvbo->tile_mode);
-
-			} else if (device->chipset >= 0x20) {
-				*align = 16384;
-				*size = roundup(*size, 64 * nvbo->tile_mode);
-
-			} else if (device->chipset >= 0x10) {
-				*align = 16384;
-				*size = roundup(*size, 32 * nvbo->tile_mode);
-			}
+	if (device->chipset >= 0x10 && device->card_type < NV_50
&&
+	    nvbo->tile_mode) {
+		if (device->chipset >= 0x40) {
+			*align = 65536;
+			*size = roundup(*size, 64 * nvbo->tile_mode);
+		} else if (device->chipset >= 0x30) {
+			*align = 32768;
+			*size = roundup(*size, 64 * nvbo->tile_mode);
+		} else if (device->chipset >= 0x20) {
+			*align = 16384;
+			*size = roundup(*size, 64 * nvbo->tile_mode);
+		} else {
+			*align = 16384;
+			*size = roundup(*size, 32 * nvbo->tile_mode);
 		}
 	} else {
 		*size = roundup(*size, (1 << nvbo->page_shift));
@@ -228,8 +224,14 @@ nouveau_bo_new(struct drm_device *dev, int size, int align,
 		if (!(flags & TTM_PL_FLAG_TT) && size > 256 * 1024)
 			nvbo->page_shift = drm->client.base.vm->vmm->lpg_shift;
 	}
-
 	nouveau_bo_fixup_align(nvbo, flags, &align, &size);
+	if (size <= 0) {
+		nv_warn(drm, "invalid size %x after setting alignment %x\n",
+			size, align);
+		kfree(nvbo);
+		return -EINVAL;
+	}
+
 	nvbo->bo.mem.num_pages = size >> PAGE_SHIFT;
 	nouveau_bo_placement_set(nvbo, flags, 0);
 
-- 
1.8.4
maarten.lankhorst at canonical.com
2013-Nov-12  12:34 UTC
[Nouveau] [PATCH 7/7] drm/nouveau: use a single vma for display
From: Maarten Lankhorst <maarten.lankhorst at canonical.com>
No need to map the same vma multiple times.
Signed-off-by: Maarten Lankhorst <maarten.lankhorst at canonical.com>
---
 drivers/gpu/drm/nouveau/nouveau_fence.h |  4 ++--
 drivers/gpu/drm/nouveau/nv50_display.c  | 13 ++++++-------
 drivers/gpu/drm/nouveau/nv50_display.h  |  2 +-
 drivers/gpu/drm/nouveau/nv50_fence.c    | 24 +++++++++++++-----------
 drivers/gpu/drm/nouveau/nv84_fence.c    | 21 +++++++++------------
 5 files changed, 31 insertions(+), 33 deletions(-)
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h
b/drivers/gpu/drm/nouveau/nouveau_fence.h
index c57bb61..60ae4e7 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.h
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.h
@@ -82,7 +82,7 @@ struct nv84_fence_chan {
 	struct nouveau_fence_chan base;
 	struct nouveau_vma vma;
 	struct nouveau_vma vma_gart;
-	struct nouveau_vma dispc_vma[4];
+	struct nouveau_vma dispc_vma;
 };
 
 struct nv84_fence_priv {
@@ -92,7 +92,7 @@ struct nv84_fence_priv {
 	u32 *suspend;
 };
 
-u64  nv84_fence_crtc(struct nouveau_channel *, int);
+u64  nv84_fence_crtc(struct nouveau_channel *);
 int  nv84_fence_context_new(struct nouveau_channel *);
 
 #endif
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c
b/drivers/gpu/drm/nouveau/nv50_display.c
index f8e66c0..4153c8a 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -433,7 +433,7 @@ evo_kick(u32 *push, void *evoc)
 static bool
 evo_sync_wait(void *data)
 {
-	if (nouveau_bo_rd32(data, EVO_MAST_NTFY) != 0x00000000)
+	if (nouveau_bo_rd32(data, EVO_MAST_NTFY / 4) != 0x00000000)
 		return true;
 	usleep_range(1, 2);
 	return false;
@@ -447,7 +447,7 @@ evo_sync(struct drm_device *dev)
 	struct nv50_mast *mast = nv50_mast(dev);
 	u32 *push = evo_wait(mast, 8);
 	if (push) {
-		nouveau_bo_wr32(disp->sync, EVO_MAST_NTFY, 0x00000000);
+		nouveau_bo_wr32(disp->sync, EVO_MAST_NTFY / 4, 0x00000000);
 		evo_mthd(push, 0x0084, 1);
 		evo_data(push, 0x80000000 | EVO_MAST_NTFY);
 		evo_mthd(push, 0x0080, 2);
@@ -465,7 +465,7 @@ evo_sync(struct drm_device *dev)
  * Page flipping channel
  *****************************************************************************/
 struct nouveau_bo *
-nv50_display_crtc_sema(struct drm_device *dev, int crtc)
+nv50_display_crtc_sema(struct drm_device *dev)
 {
 	return nv50_disp(dev)->sync;
 }
@@ -517,7 +517,6 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct
drm_framebuffer *fb,
 		       struct nouveau_channel *chan, u32 swap_interval)
 {
 	struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb);
-	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 	struct nv50_head *head = nv50_head(crtc);
 	struct nv50_sync *sync = nv50_sync(crtc);
 	u32 *push;
@@ -539,7 +538,7 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct
drm_framebuffer *fb,
 			return ret;
 
 		BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 2);
-		OUT_RING  (chan, NvEvoSema0 + nv_crtc->index);
+		OUT_RING  (chan, NvEvoSema0);
 		OUT_RING  (chan, sync->addr ^ 0x10);
 		BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_RELEASE, 1);
 		OUT_RING  (chan, sync->data + 1);
@@ -548,7 +547,7 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct
drm_framebuffer *fb,
 		OUT_RING  (chan, sync->data);
 	} else
 	if (chan && nv_mclass(chan->object) < NVC0_CHANNEL_IND_CLASS) {
-		u64 addr = nv84_fence_crtc(chan, nv_crtc->index) + sync->addr;
+		u64 addr = nv84_fence_crtc(chan) + sync->addr;
 		ret = RING_SPACE(chan, 12);
 		if (ret)
 			return ret;
@@ -567,7 +566,7 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct
drm_framebuffer *fb,
 		OUT_RING  (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL);
 	} else
 	if (chan) {
-		u64 addr = nv84_fence_crtc(chan, nv_crtc->index) + sync->addr;
+		u64 addr = nv84_fence_crtc(chan) + sync->addr;
 		ret = RING_SPACE(chan, 10);
 		if (ret)
 			return ret;
diff --git a/drivers/gpu/drm/nouveau/nv50_display.h
b/drivers/gpu/drm/nouveau/nv50_display.h
index 70da347..ea681be 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.h
+++ b/drivers/gpu/drm/nouveau/nv50_display.h
@@ -40,6 +40,6 @@ void nv50_display_flip_stop(struct drm_crtc *);
 int  nv50_display_flip_next(struct drm_crtc *, struct drm_framebuffer *,
 			    struct nouveau_channel *, u32 swap_interval);
 
-struct nouveau_bo *nv50_display_crtc_sema(struct drm_device *, int head);
+struct nouveau_bo *nv50_display_crtc_sema(struct drm_device *);
 
 #endif /* __NV50_DISPLAY_H__ */
diff --git a/drivers/gpu/drm/nouveau/nv50_fence.c
b/drivers/gpu/drm/nouveau/nv50_fence.c
index 0ee3638..f302e7f 100644
--- a/drivers/gpu/drm/nouveau/nv50_fence.c
+++ b/drivers/gpu/drm/nouveau/nv50_fence.c
@@ -41,7 +41,8 @@ nv50_fence_context_new(struct nouveau_channel *chan)
 	struct nouveau_object *object;
 	u32 start = mem->start * PAGE_SIZE;
 	u32 limit = start + mem->size - 1;
-	int ret, i;
+	int ret;
+	struct nouveau_bo *bo;
 
 	fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL);
 	if (!fctx)
@@ -62,21 +63,22 @@ nv50_fence_context_new(struct nouveau_channel *chan)
 				 }, sizeof(struct nv_dma_class),
 				 &object);
 
-	/* dma objects for display sync channel semaphore blocks */
-	for (i = 0; !ret && i < dev->mode_config.num_crtc; i++) {
-		struct nouveau_bo *bo = nv50_display_crtc_sema(dev, i);
-		u32 start = bo->bo.mem.start * PAGE_SIZE;
-		u32 limit = start + bo->bo.mem.size - 1;
+	/* dma object for display sync channel semaphore blocks */
+	bo = nv50_display_crtc_sema(dev);
+
+	if (!ret && bo) {
+		start = bo->bo.mem.start * PAGE_SIZE;
+		limit = start + bo->bo.mem.size - 1;
 
 		ret = nouveau_object_new(nv_object(chan->cli), chan->handle,
-					 NvEvoSema0 + i, 0x003d,
-					 &(struct nv_dma_class) {
+					NvEvoSema0, 0x003d,
+					&(struct nv_dma_class) {
 						.flags = NV_DMA_TARGET_VRAM |
-							 NV_DMA_ACCESS_RDWR,
+							NV_DMA_ACCESS_RDWR,
 						.start = start,
 						.limit = limit,
-					 }, sizeof(struct nv_dma_class),
-					 &object);
+					}, sizeof(struct nv_dma_class),
+					&object);
 	}
 
 	if (ret)
diff --git a/drivers/gpu/drm/nouveau/nv84_fence.c
b/drivers/gpu/drm/nouveau/nv84_fence.c
index 9fd475c..2fbfb73 100644
--- a/drivers/gpu/drm/nouveau/nv84_fence.c
+++ b/drivers/gpu/drm/nouveau/nv84_fence.c
@@ -35,10 +35,10 @@
 #include "nv50_display.h"
 
 u64
-nv84_fence_crtc(struct nouveau_channel *chan, int crtc)
+nv84_fence_crtc(struct nouveau_channel *chan)
 {
 	struct nv84_fence_chan *fctx = chan->fence;
-	return fctx->dispc_vma[crtc].offset;
+	return fctx->dispc_vma.offset;
 }
 
 static int
@@ -122,12 +122,10 @@ nv84_fence_context_del(struct nouveau_channel *chan)
 	struct drm_device *dev = chan->drm->dev;
 	struct nv84_fence_priv *priv = chan->drm->fence;
 	struct nv84_fence_chan *fctx = chan->fence;
-	int i;
+	struct nouveau_bo *bo = nv50_display_crtc_sema(dev);
 
-	for (i = 0; i < dev->mode_config.num_crtc; i++) {
-		struct nouveau_bo *bo = nv50_display_crtc_sema(dev, i);
-		nouveau_bo_vma_del(bo, &fctx->dispc_vma[i]);
-	}
+	if (bo)
+		nouveau_bo_vma_del(bo, &fctx->dispc_vma);
 
 	nouveau_bo_vma_del(priv->bo, &fctx->vma_gart);
 	nouveau_bo_vma_del(priv->bo, &fctx->vma);
@@ -143,7 +141,8 @@ nv84_fence_context_new(struct nouveau_channel *chan)
 	struct nouveau_client *client = nouveau_client(fifo);
 	struct nv84_fence_priv *priv = chan->drm->fence;
 	struct nv84_fence_chan *fctx;
-	int ret, i;
+	struct nouveau_bo *bo = nv50_display_crtc_sema(chan->drm->dev);
+	int ret;
 
 	fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL);
 	if (!fctx)
@@ -163,10 +162,8 @@ nv84_fence_context_new(struct nouveau_channel *chan)
 	}
 
 	/* map display semaphore buffers into channel's vm */
-	for (i = 0; !ret && i <
chan->drm->dev->mode_config.num_crtc; i++) {
-		struct nouveau_bo *bo = nv50_display_crtc_sema(chan->drm->dev, i);
-		ret = nouveau_bo_vma_add(bo, client->vm, &fctx->dispc_vma[i]);
-	}
+	if (!ret && bo)
+		ret = nouveau_bo_vma_add(bo, client->vm, &fctx->dispc_vma);
 
 	nouveau_bo_wr32(priv->bo, fifo->chid * 16/4, 0x00000000);
 
-- 
1.8.4
Possibly Parallel Threads
- [PATCH] drm/nouveau: do not map evicted bo's in nouveau_bo_vma_add
 - [PATCH] drm/nouveau: avoid null deref on bad arguments to nouveau_vma_getmap
 - [PATCH] drm/nouveau: avoid null deref on bad arguments to nouveau_vma_getmap
 - [PATCH] drm/nouveau: fix takedown in move_notify
 - [PATCH 4/6] drm/nouveau: introduce NOUVEAU_GEM_TILE_WCUS