diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_display.c')
| -rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_display.c | 524 |
1 files changed, 318 insertions, 206 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 508b00a2ce0..47ad74255bf 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -28,7 +28,7 @@ #include <drm/drm_crtc_helper.h> #include "nouveau_fbcon.h" -#include "nouveau_hw.h" +#include "dispnv04/hw.h" #include "nouveau_crtc.h" #include "nouveau_dma.h" #include "nouveau_gem.h" @@ -37,17 +37,172 @@ #include "nouveau_fence.h" -#include <subdev/bios/gpio.h> -#include <subdev/gpio.h> #include <engine/disp.h> +#include <core/class.h> + +static int +nouveau_display_vblank_handler(void *data, u32 type, int head) +{ + struct nouveau_drm *drm = data; + drm_handle_vblank(drm->dev, head); + return NVKM_EVENT_KEEP; +} + +int +nouveau_display_vblank_enable(struct drm_device *dev, int head) +{ + struct nouveau_display *disp = nouveau_display(dev); + if (disp) { + nouveau_event_get(disp->vblank[head]); + return 0; + } + return -EIO; +} + +void +nouveau_display_vblank_disable(struct drm_device *dev, int head) +{ + struct nouveau_display *disp = nouveau_display(dev); + if (disp) + nouveau_event_put(disp->vblank[head]); +} + +static inline int +calc(int blanks, int blanke, int total, int line) +{ + if (blanke >= blanks) { + if (line >= blanks) + line -= total; + } else { + if (line >= blanks) + line -= total; + line -= blanke + 1; + } + return line; +} + +int +nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos, + ktime_t *stime, ktime_t *etime) +{ + const u32 mthd = NV04_DISP_SCANOUTPOS + nouveau_crtc(crtc)->index; + struct nouveau_display *disp = nouveau_display(crtc->dev); + struct nv04_display_scanoutpos args; + int ret, retry = 1; + + do { + ret = nv_exec(disp->core, mthd, &args, sizeof(args)); + if (ret != 0) + return 0; + + if (args.vline) { + ret |= DRM_SCANOUTPOS_ACCURATE; + ret |= DRM_SCANOUTPOS_VALID; + break; + } + + if (retry) ndelay(crtc->linedur_ns); + } while (retry--); + + *hpos = args.hline; + *vpos = calc(args.vblanks, args.vblanke, args.vtotal, args.vline); + if (stime) *stime = ns_to_ktime(args.time[0]); + if (etime) *etime = ns_to_ktime(args.time[1]); + + if (*vpos < 0) + ret |= DRM_SCANOUTPOS_INVBL; + return ret; +} + +int +nouveau_display_scanoutpos(struct drm_device *dev, int head, unsigned int flags, + int *vpos, int *hpos, ktime_t *stime, ktime_t *etime) +{ + struct drm_crtc *crtc; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + if (nouveau_crtc(crtc)->index == head) { + return nouveau_display_scanoutpos_head(crtc, vpos, hpos, + stime, etime); + } + } + + return 0; +} + +int +nouveau_display_vblstamp(struct drm_device *dev, int head, int *max_error, + struct timeval *time, unsigned flags) +{ + struct drm_crtc *crtc; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + if (nouveau_crtc(crtc)->index == head) { + return drm_calc_vbltimestamp_from_scanoutpos(dev, + head, max_error, time, flags, crtc, + &crtc->hwmode); + } + } + + return -EINVAL; +} + +static void +nouveau_display_vblank_fini(struct drm_device *dev) +{ + struct nouveau_display *disp = nouveau_display(dev); + int i; + + drm_vblank_cleanup(dev); + + if (disp->vblank) { + for (i = 0; i < dev->mode_config.num_crtc; i++) + nouveau_event_ref(NULL, &disp->vblank[i]); + kfree(disp->vblank); + disp->vblank = NULL; + } +} + +static int +nouveau_display_vblank_init(struct drm_device *dev) +{ + struct nouveau_display *disp = nouveau_display(dev); + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_disp *pdisp = nouveau_disp(drm->device); + int ret, i; + + disp->vblank = kzalloc(dev->mode_config.num_crtc * + sizeof(*disp->vblank), GFP_KERNEL); + if (!disp->vblank) + return -ENOMEM; + + for (i = 0; i < dev->mode_config.num_crtc; i++) { + ret = nouveau_event_new(pdisp->vblank, 1, i, + nouveau_display_vblank_handler, + drm, &disp->vblank[i]); + if (ret) { + nouveau_display_vblank_fini(dev); + return ret; + } + } + + ret = drm_vblank_init(dev, dev->mode_config.num_crtc); + if (ret) { + nouveau_display_vblank_fini(dev); + return ret; + } + + return 0; +} + static void nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb) { struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb); if (fb->nvbo) - drm_gem_object_unreference_unlocked(fb->nvbo->gem); + drm_gem_object_unreference_unlocked(&fb->nvbo->gem); drm_framebuffer_cleanup(drm_fb); kfree(fb); @@ -60,7 +215,7 @@ nouveau_user_framebuffer_create_handle(struct drm_framebuffer *drm_fb, { struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb); - return drm_gem_handle_create(file_priv, fb->nvbo->gem, handle); + return drm_gem_handle_create(file_priv, &fb->nvbo->gem, handle); } static const struct drm_framebuffer_funcs nouveau_framebuffer_funcs = { @@ -78,11 +233,6 @@ nouveau_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb = &nv_fb->base; int ret; - ret = drm_framebuffer_init(dev, fb, &nouveau_framebuffer_funcs); - if (ret) { - return ret; - } - drm_helper_mode_fill_fb_struct(fb, mode_cmd); nv_fb->nvbo = nvbo; @@ -109,6 +259,11 @@ nouveau_framebuffer_init(struct drm_device *dev, return -EINVAL; } + if (nvbo->tile_flags & NOUVEAU_GEM_TILE_NONCONTIG) { + NV_ERROR(drm, "framebuffer requires contiguous bo\n"); + return -EINVAL; + } + if (nv_device(drm->device)->chipset == 0x50) nv_fb->r_format |= (tile_flags << 8); @@ -125,6 +280,11 @@ nouveau_framebuffer_init(struct drm_device *dev, } } + ret = drm_framebuffer_init(dev, fb, &nouveau_framebuffer_funcs); + if (ret) { + return ret; + } + return 0; } @@ -135,7 +295,7 @@ nouveau_user_framebuffer_create(struct drm_device *dev, { struct nouveau_framebuffer *nouveau_fb; struct drm_gem_object *gem; - int ret; + int ret = -ENOMEM; gem = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]); if (!gem) @@ -143,15 +303,19 @@ nouveau_user_framebuffer_create(struct drm_device *dev, nouveau_fb = kzalloc(sizeof(struct nouveau_framebuffer), GFP_KERNEL); if (!nouveau_fb) - return ERR_PTR(-ENOMEM); + goto err_unref; ret = nouveau_framebuffer_init(dev, nouveau_fb, mode_cmd, nouveau_gem_object(gem)); - if (ret) { - drm_gem_object_unreference(gem); - return ERR_PTR(ret); - } + if (ret) + goto err; return &nouveau_fb->base; + +err: + kfree(nouveau_fb); +err_unref: + drm_gem_object_unreference(gem); + return ERR_PTR(ret); } static const struct drm_mode_config_funcs nouveau_mode_config_funcs = { @@ -215,9 +379,7 @@ static struct nouveau_drm_prop_enum_list dither_depth[] = { int nouveau_display_init(struct drm_device *dev) { - struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_display *disp = nouveau_display(dev); - struct nouveau_gpio *gpio = nouveau_gpio(drm->device); struct drm_connector *connector; int ret; @@ -231,8 +393,7 @@ nouveau_display_init(struct drm_device *dev) /* enable hotplug interrupts */ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { struct nouveau_connector *conn = nouveau_connector(connector); - if (gpio) - gpio->irq(gpio, 0, conn->hpd, 0xff, true); + if (conn->hpd) nouveau_event_get(conn->hpd); } return ret; @@ -241,58 +402,31 @@ nouveau_display_init(struct drm_device *dev) void nouveau_display_fini(struct drm_device *dev) { - struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_display *disp = nouveau_display(dev); - struct nouveau_gpio *gpio = nouveau_gpio(drm->device); struct drm_connector *connector; /* disable hotplug interrupts */ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { struct nouveau_connector *conn = nouveau_connector(connector); - if (gpio) - gpio->irq(gpio, 0, conn->hpd, 0xff, false); + if (conn->hpd) nouveau_event_put(conn->hpd); } drm_kms_helper_poll_disable(dev); disp->fini(dev); } -static void -nouveau_display_vblank_notify(void *data, int crtc) -{ - drm_handle_vblank(data, crtc); -} - -static void -nouveau_display_vblank_get(void *data, int crtc) -{ - drm_vblank_get(data, crtc); -} - -static void -nouveau_display_vblank_put(void *data, int crtc) -{ - drm_vblank_put(data, crtc); -} - int nouveau_display_create(struct drm_device *dev) { struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_disp *pdisp = nouveau_disp(drm->device); + struct nouveau_device *device = nouveau_dev(dev); struct nouveau_display *disp; - u32 pclass = dev->pdev->class >> 8; int ret, gen; disp = drm->display = kzalloc(sizeof(*disp), GFP_KERNEL); if (!disp) return -ENOMEM; - pdisp->vblank.data = dev; - pdisp->vblank.notify = nouveau_display_vblank_notify; - pdisp->vblank.get = nouveau_display_vblank_get; - pdisp->vblank.put = nouveau_display_vblank_put; - drm_mode_config_init(dev); drm_mode_create_scaling_mode_property(dev); drm_mode_create_dvi_i_properties(dev); @@ -316,21 +450,17 @@ nouveau_display_create(struct drm_device *dev) drm_property_create_range(dev, 0, "underscan vborder", 0, 128); if (gen >= 1) { + /* -90..+90 */ disp->vibrant_hue_property = - drm_property_create(dev, DRM_MODE_PROP_RANGE, - "vibrant hue", 2); - disp->vibrant_hue_property->values[0] = 0; - disp->vibrant_hue_property->values[1] = 180; /* -90..+90 */ + drm_property_create_range(dev, 0, "vibrant hue", 0, 180); + /* -100..+100 */ disp->color_vibrance_property = - drm_property_create(dev, DRM_MODE_PROP_RANGE, - "color vibrance", 2); - disp->color_vibrance_property->values[0] = 0; - disp->color_vibrance_property->values[1] = 200; /* -100..+100 */ + drm_property_create_range(dev, 0, "color vibrance", 0, 200); } dev->mode_config.funcs = &nouveau_mode_config_funcs; - dev->mode_config.fb_base = pci_resource_start(dev->pdev, 1); + dev->mode_config.fb_base = nv_device_resource_start(device, 1); dev->mode_config.min_width = 0; dev->mode_config.min_height = 0; @@ -349,27 +479,55 @@ nouveau_display_create(struct drm_device *dev) dev->mode_config.preferred_depth = 24; dev->mode_config.prefer_shadow = 1; + if (nv_device(drm->device)->chipset < 0x11) + dev->mode_config.async_page_flip = false; + else + dev->mode_config.async_page_flip = true; + drm_kms_helper_poll_init(dev); drm_kms_helper_poll_disable(dev); - if (nouveau_modeset == 1 || - (nouveau_modeset < 0 && pclass == PCI_CLASS_DISPLAY_VGA)) { - if (nv_device(drm->device)->card_type < NV_50) - ret = nv04_display_create(dev); - else - ret = nv50_display_create(dev); - if (ret) - goto disp_create_err; + if (drm->vbios.dcb.entries) { + static const u16 oclass[] = { + GM107_DISP_CLASS, + NVF0_DISP_CLASS, + NVE0_DISP_CLASS, + NVD0_DISP_CLASS, + NVA3_DISP_CLASS, + NV94_DISP_CLASS, + NVA0_DISP_CLASS, + NV84_DISP_CLASS, + NV50_DISP_CLASS, + NV04_DISP_CLASS, + }; + int i; + + for (i = 0, ret = -ENODEV; ret && i < ARRAY_SIZE(oclass); i++) { + ret = nouveau_object_new(nv_object(drm), NVDRM_DEVICE, + NVDRM_DISPLAY, oclass[i], + NULL, 0, &disp->core); + } - if (dev->mode_config.num_crtc) { - ret = drm_vblank_init(dev, dev->mode_config.num_crtc); - if (ret) - goto vblank_err; + if (ret == 0) { + if (nv_mclass(disp->core) < NV50_DISP_CLASS) + ret = nv04_display_create(dev); + else + ret = nv50_display_create(dev); } + } else { + ret = 0; + } + + if (ret) + goto disp_create_err; - nouveau_backlight_init(dev); + if (dev->mode_config.num_crtc) { + ret = nouveau_display_vblank_init(dev); + if (ret) + goto vblank_err; } + nouveau_backlight_init(dev); return 0; vblank_err: @@ -384,9 +542,10 @@ void nouveau_display_destroy(struct drm_device *dev) { struct nouveau_display *disp = nouveau_display(dev); + struct nouveau_drm *drm = nouveau_drm(dev); nouveau_backlight_exit(dev); - drm_vblank_cleanup(dev); + nouveau_display_vblank_fini(dev); drm_kms_helper_poll_fini(dev); drm_mode_config_cleanup(dev); @@ -394,6 +553,8 @@ nouveau_display_destroy(struct drm_device *dev) if (disp->dtor) disp->dtor(dev); + nouveau_object_del(nv_object(drm), NVDRM_DEVICE, NVDRM_DISPLAY); + nouveau_drm(dev)->display = NULL; kfree(disp); } @@ -410,7 +571,7 @@ nouveau_display_suspend(struct drm_device *dev) list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct nouveau_framebuffer *nouveau_fb; - nouveau_fb = nouveau_framebuffer(crtc->fb); + nouveau_fb = nouveau_framebuffer(crtc->primary->fb); if (!nouveau_fb || !nouveau_fb->nvbo) continue; @@ -428,7 +589,7 @@ nouveau_display_suspend(struct drm_device *dev) } void -nouveau_display_resume(struct drm_device *dev) +nouveau_display_repin(struct drm_device *dev) { struct nouveau_drm *drm = nouveau_drm(dev); struct drm_crtc *crtc; @@ -437,7 +598,7 @@ nouveau_display_resume(struct drm_device *dev) list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct nouveau_framebuffer *nouveau_fb; - nouveau_fb = nouveau_framebuffer(crtc->fb); + nouveau_fb = nouveau_framebuffer(crtc->primary->fb); if (!nouveau_fb || !nouveau_fb->nvbo) continue; @@ -453,10 +614,12 @@ nouveau_display_resume(struct drm_device *dev) if (ret) NV_ERROR(drm, "Could not pin/map cursor.\n"); } +} - nouveau_fbcon_set_suspend(dev, 0); - nouveau_fbcon_zfill_all(dev); - +void +nouveau_display_resume(struct drm_device *dev) +{ + struct drm_crtc *crtc; nouveau_display_init(dev); /* Force CLUT to get re-loaded during modeset */ @@ -478,84 +641,6 @@ nouveau_display_resume(struct drm_device *dev) } } -int -nouveau_vblank_enable(struct drm_device *dev, int crtc) -{ - struct nouveau_device *device = nouveau_dev(dev); - - if (device->card_type >= NV_D0) - nv_mask(device, 0x6100c0 + (crtc * 0x800), 1, 1); - else - if (device->card_type >= NV_50) - nv_mask(device, NV50_PDISPLAY_INTR_EN_1, 0, - NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(crtc)); - else - NVWriteCRTC(dev, crtc, NV_PCRTC_INTR_EN_0, - NV_PCRTC_INTR_0_VBLANK); - - return 0; -} - -void -nouveau_vblank_disable(struct drm_device *dev, int crtc) -{ - struct nouveau_device *device = nouveau_dev(dev); - - if (device->card_type >= NV_D0) - nv_mask(device, 0x6100c0 + (crtc * 0x800), 1, 0); - else - if (device->card_type >= NV_50) - nv_mask(device, NV50_PDISPLAY_INTR_EN_1, - NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(crtc), 0); - else - NVWriteCRTC(dev, crtc, NV_PCRTC_INTR_EN_0, 0); -} - -static int -nouveau_page_flip_reserve(struct nouveau_bo *old_bo, - struct nouveau_bo *new_bo) -{ - int ret; - - ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM); - if (ret) - return ret; - - ret = ttm_bo_reserve(&new_bo->bo, false, false, false, 0); - if (ret) - goto fail; - - if (likely(old_bo != new_bo)) { - ret = ttm_bo_reserve(&old_bo->bo, false, false, false, 0); - if (ret) - goto fail_unreserve; - } - - return 0; - -fail_unreserve: - ttm_bo_unreserve(&new_bo->bo); -fail: - nouveau_bo_unpin(new_bo); - return ret; -} - -static void -nouveau_page_flip_unreserve(struct nouveau_bo *old_bo, - struct nouveau_bo *new_bo, - struct nouveau_fence *fence) -{ - nouveau_bo_fence(new_bo, fence); - ttm_bo_unreserve(&new_bo->bo); - - if (likely(old_bo != new_bo)) { - nouveau_bo_fence(old_bo, fence); - ttm_bo_unreserve(&old_bo->bo); - } - - nouveau_bo_unpin(old_bo); -} - static int nouveau_page_flip_emit(struct nouveau_channel *chan, struct nouveau_bo *old_bo, @@ -580,22 +665,18 @@ nouveau_page_flip_emit(struct nouveau_channel *chan, goto fail; /* Emit the pageflip */ - ret = RING_SPACE(chan, 3); + ret = RING_SPACE(chan, 2); if (ret) goto fail; - if (nv_device(drm->device)->card_type < NV_C0) { + if (nv_device(drm->device)->card_type < NV_C0) BEGIN_NV04(chan, NvSubSw, NV_SW_PAGE_FLIP, 1); - OUT_RING (chan, 0x00000000); - OUT_RING (chan, 0x00000000); - } else { - BEGIN_NVC0(chan, 0, NV10_SUBCHAN_REF_CNT, 1); - OUT_RING (chan, 0); - BEGIN_IMC0(chan, 0, NVSW_SUBCHAN_PAGE_FLIP, 0x0000); - } + else + BEGIN_NVC0(chan, FermiSw, NV_SW_PAGE_FLIP, 1); + OUT_RING (chan, 0x00000000); FIRE_RING (chan); - ret = nouveau_fence_new(chan, pfence); + ret = nouveau_fence_new(chan, false, pfence); if (ret) goto fail; @@ -609,14 +690,15 @@ fail: int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, - struct drm_pending_vblank_event *event) + struct drm_pending_vblank_event *event, u32 flags) { + 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->fb)->nvbo; + 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 = NULL; + struct nouveau_channel *chan = drm->channel; struct nouveau_fence *fence; int ret; @@ -627,10 +709,26 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, if (!s) return -ENOMEM; - /* Don't let the buffers go away while we flip */ - ret = nouveau_page_flip_reserve(old_bo, new_bo); + if (new_bo != old_bo) { + ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM); + if (ret) + goto fail_free; + } + + mutex_lock(&chan->cli->mutex); + + /* synchronise rendering channel with the kernel's channel */ + spin_lock(&new_bo->bo.bdev->fence_lock); + fence = nouveau_fence_ref(new_bo->bo.sync_obj); + spin_unlock(&new_bo->bo.bdev->fence_lock); + ret = nouveau_fence_sync(fence, chan); + nouveau_fence_unref(&fence); + if (ret) + goto fail_unpin; + + ret = ttm_bo_reserve(&old_bo->bo, true, false, false, NULL); if (ret) - goto fail_free; + goto fail_unpin; /* Initialize a page flip struct */ *s = (struct nouveau_page_flip_state) @@ -638,37 +736,58 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, fb->bits_per_pixel, fb->pitches[0], crtc->x, crtc->y, new_bo->bo.offset }; - /* Choose the channel the flip will be handled in */ - fence = new_bo->bo.sync_obj; - if (fence) - chan = fence->channel; - if (!chan) - chan = drm->channel; - mutex_lock(&chan->cli->mutex); + /* Keep vblanks on during flip, for the target crtc of this flip */ + drm_vblank_get(dev, nouveau_crtc(crtc)->index); /* Emit a page flip */ if (nv_device(drm->device)->card_type >= NV_50) { - ret = nv50_display_flip_next(crtc, fb, chan, 0); - if (ret) { - mutex_unlock(&chan->cli->mutex); + ret = nv50_display_flip_next(crtc, fb, chan, swap_interval); + if (ret) goto fail_unreserve; + } else { + struct nv04_display *dispnv04 = nv04_display(dev); + int head = nouveau_crtc(crtc)->index; + + 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); - mutex_unlock(&chan->cli->mutex); if (ret) goto fail_unreserve; + mutex_unlock(&chan->cli->mutex); /* Update the crtc struct and cleanup */ - crtc->fb = fb; + crtc->primary->fb = fb; - nouveau_page_flip_unreserve(old_bo, new_bo, fence); + nouveau_bo_fence(old_bo, fence); + ttm_bo_unreserve(&old_bo->bo); + if (old_bo != new_bo) + nouveau_bo_unpin(old_bo); nouveau_fence_unref(&fence); return 0; fail_unreserve: - nouveau_page_flip_unreserve(old_bo, new_bo, NULL); + drm_vblank_put(dev, nouveau_crtc(crtc)->index); + ttm_bo_unreserve(&old_bo->bo); +fail_unpin: + mutex_unlock(&chan->cli->mutex); + if (old_bo != new_bo) + nouveau_bo_unpin(new_bo); fail_free: kfree(s); return ret; @@ -683,6 +802,7 @@ nouveau_finish_page_flip(struct nouveau_channel *chan, struct drm_device *dev = drm->dev; struct nouveau_page_flip_state *s; unsigned long flags; + int crtcid = -1; spin_lock_irqsave(&dev->event_lock, flags); @@ -694,17 +814,16 @@ nouveau_finish_page_flip(struct nouveau_channel *chan, s = list_first_entry(&fctx->flip, struct nouveau_page_flip_state, head); if (s->event) { - struct drm_pending_vblank_event *e = s->event; - struct timeval now; - - do_gettimeofday(&now); - e->event.sequence = 0; - e->event.tv_sec = now.tv_sec; - e->event.tv_usec = now.tv_usec; - list_add_tail(&e->base.link, &e->base.file_priv->event_list); - wake_up_interruptible(&e->base.file_priv->event_wait); + /* Vblank timestamps/counts are only correct on >= NV-50 */ + if (nv_device(drm->device)->card_type >= NV_50) + crtcid = s->crtc; + + drm_send_vblank_event(dev, crtcid, s->event); } + /* Give up ownership of vblank for page-flipped crtc */ + drm_vblank_put(dev, s->crtc); + list_del(&s->head); if (ps) *ps = *s; @@ -747,19 +866,12 @@ nouveau_display_dumb_create(struct drm_file *file_priv, struct drm_device *dev, if (ret) return ret; - ret = drm_gem_handle_create(file_priv, bo->gem, &args->handle); - drm_gem_object_unreference_unlocked(bo->gem); + ret = drm_gem_handle_create(file_priv, &bo->gem, &args->handle); + drm_gem_object_unreference_unlocked(&bo->gem); return ret; } int -nouveau_display_dumb_destroy(struct drm_file *file_priv, struct drm_device *dev, - uint32_t handle) -{ - return drm_gem_handle_delete(file_priv, handle); -} - -int nouveau_display_dumb_map_offset(struct drm_file *file_priv, struct drm_device *dev, uint32_t handle, uint64_t *poffset) @@ -768,8 +880,8 @@ nouveau_display_dumb_map_offset(struct drm_file *file_priv, gem = drm_gem_object_lookup(dev, file_priv, handle); if (gem) { - struct nouveau_bo *bo = gem->driver_private; - *poffset = bo->bo.addr_space_offset; + struct nouveau_bo *bo = nouveau_gem_object(gem); + *poffset = drm_vma_node_offset_addr(&bo->bo.vma_node); drm_gem_object_unreference_unlocked(gem); return 0; } |
