Re: [PATCH] fbdev: efifb: do not load efifb if PCI BAR has changed but not fixuped
From: Thomas Zimmermann <tzimmermann@suse.de>
Date: 2025-06-27 09:13:13
Also in:
dri-devel, lkml
Hi Am 26.06.25 um 11:49 schrieb oushixiong1025@163.com:
From: Shixiong Ou <redacted> [WHY] On an ARM machine, the following log is present: [ 0.900884] efifb: framebuffer at 0x1020000000, using 3072k, total 3072k [ 2.297884] amdgpu 0000:04:00.0: remove_conflicting_pci_framebuffers: bar 0: 0x1000000000 -> 0x100fffffff [ 2.297886] amdgpu 0000:04:00.0: remove_conflicting_pci_framebuffers: bar 2: 0x1010000000 -> 0x10101fffff [ 2.297888] amdgpu 0000:04:00.0: remove_conflicting_pci_framebuffers: bar 5: 0x58200000 -> 0x5823ffff It show that the efifb framebuffer base is out of PCI BAR, and this results in both efi-framebuffer and amdgpudrmfb co-existing. The fbcon will be bound to efi-framebuffer by default and cannot be used. [HOW] Do not load efifb driver if PCI BAR has changed but not fixuped. In the following cases: 1. screen_info_lfb_pdev is NULL. 2. __screen_info_relocation_is_valid return false.
Apart from ruling out invalid screen_info, did you figure out why the relocation tracking didn't work? It would be good to fix this if possible. Best regards Thomas
quoted hunk ↗ jump to hunk
Signed-off-by: Shixiong Ou <redacted> --- drivers/video/fbdev/efifb.c | 4 ++++ drivers/video/screen_info_pci.c | 24 ++++++++++++++++++++++++ include/linux/screen_info.h | 5 +++++ 3 files changed, 33 insertions(+)diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c index 0e1bd3dba255..de8d016c9a66 100644 --- a/drivers/video/fbdev/efifb.c +++ b/drivers/video/fbdev/efifb.c@@ -303,6 +303,10 @@ static void efifb_setup(struct screen_info *si, char *options) static inline bool fb_base_is_valid(struct screen_info *si) { + /* check whether fb_base has changed but not fixuped */ + if (!screen_info_is_useful()) + return false; + if (si->lfb_base) return true;diff --git a/drivers/video/screen_info_pci.c b/drivers/video/screen_info_pci.c index 66bfc1d0a6dc..ac57dcaf0cac 100644 --- a/drivers/video/screen_info_pci.c +++ b/drivers/video/screen_info_pci.c@@ -9,6 +9,8 @@ static struct pci_dev *screen_info_lfb_pdev; static size_t screen_info_lfb_bar; static resource_size_t screen_info_lfb_res_start; // original start of resource static resource_size_t screen_info_lfb_offset; // framebuffer offset within resource +static bool screen_info_changed; +static bool screen_info_fixuped; static bool __screen_info_relocation_is_valid(const struct screen_info *si, struct resource *pr) {@@ -24,6 +26,24 @@ static bool __screen_info_relocation_is_valid(const struct screen_info *si, stru return true; } +bool screen_info_is_useful(void) +{ + unsigned int type; + const struct screen_info *si = &screen_info; + + type = screen_info_video_type(si); + if (type != VIDEO_TYPE_EFI) + return true; + + if (screen_info_changed && !screen_info_fixuped) { + pr_warn("The screen_info has changed but not fixuped"); + return false; + } + + pr_info("The screen_info is useful"); + return true; +} + void screen_info_apply_fixups(void) { struct screen_info *si = &screen_info;@@ -32,18 +52,22 @@ void screen_info_apply_fixups(void) struct resource *pr = &screen_info_lfb_pdev->resource[screen_info_lfb_bar]; if (pr->start != screen_info_lfb_res_start) { + screen_info_changed = true; if (__screen_info_relocation_is_valid(si, pr)) { /* * Only update base if we have an actual * relocation to a valid I/O range. */ __screen_info_set_lfb_base(si, pr->start + screen_info_lfb_offset); + screen_info_fixuped = true; pr_info("Relocating firmware framebuffer to offset %pa[d] within %pr\n", &screen_info_lfb_offset, pr); } else { pr_warn("Invalid relocating, disabling firmware framebuffer\n"); } } + } else { + screen_info_changed = true; } }diff --git a/include/linux/screen_info.h b/include/linux/screen_info.h index 923d68e07679..632cdbb1adbe 100644 --- a/include/linux/screen_info.h +++ b/include/linux/screen_info.h@@ -138,9 +138,14 @@ ssize_t screen_info_resources(const struct screen_info *si, struct resource *r, u32 __screen_info_lfb_bits_per_pixel(const struct screen_info *si); #if defined(CONFIG_PCI) +bool screen_info_is_useful(void); void screen_info_apply_fixups(void); struct pci_dev *screen_info_pci_dev(const struct screen_info *si); #else +bool screen_info_is_useful(void) +{ + return true; +} static inline void screen_info_apply_fixups(void) { } static inline struct pci_dev *screen_info_pci_dev(const struct screen_info *si)
-- -- Thomas Zimmermann Graphics Driver Developer SUSE Software Solutions Germany GmbH Frankenstrasse 146, 90461 Nuernberg, Germany GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman HRB 36809 (AG Nuernberg)