Linux Framebuffer Layer development
 help / color / mirror / Atom feed
* [PATCH v2 07/10] lib/fonts: Refactor glyph-rotation helpers
From: Thomas Zimmermann @ 2026-04-07  9:23 UTC (permalink / raw)
  To: deller, gregkh, jirislaby, geert, simona, sam
  Cc: linux-fbdev, dri-devel, linux-kernel, linux-serial,
	Thomas Zimmermann
In-Reply-To: <20260407092555.58816-1-tzimmermann@suse.de>

Change the signatures of the glyph-rotation helpers to match their
public interfaces. Drop the inline qualifier.

Rename several variables to better match their meaning. Especially
rename variables to bit_pitch (or a variant thereof) if they store
a pitch value in bits per scanline. The original code is fairly
confusing about this. Move the calculation of the bit pitch into the
new helper font_glyph_bit_pitch().

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 lib/fonts/font_rotate.c | 85 ++++++++++++++++++++++++-----------------
 1 file changed, 49 insertions(+), 36 deletions(-)

diff --git a/lib/fonts/font_rotate.c b/lib/fonts/font_rotate.c
index d79ec5eef712..09f6218e036f 100644
--- a/lib/fonts/font_rotate.c
+++ b/lib/fonts/font_rotate.c
@@ -15,6 +15,12 @@
 
 #include "font.h"
 
+/* number of bits per line */
+static unsigned int font_glyph_bit_pitch(unsigned int width)
+{
+	return round_up(width, 8);
+}
+
 static unsigned int __font_glyph_pos(unsigned int x, unsigned int y, unsigned int bit_pitch,
 				     unsigned int *bit)
 {
@@ -44,18 +50,21 @@ static void font_glyph_set_bit(unsigned char *glyph, unsigned int x, unsigned in
 	glyph[i] |= bit;
 }
 
-static inline void rotate_cw(const char *in, char *out, u32 width, u32 height)
+static void __font_glyph_rotate_90(const unsigned char *glyph,
+				   unsigned int width, unsigned int height,
+				   unsigned char *out)
 {
-	int i, j, h = height, w = width;
-	int shift = (8 - (height % 8)) & 7;
-
-	width = (width + 7) & ~7;
-	height = (height + 7) & ~7;
-
-	for (i = 0; i < h; i++) {
-		for (j = 0; j < w; j++) {
-			if (font_glyph_test_bit(in, j, i, width))
-				font_glyph_set_bit(out, height - 1 - i - shift, j, height);
+	unsigned int x, y;
+	unsigned int shift = (8 - (height % 8)) & 7;
+	unsigned int bit_pitch = font_glyph_bit_pitch(width);
+	unsigned int out_bit_pitch = font_glyph_bit_pitch(height);
+
+	for (y = 0; y < height; y++) {
+		for (x = 0; x < width; x++) {
+			if (font_glyph_test_bit(glyph, x, y, bit_pitch)) {
+				font_glyph_set_bit(out, out_bit_pitch - 1 - y - shift, x,
+						   out_bit_pitch);
+			}
 		}
 	}
 }
@@ -79,22 +88,24 @@ void font_glyph_rotate_90(const unsigned char *glyph, unsigned int width, unsign
 {
 	memset(out, 0, font_glyph_size(height, width)); /* flip width/height */
 
-	rotate_cw(glyph, out, width, height);
+	__font_glyph_rotate_90(glyph, width, height, out);
 }
 EXPORT_SYMBOL_GPL(font_glyph_rotate_90);
 
-static inline void rotate_ud(const char *in, char *out, u32 width, u32 height)
+static void __font_glyph_rotate_180(const unsigned char *glyph,
+				    unsigned int width, unsigned int height,
+				    unsigned char *out)
 {
-	int i, j;
-	int shift = (8 - (width % 8)) & 7;
-
-	width = (width + 7) & ~7;
-
-	for (i = 0; i < height; i++) {
-		for (j = 0; j < width - shift; j++) {
-			if (font_glyph_test_bit(in, j, i, width))
-				font_glyph_set_bit(out, width - (1 + j + shift),
-						   height - (1 + i), width);
+	unsigned int x, y;
+	unsigned int shift = (8 - (width % 8)) & 7;
+	unsigned int bit_pitch = font_glyph_bit_pitch(width);
+
+	for (y = 0; y < height; y++) {
+		for (x = 0; x < width; x++) {
+			if (font_glyph_test_bit(glyph, x, y, bit_pitch)) {
+				font_glyph_set_bit(out, width - (1 + x + shift), height - (1 + y),
+						   bit_pitch);
+			}
 		}
 	}
 }
@@ -115,22 +126,24 @@ void font_glyph_rotate_180(const unsigned char *glyph, unsigned int width, unsig
 {
 	memset(out, 0, font_glyph_size(width, height));
 
-	rotate_ud(glyph, out, width, height);
+	__font_glyph_rotate_180(glyph, width, height, out);
 }
 EXPORT_SYMBOL_GPL(font_glyph_rotate_180);
 
-static inline void rotate_ccw(const char *in, char *out, u32 width, u32 height)
+static void __font_glyph_rotate_270(const unsigned char *glyph,
+				    unsigned int width, unsigned int height,
+				    unsigned char *out)
 {
-	int i, j, h = height, w = width;
-	int shift = (8 - (width % 8)) & 7;
-
-	width = (width + 7) & ~7;
-	height = (height + 7) & ~7;
-
-	for (i = 0; i < h; i++) {
-		for (j = 0; j < w; j++) {
-			if (font_glyph_test_bit(in, j, i, width))
-				font_glyph_set_bit(out, i, width - 1 - j - shift, height);
+	unsigned int x, y;
+	unsigned int shift = (8 - (width % 8)) & 7;
+	unsigned int bit_pitch = font_glyph_bit_pitch(width);
+	unsigned int out_bit_pitch = font_glyph_bit_pitch(height);
+
+	for (y = 0; y < height; y++) {
+		for (x = 0; x < width; x++) {
+			if (font_glyph_test_bit(glyph, x, y, bit_pitch))
+				font_glyph_set_bit(out, y, bit_pitch - 1 - x - shift,
+						   out_bit_pitch);
 		}
 	}
 }
@@ -154,6 +167,6 @@ void font_glyph_rotate_270(const unsigned char *glyph, unsigned int width, unsig
 {
 	memset(out, 0, font_glyph_size(height, width)); /* flip width/height */
 
-	rotate_ccw(glyph, out, width, height);
+	__font_glyph_rotate_270(glyph, width, height, out);
 }
 EXPORT_SYMBOL_GPL(font_glyph_rotate_270);
-- 
2.53.0


^ permalink raw reply related

* [PATCH v2 04/10] lib/fonts: Clean up Makefile
From: Thomas Zimmermann @ 2026-04-07  9:23 UTC (permalink / raw)
  To: deller, gregkh, jirislaby, geert, simona, sam
  Cc: linux-fbdev, dri-devel, linux-kernel, linux-serial,
	Thomas Zimmermann
In-Reply-To: <20260407092555.58816-1-tzimmermann@suse.de>

Simplify the Makefile. Drop font-obj-y and sort the fonts by dictionary
order. Done in preparation for supporting optional font rotation.

v2:
- sort Makefile font entries by Family/Size in ascending order (Geert, Jiri)

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 lib/fonts/Makefile | 35 +++++++++++++++++------------------
 1 file changed, 17 insertions(+), 18 deletions(-)

diff --git a/lib/fonts/Makefile b/lib/fonts/Makefile
index 30a85a4292fa..b176af53d53e 100644
--- a/lib/fonts/Makefile
+++ b/lib/fonts/Makefile
@@ -1,23 +1,22 @@
 # SPDX-License-Identifier: GPL-2.0
 # Font handling
 
-font-objs := fonts.o
+font-y := fonts.o
 
-font-objs-$(CONFIG_FONT_SUN8x16)   += font_sun8x16.o
-font-objs-$(CONFIG_FONT_SUN12x22)  += font_sun12x22.o
-font-objs-$(CONFIG_FONT_8x8)       += font_8x8.o
-font-objs-$(CONFIG_FONT_8x16)      += font_8x16.o
-font-objs-$(CONFIG_FONT_6x11)      += font_6x11.o
-font-objs-$(CONFIG_FONT_7x14)      += font_7x14.o
-font-objs-$(CONFIG_FONT_10x18)     += font_10x18.o
-font-objs-$(CONFIG_FONT_PEARL_8x8) += font_pearl_8x8.o
-font-objs-$(CONFIG_FONT_ACORN_8x8) += font_acorn_8x8.o
-font-objs-$(CONFIG_FONT_MINI_4x6)  += font_mini_4x6.o
-font-objs-$(CONFIG_FONT_6x10)      += font_6x10.o
-font-objs-$(CONFIG_FONT_TER10x18)  += font_ter10x18.o
-font-objs-$(CONFIG_FONT_TER16x32)  += font_ter16x32.o
-font-objs-$(CONFIG_FONT_6x8)       += font_6x8.o
+# Built-in fonts; sorted by Family-Size in ascending order
+font-$(CONFIG_FONT_6x8)       += font_6x8.o
+font-$(CONFIG_FONT_6x10)      += font_6x10.o
+font-$(CONFIG_FONT_6x11)      += font_6x11.o
+font-$(CONFIG_FONT_7x14)      += font_7x14.o
+font-$(CONFIG_FONT_8x8)       += font_8x8.o
+font-$(CONFIG_FONT_8x16)      += font_8x16.o
+font-$(CONFIG_FONT_10x18)     += font_10x18.o
+font-$(CONFIG_FONT_ACORN_8x8) += font_acorn_8x8.o
+font-$(CONFIG_FONT_MINI_4x6)  += font_mini_4x6.o
+font-$(CONFIG_FONT_PEARL_8x8) += font_pearl_8x8.o
+font-$(CONFIG_FONT_SUN8x16)   += font_sun8x16.o
+font-$(CONFIG_FONT_SUN12x22)  += font_sun12x22.o
+font-$(CONFIG_FONT_TER10x18)  += font_ter10x18.o
+font-$(CONFIG_FONT_TER16x32)  += font_ter16x32.o
 
-font-objs += $(font-objs-y)
-
-obj-$(CONFIG_FONT_SUPPORT)         += font.o
+obj-$(CONFIG_FONT_SUPPORT) += font.o
-- 
2.53.0


^ permalink raw reply related

* [PATCH v2 09/10] fbcon: Fill cursor mask in helper function
From: Thomas Zimmermann @ 2026-04-07  9:23 UTC (permalink / raw)
  To: deller, gregkh, jirislaby, geert, simona, sam
  Cc: linux-fbdev, dri-devel, linux-kernel, linux-serial,
	Thomas Zimmermann
In-Reply-To: <20260407092555.58816-1-tzimmermann@suse.de>

Fbcon creates a cursor shape on the fly from the user-configured
settings. The logic to create a glyph with the cursor's bitmap mask
is duplicated in four places. In the cases that involve console
rotation, the implementation further rotates the cursor glyph for
displaying.

Consolidate all cursor-mask creation in a single helper. Update the
callers accordingly. For console rotation, use the glyph helpers to
rotate the created cursor glyph to the correct orientation.

v2:
- fix sparse truncated-bits warning

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/video/fbdev/core/bitblit.c   | 35 ++-----------------
 drivers/video/fbdev/core/fbcon.c     | 40 ++++++++++++++++++++++
 drivers/video/fbdev/core/fbcon.h     |  2 ++
 drivers/video/fbdev/core/fbcon_ccw.c | 51 ++++++----------------------
 drivers/video/fbdev/core/fbcon_cw.c  | 51 ++++++----------------------
 drivers/video/fbdev/core/fbcon_ud.c  | 50 +++++++--------------------
 6 files changed, 78 insertions(+), 151 deletions(-)

diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c
index 7478accea8ec..65681dcc5930 100644
--- a/drivers/video/fbdev/core/bitblit.c
+++ b/drivers/video/fbdev/core/bitblit.c
@@ -329,46 +329,17 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
 	    vc->vc_cursor_type != par->p->cursor_shape ||
 	    par->cursor_state.mask == NULL ||
 	    par->cursor_reset) {
-		char *mask = kmalloc_array(w, vc->vc_font.height, GFP_ATOMIC);
-		int cur_height, size, i = 0;
-		u8 msk = 0xff;
+		unsigned char *mask = kmalloc_array(vc->vc_font.height, w, GFP_ATOMIC);
 
 		if (!mask)
 			return;
+		fbcon_fill_cursor_mask(par, vc, mask);
 
 		kfree(par->cursor_state.mask);
-		par->cursor_state.mask = mask;
+		par->cursor_state.mask = (const char *)mask;
 
 		par->p->cursor_shape = vc->vc_cursor_type;
 		cursor.set |= FB_CUR_SETSHAPE;
-
-		switch (CUR_SIZE(par->p->cursor_shape)) {
-		case CUR_NONE:
-			cur_height = 0;
-			break;
-		case CUR_UNDERLINE:
-			cur_height = (vc->vc_font.height < 10) ? 1 : 2;
-			break;
-		case CUR_LOWER_THIRD:
-			cur_height = vc->vc_font.height/3;
-			break;
-		case CUR_LOWER_HALF:
-			cur_height = vc->vc_font.height >> 1;
-			break;
-		case CUR_TWO_THIRDS:
-			cur_height = (vc->vc_font.height << 1)/3;
-			break;
-		case CUR_BLOCK:
-		default:
-			cur_height = vc->vc_font.height;
-			break;
-		}
-		size = (vc->vc_font.height - cur_height) * w;
-		while (size--)
-			mask[i++] = ~msk;
-		size = cur_height * w;
-		while (size--)
-			mask[i++] = msk;
 	}
 
 	par->cursor_state.enable = enable && !use_sw;
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 8641b0b3edc4..ff4c69e971f8 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -446,6 +446,46 @@ static void fbcon_del_cursor_work(struct fb_info *info)
 	cancel_delayed_work_sync(&par->cursor_work);
 }
 
+void fbcon_fill_cursor_mask(struct fbcon_par *par, struct vc_data *vc, unsigned char *mask)
+{
+	static const unsigned int pattern = 0xffffffff;
+	unsigned int pitch = vc_font_pitch(&vc->vc_font);
+	unsigned int cur_height, size;
+
+	switch (CUR_SIZE(vc->vc_cursor_type)) {
+	case CUR_NONE:
+		cur_height = 0;
+		break;
+	case CUR_UNDERLINE:
+		if (vc->vc_font.height < 10)
+			cur_height = 1;
+		else
+			cur_height = 2;
+		break;
+	case CUR_LOWER_THIRD:
+		cur_height = vc->vc_font.height / 3;
+		break;
+	case CUR_LOWER_HALF:
+		cur_height = vc->vc_font.height / 2;
+		break;
+	case CUR_TWO_THIRDS:
+		cur_height = (vc->vc_font.height * 2) / 3;
+		break;
+	case CUR_BLOCK:
+	default:
+		cur_height = vc->vc_font.height;
+		break;
+	}
+
+	size = (vc->vc_font.height - cur_height) * pitch;
+	while (size--)
+		*mask++ = (unsigned char)~pattern;
+
+	size = cur_height * pitch;
+	while (size--)
+		*mask++ = (unsigned char)pattern;
+}
+
 #ifndef MODULE
 static int __init fb_console_setup(char *this_opt)
 {
diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h
index 1793f34a6c84..bb0727b70631 100644
--- a/drivers/video/fbdev/core/fbcon.h
+++ b/drivers/video/fbdev/core/fbcon.h
@@ -192,6 +192,8 @@ extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info);
 extern void fbcon_set_bitops_ur(struct fbcon_par *par);
 extern int  soft_cursor(struct fb_info *info, struct fb_cursor *cursor);
 
+void fbcon_fill_cursor_mask(struct fbcon_par *par, struct vc_data *vc, unsigned char *mask);
+
 #define FBCON_ATTRIBUTE_UNDERLINE 1
 #define FBCON_ATTRIBUTE_REVERSE   2
 #define FBCON_ATTRIBUTE_BOLD      4
diff --git a/drivers/video/fbdev/core/fbcon_ccw.c b/drivers/video/fbdev/core/fbcon_ccw.c
index 72453a2aaca8..723d9a33067f 100644
--- a/drivers/video/fbdev/core/fbcon_ccw.c
+++ b/drivers/video/fbdev/core/fbcon_ccw.c
@@ -296,57 +296,26 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
 	    vc->vc_cursor_type != par->p->cursor_shape ||
 	    par->cursor_state.mask == NULL ||
 	    par->cursor_reset) {
-		char *tmp, *mask = kmalloc_array(w, vc->vc_font.width,
-						 GFP_ATOMIC);
-		int cur_height, size, i = 0;
-		int width = font_glyph_pitch(vc->vc_font.width);
+		unsigned char *tmp, *mask;
 
-		if (!mask)
+		tmp = kmalloc_array(vc->vc_font.height, vc_font_pitch(&vc->vc_font), GFP_ATOMIC);
+		if (!tmp)
 			return;
+		fbcon_fill_cursor_mask(par, vc, tmp);
 
-		tmp = kmalloc_array(width, vc->vc_font.height, GFP_ATOMIC);
-
-		if (!tmp) {
-			kfree(mask);
+		mask = kmalloc_array(vc->vc_font.width, w, GFP_ATOMIC);
+		if (!mask) {
+			kfree(tmp);
 			return;
 		}
+		font_glyph_rotate_270(tmp, vc->vc_font.width, vc->vc_font.height, mask);
+		kfree(tmp);
 
 		kfree(par->cursor_state.mask);
-		par->cursor_state.mask = mask;
+		par->cursor_state.mask = (const char *)mask;
 
 		par->p->cursor_shape = vc->vc_cursor_type;
 		cursor.set |= FB_CUR_SETSHAPE;
-
-		switch (CUR_SIZE(par->p->cursor_shape)) {
-		case CUR_NONE:
-			cur_height = 0;
-			break;
-		case CUR_UNDERLINE:
-			cur_height = (vc->vc_font.height < 10) ? 1 : 2;
-			break;
-		case CUR_LOWER_THIRD:
-			cur_height = vc->vc_font.height/3;
-			break;
-		case CUR_LOWER_HALF:
-			cur_height = vc->vc_font.height >> 1;
-			break;
-		case CUR_TWO_THIRDS:
-			cur_height = (vc->vc_font.height << 1)/3;
-			break;
-		case CUR_BLOCK:
-		default:
-			cur_height = vc->vc_font.height;
-			break;
-		}
-
-		size = (vc->vc_font.height - cur_height) * width;
-		while (size--)
-			tmp[i++] = 0;
-		size = cur_height * width;
-		while (size--)
-			tmp[i++] = 0xff;
-		font_glyph_rotate_270(tmp, vc->vc_font.width, vc->vc_font.height, mask);
-		kfree(tmp);
 	}
 
 	par->cursor_state.enable = enable && !use_sw;
diff --git a/drivers/video/fbdev/core/fbcon_cw.c b/drivers/video/fbdev/core/fbcon_cw.c
index 5690fc1d7854..732d093d462f 100644
--- a/drivers/video/fbdev/core/fbcon_cw.c
+++ b/drivers/video/fbdev/core/fbcon_cw.c
@@ -279,57 +279,26 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
 	    vc->vc_cursor_type != par->p->cursor_shape ||
 	    par->cursor_state.mask == NULL ||
 	    par->cursor_reset) {
-		char *tmp, *mask = kmalloc_array(w, vc->vc_font.width,
-						 GFP_ATOMIC);
-		int cur_height, size, i = 0;
-		int width = font_glyph_pitch(vc->vc_font.width);
+		unsigned char *tmp, *mask;
 
-		if (!mask)
+		tmp = kmalloc_array(vc->vc_font.height, vc_font_pitch(&vc->vc_font), GFP_ATOMIC);
+		if (!tmp)
 			return;
+		fbcon_fill_cursor_mask(par, vc, tmp);
 
-		tmp = kmalloc_array(width, vc->vc_font.height, GFP_ATOMIC);
-
-		if (!tmp) {
-			kfree(mask);
+		mask = kmalloc_array(vc->vc_font.width, w, GFP_ATOMIC);
+		if (!mask) {
+			kfree(tmp);
 			return;
 		}
+		font_glyph_rotate_90(tmp, vc->vc_font.width, vc->vc_font.height, mask);
+		kfree(tmp);
 
 		kfree(par->cursor_state.mask);
-		par->cursor_state.mask = mask;
+		par->cursor_state.mask = (const char *)mask;
 
 		par->p->cursor_shape = vc->vc_cursor_type;
 		cursor.set |= FB_CUR_SETSHAPE;
-
-		switch (CUR_SIZE(par->p->cursor_shape)) {
-		case CUR_NONE:
-			cur_height = 0;
-			break;
-		case CUR_UNDERLINE:
-			cur_height = (vc->vc_font.height < 10) ? 1 : 2;
-			break;
-		case CUR_LOWER_THIRD:
-			cur_height = vc->vc_font.height/3;
-			break;
-		case CUR_LOWER_HALF:
-			cur_height = vc->vc_font.height >> 1;
-			break;
-		case CUR_TWO_THIRDS:
-			cur_height = (vc->vc_font.height << 1)/3;
-			break;
-		case CUR_BLOCK:
-		default:
-			cur_height = vc->vc_font.height;
-			break;
-		}
-
-		size = (vc->vc_font.height - cur_height) * width;
-		while (size--)
-			tmp[i++] = 0;
-		size = cur_height * width;
-		while (size--)
-			tmp[i++] = 0xff;
-		font_glyph_rotate_90(tmp, vc->vc_font.width, vc->vc_font.height, mask);
-		kfree(tmp);
 	}
 
 	par->cursor_state.enable = enable && !use_sw;
diff --git a/drivers/video/fbdev/core/fbcon_ud.c b/drivers/video/fbdev/core/fbcon_ud.c
index f7cd89c42b01..a1981fa4701a 100644
--- a/drivers/video/fbdev/core/fbcon_ud.c
+++ b/drivers/video/fbdev/core/fbcon_ud.c
@@ -326,50 +326,26 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
 	    vc->vc_cursor_type != par->p->cursor_shape ||
 	    par->cursor_state.mask == NULL ||
 	    par->cursor_reset) {
-		char *mask = kmalloc_array(w, vc->vc_font.height, GFP_ATOMIC);
-		int cur_height, size, i = 0;
-		u8 msk = 0xff;
+		unsigned char *tmp, *mask;
 
-		if (!mask)
+		tmp = kmalloc_array(vc->vc_font.height, w, GFP_ATOMIC);
+		if (!tmp)
 			return;
+		fbcon_fill_cursor_mask(par, vc, tmp);
+
+		mask = kmalloc_array(vc->vc_font.height, w, GFP_ATOMIC);
+		if (!mask) {
+			kfree(tmp);
+			return;
+		}
+		font_glyph_rotate_180(tmp, vc->vc_font.width, vc->vc_font.height, mask);
+		kfree(tmp);
 
 		kfree(par->cursor_state.mask);
-		par->cursor_state.mask = mask;
+		par->cursor_state.mask = (const char *)mask;
 
 		par->p->cursor_shape = vc->vc_cursor_type;
 		cursor.set |= FB_CUR_SETSHAPE;
-
-		switch (CUR_SIZE(par->p->cursor_shape)) {
-		case CUR_NONE:
-			cur_height = 0;
-			break;
-		case CUR_UNDERLINE:
-			cur_height = (vc->vc_font.height < 10) ? 1 : 2;
-			break;
-		case CUR_LOWER_THIRD:
-			cur_height = vc->vc_font.height/3;
-			break;
-		case CUR_LOWER_HALF:
-			cur_height = vc->vc_font.height >> 1;
-			break;
-		case CUR_TWO_THIRDS:
-			cur_height = (vc->vc_font.height << 1)/3;
-			break;
-		case CUR_BLOCK:
-		default:
-			cur_height = vc->vc_font.height;
-			break;
-		}
-
-		size = cur_height * w;
-
-		while (size--)
-			mask[i++] = msk;
-
-		size = (vc->vc_font.height - cur_height) * w;
-
-		while (size--)
-			mask[i++] = ~msk;
 	}
 
 	par->cursor_state.enable = enable && !use_sw;
-- 
2.53.0


^ permalink raw reply related

* [PATCH v2 08/10] lib/fonts: Implement font rotation
From: Thomas Zimmermann @ 2026-04-07  9:23 UTC (permalink / raw)
  To: deller, gregkh, jirislaby, geert, simona, sam
  Cc: linux-fbdev, dri-devel, linux-kernel, linux-serial,
	Thomas Zimmermann
In-Reply-To: <20260407092555.58816-1-tzimmermann@suse.de>

Move the core of fbcon's font-rotation code to the font library as
the new helper font_data_rotate(). The code can rotate in steps of
90°. For completeness, it also copies the glyph data for multiples
of 360°.

Bring back the memset optimization. A memset to 0 again clears the
whole glyph output buffer. Then use the internal rotation helpers on
the cleared output. Fbcon's original implementation worked like this,
but lost it during refactoring.

Replace fbcon's font-rotation code with the new implementations.
All that's left to do for fbcon is to maintain its internal fbcon
state.

v2:
- fix typos

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/video/fbdev/core/fbcon.h        |   2 +-
 drivers/video/fbdev/core/fbcon_rotate.c |  78 +++++-------------
 include/linux/font.h                    |   3 +
 lib/fonts/font_rotate.c                 | 103 ++++++++++++++++++++++++
 4 files changed, 126 insertions(+), 60 deletions(-)

diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h
index 1e3c1ef84762..1793f34a6c84 100644
--- a/drivers/video/fbdev/core/fbcon.h
+++ b/drivers/video/fbdev/core/fbcon.h
@@ -86,7 +86,7 @@ struct fbcon_par {
 	const u8    *fontdata;
 	u8    *cursor_src;
 	u32    cursor_size;
-	u32    fd_size;
+	size_t fd_size;
 
 	const struct fbcon_bitops *bitops;
 };
diff --git a/drivers/video/fbdev/core/fbcon_rotate.c b/drivers/video/fbdev/core/fbcon_rotate.c
index 588dc9d6758a..74206f5a6e98 100644
--- a/drivers/video/fbdev/core/fbcon_rotate.c
+++ b/drivers/video/fbdev/core/fbcon_rotate.c
@@ -8,84 +8,44 @@
  *  more details.
  */
 
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/string.h>
+#include <linux/errno.h>
 #include <linux/fb.h>
 #include <linux/font.h>
-#include <linux/vt_kern.h>
-#include <linux/console.h>
-#include <asm/types.h>
+
 #include "fbcon.h"
 #include "fbcon_rotate.h"
 
 int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc)
 {
 	struct fbcon_par *par = info->fbcon_par;
-	int len, err = 0;
-	int s_cellsize, d_cellsize, i;
-	const u8 *src;
-	u8 *dst;
+	unsigned char *fontbuffer;
+	int ret;
 
 	if (vc->vc_font.data == par->fontdata &&
 	    par->p->con_rotate == par->cur_rotate)
-		goto finished;
+		return 0;
 
-	src = par->fontdata = vc->vc_font.data;
+	par->fontdata = vc->vc_font.data;
 	par->cur_rotate = par->p->con_rotate;
-	len = vc->vc_font.charcount;
-	s_cellsize = font_glyph_size(vc->vc_font.width, vc->vc_font.height);
-	d_cellsize = s_cellsize;
-
-	if (par->rotate == FB_ROTATE_CW ||
-	    par->rotate == FB_ROTATE_CCW)
-		d_cellsize = font_glyph_size(vc->vc_font.height, vc->vc_font.width);
 
 	if (info->fbops->fb_sync)
 		info->fbops->fb_sync(info);
 
-	if (par->fd_size < d_cellsize * len) {
-		kfree(par->fontbuffer);
-		par->fontbuffer = NULL;
-		par->fd_size = 0;
-
-		dst = kmalloc_array(len, d_cellsize, GFP_KERNEL);
-
-		if (dst == NULL) {
-			err = -ENOMEM;
-			goto finished;
-		}
-
-		par->fd_size = d_cellsize * len;
-		par->fontbuffer = dst;
+	fontbuffer = font_data_rotate(par->p->fontdata, vc->vc_font.width,
+				      vc->vc_font.height, vc->vc_font.charcount,
+				      par->rotate, par->fontbuffer, &par->fd_size);
+	if (IS_ERR(fontbuffer)) {
+		ret = PTR_ERR(fontbuffer);
+		goto err_kfree;
 	}
 
-	dst = par->fontbuffer;
+	par->fontbuffer = fontbuffer;
 
-	switch (par->rotate) {
-	case FB_ROTATE_UD:
-		for (i = len; i--; ) {
-			font_glyph_rotate_180(src, vc->vc_font.width, vc->vc_font.height, dst);
-			src += s_cellsize;
-			dst += d_cellsize;
-		}
-		break;
-	case FB_ROTATE_CW:
-		for (i = len; i--; ) {
-			font_glyph_rotate_90(src, vc->vc_font.width, vc->vc_font.height, dst);
-			src += s_cellsize;
-			dst += d_cellsize;
-		}
-		break;
-	case FB_ROTATE_CCW:
-		for (i = len; i--; ) {
-			font_glyph_rotate_270(src, vc->vc_font.width, vc->vc_font.height, dst);
-			src += s_cellsize;
-			dst += d_cellsize;
-		}
-		break;
-	}
+	return 0;
+
+err_kfree:
+	kfree(par->fontbuffer);
+	par->fontbuffer = NULL; /* clear here to avoid output */
 
-finished:
-	return err;
+	return ret;
 }
diff --git a/include/linux/font.h b/include/linux/font.h
index 0a240dd70422..6845f02d739a 100644
--- a/include/linux/font.h
+++ b/include/linux/font.h
@@ -111,6 +111,9 @@ void font_glyph_rotate_180(const unsigned char *glyph, unsigned int width, unsig
 			   unsigned char *out);
 void font_glyph_rotate_270(const unsigned char *glyph, unsigned int width, unsigned int height,
 			   unsigned char *out);
+unsigned char *font_data_rotate(font_data_t *fd, unsigned int width, unsigned int height,
+				unsigned int charcount, unsigned int steps,
+				unsigned char *buf, size_t *bufsize);
 
 /*
  * Font description
diff --git a/lib/fonts/font_rotate.c b/lib/fonts/font_rotate.c
index 09f6218e036f..065e0fc0667b 100644
--- a/lib/fonts/font_rotate.c
+++ b/lib/fonts/font_rotate.c
@@ -9,8 +9,11 @@
  * more details.
  */
 
+#include <linux/errno.h>
 #include <linux/export.h>
 #include <linux/math.h>
+#include <linux/overflow.h>
+#include <linux/slab.h>
 #include <linux/string.h>
 
 #include "font.h"
@@ -170,3 +173,103 @@ void font_glyph_rotate_270(const unsigned char *glyph, unsigned int width, unsig
 	__font_glyph_rotate_270(glyph, width, height, out);
 }
 EXPORT_SYMBOL_GPL(font_glyph_rotate_270);
+
+/**
+ * font_data_rotate - Rotate font data by multiples of 90°
+ * @fd: The font data to rotate
+ * @width: The glyph width in bits per scanline
+ * @height: The number of scanlines in the glyph
+ * @charcount: The number of glyphs in the font
+ * @steps: Number of rotation steps of 90°
+ * @buf: Preallocated output buffer; can be NULL
+ * @bufsize: The size of @buf in bytes; can be NULL
+ *
+ * The parameters @width and @height refer to the visible number of pixels
+ * and scanlines in a single glyph. The number of glyphs is given in @charcount.
+ * Rotation happens in steps of 90°. The @steps parameter can have any value,
+ * but only 0 to 3 produce distinct results. With 4 or higher, a full rotation
+ * has been performed. You can pass any value for @steps and the helper will
+ * perform the appropriate rotation. Note that the returned buffer is not
+ * compatible with font_data_t. It only contains glyph data in the same format
+ * as returned by font_data_buf(). Callers are responsible to free the returned
+ * buffer with kfree(). Font rotation typically happens when displays get
+ * re-oriented. To avoid unnecessary re-allocation of the memory buffer, the
+ * caller can pass in an earlier result buffer in @buf for reuse. The old and
+ * new buffer sizes are given and retrieved by the caller in @bufsize. The
+ * allocation semantics are compatible with krealloc().
+ *
+ * Returns:
+ * A buffer with rotated glyphs on success, or an error pointer otherwise
+ */
+unsigned char *font_data_rotate(font_data_t *fd, unsigned int width, unsigned int height,
+				unsigned int charcount, unsigned int steps,
+				unsigned char *buf, size_t *bufsize)
+{
+	const unsigned char *src = font_data_buf(fd);
+	unsigned int s_cellsize = font_glyph_size(width, height);
+	unsigned int d_cellsize, i;
+	unsigned char *dst;
+	size_t size;
+
+	steps %= 4;
+
+	switch (steps) {
+	case 0:
+	case 2:
+		d_cellsize = s_cellsize;
+		break;
+	case 1:
+	case 3:
+		d_cellsize = font_glyph_size(height, width); /* flip width/height */
+		break;
+	}
+
+	if (check_mul_overflow(charcount, d_cellsize, &size))
+		return ERR_PTR(-EINVAL);
+
+	if (!buf || !bufsize || size > *bufsize) {
+		dst = kmalloc_array(charcount, d_cellsize, GFP_KERNEL);
+		if (!dst)
+			return ERR_PTR(-ENOMEM);
+
+		kfree(buf);
+		buf = dst;
+		if (bufsize)
+			*bufsize = size;
+	} else {
+		dst = buf;
+	}
+
+	switch (steps) {
+	case 0:
+		memcpy(dst, src, size);
+		break;
+	case 1:
+		memset(dst, 0, size);
+		for (i = 0; i < charcount; ++i) {
+			__font_glyph_rotate_90(src, width, height, dst);
+			src += s_cellsize;
+			dst += d_cellsize;
+		}
+		break;
+	case 2:
+		memset(dst, 0, size);
+		for (i = 0; i < charcount; ++i) {
+			__font_glyph_rotate_180(src, width, height, dst);
+			src += s_cellsize;
+			dst += d_cellsize;
+		}
+		break;
+	case 3:
+		memset(dst, 0, size);
+		for (i = 0; i < charcount; ++i) {
+			__font_glyph_rotate_270(src, width, height, dst);
+			src += s_cellsize;
+			dst += d_cellsize;
+		}
+		break;
+	}
+
+	return buf;
+}
+EXPORT_SYMBOL_GPL(font_data_rotate);
-- 
2.53.0


^ permalink raw reply related

* [PATCH v2 03/10] lib/fonts: Provide helpers for calculating glyph pitch and size
From: Thomas Zimmermann @ 2026-04-07  9:23 UTC (permalink / raw)
  To: deller, gregkh, jirislaby, geert, simona, sam
  Cc: linux-fbdev, dri-devel, linux-kernel, linux-serial,
	Thomas Zimmermann
In-Reply-To: <20260407092555.58816-1-tzimmermann@suse.de>

Implement pitch and size calculation for a single font glyph in the
new helpers font_glyph_pitch() and font_glyph_size(). Replace the
instances where the calculations are open-coded.

Note that in the case of fbcon console rotation, the parameters for
a glyph's width and height might be reversed. This is intentional.

v2:
- fix typos in commit message

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/tty/vt/vt.c                     |  5 ++--
 drivers/video/fbdev/core/fbcon_ccw.c    | 11 +++----
 drivers/video/fbdev/core/fbcon_cw.c     | 11 +++----
 drivers/video/fbdev/core/fbcon_rotate.c |  6 ++--
 drivers/video/fbdev/core/fbcon_ud.c     |  7 +++--
 include/linux/font.h                    | 40 +++++++++++++++++++++++++
 lib/fonts/fonts.c                       |  2 +-
 7 files changed, 61 insertions(+), 21 deletions(-)

diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 3d89d30c9596..23b9683b52a5 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -71,7 +71,6 @@
  * by Adam Tla/lka <atlka@pg.gda.pl>, Aug 2006
  */
 
-#include <linux/math.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/sched/signal.h>
@@ -244,7 +243,7 @@ enum {
  */
 unsigned int vc_font_pitch(const struct vc_font *font)
 {
-	return DIV_ROUND_UP(font->width, 8);
+	return font_glyph_pitch(font->width);
 }
 EXPORT_SYMBOL_GPL(vc_font_pitch);
 
@@ -261,7 +260,7 @@ EXPORT_SYMBOL_GPL(vc_font_pitch);
  */
 unsigned int vc_font_size(const struct vc_font *font)
 {
-	return font->height * vc_font_pitch(font) * font->charcount;
+	return font_glyph_size(font->width, font->height) * font->charcount;
 }
 EXPORT_SYMBOL_GPL(vc_font_size);
 
diff --git a/drivers/video/fbdev/core/fbcon_ccw.c b/drivers/video/fbdev/core/fbcon_ccw.c
index 2f394b5a17f7..96ef449ee6ac 100644
--- a/drivers/video/fbdev/core/fbcon_ccw.c
+++ b/drivers/video/fbdev/core/fbcon_ccw.c
@@ -26,7 +26,7 @@ static void ccw_update_attr(u8 *dst, u8 *src, int attribute,
 				  struct vc_data *vc)
 {
 	int i, j, offset = (vc->vc_font.height < 10) ? 1 : 2;
-	int width = (vc->vc_font.height + 7) >> 3;
+	int width = font_glyph_pitch(vc->vc_font.height);
 	int mod = vc->vc_font.height % 8;
 	u8 c, msk = ~(0xff << offset), msk1 = 0;
 
@@ -101,7 +101,7 @@ static inline void ccw_putcs_aligned(struct vc_data *vc, struct fb_info *info,
 {
 	struct fbcon_par *par = info->fbcon_par;
 	u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
-	u32 idx = (vc->vc_font.height + 7) >> 3;
+	u32 idx = font_glyph_pitch(vc->vc_font.height);
 	u8 *src;
 
 	while (cnt--) {
@@ -131,7 +131,7 @@ static void ccw_putcs(struct vc_data *vc, struct fb_info *info,
 {
 	struct fb_image image;
 	struct fbcon_par *par = info->fbcon_par;
-	u32 width = (vc->vc_font.height + 7)/8;
+	u32 width = font_glyph_pitch(vc->vc_font.height);
 	u32 cellsize = width * vc->vc_font.width;
 	u32 maxcnt = info->pixmap.size/cellsize;
 	u32 scan_align = info->pixmap.scan_align - 1;
@@ -223,7 +223,8 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
 	struct fb_cursor cursor;
 	struct fbcon_par *par = info->fbcon_par;
 	unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
-	int w = (vc->vc_font.height + 7) >> 3, c;
+	int w = font_glyph_pitch(vc->vc_font.height);
+	int c;
 	int y = real_y(par->p, vc->state.y);
 	int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
 	int err = 1, dx, dy;
@@ -297,7 +298,7 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
 		char *tmp, *mask = kmalloc_array(w, vc->vc_font.width,
 						 GFP_ATOMIC);
 		int cur_height, size, i = 0;
-		int width = (vc->vc_font.width + 7)/8;
+		int width = font_glyph_pitch(vc->vc_font.width);
 
 		if (!mask)
 			return;
diff --git a/drivers/video/fbdev/core/fbcon_cw.c b/drivers/video/fbdev/core/fbcon_cw.c
index 3c3ad3471ec4..ea712654edae 100644
--- a/drivers/video/fbdev/core/fbcon_cw.c
+++ b/drivers/video/fbdev/core/fbcon_cw.c
@@ -26,7 +26,7 @@ static void cw_update_attr(u8 *dst, u8 *src, int attribute,
 				  struct vc_data *vc)
 {
 	int i, j, offset = (vc->vc_font.height < 10) ? 1 : 2;
-	int width = (vc->vc_font.height + 7) >> 3;
+	int width = font_glyph_pitch(vc->vc_font.height);
 	u8 c, msk = ~(0xff >> offset);
 
 	for (i = 0; i < vc->vc_font.width; i++) {
@@ -86,7 +86,7 @@ static inline void cw_putcs_aligned(struct vc_data *vc, struct fb_info *info,
 {
 	struct fbcon_par *par = info->fbcon_par;
 	u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
-	u32 idx = (vc->vc_font.height + 7) >> 3;
+	u32 idx = font_glyph_pitch(vc->vc_font.height);
 	u8 *src;
 
 	while (cnt--) {
@@ -116,7 +116,7 @@ static void cw_putcs(struct vc_data *vc, struct fb_info *info,
 {
 	struct fb_image image;
 	struct fbcon_par *par = info->fbcon_par;
-	u32 width = (vc->vc_font.height + 7)/8;
+	u32 width = font_glyph_pitch(vc->vc_font.height);
 	u32 cellsize = width * vc->vc_font.width;
 	u32 maxcnt = info->pixmap.size/cellsize;
 	u32 scan_align = info->pixmap.scan_align - 1;
@@ -206,7 +206,8 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
 	struct fb_cursor cursor;
 	struct fbcon_par *par = info->fbcon_par;
 	unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
-	int w = (vc->vc_font.height + 7) >> 3, c;
+	int w = font_glyph_pitch(vc->vc_font.height);
+	int c;
 	int y = real_y(par->p, vc->state.y);
 	int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
 	int err = 1, dx, dy;
@@ -280,7 +281,7 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
 		char *tmp, *mask = kmalloc_array(w, vc->vc_font.width,
 						 GFP_ATOMIC);
 		int cur_height, size, i = 0;
-		int width = (vc->vc_font.width + 7)/8;
+		int width = font_glyph_pitch(vc->vc_font.width);
 
 		if (!mask)
 			return;
diff --git a/drivers/video/fbdev/core/fbcon_rotate.c b/drivers/video/fbdev/core/fbcon_rotate.c
index 5348f6c6f57c..18575c5182db 100644
--- a/drivers/video/fbdev/core/fbcon_rotate.c
+++ b/drivers/video/fbdev/core/fbcon_rotate.c
@@ -33,14 +33,12 @@ int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc)
 	src = par->fontdata = vc->vc_font.data;
 	par->cur_rotate = par->p->con_rotate;
 	len = vc->vc_font.charcount;
-	s_cellsize = ((vc->vc_font.width + 7)/8) *
-		vc->vc_font.height;
+	s_cellsize = font_glyph_size(vc->vc_font.width, vc->vc_font.height);
 	d_cellsize = s_cellsize;
 
 	if (par->rotate == FB_ROTATE_CW ||
 	    par->rotate == FB_ROTATE_CCW)
-		d_cellsize = ((vc->vc_font.height + 7)/8) *
-			vc->vc_font.width;
+		d_cellsize = font_glyph_size(vc->vc_font.height, vc->vc_font.width);
 
 	if (info->fbops->fb_sync)
 		info->fbops->fb_sync(info);
diff --git a/drivers/video/fbdev/core/fbcon_ud.c b/drivers/video/fbdev/core/fbcon_ud.c
index 6fc30cad5b19..f7cd89c42b01 100644
--- a/drivers/video/fbdev/core/fbcon_ud.c
+++ b/drivers/video/fbdev/core/fbcon_ud.c
@@ -26,7 +26,7 @@ static void ud_update_attr(u8 *dst, u8 *src, int attribute,
 				  struct vc_data *vc)
 {
 	int i, offset = (vc->vc_font.height < 10) ? 1 : 2;
-	int width = (vc->vc_font.width + 7) >> 3;
+	int width = font_glyph_pitch(vc->vc_font.width);
 	unsigned int cellsize = vc->vc_font.height * width;
 	u8 c;
 
@@ -153,7 +153,7 @@ static void ud_putcs(struct vc_data *vc, struct fb_info *info,
 {
 	struct fb_image image;
 	struct fbcon_par *par = info->fbcon_par;
-	u32 width = (vc->vc_font.width + 7)/8;
+	u32 width = font_glyph_pitch(vc->vc_font.width);
 	u32 cellsize = width * vc->vc_font.height;
 	u32 maxcnt = info->pixmap.size/cellsize;
 	u32 scan_align = info->pixmap.scan_align - 1;
@@ -253,7 +253,8 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
 	struct fb_cursor cursor;
 	struct fbcon_par *par = info->fbcon_par;
 	unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
-	int w = (vc->vc_font.width + 7) >> 3, c;
+	int w = font_glyph_pitch(vc->vc_font.width);
+	int c;
 	int y = real_y(par->p, vc->state.y);
 	int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
 	int err = 1, dx, dy;
diff --git a/include/linux/font.h b/include/linux/font.h
index 5401f07dd6ce..3bd49d914b22 100644
--- a/include/linux/font.h
+++ b/include/linux/font.h
@@ -11,10 +11,50 @@
 #ifndef _VIDEO_FONT_H
 #define _VIDEO_FONT_H
 
+#include <linux/math.h>
 #include <linux/types.h>
 
 struct console_font;
 
+/*
+ * Glyphs
+ */
+
+/**
+ * font_glyph_pitch - Calculates the number of bytes per scanline
+ * @width: The glyph width in bits per scanline
+ *
+ * A glyph's pitch is the number of bytes in a single scanline, rounded
+ * up to the next full byte. The parameter @width receives the number
+ * of visible bits per scanline. For example, if width is 14 bytes per
+ * scanline, the pitch is 2 bytes per scanline. If width is 8 bits per
+ * scanline, the pitch is 1 byte per scanline.
+ *
+ * Returns:
+ * The number of bytes in a single scanline of the glyph
+ */
+static inline unsigned int font_glyph_pitch(unsigned int width)
+{
+	return DIV_ROUND_UP(width, 8);
+}
+
+/**
+ * font_glyph_size - Calculates the number of bytes per glyph
+ * @width: The glyph width in bits per scanline
+ * @vpitch: The number of scanlines in the glyph
+ *
+ * The number of bytes in a glyph depends on the pitch and the number
+ * of scanlines. font_glyph_size automatically calculates the pitch
+ * from the given width. The parameter @vpitch gives the number of
+ * scanlines, which is usually the glyph's height in scanlines. Fonts
+ * coming from user space can sometimes have a different vertical pitch
+ * with empty scanlines between two adjacent glyphs.
+ */
+static inline unsigned int font_glyph_size(unsigned int width, unsigned int vpitch)
+{
+	return font_glyph_pitch(width) * vpitch;
+}
+
 /*
  * font_data_t and helpers
  */
diff --git a/lib/fonts/fonts.c b/lib/fonts/fonts.c
index 5938f542906b..f5d5333450a0 100644
--- a/lib/fonts/fonts.c
+++ b/lib/fonts/fonts.c
@@ -26,7 +26,7 @@
 
 #include "font.h"
 
-#define console_font_pitch(font) DIV_ROUND_UP((font)->width, 8)
+#define console_font_pitch(font) font_glyph_pitch((font)->width)
 
 /*
  * Helpers for font_data_t
-- 
2.53.0


^ permalink raw reply related

* [PATCH v2 02/10] vt: Implement helpers for struct vc_font in source file
From: Thomas Zimmermann @ 2026-04-07  9:23 UTC (permalink / raw)
  To: deller, gregkh, jirislaby, geert, simona, sam
  Cc: linux-fbdev, dri-devel, linux-kernel, linux-serial,
	Thomas Zimmermann
In-Reply-To: <20260407092555.58816-1-tzimmermann@suse.de>

Move the helpers vc_font_pitch() and vc_font_size() from the VT
header file into source file. They are not called very often, so
there's no benefit in keeping them in the headers. Also avoids
including <linux/math.h> from the header.

v2:
- fix typo in commit description

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 drivers/tty/vt/vt.c            | 35 ++++++++++++++++++++++++++++++++++
 include/linux/console_struct.h | 30 ++---------------------------
 2 files changed, 37 insertions(+), 28 deletions(-)

diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index e2df99e3d458..3d89d30c9596 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -71,6 +71,7 @@
  * by Adam Tla/lka <atlka@pg.gda.pl>, Aug 2006
  */
 
+#include <linux/math.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/sched/signal.h>
@@ -230,6 +231,40 @@ enum {
 	blank_vesa_wait,
 };
 
+/*
+ * struct vc_font
+ */
+
+/**
+ * vc_font_pitch - Calculates the number of bytes between two adjacent scanlines
+ * @font: The VC font
+ *
+ * Returns:
+ * The number of bytes between two adjacent scanlines in the font data
+ */
+unsigned int vc_font_pitch(const struct vc_font *font)
+{
+	return DIV_ROUND_UP(font->width, 8);
+}
+EXPORT_SYMBOL_GPL(vc_font_pitch);
+
+/**
+ * vc_font_size - Calculates the size of the font data in bytes
+ * @font: The VC font
+ *
+ * vc_font_size() calculates the number of bytes of font data in the
+ * font specified by @font. The function calculates the size from the
+ * font parameters.
+ *
+ * Returns:
+ * The size of the font data in bytes.
+ */
+unsigned int vc_font_size(const struct vc_font *font)
+{
+	return font->height * vc_font_pitch(font) * font->charcount;
+}
+EXPORT_SYMBOL_GPL(vc_font_size);
+
 /*
  * /sys/class/tty/tty0/
  *
diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h
index 6ce498b31855..fe915afdece5 100644
--- a/include/linux/console_struct.h
+++ b/include/linux/console_struct.h
@@ -13,7 +13,6 @@
 #ifndef _LINUX_CONSOLE_STRUCT_H
 #define _LINUX_CONSOLE_STRUCT_H
 
-#include <linux/math.h>
 #include <linux/vt.h>
 #include <linux/wait.h>
 #include <linux/workqueue.h>
@@ -83,33 +82,8 @@ struct vc_font {
 	const unsigned char *data;
 };
 
-/**
- * vc_font_pitch - Calculates the number of bytes between two adjacent scanlines
- * @font: The VC font
- *
- * Returns:
- * The number of bytes between two adjacent scanlines in the font data
- */
-static inline unsigned int vc_font_pitch(const struct vc_font *font)
-{
-	return DIV_ROUND_UP(font->width, 8);
-}
-
-/**
- * vc_font_size - Calculates the size of the font data in bytes
- * @font: The VC font
- *
- * vc_font_size() calculates the number of bytes of font data in the
- * font specified by @font. The function calculates the size from the
- * font parameters.
- *
- * Returns:
- * The size of the font data in bytes.
- */
-static inline unsigned int vc_font_size(const struct vc_font *font)
-{
-	return font->height * vc_font_pitch(font) * font->charcount;
-}
+unsigned int vc_font_pitch(const struct vc_font *font);
+unsigned int vc_font_size(const struct vc_font *font);
 
 /*
  * Example: vc_data of a console that was scrolled 3 lines down.
-- 
2.53.0


^ permalink raw reply related

* [PATCH v2 06/10] lib/fonts: Refactor glyph-pattern helpers
From: Thomas Zimmermann @ 2026-04-07  9:23 UTC (permalink / raw)
  To: deller, gregkh, jirislaby, geert, simona, sam
  Cc: linux-fbdev, dri-devel, linux-kernel, linux-serial,
	Thomas Zimmermann
In-Reply-To: <20260407092555.58816-1-tzimmermann@suse.de>

Change the signatures of the pattern helpers to align them with other
font-glyph helpers: use the font_glyph_ prefix and pass the glyph
buffer first.

Calculating the position of the involved bit is somewhat obfuscated
in the original implementation. Move it into the new helper
__font_glyph_pos() and use the result as array index and bit position.

Note that these bit helpers use a bit pitch, while other code uses a
byte pitch. This is intentional and required here.

v2:
- fix typos in commit message

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 lib/fonts/font_rotate.c | 45 ++++++++++++++++++++++++-----------------
 1 file changed, 27 insertions(+), 18 deletions(-)

diff --git a/lib/fonts/font_rotate.c b/lib/fonts/font_rotate.c
index d107a8d0a2b0..d79ec5eef712 100644
--- a/lib/fonts/font_rotate.c
+++ b/lib/fonts/font_rotate.c
@@ -15,21 +15,33 @@
 
 #include "font.h"
 
-static inline int pattern_test_bit(u32 x, u32 y, u32 pitch, const char *pat)
+static unsigned int __font_glyph_pos(unsigned int x, unsigned int y, unsigned int bit_pitch,
+				     unsigned int *bit)
 {
-	u32 tmp = (y * pitch) + x, index = tmp / 8,  bit = tmp % 8;
+	unsigned int off = y * bit_pitch + x;
+	unsigned int bit_shift = off % 8;
 
-	pat += index;
-	return (*pat) & (0x80 >> bit);
+	*bit = 0x80 >> bit_shift; /* MSB has position 0, LSB has position 7 */
+
+	return off / 8;
 }
 
-static inline void pattern_set_bit(u32 x, u32 y, u32 pitch, char *pat)
+static bool font_glyph_test_bit(const unsigned char *glyph, unsigned int x, unsigned int y,
+				unsigned int bit_pitch)
 {
-	u32 tmp = (y * pitch) + x, index = tmp / 8, bit = tmp % 8;
+	unsigned int bit;
+	unsigned int i = __font_glyph_pos(x, y, bit_pitch, &bit);
+
+	return glyph[i] & bit;
+}
 
-	pat += index;
+static void font_glyph_set_bit(unsigned char *glyph, unsigned int x, unsigned int y,
+			       unsigned int bit_pitch)
+{
+	unsigned int bit;
+	unsigned int i = __font_glyph_pos(x, y, bit_pitch, &bit);
 
-	(*pat) |= 0x80 >> bit;
+	glyph[i] |= bit;
 }
 
 static inline void rotate_cw(const char *in, char *out, u32 width, u32 height)
@@ -42,9 +54,8 @@ static inline void rotate_cw(const char *in, char *out, u32 width, u32 height)
 
 	for (i = 0; i < h; i++) {
 		for (j = 0; j < w; j++) {
-			if (pattern_test_bit(j, i, width, in))
-				pattern_set_bit(height - 1 - i - shift, j,
-						height, out);
+			if (font_glyph_test_bit(in, j, i, width))
+				font_glyph_set_bit(out, height - 1 - i - shift, j, height);
 		}
 	}
 }
@@ -81,10 +92,9 @@ static inline void rotate_ud(const char *in, char *out, u32 width, u32 height)
 
 	for (i = 0; i < height; i++) {
 		for (j = 0; j < width - shift; j++) {
-			if (pattern_test_bit(j, i, width, in))
-				pattern_set_bit(width - (1 + j + shift),
-						height - (1 + i),
-						width, out);
+			if (font_glyph_test_bit(in, j, i, width))
+				font_glyph_set_bit(out, width - (1 + j + shift),
+						   height - (1 + i), width);
 		}
 	}
 }
@@ -119,9 +129,8 @@ static inline void rotate_ccw(const char *in, char *out, u32 width, u32 height)
 
 	for (i = 0; i < h; i++) {
 		for (j = 0; j < w; j++) {
-			if (pattern_test_bit(j, i, width, in))
-				pattern_set_bit(i, width - 1 - j - shift,
-						height, out);
+			if (font_glyph_test_bit(in, j, i, width))
+				font_glyph_set_bit(out, i, width - 1 - j - shift, height);
 		}
 	}
 }
-- 
2.53.0


^ permalink raw reply related

* [PATCH v2 01/10] fbcon: Avoid OOB font access if console rotation fails
From: Thomas Zimmermann @ 2026-04-07  9:23 UTC (permalink / raw)
  To: deller, gregkh, jirislaby, geert, simona, sam
  Cc: linux-fbdev, dri-devel, linux-kernel, linux-serial,
	Thomas Zimmermann, stable
In-Reply-To: <20260407092555.58816-1-tzimmermann@suse.de>

Clear the font buffer if the reallocation during console rotation fails
in fbcon_rotate_font(). The putcs implementations for the rotated buffer
will return early in this case. See [1] for an example.

Currently, fbcon_rotate_font() keeps the old buffer, which is too small
for the rotated font. Printing to the rotated console with a high-enough
character code will overflow the font buffer.

v2:
- fix typos in commit message

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Fixes: 6cc50e1c5b57 ("[PATCH] fbcon: Console Rotation - Add support to rotate font bitmap")
Cc: <stable@vger.kernel.org> # v2.6.15+
Link: https://elixir.bootlin.com/linux/v6.19/source/drivers/video/fbdev/core/fbcon_ccw.c#L144 # [1]
---
 drivers/video/fbdev/core/fbcon_rotate.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/video/fbdev/core/fbcon_rotate.c b/drivers/video/fbdev/core/fbcon_rotate.c
index 1562a8f20b4f..5348f6c6f57c 100644
--- a/drivers/video/fbdev/core/fbcon_rotate.c
+++ b/drivers/video/fbdev/core/fbcon_rotate.c
@@ -46,6 +46,10 @@ int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc)
 		info->fbops->fb_sync(info);
 
 	if (par->fd_size < d_cellsize * len) {
+		kfree(par->fontbuffer);
+		par->fontbuffer = NULL;
+		par->fd_size = 0;
+
 		dst = kmalloc_array(len, d_cellsize, GFP_KERNEL);
 
 		if (dst == NULL) {
@@ -54,7 +58,6 @@ int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc)
 		}
 
 		par->fd_size = d_cellsize * len;
-		kfree(par->fontbuffer);
 		par->fontbuffer = dst;
 	}
 
-- 
2.53.0


^ permalink raw reply related

* [PATCH v2 05/10] lib/fonts: Implement glyph rotation
From: Thomas Zimmermann @ 2026-04-07  9:23 UTC (permalink / raw)
  To: deller, gregkh, jirislaby, geert, simona, sam
  Cc: linux-fbdev, dri-devel, linux-kernel, linux-serial,
	Thomas Zimmermann
In-Reply-To: <20260407092555.58816-1-tzimmermann@suse.de>

Move the glyph rotation helpers from fbcon to the font library. Wrap them
behind clean interfaces. Also clear the output memory to zero. Previously,
the implementation relied on the caller to do that.

Go through the fbcon code and callers of the glyph-rotation helpers. In
addition to the font rotation, there's also the cursor code, which uses
the rotation helpers.

The font-rotation relied on a single memset to zero for the whole font.
This is now multiple memsets on each glyph. This will be sorted out when
the font library also implements font rotation.

Building glyph rotation in the font library still depends on
CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y. If we get more users of the code,
we can still add a dedicated Kconfig symbol to the font library.

No changes have been made to the actual implementation of the rotate_*()
and pattern_*() functions. These will be refactored as separate changes.

v2:
- fix typos

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/video/fbdev/core/fbcon_ccw.c    |   4 +-
 drivers/video/fbdev/core/fbcon_cw.c     |   4 +-
 drivers/video/fbdev/core/fbcon_rotate.c |  12 +-
 drivers/video/fbdev/core/fbcon_rotate.h |  71 -----------
 include/linux/font.h                    |   8 ++
 lib/fonts/Makefile                      |   1 +
 lib/fonts/font_rotate.c                 | 150 ++++++++++++++++++++++++
 7 files changed, 167 insertions(+), 83 deletions(-)
 create mode 100644 lib/fonts/font_rotate.c

diff --git a/drivers/video/fbdev/core/fbcon_ccw.c b/drivers/video/fbdev/core/fbcon_ccw.c
index 96ef449ee6ac..72453a2aaca8 100644
--- a/drivers/video/fbdev/core/fbcon_ccw.c
+++ b/drivers/video/fbdev/core/fbcon_ccw.c
@@ -12,6 +12,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/fb.h>
+#include <linux/font.h>
 #include <linux/vt_kern.h>
 #include <linux/console.h>
 #include <asm/types.h>
@@ -344,8 +345,7 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
 		size = cur_height * width;
 		while (size--)
 			tmp[i++] = 0xff;
-		memset(mask, 0, w * vc->vc_font.width);
-		rotate_ccw(tmp, mask, vc->vc_font.width, vc->vc_font.height);
+		font_glyph_rotate_270(tmp, vc->vc_font.width, vc->vc_font.height, mask);
 		kfree(tmp);
 	}
 
diff --git a/drivers/video/fbdev/core/fbcon_cw.c b/drivers/video/fbdev/core/fbcon_cw.c
index ea712654edae..5690fc1d7854 100644
--- a/drivers/video/fbdev/core/fbcon_cw.c
+++ b/drivers/video/fbdev/core/fbcon_cw.c
@@ -12,6 +12,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/fb.h>
+#include <linux/font.h>
 #include <linux/vt_kern.h>
 #include <linux/console.h>
 #include <asm/types.h>
@@ -327,8 +328,7 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
 		size = cur_height * width;
 		while (size--)
 			tmp[i++] = 0xff;
-		memset(mask, 0, w * vc->vc_font.width);
-		rotate_cw(tmp, mask, vc->vc_font.width, vc->vc_font.height);
+		font_glyph_rotate_90(tmp, vc->vc_font.width, vc->vc_font.height, mask);
 		kfree(tmp);
 	}
 
diff --git a/drivers/video/fbdev/core/fbcon_rotate.c b/drivers/video/fbdev/core/fbcon_rotate.c
index 18575c5182db..588dc9d6758a 100644
--- a/drivers/video/fbdev/core/fbcon_rotate.c
+++ b/drivers/video/fbdev/core/fbcon_rotate.c
@@ -12,6 +12,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/fb.h>
+#include <linux/font.h>
 #include <linux/vt_kern.h>
 #include <linux/console.h>
 #include <asm/types.h>
@@ -60,30 +61,25 @@ int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc)
 	}
 
 	dst = par->fontbuffer;
-	memset(dst, 0, par->fd_size);
 
 	switch (par->rotate) {
 	case FB_ROTATE_UD:
 		for (i = len; i--; ) {
-			rotate_ud(src, dst, vc->vc_font.width,
-				  vc->vc_font.height);
-
+			font_glyph_rotate_180(src, vc->vc_font.width, vc->vc_font.height, dst);
 			src += s_cellsize;
 			dst += d_cellsize;
 		}
 		break;
 	case FB_ROTATE_CW:
 		for (i = len; i--; ) {
-			rotate_cw(src, dst, vc->vc_font.width,
-				  vc->vc_font.height);
+			font_glyph_rotate_90(src, vc->vc_font.width, vc->vc_font.height, dst);
 			src += s_cellsize;
 			dst += d_cellsize;
 		}
 		break;
 	case FB_ROTATE_CCW:
 		for (i = len; i--; ) {
-			rotate_ccw(src, dst, vc->vc_font.width,
-				   vc->vc_font.height);
+			font_glyph_rotate_270(src, vc->vc_font.width, vc->vc_font.height, dst);
 			src += s_cellsize;
 			dst += d_cellsize;
 		}
diff --git a/drivers/video/fbdev/core/fbcon_rotate.h b/drivers/video/fbdev/core/fbcon_rotate.h
index 8cb019e8a9c0..725bcae2df61 100644
--- a/drivers/video/fbdev/core/fbcon_rotate.h
+++ b/drivers/video/fbdev/core/fbcon_rotate.h
@@ -19,77 +19,6 @@
         (fb_scrollmode(s) == SCROLL_REDRAW || fb_scrollmode(s) == SCROLL_MOVE || !(i)->fix.xpanstep) ? \
         (i)->var.xres : (i)->var.xres_virtual; })
 
-
-static inline int pattern_test_bit(u32 x, u32 y, u32 pitch, const char *pat)
-{
-	u32 tmp = (y * pitch) + x, index = tmp / 8,  bit = tmp % 8;
-
-	pat +=index;
-	return (*pat) & (0x80 >> bit);
-}
-
-static inline void pattern_set_bit(u32 x, u32 y, u32 pitch, char *pat)
-{
-	u32 tmp = (y * pitch) + x, index = tmp / 8, bit = tmp % 8;
-
-	pat += index;
-
-	(*pat) |= 0x80 >> bit;
-}
-
-static inline void rotate_ud(const char *in, char *out, u32 width, u32 height)
-{
-	int i, j;
-	int shift = (8 - (width % 8)) & 7;
-
-	width = (width + 7) & ~7;
-
-	for (i = 0; i < height; i++) {
-		for (j = 0; j < width - shift; j++) {
-			if (pattern_test_bit(j, i, width, in))
-				pattern_set_bit(width - (1 + j + shift),
-						height - (1 + i),
-						width, out);
-		}
-
-	}
-}
-
-static inline void rotate_cw(const char *in, char *out, u32 width, u32 height)
-{
-	int i, j, h = height, w = width;
-	int shift = (8 - (height % 8)) & 7;
-
-	width = (width + 7) & ~7;
-	height = (height + 7) & ~7;
-
-	for (i = 0; i < h; i++) {
-		for (j = 0; j < w; j++) {
-			if (pattern_test_bit(j, i, width, in))
-				pattern_set_bit(height - 1 - i - shift, j,
-						height, out);
-
-		}
-	}
-}
-
-static inline void rotate_ccw(const char *in, char *out, u32 width, u32 height)
-{
-	int i, j, h = height, w = width;
-	int shift = (8 - (width % 8)) & 7;
-
-	width = (width + 7) & ~7;
-	height = (height + 7) & ~7;
-
-	for (i = 0; i < h; i++) {
-		for (j = 0; j < w; j++) {
-			if (pattern_test_bit(j, i, width, in))
-				pattern_set_bit(i, width - 1 - j - shift,
-						height, out);
-		}
-	}
-}
-
 int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc);
 
 #if defined(CONFIG_FRAMEBUFFER_CONSOLE_ROTATION)
diff --git a/include/linux/font.h b/include/linux/font.h
index 3bd49d914b22..0a240dd70422 100644
--- a/include/linux/font.h
+++ b/include/linux/font.h
@@ -104,6 +104,14 @@ unsigned int font_data_size(font_data_t *fd);
 bool font_data_is_equal(font_data_t *lhs, font_data_t *rhs);
 int font_data_export(font_data_t *fd, struct console_font *font, unsigned int vpitch);
 
+/* font_rotate.c */
+void font_glyph_rotate_90(const unsigned char *glyph, unsigned int width, unsigned int height,
+			  unsigned char *out);
+void font_glyph_rotate_180(const unsigned char *glyph, unsigned int width, unsigned int height,
+			   unsigned char *out);
+void font_glyph_rotate_270(const unsigned char *glyph, unsigned int width, unsigned int height,
+			   unsigned char *out);
+
 /*
  * Font description
  */
diff --git a/lib/fonts/Makefile b/lib/fonts/Makefile
index b176af53d53e..7202a70a56ef 100644
--- a/lib/fonts/Makefile
+++ b/lib/fonts/Makefile
@@ -2,6 +2,7 @@
 # Font handling
 
 font-y := fonts.o
+font-$(CONFIG_FRAMEBUFFER_CONSOLE_ROTATION) += font_rotate.o
 
 # Built-in fonts; sorted by Family-Size in ascending order
 font-$(CONFIG_FONT_6x8)       += font_6x8.o
diff --git a/lib/fonts/font_rotate.c b/lib/fonts/font_rotate.c
new file mode 100644
index 000000000000..d107a8d0a2b0
--- /dev/null
+++ b/lib/fonts/font_rotate.c
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Font rotation
+ *
+ *    Copyright (C) 2005 Antonino Daplas <adaplas @pol.net>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <linux/export.h>
+#include <linux/math.h>
+#include <linux/string.h>
+
+#include "font.h"
+
+static inline int pattern_test_bit(u32 x, u32 y, u32 pitch, const char *pat)
+{
+	u32 tmp = (y * pitch) + x, index = tmp / 8,  bit = tmp % 8;
+
+	pat += index;
+	return (*pat) & (0x80 >> bit);
+}
+
+static inline void pattern_set_bit(u32 x, u32 y, u32 pitch, char *pat)
+{
+	u32 tmp = (y * pitch) + x, index = tmp / 8, bit = tmp % 8;
+
+	pat += index;
+
+	(*pat) |= 0x80 >> bit;
+}
+
+static inline void rotate_cw(const char *in, char *out, u32 width, u32 height)
+{
+	int i, j, h = height, w = width;
+	int shift = (8 - (height % 8)) & 7;
+
+	width = (width + 7) & ~7;
+	height = (height + 7) & ~7;
+
+	for (i = 0; i < h; i++) {
+		for (j = 0; j < w; j++) {
+			if (pattern_test_bit(j, i, width, in))
+				pattern_set_bit(height - 1 - i - shift, j,
+						height, out);
+		}
+	}
+}
+
+/**
+ * font_glyph_rotate_90 - Rotate a glyph pattern by 90° in clockwise direction
+ * @glyph: The glyph to rotate
+ * @width: The glyph width in bits per scanline
+ * @height: The number of scanlines in the glyph
+ * @out: The rotated glyph bitmap
+ *
+ * The parameters @width and @height refer to the input glyph given in @glyph.
+ * The caller has to provide the output buffer @out of sufficient size to hold
+ * the rotated glyph. Rotating by 90° flips the width and height for the output
+ * glyph. Depending on the glyph pitch, the size of the output glyph can be
+ * different than the size of the input. Callers have to take this into account
+ * when allocating the output memory.
+ */
+void font_glyph_rotate_90(const unsigned char *glyph, unsigned int width, unsigned int height,
+			  unsigned char *out)
+{
+	memset(out, 0, font_glyph_size(height, width)); /* flip width/height */
+
+	rotate_cw(glyph, out, width, height);
+}
+EXPORT_SYMBOL_GPL(font_glyph_rotate_90);
+
+static inline void rotate_ud(const char *in, char *out, u32 width, u32 height)
+{
+	int i, j;
+	int shift = (8 - (width % 8)) & 7;
+
+	width = (width + 7) & ~7;
+
+	for (i = 0; i < height; i++) {
+		for (j = 0; j < width - shift; j++) {
+			if (pattern_test_bit(j, i, width, in))
+				pattern_set_bit(width - (1 + j + shift),
+						height - (1 + i),
+						width, out);
+		}
+	}
+}
+
+/**
+ * font_glyph_rotate_180 - Rotate a glyph pattern by 180°
+ * @glyph: The glyph to rotate
+ * @width: The glyph width in bits per scanline
+ * @height: The number of scanlines in the glyph
+ * @out: The rotated glyph bitmap
+ *
+ * The parameters @width and @height refer to the input glyph given in @glyph.
+ * The caller has to provide the output buffer @out of sufficient size to hold
+ * the rotated glyph.
+ */
+void font_glyph_rotate_180(const unsigned char *glyph, unsigned int width, unsigned int height,
+			   unsigned char *out)
+{
+	memset(out, 0, font_glyph_size(width, height));
+
+	rotate_ud(glyph, out, width, height);
+}
+EXPORT_SYMBOL_GPL(font_glyph_rotate_180);
+
+static inline void rotate_ccw(const char *in, char *out, u32 width, u32 height)
+{
+	int i, j, h = height, w = width;
+	int shift = (8 - (width % 8)) & 7;
+
+	width = (width + 7) & ~7;
+	height = (height + 7) & ~7;
+
+	for (i = 0; i < h; i++) {
+		for (j = 0; j < w; j++) {
+			if (pattern_test_bit(j, i, width, in))
+				pattern_set_bit(i, width - 1 - j - shift,
+						height, out);
+		}
+	}
+}
+
+/**
+ * font_glyph_rotate_270 - Rotate a glyph pattern by 270° in clockwise direction
+ * @glyph: The glyph to rotate
+ * @width: The glyph width in bits per scanline
+ * @height: The number of scanlines in the glyph
+ * @out: The rotated glyph bitmap
+ *
+ * The parameters @width and @height refer to the input glyph given in @glyph.
+ * The caller has to provide the output buffer @out of sufficient size to hold
+ * the rotated glyph. Rotating by 270° flips the width and height for the output
+ * glyph. Depending on the glyph pitch, the size of the output glyph can be
+ * different than the size of the input. Callers have to take this into account
+ * when allocating the output memory.
+ */
+void font_glyph_rotate_270(const unsigned char *glyph, unsigned int width, unsigned int height,
+			   unsigned char *out)
+{
+	memset(out, 0, font_glyph_size(height, width)); /* flip width/height */
+
+	rotate_ccw(glyph, out, width, height);
+}
+EXPORT_SYMBOL_GPL(font_glyph_rotate_270);
-- 
2.53.0


^ permalink raw reply related

* [PATCH v2 00/10] fbcon,fonts: Refactor framebuffer console rotation
From: Thomas Zimmermann @ 2026-04-07  9:23 UTC (permalink / raw)
  To: deller, gregkh, jirislaby, geert, simona, sam
  Cc: linux-fbdev, dri-devel, linux-kernel, linux-serial,
	Thomas Zimmermann

Refactor the framebuffer console rotation into individual components
for glyphs, fonts and the overall fbcon state. Right now this is mixed
up in fbcon_rotate.{c,h}. Also build cursor rotation on top of the new
interfaces.

Start with an OOB fix in patch 1. If buffer allocation fails, fbcon
currently uses a too-small glyph buffer for output. Avoid that.

Patches 2 to 4 make a number of small improvements to the font library
and its callers.

Patches 5 to 8 refactor the font rotation. Fbcon rotation rotates each
individual glyph in a font buffer and uses the rotated buffer's glyphs
for output. The result looks like the console buffer has been rotated
as a whole. Split this into helpers that rotate individual glyphs and
a helper that rotates the font buffer of these. Then reimplement fbcon
rotation on top. Document the public font helpers.

Patch 9 rebuilds cursor rotation on top of the new glyph helpers. The
fbcon cursor is itself a glyph that has to be rotated in sync with the
font.

Patch 10 moves all state of fbcon rotation into a single place and makes
it a build-time conditional.

Tested with fbcon under bochs on Qemu.

Built upon the fbcon changes at [1].

v2:
- fix sparse truncated-bits warning
- improve font sorting in Makefile
- fix typos

[1] https://lore.kernel.org/linux-fbdev/20260309141723.137364-1-tzimmermann@suse.de/

Thomas Zimmermann (10):
  fbcon: Avoid OOB font access if console rotation fails
  vt: Implement helpers for struct vc_font in source file
  lib/fonts: Provide helpers for calculating glyph pitch and size
  lib/fonts: Clean up Makefile
  lib/fonts: Implement glyph rotation
  lib/fonts: Refactor glyph-pattern helpers
  lib/fonts: Refactor glyph-rotation helpers
  lib/fonts: Implement font rotation
  fbcon: Fill cursor mask in helper function
  fbcon: Put font-rotation state into separate struct

 drivers/tty/vt/vt.c                     |  34 +++
 drivers/video/fbdev/core/bitblit.c      |  35 +--
 drivers/video/fbdev/core/fbcon.c        |  48 ++++-
 drivers/video/fbdev/core/fbcon.h        |  14 +-
 drivers/video/fbdev/core/fbcon_ccw.c    |  70 ++----
 drivers/video/fbdev/core/fbcon_cw.c     |  70 ++----
 drivers/video/fbdev/core/fbcon_rotate.c |  88 ++------
 drivers/video/fbdev/core/fbcon_rotate.h |  71 ------
 drivers/video/fbdev/core/fbcon_ud.c     |  67 ++----
 include/linux/console_struct.h          |  30 +--
 include/linux/font.h                    |  51 +++++
 lib/fonts/Makefile                      |  36 ++--
 lib/fonts/font_rotate.c                 | 275 ++++++++++++++++++++++++
 lib/fonts/fonts.c                       |   2 +-
 14 files changed, 525 insertions(+), 366 deletions(-)
 create mode 100644 lib/fonts/font_rotate.c

-- 
2.53.0


^ permalink raw reply

* [PATCH v3 3/3] staging: sm750fb: Rename sm750_dev members to snake_case
From: Shubham Chakraborty @ 2026-04-07  7:48 UTC (permalink / raw)
  To: gregkh
  Cc: sudipm.mukherjee, teddy.wang, linux-fbdev, linux-staging,
	linux-kernel, Shubham Chakraborty
In-Reply-To: <20260407074805.14505-1-chakrabortyshubham66@gmail.com>

Rename the sm750_dev structure members pvReg and pvMem to snake_case to
follow the kernel coding style.

Signed-off-by: Shubham Chakraborty <chakrabortyshubham66@gmail.com>
---
 drivers/staging/sm750fb/sm750.c    | 22 +++++++++++-----------
 drivers/staging/sm750fb/sm750.h    |  4 ++--
 drivers/staging/sm750fb/sm750_hw.c | 20 ++++++++++----------
 3 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/drivers/staging/sm750fb/sm750.c b/drivers/staging/sm750fb/sm750.c
index c30ffab8a5f3..1c60ba056719 100644
--- a/drivers/staging/sm750fb/sm750.c
+++ b/drivers/staging/sm750fb/sm750.c
@@ -624,27 +624,27 @@ static int sm750fb_set_drv(struct lynxfb_par *par)
 		output->paths = sm750_pnc;
 		crtc->channel = sm750_primary;
 		crtc->o_screen = 0;
-		crtc->v_screen = sm750_dev->pvMem;
+		crtc->v_screen = sm750_dev->pv_mem;
 		pr_info("use simul primary mode\n");
 		break;
 	case sm750_simul_sec:
 		output->paths = sm750_pnc;
 		crtc->channel = sm750_secondary;
 		crtc->o_screen = 0;
-		crtc->v_screen = sm750_dev->pvMem;
+		crtc->v_screen = sm750_dev->pv_mem;
 		break;
 	case sm750_dual_normal:
 		if (par->index == 0) {
 			output->paths = sm750_panel;
 			crtc->channel = sm750_primary;
 			crtc->o_screen = 0;
-			crtc->v_screen = sm750_dev->pvMem;
+			crtc->v_screen = sm750_dev->pv_mem;
 		} else {
 			output->paths = sm750_crt;
 			crtc->channel = sm750_secondary;
 			/* not consider of padding stuffs for o_screen,need fix */
 			crtc->o_screen = sm750_dev->vidmem_size >> 1;
-			crtc->v_screen = sm750_dev->pvMem + crtc->o_screen;
+			crtc->v_screen = sm750_dev->pv_mem + crtc->o_screen;
 		}
 		break;
 	case sm750_dual_swap:
@@ -652,7 +652,7 @@ static int sm750fb_set_drv(struct lynxfb_par *par)
 			output->paths = sm750_panel;
 			crtc->channel = sm750_secondary;
 			crtc->o_screen = 0;
-			crtc->v_screen = sm750_dev->pvMem;
+			crtc->v_screen = sm750_dev->pv_mem;
 		} else {
 			output->paths = sm750_crt;
 			crtc->channel = sm750_primary;
@@ -660,7 +660,7 @@ static int sm750fb_set_drv(struct lynxfb_par *par)
 			 * need fix
 			 */
 			crtc->o_screen = sm750_dev->vidmem_size >> 1;
-			crtc->v_screen = sm750_dev->pvMem + crtc->o_screen;
+			crtc->v_screen = sm750_dev->pv_mem + crtc->o_screen;
 		}
 		break;
 	default:
@@ -764,14 +764,14 @@ static int lynxfb_set_fbinfo(struct fb_info *info, int index)
 	 * must be set after crtc member initialized
 	 */
 	crtc->cursor.offset = crtc->o_screen + crtc->vidmem_size - 1024;
-	crtc->cursor.mmio = sm750_dev->pvReg +
+	crtc->cursor.mmio = sm750_dev->pv_reg +
 		0x800f0 + (int)crtc->channel * 0x140;
 
 	pr_info("crtc->cursor.mmio = %p\n", crtc->cursor.mmio);
 	crtc->cursor.max_h = 64;
 	crtc->cursor.max_w = 64;
 	crtc->cursor.size = crtc->cursor.max_h * crtc->cursor.max_w * 2 / 8;
-	crtc->cursor.vstart = sm750_dev->pvMem + crtc->cursor.offset;
+	crtc->cursor.vstart = sm750_dev->pv_mem + crtc->cursor.offset;
 
 	memset_io(crtc->cursor.vstart, 0, crtc->cursor.size);
 	if (!g_hwcursor)
@@ -1090,7 +1090,7 @@ static int lynxfb_pci_probe(struct pci_dev *pdev,
 		sm750_dev->mtrr.vram = arch_phys_wc_add(sm750_dev->vidmem_start,
 							sm750_dev->vidmem_size);
 
-	memset_io(sm750_dev->pvMem, 0, sm750_dev->vidmem_size);
+	memset_io(sm750_dev->pv_mem, 0, sm750_dev->vidmem_size);
 
 	pci_set_drvdata(pdev, sm750_dev);
 
@@ -1121,8 +1121,8 @@ static void lynxfb_pci_remove(struct pci_dev *pdev)
 	sm750fb_framebuffer_release(sm750_dev);
 	arch_phys_wc_del(sm750_dev->mtrr.vram);
 
-	iounmap(sm750_dev->pvReg);
-	iounmap(sm750_dev->pvMem);
+	iounmap(sm750_dev->pv_reg);
+	iounmap(sm750_dev->pv_mem);
 	kfree(g_settings);
 }
 
diff --git a/drivers/staging/sm750fb/sm750.h b/drivers/staging/sm750fb/sm750.h
index b683a82af349..3f6570fc8f08 100644
--- a/drivers/staging/sm750fb/sm750.h
+++ b/drivers/staging/sm750fb/sm750.h
@@ -97,8 +97,8 @@ struct sm750_dev {
 	unsigned long vidreg_start;
 	__u32 vidmem_size;
 	__u32 vidreg_size;
-	void __iomem *pvReg;
-	unsigned char __iomem *pvMem;
+	void __iomem *pv_reg;
+	unsigned char __iomem *pv_mem;
 	/* locks*/
 	spinlock_t slock;
 
diff --git a/drivers/staging/sm750fb/sm750_hw.c b/drivers/staging/sm750fb/sm750_hw.c
index 0e594734a8b9..32b3813d0d8b 100644
--- a/drivers/staging/sm750fb/sm750_hw.c
+++ b/drivers/staging/sm750fb/sm750_hw.c
@@ -49,19 +49,19 @@ int hw_sm750_map(struct sm750_dev *sm750_dev, struct pci_dev *pdev)
 	}
 
 	/* now map mmio and vidmem */
-	sm750_dev->pvReg =
+	sm750_dev->pv_reg =
 		ioremap(sm750_dev->vidreg_start, sm750_dev->vidreg_size);
-	if (!sm750_dev->pvReg) {
+	if (!sm750_dev->pv_reg) {
 		pr_err("mmio failed\n");
 		ret = -EFAULT;
 		goto exit;
 	}
-	pr_info("mmio virtual addr = %p\n", sm750_dev->pvReg);
+	pr_info("mmio virtual addr = %p\n", sm750_dev->pv_reg);
 
-	sm750_dev->accel.dpr_base = sm750_dev->pvReg + DE_BASE_ADDR_TYPE1;
-	sm750_dev->accel.dp_port_base = sm750_dev->pvReg + DE_PORT_ADDR_TYPE1;
+	sm750_dev->accel.dpr_base = sm750_dev->pv_reg + DE_BASE_ADDR_TYPE1;
+	sm750_dev->accel.dp_port_base = sm750_dev->pv_reg + DE_PORT_ADDR_TYPE1;
 
-	mmio750 = sm750_dev->pvReg;
+	mmio750 = sm750_dev->pv_reg;
 	sm750_set_chip_type(sm750_dev->devid, sm750_dev->revid);
 
 	sm750_dev->vidmem_start = pci_resource_start(pdev, 0);
@@ -76,15 +76,15 @@ int hw_sm750_map(struct sm750_dev *sm750_dev, struct pci_dev *pdev)
 		sm750_dev->vidmem_start, sm750_dev->vidmem_size);
 
 	/* reserve the vidmem space of smi adaptor */
-	sm750_dev->pvMem =
+	sm750_dev->pv_mem =
 		ioremap_wc(sm750_dev->vidmem_start, sm750_dev->vidmem_size);
-	if (!sm750_dev->pvMem) {
-		iounmap(sm750_dev->pvReg);
+	if (!sm750_dev->pv_mem) {
+		iounmap(sm750_dev->pv_reg);
 		pr_err("Map video memory failed\n");
 		ret = -EFAULT;
 		goto exit;
 	}
-	pr_info("video memory vaddr = %p\n", sm750_dev->pvMem);
+	pr_info("video memory vaddr = %p\n", sm750_dev->pv_mem);
 exit:
 	return ret;
 }
-- 
2.53.0


^ permalink raw reply related

* [PATCH v3 2/3] staging: sm750fb: Rename init_status members to snake_case
From: Shubham Chakraborty @ 2026-04-07  7:48 UTC (permalink / raw)
  To: gregkh
  Cc: sudipm.mukherjee, teddy.wang, linux-fbdev, linux-staging,
	linux-kernel, Shubham Chakraborty
In-Reply-To: <20260407074805.14505-1-chakrabortyshubham66@gmail.com>

Rename the init_status structure members powerMode, setAllEngOff, and
resetMemory to snake_case to follow the kernel coding style.

Signed-off-by: Shubham Chakraborty <chakrabortyshubham66@gmail.com>
---
 drivers/staging/sm750fb/sm750.c | 6 +++---
 drivers/staging/sm750fb/sm750.h | 6 +++---
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/staging/sm750fb/sm750.c b/drivers/staging/sm750fb/sm750.c
index 729c34372a1e..c30ffab8a5f3 100644
--- a/drivers/staging/sm750fb/sm750.c
+++ b/drivers/staging/sm750fb/sm750.c
@@ -921,9 +921,9 @@ static void sm750fb_setup(struct sm750_dev *sm750_dev, char *src)
 	sm750_dev->init_parm.chip_clk = 0;
 	sm750_dev->init_parm.mem_clk = 0;
 	sm750_dev->init_parm.master_clk = 0;
-	sm750_dev->init_parm.powerMode = 0;
-	sm750_dev->init_parm.setAllEngOff = 0;
-	sm750_dev->init_parm.resetMemory = 1;
+	sm750_dev->init_parm.power_mode = 0;
+	sm750_dev->init_parm.set_all_eng_off = 0;
+	sm750_dev->init_parm.reset_memory = 1;
 
 	/* defaultly turn g_hwcursor on for both view */
 	g_hwcursor = 3;
diff --git a/drivers/staging/sm750fb/sm750.h b/drivers/staging/sm750fb/sm750.h
index 49a79d0a8a2e..b683a82af349 100644
--- a/drivers/staging/sm750fb/sm750.h
+++ b/drivers/staging/sm750fb/sm750.h
@@ -39,13 +39,13 @@ enum sm750_path {
 };
 
 struct init_status {
-	ushort powerMode;
+	ushort power_mode;
 	/* below three clocks are in unit of MHZ*/
 	ushort chip_clk;
 	ushort mem_clk;
 	ushort master_clk;
-	ushort setAllEngOff;
-	ushort resetMemory;
+	ushort set_all_eng_off;
+	ushort reset_memory;
 };
 
 struct lynx_accel {
-- 
2.53.0


^ permalink raw reply related

* [PATCH v3 1/3] staging: sm750fb: Rename sm750_pnltype enum values to upper case
From: Shubham Chakraborty @ 2026-04-07  7:48 UTC (permalink / raw)
  To: gregkh
  Cc: sudipm.mukherjee, teddy.wang, linux-fbdev, linux-staging,
	linux-kernel, Shubham Chakraborty
In-Reply-To: <20260407074805.14505-1-chakrabortyshubham66@gmail.com>

Rename the sm750_pnltype enum values from mixed/CamelCase style to
upper-case names to follow kernel naming conventions for constants.

Signed-off-by: Shubham Chakraborty <chakrabortyshubham66@gmail.com>
---
 drivers/staging/sm750fb/sm750.c    | 6 +++---
 drivers/staging/sm750fb/sm750.h    | 6 +++---
 drivers/staging/sm750fb/sm750_hw.c | 6 +++---
 3 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/staging/sm750fb/sm750.c b/drivers/staging/sm750fb/sm750.c
index dec1f6b88a7d..729c34372a1e 100644
--- a/drivers/staging/sm750fb/sm750.c
+++ b/drivers/staging/sm750fb/sm750.c
@@ -942,11 +942,11 @@ static void sm750fb_setup(struct sm750_dev *sm750_dev, char *src)
 		} else if (!strncmp(opt, "nocrt", strlen("nocrt"))) {
 			sm750_dev->nocrt = 1;
 		} else if (!strncmp(opt, "36bit", strlen("36bit"))) {
-			sm750_dev->pnltype = sm750_doubleTFT;
+			sm750_dev->pnltype = SM750_DOUBLE_TFT;
 		} else if (!strncmp(opt, "18bit", strlen("18bit"))) {
-			sm750_dev->pnltype = sm750_dualTFT;
+			sm750_dev->pnltype = SM750_DUAL_TFT;
 		} else if (!strncmp(opt, "24bit", strlen("24bit"))) {
-			sm750_dev->pnltype = sm750_24TFT;
+			sm750_dev->pnltype = SM750_24TFT;
 		} else if (!strncmp(opt, "nohwc0", strlen("nohwc0"))) {
 			g_hwcursor &= ~0x1;
 		} else if (!strncmp(opt, "nohwc1", strlen("nohwc1"))) {
diff --git a/drivers/staging/sm750fb/sm750.h b/drivers/staging/sm750fb/sm750.h
index 67b9bfa23f41..49a79d0a8a2e 100644
--- a/drivers/staging/sm750fb/sm750.h
+++ b/drivers/staging/sm750fb/sm750.h
@@ -13,9 +13,9 @@
 #endif
 
 enum sm750_pnltype {
-	sm750_24TFT = 0,	/* 24bit tft */
-	sm750_dualTFT = 2,	/* dual 18 bit tft */
-	sm750_doubleTFT = 1,	/* 36 bit double pixel tft */
+	SM750_24TFT = 0,	/* 24bit tft */
+	SM750_DUAL_TFT = 2,	/* dual 18 bit tft */
+	SM750_DOUBLE_TFT = 1,	/* 36 bit double pixel tft */
 };
 
 /* vga channel is not concerned  */
diff --git a/drivers/staging/sm750fb/sm750_hw.c b/drivers/staging/sm750fb/sm750_hw.c
index a29faee91c78..0e594734a8b9 100644
--- a/drivers/staging/sm750fb/sm750_hw.c
+++ b/drivers/staging/sm750fb/sm750_hw.c
@@ -134,12 +134,12 @@ int hw_sm750_inithw(struct sm750_dev *sm750_dev, struct pci_dev *pdev)
 		      ~(PANEL_DISPLAY_CTRL_DUAL_DISPLAY |
 			PANEL_DISPLAY_CTRL_DOUBLE_PIXEL);
 		switch (sm750_dev->pnltype) {
-		case sm750_24TFT:
+		case SM750_24TFT:
 			break;
-		case sm750_doubleTFT:
+		case SM750_DOUBLE_TFT:
 			val |= PANEL_DISPLAY_CTRL_DOUBLE_PIXEL;
 			break;
-		case sm750_dualTFT:
+		case SM750_DUAL_TFT:
 			val |= PANEL_DISPLAY_CTRL_DUAL_DISPLAY;
 			break;
 		}
-- 
2.53.0


^ permalink raw reply related

* [PATCH v3 0/3] staging: sm750fb: Rename CamelCase identifiers
From: Shubham Chakraborty @ 2026-04-07  7:48 UTC (permalink / raw)
  To: gregkh
  Cc: sudipm.mukherjee, teddy.wang, linux-fbdev, linux-staging,
	linux-kernel, Shubham Chakraborty

Hi,

This series renames a few remaining CamelCase-style identifiers in
drivers/staging/sm750fb to match kernel coding style.

Changes in v3:
- Fix patch 1/3 commit message to say "upper case" instead of "snake_case"


Shubham Chakraborty (3):
  staging: sm750fb: Rename sm750_pnltype enum values to upper case
  staging: sm750fb: Rename init_status members to snake_case
  staging: sm750fb: Rename sm750_dev members to snake_case

 drivers/staging/sm750fb/sm750.c    | 34 +++++++++++++++---------------
 drivers/staging/sm750fb/sm750.h    | 16 +++++++-------
 drivers/staging/sm750fb/sm750_hw.c | 26 +++++++++++------------
 3 files changed, 38 insertions(+), 38 deletions(-)

-- 
2.53.0


^ permalink raw reply

* Re: [PATCH 3/8] firmware: sysfb: Make CONFIG_SYSFB a user-selectable option
From: Thomas Zimmermann @ 2026-04-07  7:39 UTC (permalink / raw)
  To: Arnd Bergmann, Javier Martinez Canillas, Ard Biesheuvel,
	Ilias Apalodimas, Huacai Chen, WANG Xuerui, Maarten Lankhorst,
	Maxime Ripard, Dave Airlie, Simona Vetter, K. Y. Srinivasan,
	Haiyang Zhang, Wei Liu, Dexuan Cui, longli, Helge Deller
  Cc: linux-arm-kernel, loongarch, linux-efi, linux-riscv, dri-devel,
	linux-hyperv, linux-fbdev
In-Reply-To: <295a43ce-92fb-435d-a82f-d1cfa8f4f28d@app.fastmail.com>

Hi

Am 02.04.26 um 18:47 schrieb Arnd Bergmann:
> On Thu, Apr 2, 2026, at 17:27, Thomas Zimmermann wrote:
>> Am 02.04.26 um 16:59 schrieb Arnd Bergmann:
>>> On Thu, Apr 2, 2026, at 16:10, Thomas Zimmermann wrote:
>>>> Am 02.04.26 um 15:08 schrieb Arnd Bergmann:
>>>>> On Thu, Apr 2, 2026, at 11:09, Thomas Zimmermann wrote:
>>>>> I don't really like this part of the series and would prefer
>>>>> to keep CONFIG_SYSFB hidden as much as possible as an x86
>>>>> (and EFI) specific implementation detail, with the hope
>>>>> of eventually seperating out the x86 bits from the EFI ones.
>>>> You mean, you want to use the EFI-provided framebuffers without the
>>>> intermediate step of going through sysfb_primary_display?
>>>>
>>>> In that case, CONFIG_SYSFB would become an x86-internal thing, right?
>>> The part that is still needed from sysfb is the arbitration
>>> between DRM_EFI and the PCI device driver for the same hardware,
>>> so I think some part of sysfb is clearly needed, in particular
>>> the sysfb_disable() function that removes the EFI framebuffer
>>> when there is a conflicting simpledrm or hardware specific
>>> driver.
>> We do most of that in the aperture-helper module. (see
>> <linux/aperture.h>). Calling sysfb_disable() from there is a workaround
>> for some corner cases. We can have an EFI-specific function that does
>> the same.
> That sounds good, yes. The same change would need to go into
> of_platform_default_populate_init() then.

The call to sysfb_disable() is a workaround for certain cases that 
aperture helpers don't handle well. In the longer term, I'd want 
aperture helpers to be more clever about aperture ownership. But as an 
intermediate step, adding other _disable() function would be an option. 
But there's no hurry.

>
>> BTW, simpledrm-on-EFI/VESA is considered obsolete and should preferably
>> be removed from that driver. Simpledrm should become a driver for
>> Devicetree nodes of type simple-framebuffer (as it originally has been
>> intended).
> Sure, I was only thinking of the case where there are both
> sysfb (from Arm/riscv UEFI) and simpledrm (from devicetree)
> objects referring to the same one, not the simpledrm
> device created by sysfb_simplefb.
>
>>> The parts that I want to keep out of that is anything
>>> related to the x86 boot protocol, non-EFI framebuffers,
>>> text console, and kexec handoff, which we don't need on
>>> non-x86 UEFI systems.
>>>
>>> I don't mind the idea of having a sysfb_primary_display
>>> in the EFI code if that helps keep EFI sane on x86,
>>> but it would be good to make that local to
>>> drivers/firmware/efi and (eventually) detached from
>>> include/uapi/linux/screen_info.h.
>> Efidrm retrieves the framebuffer settings from the contained struct
>> screen_info. Disconnecting from screen_info would require separate
>> graphics drivers for x86 and non-x86. If we split off EFI from sysfb,
>> we'd likely need a sysfbdrm driver of some sort. Just saying.
> Yes, I saw that as well and don't have an immediate idea for how
> to best do it. I saw that you already abstracted the access to
> the screen_info members in drm_sysfb_screen_info.c, which I think
> is a step in that direction.
>
> I also noticed that efidrm is mostly a subset of vesadrm, so
> in theory they could be merged back into an x86 drm driver
> along with the drm_sysfb_screen_info helpers, and have a non-x86
> driver that constructs a drm_sysfb_device directly from the
> EFI structures.

I would not want to have a unifed driver for all-things-screen_info. The 
code that can easily be shared is already in the sysfb helpers. But I 
don't mind adding a separate driver for EFI's Graphics Output Protocol. 
Then there would be current efidrm for EFI-from-screen_info and 
efigopdrm for EFI via the GOP interfaces. If EFI ever specifies another 
graphics interface, we could add another driver. The maintenance 
overhead is small on the DRM side.

What is the future of x86's boot_param and the related screen_info on 
x86-64?  Is it obsolete?  Will boot loaders run the EFI stub instead?

>
>> I think we'd also have to duplicate the framebuffer-relocation code that
>> currently works on anything using struct screen_info (see patch 5).
> You mean the code from include/linux/screen_info.h? I think
> it would make sense to have an x86 specific version of that
> to operate on the x86 screen_info, and a simpler version
> that just updates the resource for the efirdrm driver, but
> that could also be done one level higher or lower.

Makes me wonder if the relocation code could be integrated into the 
aperture helpers. It would have to track the relocation of all PCI 
graphics devices and probing DRM drivers would query the relocation 
offset for their given framebuffer.

>
>>>>> In general, I am always in favor of properly using Kconfig
>>>>> dependencies over 'select' statements, for the same reasons
>>>>> you describe, but I don't want the the x86 logic for
>>>>> the legacy VESA and VGA console handling to leak into more
>>>>> architectures than necessary.
>>>>>
>>>>> Do you think we could instead move the sysfb_init()
>>>>> function into the same two places that contain the
>>>>> sysfb_primary_display definition (arch/x86/kernel/setup.c,
>>>>> drivers/firmware/efi/efi-init.c) and simplify the efi version
>>>>> to take out the x86 bits? That would reduce the rest
>>>>> of sysfb-primary.c to the logic to unregister the device,
>>>>> and that could then be selected by both x86 and EFI.
>>>> No, I'm more than happy that sysfb finally consolidates all the
>>>> init-framebuffer setup and detection that floated around in the kernel.
>>>> I would not want it to be duplicated again.
>>>>
>>>> For now, we could certainly keep CONFIG_SYSFB hidden and autoselected.
>>>> Although I think this will require soem sort of solution at a later point.
>>> Can you clarify which problem you are trying to solve
>>> with that?
>> One thing is that some users simply what control over their kernel build.
>>
>> I also think that there might be systems that want to use
>> sysfb_primary_display (plus the relocation feature), but not create the
>> framebuffer device. Say for efi-earlycon. It needs user-control over the
>> SYSFB option to do that.
> I'm still not following, sorry. efi-earlycon doesn't require
> CONFIG_SYSFB today, and I don't see why that would need to change,
> or why it couldn't just 'select SYSFB' if it it does change.
>
>> As a side-effect, user-configurable SYSFB gives us a nice place to put
>> SYSFB_SIMPLEFB and FIRMWARE_EDID; two options that currently float
>> around in the config somewhat arbitrarily.
> You said that SYSFB_SIMPLEFB should get phased out in the future,
> right?

Yes. Better sooner than later.

>
> I'm also missing your plan for CONFIG_FIRMWARE_EDID. I only
> see three legacy drivers using the old fb_firmware_edid()
> interface, so I assume this is not what you are interested in.
>
> For the global copy that is filled by x86 and efi, and
> consumed by vesadrm and efidrm, does that even need to
> be a configuration option rather than get always enabled?

There is code in x86's old 16-bit boot/init code that reads the EDID via 
VESA. The help text on CONFIG_FIRMWARE_EDID sounds like it needs to be 
configurable because some systems can't do the VESA calls. Hence, the 
logical step seems to be to make this consistent for all systems by 
adopting the option for all EDID retrieval.

If we can remove CONFIG_FIRMWARE_EDID and make EDID support 
unconditional, I'm all for it.

Best regards
Thomas

>
>         Arnd

-- 
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstr. 146, 90461 Nürnberg, Germany, www.suse.com
GF: Jochen Jaser, Andrew McDonald, Werner Knoblich, (HRB 36809, AG Nürnberg)



^ permalink raw reply

* Re: [PATCH v10 07/21] gpu: nova-core: mm: Add TLB flush support
From: Matthew Brost @ 2026-04-07  5:14 UTC (permalink / raw)
  To: Joel Fernandes
  Cc: linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo, Bjorn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Dave Airlie, Daniel Almeida, Koen Koning,
	dri-devel, rust-for-linux, Nikola Djukic, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
	Jonathan Corbet, Alex Deucher, Christian Koenig, Jani Nikula,
	Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui,
	Matthew Auld, Lucas De Marchi, Thomas Hellstrom, Helge Deller,
	Alex Gaynor, Boqun Feng, John Hubbard, Alistair Popple,
	Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi,
	Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner,
	Elle Rhumsaa, alexeyi, Eliot Courtney, joel, linux-doc, amd-gfx,
	intel-gfx, intel-xe, linux-fbdev
In-Reply-To: <39a476f4-ecac-4313-a59f-e00e72d2b426@nvidia.com>

On Mon, Apr 06, 2026 at 06:10:07PM -0400, Joel Fernandes wrote:
> 
> 
> On 4/6/2026 5:24 PM, Joel Fernandes wrote:
> > 
> > 
> > On 4/2/2026 1:59 AM, Matthew Brost wrote:
> >> On Tue, Mar 31, 2026 at 05:20:34PM -0400, Joel Fernandes wrote:
> >>> Add TLB (Translation Lookaside Buffer) flush support for GPU MMU.
> >>>
> >>> After modifying page table entries, the GPU's TLB must be invalidated
> >>> to ensure the new mappings take effect. The Tlb struct provides flush
> >>> functionality through BAR0 registers.
> >>>
> >>> The flush operation writes the page directory base address and triggers
> >>> an invalidation, polling for completion with a 2 second timeout matching
> >>> the Nouveau driver.
> >>>
> >>> Cc: Nikola Djukic <ndjukic@nvidia.com>
> >>> Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
> >>> ---
> >>>  drivers/gpu/nova-core/mm.rs     |  1 +
> >>>  drivers/gpu/nova-core/mm/tlb.rs | 95 +++++++++++++++++++++++++++++++++
> >>>  drivers/gpu/nova-core/regs.rs   | 42 +++++++++++++++
> >>>  3 files changed, 138 insertions(+)
> >>>  create mode 100644 drivers/gpu/nova-core/mm/tlb.rs
> >>>
> >>> diff --git a/drivers/gpu/nova-core/mm.rs b/drivers/gpu/nova-core/mm.rs
> >>> index 8f3089a5fa88..cfe9cbe11d57 100644
> >>> --- a/drivers/gpu/nova-core/mm.rs
> >>> +++ b/drivers/gpu/nova-core/mm.rs
> >>> @@ -5,6 +5,7 @@
> >>>  #![expect(dead_code)]
> >>>  
> >>>  pub(crate) mod pramin;
> >>> +pub(crate) mod tlb;
> >>>  
> >>>  use kernel::sizes::SZ_4K;
> >>>  
> >>> diff --git a/drivers/gpu/nova-core/mm/tlb.rs b/drivers/gpu/nova-core/mm/tlb.rs
> >>> new file mode 100644
> >>> index 000000000000..cd3cbcf4c739
> >>> --- /dev/null
> >>> +++ b/drivers/gpu/nova-core/mm/tlb.rs
> >>> @@ -0,0 +1,95 @@
> >>> +// SPDX-License-Identifier: GPL-2.0
> >>> +
> >>> +//! TLB (Translation Lookaside Buffer) flush support for GPU MMU.
> >>> +//!
> >>> +//! After modifying page table entries, the GPU's TLB must be flushed to
> >>> +//! ensure the new mappings take effect. This module provides TLB flush
> >>> +//! functionality for virtual memory managers.
> >>> +//!
> >>> +//! # Example
> >>> +//!
> >>> +//! ```ignore
> >>> +//! use crate::mm::tlb::Tlb;
> >>> +//!
> >>> +//! fn page_table_update(tlb: &Tlb, pdb_addr: VramAddress) -> Result<()> {
> >>> +//!     // ... modify page tables ...
> >>> +//!
> >>> +//!     // Flush TLB to make changes visible (polls for completion).
> >>> +//!     tlb.flush(pdb_addr)?;
> >>> +//!
> >>> +//!     Ok(())
> >>> +//! }
> >>> +//! ```
> >>> +
> >>> +use kernel::{
> >>> +    devres::Devres,
> >>> +    io::poll::read_poll_timeout,
> >>> +    io::Io,
> >>> +    new_mutex,
> >>> +    prelude::*,
> >>> +    sync::{
> >>> +        Arc,
> >>> +        Mutex, //
> >>> +    },
> >>> +    time::Delta, //
> >>> +};
> >>> +
> >>> +use crate::{
> >>> +    driver::Bar0,
> >>> +    mm::VramAddress,
> >>> +    regs, //
> >>> +};
> >>> +
> >>> +/// TLB manager for GPU translation buffer operations.
> >>> +#[pin_data]
> >>> +pub(crate) struct Tlb {
> >>> +    bar: Arc<Devres<Bar0>>,
> >>> +    /// TLB flush serialization lock: This lock is acquired during the
> >>> +    /// DMA fence signalling critical path. It must NEVER be held across any
> >>> +    /// reclaimable CPU memory allocations because the memory reclaim path can
> >>> +    /// call `dma_fence_wait()`, which would deadlock with this lock held.
> >>> +    #[pin]
> >>> +    lock: Mutex<()>,
> >>> +}
> >>> +
> >>> +impl Tlb {
> >>> +    /// Create a new TLB manager.
> >>> +    pub(super) fn new(bar: Arc<Devres<Bar0>>) -> impl PinInit<Self> {
> >>> +        pin_init!(Self {
> >>> +            bar,
> >>> +            lock <- new_mutex!((), "tlb_flush"),
> >>> +        })
> >>> +    }
> >>> +
> >>> +    /// Flush the GPU TLB for a specific page directory base.
> >>> +    ///
> >>> +    /// This invalidates all TLB entries associated with the given PDB address.
> >>> +    /// Must be called after modifying page table entries to ensure the GPU sees
> >>> +    /// the updated mappings.
> >>> +    pub(crate) fn flush(&self, pdb_addr: VramAddress) -> Result {
> >>
> >> This landed on my list randomly, so I took a look.
> >>
> >> Wouldn’t you want to virtualize the invalidation based on your device?
> >> For example, what if you need to register interface changes on future hardware?
> > 
> > Good point, for future hardware it indeed makes sense. I will do that.
> Actually, at least in the future as far as I can see, the register definitions
> are the same for TLB invalidation are the same, so we are good and I will not be
> making any change in this regard.
> 
> But, thanks for raising the point and forcing me to double check!
> 

Not my driver, but this looks like a classic “works now” change that may
not hold up later, which is why I replied to something that isn’t really
my business.

Again, not my area, but I’ve been through this before. Generally,
getting the abstractions right up front pays off.

Matt

> --
> Joel Fernandes
> 

^ permalink raw reply

* Re: [PATCH v10 07/21] gpu: nova-core: mm: Add TLB flush support
From: Joel Fernandes @ 2026-04-06 22:10 UTC (permalink / raw)
  To: Matthew Brost
  Cc: linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo, Bjorn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Dave Airlie, Daniel Almeida, Koen Koning,
	dri-devel, rust-for-linux, Nikola Djukic, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
	Jonathan Corbet, Alex Deucher, Christian Koenig, Jani Nikula,
	Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui,
	Matthew Auld, Lucas De Marchi, Thomas Hellstrom, Helge Deller,
	Alex Gaynor, Boqun Feng, John Hubbard, Alistair Popple,
	Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi,
	Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner,
	Elle Rhumsaa, alexeyi, Eliot Courtney, joel, linux-doc, amd-gfx,
	intel-gfx, intel-xe, linux-fbdev
In-Reply-To: <0f5605c1-32e8-4a62-b852-b1db01e42817@nvidia.com>



On 4/6/2026 5:24 PM, Joel Fernandes wrote:
> 
> 
> On 4/2/2026 1:59 AM, Matthew Brost wrote:
>> On Tue, Mar 31, 2026 at 05:20:34PM -0400, Joel Fernandes wrote:
>>> Add TLB (Translation Lookaside Buffer) flush support for GPU MMU.
>>>
>>> After modifying page table entries, the GPU's TLB must be invalidated
>>> to ensure the new mappings take effect. The Tlb struct provides flush
>>> functionality through BAR0 registers.
>>>
>>> The flush operation writes the page directory base address and triggers
>>> an invalidation, polling for completion with a 2 second timeout matching
>>> the Nouveau driver.
>>>
>>> Cc: Nikola Djukic <ndjukic@nvidia.com>
>>> Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
>>> ---
>>>  drivers/gpu/nova-core/mm.rs     |  1 +
>>>  drivers/gpu/nova-core/mm/tlb.rs | 95 +++++++++++++++++++++++++++++++++
>>>  drivers/gpu/nova-core/regs.rs   | 42 +++++++++++++++
>>>  3 files changed, 138 insertions(+)
>>>  create mode 100644 drivers/gpu/nova-core/mm/tlb.rs
>>>
>>> diff --git a/drivers/gpu/nova-core/mm.rs b/drivers/gpu/nova-core/mm.rs
>>> index 8f3089a5fa88..cfe9cbe11d57 100644
>>> --- a/drivers/gpu/nova-core/mm.rs
>>> +++ b/drivers/gpu/nova-core/mm.rs
>>> @@ -5,6 +5,7 @@
>>>  #![expect(dead_code)]
>>>  
>>>  pub(crate) mod pramin;
>>> +pub(crate) mod tlb;
>>>  
>>>  use kernel::sizes::SZ_4K;
>>>  
>>> diff --git a/drivers/gpu/nova-core/mm/tlb.rs b/drivers/gpu/nova-core/mm/tlb.rs
>>> new file mode 100644
>>> index 000000000000..cd3cbcf4c739
>>> --- /dev/null
>>> +++ b/drivers/gpu/nova-core/mm/tlb.rs
>>> @@ -0,0 +1,95 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +
>>> +//! TLB (Translation Lookaside Buffer) flush support for GPU MMU.
>>> +//!
>>> +//! After modifying page table entries, the GPU's TLB must be flushed to
>>> +//! ensure the new mappings take effect. This module provides TLB flush
>>> +//! functionality for virtual memory managers.
>>> +//!
>>> +//! # Example
>>> +//!
>>> +//! ```ignore
>>> +//! use crate::mm::tlb::Tlb;
>>> +//!
>>> +//! fn page_table_update(tlb: &Tlb, pdb_addr: VramAddress) -> Result<()> {
>>> +//!     // ... modify page tables ...
>>> +//!
>>> +//!     // Flush TLB to make changes visible (polls for completion).
>>> +//!     tlb.flush(pdb_addr)?;
>>> +//!
>>> +//!     Ok(())
>>> +//! }
>>> +//! ```
>>> +
>>> +use kernel::{
>>> +    devres::Devres,
>>> +    io::poll::read_poll_timeout,
>>> +    io::Io,
>>> +    new_mutex,
>>> +    prelude::*,
>>> +    sync::{
>>> +        Arc,
>>> +        Mutex, //
>>> +    },
>>> +    time::Delta, //
>>> +};
>>> +
>>> +use crate::{
>>> +    driver::Bar0,
>>> +    mm::VramAddress,
>>> +    regs, //
>>> +};
>>> +
>>> +/// TLB manager for GPU translation buffer operations.
>>> +#[pin_data]
>>> +pub(crate) struct Tlb {
>>> +    bar: Arc<Devres<Bar0>>,
>>> +    /// TLB flush serialization lock: This lock is acquired during the
>>> +    /// DMA fence signalling critical path. It must NEVER be held across any
>>> +    /// reclaimable CPU memory allocations because the memory reclaim path can
>>> +    /// call `dma_fence_wait()`, which would deadlock with this lock held.
>>> +    #[pin]
>>> +    lock: Mutex<()>,
>>> +}
>>> +
>>> +impl Tlb {
>>> +    /// Create a new TLB manager.
>>> +    pub(super) fn new(bar: Arc<Devres<Bar0>>) -> impl PinInit<Self> {
>>> +        pin_init!(Self {
>>> +            bar,
>>> +            lock <- new_mutex!((), "tlb_flush"),
>>> +        })
>>> +    }
>>> +
>>> +    /// Flush the GPU TLB for a specific page directory base.
>>> +    ///
>>> +    /// This invalidates all TLB entries associated with the given PDB address.
>>> +    /// Must be called after modifying page table entries to ensure the GPU sees
>>> +    /// the updated mappings.
>>> +    pub(crate) fn flush(&self, pdb_addr: VramAddress) -> Result {
>>
>> This landed on my list randomly, so I took a look.
>>
>> Wouldn’t you want to virtualize the invalidation based on your device?
>> For example, what if you need to register interface changes on future hardware?
> 
> Good point, for future hardware it indeed makes sense. I will do that.
Actually, at least in the future as far as I can see, the register definitions
are the same for TLB invalidation are the same, so we are good and I will not be
making any change in this regard.

But, thanks for raising the point and forcing me to double check!

--
Joel Fernandes


^ permalink raw reply

* Re: [PATCH v10 12/21] gpu: nova-core: mm: Add unified page table entry wrapper enums
From: Joel Fernandes @ 2026-04-06 21:55 UTC (permalink / raw)
  To: Eliot Courtney, linux-kernel
  Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Bjorn Roy Baron, Benno Lossin,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
	Dave Airlie, Daniel Almeida, Koen Koning, dri-devel,
	rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet,
	Alex Deucher, Christian Koenig, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld,
	Matthew Brost, Lucas De Marchi, Thomas Hellstrom, Helge Deller,
	Alex Gaynor, Boqun Feng, John Hubbard, Alistair Popple,
	Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi,
	Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner,
	Elle Rhumsaa, alexeyi, joel, linux-doc, amd-gfx, intel-gfx,
	intel-xe, linux-fbdev
In-Reply-To: <DHIFF98P1YQ3.1IXUT02E3TF20@nvidia.com>



On 4/2/2026 1:40 AM, Eliot Courtney wrote:
> On Wed Apr 1, 2026 at 6:20 AM JST, Joel Fernandes wrote:
>> Add unified Pte, Pde, and DualPde wrapper enums that abstract over
>> MMU v2 and v3 page table entry formats. These enums allow the page
>> table walker and VMM to work with both MMU versions.
>>
>> Each unified type:
>> - Takes MmuVersion parameter in constructors
>> - Wraps both ver2 and ver3 variants
>> - Delegates method calls to the appropriate variant
>>
>> This enables version-agnostic page table operations while keeping
>> version-specific implementation details encapsulated in the ver2
>> and ver3 modules.
>>
>> Cc: Nikola Djukic <ndjukic@nvidia.com>
>> Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
>> ---
>>  drivers/gpu/nova-core/mm/pagetable.rs | 330 ++++++++++++++++++++++++++
>>  1 file changed, 330 insertions(+)
>>
>> diff --git a/drivers/gpu/nova-core/mm/pagetable.rs b/drivers/gpu/nova-core/mm/pagetable.rs
>> index 6e01a1af5222..909df37c3ee8 100644
>> --- a/drivers/gpu/nova-core/mm/pagetable.rs
>> +++ b/drivers/gpu/nova-core/mm/pagetable.rs
>> @@ -12,6 +12,13 @@
>>  pub(crate) mod ver3;
>>  
>>  use crate::gpu::Architecture;
>> +use crate::mm::{
>> +    pramin,
>> +    Pfn,
>> +    VirtualAddress,
>> +    VramAddress, //
>> +};
>> +use kernel::prelude::*;
>>  
>>  /// Extracts the page table index at a given level from a virtual address.
>>  pub(crate) trait VaLevelIndex {
>> @@ -84,6 +91,96 @@ pub(crate) const fn as_index(&self) -> u64 {
>>      }
>>  }
>>  
>> +impl MmuVersion {
>> +    /// Get the `PDE` levels (excluding PTE level) for page table walking.
>> +    pub(crate) fn pde_levels(&self) -> &'static [PageTableLevel] {
>> +        match self {
>> +            Self::V2 => ver2::PDE_LEVELS,
>> +            Self::V3 => ver3::PDE_LEVELS,
>> +        }
>> +    }
>> +
>> +    /// Get the PTE level for this MMU version.
>> +    pub(crate) fn pte_level(&self) -> PageTableLevel {
>> +        match self {
>> +            Self::V2 => ver2::PTE_LEVEL,
>> +            Self::V3 => ver3::PTE_LEVEL,
>> +        }
>> +    }
>> +
>> +    /// Get the dual PDE level (128-bit entries) for this MMU version.
>> +    pub(crate) fn dual_pde_level(&self) -> PageTableLevel {
>> +        match self {
>> +            Self::V2 => ver2::DUAL_PDE_LEVEL,
>> +            Self::V3 => ver3::DUAL_PDE_LEVEL,
>> +        }
>> +    }
>> +
>> +    /// Get the number of PDE levels for this MMU version.
>> +    pub(crate) fn pde_level_count(&self) -> usize {
>> +        self.pde_levels().len()
>> +    }
>> +
>> +    /// Get the entry size in bytes for a given level.
>> +    pub(crate) fn entry_size(&self, level: PageTableLevel) -> usize {
>> +        if level == self.dual_pde_level() {
>> +            16 // 128-bit dual PDE
>> +        } else {
>> +            8 // 64-bit PDE/PTE
>> +        }
>> +    }
>> +
>> +    /// Get the number of entries per page table page for a given level.
>> +    pub(crate) fn entries_per_page(&self, level: PageTableLevel) -> usize {
>> +        match self {
>> +            Self::V2 => match level {
>> +                // TODO: Calculate these values from the bitfield dynamically
>> +                // instead of hardcoding them.
>> +                PageTableLevel::Pdb => 4, // PD3 root: bits [48:47] = 2 bits
>> +                PageTableLevel::L3 => 256, // PD0 dual: bits [28:21] = 8 bits
>> +                _ => 512,                 // PD2, PD1, PT: 9 bits each
>> +            },
>> +            Self::V3 => match level {
>> +                PageTableLevel::Pdb => 2,  // PDE4 root: bit [56] = 1 bit, 2 entries
>> +                PageTableLevel::L4 => 256, // PDE0 dual: bits [28:21] = 8 bits
>> +                _ => 512,                  // PDE3, PDE2, PDE1, PT: 9 bits each
>> +            },
>> +        }
>> +    }
>> +
>> +    /// Extract the page table index at `level` from `va` for this MMU version.
>> +    pub(crate) fn level_index(&self, va: VirtualAddress, level: u64) -> u64 {
>> +        match self {
>> +            Self::V2 => ver2::VirtualAddressV2::new(va).level_index(level),
>> +            Self::V3 => ver3::VirtualAddressV3::new(va).level_index(level),
>> +        }
>> +    }
>> +
>> +    /// Compute upper bound on page table pages needed for `num_virt_pages`.
>> +    ///
>> +    /// Walks from PTE level up through PDE levels, accumulating the tree.
>> +    pub(crate) fn pt_pages_upper_bound(&self, num_virt_pages: usize) -> usize {
>> +        let mut total = 0;
>> +
>> +        // PTE pages at the leaf level.
>> +        let pte_epp = self.entries_per_page(self.pte_level());
>> +        let mut pages_at_level = num_virt_pages.div_ceil(pte_epp);
>> +        total += pages_at_level;
>> +
>> +        // Walk PDE levels bottom-up (reverse of pde_levels()).
>> +        for &level in self.pde_levels().iter().rev() {
>> +            let epp = self.entries_per_page(level);
>> +
>> +            // How many pages at this level do we need to point to
>> +            // the previous pages_at_level?
>> +            pages_at_level = pages_at_level.div_ceil(epp);
>> +            total += pages_at_level;
>> +        }
>> +
>> +        total
>> +    }
>> +}
>> +
> 
> We have a lot of matches on the MMU version here (and below in Pte, Pde,
> DualPde). What about making MmuVersion into a trait (e.g. Mmu) with
> associated types for Pte, Pde, DualPde which can implement traits
> defining their common operations too?

I coded this up and it did not look pretty, there's not much LOC savings and the
code becomes harder to read because of parametrization of several functions. Also:

> Then you can parameterise Vmm/PtWalk on this type.

The match still to be done somewhere, so you end up matching on chipset to call
the correct parametrized functions versus just passing in the parameter or
chipset down, in some cases.

For now I am inclined to leave it as is. Also there's a Rust pitfall we all
learnt during the turing and other patch reviews, sometimes doing a bunch of
matches is good especially if the number of variants are expected to be fixed
(in the mm case, version 2 and version 3). Traits have some disadvantages too,
example dyn traits have to heap-allocated, parametrizing can increase code size
(due to monomorphization) etc.

thanks,

--
Joel Fernandes





^ permalink raw reply

* Re: [PATCH v10 07/21] gpu: nova-core: mm: Add TLB flush support
From: Joel Fernandes @ 2026-04-06 21:24 UTC (permalink / raw)
  To: Matthew Brost
  Cc: linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo, Bjorn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Dave Airlie, Daniel Almeida, Koen Koning,
	dri-devel, rust-for-linux, Nikola Djukic, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
	Jonathan Corbet, Alex Deucher, Christian Koenig, Jani Nikula,
	Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui,
	Matthew Auld, Lucas De Marchi, Thomas Hellstrom, Helge Deller,
	Alex Gaynor, Boqun Feng, John Hubbard, Alistair Popple,
	Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi,
	Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner,
	Elle Rhumsaa, alexeyi, Eliot Courtney, joel, linux-doc, amd-gfx,
	intel-gfx, intel-xe, linux-fbdev
In-Reply-To: <ac4FpcD29XnbbsdD@gsse-cloud1.jf.intel.com>



On 4/2/2026 1:59 AM, Matthew Brost wrote:
> On Tue, Mar 31, 2026 at 05:20:34PM -0400, Joel Fernandes wrote:
>> Add TLB (Translation Lookaside Buffer) flush support for GPU MMU.
>>
>> After modifying page table entries, the GPU's TLB must be invalidated
>> to ensure the new mappings take effect. The Tlb struct provides flush
>> functionality through BAR0 registers.
>>
>> The flush operation writes the page directory base address and triggers
>> an invalidation, polling for completion with a 2 second timeout matching
>> the Nouveau driver.
>>
>> Cc: Nikola Djukic <ndjukic@nvidia.com>
>> Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
>> ---
>>  drivers/gpu/nova-core/mm.rs     |  1 +
>>  drivers/gpu/nova-core/mm/tlb.rs | 95 +++++++++++++++++++++++++++++++++
>>  drivers/gpu/nova-core/regs.rs   | 42 +++++++++++++++
>>  3 files changed, 138 insertions(+)
>>  create mode 100644 drivers/gpu/nova-core/mm/tlb.rs
>>
>> diff --git a/drivers/gpu/nova-core/mm.rs b/drivers/gpu/nova-core/mm.rs
>> index 8f3089a5fa88..cfe9cbe11d57 100644
>> --- a/drivers/gpu/nova-core/mm.rs
>> +++ b/drivers/gpu/nova-core/mm.rs
>> @@ -5,6 +5,7 @@
>>  #![expect(dead_code)]
>>  
>>  pub(crate) mod pramin;
>> +pub(crate) mod tlb;
>>  
>>  use kernel::sizes::SZ_4K;
>>  
>> diff --git a/drivers/gpu/nova-core/mm/tlb.rs b/drivers/gpu/nova-core/mm/tlb.rs
>> new file mode 100644
>> index 000000000000..cd3cbcf4c739
>> --- /dev/null
>> +++ b/drivers/gpu/nova-core/mm/tlb.rs
>> @@ -0,0 +1,95 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +
>> +//! TLB (Translation Lookaside Buffer) flush support for GPU MMU.
>> +//!
>> +//! After modifying page table entries, the GPU's TLB must be flushed to
>> +//! ensure the new mappings take effect. This module provides TLB flush
>> +//! functionality for virtual memory managers.
>> +//!
>> +//! # Example
>> +//!
>> +//! ```ignore
>> +//! use crate::mm::tlb::Tlb;
>> +//!
>> +//! fn page_table_update(tlb: &Tlb, pdb_addr: VramAddress) -> Result<()> {
>> +//!     // ... modify page tables ...
>> +//!
>> +//!     // Flush TLB to make changes visible (polls for completion).
>> +//!     tlb.flush(pdb_addr)?;
>> +//!
>> +//!     Ok(())
>> +//! }
>> +//! ```
>> +
>> +use kernel::{
>> +    devres::Devres,
>> +    io::poll::read_poll_timeout,
>> +    io::Io,
>> +    new_mutex,
>> +    prelude::*,
>> +    sync::{
>> +        Arc,
>> +        Mutex, //
>> +    },
>> +    time::Delta, //
>> +};
>> +
>> +use crate::{
>> +    driver::Bar0,
>> +    mm::VramAddress,
>> +    regs, //
>> +};
>> +
>> +/// TLB manager for GPU translation buffer operations.
>> +#[pin_data]
>> +pub(crate) struct Tlb {
>> +    bar: Arc<Devres<Bar0>>,
>> +    /// TLB flush serialization lock: This lock is acquired during the
>> +    /// DMA fence signalling critical path. It must NEVER be held across any
>> +    /// reclaimable CPU memory allocations because the memory reclaim path can
>> +    /// call `dma_fence_wait()`, which would deadlock with this lock held.
>> +    #[pin]
>> +    lock: Mutex<()>,
>> +}
>> +
>> +impl Tlb {
>> +    /// Create a new TLB manager.
>> +    pub(super) fn new(bar: Arc<Devres<Bar0>>) -> impl PinInit<Self> {
>> +        pin_init!(Self {
>> +            bar,
>> +            lock <- new_mutex!((), "tlb_flush"),
>> +        })
>> +    }
>> +
>> +    /// Flush the GPU TLB for a specific page directory base.
>> +    ///
>> +    /// This invalidates all TLB entries associated with the given PDB address.
>> +    /// Must be called after modifying page table entries to ensure the GPU sees
>> +    /// the updated mappings.
>> +    pub(crate) fn flush(&self, pdb_addr: VramAddress) -> Result {
> 
> This landed on my list randomly, so I took a look.
> 
> Wouldn’t you want to virtualize the invalidation based on your device?
> For example, what if you need to register interface changes on future hardware?

Good point, for future hardware it indeed makes sense. I will do that.
> Or, if you’re a VF, can you even do MMIO?

For VFs, TLB flush is typically done directly via VF's BAR0 MMIO. If there is
VF-specific handling for any reason, that should probably be a different
interface than a per-chip interface (more specifically, checking if Nova is
booted on a VF).

thanks,

--
Joel Fernandes


^ permalink raw reply

* Re: [PATCH v10 10/21] gpu: nova-core: mm: Add MMU v2 page table types
From: Joel Fernandes @ 2026-04-06 21:14 UTC (permalink / raw)
  To: Eliot Courtney, linux-kernel
  Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Bjorn Roy Baron, Benno Lossin,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
	Dave Airlie, Daniel Almeida, Koen Koning, dri-devel,
	rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet,
	Alex Deucher, Christian Koenig, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld,
	Matthew Brost, Lucas De Marchi, Thomas Hellstrom, Helge Deller,
	Alex Gaynor, Boqun Feng, John Hubbard, Alistair Popple,
	Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi,
	Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner,
	Elle Rhumsaa, alexeyi, joel, linux-doc, amd-gfx, intel-gfx,
	intel-xe, linux-fbdev
In-Reply-To: <DHIFGC4E879U.AXIIQKGRZQAF@nvidia.com>



On 4/2/2026 1:41 AM, Eliot Courtney wrote:
> On Wed Apr 1, 2026 at 6:20 AM JST, Joel Fernandes wrote:
>> Add page table entry and directory structures for MMU version 2
>> used by Turing/Ampere/Ada GPUs.
>>
>> Cc: Nikola Djukic <ndjukic@nvidia.com>
>> Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
>> ---
>>  drivers/gpu/nova-core/mm/pagetable.rs      |   2 +
>>  drivers/gpu/nova-core/mm/pagetable/ver2.rs | 232 +++++++++++++++++++++
>>  2 files changed, 234 insertions(+)
>>  create mode 100644 drivers/gpu/nova-core/mm/pagetable/ver2.rs
>>
>> diff --git a/drivers/gpu/nova-core/mm/pagetable.rs b/drivers/gpu/nova-core/mm/pagetable.rs
>> index 50b76d5e5aaf..38d88f8f09a9 100644
>> --- a/drivers/gpu/nova-core/mm/pagetable.rs
>> +++ b/drivers/gpu/nova-core/mm/pagetable.rs
>> @@ -8,6 +8,8 @@
>>  
>>  #![expect(dead_code)]
>>  
>> +pub(crate) mod ver2;
>> +
> 
> This looks like it has more visibility than necessary. And it seems
> incorrect for anyone in the crate to care about MMU version details.
> This can probably be just 'mod ver2'. There are a lot of other types /
> functions in this series that could have tighter visibility. Could you
> go through and see if you can reduce a bunch to private or pub(super)?
> 

Yes, indeed. I am tightening it now, there are several. Thanks!

--
Joel Fernandes


^ permalink raw reply

* Re: [PATCH v10 03/21] gpu: nova-core: gsp: Expose total physical VRAM end from FB region info
From: Joel Fernandes @ 2026-04-06 21:08 UTC (permalink / raw)
  To: Eliot Courtney, linux-kernel
  Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Bjorn Roy Baron, Benno Lossin,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
	Dave Airlie, Daniel Almeida, Koen Koning, dri-devel,
	rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet,
	Alex Deucher, Christian Koenig, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld,
	Matthew Brost, Lucas De Marchi, Thomas Hellstrom, Helge Deller,
	Alex Gaynor, Boqun Feng, John Hubbard, Alistair Popple,
	Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi,
	Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner,
	Elle Rhumsaa, alexeyi, joel, linux-doc, amd-gfx, intel-gfx,
	intel-xe, linux-fbdev
In-Reply-To: <DHIFD6N7QSU1.1RGEN0APPDHD8@nvidia.com>



On 4/2/2026 1:37 AM, Eliot Courtney wrote:
> On Wed Apr 1, 2026 at 6:20 AM JST, Joel Fernandes wrote:
>> Add `total_fb_end()` to `GspStaticConfigInfo` that computes the
>> exclusive end address of the highest valid FB region covering both
>> usable and GSP-reserved areas.
>>
>> This allows callers to know the full physical VRAM extent, not just
>> the allocatable portion.
>>
>> Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
>> ---
>>  drivers/gpu/nova-core/gsp/commands.rs    | 6 ++++++
>>  drivers/gpu/nova-core/gsp/fw/commands.rs | 7 +++++++
>>  2 files changed, 13 insertions(+)
>>
>> diff --git a/drivers/gpu/nova-core/gsp/commands.rs b/drivers/gpu/nova-core/gsp/commands.rs
>> index 41742c1633c8..5e0649024637 100644
>> --- a/drivers/gpu/nova-core/gsp/commands.rs
>> +++ b/drivers/gpu/nova-core/gsp/commands.rs
>> @@ -196,6 +196,9 @@ pub(crate) struct GetGspStaticInfoReply {
>>      /// Usable FB (VRAM) region for driver memory allocation.
>>      #[expect(dead_code)]
>>      pub(crate) usable_fb_region: Range<u64>,
>> +    /// End of VRAM.
>> +    #[expect(dead_code)]
>> +    pub(crate) total_fb_end: u64,
>>  }
>>  
>>  impl MessageFromGsp for GetGspStaticInfoReply {
>> @@ -209,9 +212,12 @@ fn read(
>>      ) -> Result<Self, Self::InitError> {
>>          let (base, size) = msg.first_usable_fb_region().ok_or(ENODEV)?;
>>  
>> +        let total_fb_end = msg.total_fb_end().ok_or(ENODEV)?;
>> +
>>          Ok(GetGspStaticInfoReply {
>>              gpu_name: msg.gpu_name_str(),
>>              usable_fb_region: base..base.saturating_add(size),
>> +            total_fb_end,
>>          })
>>      }
>>  }
>> diff --git a/drivers/gpu/nova-core/gsp/fw/commands.rs b/drivers/gpu/nova-core/gsp/fw/commands.rs
>> index 9fffa74d03f9..46932d5c8c1d 100644
>> --- a/drivers/gpu/nova-core/gsp/fw/commands.rs
>> +++ b/drivers/gpu/nova-core/gsp/fw/commands.rs
>> @@ -163,6 +163,13 @@ pub(crate) fn first_usable_fb_region(&self) -> Option<(u64, u64)> {
>>              }
>>          })
>>      }
>> +
>> +    /// Compute the end of physical VRAM from all FB regions.
>> +    pub(crate) fn total_fb_end(&self) -> Option<u64> {
>> +        self.fb_regions()
>> +            .map(|reg| reg.limit.saturating_add(1))
> 
> I think it would be better to used checked_add here.
> 

Done, thanks.

--
Joel Fernandes


^ permalink raw reply

* Re: [PATCH v10 07/21] gpu: nova-core: mm: Add TLB flush support
From: Joel Fernandes @ 2026-04-06 20:50 UTC (permalink / raw)
  To: Eliot Courtney
  Cc: linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo, Bjorn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Dave Airlie, Daniel Almeida, Koen Koning,
	dri-devel, rust-for-linux, Nikola Djukic, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
	Jonathan Corbet, Alex Deucher, Christian Koenig, Jani Nikula,
	Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui,
	Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellstrom,
	Helge Deller, Alex Gaynor, Boqun Feng, John Hubbard,
	Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot,
	Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh,
	Philipp Stanner, Elle Rhumsaa, alexeyi, joel, linux-doc, amd-gfx,
	intel-gfx, intel-xe, linux-fbdev
In-Reply-To: <DHIFLRYSRR3Z.34IFDA1592HCW@nvidia.com>

On Thu, 02 Apr 2026 14:49:05 +0900, Eliot Courtney wrote:

> > +    /// TLB flush serialization lock: This lock is acquired during the
> > +    /// DMA fence signalling critical path. It must NEVER be held across any
> > +    /// reclaimable CPU memory allocations because the memory reclaim path can
> > +    /// call `dma_fence_wait()`, which would deadlock with this lock held.
> > +    #[pin]
>
> This comment says that the lock is acquired during the DMA fence
> signalling critical path, but IIUC we don't have anything like that
> right now. Is this based on future yet to be done work? Can we reword
> this in a way so it makes sense in the current state?

Good point. Will reword. I'll still keep the references this design is
specifically for that, but will refine to avoid making it look like a fence
signalling usecase already exists. Thanks!

> > +    /// This invalidates all TLB entries associated with the given PDB address.
> > +    /// Must be called after modifying page table entries to ensure the GPU sees
> > +    /// the updated mappings.
>
> If this must be called after every operation like that, I wonder if we
> can change the design to require a guard like pattern something to
> ensure flush is called. WDYT?

That's a good thought. I looked into this -- currently there are only 2
call sites (execute_map and unmap_pages in vmm.rs), and both follow the
same pattern of dropping the PRAMIN window lock before flushing. A RAII
guard would need careful lifetime management to maintain this lock
ordering, and error propagation from drop is tricky. With just 2 call
sites, the explicit flush calls are clearer and easier to audit. If more
call sites emerge in the future, we can revisit adding a guard pattern
then.

> > +    pub(crate) fn flush(&self, pdb_addr: VramAddress) -> Result {
>
> Hopefully we don't need to be calling flush() from anywhere in the
> entire crate. Can you tighten the visibility here and in other places?
> Many things seem to be pub(crate) that don't need to be.

Agreed, will tighten flush() to pub(super) and do a broader visibility
audit across the series. Thanks!

> > +        read_poll_timeout(
> > +            || Ok(bar.read(regs::NV_TLB_FLUSH_CTRL)),
> > +            |ctrl: &regs::NV_TLB_FLUSH_CTRL| !ctrl.enable(),
> > +            Delta::ZERO,
> > +            Delta::from_secs(2),
> > +        )?;
>
> This has zero delay on the read_poll_timeout - what about adding a small
> delay of a microsecond or so?

I think Delta::ZERO is fine here -- it still calls cpu_relax() on each
iteration (not a pure busy-spin). This matches what other DRM drivers do
such polls, e.g. lima_mmu.c and panfrost_gpu.c both use read_poll_timeout
with sleep_us=0 in some places. I also measured it on GA102 and its about
~1-1.5us which I think is well within busy-loop territory. From my experience
with the scheduler, if we sleep, such short sleeps will be much longer than 1us
due to scheduling latency. I also checked OpenRM and even there it is a
sleepless spin-loop.

thanks,

-- 
Joel Fernandes

^ permalink raw reply

* Re: [PATCH v10 03/21] gpu: nova-core: gsp: Expose total physical VRAM end from FB region info
From: Joel Fernandes @ 2026-04-06 19:42 UTC (permalink / raw)
  To: Eliot Courtney
  Cc: linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo, Bjorn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Dave Airlie, Daniel Almeida, Koen Koning,
	dri-devel, rust-for-linux, Nikola Djukic, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
	Jonathan Corbet, Alex Deucher, Christian Koenig, Jani Nikula,
	Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui,
	Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellstrom,
	Helge Deller, Alex Gaynor, Boqun Feng, John Hubbard,
	Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot,
	Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh,
	Philipp Stanner, Elle Rhumsaa, alexeyi, joel, linux-doc, amd-gfx,
	intel-gfx, intel-xe, linux-fbdev
In-Reply-To: <DHIFD6N7QSU1.1RGEN0APPDHD8@nvidia.com>

On Thu, 02 Apr 2026 14:37:52 +0900, Eliot Courtney wrote:

> +    /// Compute the end of physical VRAM from all FB regions.
> +    pub(crate) fn total_fb_end(&self) -> Option<u64> {
> +        self.fb_regions()
> +            .map(|reg| reg.limit.saturating_add(1))
>
> I think it would be better to used checked_add here.

Fixed, thanks.

-- 
Joel Fernandes

^ permalink raw reply

* Re: [PATCH v10 02/21] gpu: nova-core: gsp: Extract usable FB region from GSP
From: Joel Fernandes @ 2026-04-06 18:56 UTC (permalink / raw)
  To: Eliot Courtney, linux-kernel
  Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Bjorn Roy Baron, Benno Lossin,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
	Dave Airlie, Daniel Almeida, Koen Koning, dri-devel,
	rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet,
	Alex Deucher, Christian Koenig, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld,
	Matthew Brost, Lucas De Marchi, Thomas Hellstrom, Helge Deller,
	Alex Gaynor, Boqun Feng, John Hubbard, Alistair Popple,
	Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi,
	Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner,
	Elle Rhumsaa, alexeyi, joel, linux-doc, amd-gfx, intel-gfx,
	intel-xe, linux-fbdev
In-Reply-To: <DHIFMDLKTUSR.14QI5EHNMK18I@nvidia.com>



On 4/2/2026 1:49 AM, Eliot Courtney wrote:
> On Thu Apr 2, 2026 at 8:24 AM JST, Joel Fernandes wrote:
>>
>>
>> On 4/1/2026 4:27 AM, Eliot Courtney wrote:
>>> On Wed Apr 1, 2026 at 6:20 AM JST, Joel Fernandes wrote:
>>>> Add first_usable_fb_region() to GspStaticConfigInfo to extract the first
>>>> usable FB region from GSP's fbRegionInfoParams. Usable regions are those
>>>> that are not reserved or protected.
>>>>
>>>> The extracted region is stored in GetGspStaticInfoReply and exposed as
>>>> usable_fb_region field for use by the memory subsystem.
>>>>
>>>> Cc: Nikola Djukic <ndjukic@nvidia.com>
>>>> Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
>>>> ---
>>>
>>> Please see my feedback from v9[1] which still applies.
>>>
>>> [1]: https://lore.kernel.org/all/DH1GK30TUB4V.2GR6ANXIZDFFQ@nvidia.com/
>>
>> Yeah, I am seeing it now. Amidst making the earlier 7.1 merge window for
>> the DRM buddy and earlier patches in the series, I missed this. They seem
>> to be simple nits and I will address them in the next revision. thanks,
>>
>> --
>> Joel Fernandes
> 
> No worries. Sorry I have not gotten to more of the patches yet. Trying
> to get through some more now. Thanks!
So far all the comments have been good ones, so thanks. ;-)


--
Joel Fernandes


^ permalink raw reply

* Re: [PATCH] arch/mips: Drop CONFIG_FIRMWARE_EDID from defconfig files
From: Thomas Bogendoerfer @ 2026-04-06 12:34 UTC (permalink / raw)
  To: Thomas Zimmermann; +Cc: arnd, linux-mips, linux-kernel, linux-fbdev, dri-devel
In-Reply-To: <20260401082805.214198-1-tzimmermann@suse.de>

On Wed, Apr 01, 2026 at 10:27:57AM +0200, Thomas Zimmermann wrote:
> CONFIG_FIRMWARE_EDID=y depends on X86 or EFI_GENERIC_STUB. Neither is
> true here, so drop the lines from the defconfig files.
> 
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
>  arch/mips/configs/ip32_defconfig            | 1 -
>  arch/mips/configs/lemote2f_defconfig        | 1 -
>  arch/mips/configs/malta_qemu_32r6_defconfig | 1 -
>  arch/mips/configs/maltaaprp_defconfig       | 1 -
>  arch/mips/configs/maltasmvp_defconfig       | 1 -
>  arch/mips/configs/maltasmvp_eva_defconfig   | 1 -
>  arch/mips/configs/maltaup_defconfig         | 1 -
>  7 files changed, 7 deletions(-)

applied to mips-next

Thomas.

-- 
Crap can work. Given enough thrust pigs will fly, but it's not necessarily a
good idea.                                                [ RFC1925, 2.3 ]

^ 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