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
- [Intel-gfx] [PATCH v6 08/17] drm/ttm: use gem vma_node
- [PATCH 4/6] drm: enable big page mapping for small pages when IOMMU is available
- Fixing nouveau for >4k PAGE_SIZE
- [PATCH 1/7] drm/nouveau: fix m2mf copy to tiled gart
- [PATCH] drm/nv50-: fix tiled memory layout checks