From ad76b3f7c7a0836e74ac0e316e03988ef3c43564 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 10 Nov 2014 11:24:27 +1000 Subject: [PATCH] drm/nouveau: teach nouveau_bo_pin() how to force a contig vram allocation We have the ability to move buffers around in the kernel if necessary, and should probably use it rather than failing if userspace passes us a non-contig buffer for a plane. The NOUVEAU_GEM_TILE_NONCONTIG flag from userspace will become a mere initial placement hint once all the relevant paths have been updated. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/dispnv04/crtc.c | 4 +-- drivers/gpu/drm/nouveau/dispnv04/overlay.c | 4 +-- drivers/gpu/drm/nouveau/nouveau_abi16.c | 2 +- drivers/gpu/drm/nouveau/nouveau_bo.c | 39 ++++++++++++++++++---- drivers/gpu/drm/nouveau/nouveau_bo.h | 2 +- drivers/gpu/drm/nouveau/nouveau_chan.c | 2 +- drivers/gpu/drm/nouveau/nouveau_display.c | 6 ++-- drivers/gpu/drm/nouveau/nouveau_fbcon.c | 2 +- drivers/gpu/drm/nouveau/nouveau_prime.c | 2 +- drivers/gpu/drm/nouveau/nv17_fence.c | 2 +- drivers/gpu/drm/nouveau/nv50_display.c | 8 ++--- drivers/gpu/drm/nouveau/nv50_fence.c | 2 +- drivers/gpu/drm/nouveau/nv84_fence.c | 4 +-- 13 files changed, 52 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c index 2a03e77abef4..38402ade6835 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c +++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c @@ -614,7 +614,7 @@ nv_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb) struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); int ret; - ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM); + ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM, false); if (ret == 0) { if (disp->image[nv_crtc->index]) nouveau_bo_unpin(disp->image[nv_crtc->index]); @@ -1130,7 +1130,7 @@ nv04_crtc_create(struct drm_device *dev, int crtc_num) ret = nouveau_bo_new(dev, 64*64*4, 0x100, TTM_PL_FLAG_VRAM, 0, 0x0000, NULL, NULL, &nv_crtc->cursor.nvbo); if (!ret) { - ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM); + ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM, false); if (!ret) { ret = nouveau_bo_map(nv_crtc->cursor.nvbo); if (ret) diff --git a/drivers/gpu/drm/nouveau/dispnv04/overlay.c b/drivers/gpu/drm/nouveau/dispnv04/overlay.c index 1e9056a8df94..9f2498571d09 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/overlay.c +++ b/drivers/gpu/drm/nouveau/dispnv04/overlay.c @@ -126,7 +126,7 @@ nv10_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, return -ERANGE; } - ret = nouveau_bo_pin(nv_fb->nvbo, TTM_PL_FLAG_VRAM); + ret = nouveau_bo_pin(nv_fb->nvbo, TTM_PL_FLAG_VRAM, false); if (ret) return ret; @@ -373,7 +373,7 @@ nv04_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, if (crtc_w < src_w || crtc_h < src_h) return -ERANGE; - ret = nouveau_bo_pin(nv_fb->nvbo, TTM_PL_FLAG_VRAM); + ret = nouveau_bo_pin(nv_fb->nvbo, TTM_PL_FLAG_VRAM, false); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index a24faa5e2a2a..d39a15000068 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -308,7 +308,7 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) ret = nouveau_gem_new(dev, PAGE_SIZE, 0, NOUVEAU_GEM_DOMAIN_GART, 0, 0, &chan->ntfy); if (ret == 0) - ret = nouveau_bo_pin(chan->ntfy, TTM_PL_FLAG_TT); + ret = nouveau_bo_pin(chan->ntfy, TTM_PL_FLAG_TT, false); if (ret) goto done; diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 5ece6efeab80..21ec561edc99 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -310,26 +310,49 @@ nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t type, uint32_t busy) } int -nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype) +nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype, bool contig) { struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev); struct ttm_buffer_object *bo = &nvbo->bo; + bool force = false, evict = false; int ret; ret = ttm_bo_reserve(bo, false, false, false, NULL); if (ret) return ret; - if (nvbo->pin_refcnt && !(memtype & (1 << bo->mem.mem_type))) { - NV_ERROR(drm, "bo %p pinned elsewhere: 0x%08x vs 0x%08x\n", bo, - 1 << bo->mem.mem_type, memtype); - ret = -EINVAL; - goto out; + if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA && + memtype == TTM_PL_FLAG_VRAM && contig) { + if (nvbo->tile_flags & NOUVEAU_GEM_TILE_NONCONTIG) { + if (bo->mem.mem_type == TTM_PL_VRAM) { + struct nouveau_mem *mem = bo->mem.mm_node; + if (!list_is_singular(&mem->regions)) + evict = true; + } + nvbo->tile_flags &= ~NOUVEAU_GEM_TILE_NONCONTIG; + force = true; + } } - if (nvbo->pin_refcnt++) + if (nvbo->pin_refcnt) { + if (!(memtype & (1 << bo->mem.mem_type)) || evict) { + NV_ERROR(drm, "bo %p pinned elsewhere: " + "0x%08x vs 0x%08x\n", bo, + 1 << bo->mem.mem_type, memtype); + ret = -EBUSY; + } + nvbo->pin_refcnt++; goto out; + } + if (evict) { + nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_TT, 0); + ret = nouveau_bo_validate(nvbo, false, false); + if (ret) + goto out; + } + + nvbo->pin_refcnt++; nouveau_bo_placement_set(nvbo, memtype, 0); /* drop pin_refcnt temporarily, so we don't trip the assertion @@ -354,6 +377,8 @@ nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype) } out: + if (force && ret) + nvbo->tile_flags |= NOUVEAU_GEM_TILE_NONCONTIG; ttm_bo_unreserve(bo); return ret; } diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.h b/drivers/gpu/drm/nouveau/nouveau_bo.h index c827f233e41d..072222efeeb7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.h +++ b/drivers/gpu/drm/nouveau/nouveau_bo.h @@ -73,7 +73,7 @@ int nouveau_bo_new(struct drm_device *, int size, int align, u32 flags, u32 tile_mode, u32 tile_flags, struct sg_table *sg, struct reservation_object *robj, struct nouveau_bo **); -int nouveau_bo_pin(struct nouveau_bo *, u32 flags); +int nouveau_bo_pin(struct nouveau_bo *, u32 flags, bool contig); int nouveau_bo_unpin(struct nouveau_bo *); int nouveau_bo_map(struct nouveau_bo *); void nouveau_bo_unmap(struct nouveau_bo *); diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c index 0f3da86840f2..aff9099aae6c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_chan.c +++ b/drivers/gpu/drm/nouveau/nouveau_chan.c @@ -109,7 +109,7 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device, ret = nouveau_bo_new(drm->dev, size, 0, target, 0, 0, NULL, NULL, &chan->push.buffer); if (ret == 0) { - ret = nouveau_bo_pin(chan->push.buffer, target); + ret = nouveau_bo_pin(chan->push.buffer, target, false); if (ret == 0) ret = nouveau_bo_map(chan->push.buffer); } diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index e02ab391c870..f9a0f1dc15f9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -592,7 +592,7 @@ nouveau_display_resume(struct drm_device *dev, bool runtime) if (!nouveau_fb || !nouveau_fb->nvbo) continue; - ret = nouveau_bo_pin(nouveau_fb->nvbo, TTM_PL_FLAG_VRAM); + ret = nouveau_bo_pin(nouveau_fb->nvbo, TTM_PL_FLAG_VRAM, false); if (ret) NV_ERROR(drm, "Could not pin framebuffer\n"); } @@ -600,7 +600,7 @@ nouveau_display_resume(struct drm_device *dev, bool runtime) list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); - ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM); + ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM, false); if (!ret) ret = nouveau_bo_map(nv_crtc->cursor.nvbo); if (ret) @@ -713,7 +713,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, return -ENOMEM; if (new_bo != old_bo) { - ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM); + ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM, false); if (ret) goto fail_free; } diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index b3a58b384256..3ed12a8cfc91 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -341,7 +341,7 @@ nouveau_fbcon_create(struct drm_fb_helper *helper, goto out; } - ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_VRAM); + ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_VRAM, false); if (ret) { NV_ERROR(drm, "failed to pin fb: %d\n", ret); goto out_unref; diff --git a/drivers/gpu/drm/nouveau/nouveau_prime.c b/drivers/gpu/drm/nouveau/nouveau_prime.c index 228226ab27fc..dd32ad6db53d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_prime.c +++ b/drivers/gpu/drm/nouveau/nouveau_prime.c @@ -93,7 +93,7 @@ int nouveau_gem_prime_pin(struct drm_gem_object *obj) int ret; /* pin buffer into GTT */ - ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_TT); + ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_TT, false); if (ret) return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nv17_fence.c b/drivers/gpu/drm/nouveau/nv17_fence.c index 40b461c7d5c5..57860cfa1de5 100644 --- a/drivers/gpu/drm/nouveau/nv17_fence.c +++ b/drivers/gpu/drm/nouveau/nv17_fence.c @@ -131,7 +131,7 @@ nv17_fence_create(struct nouveau_drm *drm) ret = nouveau_bo_new(drm->dev, 4096, 0x1000, TTM_PL_FLAG_VRAM, 0, 0x0000, NULL, NULL, &priv->bo); if (!ret) { - ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM); + ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM, false); if (!ret) { ret = nouveau_bo_map(priv->bo); if (ret) diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 2016d8ece028..2b5aefb3b9e5 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -1073,7 +1073,7 @@ nv50_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb) struct nv50_head *head = nv50_head(crtc); int ret; - ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM); + ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM, false); if (ret == 0) { if (head->image) nouveau_bo_unpin(head->image); @@ -1402,7 +1402,7 @@ nv50_crtc_create(struct drm_device *dev, int index) ret = nouveau_bo_new(dev, 8192, 0x100, TTM_PL_FLAG_VRAM, 0, 0x0000, NULL, NULL, &head->base.lut.nvbo); if (!ret) { - ret = nouveau_bo_pin(head->base.lut.nvbo, TTM_PL_FLAG_VRAM); + ret = nouveau_bo_pin(head->base.lut.nvbo, TTM_PL_FLAG_VRAM, false); if (!ret) { ret = nouveau_bo_map(head->base.lut.nvbo); if (ret) @@ -1425,7 +1425,7 @@ nv50_crtc_create(struct drm_device *dev, int index) ret = nouveau_bo_new(dev, 64 * 64 * 4, 0x100, TTM_PL_FLAG_VRAM, 0, 0x0000, NULL, NULL, &head->base.cursor.nvbo); if (!ret) { - ret = nouveau_bo_pin(head->base.cursor.nvbo, TTM_PL_FLAG_VRAM); + ret = nouveau_bo_pin(head->base.cursor.nvbo, TTM_PL_FLAG_VRAM, false); if (!ret) { ret = nouveau_bo_map(head->base.cursor.nvbo); if (ret) @@ -2487,7 +2487,7 @@ nv50_display_create(struct drm_device *dev) ret = nouveau_bo_new(dev, 4096, 0x1000, TTM_PL_FLAG_VRAM, 0, 0x0000, NULL, NULL, &disp->sync); if (!ret) { - ret = nouveau_bo_pin(disp->sync, TTM_PL_FLAG_VRAM); + ret = nouveau_bo_pin(disp->sync, TTM_PL_FLAG_VRAM, false); if (!ret) { ret = nouveau_bo_map(disp->sync); if (ret) diff --git a/drivers/gpu/drm/nouveau/nv50_fence.c b/drivers/gpu/drm/nouveau/nv50_fence.c index 22d242b37962..a82d9ea7c6fd 100644 --- a/drivers/gpu/drm/nouveau/nv50_fence.c +++ b/drivers/gpu/drm/nouveau/nv50_fence.c @@ -102,7 +102,7 @@ nv50_fence_create(struct nouveau_drm *drm) ret = nouveau_bo_new(drm->dev, 4096, 0x1000, TTM_PL_FLAG_VRAM, 0, 0x0000, NULL, NULL, &priv->bo); if (!ret) { - ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM); + ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM, false); if (!ret) { ret = nouveau_bo_map(priv->bo); if (ret) diff --git a/drivers/gpu/drm/nouveau/nv84_fence.c b/drivers/gpu/drm/nouveau/nv84_fence.c index 4d79be7558d8..cb5b88938d45 100644 --- a/drivers/gpu/drm/nouveau/nv84_fence.c +++ b/drivers/gpu/drm/nouveau/nv84_fence.c @@ -234,7 +234,7 @@ nv84_fence_create(struct nouveau_drm *drm) ret = nouveau_bo_new(drm->dev, 16 * priv->base.contexts, 0, TTM_PL_FLAG_VRAM, 0, 0, NULL, NULL, &priv->bo); if (ret == 0) { - ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM); + ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM, false); if (ret == 0) { ret = nouveau_bo_map(priv->bo); if (ret) @@ -249,7 +249,7 @@ nv84_fence_create(struct nouveau_drm *drm) TTM_PL_FLAG_TT | TTM_PL_FLAG_UNCACHED, 0, 0, NULL, NULL, &priv->bo_gart); if (ret == 0) { - ret = nouveau_bo_pin(priv->bo_gart, TTM_PL_FLAG_TT); + ret = nouveau_bo_pin(priv->bo_gart, TTM_PL_FLAG_TT, false); if (ret == 0) { ret = nouveau_bo_map(priv->bo_gart); if (ret) -- 2.20.1