From: sashiko-bot@kernel.org
To: "Maarten Lankhorst" <dev@lankhorst.se>, intel-xe@lists.freedesktop.org
Subject: Re: [PATCH v4 5/5] drm/i915: Introduce intel_bo_fbdev_bios_fb_takeover()
Date: Thu, 05 Nov 2026 17:04:13 +0000 [thread overview]
Message-ID: <sashiko-outbox-199572@kernel.org> (raw)
In-Reply-To: <20261105161444.593259-12-dev@lankhorst.se>
Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
- [High] drm/xe/display: unchecked drm_exec_lock_obj() in bios fb takeover
- [High] drm/xe: invalid XE_PPGTT_PTE_DM bit for stolen memory in xe_migrate_copy()
- [High] drm/xe: missing fence put and wait in xe_display_bo_fbdev_bios_fb_takeover()
- [Medium] drm/xe/display: dma_fence leak in xe_display_bo_fbdev_bios_fb_takeover()
- [Medium] drm/xe: unconditional return false in xe_display_bo_fbdev_prefer_stolen()
- [Medium] drm/i915/fbdev: missing runtime PM ref around bios_fb_pick()
- [Low] drm/i915/fbdev: unused parameters in __intel_fbdev_fb_alloc() and realloc
--
commit 1492b8e8d567ba63a9e11c639a3b16b1f1bc88dc
Author: Maarten Lankhorst <dev@lankhorst.se>
drm/i915: Introduce intel_bo_fbdev_bios_fb_takeover()
This commit introduces the intel_bo_fbdev_bios_fb_takeover() helper to
defer the decision of whether to keep a stolen-memory BIOS framebuffer
until fbdev probe time. In Xe, when stolen memory is not preferred, it
allocates a system memory buffer object and uses the migration engine to
copy the BIOS framebuffer contents.
> diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c
> index 219ee17de3f68..318b10dcea52c 100644
> --- a/drivers/gpu/drm/i915/display/intel_fbdev.c
> +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c
> @@ -225,11 +225,11 @@ static void intel_fbdev_fill_mode_cmd(struct intel_display *display,
>
> static struct intel_framebuffer *
> __intel_fbdev_fb_alloc(struct intel_display *display,
> - struct drm_fb_helper_surface_size *sizes)
> + struct drm_fb_helper_surface_size *sizes,
> + struct drm_gem_object *obj)
> {
> struct drm_mode_fb_cmd2 mode_cmd = {};
> struct drm_framebuffer *fb;
> - struct drm_gem_object *obj;
> int size;
>
> intel_fbdev_fill_mode_cmd(display, sizes, &mode_cmd);
> @@ -262,32 +262,68 @@ __intel_fbdev_fb_alloc(struct intel_display *display,
>
> }
>
> -static bool bios_fb_ok(const struct intel_framebuffer *fb,
> - const struct drm_fb_helper_surface_size *sizes)
> +static struct intel_framebuffer *
> +__intel_fbdev_fb_realloc(struct intel_display *display,
> + const struct drm_framebuffer *orig_fb,
> + struct drm_gem_object *obj)
> +{
[Severity: Low]
This isn't a bug, but in __intel_fbdev_fb_alloc() the local variable obj
was converted into a function parameter that is passed as NULL by its only
caller in intel_fbdev_driver_fbdev_probe() and immediately overwritten by
obj = intel_bo_fbdev_create(display, size) without being read. Similarly,
the display parameter in __intel_fbdev_fb_realloc() is never used. Could
these unused parameters be dropped?
[ ... ]
> @@ -305,9 +341,19 @@ int intel_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper,
>
> ifbdev->fb = NULL;
>
> - if (fb && !bios_fb_ok(fb, sizes)) {
> - drm_framebuffer_put(&fb->base);
> - fb = NULL;
> + if (fb) {
> + struct intel_framebuffer *bios_fb =
> + bios_fb_pick(fb, sizes);
> +
> + if (IS_ERR(bios_fb)) {
> + drm_dbg_kms(display->drm, "Re-using BIOS fb failed (%pe).", bios_fb);
> + bios_fb = NULL;
> + }
> +
> + if (fb != bios_fb) {
> + drm_framebuffer_put(&fb->base);
> + fb = bios_fb;
> + }
> }
>
> wakeref = intel_display_rpm_get(display);
[Severity: Medium]
Should wakeref = intel_display_rpm_get(display) be acquired before calling
bios_fb_pick(fb, sizes) in intel_fbdev_driver_fbdev_probe()?
Previously, only bios_fb_ok() ran before intel_display_rpm_get(), which was
a software-only check of the framebuffer dimensions and depth/bpp. Now,
bios_fb_pick() calls intel_bo_fbdev_bios_fb_takeover() ->
xe_display_bo_fbdev_bios_fb_takeover(), which calls
xe_bo_create_pin_map_novm() and xe_migrate_copy(). Both paths call
xe_pm_runtime_get_noresume() (via __xe_ggtt_insert_bo_at() and
xe_sched_job_create()) and access hardware (GGTT PTE writes and GPU blit
submission).
If initial fbdev setup is deferred when no outputs are connected (leaving
ifbdev->fb populated while CRTCs are disabled) and
intel_fbdev_driver_fbdev_probe() is later invoked from a hotplug event
after the initial runtime PM reference has been dropped, won't running
bios_fb_pick() before intel_display_rpm_get() trigger a missing outer
runtime PM warning in xe_pm_runtime_get_noresume() and access the device
while runtime-suspended?
[ ... ]
> diff --git a/drivers/gpu/drm/xe/display/xe_display_bo.c b/drivers/gpu/drm/xe/display/xe_display_bo.c
> index d78d893210c4f..188796ae85933 100644
> --- a/drivers/gpu/drm/xe/display/xe_display_bo.c
> +++ b/drivers/gpu/drm/xe/display/xe_display_bo.c
> @@ -120,7 +121,7 @@ static u32 xe_display_bo_fbdev_pitch_align(u32 stride)
> return ALIGN(stride, XE_PAGE_SIZE);
> }
>
> -bool xe_display_bo_fbdev_prefer_stolen(struct xe_device *xe, unsigned int size)
> +static bool xe_display_bo_fbdev_prefer_stolen(struct xe_device *xe, unsigned int size)
> {
> struct ttm_resource_manager *stolen;
>
> @@ -152,6 +153,58 @@ bool xe_display_bo_fbdev_prefer_stolen(struct xe_device *xe, unsigned int size)
> return stolen->size >= (size * 2) >> PAGE_SHIFT;
> }
[Severity: Medium]
In xe_display_bo_fbdev_prefer_stolen(), there is an unconditional
"return false;" right before the stolen size check:
drivers/gpu/drm/xe/display/xe_display_bo.c:xe_display_bo_fbdev_prefer_stolen() {
...
/* machine hang when doing lots of LMEMBAR accesses */
if (XE_DEVICE_WA(xe, 22019338487_display))
return false;
return false;
/*
* If the FB is too big, just don't use it since fbdev is not very
* important and we should probably use that space with FBC or other
* features.
*/
return stolen->size >= (size * 2) >> PAGE_SHIFT;
}
Does that unconditional return false make the stolen->size check dead code
and force xe_display_bo_fbdev_bios_fb_takeover() to always reject stolen
memory and reallocate the BIOS framebuffer into system memory on all
integrated platforms?
> +
> +static struct drm_gem_object *xe_display_bo_fbdev_bios_fb_takeover(struct drm_gem_object *obj)
> +{
> + struct xe_bo *orig_bo = gem_to_xe_bo(obj), *copy_bo;
> + struct xe_device *xe = xe_bo_device(orig_bo);
> + struct xe_validation_ctx ctx;
> + struct drm_exec exec;
> + int err;
> +
> + if (IS_DGFX(xe) ||
> + xe_display_bo_fbdev_prefer_stolen(xe, xe_bo_size(orig_bo)))
> + return obj;
> +
> + copy_bo = xe_bo_create_pin_map_novm(xe, xe_device_get_root_tile(xe), xe_bo_size(orig_bo),
> + ttm_bo_type_kernel,
> + XE_BO_FLAG_FORCE_WC | XE_BO_FLAG_SYSTEM | XE_BO_FLAG_GGTT,
> + false);
> + if (IS_ERR(copy_bo))
> + return ERR_CAST(copy_bo);
> +
> + xe_validation_guard(&ctx, &xe->val, &exec, (struct xe_val_flags) {}, err) {
> + struct dma_fence *fence;
> +
> + drm_exec_lock_obj(&exec, &orig_bo->ttm.base);
> + drm_exec_retry_on_contention(&exec);
> +
> + drm_exec_lock_obj(&exec, ©_bo->ttm.base);
> + drm_exec_retry_on_contention(&exec);
[Severity: High]
As reported by Sashiko on v2 [1], in xe_display_bo_fbdev_bios_fb_takeover(),
the return values of both drm_exec_lock_obj() calls are ignored.
If drm_exec_lock_obj() fails with a non-contention error such as -ENOMEM
(for example when kvrealloc() fails in drm_exec_obj_locked()), it unlocks
obj->resv and returns the error without setting exec->contended:
drivers/gpu/drm/drm_exec.c:drm_exec_lock_obj() {
...
ret = drm_exec_obj_locked(exec, obj);
if (ret)
dma_resv_unlock(obj->resv);
return ret;
}
Because exec->contended is NULL, drm_exec_retry_on_contention(&exec) will
not retry, and execution will continue into dma_resv_reserve_fences(),
xe_migrate_copy(), and dma_resv_add_fence() without holding the reservation
lock on orig_bo or copy_bo. Should err = drm_exec_lock_obj(...) be checked
after drm_exec_retry_on_contention(&exec) on both calls?
> +
> + err = dma_resv_reserve_fences(orig_bo->ttm.base.resv, 1);
> + if (err)
> + break;
> +
> + err = dma_resv_reserve_fences(copy_bo->ttm.base.resv, 1);
> + if (err)
> + break;
> +
> + fence = xe_migrate_copy(xe_device_get_root_tile(xe)->migrate, orig_bo, copy_bo,
> + orig_bo->ttm.resource, copy_bo->ttm.resource, false);
[Severity: High]
When xe_display_bo_fbdev_bios_fb_takeover() calls xe_migrate_copy() for an
initial plane BO in stolen memory (XE_PL_STOLEN) on integrated platforms
with GRAPHICS_VERx100(xe) < 1270 (such as Tiger Lake, Rocket Lake, or Alder
Lake), does xe_migrate_copy() program an invalid XE_PPGTT_PTE_DM bit in the
page tables?
In drivers/gpu/drm/xe/xe_migrate.c, __xe_migrate_copy() determines
src_is_vram via is_devmem(), which returns true for all XE_PL_STOLEN
resources:
drivers/gpu/drm/xe/xe_migrate.c:is_devmem() {
if (mem_type_is_vram(res->mem_type) || res->mem_type == XE_PL_STOLEN)
return true;
return false;
}
emit_pte() then unconditionally sets devmem = true when is_vram is true and
passes it to vm->pt_ops->pte_encode_addr(), which sets XE_PPGTT_PTE_DM in
the PTEs. However, stolen memory only uses the DM bit on platforms where
GRAPHICS_VERx100(xe) >= 1270, as seen in xe_bo_is_stolen_devmem():
drivers/gpu/drm/xe/xe_bo.c:xe_bo_is_stolen_devmem() {
return xe_bo_is_stolen(bo) &&
GRAPHICS_VERx100(xe_bo_device(bo)) >= 1270;
}
Won't setting XE_PPGTT_PTE_DM when migrating from stolen memory on pre-12.70
platforms cause GPU page faults or corrupted copies during BIOS framebuffer
takeover?
> + if (IS_ERR(fence)) {
> + err = PTR_ERR(fence);
> + break;
> + }
> +
> + dma_resv_add_fence(copy_bo->ttm.base.resv, fence, DMA_RESV_USAGE_KERNEL);
> + dma_resv_add_fence(orig_bo->ttm.base.resv, fence, DMA_RESV_USAGE_BOOKKEEP);
> + return ©_bo->ttm.base;
> + }
[Severity: Medium]
As reported by Sashiko on v2 [1], does xe_display_bo_fbdev_bios_fb_takeover()
leak the struct dma_fence reference returned by xe_migrate_copy()?
xe_migrate_copy() returns fence with a reference acquired for the caller,
and each call to dma_resv_add_fence() takes its own reference via
dma_fence_get(fence), but dma_fence_put(fence) is never called before
returning ©_bo->ttm.base.
[Severity: High]
As reported by Sashiko on v2 [1], in addition to leaking the fence
reference, could returning copy_bo from xe_display_bo_fbdev_bios_fb_takeover()
without waiting for fence to complete allow CPU accesses to info->screen_base
to race with the in-flight GPU migration blit?
In intel_fbdev_driver_fbdev_probe(), intel_parent_fb_pin_ggtt_pin() ->
__xe_pin_fb_vma() calls xe_bo_validate(), which returns immediately without
waiting on fences because copy_bo was already pinned by
xe_bo_create_pin_map_novm(). Then intel_bo_fbdev_fill_info() exposes
copy_bo->vmap.vaddr_iomem as info->screen_base.
If fb_set_par() is not run immediately during register_framebuffer() (for
example when CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y is active,
CONFIG_FRAMEBUFFER_CONSOLE=n, or when /dev/fb0 is accessed before fbcon_init()
runs), nothing waits on copy_bo's reservation fences before CPU reads or
writes hit info->screen_base. Should xe_display_bo_fbdev_bios_fb_takeover()
wait on the migration fence (or should the caller synchronize) before
exposing screen_base, and drop the caller's fence reference with
dma_fence_put(fence)?
[1] https://lore.kernel.org/r/20260721142610.93804-12-dev@lankhorst.se
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261105161444.593259-7-dev@lankhorst.se?part=5
next prev parent reply other threads:[~2026-11-05 17:04 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-05 16:14 [PATCH v4 0/5] drm/xe/display: Transparant fallback from stolen to sysmem Maarten Lankhorst
2026-11-05 16:14 ` [PATCH v4 1/5] drm/xe/display: Avoid using stolen memory for framebuffer when media gt exists Maarten Lankhorst
2026-11-05 16:14 ` [PATCH v4 2/5] drm/xe/migrate: Support copying between sysmem and stolen Maarten Lankhorst
2026-11-05 16:32 ` sashiko-bot
2026-11-05 16:14 ` [PATCH v4 3/5] drm/xe: Raise gt frequency slightly earlier Maarten Lankhorst
2026-11-05 16:14 ` [PATCH v4 4/5] HACK: Always fallback Maarten Lankhorst
2026-11-05 16:40 ` sashiko-bot
2026-11-05 16:14 ` [PATCH v4 5/5] drm/i915: Introduce intel_bo_fbdev_bios_fb_takeover() Maarten Lankhorst
2026-11-05 17:04 ` sashiko-bot [this message]
2026-11-05 18:12 ` ✗ CI.checkpatch: warning for drm/xe/display: Transparant fallback from stolen to sysmem. (rev4) Patchwork
2026-11-05 18:14 ` ✓ CI.KUnit: success " Patchwork
2026-11-05 18:48 ` ✗ Xe.CI.BAT: failure " Patchwork
2026-11-06 19:21 ` ✗ Xe.CI.FULL: " Patchwork
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=sashiko-outbox-199572@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=dev@lankhorst.se \
--cc=intel-xe@lists.freedesktop.org \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox