Linux Framebuffer Layer development
 help / color / mirror / Atom feed
* Re: [PATCH v3 3/4] fbdev: omapfb: Make FB_DEVICE dependency optional
From: Helge Deller @ 2025-12-30  8:05 UTC (permalink / raw)
  To: Chintan Patel; +Cc: linux-fbdev, linux-omap, linux-kernel, dri-devel
In-Reply-To: <20251230052827.4676-4-chintanlike@gmail.com>

* Chintan Patel <chintanlike@gmail.com>:
> omapfb provides several sysfs interfaces for framebuffer configuration
> and debugging, but these are not required for the core driver.
> 
> Remove the hard dependency on CONFIG_FB_DEVICE and make sysfs support
> optional by using dev_of_fbinfo() to obtain the backing device at runtime.
> When FB_DEVICE is disabled, sysfs operations are skipped while the code
> still builds and is type-checked.
> 
> Suggested-by: Helge Deller <deller@gmx.de>
> Signed-off-by: Chintan Patel <chintanlike@gmail.com>

Reviewed-by: Helge Deller <deller@gmx.de>

> ---
>  drivers/video/fbdev/omap2/omapfb/Kconfig        |  3 ++-
>  drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c | 16 ++++++++++++----
>  2 files changed, 14 insertions(+), 5 deletions(-)

^ permalink raw reply

* Re: [PATCH v3 2/4] staging: fbtft: Make FB_DEVICE dependency optional
From: Helge Deller @ 2025-12-30  8:03 UTC (permalink / raw)
  To: Chintan Patel
  Cc: linux-fbdev, linux-staging, linux-omap, linux-kernel, dri-devel
In-Reply-To: <20251230052827.4676-3-chintanlike@gmail.com>

* Chintan Patel <chintanlike@gmail.com>:
> fbtft provides sysfs interfaces for debugging and gamma configuration,
> but these are not required for the core driver.
> 
> Drop the hard dependency on CONFIG_FB_DEVICE and make sysfs support
> optional by using dev_of_fbinfo() at runtime. When FB_DEVICE is disabled,
> sysfs operations are skipped while the code remains buildable and
> type-checked.
> 
> Suggested-by: Thomas Zimmermann <tzimmermann@suse.de>
> Suggested-by: Helge Deller <deller@gmx.de>
> Signed-off-by: Chintan Patel <chintanlike@gmail.com>

Reviewed-by: Helge Deller <deller@gmx.de>


^ permalink raw reply

* Re: [PATCH v3 1/4] fb: Add dev_of_fbinfo() helper for optional sysfs support
From: Helge Deller @ 2025-12-30  8:01 UTC (permalink / raw)
  To: Chintan Patel; +Cc: linux-fbdev, linux-kernel, dri-devel
In-Reply-To: <20251230052827.4676-2-chintanlike@gmail.com>

* Chintan Patel <chintanlike@gmail.com>:
> Add dev_of_fbinfo() to return the framebuffer struct device when
> CONFIG_FB_DEVICE is enabled, or NULL otherwise.
> 
> This allows fbdev drivers to use sysfs interfaces via runtime checks
> instead of CONFIG_FB_DEVICE ifdefs, keeping the code clean while
> remaining fully buildable.
> 
> Suggested-by: Helge Deller <deller@gmx.de>
> Signed-off-by: Chintan Patel <chintanlike@gmail.com>

Reviewed-by: Helge Deller <deller@gmx.de>

^ permalink raw reply

* Re: [PATCH] staging: sm750fb: fix const array warning
From: Greg KH @ 2025-12-30  7:42 UTC (permalink / raw)
  To: MottiKumar
  Cc: sudipm.mukherjee, teddy.wang, skhan, linux-kernel-mentees,
	linux-fbdev, linux-staging, linux-kernel
In-Reply-To: <20251226120417.2599020-1-mottikumarbabu@gmail.com>

On Fri, Dec 26, 2025 at 05:34:17PM +0530, MottiKumar wrote:
> Add a missing const to g_fbmode to fix a checkpatch warning:
> "static const char * array should probably be static const char * const"
> 
> Signed-off-by: MottiKumar <mottikumarbabu@gmail.com>
> ---
>  drivers/staging/sm750fb/sm750.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/staging/sm750fb/sm750.c b/drivers/staging/sm750fb/sm750.c
> index d100b9e1d3d5..7afb58561a0c 100644
> --- a/drivers/staging/sm750fb/sm750.c
> +++ b/drivers/staging/sm750fb/sm750.c
> @@ -33,7 +33,7 @@
>  static int g_hwcursor = 1;
>  static int g_noaccel;
>  static int g_nomtrr;
> -static const char *g_fbmode[] = {NULL, NULL};
> +static const char * const g_fbmode[] = {NULL, NULL};
>  static const char *g_def_fbmode = "1024x768-32@60";
>  static char *g_settings;
>  static int g_dualview;
> -- 
> 2.43.0
> 
> 

Did you test build this change?  If not, please do so.

thanks,

greg k-h

^ permalink raw reply

* [PATCH v3 4/4] fbdev: sh_mobile_lcdc: Make FB_DEVICE dependency optional
From: Chintan Patel @ 2025-12-30  5:28 UTC (permalink / raw)
  To: linux-fbdev, linux-staging, linux-omap
  Cc: linux-kernel, dri-devel, tzimmermann, andy, deller, gregkh,
	Chintan Patel
In-Reply-To: <20251230052827.4676-1-chintanlike@gmail.com>

The sh_mobile_lcdc driver exposes overlay configuration via sysfs, but the
core driver does not require CONFIG_FB_DEVICE.

Make sysfs support optional by defining overlay_sysfs_groups conditionally
using PTR_IF(). The driver always sets .dev_groups, and the kernel
naturally skips NULL attribute groups while the code remains buildable
and type-checked.

Suggested-by: Helge Deller <deller@gmx.de>
Signed-off-by: Chintan Patel <chintanlike@gmail.com>
---
 drivers/video/fbdev/sh_mobile_lcdcfb.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/drivers/video/fbdev/sh_mobile_lcdcfb.c b/drivers/video/fbdev/sh_mobile_lcdcfb.c
index dd950e4ab5ce..cb7ed1ff9165 100644
--- a/drivers/video/fbdev/sh_mobile_lcdcfb.c
+++ b/drivers/video/fbdev/sh_mobile_lcdcfb.c
@@ -1350,7 +1350,17 @@ static struct attribute *overlay_sysfs_attrs[] = {
 	&dev_attr_overlay_rop3.attr,
 	NULL,
 };
