* [PATCH 3/6] sysfb: Add struct sysfb_display_info
From: Thomas Zimmermann @ 2025-11-21 13:36 UTC (permalink / raw)
To: ardb, javierm, arnd
Cc: x86, linux-arm-kernel, linux-kernel, linux-efi, loongarch,
linux-riscv, dri-devel, linux-hyperv, linux-pci, linux-fbdev,
Thomas Zimmermann
In-Reply-To: <20251121135624.494768-1-tzimmermann@suse.de>
Add struct sysfb_display_info to wrap display-related state. For now
it contains only the screen's video mode. Later EDID will be added as
well.
This struct will be helpful for passing display state to sysfb drivers
or from the EFI stub library.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
include/linux/sysfb.h | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/include/linux/sysfb.h b/include/linux/sysfb.h
index 8527a50a5290..8b37247528bf 100644
--- a/include/linux/sysfb.h
+++ b/include/linux/sysfb.h
@@ -8,6 +8,7 @@
*/
#include <linux/err.h>
+#include <linux/screen_info.h>
#include <linux/types.h>
#include <linux/platform_data/simplefb.h>
@@ -60,6 +61,10 @@ struct efifb_dmi_info {
int flags;
};
+struct sysfb_display_info {
+ struct screen_info screen;
+};
+
#ifdef CONFIG_SYSFB
void sysfb_disable(struct device *dev);
--
2.51.1
^ permalink raw reply related
* [PATCH 5/6] sysfb: Pass sysfb_primary_display to devices
From: Thomas Zimmermann @ 2025-11-21 13:36 UTC (permalink / raw)
To: ardb, javierm, arnd
Cc: x86, linux-arm-kernel, linux-kernel, linux-efi, loongarch,
linux-riscv, dri-devel, linux-hyperv, linux-pci, linux-fbdev,
Thomas Zimmermann
In-Reply-To: <20251121135624.494768-1-tzimmermann@suse.de>
Instead of screen_info, store a copy of sysfb_primary_display as
device data. Pick it up in drivers. Later changes will add additional
data to the display info, such as EDID information.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/firmware/sysfb.c | 5 +++--
drivers/gpu/drm/sysfb/efidrm.c | 9 ++++++---
drivers/gpu/drm/sysfb/vesadrm.c | 9 ++++++---
drivers/video/fbdev/efifb.c | 10 ++++++----
drivers/video/fbdev/vesafb.c | 10 ++++++----
drivers/video/fbdev/vga16fb.c | 8 +++++---
6 files changed, 32 insertions(+), 19 deletions(-)
diff --git a/drivers/firmware/sysfb.c b/drivers/firmware/sysfb.c
index 1f671f9219b0..8833582c1883 100644
--- a/drivers/firmware/sysfb.c
+++ b/drivers/firmware/sysfb.c
@@ -141,7 +141,8 @@ static struct device *sysfb_parent_dev(const struct screen_info *si)
static __init int sysfb_init(void)
{
- struct screen_info *si = &sysfb_primary_display.screen;
+ struct sysfb_display_info *dpy = &sysfb_primary_display;
+ struct screen_info *si = &dpy->screen;
struct device *parent;
unsigned int type;
struct simplefb_platform_data mode;
@@ -202,7 +203,7 @@ static __init int sysfb_init(void)
sysfb_set_efifb_fwnode(si, pd);
- ret = platform_device_add_data(pd, si, sizeof(*si));
+ ret = platform_device_add_data(pd, dpy, sizeof(*dpy));
if (ret)
goto err;
diff --git a/drivers/gpu/drm/sysfb/efidrm.c b/drivers/gpu/drm/sysfb/efidrm.c
index 1b683d55d6ea..29533ae8fbbf 100644
--- a/drivers/gpu/drm/sysfb/efidrm.c
+++ b/drivers/gpu/drm/sysfb/efidrm.c
@@ -4,7 +4,7 @@
#include <linux/efi.h>
#include <linux/limits.h>
#include <linux/platform_device.h>
-#include <linux/screen_info.h>
+#include <linux/sysfb.h>
#include <drm/clients/drm_client_setup.h>
#include <drm/drm_atomic.h>
@@ -141,6 +141,7 @@ static const struct drm_mode_config_funcs efidrm_mode_config_funcs = {
static struct efidrm_device *efidrm_device_create(struct drm_driver *drv,
struct platform_device *pdev)
{
+ const struct sysfb_display_info *dpy;
const struct screen_info *si;
const struct drm_format_info *format;
int width, height, stride;
@@ -160,9 +161,11 @@ static struct efidrm_device *efidrm_device_create(struct drm_driver *drv,
size_t nformats;
int ret;
- si = dev_get_platdata(&pdev->dev);
- if (!si)
+ dpy = dev_get_platdata(&pdev->dev);
+ if (!dpy)
return ERR_PTR(-ENODEV);
+ si = &dpy->screen;
+
if (screen_info_video_type(si) != VIDEO_TYPE_EFI)
return ERR_PTR(-ENODEV);
diff --git a/drivers/gpu/drm/sysfb/vesadrm.c b/drivers/gpu/drm/sysfb/vesadrm.c
index 7b7b5ba26317..16fc223f8c5b 100644
--- a/drivers/gpu/drm/sysfb/vesadrm.c
+++ b/drivers/gpu/drm/sysfb/vesadrm.c
@@ -4,7 +4,7 @@
#include <linux/ioport.h>
#include <linux/limits.h>
#include <linux/platform_device.h>
-#include <linux/screen_info.h>
+#include <linux/sysfb.h>
#include <drm/clients/drm_client_setup.h>
#include <drm/drm_atomic.h>
@@ -391,6 +391,7 @@ static const struct drm_mode_config_funcs vesadrm_mode_config_funcs = {
static struct vesadrm_device *vesadrm_device_create(struct drm_driver *drv,
struct platform_device *pdev)
{
+ const struct sysfb_display_info *dpy;
const struct screen_info *si;
const struct drm_format_info *format;
int width, height, stride;
@@ -410,9 +411,11 @@ static struct vesadrm_device *vesadrm_device_create(struct drm_driver *drv,
size_t nformats;
int ret;
- si = dev_get_platdata(&pdev->dev);
- if (!si)
+ dpy = dev_get_platdata(&pdev->dev);
+ if (!dpy)
return ERR_PTR(-ENODEV);
+ si = &dpy->screen;
+
if (screen_info_video_type(si) != VIDEO_TYPE_VLFB)
return ERR_PTR(-ENODEV);
diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c
index 0e1bd3dba255..47ebc0107209 100644
--- a/drivers/video/fbdev/efifb.c
+++ b/drivers/video/fbdev/efifb.c
@@ -15,7 +15,7 @@
#include <linux/fb.h>
#include <linux/platform_device.h>
#include <linux/printk.h>
-#include <linux/screen_info.h>
+#include <linux/sysfb.h>
#include <video/vga.h>
#include <asm/efi.h>
#include <drm/drm_utils.h> /* For drm_get_panel_orientation_quirk */
@@ -345,6 +345,7 @@ ATTRIBUTE_GROUPS(efifb);
static int efifb_probe(struct platform_device *dev)
{
+ struct sysfb_display_info *dpy;
struct screen_info *si;
struct fb_info *info;
struct efifb_par *par;
@@ -360,10 +361,11 @@ static int efifb_probe(struct platform_device *dev)
* driver. We get a copy of the attached screen_info, so that we can
* modify its values without affecting later drivers.
*/
- si = dev_get_platdata(&dev->dev);
- if (!si)
+ dpy = dev_get_platdata(&dev->dev);
+ if (!dpy)
return -ENODEV;
- si = devm_kmemdup(&dev->dev, si, sizeof(*si), GFP_KERNEL);
+
+ si = devm_kmemdup(&dev->dev, &dpy->screen, sizeof(*si), GFP_KERNEL);
if (!si)
return -ENOMEM;
diff --git a/drivers/video/fbdev/vesafb.c b/drivers/video/fbdev/vesafb.c
index a81df8865143..10d3d9ae73aa 100644
--- a/drivers/video/fbdev/vesafb.c
+++ b/drivers/video/fbdev/vesafb.c
@@ -20,7 +20,7 @@
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/platform_device.h>
-#include <linux/screen_info.h>
+#include <linux/sysfb.h>
#include <linux/io.h>
#include <video/vga.h>
@@ -243,6 +243,7 @@ static int vesafb_setup(char *options)
static int vesafb_probe(struct platform_device *dev)
{
+ struct sysfb_display_info *dpy;
struct screen_info *si;
struct fb_info *info;
struct vesafb_par *par;
@@ -257,10 +258,11 @@ static int vesafb_probe(struct platform_device *dev)
* driver. We get a copy of the attached screen_info, so that we can
* modify its values without affecting later drivers.
*/
- si = dev_get_platdata(&dev->dev);
- if (!si)
+ dpy = dev_get_platdata(&dev->dev);
+ if (!dpy)
return -ENODEV;
- si = devm_kmemdup(&dev->dev, si, sizeof(*si), GFP_KERNEL);
+
+ si = devm_kmemdup(&dev->dev, &dpy->screen, sizeof(*si), GFP_KERNEL);
if (!si)
return -ENOMEM;
diff --git a/drivers/video/fbdev/vga16fb.c b/drivers/video/fbdev/vga16fb.c
index eedab14c7d51..7853d84f10df 100644
--- a/drivers/video/fbdev/vga16fb.c
+++ b/drivers/video/fbdev/vga16fb.c
@@ -21,7 +21,7 @@
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/platform_device.h>
-#include <linux/screen_info.h>
+#include <linux/sysfb.h>
#include <asm/io.h>
#include <video/vga.h>
@@ -1305,15 +1305,17 @@ static const struct fb_ops vga16fb_ops = {
static int vga16fb_probe(struct platform_device *dev)
{
+ struct sysfb_display_info *dpy;
struct screen_info *si;
struct fb_info *info;
struct vga16fb_par *par;
int i;
int ret = 0;
- si = dev_get_platdata(&dev->dev);
- if (!si)
+ dpy = dev_get_platdata(&dev->dev);
+ if (!dpy)
return -ENODEV;
+ si = &dpy->screen;
ret = check_mode_supported(si);
if (ret)
--
2.51.1
^ permalink raw reply related
* [PATCH 2/6] efi: sysfb_efi: Reduce number of references to global screen_info
From: Thomas Zimmermann @ 2025-11-21 13:36 UTC (permalink / raw)
To: ardb, javierm, arnd
Cc: x86, linux-arm-kernel, linux-kernel, linux-efi, loongarch,
linux-riscv, dri-devel, linux-hyperv, linux-pci, linux-fbdev,
Thomas Zimmermann
In-Reply-To: <20251121135624.494768-1-tzimmermann@suse.de>
Replace usage of global screen_info with local pointers. This will
later reduce churn when screen_info is being moved.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/firmware/efi/sysfb_efi.c | 81 ++++++++++++++++---------------
drivers/firmware/sysfb.c | 4 +-
drivers/firmware/sysfb_simplefb.c | 2 +-
include/linux/sysfb.h | 9 ++--
4 files changed, 51 insertions(+), 45 deletions(-)
diff --git a/drivers/firmware/efi/sysfb_efi.c b/drivers/firmware/efi/sysfb_efi.c
index 1e509595ac03..8e0f9d08397f 100644
--- a/drivers/firmware/efi/sysfb_efi.c
+++ b/drivers/firmware/efi/sysfb_efi.c
@@ -92,7 +92,7 @@ void efifb_setup_from_dmi(struct screen_info *si, const char *opt)
})
#ifdef CONFIG_EFI
-static int __init efifb_set_system(const struct dmi_system_id *id)
+static int __init efifb_set_system(struct screen_info *si, const struct dmi_system_id *id)
{
struct efifb_dmi_info *info = id->driver_data;
@@ -101,14 +101,14 @@ static int __init efifb_set_system(const struct dmi_system_id *id)
return 0;
/* Trust the bootloader over the DMI tables */
- if (screen_info.lfb_base == 0) {
+ if (si->lfb_base == 0) {
#if defined(CONFIG_PCI)
struct pci_dev *dev = NULL;
int found_bar = 0;
#endif
if (info->base) {
- screen_info.lfb_base = choose_value(info->base,
- screen_info.lfb_base, OVERRIDE_BASE,
+ si->lfb_base = choose_value(info->base,
+ si->lfb_base, OVERRIDE_BASE,
info->flags);
#if defined(CONFIG_PCI)
@@ -135,49 +135,53 @@ static int __init efifb_set_system(const struct dmi_system_id *id)
start = pci_resource_start(dev, i);
end = pci_resource_end(dev, i);
- if (screen_info.lfb_base >= start &&
- screen_info.lfb_base < end) {
+ if (si->lfb_base >= start && si->lfb_base < end) {
found_bar = 1;
break;
}
}
}
if (!found_bar)
- screen_info.lfb_base = 0;
+ si->lfb_base = 0;
#endif
}
}
- if (screen_info.lfb_base) {
- screen_info.lfb_linelength = choose_value(info->stride,
- screen_info.lfb_linelength, OVERRIDE_STRIDE,
+ if (si->lfb_base) {
+ si->lfb_linelength = choose_value(info->stride,
+ si->lfb_linelength, OVERRIDE_STRIDE,
info->flags);
- screen_info.lfb_width = choose_value(info->width,
- screen_info.lfb_width, OVERRIDE_WIDTH,
+ si->lfb_width = choose_value(info->width,
+ si->lfb_width, OVERRIDE_WIDTH,
info->flags);
- screen_info.lfb_height = choose_value(info->height,
- screen_info.lfb_height, OVERRIDE_HEIGHT,
+ si->lfb_height = choose_value(info->height,
+ si->lfb_height, OVERRIDE_HEIGHT,
info->flags);
- if (screen_info.orig_video_isVGA == 0)
- screen_info.orig_video_isVGA = VIDEO_TYPE_EFI;
+ if (si->orig_video_isVGA == 0)
+ si->orig_video_isVGA = VIDEO_TYPE_EFI;
} else {
- screen_info.lfb_linelength = 0;
- screen_info.lfb_width = 0;
- screen_info.lfb_height = 0;
- screen_info.orig_video_isVGA = 0;
+ si->lfb_linelength = 0;
+ si->lfb_width = 0;
+ si->lfb_height = 0;
+ si->orig_video_isVGA = 0;
return 0;
}
printk(KERN_INFO "efifb: dmi detected %s - framebuffer at 0x%08x "
"(%dx%d, stride %d)\n", id->ident,
- screen_info.lfb_base, screen_info.lfb_width,
- screen_info.lfb_height, screen_info.lfb_linelength);
+ si->lfb_base, si->lfb_width,
+ si->lfb_height, si->lfb_linelength);
return 1;
}
+static int __init efifb_set_system_callback(const struct dmi_system_id *id)
+{
+ return efifb_set_system(&screen_info, id);
+}
+
#define EFIFB_DMI_SYSTEM_ID(vendor, name, enumid) \
{ \
- efifb_set_system, \
+ efifb_set_system_callback, \
name, \
{ \
DMI_MATCH(DMI_BIOS_VENDOR, vendor), \
@@ -284,12 +288,13 @@ static const struct dmi_system_id efifb_dmi_swap_width_height[] __initconst = {
{},
};
-static bool efifb_overlaps_pci_range(const struct of_pci_range *range)
+static bool efifb_overlaps_pci_range(const struct screen_info *si,
+ const struct of_pci_range *range)
{
- u64 fb_base = screen_info.lfb_base;
+ u64 fb_base = si->lfb_base;
- if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE)
- fb_base |= (u64)(unsigned long)screen_info.ext_lfb_base << 32;
+ if (si->capabilities & VIDEO_CAPABILITY_64BIT_BASE)
+ fb_base |= (u64)(unsigned long)si->ext_lfb_base << 32;
return fb_base >= range->cpu_addr &&
fb_base < (range->cpu_addr + range->size);
@@ -311,7 +316,7 @@ static struct device_node *find_pci_overlap_node(void)
}
for_each_of_pci_range(&parser, &range)
- if (efifb_overlaps_pci_range(&range))
+ if (efifb_overlaps_pci_range(&screen_info, &range))
return np;
}
return NULL;
@@ -349,25 +354,25 @@ static const struct fwnode_operations efifb_fwnode_ops = {
static struct fwnode_handle efifb_fwnode;
-__init void sysfb_apply_efi_quirks(void)
+__init void sysfb_apply_efi_quirks(struct screen_info *si)
{
- if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI ||
- !(screen_info.capabilities & VIDEO_CAPABILITY_SKIP_QUIRKS))
+ if (si->orig_video_isVGA != VIDEO_TYPE_EFI ||
+ !(si->capabilities & VIDEO_CAPABILITY_SKIP_QUIRKS))
dmi_check_system(efifb_dmi_system_table);
- if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI &&
+ if (si->orig_video_isVGA == VIDEO_TYPE_EFI &&
dmi_check_system(efifb_dmi_swap_width_height)) {
- u16 temp = screen_info.lfb_width;
+ u16 temp = si->lfb_width;
- screen_info.lfb_width = screen_info.lfb_height;
- screen_info.lfb_height = temp;
- screen_info.lfb_linelength = 4 * screen_info.lfb_width;
+ si->lfb_width = si->lfb_height;
+ si->lfb_height = temp;
+ si->lfb_linelength = 4 * si->lfb_width;
}
}
-__init void sysfb_set_efifb_fwnode(struct platform_device *pd)
+__init void sysfb_set_efifb_fwnode(const struct screen_info *si, struct platform_device *pd)
{
- if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI && IS_ENABLED(CONFIG_PCI)) {
+ if (si->orig_video_isVGA == VIDEO_TYPE_EFI && IS_ENABLED(CONFIG_PCI)) {
fwnode_init(&efifb_fwnode, &efifb_fwnode_ops);
pd->dev.fwnode = &efifb_fwnode;
}
diff --git a/drivers/firmware/sysfb.c b/drivers/firmware/sysfb.c
index 889e5b05c739..916b28538a29 100644
--- a/drivers/firmware/sysfb.c
+++ b/drivers/firmware/sysfb.c
@@ -155,7 +155,7 @@ static __init int sysfb_init(void)
if (disabled)
goto unlock_mutex;
- sysfb_apply_efi_quirks();
+ sysfb_apply_efi_quirks(si);
parent = sysfb_parent_dev(si);
if (IS_ERR(parent)) {
@@ -200,7 +200,7 @@ static __init int sysfb_init(void)
pd->dev.parent = parent;
- sysfb_set_efifb_fwnode(pd);
+ sysfb_set_efifb_fwnode(si, pd);
ret = platform_device_add_data(pd, si, sizeof(*si));
if (ret)
diff --git a/drivers/firmware/sysfb_simplefb.c b/drivers/firmware/sysfb_simplefb.c
index 592d8a644619..71f542e37732 100644
--- a/drivers/firmware/sysfb_simplefb.c
+++ b/drivers/firmware/sysfb_simplefb.c
@@ -117,7 +117,7 @@ __init struct platform_device *sysfb_create_simplefb(const struct screen_info *s
pd->dev.parent = parent;
- sysfb_set_efifb_fwnode(pd);
+ sysfb_set_efifb_fwnode(si, pd);
ret = platform_device_add_resources(pd, &res, 1);
if (ret)
diff --git a/include/linux/sysfb.h b/include/linux/sysfb.h
index b449665c686a..8527a50a5290 100644
--- a/include/linux/sysfb.h
+++ b/include/linux/sysfb.h
@@ -82,16 +82,17 @@ static inline bool sysfb_handles_screen_info(void)
#ifdef CONFIG_EFI
extern struct efifb_dmi_info efifb_dmi_list[];
-void sysfb_apply_efi_quirks(void);
-void sysfb_set_efifb_fwnode(struct platform_device *pd);
+void sysfb_apply_efi_quirks(struct screen_info *si);
+void sysfb_set_efifb_fwnode(const struct screen_info *si, struct platform_device *pd);
#else /* CONFIG_EFI */
-static inline void sysfb_apply_efi_quirks(void)
+static inline void sysfb_apply_efi_quirks(struct screen_info *si)
{
}
-static inline void sysfb_set_efifb_fwnode(struct platform_device *pd)
+static inline void sysfb_set_efifb_fwnode(const struct screen_info *si,
+ struct platform_device *pd)
{
}
--
2.51.1
^ permalink raw reply related
* [PATCH 4/6] sysfb: Replace screen_info with sysfb_primary_display
From: Thomas Zimmermann @ 2025-11-21 13:36 UTC (permalink / raw)
To: ardb, javierm, arnd
Cc: x86, linux-arm-kernel, linux-kernel, linux-efi, loongarch,
linux-riscv, dri-devel, linux-hyperv, linux-pci, linux-fbdev,
Thomas Zimmermann
In-Reply-To: <20251121135624.494768-1-tzimmermann@suse.de>
Replace the global screen_info with sysfb_primary_display of type
struct sysfb_display_info. Adapt all users of screen_info.
Instances of screen_info are defined for x86, loongarch and EFI,
with only one instance compiled into a specific build. Replace all
of them with sysfb_primary_display.
All existing users of screen_info are updated by pointing them to
sysfb_primary_display.screen instead. This introduces some churn to
the code, but has no impact on functionality.
Boot parameters and EFI config tables are unchanged. They transfer
screen_info as before. The logic in EFI's alloc_screen_info() changes
slightly, as it now returns the screen field of sysfb_primary_display.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
arch/arm64/kernel/image-vars.h | 2 +-
arch/loongarch/kernel/efi.c | 11 ++++++-----
arch/loongarch/kernel/image-vars.h | 2 +-
arch/riscv/kernel/image-vars.h | 2 +-
arch/x86/kernel/kexec-bzimage64.c | 4 +++-
arch/x86/kernel/setup.c | 10 ++++++----
arch/x86/video/video-common.c | 4 ++--
drivers/firmware/efi/earlycon.c | 8 ++++----
drivers/firmware/efi/efi-init.c | 14 +++++++-------
drivers/firmware/efi/libstub/efi-stub-entry.c | 18 +++++++++++++-----
drivers/firmware/efi/sysfb_efi.c | 4 ++--
drivers/firmware/sysfb.c | 6 +++---
drivers/hv/vmbus_drv.c | 6 +++---
drivers/pci/vgaarb.c | 4 ++--
drivers/video/screen_info_pci.c | 5 +++--
include/linux/screen_info.h | 2 --
include/linux/sysfb.h | 5 +++--
17 files changed, 60 insertions(+), 47 deletions(-)
diff --git a/arch/arm64/kernel/image-vars.h b/arch/arm64/kernel/image-vars.h
index 5369763606e7..a7867bd8cfb6 100644
--- a/arch/arm64/kernel/image-vars.h
+++ b/arch/arm64/kernel/image-vars.h
@@ -38,7 +38,7 @@ PROVIDE(__efistub__end = _end);
PROVIDE(__efistub___inittext_end = __inittext_end);
PROVIDE(__efistub__edata = _edata);
#if defined(CONFIG_EFI_EARLYCON) || defined(CONFIG_SYSFB)
-PROVIDE(__efistub_screen_info = screen_info);
+PROVIDE(__efistub_sysfb_primary_display = sysfb_primary_display);
#endif
PROVIDE(__efistub__ctype = _ctype);
diff --git a/arch/loongarch/kernel/efi.c b/arch/loongarch/kernel/efi.c
index 860a3bc030e0..b11188413f4d 100644
--- a/arch/loongarch/kernel/efi.c
+++ b/arch/loongarch/kernel/efi.c
@@ -18,7 +18,7 @@
#include <linux/kobject.h>
#include <linux/memblock.h>
#include <linux/reboot.h>
-#include <linux/screen_info.h>
+#include <linux/sysfb.h>
#include <linux/uaccess.h>
#include <asm/early_ioremap.h>
@@ -75,8 +75,8 @@ bool efi_poweroff_required(void)
unsigned long __initdata screen_info_table = EFI_INVALID_TABLE_ADDR;
#if defined(CONFIG_SYSFB) || defined(CONFIG_EFI_EARLYCON)
-struct screen_info screen_info __section(".data");
-EXPORT_SYMBOL_GPL(screen_info);
+struct sysfb_display_info sysfb_primary_display __section(".data");
+EXPORT_SYMBOL_GPL(sysfb_primary_display);
#endif
static void __init init_screen_info(void)
@@ -91,11 +91,12 @@ static void __init init_screen_info(void)
pr_err("Could not map screen_info config table\n");
return;
}
- screen_info = *si;
+ sysfb_primary_display.screen = *si;
memset(si, 0, sizeof(*si));
early_memunmap(si, sizeof(*si));
- memblock_reserve(__screen_info_lfb_base(&screen_info), screen_info.lfb_size);
+ memblock_reserve(__screen_info_lfb_base(&sysfb_primary_display.screen),
+ sysfb_primary_display.screen.lfb_size);
}
void __init efi_init(void)
diff --git a/arch/loongarch/kernel/image-vars.h b/arch/loongarch/kernel/image-vars.h
index 41ddcf56d21c..e557ebd46c2b 100644
--- a/arch/loongarch/kernel/image-vars.h
+++ b/arch/loongarch/kernel/image-vars.h
@@ -12,7 +12,7 @@ __efistub_kernel_entry = kernel_entry;
__efistub_kernel_asize = kernel_asize;
__efistub_kernel_fsize = kernel_fsize;
#if defined(CONFIG_EFI_EARLYCON) || defined(CONFIG_SYSFB)
-__efistub_screen_info = screen_info;
+__efistub_sysfb_primary_display = sysfb_primary_display;
#endif
#endif
diff --git a/arch/riscv/kernel/image-vars.h b/arch/riscv/kernel/image-vars.h
index 3df30dd1c458..3bd9d06a8b8f 100644
--- a/arch/riscv/kernel/image-vars.h
+++ b/arch/riscv/kernel/image-vars.h
@@ -29,7 +29,7 @@ __efistub__end = _end;
__efistub__edata = _edata;
__efistub___init_text_end = __init_text_end;
#if defined(CONFIG_EFI_EARLYCON) || defined(CONFIG_SYSFB)
-__efistub_screen_info = screen_info;
+__efistub_sysfb_primary_display = sysfb_primary_display;
#endif
#endif
diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c
index c3244ac680d1..7508d0ccc740 100644
--- a/arch/x86/kernel/kexec-bzimage64.c
+++ b/arch/x86/kernel/kexec-bzimage64.c
@@ -20,6 +20,7 @@
#include <linux/of_fdt.h>
#include <linux/efi.h>
#include <linux/random.h>
+#include <linux/sysfb.h>
#include <asm/bootparam.h>
#include <asm/setup.h>
@@ -303,7 +304,8 @@ setup_boot_parameters(struct kimage *image, struct boot_params *params,
params->hdr.hardware_subarch = boot_params.hdr.hardware_subarch;
/* Copying screen_info will do? */
- memcpy(¶ms->screen_info, &screen_info, sizeof(struct screen_info));
+ memcpy(¶ms->screen_info, &sysfb_primary_display.screen,
+ sizeof(sysfb_primary_display.screen));
/* Fill in memsize later */
params->screen_info.ext_mem_k = 0;
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 1b2edd07a3e1..675e4b9deb1f 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -22,6 +22,7 @@
#include <linux/random.h>
#include <linux/root_dev.h>
#include <linux/static_call.h>
+#include <linux/sysfb.h>
#include <linux/swiotlb.h>
#include <linux/tboot.h>
#include <linux/usb/xhci-dbgp.h>
@@ -211,8 +212,9 @@ arch_initcall(init_x86_sysctl);
/*
* Setup options
*/
-struct screen_info screen_info;
-EXPORT_SYMBOL(screen_info);
+
+struct sysfb_display_info sysfb_primary_display;
+EXPORT_SYMBOL(sysfb_primary_display);
#if defined(CONFIG_FIRMWARE_EDID)
struct edid_info edid_info;
EXPORT_SYMBOL_GPL(edid_info);
@@ -526,7 +528,7 @@ static void __init parse_setup_data(void)
static void __init parse_boot_params(void)
{
ROOT_DEV = old_decode_dev(boot_params.hdr.root_dev);
- screen_info = boot_params.screen_info;
+ sysfb_primary_display.screen = boot_params.screen_info;
#if defined(CONFIG_FIRMWARE_EDID)
edid_info = boot_params.edid_info;
#endif
@@ -1254,7 +1256,7 @@ void __init setup_arch(char **cmdline_p)
#ifdef CONFIG_VT
#if defined(CONFIG_VGA_CONSOLE)
if (!efi_enabled(EFI_BOOT) || (efi_mem_type(0xa0000) != EFI_CONVENTIONAL_MEMORY))
- vgacon_register_screen(&screen_info);
+ vgacon_register_screen(&sysfb_primary_display.screen);
#endif
#endif
x86_init.oem.banner();
diff --git a/arch/x86/video/video-common.c b/arch/x86/video/video-common.c
index e0aeee99bc99..152789f00fcd 100644
--- a/arch/x86/video/video-common.c
+++ b/arch/x86/video/video-common.c
@@ -9,7 +9,7 @@
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/screen_info.h>
+#include <linux/sysfb.h>
#include <linux/vgaarb.h>
#include <asm/video.h>
@@ -29,7 +29,7 @@ EXPORT_SYMBOL(pgprot_framebuffer);
bool video_is_primary_device(struct device *dev)
{
#ifdef CONFIG_SCREEN_INFO
- struct screen_info *si = &screen_info;
+ struct screen_info *si = &sysfb_primary_display.screen;
struct resource res[SCREEN_INFO_MAX_RESOURCES];
ssize_t i, numres;
#endif
diff --git a/drivers/firmware/efi/earlycon.c b/drivers/firmware/efi/earlycon.c
index fac3a295c57f..d63849457164 100644
--- a/drivers/firmware/efi/earlycon.c
+++ b/drivers/firmware/efi/earlycon.c
@@ -9,7 +9,7 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/serial_core.h>
-#include <linux/screen_info.h>
+#include <linux/sysfb.h>
#include <linux/string.h>
#include <asm/early_ioremap.h>
@@ -32,7 +32,7 @@ static void *efi_fb;
*/
static int __init efi_earlycon_remap_fb(void)
{
- const struct screen_info *si = &screen_info;
+ const struct screen_info *si = &sysfb_primary_display.screen;
/* bail if there is no bootconsole or it was unregistered already */
if (!earlycon_console || !console_is_registered(earlycon_console))
@@ -147,7 +147,7 @@ static void efi_earlycon_write_char(u32 *dst, unsigned char c, unsigned int h,
static void
efi_earlycon_write(struct console *con, const char *str, unsigned int num)
{
- const struct screen_info *si = &screen_info;
+ const struct screen_info *si = &sysfb_primary_display.screen;
u32 cur_efi_x = efi_x;
unsigned int len;
const char *s;
@@ -227,7 +227,7 @@ void __init efi_earlycon_reprobe(void)
static int __init efi_earlycon_setup(struct earlycon_device *device,
const char *opt)
{
- const struct screen_info *si = &screen_info;
+ const struct screen_info *si = &sysfb_primary_display.screen;
u16 xres, yres;
u32 i;
diff --git a/drivers/firmware/efi/efi-init.c b/drivers/firmware/efi/efi-init.c
index a65c2d5b9e7b..ced12c82d2a9 100644
--- a/drivers/firmware/efi/efi-init.c
+++ b/drivers/firmware/efi/efi-init.c
@@ -19,7 +19,7 @@
#include <linux/of_address.h>
#include <linux/of_fdt.h>
#include <linux/platform_device.h>
-#include <linux/screen_info.h>
+#include <linux/sysfb.h>
#include <asm/efi.h>
@@ -61,8 +61,8 @@ extern __weak const efi_config_table_type_t efi_arch_tables[];
* everything else can get it from here.
*/
#if !defined(CONFIG_X86) && (defined(CONFIG_SYSFB) || defined(CONFIG_EFI_EARLYCON))
-struct screen_info screen_info __section(".data");
-EXPORT_SYMBOL_GPL(screen_info);
+struct sysfb_display_info sysfb_primary_display __section(".data");
+EXPORT_SYMBOL_GPL(sysfb_primary_display);
#endif
static void __init init_screen_info(void)
@@ -75,13 +75,13 @@ static void __init init_screen_info(void)
pr_err("Could not map screen_info config table\n");
return;
}
- screen_info = *si;
+ sysfb_primary_display.screen = *si;
memset(si, 0, sizeof(*si));
early_memunmap(si, sizeof(*si));
- if (memblock_is_map_memory(screen_info.lfb_base))
- memblock_mark_nomap(screen_info.lfb_base,
- screen_info.lfb_size);
+ if (memblock_is_map_memory(sysfb_primary_display.screen.lfb_base))
+ memblock_mark_nomap(sysfb_primary_display.screen.lfb_base,
+ sysfb_primary_display.screen.lfb_size);
if (IS_ENABLED(CONFIG_EFI_EARLYCON))
efi_earlycon_reprobe();
diff --git a/drivers/firmware/efi/libstub/efi-stub-entry.c b/drivers/firmware/efi/libstub/efi-stub-entry.c
index a6c049835190..401ecbbdf331 100644
--- a/drivers/firmware/efi/libstub/efi-stub-entry.c
+++ b/drivers/firmware/efi/libstub/efi-stub-entry.c
@@ -1,13 +1,18 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/efi.h>
-#include <linux/screen_info.h>
+#include <linux/sysfb.h>
#include <asm/efi.h>
#include "efistub.h"
-static unsigned long screen_info_offset;
+static unsigned long kernel_image_offset;
+
+static void *kernel_image_addr(void *addr)
+{
+ return addr + kernel_image_offset;
+}
struct screen_info *alloc_screen_info(void)
{
@@ -16,8 +21,11 @@ struct screen_info *alloc_screen_info(void)
if (IS_ENABLED(CONFIG_X86) ||
IS_ENABLED(CONFIG_EFI_EARLYCON) ||
- IS_ENABLED(CONFIG_SYSFB))
- return (void *)&screen_info + screen_info_offset;
+ IS_ENABLED(CONFIG_SYSFB)) {
+ struct sysfb_display_info *dpy = kernel_image_addr(&sysfb_primary_display);
+
+ return &dpy->screen;
+ }
return NULL;
}
@@ -73,7 +81,7 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
return status;
}
- screen_info_offset = image_addr - (unsigned long)image->image_base;
+ kernel_image_offset = image_addr - (unsigned long)image->image_base;
status = efi_stub_common(handle, image, image_addr, cmdline_ptr);
diff --git a/drivers/firmware/efi/sysfb_efi.c b/drivers/firmware/efi/sysfb_efi.c
index 8e0f9d08397f..46ad95084b50 100644
--- a/drivers/firmware/efi/sysfb_efi.c
+++ b/drivers/firmware/efi/sysfb_efi.c
@@ -176,7 +176,7 @@ static int __init efifb_set_system(struct screen_info *si, const struct dmi_syst
static int __init efifb_set_system_callback(const struct dmi_system_id *id)
{
- return efifb_set_system(&screen_info, id);
+ return efifb_set_system(&sysfb_primary_display.screen, id);
}
#define EFIFB_DMI_SYSTEM_ID(vendor, name, enumid) \
@@ -316,7 +316,7 @@ static struct device_node *find_pci_overlap_node(void)
}
for_each_of_pci_range(&parser, &range)
- if (efifb_overlaps_pci_range(&screen_info, &range))
+ if (efifb_overlaps_pci_range(&sysfb_primary_display.screen, &range))
return np;
}
return NULL;
diff --git a/drivers/firmware/sysfb.c b/drivers/firmware/sysfb.c
index 916b28538a29..1f671f9219b0 100644
--- a/drivers/firmware/sysfb.c
+++ b/drivers/firmware/sysfb.c
@@ -66,7 +66,7 @@ static bool sysfb_unregister(void)
*/
void sysfb_disable(struct device *dev)
{
- struct screen_info *si = &screen_info;
+ struct screen_info *si = &sysfb_primary_display.screen;
struct device *parent;
mutex_lock(&disable_lock);
@@ -92,7 +92,7 @@ EXPORT_SYMBOL_GPL(sysfb_disable);
*/
bool sysfb_handles_screen_info(void)
{
- const struct screen_info *si = &screen_info;
+ const struct screen_info *si = &sysfb_primary_display.screen;
return !!screen_info_video_type(si);
}
@@ -141,7 +141,7 @@ static struct device *sysfb_parent_dev(const struct screen_info *si)
static __init int sysfb_init(void)
{
- struct screen_info *si = &screen_info;
+ struct screen_info *si = &sysfb_primary_display.screen;
struct device *parent;
unsigned int type;
struct simplefb_platform_data mode;
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index 69591dc7bad2..e7ebfa4cee45 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -29,7 +29,7 @@
#include <linux/delay.h>
#include <linux/panic_notifier.h>
#include <linux/ptrace.h>
-#include <linux/screen_info.h>
+#include <linux/sysfb.h>
#include <linux/efi.h>
#include <linux/random.h>
#include <linux/kernel.h>
@@ -2282,8 +2282,8 @@ static void __maybe_unused vmbus_reserve_fb(void)
if (efi_enabled(EFI_BOOT)) {
/* Gen2 VM: get FB base from EFI framebuffer */
if (IS_ENABLED(CONFIG_SYSFB)) {
- start = screen_info.lfb_base;
- size = max_t(__u32, screen_info.lfb_size, 0x800000);
+ start = sysfb_primary_display.screen.lfb_base;
+ size = max_t(__u32, sysfb_primary_display.screen.lfb_size, 0x800000);
}
} else {
/* Gen1 VM: get FB base from PCI */
diff --git a/drivers/pci/vgaarb.c b/drivers/pci/vgaarb.c
index 436fa7f4c387..805be9ea4a34 100644
--- a/drivers/pci/vgaarb.c
+++ b/drivers/pci/vgaarb.c
@@ -26,7 +26,7 @@
#include <linux/poll.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
-#include <linux/screen_info.h>
+#include <linux/sysfb.h>
#include <linux/vt.h>
#include <linux/console.h>
#include <linux/acpi.h>
@@ -557,7 +557,7 @@ EXPORT_SYMBOL(vga_put);
static bool vga_is_firmware_default(struct pci_dev *pdev)
{
#if defined CONFIG_X86
- return pdev == screen_info_pci_dev(&screen_info);
+ return pdev == screen_info_pci_dev(&sysfb_primary_display.screen);
#else
return false;
#endif
diff --git a/drivers/video/screen_info_pci.c b/drivers/video/screen_info_pci.c
index 66bfc1d0a6dc..8f34d8a74f09 100644
--- a/drivers/video/screen_info_pci.c
+++ b/drivers/video/screen_info_pci.c
@@ -4,6 +4,7 @@
#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;
@@ -26,7 +27,7 @@ static bool __screen_info_relocation_is_valid(const struct screen_info *si, stru
void screen_info_apply_fixups(void)
{
- struct screen_info *si = &screen_info;
+ 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];
@@ -75,7 +76,7 @@ static void screen_info_fixup_lfb(struct pci_dev *pdev)
.flags = IORESOURCE_MEM,
};
const struct resource *pr;
- const struct screen_info *si = &screen_info;
+ const struct screen_info *si = &sysfb_primary_display.screen;
if (screen_info_lfb_pdev)
return; // already found
diff --git a/include/linux/screen_info.h b/include/linux/screen_info.h
index 1690706206e8..c022403c599a 100644
--- a/include/linux/screen_info.h
+++ b/include/linux/screen_info.h
@@ -151,6 +151,4 @@ static inline struct pci_dev *screen_info_pci_dev(const struct screen_info *si)
}
#endif
-extern struct screen_info screen_info;
-
#endif /* _SCREEN_INFO_H */
diff --git a/include/linux/sysfb.h b/include/linux/sysfb.h
index 8b37247528bf..e8bde392c690 100644
--- a/include/linux/sysfb.h
+++ b/include/linux/sysfb.h
@@ -8,11 +8,10 @@
*/
#include <linux/err.h>
+#include <linux/platform_data/simplefb.h>
#include <linux/screen_info.h>
#include <linux/types.h>
-#include <linux/platform_data/simplefb.h>
-
struct device;
struct platform_device;
struct screen_info;
@@ -65,6 +64,8 @@ struct sysfb_display_info {
struct screen_info screen;
};
+extern struct sysfb_display_info sysfb_primary_display;
+
#ifdef CONFIG_SYSFB
void sysfb_disable(struct device *dev);
--
2.51.1
^ permalink raw reply related
* [PATCH 1/6] efi: earlycon: Reduce number of references to global screen_info
From: Thomas Zimmermann @ 2025-11-21 13:36 UTC (permalink / raw)
To: ardb, javierm, arnd
Cc: x86, linux-arm-kernel, linux-kernel, linux-efi, loongarch,
linux-riscv, dri-devel, linux-hyperv, linux-pci, linux-fbdev,
Thomas Zimmermann
In-Reply-To: <20251121135624.494768-1-tzimmermann@suse.de>
Replace usage of global screen_info with local pointers. This will
later reduce churn when screen_info is being moved.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/firmware/efi/earlycon.c | 40 ++++++++++++++++-----------------
1 file changed, 20 insertions(+), 20 deletions(-)
diff --git a/drivers/firmware/efi/earlycon.c b/drivers/firmware/efi/earlycon.c
index d18a1a5de144..fac3a295c57f 100644
--- a/drivers/firmware/efi/earlycon.c
+++ b/drivers/firmware/efi/earlycon.c
@@ -32,12 +32,13 @@ static void *efi_fb;
*/
static int __init efi_earlycon_remap_fb(void)
{
+ const struct screen_info *si = &screen_info;
+
/* bail if there is no bootconsole or it was unregistered already */
if (!earlycon_console || !console_is_registered(earlycon_console))
return 0;
- efi_fb = memremap(fb_base, screen_info.lfb_size,
- fb_wb ? MEMREMAP_WB : MEMREMAP_WC);
+ efi_fb = memremap(fb_base, si->lfb_size, fb_wb ? MEMREMAP_WB : MEMREMAP_WC);
return efi_fb ? 0 : -ENOMEM;
}
@@ -71,12 +72,12 @@ static __ref void efi_earlycon_unmap(void *addr, unsigned long len)
early_memunmap(addr, len);
}
-static void efi_earlycon_clear_scanline(unsigned int y)
+static void efi_earlycon_clear_scanline(unsigned int y, const struct screen_info *si)
{
unsigned long *dst;
u16 len;
- len = screen_info.lfb_linelength;
+ len = si->lfb_linelength;
dst = efi_earlycon_map(y*len, len);
if (!dst)
return;
@@ -85,7 +86,7 @@ static void efi_earlycon_clear_scanline(unsigned int y)
efi_earlycon_unmap(dst, len);
}
-static void efi_earlycon_scroll_up(void)
+static void efi_earlycon_scroll_up(const struct screen_info *si)
{
unsigned long *dst, *src;
u16 maxlen = 0;
@@ -99,8 +100,8 @@ static void efi_earlycon_scroll_up(void)
}
maxlen *= 4;
- len = screen_info.lfb_linelength;
- height = screen_info.lfb_height;
+ len = si->lfb_linelength;
+ height = si->lfb_height;
for (i = 0; i < height - font->height; i++) {
dst = efi_earlycon_map(i*len, len);
@@ -120,7 +121,8 @@ static void efi_earlycon_scroll_up(void)
}
}
-static void efi_earlycon_write_char(u32 *dst, unsigned char c, unsigned int h)
+static void efi_earlycon_write_char(u32 *dst, unsigned char c, unsigned int h,
+ const struct screen_info *si)
{
const u32 color_black = 0x00000000;
const u32 color_white = 0x00ffffff;
@@ -145,13 +147,12 @@ static void efi_earlycon_write_char(u32 *dst, unsigned char c, unsigned int h)
static void
efi_earlycon_write(struct console *con, const char *str, unsigned int num)
{
- struct screen_info *si;
+ const struct screen_info *si = &screen_info;
u32 cur_efi_x = efi_x;
unsigned int len;
const char *s;
void *dst;
- si = &screen_info;
len = si->lfb_linelength;
while (num) {
@@ -174,7 +175,7 @@ efi_earlycon_write(struct console *con, const char *str, unsigned int num)
x = efi_x;
while (n-- > 0) {
- efi_earlycon_write_char(dst + x*4, *s, h);
+ efi_earlycon_write_char(dst + x*4, *s, h, si);
x += font->width;
s++;
}
@@ -207,10 +208,10 @@ efi_earlycon_write(struct console *con, const char *str, unsigned int num)
cur_line_y = (cur_line_y + 1) % max_line_y;
efi_y -= font->height;
- efi_earlycon_scroll_up();
+ efi_earlycon_scroll_up(si);
for (i = 0; i < font->height; i++)
- efi_earlycon_clear_scanline(efi_y + i);
+ efi_earlycon_clear_scanline(efi_y + i, si);
}
}
}
@@ -226,22 +227,21 @@ void __init efi_earlycon_reprobe(void)
static int __init efi_earlycon_setup(struct earlycon_device *device,
const char *opt)
{
- struct screen_info *si;
+ const struct screen_info *si = &screen_info;
u16 xres, yres;
u32 i;
fb_wb = opt && !strcmp(opt, "ram");
- if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI) {
+ if (si->orig_video_isVGA != VIDEO_TYPE_EFI) {
fb_probed = true;
return -ENODEV;
}
- fb_base = screen_info.lfb_base;
- if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE)
- fb_base |= (u64)screen_info.ext_lfb_base << 32;
+ fb_base = si->lfb_base;
+ if (si->capabilities & VIDEO_CAPABILITY_64BIT_BASE)
+ fb_base |= (u64)si->ext_lfb_base << 32;
- si = &screen_info;
xres = si->lfb_width;
yres = si->lfb_height;
@@ -266,7 +266,7 @@ static int __init efi_earlycon_setup(struct earlycon_device *device,
efi_y -= font->height;
for (i = 0; i < (yres - efi_y) / font->height; i++)
- efi_earlycon_scroll_up();
+ efi_earlycon_scroll_up(si);
device->con->write = efi_earlycon_write;
earlycon_console = device->con;
--
2.51.1
^ permalink raw reply related
* [PATCH 0/6] arch,sysfb: Move screen and edid info into single place
From: Thomas Zimmermann @ 2025-11-21 13:36 UTC (permalink / raw)
To: ardb, javierm, arnd
Cc: x86, linux-arm-kernel, linux-kernel, linux-efi, loongarch,
linux-riscv, dri-devel, linux-hyperv, linux-pci, linux-fbdev,
Thomas Zimmermann
Replace screen_info and edid_info with sysfb_primary_device of type
struct sysfb_display_info. Update all users.
Sysfb DRM drivers currently fetch the global edid_info directly, when
they should get that information together with the screen_info from their
device. Wrapping screen_info and edid_info in sysfb_primary_display and
passing this to drivers enables this.
Replacing both with sysfb_primary_display has been motivate by the EFI
stub. EFI wants to transfer EDID via config table in a single entry.
Using struct sysfb_display_info this will become easily possible. Hence
accept some churn in architecture code for the long-term improvements.
Patches 1 and 2 reduce the exposure of screen_info in EFI-related code.
Patch 3 adds struct sysfb_display_info.
Patch 4 replaces scren_info with sysfb_primary_display. This results in
several changes throught the kernel, but is really just a refactoring.
Patch 5 updates sysfb to transfer sysfb_primary_display to the related
drivers.
Patch 6 moves edid_info into sysfb_primary_display. This resolves some
drivers' reference to the global edid_info, but also makes the EDID data
available on non-x86 architectures.
The short-term benefit of this series is in patches 5 and 6. With
sysfb_primary_display in place a follow-up series will improve EFI support
for EDID as outlined in the series at [1] and [2].
[1] https://lore.kernel.org/dri-devel/20251015160816.525825-1-tzimmermann@suse.de/
[2] https://lore.kernel.org/linux-efi/20251119123011.1187249-5-ardb+git@google.com/
Thomas Zimmermann (6):
efi: earlycon: Reduce number of references to global screen_info
efi: sysfb_efi: Reduce number of references to global screen_info
sysfb: Add struct sysfb_display_info
sysfb: Replace screen_info with sysfb_primary_display
sysfb: Pass sysfb_primary_display to devices
sysfb: Move edid_info into sysfb_primary_display
arch/arm64/kernel/image-vars.h | 2 +-
arch/loongarch/kernel/efi.c | 11 +--
arch/loongarch/kernel/image-vars.h | 2 +-
arch/riscv/kernel/image-vars.h | 2 +-
arch/x86/kernel/kexec-bzimage64.c | 4 +-
arch/x86/kernel/setup.c | 16 ++--
arch/x86/video/video-common.c | 4 +-
drivers/firmware/efi/earlycon.c | 42 +++++-----
drivers/firmware/efi/efi-init.c | 14 ++--
drivers/firmware/efi/libstub/efi-stub-entry.c | 18 +++--
drivers/firmware/efi/sysfb_efi.c | 81 ++++++++++---------
drivers/firmware/sysfb.c | 13 +--
drivers/firmware/sysfb_simplefb.c | 2 +-
drivers/gpu/drm/sysfb/efidrm.c | 14 ++--
drivers/gpu/drm/sysfb/vesadrm.c | 14 ++--
drivers/hv/vmbus_drv.c | 6 +-
drivers/pci/vgaarb.c | 4 +-
drivers/video/Kconfig | 1 -
drivers/video/fbdev/core/fbmon.c | 8 +-
drivers/video/fbdev/efifb.c | 10 ++-
drivers/video/fbdev/vesafb.c | 10 ++-
drivers/video/fbdev/vga16fb.c | 8 +-
drivers/video/screen_info_pci.c | 5 +-
include/linux/screen_info.h | 2 -
include/linux/sysfb.h | 23 ++++--
include/video/edid.h | 4 -
26 files changed, 177 insertions(+), 143 deletions(-)
base-commit: 57e807d4454add8b60e8807ad1cf812141f34cdb
--
2.51.1
^ permalink raw reply
* Re: [RFC/RFT PATCH] fbdev: q40fb: request memory region
From: Helge Deller @ 2025-11-21 10:17 UTC (permalink / raw)
To: Geert Uytterhoeven, Sukrut Heroorkar
Cc: open list:FRAMEBUFFER LAYER, open list:FRAMEBUFFER LAYER, shuah,
david.hunter.linux, linux-m68k
In-Reply-To: <CAMuHMdV3UvDHT0uu8oeiCGc9pURaLPDPmG-Fu9kC9H8DQyqRDw@mail.gmail.com>
Hi Geert & Sukrut,
On 11/21/25 11:03, Geert Uytterhoeven wrote:
> On Thu, 20 Nov 2025 at 19:03, Sukrut Heroorkar <hsukrut3@gmail.com> wrote:
>> The q40fb driver uses a fixed physical address but never reserves
>> the corresponding I/O region. Reserve the range as suggested in
>> Documentation/gpu/todo.rst ("Request memory regions in all fbdev drivers").
>>
>> If the memory cannot be reserved, fail probe with -EBUSY to avoid
>> conflicting with another user of the same address.
>>
>> Signed-off-by: Sukrut Heroorkar <hsukrut3@gmail.com>
>
> Thanks for your patch!
>
>> ---
>> Testing: This patch is sent as RFT since Q40 hardware is unavilable and
>> QEMU does not emulated a Q40 platform. The change is therefore compile-tested
>> only.
>
> I would suggest not to apply this, unless it is tested on real
> hardware. It wouldn't be the first time an innocent-looking change like
> this breaks a system. See e.g.
> https://lore.kernel.org/all/Y5I2oQexHNdlIbsQ@shell.armlinux.org.uk
Geert, that's actually my thought as well, so I'm happy you wrote down
your opinion here!
By any chance, do you (or someone on this list) know of someone who has
that card and might be able to test it?
Helge
>> --- a/drivers/video/fbdev/q40fb.c
>> +++ b/drivers/video/fbdev/q40fb.c
>> @@ -101,6 +101,13 @@ static int q40fb_probe(struct platform_device *dev)
>> info->par = NULL;
>> info->screen_base = (char *) q40fb_fix.smem_start;
>>
>> + if (!request_mem_region(q40fb_fix.smem_start, q40fb_fix.smem_len,
>> + "q40fb")) {
>> + dev_err(&dev->dev, "cannot reserve video memory at 0x%lx\n",
>> + q40fb_fix.smem_start);
>> + return -EBUSY;
>> + }
>> +
>> if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
>> framebuffer_release(info);
>> return -ENOMEM;
^ permalink raw reply
* Re: [RFC/RFT PATCH] fbdev: q40fb: request memory region
From: Geert Uytterhoeven @ 2025-11-21 10:03 UTC (permalink / raw)
To: Sukrut Heroorkar
Cc: Helge Deller, open list:FRAMEBUFFER LAYER,
open list:FRAMEBUFFER LAYER, open list, shuah, david.hunter.linux,
linux-m68k
In-Reply-To: <20251120180233.763975-1-hsukrut3@gmail.com>
Hi Sukrut,
CC linux-m68k
On Thu, 20 Nov 2025 at 19:03, Sukrut Heroorkar <hsukrut3@gmail.com> wrote:
> The q40fb driver uses a fixed physical address but never reserves
> the corresponding I/O region. Reserve the range as suggested in
> Documentation/gpu/todo.rst ("Request memory regions in all fbdev drivers").
>
> If the memory cannot be reserved, fail probe with -EBUSY to avoid
> conflicting with another user of the same address.
>
> Signed-off-by: Sukrut Heroorkar <hsukrut3@gmail.com>
Thanks for your patch!
> ---
> Testing: This patch is sent as RFT since Q40 hardware is unavilable and
> QEMU does not emulated a Q40 platform. The change is therefore compile-tested
> only.
I would suggest not to apply this, unless it is tested on real
hardware. It wouldn't be the first time an innocent-looking change like
this breaks a system. See e.g.
https://lore.kernel.org/all/Y5I2oQexHNdlIbsQ@shell.armlinux.org.uk
> --- a/drivers/video/fbdev/q40fb.c
> +++ b/drivers/video/fbdev/q40fb.c
> @@ -101,6 +101,13 @@ static int q40fb_probe(struct platform_device *dev)
> info->par = NULL;
> info->screen_base = (char *) q40fb_fix.smem_start;
>
> + if (!request_mem_region(q40fb_fix.smem_start, q40fb_fix.smem_len,
> + "q40fb")) {
> + dev_err(&dev->dev, "cannot reserve video memory at 0x%lx\n",
> + q40fb_fix.smem_start);
> + return -EBUSY;
> + }
> +
> if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
> framebuffer_release(info);
> return -ENOMEM;
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* [PATCH] backlight: aw99706: Fix unused function warnings from suspend/resume ops
From: Nathan Chancellor @ 2025-11-20 20:22 UTC (permalink / raw)
To: Lee Jones, Daniel Thompson, Jingoo Han, Helge Deller, Pengyu Luo,
Junjie Cao
Cc: dri-devel, linux-fbdev, patches, Nathan Chancellor
When building for a platform without CONFIG_PM_SLEEP, such as s390,
there are two unused function warnings:
drivers/video/backlight/aw99706.c:436:12: error: 'aw99706_resume' defined but not used [-Werror=unused-function]
436 | static int aw99706_resume(struct device *dev)
| ^~~~~~~~~~~~~~
drivers/video/backlight/aw99706.c:429:12: error: 'aw99706_suspend' defined but not used [-Werror=unused-function]
429 | static int aw99706_suspend(struct device *dev)
| ^~~~~~~~~~~~~~~
SET_SYSTEM_SLEEP_PM_OPS, used within SIMPLE_DEV_PM_OPS, expands to
nothing when CONFIG_PM_SLEEP is not set, so these functions are
completely unused in this configuration.
SIMPLE_DEV_PM_OPS is deprecated in favor of DEFINE_SIMPLE_DEV_PM_OPS,
which avoids this issue by using pm_sleep_ptr to make these callbacks
NULL when CONFIG_PM_SLEEP is unset while making the callback functions
always appear used to the compiler regardless of configuration. Switch
to DEFINE_SIMPLE_DEV_PM_OPS for aw99706_pm_ops to clear up the warning.
Additionally, wrap the pointer to aw99706_pm_ops in pm_ptr() in
aw99706_i2c_driver to ensure that the structure is completely eliminated
in configurations without CONFIG_PM.
Fixes: 88a8e9b49ee8 ("backlight: aw99706: Add support for Awinic AW99706 backlight")
Signed-off-by: Nathan Chancellor <nathan@kernel.org>
---
drivers/video/backlight/aw99706.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/video/backlight/aw99706.c b/drivers/video/backlight/aw99706.c
index b7c1d24b17ac..df5b23b2f753 100644
--- a/drivers/video/backlight/aw99706.c
+++ b/drivers/video/backlight/aw99706.c
@@ -440,7 +440,7 @@ static int aw99706_resume(struct device *dev)
return aw99706_hw_init(aw);
}
-static SIMPLE_DEV_PM_OPS(aw99706_pm_ops, aw99706_suspend, aw99706_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(aw99706_pm_ops, aw99706_suspend, aw99706_resume);
static const struct i2c_device_id aw99706_ids[] = {
{ "aw99706" },
@@ -461,7 +461,7 @@ static struct i2c_driver aw99706_i2c_driver = {
.driver = {
.name = "aw99706",
.of_match_table = aw99706_match_table,
- .pm = &aw99706_pm_ops,
+ .pm = pm_ptr(&aw99706_pm_ops),
},
};
---
base-commit: 1704e206cb98c5e43af1483e3b07450055a31008
change-id: 20251120-backlight-aw99706-fix-unused-pm-functions-fe2775c4dec6
Best regards,
--
Nathan Chancellor <nathan@kernel.org>
^ permalink raw reply related
* [RFC/RFT PATCH] fbdev: q40fb: request memory region
From: Sukrut Heroorkar @ 2025-11-20 18:02 UTC (permalink / raw)
To: Helge Deller, Sukrut Heroorkar, open list:FRAMEBUFFER LAYER,
open list:FRAMEBUFFER LAYER, open list
Cc: shuah, david.hunter.linux
The q40fb driver uses a fixed physical address but never reserves
the corresponding I/O region. Reserve the range as suggested in
Documentation/gpu/todo.rst ("Request memory regions in all fbdev drivers").
If the memory cannot be reserved, fail probe with -EBUSY to avoid
conflicting with another user of the same address.
Signed-off-by: Sukrut Heroorkar <hsukrut3@gmail.com>
---
Testing: This patch is sent as RFT since Q40 hardware is unavilable and
QEMU does not emulated a Q40 platform. The change is therefore compile-tested
only.
drivers/video/fbdev/q40fb.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/video/fbdev/q40fb.c b/drivers/video/fbdev/q40fb.c
index 1ff8fa176124..7b5c31745041 100644
--- a/drivers/video/fbdev/q40fb.c
+++ b/drivers/video/fbdev/q40fb.c
@@ -101,6 +101,13 @@ static int q40fb_probe(struct platform_device *dev)
info->par = NULL;
info->screen_base = (char *) q40fb_fix.smem_start;
+ if (!request_mem_region(q40fb_fix.smem_start, q40fb_fix.smem_len,
+ "q40fb")) {
+ dev_err(&dev->dev, "cannot reserve video memory at 0x%lx\n",
+ q40fb_fix.smem_start);
+ return -EBUSY;
+ }
+
if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
framebuffer_release(info);
return -ENOMEM;
--
2.43.0
^ permalink raw reply related
* Re: [PATCH] fbdev: q40fb: request memory region
From: sukrut heroorkar @ 2025-11-20 18:00 UTC (permalink / raw)
To: David Hunter
Cc: Helge Deller, open list:FRAMEBUFFER LAYER,
open list:FRAMEBUFFER LAYER, open list, shuah
In-Reply-To: <4ec784a5-0f67-4fd3-9d51-d89a9fa9a385@gmail.com>
On Wed, Nov 19, 2025 at 7:27 PM David Hunter
<david.hunter.linux@gmail.com> wrote:
>
> On 11/18/25 04:56, Sukrut Heroorkar wrote:
> > The q40fb driver uses a fixed physical address but never reserves
> > the corresponding I/O region. Reserve the range as suggested in
> > Documentation/gpu/todo.rst ("Request memory regions in all fbdev drivers").
> >
> > No functional change beyond claming the resource. This change is compile
> > tested only.
>
> Reserving memory is a significant "functional" change, so you should not
> put "No functional change...". I have noticed that in the mentorship
> program, mentees might say this often times when they have not done
> testing.
>
> Thank you for describing that you did a compile test, but I believe that
> more testing should be done before this patch is accepted.
qemu-system-m68k does not emulate a Q40 machine, thus the change
was compile tested only with W=1 & debugging enabled.
>
> As a result, if you are unable to test this device, I believe that an
> RFT tag should be used. Also, the testing information goes below the
> "---". This puts it in the change log and would make it so that if a
> patch is accepted, everything below the change log is not put in the
> commit message.
Thank you. I will make a note of this for the future patches.
> >
> > Signed-off-by: Sukrut Heroorkar <hsukrut3@gmail.com>
> > ---
> > drivers/video/fbdev/q40fb.c | 7 +++++++
> > 1 file changed, 7 insertions(+)
> >
> > diff --git a/drivers/video/fbdev/q40fb.c b/drivers/video/fbdev/q40fb.c
> > index 1ff8fa176124..935260326c6f 100644
> > --- a/drivers/video/fbdev/q40fb.c
> > +++ b/drivers/video/fbdev/q40fb.c
> > @@ -101,6 +101,12 @@ static int q40fb_probe(struct platform_device *dev)
> > info->par = NULL;
> > info->screen_base = (char *) q40fb_fix.smem_start;
> >
> > + if (!request_mem_region(q40fb_fix.smem_start, q40fb_fix.smem_len,
> > + "q40fb")) {
> > + dev_err(&dev->dev, "cannot reserve video memory at 0x%lx\n",
> > + q40fb_fix.smem_start);
> > + }
> > +
>
> Is this correct? It seems to me that in the case of an error, all you
> are doing is simply logging the error and proceeding. Would this cause
> the device to continue to try to use space that it was not able to
> reserve? I do not have experience with this device or the driver, but
> that does not seem correct to me.
I referred to a patch, which was recently accepted, having a similar
implementation.
However, other fbdev drivers with similar implementation, returns a
-EBUSY when the
If() evaluates true indicating resource already being occupied. I
will make the necessary
changes and resend the patch as RFT.
>
> > if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
> > framebuffer_release(info);
> > return -ENOMEM;
> > @@ -144,6 +150,7 @@ static int __init q40fb_init(void)
> > if (ret)
> > platform_driver_unregister(&q40fb_driver);
> > }
> > +
> > return ret;
> > }
> >
>
^ permalink raw reply
* Re: [PATCH v2 1/2] backlight: Add Congatec Board Controller (CGBC) backlight support
From: Krzysztof Kozlowski @ 2025-11-20 14:09 UTC (permalink / raw)
To: petri.karhula, Thomas Richard, Lee Jones, Daniel Thompson,
Jingoo Han, Helge Deller
Cc: linux-kernel, dri-devel, linux-fbdev
In-Reply-To: <20251119-cgbc-backlight-v2-1-4d4edd7ca662@novatron.fi>
On 19/11/2025 09:25, Petri Karhula via B4 Relay wrote:
> +}
> +
> +/**
> + * Remove function for CGBC backlight driver
> + * @pdev: Platform device
> + *
> + * The Linux device-managed resource framework (devres) does the cleanup.
> + * No explicit cleanup is needed here.
> + */
> +static void cgbc_bl_remove(struct platform_device *pdev)
> +{
> + dev_info(&pdev->dev, "CGBC backlight driver removed\n");
> +}
I reviewed v1, but all comments are applicable.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH] backlight: Add Congatec Board Controller (CGBC) backlight support
From: Krzysztof Kozlowski @ 2025-11-20 14:09 UTC (permalink / raw)
To: petri.karhula, Thomas Richard, Lee Jones, Daniel Thompson,
Jingoo Han, Helge Deller
Cc: linux-kernel, dri-devel, linux-fbdev
In-Reply-To: <20251118-cgbc-backlight-v1-1-cc6ac5301034@novatron.fi>
On 18/11/2025 17:43, Petri Karhula via B4 Relay wrote:
> +
> +/**
> + * Get current backlight brightness
> + * @bl: Backlight device
> + *
> + * Returns the current brightness level by reading from hardware.
> + *
> + * Return: Current brightness level (0-100), or negative error code
> + */
Why are you documenting standard API?
> +static int cgbc_bl_get_brightness(struct backlight_device *bl)
> +{
> + struct cgbc_bl_data *bl_data = bl_get_data(bl);
> + int ret;
> +
> + /* Read current PWM brightness settings */
> + ret = cgbc_bl_read_pwm_settings(bl_data);
> +
> + if (ret < 0) {
> + dev_err(bl_data->dev, "Failed to read PWM settings: %d\n", ret);
> + return ret;
> + }
> +
> + return bl_data->current_brightness;
> +}
> +
> +/* Backlight device operations */
Huh? Can it be a GPIO device operations?
> +static const struct backlight_ops cgbc_bl_ops = {
> + .options = BL_CORE_SUSPENDRESUME,
> + .update_status = cgbc_bl_update_status,
> + .get_brightness = cgbc_bl_get_brightness,
> +};
> +
> +/**
> + * Probe function for CGBC backlight driver
> + * @pdev: Platform device
> + *
> + * Initializes the CGBC backlight driver and registers it with the
> + * Linux backlight subsystem.
> + *
> + * Return: 0 on success, negative error code on failure
Very redundant and useless comment.
> + */
> +static int cgbc_bl_probe(struct platform_device *pdev)
> +{
> + struct cgbc_device_data *cgbc = dev_get_drvdata(pdev->dev.parent);
> + struct cgbc_bl_data *bl_data;
> + struct backlight_properties props;
> + struct backlight_device *bl_dev;
> + int ret;
> +
> + bl_data = devm_kzalloc(&pdev->dev, sizeof(*bl_data), GFP_KERNEL);
> +
Drop blank line. There is never such line between allocation and check.
> + if (!bl_data)
> + return -ENOMEM;
> +
> + bl_data->dev = &pdev->dev;
> + bl_data->cgbc = cgbc;
> +
> + ret = cgbc_bl_read_pwm_settings(bl_data);
> +
> + if (ret) {
> + dev_err(&pdev->dev, "Failed to read initial PWM settings: %d\n",
> + ret);
return dev_err_probe
> + return ret;
> + }
> +
> + memset(&props, 0, sizeof(props));
> + props.type = BACKLIGHT_PLATFORM;
> + props.max_brightness = CGBC_BL_MAX_BRIGHTNESS;
> + props.brightness = bl_data->current_brightness;
> +
> + bl_dev = devm_backlight_device_register(&pdev->dev, "cgbc-backlight",
> + &pdev->dev, bl_data,
> + &cgbc_bl_ops, &props);
> +
> + if (IS_ERR(bl_dev)) {
> + dev_err(&pdev->dev, "Failed to register backlight device\n");
return dev_err_probe
> + return PTR_ERR(bl_dev);
> + }
> +
> + bl_data->bl_dev = bl_dev;
> + platform_set_drvdata(pdev, bl_data);
> +
> + dev_info(&pdev->dev,
> + "CGBC backlight driver registered (brightness=%u)\n",
> + bl_data->current_brightness);
Drop.
This does not look like useful printk message. Drivers should be silent
on success:
https://elixir.bootlin.com/linux/v6.15-rc7/source/Documentation/process/coding-style.rst#L913
https://elixir.bootlin.com/linux/v6.15-rc7/source/Documentation/process/debugging/driver_development_debugging_guide.rst#L79
> +
> + return 0;
> +}
> +
> +/**
> + * Remove function for CGBC backlight driver
> + * @pdev: Platform device
> + *
> + * The Linux device-managed resource framework (devres) does the cleanup.
> + * No explicit cleanup is needed here.
Drop such comments, they are not useful. Please write only useful
comments, not ones stating obvious.
> + */
> +static void cgbc_bl_remove(struct platform_device *pdev)
> +{
> + dev_info(&pdev->dev, "CGBC backlight driver removed\n");
Drop, there is no such code in Linux kernel. Drop it.
> +}
> +
Best regards,
Krzysztof
^ permalink raw reply
* [PATCH] fbdev/tcx.c fix mem_map to correct smem_start offset
From: René Rebe @ 2025-11-20 13:24 UTC (permalink / raw)
To: linux-fbdev; +Cc: Helge Deller
403ae52ac047 ("sparc: fix drivers/video/tcx.c warning") changed the
physbase initializing breaking the user-space mmap, e.g. for Xorg
entirely.
Fix fbdev mmap table so the sbus mmap helper work correctly, and
not try to map vastly (physbase) offset memory.
Fixes: 403ae52ac047 ("sparc: fix drivers/video/tcx.c warning")
Signed-off-by: René Rebe <rene@exactco.de>
---
drivers/video/fbdev/tcx.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/video/fbdev/tcx.c b/drivers/video/fbdev/tcx.c
index f9a0085ad72b..ca9e84e8d860 100644
--- a/drivers/video/fbdev/tcx.c
+++ b/drivers/video/fbdev/tcx.c
@@ -428,7 +428,7 @@ static int tcx_probe(struct platform_device *op)
j = i;
break;
}
- par->mmap_map[i].poff = op->resource[j].start;
+ par->mmap_map[i].poff = op->resource[j].start - info->fix.smem_start;
}
info->fbops = &tcx_ops;
--
2.46.0
--
René Rebe, ExactCODE GmbH, Berlin, Germany
https://exactco.de • https://t2linux.com • https://patreon.com/renerebe
^ permalink raw reply related
* Re: [PATCH] fbdev: core: Fix vmalloc-out-of-bounds in fb_imageblit
From: kernel test robot @ 2025-11-20 9:23 UTC (permalink / raw)
To: ssrane_b23, Zsolt Kajtar, Simona Vetter, Helge Deller
Cc: oe-kbuild-all, Shaurya Rane, linux-fbdev, dri-devel, linux-kernel,
syzbot+5a40432dfe8f86ee657a
In-Reply-To: <20251119133821.89998-1-ssranevjti@gmail.com>
Hi,
kernel test robot noticed the following build warnings:
[auto build test WARNING on drm-misc/drm-misc-next]
[also build test WARNING on drm-tip/drm-tip linus/master v6.18-rc6 next-20251119]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/ssrane_b23-ee-vjti-ac-in/fbdev-core-Fix-vmalloc-out-of-bounds-in-fb_imageblit/20251119-215054
base: git://anongit.freedesktop.org/drm/drm-misc drm-misc-next
patch link: https://lore.kernel.org/r/20251119133821.89998-1-ssranevjti%40gmail.com
patch subject: [PATCH] fbdev: core: Fix vmalloc-out-of-bounds in fb_imageblit
config: nios2-randconfig-r073-20251120 (https://download.01.org/0day-ci/archive/20251120/202511201752.4fVbQwPc-lkp@intel.com/config)
compiler: nios2-linux-gcc (GCC) 10.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251120/202511201752.4fVbQwPc-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202511201752.4fVbQwPc-lkp@intel.com/
All warnings (new ones prefixed by >>):
In file included from drivers/video/fbdev/core/cfbimgblt.c:17:
drivers/video/fbdev/core/fb_imageblit.h: In function 'fb_imageblit':
>> drivers/video/fbdev/core/fb_imageblit.h:490:16: warning: unused variable 'max_offset_bytes' [-Wunused-variable]
490 | unsigned long max_offset_bytes;
| ^~~~~~~~~~~~~~~~
vim +/max_offset_bytes +490 drivers/video/fbdev/core/fb_imageblit.h
480
481 static inline void fb_imageblit(struct fb_info *p, const struct fb_image *image)
482 {
483 int bpp = p->var.bits_per_pixel;
484 unsigned int bits_per_line = BYTES_TO_BITS(p->fix.line_length);
485 struct fb_address dst = fb_address_init(p);
486 struct fb_reverse reverse = fb_reverse_init(p);
487 const u32 *palette = fb_palette(p);
488 struct fb_image clipped_image;
489 u32 max_x, max_y;
> 490 unsigned long max_offset_bytes;
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH v2 1/2] backlight: Add Congatec Board Controller (CGBC) backlight support
From: Thomas Richard @ 2025-11-20 9:09 UTC (permalink / raw)
To: petri.karhula, Lee Jones, Daniel Thompson, Jingoo Han,
Helge Deller
Cc: linux-kernel, dri-devel, linux-fbdev
In-Reply-To: <20251119-cgbc-backlight-v2-1-4d4edd7ca662@novatron.fi>
Hello Petri,
Thanks for your patch.
On 11/19/25 9:25 AM, Petri Karhula via B4 Relay wrote:
> From: Petri Karhula <petri.karhula@novatron.fi>
>
> This driver provides backlight brightness control through the Linux
> backlight subsystem. It communicates with the board controller to
> adjust LCD backlight using PWM signals. Communication is done
> through Congatec Board Controller core driver.
>
> Signed-off-by: Petri Karhula <petri.karhula@novatron.fi>
> ---
> drivers/video/backlight/Kconfig | 11 ++
> drivers/video/backlight/Makefile | 1 +
> drivers/video/backlight/cgbc_bl.c | 281 ++++++++++++++++++++++++++++++++++++++
> 3 files changed, 293 insertions(+)
>
> diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
> index d9374d208cee..702f3b8ed036 100644
> --- a/drivers/video/backlight/Kconfig
> +++ b/drivers/video/backlight/Kconfig
> @@ -249,6 +249,17 @@ config BACKLIGHT_PWM
> If you have a LCD backlight adjustable by PWM, say Y to enable
> this driver.
>
> +config BACKLIGHT_CGBC
> + tristate "Congatec Board Controller (CGBC) backlight support"
> + depends on MFD_CGBC && X86
> + help
> + Say Y here to enable support for LCD backlight control on Congatec
> + x86-based boards via the CGBC (Congatec Board Controller).
> +
> + This driver provides backlight brightness control through the Linux
> + backlight subsystem. It communicates with the board controller to
> + adjust LCD backlight using PWM signals.
> +
> config BACKLIGHT_DA903X
> tristate "Backlight Driver for DA9030/DA9034 using WLED"
> depends on PMIC_DA903X
> diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
> index dfbb169bf6ea..0169fd8873ed 100644
> --- a/drivers/video/backlight/Makefile
> +++ b/drivers/video/backlight/Makefile
> @@ -27,6 +27,7 @@ obj-$(CONFIG_BACKLIGHT_APPLE_DWI) += apple_dwi_bl.o
> obj-$(CONFIG_BACKLIGHT_AS3711) += as3711_bl.o
> obj-$(CONFIG_BACKLIGHT_BD6107) += bd6107.o
> obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
> +obj-$(CONFIG_BACKLIGHT_CGBC) += cgbc_bl.o
> obj-$(CONFIG_BACKLIGHT_DA903X) += da903x_bl.o
> obj-$(CONFIG_BACKLIGHT_DA9052) += da9052_bl.o
> obj-$(CONFIG_BACKLIGHT_EP93XX) += ep93xx_bl.o
> diff --git a/drivers/video/backlight/cgbc_bl.c b/drivers/video/backlight/cgbc_bl.c
> new file mode 100644
> index 000000000000..4382321f4cac
> --- /dev/null
> +++ b/drivers/video/backlight/cgbc_bl.c
> @@ -0,0 +1,281 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Congatec Board Controller (CGBC) Backlight Driver
> + *
> + * This driver provides backlight control for LCD displays connected to
> + * Congatec boards via the CGBC (Congatec Board Controller). It integrates
> + * with the Linux backlight subsystem and communicates with hardware through
> + * the cgbc-core module.
> + *
> + * Copyright (C) 2025 Novatron Oy
> + *
> + * Author: Petri Karhula <petri.karhula@novatron.fi>
> + */
> +
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/backlight.h>
> +
> +#include <linux/mfd/cgbc.h>
headers shall be sorted in alphabetical order
> +
> +#define CGBC_BL_DRIVER_VERSION "0.0.1"
not needed
> +
> +#define BLT_PWM_DUTY_MASK 0x7F
> +#define BLT_PWM_INVERTED_MASK 0x80
Use GENMASK
> +
> +/* CGBC command for PWM brightness control*/
> +#define CGBC_CMD_BLT0_PWM 0x75
> +
> +#define CGBC_BL_MAX_BRIGHTNESS 100
> +
> +/**
> + * CGBC backlight driver data
> + * @dev: Pointer to the platform device
> + * @bl_dev: Pointer to the backlight device
> + * @cgbc: Pointer to the parent CGBC device data
> + * @current_brightness: Current brightness level (0-100)
> + */
> +struct cgbc_bl_data {
> + struct device *dev;
> + struct backlight_device *bl_dev;
not used
> + struct cgbc_device_data *cgbc;
> + unsigned int current_brightness;
> +};
> +
> +/**
> + * Read current PWM settings from hardware
> + * @bl_data: Backlight driver data
> + *
> + * Reads the current PWM duty cycle percentage (= brightness level)
> + * from the board controller.
> + *
> + * Return: 0 on success, negative error code on failure
> + */
> +static int cgbc_bl_read_pwm_settings(struct cgbc_bl_data *bl_data)
> +{
> + u8 cmd_buf[4] = { CGBC_CMD_BLT0_PWM, 0, 0, 0 };
> + u8 reply_buf[3];
> + int ret;
> +
> + ret = cgbc_command(bl_data->cgbc, cmd_buf, sizeof(cmd_buf), reply_buf,
> + sizeof(reply_buf), NULL);
> +
> + if (ret < 0) {
> + dev_err(bl_data->dev, "Failed to read PWM settings: %d\n", ret);
> + return ret;
> + }
error message not needed from my point of view.
> +
> + /*
> + * Only return PWM duty factor percentage,
> + * ignore polarity inversion bit (bit 7)
> + */
> + bl_data->current_brightness = reply_buf[0] & BLT_PWM_DUTY_MASK;
I would prefer to use FIELD_GET
> +
> + dev_dbg(bl_data->dev, "Current PWM duty=%u\n", bl_data->current_brightness);
Not needed from my point of view.
> +
> + return 0;
> +}
> +
> +/**
> + * Set backlight brightness
> + * @bl_data: Backlight driver data
> + * @brightness: Brightness level (0-100)
> + *
> + * Sets the backlight brightness by configuring the PWM duty cycle.
> + * Preserves the current polarity and frequency settings.
> + *
> + * Return: 0 on success, negative error code on failure
> + */
> +static int cgbc_bl_set_brightness(struct cgbc_bl_data *bl_data, u8 brightness)
> +{
> + u8 cmd_buf[4] = { CGBC_CMD_BLT0_PWM, 0, 0, 0 };
u8 cmd_buf[4] = { CGBC_CMD_BLT0_PWM };
> + u8 reply_buf[3];
> + int ret;
> +
> + /* Read the current values */
> + ret = cgbc_command(bl_data->cgbc, cmd_buf, sizeof(cmd_buf), reply_buf,
> + sizeof(reply_buf), NULL);
> +
> + if (ret < 0) {
> + dev_err(bl_data->dev, "Failed to read PWM settings: %d\n", ret);
> + return ret;
> + }
error message not needed from my point of view.
> +
> + /*
> + * Prepare command buffer for writing new settings. Only 2nd byte is changed
> + * to set new brightness (PWM duty cycle %). Other balues (polarity, frequency)
values
> + * are preserved from the read values.
> + */
> + cmd_buf[1] = (reply_buf[0] & BLT_PWM_INVERTED_MASK) |
> + (BLT_PWM_DUTY_MASK & brightness);
use FIELD_PREP
> + cmd_buf[2] = reply_buf[1];
> + cmd_buf[3] = reply_buf[2];
> +
> + ret = cgbc_command(bl_data->cgbc, cmd_buf, sizeof(cmd_buf), reply_buf,
> + sizeof(reply_buf), NULL);
> +
> + if (ret < 0) {
> + dev_err(bl_data->dev, "Failed to set brightness: %d\n", ret);
error messages not needed from my point of view.
> + return ret;
> + }
> +
> + bl_data->current_brightness = reply_buf[0] & BLT_PWM_DUTY_MASK;
> +
> + /* Verify the setting was applied correctly */
> + if (bl_data->current_brightness != brightness) {
> + dev_err(bl_data->dev,
> + "Brightness setting verification failed\n");
> + return -EIO;
> + }
Do we really need to check the brightness returned by the board
controller? Have you ever run into a situation where cbgc_command
completed without errors, but the brightness level didn’t match what you
expected? Maybe we could assume that if the cbgc_command returned
successfully the brightness value is correct?
I'm not against checking the backlight value. I looked at Congatec's
implementation and they also check it.
> +
> + dev_dbg(bl_data->dev, "Set brightness to %u\n", brightness);
Not needed, the core already has this message
> +
> + return 0;
> +}
> +
> +/**
> + * Backlight update callback
> + * @bl: Backlight device
> + *
> + * Called by the backlight subsystem when brightness needs to be updated.
> + * Changes the brightness level on the hardware
> + * if requested value differs from the current setting.
> + *
> + * Return: 0 on success, negative error code on failure
> + */
> +static int cgbc_bl_update_status(struct backlight_device *bl)
> +{
> + struct cgbc_bl_data *bl_data = bl_get_data(bl);
> + u8 brightness;
> + int ret;
> +
> + brightness = bl->props.brightness;
use backlight_get_brightness()
> +
> + if (brightness != bl_data->current_brightness) {
> + ret = cgbc_bl_set_brightness(bl_data, brightness);
> +
> + if (ret < 0) {
> + dev_err(bl_data->dev, "Failed to set brightness: %d\n",
> + ret);
> + return ret;
> + }
error message not needed from my point of view.
> + }
> +
> + return 0;
> +}
> +
> +/**
> + * Get current backlight brightness
> + * @bl: Backlight device
> + *
> + * Returns the current brightness level by reading from hardware.
> + *
> + * Return: Current brightness level (0-100), or negative error code
> + */
> +static int cgbc_bl_get_brightness(struct backlight_device *bl)
> +{
> + struct cgbc_bl_data *bl_data = bl_get_data(bl);
> + int ret;
> +
> + /* Read current PWM brightness settings */
> + ret = cgbc_bl_read_pwm_settings(bl_data);
> +
> + if (ret < 0) {
> + dev_err(bl_data->dev, "Failed to read PWM settings: %d\n", ret);
> + return ret;
> + }
error message not needed from my point of view.
If you remove all these error messages, you can also remove the struct
device in the struct cgbc_bl_data.
> +
> + return bl_data->current_brightness;
> +}
Maybe you can remove cgbc_bl_read_pwm_settings() and move all the code
in cgbc_bl_get_brightness(). It makes the code easier to read.
> +
> +/* Backlight device operations */
> +static const struct backlight_ops cgbc_bl_ops = {
> + .options = BL_CORE_SUSPENDRESUME,
> + .update_status = cgbc_bl_update_status,
> + .get_brightness = cgbc_bl_get_brightness,
> +};
> +
> +/**
> + * Probe function for CGBC backlight driver
> + * @pdev: Platform device
> + *
> + * Initializes the CGBC backlight driver and registers it with the
> + * Linux backlight subsystem.
> + *
> + * Return: 0 on success, negative error code on failure
> + */
> +static int cgbc_bl_probe(struct platform_device *pdev)
> +{
> + struct cgbc_device_data *cgbc = dev_get_drvdata(pdev->dev.parent);
> + struct cgbc_bl_data *bl_data;
> + struct backlight_properties props;
> + struct backlight_device *bl_dev;
> + int ret;
nitpick: reverse xmas tree
> +
> + bl_data = devm_kzalloc(&pdev->dev, sizeof(*bl_data), GFP_KERNEL);
> +
nitpick: drop empty line.
> + if (!bl_data)
> + return -ENOMEM;
> +
> + bl_data->dev = &pdev->dev;
> + bl_data->cgbc = cgbc;
> +
> + ret = cgbc_bl_read_pwm_settings(bl_data);
> +
nitpick: drop empty line.
> + if (ret) {
> + dev_err(&pdev->dev, "Failed to read initial PWM settings: %d\n",
> + ret);
> + return ret;
> + }
Use dev_err_probe().
> +
> + memset(&props, 0, sizeof(props));
Use struct backlight_properties props = { };
> + props.type = BACKLIGHT_PLATFORM;
> + props.max_brightness = CGBC_BL_MAX_BRIGHTNESS;
> + props.brightness = bl_data->current_brightness;
> +
> + bl_dev = devm_backlight_device_register(&pdev->dev, "cgbc-backlight",
> + &pdev->dev, bl_data,
> + &cgbc_bl_ops, &props);
> +
> + if (IS_ERR(bl_dev)) {
> + dev_err(&pdev->dev, "Failed to register backlight device\n");
> + return PTR_ERR(bl_dev);
> + }
Use dev_err_probe()
> +
> + bl_data->bl_dev = bl_dev;
> + platform_set_drvdata(pdev, bl_data);
> +
> + dev_info(&pdev->dev,
> + "CGBC backlight driver registered (brightness=%u)\n",
> + bl_data->current_brightness);
No logs if device probes successfully.
> +
> + return 0;
> +}
> +
> +/**
> + * Remove function for CGBC backlight driver
> + * @pdev: Platform device
> + *
> + * The Linux device-managed resource framework (devres) does the cleanup.
> + * No explicit cleanup is needed here.
> + */
> +static void cgbc_bl_remove(struct platform_device *pdev)
> +{
> + dev_info(&pdev->dev, "CGBC backlight driver removed\n");
> +}
Remove operation does nothing so drop it.
> +
> +static struct platform_driver cgbc_bl_driver = {
> + .driver = {
> + .name = "cgbc-backlight",
> + },
> + .probe = cgbc_bl_probe,
> + .remove = cgbc_bl_remove,
> +};
> +
> +module_platform_driver(cgbc_bl_driver);
> +
> +MODULE_AUTHOR("Petri Karhula <petri.karhula@novatron.fi>");
> +MODULE_DESCRIPTION("Congatec Board Controller (CGBC) Backlight Driver");
> +MODULE_LICENSE("GPL");
> +MODULE_VERSION(CGBC_BL_DRIVER_VERSION);
Not needed
> +MODULE_ALIAS("platform:cgbc-backlight");
>
Best Regards,
Thomas
^ permalink raw reply
* Re: [PATCH] fbdev: core: Fix vmalloc-out-of-bounds in fb_imageblit
From: Kajtár Zsolt @ 2025-11-19 21:05 UTC (permalink / raw)
To: ssrane_b23, Simona Vetter, Helge Deller
Cc: linux-fbdev, dri-devel, linux-kernel, syzbot+5a40432dfe8f86ee657a
In-Reply-To: <20251119133821.89998-1-ssranevjti@gmail.com>
[-- Attachment #1.1: Type: text/plain, Size: 1037 bytes --]
Hello!
> This patch replaces the insufficient check with a more precise one. It
> calculates the effective width in bytes of the image (accounting for
> clipping against xres_virtual) and ensures that the last byte of the
> operation falls within the screen buffer. Specifically, it checks if
> '(dy + height - 1) * line_length + effective_width_bytes' exceeds
> screen_size. If it does, the drawing height max_y is reduced to
> prevent the out-of-bounds access.
I know my opinion doesn't count much but would like make a note.
Any bound checks which are applied here or at the entry of the other 2
low level drawing routines are just masking an issue somewhere in the
console code. The text area should be entirely within bounds of the
screen memory. If that's always the case then there shouldn't be any
drawing request outside of the framebuffer either.
Please consider at least to add a warning instead of silent clipping, as
every time such clipping was done it was a result of a bug.
--
-soci-
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]
^ permalink raw reply
* Re: [PATCH] fbdev: q40fb: request memory region
From: David Hunter @ 2025-11-19 13:57 UTC (permalink / raw)
To: Sukrut Heroorkar, Helge Deller, open list:FRAMEBUFFER LAYER,
open list:FRAMEBUFFER LAYER, open list
Cc: shuah, david.hunter.linux
In-Reply-To: <20251118095700.393474-1-hsukrut3@gmail.com>
On 11/18/25 04:56, Sukrut Heroorkar wrote:
> The q40fb driver uses a fixed physical address but never reserves
> the corresponding I/O region. Reserve the range as suggested in
> Documentation/gpu/todo.rst ("Request memory regions in all fbdev drivers").
>
> No functional change beyond claming the resource. This change is compile
> tested only.
Reserving memory is a significant "functional" change, so you should not
put "No functional change...". I have noticed that in the mentorship
program, mentees might say this often times when they have not done
testing.
Thank you for describing that you did a compile test, but I believe that
more testing should be done before this patch is accepted.
As a result, if you are unable to test this device, I believe that an
RFT tag should be used. Also, the testing information goes below the
"---". This puts it in the change log and would make it so that if a
patch is accepted, everything below the change log is not put in the
commit message.
>
> Signed-off-by: Sukrut Heroorkar <hsukrut3@gmail.com>
> ---
> drivers/video/fbdev/q40fb.c | 7 +++++++
> 1 file changed, 7 insertions(+)
>
> diff --git a/drivers/video/fbdev/q40fb.c b/drivers/video/fbdev/q40fb.c
> index 1ff8fa176124..935260326c6f 100644
> --- a/drivers/video/fbdev/q40fb.c
> +++ b/drivers/video/fbdev/q40fb.c
> @@ -101,6 +101,12 @@ static int q40fb_probe(struct platform_device *dev)
> info->par = NULL;
> info->screen_base = (char *) q40fb_fix.smem_start;
>
> + if (!request_mem_region(q40fb_fix.smem_start, q40fb_fix.smem_len,
> + "q40fb")) {
> + dev_err(&dev->dev, "cannot reserve video memory at 0x%lx\n",
> + q40fb_fix.smem_start);
> + }
> +
Is this correct? It seems to me that in the case of an error, all you
are doing is simply logging the error and proceeding. Would this cause
the device to continue to try to use space that it was not able to
reserve? I do not have experience with this device or the driver, but
that does not seem correct to me.
> if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
> framebuffer_release(info);
> return -ENOMEM;
> @@ -144,6 +150,7 @@ static int __init q40fb_init(void)
> if (ret)
> platform_driver_unregister(&q40fb_driver);
> }
> +
> return ret;
> }
>
^ permalink raw reply
* [PATCH] fbdev: core: Fix vmalloc-out-of-bounds in fb_imageblit
From: ssrane_b23 @ 2025-11-19 13:38 UTC (permalink / raw)
To: Zsolt Kajtar, Simona Vetter, Helge Deller
Cc: Shaurya Rane, linux-fbdev, dri-devel, linux-kernel,
syzbot+5a40432dfe8f86ee657a
From: Shaurya Rane <ssrane_b23@ee.vjti.ac.in>
syzbot reported a vmalloc-out-of-bounds write in fb_imageblit. The crash
occurs when drawing an image at the very end of the framebuffer memory.
The current bounds check in fb_imageblit limits the drawing height (max_y)
by dividing the screen size by the line length. However, this calculation
only ensures that the start of the last line fits within the buffer. It
fails to account for the width of the image on that final line. If the
image width (multiplied by bpp) exceeds the remaining space on the last
line, the drawing routine writes past the end of the allocated video
memory.
This patch replaces the insufficient check with a more precise one. It
calculates the effective width in bytes of the image (accounting for
clipping against xres_virtual) and ensures that the last byte of the
operation falls within the screen buffer. Specifically, it checks if
'(dy + height - 1) * line_length + effective_width_bytes' exceeds
screen_size. If it does, the drawing height max_y is reduced to
prevent the out-of-bounds access.
Reported-by: syzbot+5a40432dfe8f86ee657a@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=5a40432dfe8f86ee657a
Signed-off-by: Shaurya Rane <ssrane_b23@ee.vjti.ac.in>
---
drivers/video/fbdev/core/fb_imageblit.h | 66 +++++++++++++++++++++++--
1 file changed, 62 insertions(+), 4 deletions(-)
diff --git a/drivers/video/fbdev/core/fb_imageblit.h b/drivers/video/fbdev/core/fb_imageblit.h
index 3b2bb4946505..0c0d05cff3f8 100644
--- a/drivers/video/fbdev/core/fb_imageblit.h
+++ b/drivers/video/fbdev/core/fb_imageblit.h
@@ -485,11 +485,69 @@ static inline void fb_imageblit(struct fb_info *p, const struct fb_image *image)
struct fb_address dst = fb_address_init(p);
struct fb_reverse reverse = fb_reverse_init(p);
const u32 *palette = fb_palette(p);
+ struct fb_image clipped_image;
+ u32 max_x, max_y;
+ unsigned long max_offset_bytes;
+
+ /* Validate basic parameters */
+ if (!image || !p->screen_buffer || !p->screen_size ||
+ !image->width || !image->height)
+ return;
+
+ /* Calculate maximum addressable coordinates based on virtual resolution and buffer size */
+ max_x = p->var.xres_virtual;
+ max_y = p->var.yres_virtual;
+
+ /* Check against actual buffer size to prevent vmalloc overflow */
+ {
+ unsigned long effective_width_bytes;
+ u32 right_edge = image->dx + image->width;
+
+ if (right_edge < image->dx)
+ right_edge = max_x;
+ else
+ right_edge = min(right_edge, max_x);
+
+ effective_width_bytes = (unsigned long)right_edge * bpp;
+ effective_width_bytes = (effective_width_bytes + 7) / 8;
+
+ if (effective_width_bytes > p->screen_size) {
+ max_y = 0;
+ } else if (p->fix.line_length) {
+ u32 max_lines = (p->screen_size - effective_width_bytes) /
+ p->fix.line_length + 1;
+ if (max_lines < max_y)
+ max_y = max_lines;
+ }
+ }
+
+ /* If image is completely outside bounds, skip it */
+ if (image->dx >= max_x || image->dy >= max_y)
+ return;
+
+ /* Create clipped image - clip to virtual resolution bounds */
+ clipped_image = *image;
+
+ /* Clip width if it extends beyond right edge */
+ if (clipped_image.dx + clipped_image.width > max_x) {
+ if (clipped_image.dx < max_x)
+ clipped_image.width = max_x - clipped_image.dx;
+ else
+ return; /* completely outside */
+ }
+
+ /* Clip height if it extends beyond bottom edge */
+ if (clipped_image.dy + clipped_image.height > max_y) {
+ if (clipped_image.dy < max_y)
+ clipped_image.height = max_y - clipped_image.dy;
+ else
+ return; /* completely outside */
+ }
- fb_address_forward(&dst, image->dy * bits_per_line + image->dx * bpp);
+ fb_address_forward(&dst, clipped_image.dy * bits_per_line + clipped_image.dx * bpp);
- if (image->depth == 1)
- fb_bitmap_imageblit(image, &dst, bits_per_line, palette, bpp, reverse);
+ if (clipped_image.depth == 1)
+ fb_bitmap_imageblit(&clipped_image, &dst, bits_per_line, palette, bpp, reverse);
else
- fb_color_imageblit(image, &dst, bits_per_line, palette, bpp, reverse);
+ fb_color_imageblit(&clipped_image, &dst, bits_per_line, palette, bpp, reverse);
}
--
2.34.1
^ permalink raw reply related
* Re: [syzbot] [fbdev?] KASAN: vmalloc-out-of-bounds Write in imageblit (6)
From: syzbot @ 2025-11-19 10:42 UTC (permalink / raw)
To: linux-fbdev, linux-kernel, ssranevjti, syzkaller-bugs
In-Reply-To: <e69c10c5-ee82-4229-b7b6-e3993442595b@gmail.com>
Hello,
syzbot has tested the proposed patch and the reproducer did not trigger any issue:
Reported-by: syzbot+5a40432dfe8f86ee657a@syzkaller.appspotmail.com
Tested-by: syzbot+5a40432dfe8f86ee657a@syzkaller.appspotmail.com
Tested on:
commit: 8b690556 Merge tag 'for-linus' of git://git.kernel.org..
git tree: upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=10921212580000
kernel config: https://syzkaller.appspot.com/x/.config?x=1cd7f786c0f5182f
dashboard link: https://syzkaller.appspot.com/bug?extid=5a40432dfe8f86ee657a
compiler: gcc (Debian 12.2.0-14+deb12u1) 12.2.0, GNU ld (GNU Binutils for Debian) 2.40
patch: https://syzkaller.appspot.com/x/patch.diff?x=13a21212580000
Note: testing is done by a robot and is best-effort only.
^ permalink raw reply
* Re: [syzbot] [fbdev?] KASAN: vmalloc-out-of-bounds Write in imageblit (6)
From: shaurya @ 2025-11-19 10:18 UTC (permalink / raw)
To: syzbot+5a40432dfe8f86ee657a; +Cc: linux-fbdev, linux-kernel, syzkaller-bugs
In-Reply-To: <691c279e.a70a0220.3124cb.00b5.GAE@google.com>
[-- Attachment #1: Type: text/plain, Size: 82 bytes --]
#syz test:
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master
[-- Attachment #2: 0001-testing-my-fix.patch --]
[-- Type: text/x-patch, Size: 3132 bytes --]
From 188fc7eea4a00500a806b7b122d20289abc2bf00 Mon Sep 17 00:00:00 2001
From: Shaurya Rane <ssrane_b23@ee.vjti.ac.in>
Date: Wed, 19 Nov 2025 15:44:51 +0530
Subject: [PATCH] testing my fix
Signed-off-by: Shaurya Rane <ssrane_b23@ee.vjti.ac.in>
---
drivers/video/fbdev/core/fb_imageblit.h | 66 +++++++++++++++++++++++--
1 file changed, 62 insertions(+), 4 deletions(-)
diff --git a/drivers/video/fbdev/core/fb_imageblit.h b/drivers/video/fbdev/core/fb_imageblit.h
index 3b2bb4946505..aee7f4032164 100644
--- a/drivers/video/fbdev/core/fb_imageblit.h
+++ b/drivers/video/fbdev/core/fb_imageblit.h
@@ -485,11 +485,69 @@ static inline void fb_imageblit(struct fb_info *p, const struct fb_image *image)
struct fb_address dst = fb_address_init(p);
struct fb_reverse reverse = fb_reverse_init(p);
const u32 *palette = fb_palette(p);
+ struct fb_image clipped_image;
+ u32 max_x, max_y;
+ unsigned long max_offset_bytes;
+
+ /* Validate basic parameters */
+ if (!image || !p->screen_buffer || !p->screen_size ||
+ !image->width || !image->height)
+ return;
+
+ /* Calculate maximum addressable coordinates based on virtual resolution and buffer size */
+ max_x = p->var.xres_virtual;
+ max_y = p->var.yres_virtual;
+
+ /* Also check against actual buffer size to prevent vmalloc overflow */
+ {
+ unsigned long effective_width_bytes;
+ u32 right_edge = image->dx + image->width;
+
+ if (right_edge < image->dx)
+ right_edge = max_x;
+ else
+ right_edge = min(right_edge, max_x);
+
+ effective_width_bytes = (unsigned long)right_edge * bpp;
+ effective_width_bytes = (effective_width_bytes + 7) / 8;
+
+ if (effective_width_bytes > p->screen_size) {
+ max_y = 0;
+ } else if (p->fix.line_length) {
+ u32 max_lines = (p->screen_size - effective_width_bytes) /
+ p->fix.line_length + 1;
+ if (max_lines < max_y)
+ max_y = max_lines;
+ }
+ }
+
+ /* If image is completely outside bounds, skip it */
+ if (image->dx >= max_x || image->dy >= max_y)
+ return;
+
+ /* Create clipped image - clip to virtual resolution bounds */
+ clipped_image = *image;
+
+ /* Clip width if it extends beyond right edge */
+ if (clipped_image.dx + clipped_image.width > max_x) {
+ if (clipped_image.dx < max_x)
+ clipped_image.width = max_x - clipped_image.dx;
+ else
+ return; /* completely outside */
+ }
+
+ /* Clip height if it extends beyond bottom edge */
+ if (clipped_image.dy + clipped_image.height > max_y) {
+ if (clipped_image.dy < max_y)
+ clipped_image.height = max_y - clipped_image.dy;
+ else
+ return; /* completely outside */
+ }
- fb_address_forward(&dst, image->dy * bits_per_line + image->dx * bpp);
+ fb_address_forward(&dst, clipped_image.dy * bits_per_line + clipped_image.dx * bpp);
- if (image->depth == 1)
- fb_bitmap_imageblit(image, &dst, bits_per_line, palette, bpp, reverse);
+ if (clipped_image.depth == 1)
+ fb_bitmap_imageblit(&clipped_image, &dst, bits_per_line, palette, bpp, reverse);
else
- fb_color_imageblit(image, &dst, bits_per_line, palette, bpp, reverse);
+ fb_color_imageblit(&clipped_image, &dst, bits_per_line, palette, bpp, reverse);
}
--
2.34.1
^ permalink raw reply related
* [PATCH v2 1/2] backlight: Add Congatec Board Controller (CGBC) backlight support
From: Petri Karhula via B4 Relay @ 2025-11-19 8:25 UTC (permalink / raw)
To: Thomas Richard, Lee Jones, Daniel Thompson, Jingoo Han,
Helge Deller
Cc: linux-kernel, dri-devel, linux-fbdev, Petri Karhula
In-Reply-To: <20251119-cgbc-backlight-v2-0-4d4edd7ca662@novatron.fi>
From: Petri Karhula <petri.karhula@novatron.fi>
This driver provides backlight brightness control through the Linux
backlight subsystem. It communicates with the board controller to
adjust LCD backlight using PWM signals. Communication is done
through Congatec Board Controller core driver.
Signed-off-by: Petri Karhula <petri.karhula@novatron.fi>
---
drivers/video/backlight/Kconfig | 11 ++
drivers/video/backlight/Makefile | 1 +
drivers/video/backlight/cgbc_bl.c | 281 ++++++++++++++++++++++++++++++++++++++
3 files changed, 293 insertions(+)
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index d9374d208cee..702f3b8ed036 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -249,6 +249,17 @@ config BACKLIGHT_PWM
If you have a LCD backlight adjustable by PWM, say Y to enable
this driver.
+config BACKLIGHT_CGBC
+ tristate "Congatec Board Controller (CGBC) backlight support"
+ depends on MFD_CGBC && X86
+ help
+ Say Y here to enable support for LCD backlight control on Congatec
+ x86-based boards via the CGBC (Congatec Board Controller).
+
+ This driver provides backlight brightness control through the Linux
+ backlight subsystem. It communicates with the board controller to
+ adjust LCD backlight using PWM signals.
+
config BACKLIGHT_DA903X
tristate "Backlight Driver for DA9030/DA9034 using WLED"
depends on PMIC_DA903X
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index dfbb169bf6ea..0169fd8873ed 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_BACKLIGHT_APPLE_DWI) += apple_dwi_bl.o
obj-$(CONFIG_BACKLIGHT_AS3711) += as3711_bl.o
obj-$(CONFIG_BACKLIGHT_BD6107) += bd6107.o
obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
+obj-$(CONFIG_BACKLIGHT_CGBC) += cgbc_bl.o
obj-$(CONFIG_BACKLIGHT_DA903X) += da903x_bl.o
obj-$(CONFIG_BACKLIGHT_DA9052) += da9052_bl.o
obj-$(CONFIG_BACKLIGHT_EP93XX) += ep93xx_bl.o
diff --git a/drivers/video/backlight/cgbc_bl.c b/drivers/video/backlight/cgbc_bl.c
new file mode 100644
index 000000000000..4382321f4cac
--- /dev/null
+++ b/drivers/video/backlight/cgbc_bl.c
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Congatec Board Controller (CGBC) Backlight Driver
+ *
+ * This driver provides backlight control for LCD displays connected to
+ * Congatec boards via the CGBC (Congatec Board Controller). It integrates
+ * with the Linux backlight subsystem and communicates with hardware through
+ * the cgbc-core module.
+ *
+ * Copyright (C) 2025 Novatron Oy
+ *
+ * Author: Petri Karhula <petri.karhula@novatron.fi>
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/backlight.h>
+
+#include <linux/mfd/cgbc.h>
+
+#define CGBC_BL_DRIVER_VERSION "0.0.1"
+
+#define BLT_PWM_DUTY_MASK 0x7F
+#define BLT_PWM_INVERTED_MASK 0x80
+
+/* CGBC command for PWM brightness control*/
+#define CGBC_CMD_BLT0_PWM 0x75
+
+#define CGBC_BL_MAX_BRIGHTNESS 100
+
+/**
+ * CGBC backlight driver data
+ * @dev: Pointer to the platform device
+ * @bl_dev: Pointer to the backlight device
+ * @cgbc: Pointer to the parent CGBC device data
+ * @current_brightness: Current brightness level (0-100)
+ */
+struct cgbc_bl_data {
+ struct device *dev;
+ struct backlight_device *bl_dev;
+ struct cgbc_device_data *cgbc;
+ unsigned int current_brightness;
+};
+
+/**
+ * Read current PWM settings from hardware
+ * @bl_data: Backlight driver data
+ *
+ * Reads the current PWM duty cycle percentage (= brightness level)
+ * from the board controller.
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+static int cgbc_bl_read_pwm_settings(struct cgbc_bl_data *bl_data)
+{
+ u8 cmd_buf[4] = { CGBC_CMD_BLT0_PWM, 0, 0, 0 };
+ u8 reply_buf[3];
+ int ret;
+
+ ret = cgbc_command(bl_data->cgbc, cmd_buf, sizeof(cmd_buf), reply_buf,
+ sizeof(reply_buf), NULL);
+
+ if (ret < 0) {
+ dev_err(bl_data->dev, "Failed to read PWM settings: %d\n", ret);
+ return ret;
+ }
+
+ /*
+ * Only return PWM duty factor percentage,
+ * ignore polarity inversion bit (bit 7)
+ */
+ bl_data->current_brightness = reply_buf[0] & BLT_PWM_DUTY_MASK;
+
+ dev_dbg(bl_data->dev, "Current PWM duty=%u\n", bl_data->current_brightness);
+
+ return 0;
+}
+
+/**
+ * Set backlight brightness
+ * @bl_data: Backlight driver data
+ * @brightness: Brightness level (0-100)
+ *
+ * Sets the backlight brightness by configuring the PWM duty cycle.
+ * Preserves the current polarity and frequency settings.
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+static int cgbc_bl_set_brightness(struct cgbc_bl_data *bl_data, u8 brightness)
+{
+ u8 cmd_buf[4] = { CGBC_CMD_BLT0_PWM, 0, 0, 0 };
+ u8 reply_buf[3];
+ int ret;
+
+ /* Read the current values */
+ ret = cgbc_command(bl_data->cgbc, cmd_buf, sizeof(cmd_buf), reply_buf,
+ sizeof(reply_buf), NULL);
+
+ if (ret < 0) {
+ dev_err(bl_data->dev, "Failed to read PWM settings: %d\n", ret);
+ return ret;
+ }
+
+ /*
+ * Prepare command buffer for writing new settings. Only 2nd byte is changed
+ * to set new brightness (PWM duty cycle %). Other balues (polarity, frequency)
+ * are preserved from the read values.
+ */
+ cmd_buf[1] = (reply_buf[0] & BLT_PWM_INVERTED_MASK) |
+ (BLT_PWM_DUTY_MASK & brightness);
+ cmd_buf[2] = reply_buf[1];
+ cmd_buf[3] = reply_buf[2];
+
+ ret = cgbc_command(bl_data->cgbc, cmd_buf, sizeof(cmd_buf), reply_buf,
+ sizeof(reply_buf), NULL);
+
+ if (ret < 0) {
+ dev_err(bl_data->dev, "Failed to set brightness: %d\n", ret);
+ return ret;
+ }
+
+ bl_data->current_brightness = reply_buf[0] & BLT_PWM_DUTY_MASK;
+
+ /* Verify the setting was applied correctly */
+ if (bl_data->current_brightness != brightness) {
+ dev_err(bl_data->dev,
+ "Brightness setting verification failed\n");
+ return -EIO;
+ }
+
+ dev_dbg(bl_data->dev, "Set brightness to %u\n", brightness);
+
+ return 0;
+}
+
+/**
+ * Backlight update callback
+ * @bl: Backlight device
+ *
+ * Called by the backlight subsystem when brightness needs to be updated.
+ * Changes the brightness level on the hardware
+ * if requested value differs from the current setting.
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+static int cgbc_bl_update_status(struct backlight_device *bl)
+{
+ struct cgbc_bl_data *bl_data = bl_get_data(bl);
+ u8 brightness;
+ int ret;
+
+ brightness = bl->props.brightness;
+
+ if (brightness != bl_data->current_brightness) {
+ ret = cgbc_bl_set_brightness(bl_data, brightness);
+
+ if (ret < 0) {
+ dev_err(bl_data->dev, "Failed to set brightness: %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Get current backlight brightness
+ * @bl: Backlight device
+ *
+ * Returns the current brightness level by reading from hardware.
+ *
+ * Return: Current brightness level (0-100), or negative error code
+ */
+static int cgbc_bl_get_brightness(struct backlight_device *bl)
+{
+ struct cgbc_bl_data *bl_data = bl_get_data(bl);
+ int ret;
+
+ /* Read current PWM brightness settings */
+ ret = cgbc_bl_read_pwm_settings(bl_data);
+
+ if (ret < 0) {
+ dev_err(bl_data->dev, "Failed to read PWM settings: %d\n", ret);
+ return ret;
+ }
+
+ return bl_data->current_brightness;
+}
+
+/* Backlight device operations */
+static const struct backlight_ops cgbc_bl_ops = {
+ .options = BL_CORE_SUSPENDRESUME,
+ .update_status = cgbc_bl_update_status,
+ .get_brightness = cgbc_bl_get_brightness,
+};
+
+/**
+ * Probe function for CGBC backlight driver
+ * @pdev: Platform device
+ *
+ * Initializes the CGBC backlight driver and registers it with the
+ * Linux backlight subsystem.
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+static int cgbc_bl_probe(struct platform_device *pdev)
+{
+ struct cgbc_device_data *cgbc = dev_get_drvdata(pdev->dev.parent);
+ struct cgbc_bl_data *bl_data;
+ struct backlight_properties props;
+ struct backlight_device *bl_dev;
+ int ret;
+
+ bl_data = devm_kzalloc(&pdev->dev, sizeof(*bl_data), GFP_KERNEL);
+
+ if (!bl_data)
+ return -ENOMEM;
+
+ bl_data->dev = &pdev->dev;
+ bl_data->cgbc = cgbc;
+
+ ret = cgbc_bl_read_pwm_settings(bl_data);
+
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to read initial PWM settings: %d\n",
+ ret);
+ return ret;
+ }
+
+ memset(&props, 0, sizeof(props));
+ props.type = BACKLIGHT_PLATFORM;
+ props.max_brightness = CGBC_BL_MAX_BRIGHTNESS;
+ props.brightness = bl_data->current_brightness;
+
+ bl_dev = devm_backlight_device_register(&pdev->dev, "cgbc-backlight",
+ &pdev->dev, bl_data,
+ &cgbc_bl_ops, &props);
+
+ if (IS_ERR(bl_dev)) {
+ dev_err(&pdev->dev, "Failed to register backlight device\n");
+ return PTR_ERR(bl_dev);
+ }
+
+ bl_data->bl_dev = bl_dev;
+ platform_set_drvdata(pdev, bl_data);
+
+ dev_info(&pdev->dev,
+ "CGBC backlight driver registered (brightness=%u)\n",
+ bl_data->current_brightness);
+
+ return 0;
+}
+
+/**
+ * Remove function for CGBC backlight driver
+ * @pdev: Platform device
+ *
+ * The Linux device-managed resource framework (devres) does the cleanup.
+ * No explicit cleanup is needed here.
+ */
+static void cgbc_bl_remove(struct platform_device *pdev)
+{
+ dev_info(&pdev->dev, "CGBC backlight driver removed\n");
+}
+
+static struct platform_driver cgbc_bl_driver = {
+ .driver = {
+ .name = "cgbc-backlight",
+ },
+ .probe = cgbc_bl_probe,
+ .remove = cgbc_bl_remove,
+};
+
+module_platform_driver(cgbc_bl_driver);
+
+MODULE_AUTHOR("Petri Karhula <petri.karhula@novatron.fi>");
+MODULE_DESCRIPTION("Congatec Board Controller (CGBC) Backlight Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(CGBC_BL_DRIVER_VERSION);
+MODULE_ALIAS("platform:cgbc-backlight");
--
2.34.1
^ permalink raw reply related
* [PATCH v2 2/2] mfd: cgbc: Add support for backlight
From: Petri Karhula via B4 Relay @ 2025-11-19 8:25 UTC (permalink / raw)
To: Thomas Richard, Lee Jones, Daniel Thompson, Jingoo Han,
Helge Deller
Cc: linux-kernel, dri-devel, linux-fbdev, Petri Karhula
In-Reply-To: <20251119-cgbc-backlight-v2-0-4d4edd7ca662@novatron.fi>
From: Petri Karhula <petri.karhula@novatron.fi>
The Board Controller has control for display backlight.
Add backlight cell for the cgbc-backlight driver which
adds support for backlight brightness control.
Signed-off-by: Petri Karhula <petri.karhula@novatron.fi>
---
drivers/mfd/cgbc-core.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/mfd/cgbc-core.c b/drivers/mfd/cgbc-core.c
index 4782ff1114a9..10bb4b414c34 100644
--- a/drivers/mfd/cgbc-core.c
+++ b/drivers/mfd/cgbc-core.c
@@ -237,6 +237,7 @@ static struct mfd_cell cgbc_devs[] = {
{ .name = "cgbc-i2c", .id = 1 },
{ .name = "cgbc-i2c", .id = 2 },
{ .name = "cgbc-hwmon" },
+ { .name = "cgbc-backlight" },
};
static int cgbc_map(struct cgbc_device_data *cgbc)
--
2.34.1
^ permalink raw reply related
* [PATCH v2 0/2] Backlight driver to control backlight behind Congatec Board Controller.
From: Petri Karhula via B4 Relay @ 2025-11-19 8:25 UTC (permalink / raw)
To: Thomas Richard, Lee Jones, Daniel Thompson, Jingoo Han,
Helge Deller
Cc: linux-kernel, dri-devel, linux-fbdev, Petri Karhula
This driver provides backlight brightness control through the Linux
backlight subsystem. It communicates with the board controller to
adjust LCD backlight using PWM signals. Communication is done
through Congatec Board Controller core driver.
Signed-off-by: Petri Karhula <petri.karhula@novatron.fi>
---
Changes in v2:
- Separated Board Controller core driver change into its own patch
- Link to v1: https://lore.kernel.org/r/20251118-cgbc-backlight-v1-1-cc6ac5301034@novatron.fi
---
Petri Karhula (2):
backlight: Add Congatec Board Controller (CGBC) backlight support
mfd: cgbc: Add support for backlight
drivers/mfd/cgbc-core.c | 1 +
drivers/video/backlight/Kconfig | 11 ++
drivers/video/backlight/Makefile | 1 +
drivers/video/backlight/cgbc_bl.c | 281 ++++++++++++++++++++++++++++++++++++++
4 files changed, 294 insertions(+)
---
base-commit: e7c375b181600caf135cfd03eadbc45eb530f2cb
change-id: 20251118-cgbc-backlight-35c1109db0b8
Best regards,
--
Petri Karhula <petri.karhula@novatron.fi>
^ permalink raw reply
* Re: [PATCH] fbdev/tridentfb: replace printk() with dev_*() in probe
From: Javier Garcia @ 2025-11-19 7:16 UTC (permalink / raw)
To: deller; +Cc: linux-fbdev, dri-devel, linux-kernel, shuah
In-Reply-To: <20251115125701.3228804-1-rampxxxx@gmail.com>
Hi Deller,
Any comments on this patch?,
Thanks!
---
Javier Garcia
On Sat, 15 Nov 2025 at 13:57, Javier Garcia <rampxxxx@gmail.com> wrote:
>
> - Replace in `trident_pc_probe()` printk by dev_* fn's
> - Delete the prefix `tridentfb:` from msg strings, not needed now.
>
> Signed-off-by: Javier Garcia <rampxxxx@gmail.com>
> ---
> drivers/video/fbdev/tridentfb.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/video/fbdev/tridentfb.c b/drivers/video/fbdev/tridentfb.c
> index 516cf2a18757..17b7253b8fbe 100644
> --- a/drivers/video/fbdev/tridentfb.c
> +++ b/drivers/video/fbdev/tridentfb.c
> @@ -1631,7 +1631,7 @@ static int trident_pci_probe(struct pci_dev *dev,
> }
>
> if (noaccel) {
> - printk(KERN_DEBUG "disabling acceleration\n");
> + dev_dbg(&dev->dev, "disabling acceleration\n");
> info->flags |= FBINFO_HWACCEL_DISABLED;
> info->pixmap.scan_align = 1;
> }
> @@ -1693,7 +1693,7 @@ static int trident_pci_probe(struct pci_dev *dev,
> info->var.activate |= FB_ACTIVATE_NOW;
> info->device = &dev->dev;
> if (register_framebuffer(info) < 0) {
> - printk(KERN_ERR "tridentfb: could not register framebuffer\n");
> + dev_err(&dev->dev, "could not register framebuffer\n");
> fb_dealloc_cmap(&info->cmap);
> err = -EINVAL;
> goto out_unmap2;
> --
> 2.50.1
>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox