From fcd6f048386da34d970bfeee25ac3c3fc28819ad Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 12 Feb 2019 22:28:13 +1000 Subject: [PATCH] drm/nouveau/kms/nv04-nv4x: move a bunch of pre-nv50 page flip code to dispnv04 Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/dispnv04/crtc.c | 214 ++++++++++++++++++++- drivers/gpu/drm/nouveau/dispnv04/disp.c | 19 ++ drivers/gpu/drm/nouveau/dispnv04/disp.h | 2 + drivers/gpu/drm/nouveau/nouveau_display.c | 215 +--------------------- drivers/gpu/drm/nouveau/nouveau_display.h | 15 -- drivers/gpu/drm/nouveau/nouveau_drm.c | 13 -- drivers/gpu/drm/nouveau/nouveau_drv.h | 1 - drivers/gpu/drm/nouveau/nouveau_fence.h | 2 - 8 files changed, 235 insertions(+), 246 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c index 2c569e264df3..f22f01020625 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c +++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c @@ -40,6 +40,7 @@ #include "nvreg.h" #include "nouveau_fbcon.h" #include "disp.h" +#include "nouveau_dma.h" #include #include @@ -1077,12 +1078,223 @@ nouveau_crtc_set_config(struct drm_mode_set *set, return ret; } +struct nv04_page_flip_state { + struct list_head head; + struct drm_pending_vblank_event *event; + struct drm_crtc *crtc; + int bpp, pitch; + u64 offset; +}; + +static int +nv04_finish_page_flip(struct nouveau_channel *chan, + struct nv04_page_flip_state *ps) +{ + struct nouveau_fence_chan *fctx = chan->fence; + struct nouveau_drm *drm = chan->drm; + struct drm_device *dev = drm->dev; + struct nv04_page_flip_state *s; + unsigned long flags; + + spin_lock_irqsave(&dev->event_lock, flags); + + if (list_empty(&fctx->flip)) { + NV_ERROR(drm, "unexpected pageflip\n"); + spin_unlock_irqrestore(&dev->event_lock, flags); + return -EINVAL; + } + + s = list_first_entry(&fctx->flip, struct nv04_page_flip_state, head); + if (s->event) { + drm_crtc_arm_vblank_event(s->crtc, s->event); + } else { + /* Give up ownership of vblank for page-flipped crtc */ + drm_crtc_vblank_put(s->crtc); + } + + list_del(&s->head); + if (ps) + *ps = *s; + kfree(s); + + spin_unlock_irqrestore(&dev->event_lock, flags); + return 0; +} + +int +nv04_flip_complete(struct nvif_notify *notify) +{ + struct nouveau_cli *cli = (void *)notify->object->client; + struct nouveau_drm *drm = cli->drm; + struct nouveau_channel *chan = drm->channel; + struct nv04_page_flip_state state; + + if (!nv04_finish_page_flip(chan, &state)) { + nv_set_crtc_base(drm->dev, drm_crtc_index(state.crtc), + state.offset + state.crtc->y * + state.pitch + state.crtc->x * + state.bpp / 8); + } + + return NVIF_NOTIFY_KEEP; +} + +static int +nv04_page_flip_emit(struct nouveau_channel *chan, + struct nouveau_bo *old_bo, + struct nouveau_bo *new_bo, + struct nv04_page_flip_state *s, + struct nouveau_fence **pfence) +{ + struct nouveau_fence_chan *fctx = chan->fence; + struct nouveau_drm *drm = chan->drm; + struct drm_device *dev = drm->dev; + unsigned long flags; + int ret; + + /* Queue it to the pending list */ + spin_lock_irqsave(&dev->event_lock, flags); + list_add_tail(&s->head, &fctx->flip); + spin_unlock_irqrestore(&dev->event_lock, flags); + + /* Synchronize with the old framebuffer */ + ret = nouveau_fence_sync(old_bo, chan, false, false); + if (ret) + goto fail; + + /* Emit the pageflip */ + ret = RING_SPACE(chan, 2); + if (ret) + goto fail; + + BEGIN_NV04(chan, NvSubSw, NV_SW_PAGE_FLIP, 1); + OUT_RING (chan, 0x00000000); + FIRE_RING (chan); + + ret = nouveau_fence_new(chan, false, pfence); + if (ret) + goto fail; + + return 0; +fail: + spin_lock_irqsave(&dev->event_lock, flags); + list_del(&s->head); + spin_unlock_irqrestore(&dev->event_lock, flags); + return ret; +} + +static int +nv04_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event, u32 flags, + struct drm_modeset_acquire_ctx *ctx) +{ + const int swap_interval = (flags & DRM_MODE_PAGE_FLIP_ASYNC) ? 0 : 1; + struct drm_device *dev = crtc->dev; + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->primary->fb)->nvbo; + struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo; + struct nv04_page_flip_state *s; + struct nouveau_channel *chan; + struct nouveau_cli *cli; + struct nouveau_fence *fence; + struct nv04_display *dispnv04 = nv04_display(dev); + int head = nouveau_crtc(crtc)->index; + int ret; + + chan = drm->channel; + if (!chan) + return -ENODEV; + cli = (void *)chan->user.client; + + s = kzalloc(sizeof(*s), GFP_KERNEL); + if (!s) + return -ENOMEM; + + if (new_bo != old_bo) { + ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM, true); + if (ret) + goto fail_free; + } + + mutex_lock(&cli->mutex); + ret = ttm_bo_reserve(&new_bo->bo, true, false, NULL); + if (ret) + goto fail_unpin; + + /* synchronise rendering channel with the kernel's channel */ + ret = nouveau_fence_sync(new_bo, chan, false, true); + if (ret) { + ttm_bo_unreserve(&new_bo->bo); + goto fail_unpin; + } + + if (new_bo != old_bo) { + ttm_bo_unreserve(&new_bo->bo); + + ret = ttm_bo_reserve(&old_bo->bo, true, false, NULL); + if (ret) + goto fail_unpin; + } + + /* Initialize a page flip struct */ + *s = (struct nv04_page_flip_state) + { { }, event, crtc, fb->format->cpp[0] * 8, fb->pitches[0], + new_bo->bo.offset }; + + /* Keep vblanks on during flip, for the target crtc of this flip */ + drm_crtc_vblank_get(crtc); + + /* Emit a page flip */ + if (swap_interval) { + ret = RING_SPACE(chan, 8); + if (ret) + goto fail_unreserve; + + BEGIN_NV04(chan, NvSubImageBlit, 0x012c, 1); + OUT_RING (chan, 0); + BEGIN_NV04(chan, NvSubImageBlit, 0x0134, 1); + OUT_RING (chan, head); + BEGIN_NV04(chan, NvSubImageBlit, 0x0100, 1); + OUT_RING (chan, 0); + BEGIN_NV04(chan, NvSubImageBlit, 0x0130, 1); + OUT_RING (chan, 0); + } + + nouveau_bo_ref(new_bo, &dispnv04->image[head]); + + ret = nv04_page_flip_emit(chan, old_bo, new_bo, s, &fence); + if (ret) + goto fail_unreserve; + mutex_unlock(&cli->mutex); + + /* Update the crtc struct and cleanup */ + crtc->primary->fb = fb; + + nouveau_bo_fence(old_bo, fence, false); + ttm_bo_unreserve(&old_bo->bo); + if (old_bo != new_bo) + nouveau_bo_unpin(old_bo); + nouveau_fence_unref(&fence); + return 0; + +fail_unreserve: + drm_crtc_vblank_put(crtc); + ttm_bo_unreserve(&old_bo->bo); +fail_unpin: + mutex_unlock(&cli->mutex); + if (old_bo != new_bo) + nouveau_bo_unpin(new_bo); +fail_free: + kfree(s); + return ret; +} + static const struct drm_crtc_funcs nv04_crtc_funcs = { .cursor_set = nv04_crtc_cursor_set, .cursor_move = nv04_crtc_cursor_move, .gamma_set = nv_crtc_gamma_set, .set_config = nouveau_crtc_set_config, - .page_flip = nouveau_crtc_page_flip, + .page_flip = nv04_crtc_page_flip, .destroy = nv_crtc_destroy, }; diff --git a/drivers/gpu/drm/nouveau/dispnv04/disp.c b/drivers/gpu/drm/nouveau/dispnv04/disp.c index f2abae39fdca..bda02f660304 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv04/disp.c @@ -31,9 +31,16 @@ #include "nouveau_encoder.h" #include "nouveau_connector.h" +#include + static void nv04_display_fini(struct drm_device *dev) { + struct nv04_display *disp = nv04_display(dev); + + /* Disable flip completion events. */ + nvif_notify_put(&disp->flip); + /* Disable vblank interrupts. */ NVWriteCRTC(dev, 0, NV_PCRTC_INTR_EN_0, 0); if (nv_two_heads(dev)) @@ -43,6 +50,7 @@ nv04_display_fini(struct drm_device *dev) static int nv04_display_init(struct drm_device *dev) { + struct nv04_display *disp = nv04_display(dev); struct nouveau_encoder *encoder; struct nouveau_crtc *crtc; @@ -60,6 +68,8 @@ nv04_display_init(struct drm_device *dev) list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.base.head) encoder->enc_save(&encoder->base.base); + /* Enable flip completion events. */ + nvif_notify_get(&disp->flip); return 0; } @@ -80,6 +90,8 @@ nv04_display_destroy(struct drm_device *dev) nouveau_hw_save_vga_fonts(dev, 0); + nvif_notify_fini(&disp->flip); + nouveau_display(dev)->priv = NULL; kfree(disp); @@ -113,6 +125,13 @@ nv04_display_create(struct drm_device *dev) /* Pre-nv50 doesn't support atomic, so don't expose the ioctls */ dev->driver->driver_features &= ~DRIVER_ATOMIC; + /* Request page flip completion event. */ + if (drm->nvsw.client) { + nvif_notify_init(&drm->nvsw, nv04_flip_complete, + false, NV04_NVSW_NTFY_UEVENT, + NULL, 0, 0, &disp->flip); + } + nouveau_hw_save_vga_fonts(dev, 1); nv04_crtc_create(dev, 0); diff --git a/drivers/gpu/drm/nouveau/dispnv04/disp.h b/drivers/gpu/drm/nouveau/dispnv04/disp.h index 91bbc0c104eb..c6ed20a09f4a 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/disp.h +++ b/drivers/gpu/drm/nouveau/dispnv04/disp.h @@ -82,6 +82,7 @@ struct nv04_display { uint32_t saved_vga_font[4][16384]; uint32_t dac_users[4]; struct nouveau_bo *image[2]; + struct nvif_notify flip; }; static inline struct nv04_display * @@ -173,4 +174,5 @@ nouveau_bios_run_init_table(struct drm_device *dev, u16 table, ); } +int nv04_flip_complete(struct nvif_notify *); #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 56b6ac1b8edd..1acf035db02e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -32,18 +32,13 @@ #include #include -#include - #include "nouveau_fbcon.h" -#include "dispnv04/hw.h" #include "nouveau_crtc.h" -#include "nouveau_dma.h" #include "nouveau_gem.h" #include "nouveau_connector.h" #include "nv50_display.h" -#include "nouveau_fence.h" - +#include #include #include @@ -415,7 +410,6 @@ int nouveau_display_init(struct drm_device *dev) { struct nouveau_display *disp = nouveau_display(dev); - struct nouveau_drm *drm = nouveau_drm(dev); struct drm_connector *connector; struct drm_connector_list_iter conn_iter; int ret; @@ -437,8 +431,6 @@ nouveau_display_init(struct drm_device *dev) } drm_connector_list_iter_end(&conn_iter); - /* enable flip completion events */ - nvif_notify_get(&drm->flip); return ret; } @@ -457,9 +449,6 @@ nouveau_display_fini(struct drm_device *dev, bool suspend, bool runtime) drm_helper_force_disable_all(dev); } - /* disable flip completion events */ - nvif_notify_put(&drm->flip); - /* disable hotplug interrupts */ drm_connector_list_iter_begin(dev, &conn_iter); nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) { @@ -738,208 +727,6 @@ nouveau_display_resume(struct drm_device *dev, bool runtime) } } -static int -nouveau_page_flip_emit(struct nouveau_channel *chan, - struct nouveau_bo *old_bo, - struct nouveau_bo *new_bo, - struct nouveau_page_flip_state *s, - struct nouveau_fence **pfence) -{ - struct nouveau_fence_chan *fctx = chan->fence; - struct nouveau_drm *drm = chan->drm; - struct drm_device *dev = drm->dev; - unsigned long flags; - int ret; - - /* Queue it to the pending list */ - spin_lock_irqsave(&dev->event_lock, flags); - list_add_tail(&s->head, &fctx->flip); - spin_unlock_irqrestore(&dev->event_lock, flags); - - /* Synchronize with the old framebuffer */ - ret = nouveau_fence_sync(old_bo, chan, false, false); - if (ret) - goto fail; - - /* Emit the pageflip */ - ret = RING_SPACE(chan, 2); - if (ret) - goto fail; - - BEGIN_NV04(chan, NvSubSw, NV_SW_PAGE_FLIP, 1); - OUT_RING (chan, 0x00000000); - FIRE_RING (chan); - - ret = nouveau_fence_new(chan, false, pfence); - if (ret) - goto fail; - - return 0; -fail: - spin_lock_irqsave(&dev->event_lock, flags); - list_del(&s->head); - spin_unlock_irqrestore(&dev->event_lock, flags); - return ret; -} - -int -nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, - struct drm_pending_vblank_event *event, u32 flags, - struct drm_modeset_acquire_ctx *ctx) -{ - const int swap_interval = (flags & DRM_MODE_PAGE_FLIP_ASYNC) ? 0 : 1; - struct drm_device *dev = crtc->dev; - struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->primary->fb)->nvbo; - struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo; - struct nouveau_page_flip_state *s; - struct nouveau_channel *chan; - struct nouveau_cli *cli; - struct nouveau_fence *fence; - struct nv04_display *dispnv04 = nv04_display(dev); - int head = nouveau_crtc(crtc)->index; - int ret; - - chan = drm->channel; - if (!chan) - return -ENODEV; - cli = (void *)chan->user.client; - - s = kzalloc(sizeof(*s), GFP_KERNEL); - if (!s) - return -ENOMEM; - - if (new_bo != old_bo) { - ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM, true); - if (ret) - goto fail_free; - } - - mutex_lock(&cli->mutex); - ret = ttm_bo_reserve(&new_bo->bo, true, false, NULL); - if (ret) - goto fail_unpin; - - /* synchronise rendering channel with the kernel's channel */ - ret = nouveau_fence_sync(new_bo, chan, false, true); - if (ret) { - ttm_bo_unreserve(&new_bo->bo); - goto fail_unpin; - } - - if (new_bo != old_bo) { - ttm_bo_unreserve(&new_bo->bo); - - ret = ttm_bo_reserve(&old_bo->bo, true, false, NULL); - if (ret) - goto fail_unpin; - } - - /* Initialize a page flip struct */ - *s = (struct nouveau_page_flip_state) - { { }, event, crtc, fb->format->cpp[0] * 8, fb->pitches[0], - new_bo->bo.offset }; - - /* Keep vblanks on during flip, for the target crtc of this flip */ - drm_crtc_vblank_get(crtc); - - /* Emit a page flip */ - if (swap_interval) { - ret = RING_SPACE(chan, 8); - if (ret) - goto fail_unreserve; - - BEGIN_NV04(chan, NvSubImageBlit, 0x012c, 1); - OUT_RING (chan, 0); - BEGIN_NV04(chan, NvSubImageBlit, 0x0134, 1); - OUT_RING (chan, head); - BEGIN_NV04(chan, NvSubImageBlit, 0x0100, 1); - OUT_RING (chan, 0); - BEGIN_NV04(chan, NvSubImageBlit, 0x0130, 1); - OUT_RING (chan, 0); - } - - nouveau_bo_ref(new_bo, &dispnv04->image[head]); - - ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence); - if (ret) - goto fail_unreserve; - mutex_unlock(&cli->mutex); - - /* Update the crtc struct and cleanup */ - crtc->primary->fb = fb; - - nouveau_bo_fence(old_bo, fence, false); - ttm_bo_unreserve(&old_bo->bo); - if (old_bo != new_bo) - nouveau_bo_unpin(old_bo); - nouveau_fence_unref(&fence); - return 0; - -fail_unreserve: - drm_crtc_vblank_put(crtc); - ttm_bo_unreserve(&old_bo->bo); -fail_unpin: - mutex_unlock(&cli->mutex); - if (old_bo != new_bo) - nouveau_bo_unpin(new_bo); -fail_free: - kfree(s); - return ret; -} - -int -nouveau_finish_page_flip(struct nouveau_channel *chan, - struct nouveau_page_flip_state *ps) -{ - struct nouveau_fence_chan *fctx = chan->fence; - struct nouveau_drm *drm = chan->drm; - struct drm_device *dev = drm->dev; - struct nouveau_page_flip_state *s; - unsigned long flags; - - spin_lock_irqsave(&dev->event_lock, flags); - - if (list_empty(&fctx->flip)) { - NV_ERROR(drm, "unexpected pageflip\n"); - spin_unlock_irqrestore(&dev->event_lock, flags); - return -EINVAL; - } - - s = list_first_entry(&fctx->flip, struct nouveau_page_flip_state, head); - if (s->event) { - drm_crtc_arm_vblank_event(s->crtc, s->event); - } else { - /* Give up ownership of vblank for page-flipped crtc */ - drm_crtc_vblank_put(s->crtc); - } - - list_del(&s->head); - if (ps) - *ps = *s; - kfree(s); - - spin_unlock_irqrestore(&dev->event_lock, flags); - return 0; -} - -int -nouveau_flip_complete(struct nvif_notify *notify) -{ - struct nouveau_drm *drm = container_of(notify, typeof(*drm), flip); - struct nouveau_channel *chan = drm->channel; - struct nouveau_page_flip_state state; - - if (!nouveau_finish_page_flip(chan, &state)) { - nv_set_crtc_base(drm->dev, drm_crtc_index(state.crtc), - state.offset + state.crtc->y * - state.pitch + state.crtc->x * - state.bpp / 8); - } - - return NVIF_NOTIFY_KEEP; -} - int nouveau_display_dumb_create(struct drm_file *file_priv, struct drm_device *dev, struct drm_mode_create_dumb *args) diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h index eb77e41c2d4e..2676876a82c7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.h +++ b/drivers/gpu/drm/nouveau/nouveau_display.h @@ -25,14 +25,6 @@ int nouveau_framebuffer_new(struct drm_device *, const struct drm_mode_fb_cmd2 *, struct nouveau_bo *, struct nouveau_framebuffer **); -struct nouveau_page_flip_state { - struct list_head head; - struct drm_pending_vblank_event *event; - struct drm_crtc *crtc; - int bpp, pitch; - u64 offset; -}; - struct nouveau_display { void *priv; void (*dtor)(struct drm_device *); @@ -71,13 +63,6 @@ bool nouveau_display_scanoutpos(struct drm_device *, unsigned int, bool, int *, int *, ktime_t *, ktime_t *, const struct drm_display_mode *); -int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, - struct drm_pending_vblank_event *event, - uint32_t page_flip_flags, - struct drm_modeset_acquire_ctx *ctx); -int nouveau_finish_page_flip(struct nouveau_channel *, - struct nouveau_page_flip_state *); - int nouveau_display_dumb_create(struct drm_file *, struct drm_device *, struct drm_mode_create_dumb *args); int nouveau_display_dumb_map_offset(struct drm_file *, struct drm_device *, diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 2c665f9aba93..4ee530c941b1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -44,7 +44,6 @@ #include #include #include -#include #include "nouveau_drv.h" #include "nouveau_dma.h" @@ -288,7 +287,6 @@ nouveau_accel_fini(struct nouveau_drm *drm) nouveau_channel_idle(drm->channel); nvif_object_fini(&drm->ntfy); nvkm_gpuobj_del(&drm->notify); - nvif_notify_fini(&drm->flip); nvif_object_fini(&drm->nvsw); nouveau_channel_del(&drm->channel); @@ -412,17 +410,6 @@ nouveau_accel_init(struct nouveau_drm *drm) BEGIN_NV04(drm->channel, NvSubSw, 0, 1); OUT_RING (drm->channel, drm->nvsw.handle); } - - ret = nvif_notify_init(&drm->nvsw, - nouveau_flip_complete, - false, NV04_NVSW_NTFY_UEVENT, - NULL, 0, 0, &drm->flip); - if (ret == 0) - ret = nvif_notify_get(&drm->flip); - if (ret) { - nouveau_accel_fini(drm); - return; - } } if (ret) { diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index d20b9ba4b1c1..0ea79c047d8c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -181,7 +181,6 @@ struct nouveau_drm { struct nouveau_fbdev *fbcon; struct nvif_object nvsw; struct nvif_object ntfy; - struct nvif_notify flip; /* nv10-nv40 tiling regions */ struct { diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h b/drivers/gpu/drm/nouveau/nouveau_fence.h index b999e6058046..ad27caeca0fd 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.h +++ b/drivers/gpu/drm/nouveau/nouveau_fence.h @@ -82,8 +82,6 @@ int nv50_fence_create(struct nouveau_drm *); int nv84_fence_create(struct nouveau_drm *); int nvc0_fence_create(struct nouveau_drm *); -int nouveau_flip_complete(struct nvif_notify *); - struct nv84_fence_chan { struct nouveau_fence_chan base; struct nouveau_vma *vma; -- 2.25.1