From 6f5bcd4446d9ea508040e1bbca3a70b45477264e Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Tue, 5 Nov 2024 14:29:08 +0100 Subject: [PATCH] intel/display: check for mappable framebuffer The driver code may allocate framebuffers which do not fit in the aperture. Trying to use such framebuffer may lead to only partial visible content on the screen and the rest either black or garbage. Instead check for this circumstance and deny to use such framebuffers and release them, since the user would get an unusable/hard to interpret state. Additionally, release the vma mappings earlier in order to reduce the likelihood of such un-mappable framebuffers. Issue #5377 --- .../src/driver/framebuffer/intel/pc/lx_user.c | 68 ++++++++++++++++--- 1 file changed, 60 insertions(+), 8 deletions(-) diff --git a/repos/pc/src/driver/framebuffer/intel/pc/lx_user.c b/repos/pc/src/driver/framebuffer/intel/pc/lx_user.c index 75ec819a0d..9e1ba48b94 100644 --- a/repos/pc/src/driver/framebuffer/intel/pc/lx_user.c +++ b/repos/pc/src/driver/framebuffer/intel/pc/lx_user.c @@ -385,6 +385,41 @@ static int kernel_register_fb(struct fb_info const * const fb_info, } +static void destroy_fb_and_capture(struct drm_client_dev * const dev, + struct drm_connector const * const connector, + struct drm_framebuffer * const fb) +{ + struct drm_mode_create_dumb * dumb_create = NULL; + struct drm_mode_fb_cmd2 * fb_cmd = NULL; + struct gem_dumb * gem_dumb = NULL; + struct fb_info info = {}; + + if (!fb) + return; + + if (!dumb_meta(dev, fb, &dumb_create, &fb_cmd)) + return; + + if (!dumb_gem(dev, fb, &gem_dumb)) + return; + + info.var.bits_per_pixel = 32; + info.node = connector->index; + info.par = connector->name; + + kernel_register_fb(&info, 0, 0); + + if (gem_dumb->vma) { + intel_unpin_fb_vma(gem_dumb->vma, gem_dumb->flags); + + gem_dumb->vma = NULL; + gem_dumb->flags = 0; + } + + destroy_fb(dev, dumb_create, fb_cmd); +} + + struct drm_mode_fb_cmd2 fb_of_screen(struct drm_client_dev * const dev, struct genode_mode const * const conf_mode, struct fb_info * const fb_info, @@ -413,15 +448,9 @@ struct drm_mode_fb_cmd2 fb_of_screen(struct drm_client_dev * const dev, /* notify genode side about switch from connector specific fb to mirror fb */ if (fb && conf_mode->mirror && fb != fb_mirror) { - struct fb_info info = {}; - info.var.bits_per_pixel = 32; - info.node = connector->index; - info.par = connector->name; + destroy_fb_and_capture(dev, connector, fb); - kernel_register_fb(&info, mode->width_mm, mode->height_mm); - - destroy_fb(dev, gem_dumb, fb_cmd); } if (fb_mirror) @@ -771,7 +800,18 @@ static bool reconfigure(struct drm_client_dev * const dev) unsigned width_mm = mode->width_mm ? : connector->display_info.width_mm; unsigned height_mm = mode->height_mm ? : connector->display_info.height_mm; - user_register_fb(dev, &fb_info, &fb_cmd, width_mm, height_mm); + int err = user_register_fb(dev, &fb_info, &fb_cmd, width_mm, height_mm); + + if (err == -ENOSPC) { + + struct drm_framebuffer *fb = drm_framebuffer_lookup(dev->dev, + dev->file, + fb_cmd.fb_id); + if (fb) + drm_framebuffer_put(fb); + + destroy_fb_and_capture(dev, connector, fb); + } } break; @@ -1354,6 +1394,18 @@ static int user_register_fb(struct drm_client_dev const * const dev, return result; } + if (!i915_vma_is_map_and_fenceable(gem_dumb->vma)) { + printk("%s: framebuffer not mappable in aperture -> destroying framebuffer\n", + (info && info->par) ? (char *)info->par : "unknown"); + + intel_unpin_fb_vma(gem_dumb->vma, gem_dumb->flags); + + gem_dumb->vma = NULL; + gem_dumb->flags = 0; + + return -ENOSPC; + } + vaddr = i915_vma_pin_iomap(gem_dumb->vma); if (IS_ERR(vaddr)) { intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref);