From 21fbd085e62ff9a11318f5a9aba55e56e8503173 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 26 Apr 2018 09:48:55 +0200 Subject: [PATCH 1/5] drm/vmwgfx: Clean up fbdev modeset locking At least since the atomic port, the vmwgfx fbdev code is taking a number of unnecessary modeset locks. In particular the kms_set_config() function will grab its own locks, leading to locking retries. So avoid drm_modeset_lock_all() and instead provide a local acquire context for kms_set_config(). Also have the vmw_kms_fbdev_init data itself grab the lock that it needs. This also fixed a long standing problem that vmw_fb_close() didn't provide an acquire context for kms_set_config(), causing potential warnings and hangs during driver unload. This problem was uncovered by the recent commit "drm/vmwgfx: Improve on hibernation" Testing done: Repeated driver load and unload on Ubuntu 16.04.2 Fixes: c3b9b1657344 ("drm/vmwgfx: Improve on hibernation") Signed-off-by: Thomas Hellstrom Reviewed-by: Deepak Rawat Reviewed-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 31 ++++++++++------------------- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 13 +++++++++--- 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index 2582ffd36bb5..ba0cdb743c3e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -441,11 +441,11 @@ static int vmwgfx_set_config_internal(struct drm_mode_set *set) struct drm_crtc *crtc = set->crtc; struct drm_framebuffer *fb; struct drm_crtc *tmp; - struct drm_modeset_acquire_ctx *ctx; struct drm_device *dev = set->crtc->dev; + struct drm_modeset_acquire_ctx ctx; int ret; - ctx = dev->mode_config.acquire_ctx; + drm_modeset_acquire_init(&ctx, 0); restart: /* @@ -458,7 +458,7 @@ restart: fb = set->fb; - ret = crtc->funcs->set_config(set, ctx); + ret = crtc->funcs->set_config(set, &ctx); if (ret == 0) { crtc->primary->crtc = crtc; crtc->primary->fb = fb; @@ -473,20 +473,13 @@ restart: } if (ret == -EDEADLK) { - dev->mode_config.acquire_ctx = NULL; - -retry_locking: - drm_modeset_backoff(ctx); - - ret = drm_modeset_lock_all_ctx(dev, ctx); - if (ret) - goto retry_locking; - - dev->mode_config.acquire_ctx = ctx; - + drm_modeset_backoff(&ctx); goto restart; } + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + return ret; } @@ -624,7 +617,6 @@ static int vmw_fb_set_par(struct fb_info *info) } mutex_lock(&par->bo_mutex); - drm_modeset_lock_all(vmw_priv->dev); ret = vmw_fb_kms_framebuffer(info); if (ret) goto out_unlock; @@ -657,7 +649,6 @@ out_unlock: drm_mode_destroy(vmw_priv->dev, old_mode); par->set_mode = mode; - drm_modeset_unlock_all(vmw_priv->dev); mutex_unlock(&par->bo_mutex); return ret; @@ -713,18 +704,14 @@ int vmw_fb_init(struct vmw_private *vmw_priv) par->max_width = fb_width; par->max_height = fb_height; - drm_modeset_lock_all(vmw_priv->dev); ret = vmw_kms_fbdev_init_data(vmw_priv, 0, par->max_width, par->max_height, &par->con, &par->crtc, &init_mode); - if (ret) { - drm_modeset_unlock_all(vmw_priv->dev); + if (ret) goto err_kms; - } info->var.xres = init_mode->hdisplay; info->var.yres = init_mode->vdisplay; - drm_modeset_unlock_all(vmw_priv->dev); /* * Create buffers and alloc memory @@ -832,7 +819,9 @@ int vmw_fb_close(struct vmw_private *vmw_priv) cancel_delayed_work_sync(&par->local_work); unregister_framebuffer(info); + mutex_lock(&par->bo_mutex); (void) vmw_fb_kms_detach(par, true, true); + mutex_unlock(&par->bo_mutex); vfree(par->vmalloc); framebuffer_release(info); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index f11601b6fd74..aacc9307ab0b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -2680,7 +2680,9 @@ int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv, struct vmw_display_unit *du; struct drm_display_mode *mode; int i = 0; + int ret = 0; + mutex_lock(&dev_priv->dev->mode_config.mutex); list_for_each_entry(con, &dev_priv->dev->mode_config.connector_list, head) { if (i == unit) @@ -2691,7 +2693,8 @@ int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv, if (i != unit) { DRM_ERROR("Could not find initial display unit.\n"); - return -EINVAL; + ret = -EINVAL; + goto out_unlock; } if (list_empty(&con->modes)) @@ -2699,7 +2702,8 @@ int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv, if (list_empty(&con->modes)) { DRM_ERROR("Could not find initial display mode.\n"); - return -EINVAL; + ret = -EINVAL; + goto out_unlock; } du = vmw_connector_to_du(con); @@ -2720,7 +2724,10 @@ int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv, head); } - return 0; + out_unlock: + mutex_unlock(&dev_priv->dev->mode_config.mutex); + + return ret; } /** From 13f149d47392782baafd96d54d4e65f3b5ca342f Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 26 Apr 2018 09:59:30 +0200 Subject: [PATCH 2/5] drm/vmwgfx: Fix a buffer object leak A buffer object leak was introduced when fixing a premature buffer object release. Fix this. Cc: Fixes: 73a88250b709 ("Fix a destoy-while-held mutex problem.") Signed-off-by: Thomas Hellstrom Reviewed-by: Deepak Rawat Reviewed-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index aacc9307ab0b..96fd7a03d2f8 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -2595,6 +2595,7 @@ void vmw_kms_helper_resource_finish(struct vmw_validation_ctx *ctx, vmw_kms_helper_buffer_finish(res->dev_priv, NULL, ctx->buf, out_fence, NULL); + vmw_dmabuf_unreference(&ctx->buf); vmw_resource_unreserve(res, false, NULL, 0); mutex_unlock(&res->dev_priv->cmdbuf_mutex); } From b607990c76ceda0a7a7ceacabab174cdc8b9beee Mon Sep 17 00:00:00 2001 From: Ian W MORRISON Date: Wed, 11 Apr 2018 14:42:13 +1000 Subject: [PATCH 3/5] drm/i915/glk: Add MODULE_FIRMWARE for Geminilake As the Geminilake firmware is now merged to linux-firmware.git use MODUE_FIRMWARE to load the firmware. This removes the error message in the dmesg log: i915 0000:00:02.0: Direct firmware load for i915/glk_dmc_ver1_04.bin failed with error -2 i915 0000:00:02.0: Failed to load DMC firmware i915/glk_dmc_ver1_04.bin. Disabling runtime power management. i915 0000:00:02.0: DMC firmware homepage: https://01.org/linuxgraphics/downloads/firmware and now shows that the firmware has correctly loaded: [drm] Finished loading DMC firmware i915/glk_dmc_ver1_04.bin (v1.4) Signed-off-by: Ian W MORRISON Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20180411044213.383-1-ianwmorrison@gmail.com (cherry picked from commit f6d3e06f074721ad3a231df745d85b60428c1f03) Signed-off-by: Joonas Lahtinen --- drivers/gpu/drm/i915/intel_csr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c index 41e6c75a7f3c..f9550ea46c26 100644 --- a/drivers/gpu/drm/i915/intel_csr.c +++ b/drivers/gpu/drm/i915/intel_csr.c @@ -35,6 +35,7 @@ */ #define I915_CSR_GLK "i915/glk_dmc_ver1_04.bin" +MODULE_FIRMWARE(I915_CSR_GLK); #define GLK_CSR_VERSION_REQUIRED CSR_VERSION(1, 4) #define I915_CSR_CNL "i915/cnl_dmc_ver1_07.bin" From f7aef1c207092770d06d0df21dceafdca2b49c39 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 30 Apr 2018 15:32:32 +0200 Subject: [PATCH 4/5] drm/vc4: Make sure vc4_bo_{inc,dec}_usecnt() calls are balanced Commit b9f19259b84d ("drm/vc4: Add the DRM_IOCTL_VC4_GEM_MADVISE ioctl") introduced a mechanism to mark some BOs as purgeable to allow the driver to drop them under memory pressure. In order to implement this feature we had to add a mechanism to mark BOs as currently used by a piece of hardware which materialized through the ->usecnt counter. Plane code is supposed to increment usecnt when it attaches a BO to a plane and decrement it when it's done with this BO, which was done in the ->prepare_fb() and ->cleanup_fb() hooks. The problem is, async page flip logic does not go through the regular atomic update path, and ->prepare_fb() and ->cleanup_fb() are not called in this case. Fix that by manually calling vc4_bo_{inc,dec}_usecnt() in the async-page-flip path. Note that all this should go away as soon as we get generic async page flip support in the core, in the meantime, this fix should do the trick. Fixes: b9f19259b84d ("drm/vc4: Add the DRM_IOCTL_VC4_GEM_MADVISE ioctl") Reported-by: Peter Robinson Cc: Signed-off-by: Boris Brezillon Signed-off-by: Eric Anholt Link: https://patchwork.freedesktop.org/patch/msgid/20180430133232.32457-1-boris.brezillon@bootlin.com Link: https://patchwork.freedesktop.org/patch/msgid/20180430133232.32457-1-boris.brezillon@bootlin.com --- drivers/gpu/drm/vc4/vc4_crtc.c | 46 +++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index bf4667481935..c61dff594195 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -760,6 +760,7 @@ static irqreturn_t vc4_crtc_irq_handler(int irq, void *data) struct vc4_async_flip_state { struct drm_crtc *crtc; struct drm_framebuffer *fb; + struct drm_framebuffer *old_fb; struct drm_pending_vblank_event *event; struct vc4_seqno_cb cb; @@ -789,6 +790,23 @@ vc4_async_page_flip_complete(struct vc4_seqno_cb *cb) drm_crtc_vblank_put(crtc); drm_framebuffer_put(flip_state->fb); + + /* Decrement the BO usecnt in order to keep the inc/dec calls balanced + * when the planes are updated through the async update path. + * FIXME: we should move to generic async-page-flip when it's + * available, so that we can get rid of this hand-made cleanup_fb() + * logic. + */ + if (flip_state->old_fb) { + struct drm_gem_cma_object *cma_bo; + struct vc4_bo *bo; + + cma_bo = drm_fb_cma_get_gem_obj(flip_state->old_fb, 0); + bo = to_vc4_bo(&cma_bo->base); + vc4_bo_dec_usecnt(bo); + drm_framebuffer_put(flip_state->old_fb); + } + kfree(flip_state); up(&vc4->async_modeset); @@ -813,9 +831,22 @@ static int vc4_async_page_flip(struct drm_crtc *crtc, struct drm_gem_cma_object *cma_bo = drm_fb_cma_get_gem_obj(fb, 0); struct vc4_bo *bo = to_vc4_bo(&cma_bo->base); + /* Increment the BO usecnt here, so that we never end up with an + * unbalanced number of vc4_bo_{dec,inc}_usecnt() calls when the + * plane is later updated through the non-async path. + * FIXME: we should move to generic async-page-flip when it's + * available, so that we can get rid of this hand-made prepare_fb() + * logic. + */ + ret = vc4_bo_inc_usecnt(bo); + if (ret) + return ret; + flip_state = kzalloc(sizeof(*flip_state), GFP_KERNEL); - if (!flip_state) + if (!flip_state) { + vc4_bo_dec_usecnt(bo); return -ENOMEM; + } drm_framebuffer_get(fb); flip_state->fb = fb; @@ -826,10 +857,23 @@ static int vc4_async_page_flip(struct drm_crtc *crtc, ret = down_interruptible(&vc4->async_modeset); if (ret) { drm_framebuffer_put(fb); + vc4_bo_dec_usecnt(bo); kfree(flip_state); return ret; } + /* Save the current FB before it's replaced by the new one in + * drm_atomic_set_fb_for_plane(). We'll need the old FB in + * vc4_async_page_flip_complete() to decrement the BO usecnt and keep + * it consistent. + * FIXME: we should move to generic async-page-flip when it's + * available, so that we can get rid of this hand-made cleanup_fb() + * logic. + */ + flip_state->old_fb = plane->state->fb; + if (flip_state->old_fb) + drm_framebuffer_get(flip_state->old_fb); + WARN_ON(drm_crtc_vblank_get(crtc) != 0); /* Immediately update the plane's legacy fb pointer, so that later From 49ceda9de2da4d1827941d06701f3017c27c1855 Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Fri, 20 Apr 2018 14:59:59 -0400 Subject: [PATCH 5/5] drm/bridge: vga-dac: Fix edid memory leak edid should be freed once it's finished being used. Fixes: 56fe8b6f4991 ("drm/bridge: Add RGB to VGA bridge support") Cc: Rob Herring Cc: Sean Paul Cc: Maxime Ripard Cc: Archit Taneja Cc: Andrzej Hajda Cc: Laurent Pinchart Cc: # v4.9+ Reviewed-by: Maxime Ripard Reviewed-by: Laurent Pinchart Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20180420190007.1572-1-seanpaul@chromium.org --- drivers/gpu/drm/bridge/dumb-vga-dac.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/dumb-vga-dac.c b/drivers/gpu/drm/bridge/dumb-vga-dac.c index 498d5948d1a8..9837c8d69e69 100644 --- a/drivers/gpu/drm/bridge/dumb-vga-dac.c +++ b/drivers/gpu/drm/bridge/dumb-vga-dac.c @@ -56,7 +56,9 @@ static int dumb_vga_get_modes(struct drm_connector *connector) } drm_mode_connector_update_edid_property(connector, edid); - return drm_add_edid_modes(connector, edid); + ret = drm_add_edid_modes(connector, edid); + kfree(edid); + return ret; fallback: /*