-ATTRIBUTE_GROUPS(overlay_sysfs);
+
+#ifdef CONFIG_FB_DEVICE
+static const struct attribute_group overlay_sysfs_group = {
+	.attrs = overlay_sysfs_attrs,
+};
+#endif
+
+static const struct attribute_group *overlay_sysfs_groups[] = {
+	PTR_IF(IS_ENABLED(CONFIG_FB_DEVICE), &overlay_sysfs_group),
+	NULL,
+};
 
 static const struct fb_fix_screeninfo sh_mobile_lcdc_overlay_fix  = {
 	.id =		"SH Mobile LCDC",
-- 
2.43.0


^ permalink raw reply related

* [PATCH v3 3/4] fbdev: omapfb: Make FB_DEVICE dependency optional
From: Chintan Patel @ 2025-12-30  5:28 UTC (permalink / raw)
  To: linux-fbdev, linux-staging, linux-omap
  Cc: linux-kernel, dri-devel, tzimmermann, andy, deller, gregkh,
	Chintan Patel
In-Reply-To: <20251230052827.4676-1-chintanlike@gmail.com>

omapfb provides several sysfs interfaces for framebuffer configuration
and debugging, but these are not required for the core driver.

Remove the hard dependency on CONFIG_FB_DEVICE and make sysfs support
optional by using dev_of_fbinfo() to obtain the backing device at runtime.
When FB_DEVICE is disabled, sysfs operations are skipped while the code
still builds and is type-checked.

Suggested-by: Helge Deller <deller@gmx.de>
Signed-off-by: Chintan Patel <chintanlike@gmail.com>
---
 drivers/video/fbdev/omap2/omapfb/Kconfig        |  3 ++-
 drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c | 16 ++++++++++++----
 2 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/drivers/video/fbdev/omap2/omapfb/Kconfig b/drivers/video/fbdev/omap2/omapfb/Kconfig
index f4cdf999a080..2d20e79adefc 100644
--- a/drivers/video/fbdev/omap2/omapfb/Kconfig
+++ b/drivers/video/fbdev/omap2/omapfb/Kconfig
@@ -5,7 +5,6 @@ config OMAP2_VRFB
 menuconfig FB_OMAP2
 	tristate "OMAP2+ frame buffer support"
 	depends on FB
-	depends on FB_DEVICE
 	depends on DRM_OMAP = n
 	depends on GPIOLIB
 	select FB_OMAP2_DSS
@@ -13,6 +12,8 @@ menuconfig FB_OMAP2
 	select FB_IOMEM_HELPERS
 	help
 	  Frame buffer driver for OMAP2+ based boards.
+	  FB_DEVICE is not required, but if enabled, provides sysfs interface
+	  for framebuffer configuration and debugging.
 
 if FB_OMAP2
 
diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c b/drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c
index 831b2c2fbdf9..ef555dd598aa 100644
--- a/drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c
+++ b/drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c
@@ -558,10 +558,14 @@ int omapfb_create_sysfs(struct omapfb2_device *fbdev)
 
 	DBG("create sysfs for fbs\n");
 	for (i = 0; i < fbdev->num_fbs; i++) {
+		struct device *dev = dev_of_fbinfo(fbdev->fbs[i]);
 		int t;
+
+		if (!dev)
+			continue;
+
 		for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++) {
-			r = device_create_file(fbdev->fbs[i]->dev,
-					&omapfb_attrs[t]);
+			r = device_create_file(dev, &omapfb_attrs[t]);
 
 			if (r) {
 				dev_err(fbdev->dev, "failed to create sysfs "
@@ -580,9 +584,13 @@ void omapfb_remove_sysfs(struct omapfb2_device *fbdev)
 
 	DBG("remove sysfs for fbs\n");
 	for (i = 0; i < fbdev->num_fbs; i++) {
+		struct device *dev = dev_of_fbinfo(fbdev->fbs[i]);
+
+		if (!dev)
+			continue;
+
 		for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++)
-			device_remove_file(fbdev->fbs[i]->dev,
-					&omapfb_attrs[t]);
+			device_remove_file(dev, &omapfb_attrs[t]);
 	}
 }
 
-- 
2.43.0


^ permalink raw reply related

* [PATCH v3 2/4] staging: fbtft: Make FB_DEVICE dependency optional
From: Chintan Patel @ 2025-12-30  5:28 UTC (permalink / raw)
  To: linux-fbdev, linux-staging, linux-omap
  Cc: linux-kernel, dri-devel, tzimmermann, andy, deller, gregkh,
	Chintan Patel
In-Reply-To: <20251230052827.4676-1-chintanlike@gmail.com>

fbtft provides sysfs interfaces for debugging and gamma configuration,
but these are not required for the core driver.

Drop the hard dependency on CONFIG_FB_DEVICE and make sysfs support
optional by using dev_of_fbinfo() at runtime. When FB_DEVICE is disabled,
sysfs operations are skipped while the code remains buildable and
type-checked.

Suggested-by: Thomas Zimmermann <tzimmermann@suse.de>
Suggested-by: Helge Deller <deller@gmx.de>
Signed-off-by: Chintan Patel <chintanlike@gmail.com>
---
 drivers/staging/fbtft/Kconfig       |  5 ++++-
 drivers/staging/fbtft/fbtft-sysfs.c | 20 ++++++++++++++++----
 2 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig
index c2655768209a..578412a2f379 100644
--- a/drivers/staging/fbtft/Kconfig
+++ b/drivers/staging/fbtft/Kconfig
@@ -2,11 +2,14 @@
 menuconfig FB_TFT
 	tristate "Support for small TFT LCD display modules"
 	depends on FB && SPI
-	depends on FB_DEVICE
 	depends on BACKLIGHT_CLASS_DEVICE
 	depends on GPIOLIB || COMPILE_TEST
 	select FB_BACKLIGHT
 	select FB_SYSMEM_HELPERS_DEFERRED
+	help
+	  Support for small TFT LCD display modules over SPI bus. FB_DEVICE
+	  is not required, but if enabled, provides sysfs interface for debugging
+	  and gamma curve configuration.
 
 if FB_TFT
 
diff --git a/drivers/staging/fbtft/fbtft-sysfs.c b/drivers/staging/fbtft/fbtft-sysfs.c
index e45c90a03a90..d05599d80011 100644
--- a/drivers/staging/fbtft/fbtft-sysfs.c
+++ b/drivers/staging/fbtft/fbtft-sysfs.c
@@ -203,14 +203,26 @@ static struct device_attribute debug_device_attr =
 
 void fbtft_sysfs_init(struct fbtft_par *par)
 {
-	device_create_file(par->info->dev, &debug_device_attr);
+	struct device *dev;
+
+	dev = dev_of_fbinfo(par->info);
+	if (!dev)
+		return;
+
+	device_create_file(dev, &debug_device_attr);
 	if (par->gamma.curves && par->fbtftops.set_gamma)
-		device_create_file(par->info->dev, &gamma_device_attrs[0]);
+		device_create_file(dev, &gamma_device_attrs[0]);
 }
 
 void fbtft_sysfs_exit(struct fbtft_par *par)
 {
-	device_remove_file(par->info->dev, &debug_device_attr);
+	struct device *dev;
+
+	dev = dev_of_fbinfo(par->info);
+	if (!dev)
+		return;
+
+	device_remove_file(dev, &debug_device_attr);
 	if (par->gamma.curves && par->fbtftops.set_gamma)
-		device_remove_file(par->info->dev, &gamma_device_attrs[0]);
+		device_remove_file(dev, &gamma_device_attrs[0]);
 }
-- 
2.43.0


^ permalink raw reply related

* [PATCH v3 1/4] fb: Add dev_of_fbinfo() helper for optional sysfs support
From: Chintan Patel @ 2025-12-30  5:28 UTC (permalink / raw)
  To: linux-fbdev, linux-staging, linux-omap
  Cc: linux-kernel, dri-devel, tzimmermann, andy, deller, gregkh,
	Chintan Patel
In-Reply-To: <20251230052827.4676-1-chintanlike@gmail.com>

Add dev_of_fbinfo() to return the framebuffer struct device when
CONFIG_FB_DEVICE is enabled, or NULL otherwise.

This allows fbdev drivers to use sysfs interfaces via runtime checks
instead of CONFIG_FB_DEVICE ifdefs, keeping the code clean while
remaining fully buildable.

Suggested-by: Helge Deller <deller@gmx.de>
Signed-off-by: Chintan Patel <chintanlike@gmail.com>
---
 include/linux/fb.h | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/include/linux/fb.h b/include/linux/fb.h
index 05cc251035da..dad3fb61a06a 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -628,6 +628,15 @@ static inline void unlock_fb_info(struct fb_info *info)
 	mutex_unlock(&info->lock);
 }
 
+static inline struct device *dev_of_fbinfo(const struct fb_info *info)
+{
+#ifdef CONFIG_FB_DEVICE
+	return info->dev;
+#else
+	return NULL;
+#endif
+}
+
 static inline void __fb_pad_aligned_buffer(u8 *dst, u32 d_pitch,
 					   u8 *src, u32 s_pitch, u32 height)
 {
-- 
2.43.0


^ permalink raw reply related

* [PATCH v3 0/4] fbdev: Make CONFIG_FB_DEVICE optional for drivers
From: Chintan Patel @ 2025-12-30  5:28 UTC (permalink / raw)
  To: linux-fbdev, linux-staging, linux-omap
  Cc: linux-kernel, dri-devel, tzimmermann, andy, deller, gregkh,
	Chintan Patel

This series makes CONFIG_FB_DEVICE optional for fbdev drivers that use
it only for sysfs interfaces, addressing Thomas Zimmermann’s TODO to
remove hard FB_DEVICE dependencies.

The series introduces a small helper, dev_of_fbinfo(), which returns
NULL when CONFIG_FB_DEVICE=n. This allows sysfs code paths to be skipped
via runtime checks, avoids #ifdef CONFIG_FB_DEVICE clutter, and keeps
full compile-time syntax checking.

Signed-off-by: Chintan Patel <chintanlike@gmail.com>
---
Changes in v3:
- Use PTR_IF() to conditionally include overlay_sysfs_group in 
  overlay_sysfs_groups
- Decouple variable definition and assignment in fbtft_sysfs_init/exit

Changes in v2:
- Add dev_of_fbinfo() helper (suggested by Geert Uytterhoeven)
- Replace #ifdef CONFIG_FB_DEVICE blocks with runtime NULL checks
- Switch to fb_dbg() / fb_info() logging (suggested by Thomas Zimmermann)

---

Chintan Patel (4):
  fb: Add dev_of_fbinfo() helper for optional sysfs support
  staging: fbtft: Make FB_DEVICE dependency optional
  fbdev: omapfb: Make FB_DEVICE dependency optional
  fbdev: sh_mobile_lcdc: Make FB_DEVICE dependency optional

 drivers/staging/fbtft/Kconfig                 |  5 ++++-
 drivers/staging/fbtft/fbtft-sysfs.c           | 20 +++++++++++++++----
 drivers/video/fbdev/omap2/omapfb/Kconfig      |  3 ++-
 .../video/fbdev/omap2/omapfb/omapfb-sysfs.c   | 16 +++++++++++----
 drivers/video/fbdev/sh_mobile_lcdcfb.c        | 12 ++++++++++-
 include/linux/fb.h                            |  9 +++++++++
 6 files changed, 54 insertions(+), 11 deletions(-)

-- 
2.43.0


^ permalink raw reply

* [PATCH 00/12] Recover sysfb after DRM probe failure
From: Zack Rusin @ 2025-12-29 21:58 UTC (permalink / raw)
  To: dri-devel
  Cc: Alex Deucher, amd-gfx, Ard Biesheuvel, Ce Sun, Chia-I Wu,
	Christian König, Danilo Krummrich, Dave Airlie, Deepak Rawat,
	Dmitry Osipenko, Gerd Hoffmann, Gurchetan Singh, Hans de Goede,
	Hawking Zhang, Helge Deller, intel-gfx, intel-xe, Jani Nikula,
	Javier Martinez Canillas, Jocelyn Falempe, Joonas Lahtinen,
	Lijo Lazar, linux-efi, linux-fbdev, linux-hyperv, linux-kernel,
	Lucas De Marchi, Lyude Paul, Maarten Lankhorst,
	Mario Limonciello (AMD), Mario Limonciello, Maxime Ripard,
	nouveau, Rodrigo Vivi, Simona Vetter, spice-devel,
	Thomas Hellström, Thomas Zimmermann, Timur Kristóf,
	Tvrtko Ursulin, virtualization, Vitaly Prosyak

Almost a rite of passage for every DRM developer and most Linux users
is upgrading your DRM driver/updating boot flags/changing some config
and having DRM driver fail at probe resulting in a blank screen.

Currently there's no way to recover from DRM driver probe failure. PCI
DRM driver explicitly throw out the existing sysfb to get exclusive
access to PCI resources so if the probe fails the system is left without
a functioning display driver.

Add code to sysfb to recever system framebuffer when DRM driver's probe
fails. This means that a DRM driver that fails to load reloads the system
framebuffer driver.

This works best with simpledrm. Without it Xorg won't recover because
it still tries to load the vendor specific driver which ends up usually
not working at all. With simpledrm the system recovers really nicely
ending up with a working console and not a blank screen.

There's a caveat in that some hardware might require some special magic
register write to recover EFI display. I'd appreciate it a lot if
maintainers could introduce a temporary failure in their drivers
probe to validate that the sysfb recovers and they get a working console.
The easiest way to double check it is by adding:
 /* XXX: Temporary failure to test sysfb restore - REMOVE BEFORE COMMIT */
 dev_info(&pdev->dev, "Testing sysfb restore: forcing probe failure\n");
 ret = -EINVAL;
 goto out_error;
or such right after the devm_aperture_remove_conflicting_pci_devices .

Cc: Alex Deucher <alexander.deucher@amd.com>
Cc: amd-gfx@lists.freedesktop.org
Cc: Ard Biesheuvel <ardb@kernel.org>
Cc: Ce Sun <cesun102@amd.com>
Cc: Chia-I Wu <olvaffe@gmail.com>
Cc: "Christian König" <christian.koenig@amd.com>
Cc: Danilo Krummrich <dakr@kernel.org>
Cc: Dave Airlie <airlied@redhat.com>
Cc: Deepak Rawat <drawat.floss@gmail.com>
Cc: Dmitry Osipenko <dmitry.osipenko@collabora.com>
Cc: dri-devel@lists.freedesktop.org
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Gurchetan Singh <gurchetansingh@chromium.org>
Cc: Hans de Goede <hansg@kernel.org>
Cc: Hawking Zhang <Hawking.Zhang@amd.com>
Cc: Helge Deller <deller@gmx.de>
Cc: intel-gfx@lists.freedesktop.org
Cc: intel-xe@lists.freedesktop.org
Cc: Jani Nikula <jani.nikula@linux.intel.com>
Cc: Javier Martinez Canillas <javierm@redhat.com>
Cc: Jocelyn Falempe <jfalempe@redhat.com>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Lijo Lazar <lijo.lazar@amd.com>
Cc: linux-efi@vger.kernel.org
Cc: linux-fbdev@vger.kernel.org
Cc: linux-hyperv@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: Lucas De Marchi <lucas.demarchi@intel.com>
Cc: Lyude Paul <lyude@redhat.com>
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Cc: "Mario Limonciello (AMD)" <superm1@kernel.org>
Cc: Mario Limonciello <mario.limonciello@amd.com>
Cc: Maxime Ripard <mripard@kernel.org>
Cc: nouveau@lists.freedesktop.org
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Simona Vetter <simona@ffwll.ch>
Cc: spice-devel@lists.freedesktop.org
Cc: "Thomas Hellström" <thomas.hellstrom@linux.intel.com>
Cc: Thomas Zimmermann <tzimmermann@suse.de>
Cc: "Timur Kristóf" <timur.kristof@gmail.com>
Cc: Tvrtko Ursulin <tursulin@ursulin.net>
Cc: virtualization@lists.linux.dev
Cc: Vitaly Prosyak <vitaly.prosyak@amd.com>

Zack Rusin (12):
  video/aperture: Add sysfb restore on DRM probe failure
  drm/vmwgfx: Use devm aperture helpers for sysfb restore on probe
    failure
  drm/xe: Use devm aperture helpers for sysfb restore on probe failure
  drm/amdgpu: Use devm aperture helpers for sysfb restore on probe
    failure
  drm/virtio: Add sysfb restore on probe failure
  drm/nouveau: Use devm aperture helpers for sysfb restore on probe
    failure
  drm/qxl: Use devm aperture helpers for sysfb restore on probe failure
  drm/vboxvideo: Use devm aperture helpers for sysfb restore on probe
    failure
  drm/hyperv: Add sysfb restore on probe failure
  drm/ast: Use devm aperture helpers for sysfb restore on probe failure
  drm/radeon: Use devm aperture helpers for sysfb restore on probe
    failure
  drm/i915: Use devm aperture helpers for sysfb restore on probe failure

 drivers/firmware/efi/sysfb_efi.c           |   2 +-
 drivers/firmware/sysfb.c                   | 191 +++++++++++++--------
 drivers/firmware/sysfb_simplefb.c          |  10 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_device.c |   9 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c    |   7 +
 drivers/gpu/drm/ast/ast_drv.c              |  13 +-
 drivers/gpu/drm/hyperv/hyperv_drm_drv.c    |  23 +++
 drivers/gpu/drm/i915/i915_driver.c         |  13 +-
 drivers/gpu/drm/nouveau/nouveau_drm.c      |  16 +-
 drivers/gpu/drm/qxl/qxl_drv.c              |  14 +-
 drivers/gpu/drm/radeon/radeon_drv.c        |  15 +-
 drivers/gpu/drm/vboxvideo/vbox_drv.c       |  13 +-
 drivers/gpu/drm/virtio/virtgpu_drv.c       |  29 ++++
 drivers/gpu/drm/vmwgfx/vmwgfx_drv.c        |  13 +-
 drivers/gpu/drm/xe/xe_device.c             |   7 +-
 drivers/gpu/drm/xe/xe_pci.c                |   7 +
 drivers/video/aperture.c                   |  54 ++++++
 include/linux/aperture.h                   |  14 ++
 include/linux/sysfb.h                      |   6 +
 19 files changed, 368 insertions(+), 88 deletions(-)

-- 
2.48.1


^ permalink raw reply

* [PATCH 01/12] video/aperture: Add sysfb restore on DRM probe failure
From: Zack Rusin @ 2025-12-29 21:58 UTC (permalink / raw)
  To: dri-devel
  Cc: Ard Biesheuvel, Thomas Zimmermann, Javier Martinez Canillas,
	Helge Deller, linux-efi, linux-kernel, linux-fbdev
In-Reply-To: <20251229215906.3688205-1-zack.rusin@broadcom.com>

When a DRM driver calls aperture_remove_conflicting_pci_devices(), the
firmware framebuffer (EFI, VESA, etc.) is disabled and its platform
device is unregistered. If the DRM driver's probe subsequently fails,
the user is left with no display output.

Add sysfb_restore() to re-enable the Generic System Framebuffers
support and re-create the platform device that was previously
unregistered by sysfb_disable().

Add devm_aperture_remove_conflicting_pci_devices() which wraps the
existing function and registers a devm action to automatically call
sysfb_restore() if the driver's probe fails or the driver is unloaded.
Drivers can call devm_aperture_remove_conflicting_pci_devices_done()
after successful probe to cancel the automatic restore.

Refactor sysfb_init() to use a shared __sysfb_create_device() helper
that can be called from both sysfb_init() and sysfb_restore(). Add a
quirks_applied flag to handle the edge case where a driver calls
sysfb_disable() before sysfb_init() runs, in this case sysfb_restore()
defers device creation to sysfb_init() since the __init quirk functions
cannot be called after init memory is freed.

Signed-off-by: Zack Rusin <zack.rusin@broadcom.com>
Cc: Ard Biesheuvel <ardb@kernel.org>
Cc: Thomas Zimmermann <tzimmermann@suse.de>
Cc: Javier Martinez Canillas <javierm@redhat.com>
Cc: Helge Deller <deller@gmx.de>
Cc: linux-efi@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: dri-devel@lists.freedesktop.org
Cc: linux-fbdev@vger.kernel.org
---
 drivers/firmware/efi/sysfb_efi.c  |   2 +-
 drivers/firmware/sysfb.c          | 191 +++++++++++++++++++-----------
 drivers/firmware/sysfb_simplefb.c |  10 +-
 drivers/video/aperture.c          |  54 +++++++++
 include/linux/aperture.h          |  14 +++
 include/linux/sysfb.h             |   6 +
 6 files changed, 201 insertions(+), 76 deletions(-)

diff --git a/drivers/firmware/efi/sysfb_efi.c b/drivers/firmware/efi/sysfb_efi.c
index 1e509595ac03..3fe7c57ad849 100644
--- a/drivers/firmware/efi/sysfb_efi.c
+++ b/drivers/firmware/efi/sysfb_efi.c
@@ -365,7 +365,7 @@ __init void sysfb_apply_efi_quirks(void)
 	}
 }
 
