From: Thomas Zimmermann <tzimmermann@suse.de>
To: javierm@redhat.com, arnd@arndb.de, ardb@kernel.org,
ilias.apalodimas@linaro.org, chenhuacai@kernel.org,
kernel@xen0n.name, maarten.lankhorst@linux.intel.com,
mripard@kernel.org, airlied@gmail.com, simona@ffwll.ch,
kys@microsoft.com, haiyangz@microsoft.com, wei.liu@kernel.org,
decui@microsoft.com, longli@microsoft.com, deller@gmx.de
Cc: linux-arm-kernel@lists.infradead.org, loongarch@lists.linux.dev,
linux-efi@vger.kernel.org, linux-riscv@lists.infradead.org,
dri-devel@lists.freedesktop.org, linux-hyperv@vger.kernel.org,
linux-fbdev@vger.kernel.org,
Thomas Zimmermann <tzimmermann@suse.de>
Subject: [PATCH 5/8] firmware: sysfb: Implement screen_info relocation for primary display
Date: Thu, 2 Apr 2026 11:09:19 +0200 [thread overview]
Message-ID: <20260402092305.208728-6-tzimmermann@suse.de> (raw)
In-Reply-To: <20260402092305.208728-1-tzimmermann@suse.de>
Move the relocation tracking for screen_info from the screen_info
helpers to sysfb. The relocation code operates on sysfb_primary_display,
which belongs to sysfb. The remaining screen_info helpers are now free
from global state.
Adapt some symbol names. Now prefer early returns in the helper
sysfb_apply_screen_info_fixup() over nested branching. Also return an
errno code from sysfb_apply_screen_info_fixup() if the relocation
failed. In this case, do not create a device for the framebuffer.
The original code advertised this behavior in a comment but never
implemented it.
Framebuffer aperture relocation can happen during boot if the PCI
graphics device is located behind a PCI bridge. If the bridge's sub-
bus gets relocated, the framebuffer aperture moves accordingly. The
helper for tracking these relocations fixes up the values stored in
sysfb_primary_display so that they refer to the correct address range
again. Generic system-framebuffer drivers would not work otherwise.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/firmware/sysfb.h | 5 ++
drivers/firmware/sysfb_pci.c | 111 +++++++++++++++++++++++++++++++
drivers/firmware/sysfb_primary.c | 9 ++-
drivers/video/screen_info_pci.c | 110 ------------------------------
include/linux/screen_info.h | 3 -
5 files changed, 123 insertions(+), 115 deletions(-)
diff --git a/drivers/firmware/sysfb.h b/drivers/firmware/sysfb.h
index 9f7fe2e03f68..1eaa3b0fa364 100644
--- a/drivers/firmware/sysfb.h
+++ b/drivers/firmware/sysfb.h
@@ -8,8 +8,13 @@
struct pci_dev;
#ifdef CONFIG_PCI
+int sysfb_apply_screen_info_fixups(void);
bool sysfb_pci_dev_is_enabled(struct pci_dev *pdev);
#else
+static inline int sysfb_apply_screen_info_fixups(void)
+{
+ return 0;
+}
static inline bool sysfb_pci_dev_is_enabled(struct pci_dev *pdev)
{
return false;
diff --git a/drivers/firmware/sysfb_pci.c b/drivers/firmware/sysfb_pci.c
index 8f3adeef4fb1..d972750c6bc6 100644
--- a/drivers/firmware/sysfb_pci.c
+++ b/drivers/firmware/sysfb_pci.c
@@ -1,9 +1,120 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <linux/pci.h>
+#include <linux/printk.h>
+#include <linux/screen_info.h>
+#include <linux/sysfb.h>
#include "sysfb.h"
+static struct pci_dev *sysfb_lfb_pdev;
+static size_t sysfb_lfb_bar;
+static resource_size_t sysfb_lfb_res_start; // original start of resource
+static resource_size_t sysfb_lfb_offset; // framebuffer offset within resource
+
+static bool __sysfb_relocation_is_valid(const struct screen_info *si, struct resource *pr)
+{
+ u64 size = __screen_info_lfb_size(si, screen_info_video_type(si));
+
+ if (sysfb_lfb_offset > resource_size(pr))
+ return false;
+ if (size > resource_size(pr))
+ return false;
+ if (resource_size(pr) - size < sysfb_lfb_offset)
+ return false;
+
+ return true;
+}
+
+int sysfb_apply_screen_info_fixups(void)
+{
+ struct screen_info *si = &sysfb_primary_display.screen;
+ struct resource *pr;
+
+ if (!sysfb_lfb_pdev)
+ return 0; /* primary display is not on a PCI device */
+
+ pr = &sysfb_lfb_pdev->resource[sysfb_lfb_bar];
+
+ if (pr->start == sysfb_lfb_res_start)
+ return 0; /* no relocation took place */
+
+ if (!__sysfb_relocation_is_valid(si, pr))
+ return -ENXIO;
+
+ /*
+ * Only update base if we have an actual relocation to a valid I/O range.
+ */
+ __screen_info_set_lfb_base(si, pr->start + sysfb_lfb_offset);
+ pr_info("Relocating firmware framebuffer to offset %pa[d] within %pr\n",
+ &sysfb_lfb_offset, pr);
+
+ return 0;
+}
+
+static int __screen_info_lfb_pci_bus_region(const struct screen_info *si, unsigned int type,
+ struct pci_bus_region *r)
+{
+ u64 base, size;
+
+ base = __screen_info_lfb_base(si);
+ if (!base)
+ return -EINVAL;
+
+ size = __screen_info_lfb_size(si, type);
+ if (!size)
+ return -EINVAL;
+
+ r->start = base;
+ r->end = base + size - 1;
+
+ return 0;
+}
+
+static void sysfb_fixup_lfb(struct pci_dev *pdev)
+{
+ unsigned int type;
+ struct pci_bus_region bus_region;
+ int ret;
+ struct resource r = {
+ .flags = IORESOURCE_MEM,
+ };
+ const struct resource *pr;
+ const struct screen_info *si = &sysfb_primary_display.screen;
+
+ if (sysfb_lfb_pdev)
+ return; // already found
+
+ type = screen_info_video_type(si);
+ if (!__screen_info_has_lfb(type))
+ return; // only applies to EFI; maybe VESA
+
+ ret = __screen_info_lfb_pci_bus_region(si, type, &bus_region);
+ if (ret < 0)
+ return;
+
+ /*
+ * Translate the PCI bus address to resource. Account for an offset if
+ * the framebuffer is behind a PCI host bridge.
+ */
+ pcibios_bus_to_resource(pdev->bus, &r, &bus_region);
+
+ pr = pci_find_resource(pdev, &r);
+ if (!pr)
+ return;
+
+ /*
+ * We've found a PCI device with the framebuffer resource. Store away
+ * the parameters to track relocation of the framebuffer aperture.
+ */
+ sysfb_lfb_pdev = pdev;
+ sysfb_lfb_bar = pr - pdev->resource;
+ sysfb_lfb_offset = r.start - pr->start;
+ sysfb_lfb_res_start = bus_region.start;
+}
+DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY, 16,
+ sysfb_fixup_lfb);
+
bool sysfb_pci_dev_is_enabled(struct pci_dev *pdev)
{
/*
diff --git a/drivers/firmware/sysfb_primary.c b/drivers/firmware/sysfb_primary.c
index ab8d7fc468bb..298f87a43a7e 100644
--- a/drivers/firmware/sysfb_primary.c
+++ b/drivers/firmware/sysfb_primary.c
@@ -32,6 +32,7 @@
#include <linux/pci.h>
#include <linux/platform_data/simplefb.h>
#include <linux/platform_device.h>
+#include <linux/printk.h>
#include <linux/screen_info.h>
#include <linux/sysfb.h>
@@ -127,11 +128,15 @@ static __init int sysfb_init(void)
struct simplefb_platform_data mode;
const char *name;
bool compatible;
- int ret = 0;
+ int ret;
- screen_info_apply_fixups();
+ ret = sysfb_apply_screen_info_fixups();
mutex_lock(&disable_lock);
+ if (ret) {
+ pr_warn("Invalid relocation, disabling system framebuffer\n");
+ disabled = true; /* screen_info relocation failed */
+ }
if (disabled)
goto unlock_mutex;
diff --git a/drivers/video/screen_info_pci.c b/drivers/video/screen_info_pci.c
index 8f34d8a74f09..d8985a54ce71 100644
--- a/drivers/video/screen_info_pci.c
+++ b/drivers/video/screen_info_pci.c
@@ -1,117 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/pci.h>
-#include <linux/printk.h>
#include <linux/screen_info.h>
-#include <linux/string.h>
-#include <linux/sysfb.h>
-
-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_relocation_is_valid(const struct screen_info *si, struct resource *pr)
-{
- u64 size = __screen_info_lfb_size(si, screen_info_video_type(si));
-
- if (screen_info_lfb_offset > resource_size(pr))
- return false;
- if (size > resource_size(pr))
- return false;
- if (resource_size(pr) - size < screen_info_lfb_offset)
- return false;
-
- return true;
-}
-
-void screen_info_apply_fixups(void)
-{
- struct screen_info *si = &sysfb_primary_display.screen;
-
- if (screen_info_lfb_pdev) {
- struct resource *pr = &screen_info_lfb_pdev->resource[screen_info_lfb_bar];
-
- if (pr->start != screen_info_lfb_res_start) {
- 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);
- 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");
- }
- }
- }
-}
-
-static int __screen_info_lfb_pci_bus_region(const struct screen_info *si, unsigned int type,
- struct pci_bus_region *r)
-{
- u64 base, size;
-
- base = __screen_info_lfb_base(si);
- if (!base)
- return -EINVAL;
-
- size = __screen_info_lfb_size(si, type);
- if (!size)
- return -EINVAL;
-
- r->start = base;
- r->end = base + size - 1;
-
- return 0;
-}
-
-static void screen_info_fixup_lfb(struct pci_dev *pdev)
-{
- unsigned int type;
- struct pci_bus_region bus_region;
- int ret;
- struct resource r = {
- .flags = IORESOURCE_MEM,
- };
- const struct resource *pr;
- const struct screen_info *si = &sysfb_primary_display.screen;
-
- if (screen_info_lfb_pdev)
- return; // already found
-
- type = screen_info_video_type(si);
- if (!__screen_info_has_lfb(type))
- return; // only applies to EFI; maybe VESA
-
- ret = __screen_info_lfb_pci_bus_region(si, type, &bus_region);
- if (ret < 0)
- return;
-
- /*
- * Translate the PCI bus address to resource. Account
- * for an offset if the framebuffer is behind a PCI host
- * bridge.
- */
- pcibios_bus_to_resource(pdev->bus, &r, &bus_region);
-
- pr = pci_find_resource(pdev, &r);
- if (!pr)
- return;
-
- /*
- * We've found a PCI device with the framebuffer
- * resource. Store away the parameters to track
- * relocation of the framebuffer aperture.
- */
- screen_info_lfb_pdev = pdev;
- screen_info_lfb_bar = pr - pdev->resource;
- screen_info_lfb_offset = r.start - pr->start;
- screen_info_lfb_res_start = bus_region.start;
-}
-DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY, 16,
- screen_info_fixup_lfb);
static struct pci_dev *__screen_info_pci_dev(struct resource *res)
{
diff --git a/include/linux/screen_info.h b/include/linux/screen_info.h
index c022403c599a..2adbe25b88d8 100644
--- a/include/linux/screen_info.h
+++ b/include/linux/screen_info.h
@@ -140,11 +140,8 @@ u32 __screen_info_lfb_bits_per_pixel(const struct screen_info *si);
int screen_info_pixel_format(const struct screen_info *si, struct pixel_format *f);
#if defined(CONFIG_PCI)
-void screen_info_apply_fixups(void);
struct pci_dev *screen_info_pci_dev(const struct screen_info *si);
#else
-static inline void screen_info_apply_fixups(void)
-{ }
static inline struct pci_dev *screen_info_pci_dev(const struct screen_info *si)
{
return NULL;
--
2.53.0
next prev parent reply other threads:[~2026-04-02 9:23 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-02 9:09 [PATCH 0/8] firmware: sysfb: Consolidate config/code wrt. sysfb_primary_screen Thomas Zimmermann
2026-04-02 9:09 ` [PATCH 1/8] hv: Select CONFIG_SYSFB only for CONFIG_HYPERV_VMBUS Thomas Zimmermann
2026-04-02 10:50 ` Saurabh Singh Sengar
2026-04-02 9:09 ` [PATCH 2/8] firmware: efi: Never declare sysfb_primary_display on x86 Thomas Zimmermann
2026-04-02 9:09 ` [PATCH 3/8] firmware: sysfb: Make CONFIG_SYSFB a user-selectable option Thomas Zimmermann
2026-04-02 13:08 ` Arnd Bergmann
2026-04-02 14:10 ` Thomas Zimmermann
2026-04-02 14:59 ` Arnd Bergmann
2026-04-02 15:27 ` Thomas Zimmermann
2026-04-02 16:47 ` Arnd Bergmann
2026-04-02 9:09 ` [PATCH 4/8] firmware: sysfb: Split sysfb.c into sysfb_primary.c and sysfb_pci.c Thomas Zimmermann
2026-04-02 9:09 ` Thomas Zimmermann [this message]
2026-04-02 9:09 ` [PATCH 6/8] firmware: sysfb: Avoid forward-declaring sysfb_parent_dev() Thomas Zimmermann
2026-04-02 9:09 ` [PATCH 7/8] firmware: efi: Make CONFIG_EFI_EARLYCON depend on CONFIG_SYSFB; clean up Thomas Zimmermann
2026-04-02 9:09 ` [PATCH 8/8] firmware: sysfb: Move CONFIG_FIRMWARE_EDID to firmware options Thomas Zimmermann
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=20260402092305.208728-6-tzimmermann@suse.de \
--to=tzimmermann@suse.de \
--cc=airlied@gmail.com \
--cc=ardb@kernel.org \
--cc=arnd@arndb.de \
--cc=chenhuacai@kernel.org \
--cc=decui@microsoft.com \
--cc=deller@gmx.de \
--cc=dri-devel@lists.freedesktop.org \
--cc=haiyangz@microsoft.com \
--cc=ilias.apalodimas@linaro.org \
--cc=javierm@redhat.com \
--cc=kernel@xen0n.name \
--cc=kys@microsoft.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-efi@vger.kernel.org \
--cc=linux-fbdev@vger.kernel.org \
--cc=linux-hyperv@vger.kernel.org \
--cc=linux-riscv@lists.infradead.org \
--cc=longli@microsoft.com \
--cc=loongarch@lists.linux.dev \
--cc=maarten.lankhorst@linux.intel.com \
--cc=mripard@kernel.org \
--cc=simona@ffwll.ch \
--cc=wei.liu@kernel.org \
/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