-__init void sysfb_set_efifb_fwnode(struct platform_device *pd)
+void sysfb_set_efifb_fwnode(struct platform_device *pd)
 {
 	if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI && IS_ENABLED(CONFIG_PCI)) {
 		fwnode_init(&efifb_fwnode, &efifb_fwnode_ops);
diff --git a/drivers/firmware/sysfb.c b/drivers/firmware/sysfb.c
index 889e5b05c739..c45b6f487103 100644
--- a/drivers/firmware/sysfb.c
+++ b/drivers/firmware/sysfb.c
@@ -38,6 +38,7 @@
 static struct platform_device *pd;
 static DEFINE_MUTEX(disable_lock);
 static bool disabled;
+static bool quirks_applied;
 
 static struct device *sysfb_parent_dev(const struct screen_info *si);
 
@@ -79,6 +80,121 @@ void sysfb_disable(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(sysfb_disable);
 
+/* Caller must hold disable_lock */
+static int __sysfb_create_device(bool restore)
+{
+	struct screen_info *si = &screen_info;
+	struct device *parent;
+	unsigned int type;
+	struct simplefb_platform_data mode;
+	const char *name;
+	bool compatible;
+	int ret = 0;
+
+	if (!IS_ERR_OR_NULL(pd))
+		return 0;
+
+	/*
+	 * If quirks haven't been applied yet, sysfb_init() hasn't run.
+	 * Don't create the device now - let sysfb_init() do it after
+	 * applying the necessary fixups and quirks. We can't call
+	 * sysfb_apply_efi_quirks() here because it's __init.
+	 */
+	if (!quirks_applied)
+		return 0;
+
+	parent = sysfb_parent_dev(si);
+	if (IS_ERR(parent))
+		return PTR_ERR(parent);
+
+	type = screen_info_video_type(si);
+
+	/* try to create a simple-framebuffer device */
+	compatible = sysfb_parse_mode(si, &mode);
+	if (compatible) {
+		pd = sysfb_create_simplefb(si, &mode, parent);
+		if (!IS_ERR(pd)) {
+			if (restore)
+				pr_info("sysfb: restored simple-framebuffer device\n");
+			goto put_device;
+		}
+	}
+
+	/* if the FB is incompatible, create a legacy framebuffer device */
+	switch (type) {
+	case VIDEO_TYPE_EGAC:
+		name = "ega-framebuffer";
+		break;
+	case VIDEO_TYPE_VGAC:
+		name = "vga-framebuffer";
+		break;
+	case VIDEO_TYPE_VLFB:
+		name = "vesa-framebuffer";
+		break;
+	case VIDEO_TYPE_EFI:
+		name = "efi-framebuffer";
+		break;
+	default:
+		name = "platform-framebuffer";
+		break;
+	}
+
+	pd = platform_device_alloc(name, 0);
+	if (!pd) {
+		ret = -ENOMEM;
+		goto put_device;
+	}
+
+	pd->dev.parent = parent;
+
+	sysfb_set_efifb_fwnode(pd);
+
+	ret = platform_device_add_data(pd, si, sizeof(*si));
+	if (ret)
+		goto err;
+
+	ret = platform_device_add(pd);
+	if (ret)
+		goto err;
+
+	if (restore)
+		pr_info("sysfb: restored %s device\n", name);
+	goto put_device;
+err:
+	platform_device_put(pd);
+	pd = NULL;
+put_device:
+	put_device(parent);
+	return ret;
+}
+
+/**
+ * sysfb_restore() - restore the Generic System Framebuffer
+ *
+ * This function re-enables the Generic System Framebuffers support and
+ * re-creates the platform device that was previously unregistered by
+ * sysfb_disable(). This is intended for use by DRM drivers that need to
+ * restore the fallback framebuffer when their probe fails after having
+ * called aperture_remove_conflicting_devices() or similar.
+ *
+ * Context: The function can sleep. A @disable_lock mutex is acquired.
+ *
+ * Returns:
+ * 0 on success, or a negative errno value otherwise.
+ */
+int sysfb_restore(void)
+{
+	int ret;
+
+	mutex_lock(&disable_lock);
+	disabled = false;
+	ret = __sysfb_create_device(true);
+	mutex_unlock(&disable_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(sysfb_restore);
+
 /**
  * sysfb_handles_screen_info() - reports if sysfb handles the global screen_info
  *
@@ -141,82 +257,17 @@ static struct device *sysfb_parent_dev(const struct screen_info *si)
 
 static __init int sysfb_init(void)
 {
-	struct screen_info *si = &screen_info;
-	struct device *parent;
-	unsigned int type;
-	struct simplefb_platform_data mode;
-	const char *name;
-	bool compatible;
 	int ret = 0;
 
 	screen_info_apply_fixups();
-
-	mutex_lock(&disable_lock);
-	if (disabled)
-		goto unlock_mutex;
-
 	sysfb_apply_efi_quirks();
 
-	parent = sysfb_parent_dev(si);
-	if (IS_ERR(parent)) {
-		ret = PTR_ERR(parent);
-		goto unlock_mutex;
-	}
-
-	/* try to create a simple-framebuffer device */
-	compatible = sysfb_parse_mode(si, &mode);
-	if (compatible) {
-		pd = sysfb_create_simplefb(si, &mode, parent);
-		if (!IS_ERR(pd))
-			goto put_device;
-	}
-
-	type = screen_info_video_type(si);
-
-	/* if the FB is incompatible, create a legacy framebuffer device */
-	switch (type) {
-	case VIDEO_TYPE_EGAC:
-		name = "ega-framebuffer";
-		break;
-	case VIDEO_TYPE_VGAC:
-		name = "vga-framebuffer";
-		break;
-	case VIDEO_TYPE_VLFB:
-		name = "vesa-framebuffer";
-		break;
-	case VIDEO_TYPE_EFI:
-		name = "efi-framebuffer";
-		break;
-	default:
-		name = "platform-framebuffer";
-		break;
-	}
-
-	pd = platform_device_alloc(name, 0);
-	if (!pd) {
-		ret = -ENOMEM;
-		goto put_device;
-	}
-
-	pd->dev.parent = parent;
-
-	sysfb_set_efifb_fwnode(pd);
-
-	ret = platform_device_add_data(pd, si, sizeof(*si));
-	if (ret)
-		goto err;
-
-	ret = platform_device_add(pd);
-	if (ret)
-		goto err;
-
-	goto put_device;
-err:
-	platform_device_put(pd);
-put_device:
-	put_device(parent);
-unlock_mutex:
+	mutex_lock(&disable_lock);
+	quirks_applied = true;
+	if (!disabled)
+		ret = __sysfb_create_device(false);
 	mutex_unlock(&disable_lock);
+
 	return ret;
 }
 
diff --git a/drivers/firmware/sysfb_simplefb.c b/drivers/firmware/sysfb_simplefb.c
index 592d8a644619..6fcbc3ae17d5 100644
--- a/drivers/firmware/sysfb_simplefb.c
+++ b/drivers/firmware/sysfb_simplefb.c
@@ -24,8 +24,8 @@ static const char simplefb_resname[] = "BOOTFB";
 static const struct simplefb_format formats[] = SIMPLEFB_FORMATS;
 
 /* try parsing screen_info into a simple-framebuffer mode struct */
-__init bool sysfb_parse_mode(const struct screen_info *si,
-			     struct simplefb_platform_data *mode)
+bool sysfb_parse_mode(const struct screen_info *si,
+		      struct simplefb_platform_data *mode)
 {
 	__u8 type;
 	u32 bits_per_pixel;
@@ -61,9 +61,9 @@ __init bool sysfb_parse_mode(const struct screen_info *si,
 	return false;
 }
 
-__init struct platform_device *sysfb_create_simplefb(const struct screen_info *si,
-						     const struct simplefb_platform_data *mode,
-						     struct device *parent)
+struct platform_device *sysfb_create_simplefb(const struct screen_info *si,
+					      const struct simplefb_platform_data *mode,
+					      struct device *parent)
 {
 	struct platform_device *pd;
 	struct resource res;
diff --git a/drivers/video/aperture.c b/drivers/video/aperture.c
index 2b5a1e666e9b..4de6dc04a3fd 100644
--- a/drivers/video/aperture.c
+++ b/drivers/video/aperture.c
@@ -372,3 +372,57 @@ int aperture_remove_conflicting_pci_devices(struct pci_dev *pdev, const char *na
 
 }
 EXPORT_SYMBOL(aperture_remove_conflicting_pci_devices);
+
+static void devm_aperture_restore_sysfb(void *unused)
+{
+	sysfb_restore();
+}
+
+/**
+ * devm_aperture_remove_conflicting_pci_devices - remove existing framebuffers
+ *                                                with sysfb restore on failure
+ * @pdev: PCI device
+ * @name: a descriptive name of the requesting driver
+ *
+ * This function removes devices that own apertures within any of @pdev's
+ * memory bars, similar to aperture_remove_conflicting_pci_devices().
+ *
+ * Additionally, it registers a devm action that will restore the system
+ * framebuffer if the driver's probe fails or the driver is unloaded. This
+ * ensures the user doesn't lose display output if the DRM driver probe fails
+ * after removing the firmware framebuffer.
+ *
+ * This function should be called early in the driver's probe function. The
+ * driver must call devm_aperture_remove_conflicting_pci_devices_done() after
+ * successfully completing probe to cancel the automatic restore.
+ *
+ * Returns:
+ * 0 on success, or a negative errno code otherwise
+ */
+int devm_aperture_remove_conflicting_pci_devices(struct pci_dev *pdev,
+						 const char *name)
+{
+	int ret;
+
+	ret = aperture_remove_conflicting_pci_devices(pdev, name);
+	if (ret)
+		return ret;
+
+	return devm_add_action_or_reset(&pdev->dev, devm_aperture_restore_sysfb,
+					NULL);
+}
+EXPORT_SYMBOL(devm_aperture_remove_conflicting_pci_devices);
+
+/**
+ * devm_aperture_remove_conflicting_pci_devices_done - cancel sysfb restore
+ * @pdev: PCI device
+ *
+ * Cancels the automatic sysfb restore action registered by
+ * devm_aperture_remove_conflicting_pci_devices(). Call this after the
+ * driver has successfully completed probe and registered its display.
+ */
+void devm_aperture_remove_conflicting_pci_devices_done(struct pci_dev *pdev)
+{
+	devm_remove_action(&pdev->dev, devm_aperture_restore_sysfb, NULL);
+}
+EXPORT_SYMBOL(devm_aperture_remove_conflicting_pci_devices_done);
diff --git a/include/linux/aperture.h b/include/linux/aperture.h
index 1a9a88b11584..ea0ece7f777e 100644
--- a/include/linux/aperture.h
+++ b/include/linux/aperture.h
@@ -19,6 +19,10 @@ int aperture_remove_conflicting_devices(resource_size_t base, resource_size_t si
 int __aperture_remove_legacy_vga_devices(struct pci_dev *pdev);
 
 int aperture_remove_conflicting_pci_devices(struct pci_dev *pdev, const char *name);
+
+int devm_aperture_remove_conflicting_pci_devices(struct pci_dev *pdev,
+						 const char *name);
+void devm_aperture_remove_conflicting_pci_devices_done(struct pci_dev *pdev);
 #else
 static inline int devm_aperture_acquire_for_platform_device(struct platform_device *pdev,
 							    resource_size_t base,
@@ -42,6 +46,16 @@ static inline int aperture_remove_conflicting_pci_devices(struct pci_dev *pdev,
 {
 	return 0;
 }
+
+static inline int devm_aperture_remove_conflicting_pci_devices(struct pci_dev *pdev,
+							       const char *name)
+{
+	return 0;
+}
+
+static inline void devm_aperture_remove_conflicting_pci_devices_done(struct pci_dev *pdev)
+{
+}
 #endif
 
 /**
diff --git a/include/linux/sysfb.h b/include/linux/sysfb.h
index b449665c686a..c0ade38bcf99 100644
--- a/include/linux/sysfb.h
+++ b/include/linux/sysfb.h
@@ -63,6 +63,7 @@ struct efifb_dmi_info {
 #ifdef CONFIG_SYSFB
 
 void sysfb_disable(struct device *dev);
+int sysfb_restore(void);
 
 bool sysfb_handles_screen_info(void);
 
@@ -72,6 +73,11 @@ static inline void sysfb_disable(struct device *dev)
 {
 }
 
+static inline int sysfb_restore(void)
+{
+	return -ENODEV;
+}
+
 static inline bool sysfb_handles_screen_info(void)
 {
 	return false;
-- 
2.48.1


^ permalink raw reply related

* Re: [PATCH] Replace udelay() with usleep_range() in PLL initialization code. According to Documentation/timers/timers-howto.rst, usleep_range() is preferred for delays "10us - 20ms"
From: Andy Shevchenko @ 2025-12-29  7:41 UTC (permalink / raw)
  To: Alexandru Costin
  Cc: andy, gregkh, dri-devel, linux-fbdev, linux-staging, linux-kernel
In-Reply-To: <20251229010814.94255-1-spxxky.dev@gmail.com>

On Mon, Dec 29, 2025 at 3:09 AM Alexandru Costin <spxxky.dev@gmail.com> wrote:
>
> Resolves checkpatch warnings:
>   WARNING: usleep_range is preferred over udelay

First of all, fix checkpatch to point to a newer API, i.e. fsleep().

...

> @@ -210,7 +210,8 @@ static void write_reg8_bus8(struct fbtft_par *par, int len, ...)

> -       udelay(100);
> +       usleep_range(100, 120);

> @@ -231,7 +232,7 @@ static void write_reg8_bus8(struct fbtft_par *par, int len, ...)

> -       udelay(100);
> +       usleep_range(100, 120);

This is an IO function for the hardware in question. Have you tested
it? How do you know that this is a non-atomic context?

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply

* [PATCH] Replace udelay() with usleep_range() in PLL initialization code. According to Documentation/timers/timers-howto.rst, usleep_range() is preferred for delays "10us - 20ms"
From: Alexandru Costin @ 2025-12-29  1:08 UTC (permalink / raw)
  To: andy, gregkh
  Cc: dri-devel, linux-fbdev, linux-staging, linux-kernel,
	Alexandru Costin

Resolves checkpatch warnings:
  WARNING: usleep_range is preferred over udelay

Signed-off-by: Alexandru Costin <spxxky.dev@gmail.com>
---
 drivers/staging/fbtft/fb_ra8875.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/staging/fbtft/fb_ra8875.c b/drivers/staging/fbtft/fb_ra8875.c
index 0ab1de6647d0..130150b0f07f 100644
--- a/drivers/staging/fbtft/fb_ra8875.c
+++ b/drivers/staging/fbtft/fb_ra8875.c
@@ -210,7 +210,8 @@ static void write_reg8_bus8(struct fbtft_par *par, int len, ...)
 	}
 	len--;
 
-	udelay(100);
+	usleep_range(100, 120);
+
 
 	if (len) {
 		buf = (u8 *)par->buf;
@@ -231,7 +232,7 @@ static void write_reg8_bus8(struct fbtft_par *par, int len, ...)
 
 	/* restore user spi-speed */
 	par->fbtftops.write = fbtft_write_spi;
-	udelay(100);
+	usleep_range(100, 120);
 }
 
 static int write_vmem16_bus8(struct fbtft_par *par, size_t offset, size_t len)
-- 
2.43.0


^ permalink raw reply related

* [PATCH] fbdev: smscufx: properly copy ioctl memory to kernelspace
From: Greg Kroah-Hartman @ 2025-12-28 13:17 UTC (permalink / raw)
  To: linux-fbdev, dri-devel
  Cc: linux-kernel, Greg Kroah-Hartman, Tianchu Chen, stable,
	Steve Glendinning, Helge Deller

The UFX_IOCTL_REPORT_DAMAGE ioctl does not properly copy data from
userspace to kernelspace, and instead directly references the memory,
which can cause problems if invalid data is passed from userspace.  Fix
this all up by correctly copying the memory before accessing it within
the kernel.

Reported-by: Tianchu Chen <flynnnchen@tencent.com>
Cc: stable <stable@kernel.org>
Cc: Steve Glendinning <steve.glendinning@shawell.net>
Cc: Helge Deller <deller@gmx.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 drivers/video/fbdev/smscufx.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/video/fbdev/smscufx.c b/drivers/video/fbdev/smscufx.c
index 5f0dd01fd834..891ce7b76d63 100644
--- a/drivers/video/fbdev/smscufx.c
+++ b/drivers/video/fbdev/smscufx.c
@@ -932,7 +932,6 @@ static int ufx_ops_ioctl(struct fb_info *info, unsigned int cmd,
 			 unsigned long arg)
 {
 	struct ufx_data *dev = info->par;
-	struct dloarea *area = NULL;
 
 	if (!atomic_read(&dev->usb_active))
 		return 0;
@@ -947,6 +946,10 @@ static int ufx_ops_ioctl(struct fb_info *info, unsigned int cmd,
 
 	/* TODO: Help propose a standard fb.h ioctl to report mmap damage */
 	if (cmd == UFX_IOCTL_REPORT_DAMAGE) {
+		struct dloarea *area __free(kfree) = kmalloc(sizeof(*area), GFP_KERNEL);
+		if (!area)
+			return -ENOMEM;
+
 		/* If we have a damage-aware client, turn fb_defio "off"
 		 * To avoid perf imact of unnecessary page fault handling.
 		 * Done by resetting the delay for this fb_info to a very
@@ -956,7 +959,8 @@ static int ufx_ops_ioctl(struct fb_info *info, unsigned int cmd,
 		if (info->fbdefio)
 			info->fbdefio->delay = UFX_DEFIO_WRITE_DISABLE;
 
-		area = (struct dloarea *)arg;
+		if (copy_from_user(area, (u8 __user *)arg, sizeof(*area)))
+			return -EFAULT;
 
 		if (area->x < 0)
 			area->x = 0;
-- 
2.52.0


^ permalink raw reply related

* Re: [PATCH v2 2/4] staging: fbtft: Make FB_DEVICE dependency optional
From: Chintan Patel @ 2025-12-28  3:36 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: linux-fbdev, linux-staging, linux-omap, linux-kernel, dri-devel,
	tzimmermann, andy, deller, gregkh
In-Reply-To: <CAHp75VeLF8nd-JiPFnxJ2H43ZS=oYgW4=BTZjR_GuUuj03gyRg@mail.gmail.com>

Hi Andy,

On 12/27/25 06:19, Andy Shevchenko wrote:
> On Fri, Dec 19, 2025 at 7:43 AM Chintan Patel <chintanlike@gmail.com> wrote:
>>
>> fbtft provides sysfs interfaces for debugging and gamma configuration,
>> but these are not required for the core driver.
>>
>> Drop the hard dependency on CONFIG_FB_DEVICE and make sysfs support
>> optional by using dev_of_fbinfo() at runtime. When FB_DEVICE is disabled,
>> sysfs operations are skipped while the code remains buildable and
>> type-checked.
> 
>> v2:
>> - Replace CONFIG_FB_DEVICE ifdefs with runtime checks
>> - Use dev_of_fbinfo() to guard sysfs creation and removal
> 
> The place for the change log is either a cover letter, or...
> 
>> Suggested-by: Thomas Zimmermann <tzimmermann@suse.de>
>> Suggested-by: Helge Deller <deller@gmx.de>
>> Signed-off-by: Chintan Patel <chintanlike@gmail.com>
>> ---
> 
> ...a comment block here. It's not so important to be in the Git
> history since we have a lore.kernel.org archive.

Thank you for suggestion! Will move to coverletter.

>>   drivers/staging/fbtft/Kconfig       |  5 ++++-
>>   drivers/staging/fbtft/fbtft-sysfs.c | 18 ++++++++++++++----
> 
> ...
> 
>>   void fbtft_sysfs_init(struct fbtft_par *par)
>>   {
>> -       device_create_file(par->info->dev, &debug_device_attr);
>> +       struct device *dev = dev_of_fbinfo(par->info);
>> +
>> +       if (!dev)
>> +               return;
> 
> 
> The better way is to decouple the definition and the assignment in the
> cases when it's followed by a conditional (validation check). In this
> case any new code added in between doesn't affect readability and
> maintenance efforts.
> 
>         struct device *dev;
> 
>         dev = dev_of_fbinfo(par->info);
>         if (!dev)
>                 return;
> 
>> +       device_create_file(dev, &debug_device_attr);
>>          if (par->gamma.curves && par->fbtftops.set_gamma)
>> -               device_create_file(par->info->dev, &gamma_device_attrs[0]);
>> +               device_create_file(dev, &gamma_device_attrs[0]);
>>   }
> 
> Ditto for the rest.

Will do v3 and re-send. Thanks for reviews!



^ permalink raw reply

* Re: [PATCH v2 0/4] fbdev: Make CONFIG_FB_DEVICE optional for drivers
From: Andy Shevchenko @ 2025-12-27 14:24 UTC (permalink / raw)
  To: Chintan Patel
  Cc: linux-fbdev, linux-staging, linux-omap, linux-kernel, dri-devel,
	tzimmermann, andy, deller, gregkh
In-Reply-To: <20251219054320.447281-1-chintanlike@gmail.com>

On Fri, Dec 19, 2025 at 7:43 AM Chintan Patel <chintanlike@gmail.com> wrote:
>
> This series makes CONFIG_FB_DEVICE optional for fbdev drivers that use
> it only for sysfs interfaces, addressing Thomas Zimmermann’s TODO to
> remove hard FB_DEVICE dependencies.
>
> The series introduces a small helper, dev_of_fbinfo(), which returns
> NULL when CONFIG_FB_DEVICE=n. This allows sysfs code paths to be skipped
> via runtime checks, avoids #ifdef CONFIG_FB_DEVICE clutter, and keeps
> full compile-time syntax checking.

Please, address my comments and I give a tag for v3. I pretty much
like the series, thanks!

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply

* Re: [PATCH v2 1/4] fb: Add dev_of_fbinfo() helper for optional sysfs support
From: Andy Shevchenko @ 2025-12-27 14:23 UTC (permalink / raw)
  To: Chintan Patel
  Cc: linux-fbdev, linux-staging, linux-omap, linux-kernel, dri-devel,
	tzimmermann, andy, deller, gregkh
In-Reply-To: <20251219054320.447281-2-chintanlike@gmail.com>

On Fri, Dec 19, 2025 at 7:43 AM Chintan Patel <chintanlike@gmail.com> wrote:
>
> Add dev_of_fbinfo() to return the framebuffer struct device when
> CONFIG_FB_DEVICE is enabled, or NULL otherwise.
>
> This allows fbdev drivers to use sysfs interfaces via runtime checks
> instead of CONFIG_FB_DEVICE ifdefs, keeping the code clean while
> remaining fully buildable.

Reviewed-by: Andy Shevchenko <andy@kernel.org>

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply

* Re: [PATCH v2 4/4] fbdev: sh_mobile_lcdc: Make FB_DEVICE dependency optional
From: Andy Shevchenko @ 2025-12-27 14:21 UTC (permalink / raw)
  To: Chintan Patel
  Cc: linux-fbdev, linux-staging, linux-omap, linux-kernel, dri-devel,
	tzimmermann, andy, deller, gregkh
In-Reply-To: <20251219054320.447281-5-chintanlike@gmail.com>

On Fri, Dec 19, 2025 at 7:43 AM Chintan Patel <chintanlike@gmail.com> wrote:
>
> The sh_mobile_lcdc driver exposes overlay configuration via sysfs, but the
> core driver does not require CONFIG_FB_DEVICE.
>
> Make sysfs support optional by defining overlay_sysfs_groups as NULL when
> FB_DEVICE is disabled. The driver always sets .dev_groups, and the kernel
> naturally skips NULL attribute groups while the code remains buildable
> and type-checked.

> v2:
> - Replace CONFIG_FB_DEVICE ifdefs with NULL overlay_sysfs_groups
> - Always populate .dev_groups

Same comment about the changelog in the commit messages.

...

> +#ifdef CONFIG_FB_DEVICE
>  ATTRIBUTE_GROUPS(overlay_sysfs);
> +#else
> +/*
> + * When CONFIG_FB_DEVICE is disabled, define overlay_sysfs_groups as NULL.
> + * The compiler will optimize out the sysfs code paths when dev_groups is NULL.
> + */
> +static const struct attribute_group *overlay_sysfs_groups[] = { NULL };
> +#endif

Hmm... I'm wondering if PTR_IF() can anyhow help here.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply

* Re: [PATCH v2 2/4] staging: fbtft: Make FB_DEVICE dependency optional
From: Andy Shevchenko @ 2025-12-27 14:19 UTC (permalink / raw)
  To: Chintan Patel
  Cc: linux-fbdev, linux-staging, linux-omap, linux-kernel, dri-devel,
	tzimmermann, andy, deller, gregkh
In-Reply-To: <20251219054320.447281-3-chintanlike@gmail.com>

On Fri, Dec 19, 2025 at 7:43 AM Chintan Patel <chintanlike@gmail.com> wrote:
>
> fbtft provides sysfs interfaces for debugging and gamma configuration,
> but these are not required for the core driver.
>
> Drop the hard dependency on CONFIG_FB_DEVICE and make sysfs support
> optional by using dev_of_fbinfo() at runtime. When FB_DEVICE is disabled,
> sysfs operations are skipped while the code remains buildable and
> type-checked.

> v2:
> - Replace CONFIG_FB_DEVICE ifdefs with runtime checks
> - Use dev_of_fbinfo() to guard sysfs creation and removal

The place for the change log is either a cover letter, or...

> Suggested-by: Thomas Zimmermann <tzimmermann@suse.de>
> Suggested-by: Helge Deller <deller@gmx.de>
> Signed-off-by: Chintan Patel <chintanlike@gmail.com>
> ---

...a comment block here. It's not so important to be in the Git
history since we have a lore.kernel.org archive.

>  drivers/staging/fbtft/Kconfig       |  5 ++++-
>  drivers/staging/fbtft/fbtft-sysfs.c | 18 ++++++++++++++----

...

>  void fbtft_sysfs_init(struct fbtft_par *par)
>  {
> -       device_create_file(par->info->dev, &debug_device_attr);
> +       struct device *dev = dev_of_fbinfo(par->info);
> +
> +       if (!dev)
> +               return;


The better way is to decouple the definition and the assignment in the
cases when it's followed by a conditional (validation check). In this
case any new code added in between doesn't affect readability and
maintenance efforts.

       struct device *dev;

       dev = dev_of_fbinfo(par->info);
       if (!dev)
               return;

> +       device_create_file(dev, &debug_device_attr);
>         if (par->gamma.curves && par->fbtftops.set_gamma)
> -               device_create_file(par->info->dev, &gamma_device_attrs[0]);
> +               device_create_file(dev, &gamma_device_attrs[0]);
>  }

Ditto for the rest.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply

* Re: [PATCH v2 2/4] staging: fbtft: Make FB_DEVICE dependency optional
From: Andy Shevchenko @ 2025-12-27 14:15 UTC (permalink / raw)
  To: Chintan Patel
  Cc: linux-fbdev, linux-staging, linux-omap, linux-kernel, dri-devel,
	tzimmermann, andy, deller, gregkh
In-Reply-To: <20251219054320.447281-3-chintanlike@gmail.com>

On Fri, Dec 19, 2025 at 7:43 AM Chintan Patel <chintanlike@gmail.com> wrote:
>
> fbtft provides sysfs interfaces for debugging and gamma configuration,
> but these are not required for the core driver.
>
> Drop the hard dependency on CONFIG_FB_DEVICE and make sysfs support
> optional by using dev_of_fbinfo() at runtime. When FB_DEVICE is disabled,
> sysfs operations are skipped while the code remains buildable and
> type-checked.
>
> v2:
> - Replace CONFIG_FB_DEVICE ifdefs with runtime checks
> - Use dev_of_fbinfo() to guard sysfs creation and removal
>
> Suggested-by: Thomas Zimmermann <tzimmermann@suse.de>
> Suggested-by: Helge Deller <deller@gmx.de>
> Signed-off-by: Chintan Patel <chintanlike@gmail.com>
> ---
>  drivers/staging/fbtft/Kconfig       |  5 ++++-
>  drivers/staging/fbtft/fbtft-sysfs.c | 18 ++++++++++++++----
>  2 files changed, 18 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig
> index c2655768209a..578412a2f379 100644
> --- a/drivers/staging/fbtft/Kconfig
> +++ b/drivers/staging/fbtft/Kconfig
> @@ -2,11 +2,14 @@
>  menuconfig FB_TFT
>         tristate "Support for small TFT LCD display modules"
>         depends on FB && SPI
> -       depends on FB_DEVICE
>         depends on BACKLIGHT_CLASS_DEVICE
>         depends on GPIOLIB || COMPILE_TEST
>         select FB_BACKLIGHT
>         select FB_SYSMEM_HELPERS_DEFERRED
> +       help
> +         Support for small TFT LCD display modules over SPI bus. FB_DEVICE
> +         is not required, but if enabled, provides sysfs interface for debugging
> +         and gamma curve configuration.
>
>  if FB_TFT
>
> diff --git a/drivers/staging/fbtft/fbtft-sysfs.c b/drivers/staging/fbtft/fbtft-sysfs.c
> index e45c90a03a90..848702fc871a 100644
> --- a/drivers/staging/fbtft/fbtft-sysfs.c
> +++ b/drivers/staging/fbtft/fbtft-sysfs.c
> @@ -203,14 +203,24 @@ static struct device_attribute debug_device_attr =
>
>  void fbtft_sysfs_init(struct fbtft_par *par)
>  {
> -       device_create_file(par->info->dev, &debug_device_attr);
> +       struct device *dev = dev_of_fbinfo(par->info);
> +
> +       if (!dev)
> +               return;
> +
> +       device_create_file(dev, &debug_device_attr);
>         if (par->gamma.curves && par->fbtftops.set_gamma)
> -               device_create_file(par->info->dev, &gamma_device_attrs[0]);
> +               device_create_file(dev, &gamma_device_attrs[0]);
>  }
>
>  void fbtft_sysfs_exit(struct fbtft_par *par)
>  {
> -       device_remove_file(par->info->dev, &debug_device_attr);
> +       struct device *dev = dev_of_fbinfo(par->info);
> +
> +       if (!dev)
> +               return;
> +
> +       device_remove_file(dev, &debug_device_attr);
>         if (par->gamma.curves && par->fbtftops.set_gamma)
> -               device_remove_file(par->info->dev, &gamma_device_attrs[0]);
> +               device_remove_file(dev, &gamma_device_attrs[0]);
>  }
> --
> 2.43.0
>


-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply

* [PATCH 1/3] drivers: video: fbdev: Remove hyperv_fb driver
From: Prasanna Kumar T S M @ 2025-12-27  4:24 UTC (permalink / raw)
  To: linux-fbdev, dri-devel, linux-hyperv, ssengar, mhklinux, wei.liu,
	ptsm, tzimmermann, deller, kys, haiyangz, decui
  Cc: mrathor, rdunlap, soci, hsukrut3, linux-kernel

The HyperV DRM driver is available since 5.14. This makes the hyperv_fb
driver redundant, remove it.

Signed-off-by: Prasanna Kumar T S M <ptsm@linux.microsoft.com>
---
 MAINTAINERS                     |   10 -
 drivers/video/fbdev/Kconfig     |   11 -
 drivers/video/fbdev/Makefile    |    1 -
 drivers/video/fbdev/hyperv_fb.c | 1388 -------------------------------
 4 files changed, 1410 deletions(-)
 delete mode 100644 drivers/video/fbdev/hyperv_fb.c

diff --git a/MAINTAINERS b/MAINTAINERS
index dc731d37c8fe..73073551048e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11762,16 +11762,6 @@ F:	include/uapi/rdma/mana-abi.h
 F:	net/vmw_vsock/hyperv_transport.c
 F:	tools/hv/
 
-HYPER-V FRAMEBUFFER DRIVER
-M:	"K. Y. Srinivasan" <kys@microsoft.com>
-M:	Haiyang Zhang <haiyangz@microsoft.com>
-M:	Wei Liu <wei.liu@kernel.org>
-M:	Dexuan Cui <decui@microsoft.com>
-L:	linux-hyperv@vger.kernel.org
-S:	Obsolete
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux.git
-F:	drivers/video/fbdev/hyperv_fb.c
-
 HYPERBUS SUPPORT
 M:	Vignesh Raghavendra <vigneshr@ti.com>
 R:	Tudor Ambarus <tudor.ambarus@linaro.org>
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index a733f90eca55..45733522ff48 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -1770,17 +1770,6 @@ config FB_BROADSHEET
 	  and could also have been called by other names when coupled with
 	  a bridge adapter.
 
-config FB_HYPERV
-	tristate "Microsoft Hyper-V Synthetic Video support (DEPRECATED)"
-	depends on FB && HYPERV_VMBUS
-	select DMA_CMA if HAVE_DMA_CONTIGUOUS && CMA
-	select FB_IOMEM_HELPERS_DEFERRED
-	help
-	  This framebuffer driver supports Microsoft Hyper-V Synthetic Video.
-
-	  This driver is deprecated, please use the Hyper-V DRM driver at
-	  drivers/gpu/drm/hyperv (CONFIG_DRM_HYPERV) instead.
-
 config FB_SIMPLE
 	tristate "Simple framebuffer support"
 	depends on FB
diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile
index b3d12f977c06..36a18d958ba0 100644
--- a/drivers/video/fbdev/Makefile
+++ b/drivers/video/fbdev/Makefile
@@ -111,7 +111,6 @@ obj-y                             += omap2/
 obj-$(CONFIG_XEN_FBDEV_FRONTEND)  += xen-fbfront.o
 obj-$(CONFIG_FB_CARMINE)          += carminefb.o
 obj-$(CONFIG_FB_MB862XX)	  += mb862xx/
-obj-$(CONFIG_FB_HYPERV)		  += hyperv_fb.o
 obj-$(CONFIG_FB_OPENCORES)	  += ocfb.o
 obj-$(CONFIG_FB_SM712)		  += sm712fb.o
 
diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
deleted file mode 100644
index c99e2ea4b3de..000000000000
--- a/drivers/video/fbdev/hyperv_fb.c
+++ /dev/null
@@ -1,1388 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (c) 2012, Microsoft Corporation.
- *
- * Author:
- *   Haiyang Zhang <haiyangz@microsoft.com>
- */
-
-/*
- * Hyper-V Synthetic Video Frame Buffer Driver
- *
- * This is the driver for the Hyper-V Synthetic Video, which supports
- * screen resolution up to Full HD 1920x1080 with 32 bit color on Windows
- * Server 2012, and 1600x1200 with 16 bit color on Windows Server 2008 R2
- * or earlier.
- *
- * It also solves the double mouse cursor issue of the emulated video mode.
- *
- * The default screen resolution is 1152x864, which may be changed by a
- * kernel parameter:
- *     video=hyperv_fb:<width>x<height>
- *     For example: video=hyperv_fb:1280x1024
- *
- * Portrait orientation is also supported:
- *     For example: video=hyperv_fb:864x1152
- *
- * When a Windows 10 RS5+ host is used, the virtual machine screen
- * resolution is obtained from the host. The "video=hyperv_fb" option is
- * not needed, but still can be used to overwrite what the host specifies.
- * The VM resolution on the host could be set by executing the powershell
- * "set-vmvideo" command. For example
- *     set-vmvideo -vmname name -horizontalresolution:1920 \
- * -verticalresolution:1200 -resolutiontype single
- *
- * Gen 1 VMs also support direct using VM's physical memory for framebuffer.
- * It could improve the efficiency and performance for framebuffer and VM.
- * This requires to allocate contiguous physical memory from Linux kernel's
- * CMA memory allocator. To enable this, supply a kernel parameter to give
- * enough memory space to CMA allocator for framebuffer. For example:
- *    cma=130m
- * This gives 130MB memory to CMA allocator that can be allocated to
- * framebuffer. For reference, 8K resolution (7680x4320) takes about
- * 127MB memory.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/aperture.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/vmalloc.h>
-#include <linux/init.h>
-#include <linux/completion.h>
-#include <linux/fb.h>
-#include <linux/pci.h>
-#include <linux/panic_notifier.h>
-#include <linux/efi.h>
-#include <linux/console.h>
-
-#include <linux/hyperv.h>
-
-/* Hyper-V Synthetic Video Protocol definitions and structures */
-#define MAX_VMBUS_PKT_SIZE 0x4000
-
-#define SYNTHVID_VERSION(major, minor) ((minor) << 16 | (major))
-/* Support for VERSION_WIN7 is removed. #define is retained for reference. */
-#define SYNTHVID_VERSION_WIN7 SYNTHVID_VERSION(3, 0)
-#define SYNTHVID_VERSION_WIN8 SYNTHVID_VERSION(3, 2)
-#define SYNTHVID_VERSION_WIN10 SYNTHVID_VERSION(3, 5)
-
-#define SYNTHVID_VER_GET_MAJOR(ver) (ver & 0x0000ffff)
-#define SYNTHVID_VER_GET_MINOR(ver) ((ver & 0xffff0000) >> 16)
-
-#define SYNTHVID_DEPTH_WIN8 32
-#define SYNTHVID_FB_SIZE_WIN8 (8 * 1024 * 1024)
-
-enum pipe_msg_type {
-	PIPE_MSG_INVALID,
-	PIPE_MSG_DATA,
-	PIPE_MSG_MAX
-};
-
-struct pipe_msg_hdr {
-	u32 type;
-	u32 size; /* size of message after this field */
-} __packed;
-
-
-enum synthvid_msg_type {
-	SYNTHVID_ERROR			= 0,
-	SYNTHVID_VERSION_REQUEST	= 1,
-	SYNTHVID_VERSION_RESPONSE	= 2,
-	SYNTHVID_VRAM_LOCATION		= 3,
-	SYNTHVID_VRAM_LOCATION_ACK	= 4,
-	SYNTHVID_SITUATION_UPDATE	= 5,
-	SYNTHVID_SITUATION_UPDATE_ACK	= 6,
-	SYNTHVID_POINTER_POSITION	= 7,
-	SYNTHVID_POINTER_SHAPE		= 8,
-	SYNTHVID_FEATURE_CHANGE		= 9,
-	SYNTHVID_DIRT			= 10,
-	SYNTHVID_RESOLUTION_REQUEST	= 13,
-	SYNTHVID_RESOLUTION_RESPONSE	= 14,
-
-	SYNTHVID_MAX			= 15
-};
-
-#define		SYNTHVID_EDID_BLOCK_SIZE	128
-#define		SYNTHVID_MAX_RESOLUTION_COUNT	64
-
-struct hvd_screen_info {
-	u16 width;
-	u16 height;
-} __packed;
-
-struct synthvid_msg_hdr {
-	u32 type;
-	u32 size;  /* size of this header + payload after this field*/
-} __packed;
-
-struct synthvid_version_req {
-	u32 version;
-} __packed;
-
-struct synthvid_version_resp {
-	u32 version;
-	u8 is_accepted;
-	u8 max_video_outputs;
-} __packed;
-
-struct synthvid_supported_resolution_req {
-	u8 maximum_resolution_count;
-} __packed;
-
-struct synthvid_supported_resolution_resp {
-	u8 edid_block[SYNTHVID_EDID_BLOCK_SIZE];
-	u8 resolution_count;
-	u8 default_resolution_index;
-	u8 is_standard;
-	struct hvd_screen_info
-		supported_resolution[SYNTHVID_MAX_RESOLUTION_COUNT];
-} __packed;
-
-struct synthvid_vram_location {
-	u64 user_ctx;
-	u8 is_vram_gpa_specified;
-	u64 vram_gpa;
-} __packed;
-
-struct synthvid_vram_location_ack {
-	u64 user_ctx;
-} __packed;
-
-struct video_output_situation {
-	u8 active;
-	u32 vram_offset;
-	u8 depth_bits;
-	u32 width_pixels;
-	u32 height_pixels;
-	u32 pitch_bytes;
-} __packed;
-
-struct synthvid_situation_update {
-	u64 user_ctx;
-	u8 video_output_count;
-	struct video_output_situation video_output[1];
-} __packed;
-
-struct synthvid_situation_update_ack {
-	u64 user_ctx;
-} __packed;
-
-struct synthvid_pointer_position {
-	u8 is_visible;
-	u8 video_output;
-	s32 image_x;
-	s32 image_y;
-} __packed;
-
-
-#define CURSOR_MAX_X 96
-#define CURSOR_MAX_Y 96
-#define CURSOR_ARGB_PIXEL_SIZE 4
-#define CURSOR_MAX_SIZE (CURSOR_MAX_X * CURSOR_MAX_Y * CURSOR_ARGB_PIXEL_SIZE)
-#define CURSOR_COMPLETE (-1)
-
-struct synthvid_pointer_shape {
-	u8 part_idx;
-	u8 is_argb;
-	u32 width; /* CURSOR_MAX_X at most */
-	u32 height; /* CURSOR_MAX_Y at most */
-	u32 hot_x; /* hotspot relative to upper-left of pointer image */
-	u32 hot_y;
-	u8 data[4];
-} __packed;
-
-struct synthvid_feature_change {
-	u8 is_dirt_needed;
-	u8 is_ptr_pos_needed;
-	u8 is_ptr_shape_needed;
-	u8 is_situ_needed;
-} __packed;
-
-struct rect {
-	s32 x1, y1; /* top left corner */
-	s32 x2, y2; /* bottom right corner, exclusive */
-} __packed;
-
-struct synthvid_dirt {
-	u8 video_output;
-	u8 dirt_count;
-	struct rect rect[1];
-} __packed;
-
-struct synthvid_msg {
-	struct pipe_msg_hdr pipe_hdr;
-	struct synthvid_msg_hdr vid_hdr;
-	union {
-		struct synthvid_version_req ver_req;
-		struct synthvid_version_resp ver_resp;
-		struct synthvid_vram_location vram;
-		struct synthvid_vram_location_ack vram_ack;
-		struct synthvid_situation_update situ;
-		struct synthvid_situation_update_ack situ_ack;
-		struct synthvid_pointer_position ptr_pos;
-		struct synthvid_pointer_shape ptr_shape;
-		struct synthvid_feature_change feature_chg;
-		struct synthvid_dirt dirt;
-		struct synthvid_supported_resolution_req resolution_req;
-		struct synthvid_supported_resolution_resp resolution_resp;
-	};
-} __packed;
-
-
-/* FB driver definitions and structures */
-#define HVFB_WIDTH 1152 /* default screen width */
-#define HVFB_HEIGHT 864 /* default screen height */
-#define HVFB_WIDTH_MIN 640
-#define HVFB_HEIGHT_MIN 480
-
-#define RING_BUFSIZE (256 * 1024)
-#define VSP_TIMEOUT (10 * HZ)
-#define HVFB_UPDATE_DELAY (HZ / 20)
-#define HVFB_ONDEMAND_THROTTLE (HZ / 20)
-
-struct hvfb_par {
-	struct fb_info *info;
-	struct resource *mem;
-	bool fb_ready; /* fb device is ready */
-	struct completion wait;
-	u32 synthvid_version;
-
-	struct delayed_work dwork;
-	bool update;
-	bool update_saved; /* The value of 'update' before hibernation */
-
-	u32 pseudo_palette[16];
-	u8 init_buf[MAX_VMBUS_PKT_SIZE];
-	u8 recv_buf[MAX_VMBUS_PKT_SIZE];
-
-	/* If true, the VSC notifies the VSP on every framebuffer change */
-	bool synchronous_fb;
-
-	/* If true, need to copy from deferred IO mem to framebuffer mem */
-	bool need_docopy;
-
-	struct notifier_block hvfb_panic_nb;
-
-	/* Memory for deferred IO and frame buffer itself */
-	unsigned char *dio_vp;
-	unsigned char *mmio_vp;
-	phys_addr_t mmio_pp;
-
-	/* Dirty rectangle, protected by delayed_refresh_lock */
-	int x1, y1, x2, y2;
-	bool delayed_refresh;
-	spinlock_t delayed_refresh_lock;
-};
-
-static uint screen_width = HVFB_WIDTH;
-static uint screen_height = HVFB_HEIGHT;
-static uint screen_depth;
-static uint screen_fb_size;
-static uint dio_fb_size; /* FB size for deferred IO */
-
-static void hvfb_putmem(struct fb_info *info);
-
-/* Send message to Hyper-V host */
-static inline int synthvid_send(struct hv_device *hdev,
-				struct synthvid_msg *msg)
-{
-	static atomic64_t request_id = ATOMIC64_INIT(0);
-	int ret;
-
-	msg->pipe_hdr.type = PIPE_MSG_DATA;
-	msg->pipe_hdr.size = msg->vid_hdr.size;
-
-	ret = vmbus_sendpacket(hdev->channel, msg,
-			       msg->vid_hdr.size + sizeof(struct pipe_msg_hdr),
-			       atomic64_inc_return(&request_id),
-			       VM_PKT_DATA_INBAND, 0);
-
-	if (ret)
-		pr_err_ratelimited("Unable to send packet via vmbus; error %d\n", ret);
-
-	return ret;
-}
-
-
-/* Send screen resolution info to host */
-static int synthvid_send_situ(struct hv_device *hdev)
-{
-	struct fb_info *info = hv_get_drvdata(hdev);
-	struct synthvid_msg msg;
-
-	if (!info)
-		return -ENODEV;
-
-	memset(&msg, 0, sizeof(struct synthvid_msg));
-
-	msg.vid_hdr.type = SYNTHVID_SITUATION_UPDATE;
-	msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
-		sizeof(struct synthvid_situation_update);
-	msg.situ.user_ctx = 0;
-	msg.situ.video_output_count = 1;
-	msg.situ.video_output[0].active = 1;
-	msg.situ.video_output[0].vram_offset = 0;
-	msg.situ.video_output[0].depth_bits = info->var.bits_per_pixel;
-	msg.situ.video_output[0].width_pixels = info->var.xres;
-	msg.situ.video_output[0].height_pixels = info->var.yres;
-	msg.situ.video_output[0].pitch_bytes = info->fix.line_length;
-
-	synthvid_send(hdev, &msg);
-
-	return 0;
-}
-
-/* Send mouse pointer info to host */
-static int synthvid_send_ptr(struct hv_device *hdev)
-{
-	struct synthvid_msg msg;
-
-	memset(&msg, 0, sizeof(struct synthvid_msg));
-	msg.vid_hdr.type = SYNTHVID_POINTER_POSITION;
-	msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
-		sizeof(struct synthvid_pointer_position);
-	msg.ptr_pos.is_visible = 1;
-	msg.ptr_pos.video_output = 0;
-	msg.ptr_pos.image_x = 0;
-	msg.ptr_pos.image_y = 0;
-	synthvid_send(hdev, &msg);
-
-	memset(&msg, 0, sizeof(struct synthvid_msg));
-	msg.vid_hdr.type = SYNTHVID_POINTER_SHAPE;
-	msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
-		sizeof(struct synthvid_pointer_shape);
-	msg.ptr_shape.part_idx = CURSOR_COMPLETE;
-	msg.ptr_shape.is_argb = 1;
-	msg.ptr_shape.width = 1;
-	msg.ptr_shape.height = 1;
-	msg.ptr_shape.hot_x = 0;
-	msg.ptr_shape.hot_y = 0;
-	msg.ptr_shape.data[0] = 0;
-	msg.ptr_shape.data[1] = 1;
-	msg.ptr_shape.data[2] = 1;
-	msg.ptr_shape.data[3] = 1;
-	synthvid_send(hdev, &msg);
-
-	return 0;
-}
-
-/* Send updated screen area (dirty rectangle) location to host */
-static int
-synthvid_update(struct fb_info *info, int x1, int y1, int x2, int y2)
-{
-	struct hv_device *hdev = device_to_hv_device(info->device);
-	struct synthvid_msg msg;
-
-	memset(&msg, 0, sizeof(struct synthvid_msg));
-	if (x2 == INT_MAX)
-		x2 = info->var.xres;
-	if (y2 == INT_MAX)
-		y2 = info->var.yres;
-
-	msg.vid_hdr.type = SYNTHVID_DIRT;
-	msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
-		sizeof(struct synthvid_dirt);
-	msg.dirt.video_output = 0;
-	msg.dirt.dirt_count = 1;
-	msg.dirt.rect[0].x1 = (x1 > x2) ? 0 : x1;
-	msg.dirt.rect[0].y1 = (y1 > y2) ? 0 : y1;
-	msg.dirt.rect[0].x2 =
-		(x2 < x1 || x2 > info->var.xres) ? info->var.xres : x2;
-	msg.dirt.rect[0].y2 =
-		(y2 < y1 || y2 > info->var.yres) ? info->var.yres : y2;
-
-	synthvid_send(hdev, &msg);
-
-	return 0;
-}
-
-static void hvfb_docopy(struct hvfb_par *par,
-			unsigned long offset,
-			unsigned long size)
-{
-	if (!par || !par->mmio_vp || !par->dio_vp || !par->fb_ready ||
-	    size == 0 || offset >= dio_fb_size)
-		return;
-
-	if (offset + size > dio_fb_size)
-		size = dio_fb_size - offset;
-
-	memcpy(par->mmio_vp + offset, par->dio_vp + offset, size);
-}
-
-/* Deferred IO callback */
-static void synthvid_deferred_io(struct fb_info *p, struct list_head *pagereflist)
-{
-	struct hvfb_par *par = p->par;
-	struct fb_deferred_io_pageref *pageref;
-	unsigned long start, end;
-	int y1, y2, miny, maxy;
-
-	miny = INT_MAX;
-	maxy = 0;
-
-	/*
-	 * Merge dirty pages. It is possible that last page cross
-	 * over the end of frame buffer row yres. This is taken care of
-	 * in synthvid_update function by clamping the y2
-	 * value to yres.
-	 */
-	list_for_each_entry(pageref, pagereflist, list) {
-		start = pageref->offset;
-		end = start + PAGE_SIZE - 1;
-		y1 = start / p->fix.line_length;
-		y2 = end / p->fix.line_length;
-		miny = min_t(int, miny, y1);
-		maxy = max_t(int, maxy, y2);
-
-		/* Copy from dio space to mmio address */
-		if (par->fb_ready && par->need_docopy)
-			hvfb_docopy(par, start, PAGE_SIZE);
-	}
-
-	if (par->fb_ready && par->update)
-		synthvid_update(p, 0, miny, p->var.xres, maxy + 1);
-}
-
-static struct fb_deferred_io synthvid_defio = {
-	.delay		= HZ / 20,
-	.deferred_io	= synthvid_deferred_io,
-};
-
-/*
- * Actions on received messages from host:
- * Complete the wait event.
- * Or, reply with screen and cursor info.
- */
-static void synthvid_recv_sub(struct hv_device *hdev)
-{
-	struct fb_info *info = hv_get_drvdata(hdev);
-	struct hvfb_par *par;
-	struct synthvid_msg *msg;
-
-	if (!info)
-		return;
-
-	par = info->par;
-	msg = (struct synthvid_msg *)par->recv_buf;
-
-	/* Complete the wait event */
-	if (msg->vid_hdr.type == SYNTHVID_VERSION_RESPONSE ||
-	    msg->vid_hdr.type == SYNTHVID_RESOLUTION_RESPONSE ||
-	    msg->vid_hdr.type == SYNTHVID_VRAM_LOCATION_ACK) {
-		memcpy(par->init_buf, msg, MAX_VMBUS_PKT_SIZE);
-		complete(&par->wait);
-		return;
-	}
-
-	/* Reply with screen and cursor info */
-	if (msg->vid_hdr.type == SYNTHVID_FEATURE_CHANGE) {
-		if (par->fb_ready) {
-			synthvid_send_ptr(hdev);
-			synthvid_send_situ(hdev);
-		}
-
-		par->update = msg->feature_chg.is_dirt_needed;
-		if (par->update)
-			schedule_delayed_work(&par->dwork, HVFB_UPDATE_DELAY);
-	}
-}
-
-/* Receive callback for messages from the host */
-static void synthvid_receive(void *ctx)
-{
-	struct hv_device *hdev = ctx;
-	struct fb_info *info = hv_get_drvdata(hdev);
-	struct hvfb_par *par;
-	struct synthvid_msg *recv_buf;
-	u32 bytes_recvd;
-	u64 req_id;
-	int ret;
-
-	if (!info)
-		return;
-
-	par = info->par;
-	recv_buf = (struct synthvid_msg *)par->recv_buf;
-
-	do {
-		ret = vmbus_recvpacket(hdev->channel, recv_buf,
-				       MAX_VMBUS_PKT_SIZE,
-				       &bytes_recvd, &req_id);
-		if (bytes_recvd > 0 &&
-		    recv_buf->pipe_hdr.type == PIPE_MSG_DATA)
-			synthvid_recv_sub(hdev);
-	} while (bytes_recvd > 0 && ret == 0);
-}
-
-/* Check if the ver1 version is equal or greater than ver2 */
-static inline bool synthvid_ver_ge(u32 ver1, u32 ver2)
-{
-	if (SYNTHVID_VER_GET_MAJOR(ver1) > SYNTHVID_VER_GET_MAJOR(ver2) ||
-	    (SYNTHVID_VER_GET_MAJOR(ver1) == SYNTHVID_VER_GET_MAJOR(ver2) &&
-	     SYNTHVID_VER_GET_MINOR(ver1) >= SYNTHVID_VER_GET_MINOR(ver2)))
-		return true;
-
-	return false;
-}
-
-/* Check synthetic video protocol version with the host */
-static int synthvid_negotiate_ver(struct hv_device *hdev, u32 ver)
-{
-	struct fb_info *info = hv_get_drvdata(hdev);
-	struct hvfb_par *par = info->par;
-	struct synthvid_msg *msg = (struct synthvid_msg *)par->init_buf;
-	int ret = 0;
-	unsigned long t;
-
-	memset(msg, 0, sizeof(struct synthvid_msg));
-	msg->vid_hdr.type = SYNTHVID_VERSION_REQUEST;
-	msg->vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
-		sizeof(struct synthvid_version_req);
-	msg->ver_req.version = ver;
-	synthvid_send(hdev, msg);
-
-	t = wait_for_completion_timeout(&par->wait, VSP_TIMEOUT);
-	if (!t) {
-		pr_err("Time out on waiting version response\n");
-		ret = -ETIMEDOUT;
-		goto out;
-	}
-	if (!msg->ver_resp.is_accepted) {
-		ret = -ENODEV;
-		goto out;
-	}
-
-	par->synthvid_version = ver;
-	pr_info("Synthvid Version major %d, minor %d\n",
-		SYNTHVID_VER_GET_MAJOR(ver), SYNTHVID_VER_GET_MINOR(ver));
-
-out:
-	return ret;
-}
-
-/* Get current resolution from the host */
-static int synthvid_get_supported_resolution(struct hv_device *hdev)
-{
-	struct fb_info *info = hv_get_drvdata(hdev);
-	struct hvfb_par *par = info->par;
-	struct synthvid_msg *msg = (struct synthvid_msg *)par->init_buf;
-	int ret = 0;
-	unsigned long t;
-	u8 index;
-
-	memset(msg, 0, sizeof(struct synthvid_msg));
-	msg->vid_hdr.type = SYNTHVID_RESOLUTION_REQUEST;
-	msg->vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
-		sizeof(struct synthvid_supported_resolution_req);
-
-	msg->resolution_req.maximum_resolution_count =
-		SYNTHVID_MAX_RESOLUTION_COUNT;
-	synthvid_send(hdev, msg);
-
-	t = wait_for_completion_timeout(&par->wait, VSP_TIMEOUT);
-	if (!t) {
-		pr_err("Time out on waiting resolution response\n");
-		ret = -ETIMEDOUT;
-		goto out;
-	}
-
-	if (msg->resolution_resp.resolution_count == 0) {
-		pr_err("No supported resolutions\n");
-		ret = -ENODEV;
-		goto out;
-	}
-
-	index = msg->resolution_resp.default_resolution_index;
-	if (index >= msg->resolution_resp.resolution_count) {
-		pr_err("Invalid resolution index: %d\n", index);
-		ret = -ENODEV;
-		goto out;
-	}
-
-	screen_width =
-		msg->resolution_resp.supported_resolution[index].width;
-	screen_height =
-		msg->resolution_resp.supported_resolution[index].height;
-
-out:
-	return ret;
-}
-
-/* Connect to VSP (Virtual Service Provider) on host */
-static int synthvid_connect_vsp(struct hv_device *hdev)
-{
-	struct fb_info *info = hv_get_drvdata(hdev);
-	struct hvfb_par *par = info->par;
-	int ret;
-
-	ret = vmbus_open(hdev->channel, RING_BUFSIZE, RING_BUFSIZE,
-			 NULL, 0, synthvid_receive, hdev);
-	if (ret) {
-		pr_err("Unable to open vmbus channel\n");
-		return ret;
-	}
-
-	/* Negotiate the protocol version with host */
-	switch (vmbus_proto_version) {
-	case VERSION_WIN10:
-	case VERSION_WIN10_V5:
-		ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN10);
-		if (!ret)
-			break;
-		fallthrough;
-	case VERSION_WIN8:
-	case VERSION_WIN8_1:
-		ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN8);
-		break;
-	default:
-		ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN10);
-		break;
-	}
-
-	if (ret) {
-		pr_err("Synthetic video device version not accepted\n");
-		goto error;
-	}
-
-	screen_depth = SYNTHVID_DEPTH_WIN8;
-	if (synthvid_ver_ge(par->synthvid_version, SYNTHVID_VERSION_WIN10)) {
-		ret = synthvid_get_supported_resolution(hdev);
-		if (ret)
-			pr_info("Failed to get supported resolution from host, use default\n");
-	}
-
-	screen_fb_size = hdev->channel->offermsg.offer.
-				mmio_megabytes * 1024 * 1024;
-
-	return 0;
-
-error:
-	vmbus_close(hdev->channel);
-	return ret;
-}
-
-/* Send VRAM and Situation messages to the host */
-static int synthvid_send_config(struct hv_device *hdev)
-{
-	struct fb_info *info = hv_get_drvdata(hdev);
-	struct hvfb_par *par = info->par;
-	struct synthvid_msg *msg = (struct synthvid_msg *)par->init_buf;
-	int ret = 0;
-	unsigned long t;
-
-	/* Send VRAM location */
-	memset(msg, 0, sizeof(struct synthvid_msg));
-	msg->vid_hdr.type = SYNTHVID_VRAM_LOCATION;
-	msg->vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
-		sizeof(struct synthvid_vram_location);
-	msg->vram.user_ctx = msg->vram.vram_gpa = par->mmio_pp;
-	msg->vram.is_vram_gpa_specified = 1;
-	synthvid_send(hdev, msg);
-
-	t = wait_for_completion_timeout(&par->wait, VSP_TIMEOUT);
-	if (!t) {
-		pr_err("Time out on waiting vram location ack\n");
-		ret = -ETIMEDOUT;
-		goto out;
-	}
-	if (msg->vram_ack.user_ctx != par->mmio_pp) {
-		pr_err("Unable to set VRAM location\n");
-		ret = -ENODEV;
-		goto out;
-	}
-
-	/* Send pointer and situation update */
-	synthvid_send_ptr(hdev);
-	synthvid_send_situ(hdev);
-
-out:
-	return ret;
-}
-
-
-/*
- * Delayed work callback:
- * It is scheduled to call whenever update request is received and it has
- * not been called in last HVFB_ONDEMAND_THROTTLE time interval.
- */
-static void hvfb_update_work(struct work_struct *w)
-{
-	struct hvfb_par *par = container_of(w, struct hvfb_par, dwork.work);
-	struct fb_info *info = par->info;
-	unsigned long flags;
-	int x1, x2, y1, y2;
-	int j;
-
-	spin_lock_irqsave(&par->delayed_refresh_lock, flags);
-	/* Reset the request flag */
-	par->delayed_refresh = false;
-
-	/* Store the dirty rectangle to local variables */
-	x1 = par->x1;
-	x2 = par->x2;
-	y1 = par->y1;
-	y2 = par->y2;
-
-	/* Clear dirty rectangle */
-	par->x1 = par->y1 = INT_MAX;
-	par->x2 = par->y2 = 0;
-
-	spin_unlock_irqrestore(&par->delayed_refresh_lock, flags);
-
-	if (x1 > info->var.xres || x2 > info->var.xres ||
-	    y1 > info->var.yres || y2 > info->var.yres || x2 <= x1)
-		return;
-
-	/* Copy the dirty rectangle to frame buffer memory */
-	if (par->need_docopy)
-		for (j = y1; j < y2; j++)
-			hvfb_docopy(par,
-				    j * info->fix.line_length +
-				    (x1 * screen_depth / 8),
-				    (x2 - x1) * screen_depth / 8);
-
-	/* Refresh */
-	if (par->fb_ready && par->update)
-		synthvid_update(info, x1, y1, x2, y2);
-}
-
-/*
- * Control the on-demand refresh frequency. It schedules a delayed
- * screen update if it has not yet.
- */
-static void hvfb_ondemand_refresh_throttle(struct hvfb_par *par,
-					   int x1, int y1, int w, int h)
-{
-	unsigned long flags;
-	int x2 = x1 + w;
-	int y2 = y1 + h;
-
-	spin_lock_irqsave(&par->delayed_refresh_lock, flags);
-
-	/* Merge dirty rectangle */
-	par->x1 = min_t(int, par->x1, x1);
-	par->y1 = min_t(int, par->y1, y1);
-	par->x2 = max_t(int, par->x2, x2);
-	par->y2 = max_t(int, par->y2, y2);
-
-	/* Schedule a delayed screen update if not yet */
-	if (par->delayed_refresh == false) {
-		schedule_delayed_work(&par->dwork,
-				      HVFB_ONDEMAND_THROTTLE);
-		par->delayed_refresh = true;
-	}
-
-	spin_unlock_irqrestore(&par->delayed_refresh_lock, flags);
-}
-
-static int hvfb_on_panic(struct notifier_block *nb,
-			 unsigned long e, void *p)
-{
-	struct hv_device *hdev;
-	struct hvfb_par *par;
-	struct fb_info *info;
-
-	par = container_of(nb, struct hvfb_par, hvfb_panic_nb);
-	info = par->info;
-	hdev = device_to_hv_device(info->device);
-
-	if (hv_ringbuffer_spinlock_busy(hdev->channel))
-		return NOTIFY_DONE;
-
-	par->synchronous_fb = true;
-	if (par->need_docopy)
-		hvfb_docopy(par, 0, dio_fb_size);
-	synthvid_update(info, 0, 0, INT_MAX, INT_MAX);
-
-	return NOTIFY_DONE;
-}
-
-/* Framebuffer operation handlers */
-
-static int hvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
-{
-	if (var->xres < HVFB_WIDTH_MIN || var->yres < HVFB_HEIGHT_MIN ||
-	    var->xres > screen_width || var->yres >  screen_height ||
-	    var->bits_per_pixel != screen_depth)
-		return -EINVAL;
-
-	var->xres_virtual = var->xres;
-	var->yres_virtual = var->yres;
-
-	return 0;
-}
-
-static int hvfb_set_par(struct fb_info *info)
-{
-	struct hv_device *hdev = device_to_hv_device(info->device);
-
-	return synthvid_send_situ(hdev);
-}
-
-
-static inline u32 chan_to_field(u32 chan, struct fb_bitfield *bf)
-{
-	return ((chan & 0xffff) >> (16 - bf->length)) << bf->offset;
-}
-
-static int hvfb_setcolreg(unsigned regno, unsigned red, unsigned green,
-			  unsigned blue, unsigned transp, struct fb_info *info)
-{
-	u32 *pal = info->pseudo_palette;
-
-	if (regno > 15)
-		return -EINVAL;
-
-	pal[regno] = chan_to_field(red, &info->var.red)
-		| chan_to_field(green, &info->var.green)
-		| chan_to_field(blue, &info->var.blue)
-		| chan_to_field(transp, &info->var.transp);
-
-	return 0;
-}
-
-static int hvfb_blank(int blank, struct fb_info *info)
-{
-	return 1;	/* get fb_blank to set the colormap to all black */
-}
-
-static void hvfb_ops_damage_range(struct fb_info *info, off_t off, size_t len)
-{
-	/* TODO: implement damage handling */
-}
-
-static void hvfb_ops_damage_area(struct fb_info *info, u32 x, u32 y, u32 width, u32 height)
-{
-	struct hvfb_par *par = info->par;
-
-	if (par->synchronous_fb)
-		synthvid_update(info, 0, 0, INT_MAX, INT_MAX);
-	else
-		hvfb_ondemand_refresh_throttle(par, x, y, width, height);
-}
-
-/*
- * fb_ops.fb_destroy is called by the last put_fb_info() call at the end
- * of unregister_framebuffer() or fb_release(). Do any cleanup related to
- * framebuffer here.
- */
-static void hvfb_destroy(struct fb_info *info)
-{
-	hvfb_putmem(info);
-	framebuffer_release(info);
-}
-
-/*
- * TODO: GEN1 codepaths allocate from system or DMA-able memory. Fix the
- *       driver to use the _SYSMEM_ or _DMAMEM_ helpers in these cases.
- */
-FB_GEN_DEFAULT_DEFERRED_IOMEM_OPS(hvfb_ops,
-				  hvfb_ops_damage_range,
-				  hvfb_ops_damage_area)
-
-static const struct fb_ops hvfb_ops = {
-	.owner = THIS_MODULE,
-	FB_DEFAULT_DEFERRED_OPS(hvfb_ops),
-	.fb_check_var = hvfb_check_var,
-	.fb_set_par = hvfb_set_par,
-	.fb_setcolreg = hvfb_setcolreg,
-	.fb_blank = hvfb_blank,
-	.fb_destroy	= hvfb_destroy,
-};
-
-/* Get options from kernel paramenter "video=" */
-static void hvfb_get_option(struct fb_info *info)
-{
-	struct hvfb_par *par = info->par;
-	char *opt = NULL, *p;
-	uint x = 0, y = 0;
-
-	if (fb_get_options(KBUILD_MODNAME, &opt) || !opt || !*opt)
-		return;
-
-	p = strsep(&opt, "x");
-	if (!*p || kstrtouint(p, 0, &x) ||
-	    !opt || !*opt || kstrtouint(opt, 0, &y)) {
-		pr_err("Screen option is invalid: skipped\n");
-		return;
-	}
-
-	if (x < HVFB_WIDTH_MIN || y < HVFB_HEIGHT_MIN ||
-	    (synthvid_ver_ge(par->synthvid_version, SYNTHVID_VERSION_WIN10) &&
-	    (x * y * screen_depth / 8 > screen_fb_size)) ||
-	    (par->synthvid_version == SYNTHVID_VERSION_WIN8 &&
-	     x * y * screen_depth / 8 > SYNTHVID_FB_SIZE_WIN8)) {
-		pr_err("Screen resolution option is out of range: skipped\n");
-		return;
-	}
-
-	screen_width = x;
-	screen_height = y;
-	return;
-}
-
-/*
- * Allocate enough contiguous physical memory.
- * Return physical address if succeeded or -1 if failed.
- */
-static phys_addr_t hvfb_get_phymem(struct hv_device *hdev,
-				   unsigned int request_size)
-{
-	struct page *page = NULL;
-	dma_addr_t dma_handle;
-	void *vmem;
-	phys_addr_t paddr = 0;
-	unsigned int order = get_order(request_size);
-
-	if (request_size == 0)
-		return -1;
-
-	if (order <= MAX_PAGE_ORDER) {
-		/* Call alloc_pages if the size is less than 2^MAX_PAGE_ORDER */
-		page = alloc_pages(GFP_KERNEL | __GFP_ZERO, order);
-		if (!page)
-			return -1;
-
-		paddr = (page_to_pfn(page) << PAGE_SHIFT);
-	} else {
-		/* Allocate from CMA */
-		hdev->device.coherent_dma_mask = DMA_BIT_MASK(64);
-
-		vmem = dma_alloc_coherent(&hdev->device,
-					  round_up(request_size, PAGE_SIZE),
-					  &dma_handle,
-					  GFP_KERNEL | __GFP_NOWARN);
-
-		if (!vmem)
-			return -1;
-
-		paddr = virt_to_phys(vmem);
-	}
-
-	return paddr;
-}
-
-/* Release contiguous physical memory */
-static void hvfb_release_phymem(struct device *device,
-				phys_addr_t paddr, unsigned int size)
-{
-	unsigned int order = get_order(size);
-
-	if (order <= MAX_PAGE_ORDER)
-		__free_pages(pfn_to_page(paddr >> PAGE_SHIFT), order);
-	else
-		dma_free_coherent(device,
-				  round_up(size, PAGE_SIZE),
-				  phys_to_virt(paddr),
-				  paddr);
-}
-
-
-/* Get framebuffer memory from Hyper-V video pci space */
-static int hvfb_getmem(struct hv_device *hdev, struct fb_info *info)
-{
-	struct hvfb_par *par = info->par;
-	struct pci_dev *pdev  = NULL;
-	void __iomem *fb_virt;
-	int gen2vm = efi_enabled(EFI_BOOT);
-	resource_size_t base = 0;
-	resource_size_t size = 0;
-	phys_addr_t paddr;
-	int ret;
-
-	if (!gen2vm) {
-		pdev = pci_get_device(PCI_VENDOR_ID_MICROSOFT,
-			PCI_DEVICE_ID_HYPERV_VIDEO, NULL);
-		if (!pdev) {
-			pr_err("Unable to find PCI Hyper-V video\n");
-			return -ENODEV;
-		}
-
-		base = pci_resource_start(pdev, 0);
-		size = pci_resource_len(pdev, 0);
-		aperture_remove_conflicting_devices(base, size, KBUILD_MODNAME);
-
-		/*
-		 * For Gen 1 VM, we can directly use the contiguous memory
-		 * from VM. If we succeed, deferred IO happens directly
-		 * on this allocated framebuffer memory, avoiding extra
-		 * memory copy.
-		 */
-		paddr = hvfb_get_phymem(hdev, screen_fb_size);
-		if (paddr != (phys_addr_t) -1) {
-			par->mmio_pp = paddr;
-			par->mmio_vp = par->dio_vp = __va(paddr);
-
-			info->fix.smem_start = paddr;
-			info->fix.smem_len = screen_fb_size;
-			info->screen_base = par->mmio_vp;
-			info->screen_size = screen_fb_size;
-
-			par->need_docopy = false;
-			goto getmem_done;
-		}
-		pr_info("Unable to allocate enough contiguous physical memory on Gen 1 VM. Using MMIO instead.\n");
-	} else {
-		aperture_remove_all_conflicting_devices(KBUILD_MODNAME);
-	}
-
-	/*
-	 * Cannot use contiguous physical memory, so allocate MMIO space for
-	 * the framebuffer. At this point in the function, conflicting devices
-	 * that might have claimed the framebuffer MMIO space based on
-	 * screen_info.lfb_base must have already been removed so that
-	 * vmbus_allocate_mmio() does not allocate different MMIO space. If the
-	 * kdump image were to be loaded using kexec_file_load(), the
-	 * framebuffer location in the kdump image would be set from
-	 * screen_info.lfb_base at the time that kdump is enabled. If the
-	 * framebuffer has moved elsewhere, this could be the wrong location,
-	 * causing kdump to hang when efifb (for example) loads.
-	 */
-	dio_fb_size =
-		screen_width * screen_height * screen_depth / 8;
-
-	ret = vmbus_allocate_mmio(&par->mem, hdev, 0, -1,
-				  screen_fb_size, 0x100000, true);
-	if (ret != 0) {
-		pr_err("Unable to allocate framebuffer memory\n");
-		goto err1;
-	}
-
-	/*
-	 * Map the VRAM cacheable for performance. This is also required for
-	 * VM Connect to display properly for ARM64 Linux VM, as the host also
-	 * maps the VRAM cacheable.
-	 */
-	fb_virt = ioremap_cache(par->mem->start, screen_fb_size);
-	if (!fb_virt)
-		goto err2;
-
-	/* Allocate memory for deferred IO */
-	par->dio_vp = vzalloc(round_up(dio_fb_size, PAGE_SIZE));
-	if (par->dio_vp == NULL)
-		goto err3;
-
-	/* Physical address of FB device */
-	par->mmio_pp = par->mem->start;
-	/* Virtual address of FB device */
-	par->mmio_vp = (unsigned char *) fb_virt;
-
-	info->fix.smem_start = par->mem->start;
-	info->fix.smem_len = dio_fb_size;
-	info->screen_base = par->dio_vp;
-	info->screen_size = dio_fb_size;
-
-getmem_done:
-	if (!gen2vm)
-		pci_dev_put(pdev);
-
-	return 0;
-
-err3:
-	iounmap(fb_virt);
-err2:
-	vmbus_free_mmio(par->mem->start, screen_fb_size);
-	par->mem = NULL;
-err1:
-	if (!gen2vm)
-		pci_dev_put(pdev);
-
-	return -ENOMEM;
-}
-
-/* Release the framebuffer */
-static void hvfb_putmem(struct fb_info *info)
-{
-	struct hvfb_par *par = info->par;
-
-	if (par->need_docopy) {
-		vfree(par->dio_vp);
-		iounmap(par->mmio_vp);
-		vmbus_free_mmio(par->mem->start, screen_fb_size);
-	} else {
-		hvfb_release_phymem(info->device, info->fix.smem_start,
-				    screen_fb_size);
-	}
-
-	par->mem = NULL;
-}
-
-
-static int hvfb_probe(struct hv_device *hdev,
-		      const struct hv_vmbus_device_id *dev_id)
-{
-	struct fb_info *info;
-	struct hvfb_par *par;
-	int ret;
-
-	info = framebuffer_alloc(sizeof(struct hvfb_par), &hdev->device);
-	if (!info)
-		return -ENOMEM;
-
-	par = info->par;
-	par->info = info;
-	par->fb_ready = false;
-	par->need_docopy = true;
-	init_completion(&par->wait);
-	INIT_DELAYED_WORK(&par->dwork, hvfb_update_work);
-
-	par->delayed_refresh = false;
-	spin_lock_init(&par->delayed_refresh_lock);
-	par->x1 = par->y1 = INT_MAX;
-	par->x2 = par->y2 = 0;
-
-	/* Connect to VSP */
-	hv_set_drvdata(hdev, info);
-	ret = synthvid_connect_vsp(hdev);
-	if (ret) {
-		pr_err("Unable to connect to VSP\n");
-		goto error1;
-	}
-
-	hvfb_get_option(info);
-	pr_info("Screen resolution: %dx%d, Color depth: %d, Frame buffer size: %d\n",
-		screen_width, screen_height, screen_depth, screen_fb_size);
-
-	ret = hvfb_getmem(hdev, info);
-	if (ret) {
-		pr_err("No memory for framebuffer\n");
-		goto error2;
-	}
-
-	/* Set up fb_info */
-	info->var.xres_virtual = info->var.xres = screen_width;
-	info->var.yres_virtual = info->var.yres = screen_height;
-	info->var.bits_per_pixel = screen_depth;
-
-	if (info->var.bits_per_pixel == 16) {
-		info->var.red = (struct fb_bitfield){11, 5, 0};
-		info->var.green = (struct fb_bitfield){5, 6, 0};
-		info->var.blue = (struct fb_bitfield){0, 5, 0};
-		info->var.transp = (struct fb_bitfield){0, 0, 0};
-	} else {
-		info->var.red = (struct fb_bitfield){16, 8, 0};
-		info->var.green = (struct fb_bitfield){8, 8, 0};
-		info->var.blue = (struct fb_bitfield){0, 8, 0};
-		info->var.transp = (struct fb_bitfield){24, 8, 0};
-	}
-
-	info->var.activate = FB_ACTIVATE_NOW;
-	info->var.height = -1;
-	info->var.width = -1;
-	info->var.vmode = FB_VMODE_NONINTERLACED;
-
-	strcpy(info->fix.id, KBUILD_MODNAME);
-	info->fix.type = FB_TYPE_PACKED_PIXELS;
-	info->fix.visual = FB_VISUAL_TRUECOLOR;
-	info->fix.line_length = screen_width * screen_depth / 8;
-	info->fix.accel = FB_ACCEL_NONE;
-
-	info->fbops = &hvfb_ops;
-	info->pseudo_palette = par->pseudo_palette;
-
-	/* Initialize deferred IO */
-	info->fbdefio = &synthvid_defio;
-	fb_deferred_io_init(info);
-
-	/* Send config to host */
-	ret = synthvid_send_config(hdev);
-	if (ret)
-		goto error;
-
-	ret = devm_register_framebuffer(&hdev->device, info);
-	if (ret) {
-		pr_err("Unable to register framebuffer\n");
-		goto error;
-	}
-
-	par->fb_ready = true;
-
-	par->synchronous_fb = false;
-
-	/*
-	 * We need to be sure this panic notifier runs _before_ the
-	 * vmbus disconnect, so order it by priority. It must execute
-	 * before the function hv_panic_vmbus_unload() [drivers/hv/vmbus_drv.c],
-	 * which is almost at the end of list, with priority = INT_MIN + 1.
-	 */
-	par->hvfb_panic_nb.notifier_call = hvfb_on_panic;
-	par->hvfb_panic_nb.priority = INT_MIN + 10;
-	atomic_notifier_chain_register(&panic_notifier_list,
-				       &par->hvfb_panic_nb);
-
-	return 0;
-
-error:
-	fb_deferred_io_cleanup(info);
-	hvfb_putmem(info);
-error2:
-	vmbus_close(hdev->channel);
-error1:
-	cancel_delayed_work_sync(&par->dwork);
-	hv_set_drvdata(hdev, NULL);
-	framebuffer_release(info);
-	return ret;
-}
-
-static void hvfb_remove(struct hv_device *hdev)
-{
-	struct fb_info *info = hv_get_drvdata(hdev);
-	struct hvfb_par *par = info->par;
-
-	atomic_notifier_chain_unregister(&panic_notifier_list,
-					 &par->hvfb_panic_nb);
-
-	par->update = false;
-	par->fb_ready = false;
-
-	fb_deferred_io_cleanup(info);
-
-	cancel_delayed_work_sync(&par->dwork);
-
-	vmbus_close(hdev->channel);
-	hv_set_drvdata(hdev, NULL);
-}
-
-static int hvfb_suspend(struct hv_device *hdev)
-{
-	struct fb_info *info = hv_get_drvdata(hdev);
-	struct hvfb_par *par = info->par;
-
-	console_lock();
-
-	/* 1 means do suspend */
-	fb_set_suspend(info, 1);
-
-	cancel_delayed_work_sync(&par->dwork);
-	cancel_delayed_work_sync(&info->deferred_work);
-
-	par->update_saved = par->update;
-	par->update = false;
-	par->fb_ready = false;
-
-	vmbus_close(hdev->channel);
-
-	console_unlock();
-
-	return 0;
-}
-
-static int hvfb_resume(struct hv_device *hdev)
-{
-	struct fb_info *info = hv_get_drvdata(hdev);
-	struct hvfb_par *par = info->par;
-	int ret;
-
-	console_lock();
-
-	ret = synthvid_connect_vsp(hdev);
-	if (ret != 0)
-		goto out;
-
-	ret = synthvid_send_config(hdev);
-	if (ret != 0) {
-		vmbus_close(hdev->channel);
-		goto out;
-	}
-
-	par->fb_ready = true;
-	par->update = par->update_saved;
-
-	schedule_delayed_work(&info->deferred_work, info->fbdefio->delay);
-	schedule_delayed_work(&par->dwork, HVFB_UPDATE_DELAY);
-
-	/* 0 means do resume */
-	fb_set_suspend(info, 0);
-
-out:
-	console_unlock();
-
-	return ret;
-}
-
-
-static const struct pci_device_id pci_stub_id_table[] = {
-	{
-		.vendor      = PCI_VENDOR_ID_MICROSOFT,
-		.device      = PCI_DEVICE_ID_HYPERV_VIDEO,
-	},
-	{ /* end of list */ }
-};
-
-static const struct hv_vmbus_device_id id_table[] = {
-	/* Synthetic Video Device GUID */
-	{HV_SYNTHVID_GUID},
-	{}
-};
-
-MODULE_DEVICE_TABLE(pci, pci_stub_id_table);
-MODULE_DEVICE_TABLE(vmbus, id_table);
-
-static struct hv_driver hvfb_drv = {
-	.name = KBUILD_MODNAME,
-	.id_table = id_table,
-	.probe = hvfb_probe,
-	.remove = hvfb_remove,
-	.suspend = hvfb_suspend,
-	.resume = hvfb_resume,
-	.driver = {
-		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
-	},
-};
-
-static int hvfb_pci_stub_probe(struct pci_dev *pdev,
-			       const struct pci_device_id *ent)
-{
-	return 0;
-}
-
-static void hvfb_pci_stub_remove(struct pci_dev *pdev)
-{
-}
-
-static struct pci_driver hvfb_pci_stub_driver = {
-	.name =		KBUILD_MODNAME,
-	.id_table =	pci_stub_id_table,
-	.probe =	hvfb_pci_stub_probe,
-	.remove =	hvfb_pci_stub_remove,
-	.driver = {
-		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
-	}
-};
-
-static int __init hvfb_drv_init(void)
-{
-	int ret;
-
-	pr_warn("Deprecated: use Hyper-V DRM driver instead\n");
-
-	if (fb_modesetting_disabled("hyper_fb"))
-		return -ENODEV;
-
-	ret = vmbus_driver_register(&hvfb_drv);
-	if (ret != 0)
-		return ret;
-
-	ret = pci_register_driver(&hvfb_pci_stub_driver);
-	if (ret != 0) {
-		vmbus_driver_unregister(&hvfb_drv);
-		return ret;
-	}
-
-	return 0;
-}
-
-static void __exit hvfb_drv_exit(void)
-{
-	pci_unregister_driver(&hvfb_pci_stub_driver);
-	vmbus_driver_unregister(&hvfb_drv);
-}
-
-module_init(hvfb_drv_init);
-module_exit(hvfb_drv_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Microsoft Hyper-V Synthetic Video Frame Buffer Driver");
-- 
2.49.0


^ permalink raw reply related

* Re: [PATCH v2] fbdev: bitblit: bound-check glyph index in bit_putcs*
From: Barry K. Nathan @ 2025-12-27  2:04 UTC (permalink / raw)
  To: Vitaly Chikunov, Junjie Cao, Thomas Zimmermann,
	Greg Kroah-Hartman
  Cc: Peilin Ye, Daniel Vetter, Shigeru Yoshida, Simona Vetter,
	Helge Deller, Zsolt Kajtar, Albin Babu Varghese, linux-fbdev,
	dri-devel, linux-kernel, stable, regressions
In-Reply-To: <aU58SeZZPxScVPad@altlinux.org>

On 12/26/25 4:21 AM, Vitaly Chikunov wrote:
> Dear linux-fbdev, stable,
> 
> On Fri, Dec 26, 2025 at 01:29:13AM +0300, Vitaly Chikunov wrote:
>>
>> On Mon, Oct 20, 2025 at 09:47:01PM +0800, Junjie Cao wrote:
>>> bit_putcs_aligned()/unaligned() derived the glyph pointer from the
>>> character value masked by 0xff/0x1ff, which may exceed the actual font's
>>> glyph count and read past the end of the built-in font array.
>>> Clamp the index to the actual glyph count before computing the address.
>>>
>>> This fixes a global out-of-bounds read reported by syzbot.
>>>
>>> Reported-by: syzbot+793cf822d213be1a74f2@syzkaller.appspotmail.com
>>> Closes: https://syzkaller.appspot.com/bug?extid=793cf822d213be1a74f2
>>> Tested-by: syzbot+793cf822d213be1a74f2@syzkaller.appspotmail.com
>>> Signed-off-by: Junjie Cao <junjie.cao@intel.com>
>>
>> This commit is applied to v5.10.247 and causes a regression: when
>> switching VT with ctrl-alt-f2 the screen is blank or completely filled
>> with angle characters, then new text is not appearing (or not visible).
>>
>> This commit is found with git bisect from v5.10.246 to v5.10.247:
>>
>>    0998a6cb232674408a03e8561dc15aa266b2f53b is the first bad commit
>>    commit 0998a6cb232674408a03e8561dc15aa266b2f53b
>>    Author:     Junjie Cao <junjie.cao@intel.com>
>>    AuthorDate: 2025-10-20 21:47:01 +0800
>>    Commit:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>>    CommitDate: 2025-12-07 06:08:07 +0900
>>
>>        fbdev: bitblit: bound-check glyph index in bit_putcs*
>>
>>        commit 18c4ef4e765a798b47980555ed665d78b71aeadf upstream.
>>
>>        bit_putcs_aligned()/unaligned() derived the glyph pointer from the
>>        character value masked by 0xff/0x1ff, which may exceed the actual font's
>>        glyph count and read past the end of the built-in font array.
>>        Clamp the index to the actual glyph count before computing the address.
>>
>>        This fixes a global out-of-bounds read reported by syzbot.
>>
>>        Reported-by: syzbot+793cf822d213be1a74f2@syzkaller.appspotmail.com
>>        Closes: https://syzkaller.appspot.com/bug?extid=793cf822d213be1a74f2
>>        Tested-by: syzbot+793cf822d213be1a74f2@syzkaller.appspotmail.com
>>        Signed-off-by: Junjie Cao <junjie.cao@intel.com>
>>        Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
>>        Signed-off-by: Helge Deller <deller@gmx.de>
>>        Cc: stable@vger.kernel.org
>>        Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>>
>>     drivers/video/fbdev/core/bitblit.c | 16 ++++++++++++----
>>     1 file changed, 12 insertions(+), 4 deletions(-)
>>
>> The minimal reproducer in cli, after kernel is booted:
>>
>>    date >/dev/tty2; chvt 2
>>
>> and the date does not appear.
>>
>> Thanks,
>>
>> #regzbot introduced: 0998a6cb232674408a03e8561dc15aa266b2f53b
>>
>>> ---
>>> v1: https://lore.kernel.org/linux-fbdev/5d237d1a-a528-4205-a4d8-71709134f1e1@suse.de/
>>> v1 -> v2:
>>>   - Fix indentation and add blank line after declarations with the .pl helper
>>>   - No functional changes
>>>
>>>   drivers/video/fbdev/core/bitblit.c | 16 ++++++++++++----
>>>   1 file changed, 12 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c
>>> index 9d2e59796c3e..085ffb44c51a 100644
>>> --- a/drivers/video/fbdev/core/bitblit.c
>>> +++ b/drivers/video/fbdev/core/bitblit.c
>>> @@ -79,12 +79,16 @@ static inline void bit_putcs_aligned(struct vc_data *vc, struct fb_info *info,
>>>   				     struct fb_image *image, u8 *buf, u8 *dst)
>>>   {
>>>   	u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
>>> +	unsigned int charcnt = vc->vc_font.charcount;
> 
> Perhaps, vc->vc_font.charcount (which is relied upon in the following
> comparison) is not always set correctly in v5.10.247. At least two
> commits that set vc_font.charcount are missing from v5.10.247:
> 
>    a1ac250a82a5 ("fbcon: Avoid using FNTCHARCNT() and hard-coded built-in font charcount")
>    a5a923038d70 ("fbdev: fbcon: Properly revert changes when vc_resize() failed")
> 
> Thanks,

I was just about to report this.

I found two ways to fix this bug. One is to revert this patch; the other 
is to apply the following 3 patches, which are already present in 5.11 
and later:

7a089ec7d77fe7d50f6bb7b178fa25eec9fd822b
     console: Delete unused con_font_copy() callback implementations

4ee573086bd88ff3060dda07873bf755d332e9ba
     Fonts: Add charcount field to font_desc

a1ac250a82a5e97db71f14101ff7468291a6aaef
     fbcon: Avoid using FNTCHARCNT() and hard-coded built-in font
     charcount

(Oh, by the way, this same regression also affects 5.4.302, and the same 
3 patches fix the regression on 5.4 as well, once you manually fix merge 
conflicts. Maybe it would be better to backport other additional commits 
instead of fixing the merge conflicts manually, but since 5.4 is now EOL 
I didn't dig that deep.)

Once these 3 patches are applied, I wonder if a5a923038d70 now becomes 
necessary for 5.10.y. For what it's worth, it applies fine and the 
resulting kernel seems to run OK in brief testing.

-- 
-Barry K. Nathan  <barryn@pobox.com>

^ permalink raw reply

* Re: [PATCH v2] fbdev: bitblit: bound-check glyph index in bit_putcs*
From: Vitaly Chikunov @ 2025-12-26 12:21 UTC (permalink / raw)
  To: Junjie Cao, Thomas Zimmermann, Greg Kroah-Hartman
  Cc: Peilin Ye, Daniel Vetter, Shigeru Yoshida, Simona Vetter,
	Helge Deller, Zsolt Kajtar, Albin Babu Varghese, linux-fbdev,
	dri-devel, linux-kernel, stable, regressions
In-Reply-To: <aU23brU4lZqIkw4Z@altlinux.org>

Dear linux-fbdev, stable,

On Fri, Dec 26, 2025 at 01:29:13AM +0300, Vitaly Chikunov wrote:
> 
> On Mon, Oct 20, 2025 at 09:47:01PM +0800, Junjie Cao wrote:
> > bit_putcs_aligned()/unaligned() derived the glyph pointer from the
> > character value masked by 0xff/0x1ff, which may exceed the actual font's
> > glyph count and read past the end of the built-in font array.
> > Clamp the index to the actual glyph count before computing the address.
> > 
> > This fixes a global out-of-bounds read reported by syzbot.
> > 
> > Reported-by: syzbot+793cf822d213be1a74f2@syzkaller.appspotmail.com
> > Closes: https://syzkaller.appspot.com/bug?extid=793cf822d213be1a74f2
> > Tested-by: syzbot+793cf822d213be1a74f2@syzkaller.appspotmail.com
> > Signed-off-by: Junjie Cao <junjie.cao@intel.com>
> 
> This commit is applied to v5.10.247 and causes a regression: when
> switching VT with ctrl-alt-f2 the screen is blank or completely filled
> with angle characters, then new text is not appearing (or not visible).
> 
> This commit is found with git bisect from v5.10.246 to v5.10.247:
> 
>   0998a6cb232674408a03e8561dc15aa266b2f53b is the first bad commit
>   commit 0998a6cb232674408a03e8561dc15aa266b2f53b
>   Author:     Junjie Cao <junjie.cao@intel.com>
>   AuthorDate: 2025-10-20 21:47:01 +0800
>   Commit:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>   CommitDate: 2025-12-07 06:08:07 +0900
> 
>       fbdev: bitblit: bound-check glyph index in bit_putcs*
> 
>       commit 18c4ef4e765a798b47980555ed665d78b71aeadf upstream.
> 
>       bit_putcs_aligned()/unaligned() derived the glyph pointer from the
>       character value masked by 0xff/0x1ff, which may exceed the actual font's
>       glyph count and read past the end of the built-in font array.
>       Clamp the index to the actual glyph count before computing the address.
> 
>       This fixes a global out-of-bounds read reported by syzbot.
> 
>       Reported-by: syzbot+793cf822d213be1a74f2@syzkaller.appspotmail.com
>       Closes: https://syzkaller.appspot.com/bug?extid=793cf822d213be1a74f2
>       Tested-by: syzbot+793cf822d213be1a74f2@syzkaller.appspotmail.com
>       Signed-off-by: Junjie Cao <junjie.cao@intel.com>
>       Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
>       Signed-off-by: Helge Deller <deller@gmx.de>
>       Cc: stable@vger.kernel.org
>       Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> 
>    drivers/video/fbdev/core/bitblit.c | 16 ++++++++++++----
>    1 file changed, 12 insertions(+), 4 deletions(-)
> 
> The minimal reproducer in cli, after kernel is booted:
> 
>   date >/dev/tty2; chvt 2
> 
> and the date does not appear.
> 
> Thanks,
> 
> #regzbot introduced: 0998a6cb232674408a03e8561dc15aa266b2f53b
> 
> > ---
> > v1: https://lore.kernel.org/linux-fbdev/5d237d1a-a528-4205-a4d8-71709134f1e1@suse.de/
> > v1 -> v2:
> >  - Fix indentation and add blank line after declarations with the .pl helper
> >  - No functional changes
> > 
> >  drivers/video/fbdev/core/bitblit.c | 16 ++++++++++++----
> >  1 file changed, 12 insertions(+), 4 deletions(-)
> > 
> > diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c
> > index 9d2e59796c3e..085ffb44c51a 100644
> > --- a/drivers/video/fbdev/core/bitblit.c
> > +++ b/drivers/video/fbdev/core/bitblit.c
> > @@ -79,12 +79,16 @@ static inline void bit_putcs_aligned(struct vc_data *vc, struct fb_info *info,
> >  				     struct fb_image *image, u8 *buf, u8 *dst)
> >  {
> >  	u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
> > +	unsigned int charcnt = vc->vc_font.charcount;

Perhaps, vc->vc_font.charcount (which is relied upon in the following
comparison) is not always set correctly in v5.10.247. At least two
commits that set vc_font.charcount are missing from v5.10.247:

  a1ac250a82a5 ("fbcon: Avoid using FNTCHARCNT() and hard-coded built-in font charcount")
  a5a923038d70 ("fbdev: fbcon: Properly revert changes when vc_resize() failed")

Thanks,


> >  	u32 idx = vc->vc_font.width >> 3;
> >  	u8 *src;
> >  
> >  	while (cnt--) {
> > -		src = vc->vc_font.data + (scr_readw(s++)&
> > -					  charmask)*cellsize;
> > +		u16 ch = scr_readw(s++) & charmask;
> > +
> > +		if (ch >= charcnt)
> > +			ch = 0;
> > +		src = vc->vc_font.data + (unsigned int)ch * cellsize;
> >  
> >  		if (attr) {
> >  			update_attr(buf, src, attr, vc);
> > @@ -112,14 +116,18 @@ static inline void bit_putcs_unaligned(struct vc_data *vc,
> >  				       u8 *dst)
> >  {
> >  	u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
> > +	unsigned int charcnt = vc->vc_font.charcount;
> >  	u32 shift_low = 0, mod = vc->vc_font.width % 8;
> >  	u32 shift_high = 8;
> >  	u32 idx = vc->vc_font.width >> 3;
> >  	u8 *src;
> >  
> >  	while (cnt--) {
> > -		src = vc->vc_font.data + (scr_readw(s++)&
> > -					  charmask)*cellsize;
> > +		u16 ch = scr_readw(s++) & charmask;
> > +
> > +		if (ch >= charcnt)
> > +			ch = 0;
> > +		src = vc->vc_font.data + (unsigned int)ch * cellsize;
> >  
> >  		if (attr) {
> >  			update_attr(buf, src, attr, vc);
> > -- 
> > 2.48.1
> > 

^ permalink raw reply

* [PATCH] staging: sm750fb: fix const array warning
From: MottiKumar @ 2025-12-26 12:04 UTC (permalink / raw)
  To: sudipm.mukherjee, teddy.wang, gregkh
  Cc: skhan, linux-kernel-mentees, linux-fbdev, linux-staging,
	linux-kernel, mottikumarbabu

Add a missing const to g_fbmode to fix a checkpatch warning:
"static const char * array should probably be static const char * const"

Signed-off-by: MottiKumar <mottikumarbabu@gmail.com>
---
 drivers/staging/sm750fb/sm750.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/staging/sm750fb/sm750.c b/drivers/staging/sm750fb/sm750.c
index d100b9e1d3d5..7afb58561a0c 100644
--- a/drivers/staging/sm750fb/sm750.c
+++ b/drivers/staging/sm750fb/sm750.c
@@ -33,7 +33,7 @@
 static int g_hwcursor = 1;
 static int g_noaccel;
 static int g_nomtrr;
-static const char *g_fbmode[] = {NULL, NULL};
+static const char * const g_fbmode[] = {NULL, NULL};
 static const char *g_def_fbmode = "1024x768-32@60";
 static char *g_settings;
 static int g_dualview;
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH v2] fbdev: bitblit: bound-check glyph index in bit_putcs*
From: Vitaly Chikunov @ 2025-12-25 22:29 UTC (permalink / raw)
  To: Junjie Cao
  Cc: Thomas Zimmermann, Simona Vetter, Helge Deller, Zsolt Kajtar,
	Albin Babu Varghese, linux-fbdev, dri-devel, linux-kernel, stable,
	regressions
In-Reply-To: <20251020134701.84082-1-junjie.cao@intel.com>

Dear linux-fbdev, stable,

On Mon, Oct 20, 2025 at 09:47:01PM +0800, Junjie Cao wrote:
> bit_putcs_aligned()/unaligned() derived the glyph pointer from the
> character value masked by 0xff/0x1ff, which may exceed the actual font's
> glyph count and read past the end of the built-in font array.
> Clamp the index to the actual glyph count before computing the address.
> 
> This fixes a global out-of-bounds read reported by syzbot.
> 
> Reported-by: syzbot+793cf822d213be1a74f2@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=793cf822d213be1a74f2
> Tested-by: syzbot+793cf822d213be1a74f2@syzkaller.appspotmail.com
> Signed-off-by: Junjie Cao <junjie.cao@intel.com>

This commit is applied to v5.10.247 and causes a regression: when
switching VT with ctrl-alt-f2 the screen is blank or completely filled
with angle characters, then new text is not appearing (or not visible).

This commit is found with git bisect from v5.10.246 to v5.10.247:

  0998a6cb232674408a03e8561dc15aa266b2f53b is the first bad commit
  commit 0998a6cb232674408a03e8561dc15aa266b2f53b
  Author:     Junjie Cao <junjie.cao@intel.com>
  AuthorDate: 2025-10-20 21:47:01 +0800
  Commit:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  CommitDate: 2025-12-07 06:08:07 +0900

      fbdev: bitblit: bound-check glyph index in bit_putcs*

      commit 18c4ef4e765a798b47980555ed665d78b71aeadf upstream.

      bit_putcs_aligned()/unaligned() derived the glyph pointer from the
      character value masked by 0xff/0x1ff, which may exceed the actual font's
      glyph count and read past the end of the built-in font array.
      Clamp the index to the actual glyph count before computing the address.

      This fixes a global out-of-bounds read reported by syzbot.

      Reported-by: syzbot+793cf822d213be1a74f2@syzkaller.appspotmail.com
      Closes: https://syzkaller.appspot.com/bug?extid=793cf822d213be1a74f2
      Tested-by: syzbot+793cf822d213be1a74f2@syzkaller.appspotmail.com
      Signed-off-by: Junjie Cao <junjie.cao@intel.com>
      Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
      Signed-off-by: Helge Deller <deller@gmx.de>
      Cc: stable@vger.kernel.org
      Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

   drivers/video/fbdev/core/bitblit.c | 16 ++++++++++++----
   1 file changed, 12 insertions(+), 4 deletions(-)

The minimal reproducer in cli, after kernel is booted:

  date >/dev/tty2; chvt 2

and the date does not appear.

Thanks,

#regzbot introduced: 0998a6cb232674408a03e8561dc15aa266b2f53b

> ---
> v1: https://lore.kernel.org/linux-fbdev/5d237d1a-a528-4205-a4d8-71709134f1e1@suse.de/
> v1 -> v2:
>  - Fix indentation and add blank line after declarations with the .pl helper
>  - No functional changes
> 
>  drivers/video/fbdev/core/bitblit.c | 16 ++++++++++++----
>  1 file changed, 12 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c
> index 9d2e59796c3e..085ffb44c51a 100644
> --- a/drivers/video/fbdev/core/bitblit.c
> +++ b/drivers/video/fbdev/core/bitblit.c
> @@ -79,12 +79,16 @@ static inline void bit_putcs_aligned(struct vc_data *vc, struct fb_info *info,
>  				     struct fb_image *image, u8 *buf, u8 *dst)
>  {
>  	u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
> +	unsigned int charcnt = vc->vc_font.charcount;
>  	u32 idx = vc->vc_font.width >> 3;
>  	u8 *src;
>  
>  	while (cnt--) {
> -		src = vc->vc_font.data + (scr_readw(s++)&
> -					  charmask)*cellsize;
> +		u16 ch = scr_readw(s++) & charmask;
> +
> +		if (ch >= charcnt)
> +			ch = 0;
> +		src = vc->vc_font.data + (unsigned int)ch * cellsize;
>  
>  		if (attr) {
>  			update_attr(buf, src, attr, vc);
> @@ -112,14 +116,18 @@ static inline void bit_putcs_unaligned(struct vc_data *vc,
>  				       u8 *dst)
>  {
>  	u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
> +	unsigned int charcnt = vc->vc_font.charcount;
>  	u32 shift_low = 0, mod = vc->vc_font.width % 8;
>  	u32 shift_high = 8;
>  	u32 idx = vc->vc_font.width >> 3;
>  	u8 *src;
>  
>  	while (cnt--) {
> -		src = vc->vc_font.data + (scr_readw(s++)&
> -					  charmask)*cellsize;
> +		u16 ch = scr_readw(s++) & charmask;
> +
> +		if (ch >= charcnt)
> +			ch = 0;
> +		src = vc->vc_font.data + (unsigned int)ch * cellsize;
>  
>  		if (attr) {
>  			update_attr(buf, src, attr, vc);
> -- 
> 2.48.1
> 

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox