* [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 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 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 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
* Re: [PATCH v5 8/9] driver core: Replace dev->of_node_reused with dev_of_node_reused()
From: Johan Hovold @ 2026-04-07 9:07 UTC (permalink / raw)
To: Douglas Anderson
Cc: Greg Kroah-Hartman, Rafael J . Wysocki, Danilo Krummrich,
Alan Stern, Alexey Kardashevskiy, Eric Dumazet, Leon Romanovsky,
Christoph Hellwig, Robin Murphy, maz, Alexander Lobakin,
Saravana Kannan, Mark Brown, alexander.stein, andrew, andrew,
andriy.shevchenko, astewart, bhelgaas, brgl, davem, devicetree,
driver-core, hkallweit1, jirislaby, joel, kees, kuba, lgirdwood,
linux-arm-kernel, linux-aspeed, linux-kernel, linux-pci,
linux-serial, linux-usb, linux, mani, netdev, pabeni, robh
In-Reply-To: <20260406162231.v5.8.I806b8636cd3724f6cd1f5e199318ab8694472d90@changeid>
On Mon, Apr 06, 2026 at 04:23:01PM -0700, Doug Anderson wrote:
> In C, bitfields are not necessarily safe to modify from multiple
> threads without locking. Switch "of_node_reused" over to the "flags"
> field so modifications are safe.
This flag is only set before registering a device with driver core so
there is no issue using the existing bitfield here (with the caveat that
PCI pwrctrl may have gotten that wrong). I haven't checked the other
flags, but I assume most of them work the same way.
But apart from the commit message being misleading, switching to using
atomic ops and accessors for consistency is fine.
> Cc: Johan Hovold <johan@kernel.org>
> Acked-by: Mark Brown <broonie@kernel.org>
> Reviewed-by: Rafael J. Wysocki (Intel) <rafael@kernel.org>
> Reviewed-by: Danilo Krummrich <dakr@kernel.org>
> Signed-off-by: Douglas Anderson <dianders@chromium.org>
> ---
> Not fixing any known bugs; problem is theoretical and found by code
> inspection. Change is done somewhat manually and only lightly tested
> (mostly compile-time tested).
> diff --git a/drivers/regulator/bq257xx-regulator.c b/drivers/regulator/bq257xx-regulator.c
> index dab8f1ab4450..40e0f1a7ae81 100644
> --- a/drivers/regulator/bq257xx-regulator.c
> +++ b/drivers/regulator/bq257xx-regulator.c
> @@ -143,7 +143,7 @@ static int bq257xx_regulator_probe(struct platform_device *pdev)
> struct regulator_config cfg = {};
>
> pdev->dev.of_node = pdev->dev.parent->of_node;
> - pdev->dev.of_node_reused = true;
> + dev_set_of_node_reused(&pdev->dev);
>
> pdata = devm_kzalloc(&pdev->dev, sizeof(struct bq257xx_reg_data), GFP_KERNEL);
> if (!pdata)
> diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c
> index e66408f23bb6..8297d31cde9f 100644
> --- a/drivers/regulator/rk808-regulator.c
> +++ b/drivers/regulator/rk808-regulator.c
> @@ -2115,7 +2115,7 @@ static int rk808_regulator_probe(struct platform_device *pdev)
> int ret, i, nregulators;
>
> pdev->dev.of_node = pdev->dev.parent->of_node;
> - pdev->dev.of_node_reused = true;
> + dev_set_of_node_reused(&pdev->dev);
>
> regmap = dev_get_regmap(pdev->dev.parent, NULL);
> if (!regmap)
These two uses are broken currently though and should be using
device_set_of_node_from_dev() so that an extra reference is taken to
balance the one dropped by the platform bus code.
I'll send two fixes to Mark, any merge conflict should be trivial to
fixup.
Reviewed-by: Johan Hovold <johan@kernel.org>
Johan
^ permalink raw reply
* Re: [PATCH v5 8/9] driver core: Replace dev->of_node_reused with dev_of_node_reused()
From: Manivannan Sadhasivam @ 2026-04-07 7:27 UTC (permalink / raw)
To: Douglas Anderson
Cc: Greg Kroah-Hartman, Rafael J . Wysocki, Danilo Krummrich,
Alan Stern, Alexey Kardashevskiy, Johan Hovold, Eric Dumazet,
Leon Romanovsky, Christoph Hellwig, Robin Murphy, maz,
Alexander Lobakin, Saravana Kannan, Mark Brown, alexander.stein,
andrew, andrew, andriy.shevchenko, astewart, bhelgaas, brgl,
davem, devicetree, driver-core, hkallweit1, jirislaby, joel, kees,
kuba, lgirdwood, linux-arm-kernel, linux-aspeed, linux-kernel,
linux-pci, linux-serial, linux-usb, linux, netdev, pabeni, robh
In-Reply-To: <20260406162231.v5.8.I806b8636cd3724f6cd1f5e199318ab8694472d90@changeid>
On Mon, Apr 06, 2026 at 04:23:01PM -0700, Douglas Anderson wrote:
> In C, bitfields are not necessarily safe to modify from multiple
> threads without locking. Switch "of_node_reused" over to the "flags"
> field so modifications are safe.
>
> Cc: Johan Hovold <johan@kernel.org>
> Acked-by: Mark Brown <broonie@kernel.org>
> Reviewed-by: Rafael J. Wysocki (Intel) <rafael@kernel.org>
> Reviewed-by: Danilo Krummrich <dakr@kernel.org>
> Signed-off-by: Douglas Anderson <dianders@chromium.org>
Acked-by: Manivannan Sadhasivam <mani@kernel.org> # PCI_PWRCTRL
- Mani
> ---
> Not fixing any known bugs; problem is theoretical and found by code
> inspection. Change is done somewhat manually and only lightly tested
> (mostly compile-time tested).
>
> (no changes since v4)
>
> Changes in v4:
> - Use accessor functions for flags
>
> Changes in v3:
> - New
>
> drivers/base/core.c | 2 +-
> drivers/base/pinctrl.c | 2 +-
> drivers/base/platform.c | 2 +-
> drivers/net/pcs/pcs-xpcs-plat.c | 2 +-
> drivers/of/device.c | 6 +++---
> drivers/pci/of.c | 2 +-
> drivers/pci/pwrctrl/core.c | 2 +-
> drivers/regulator/bq257xx-regulator.c | 2 +-
> drivers/regulator/rk808-regulator.c | 2 +-
> drivers/tty/serial/serial_base_bus.c | 2 +-
> drivers/usb/gadget/udc/aspeed-vhub/dev.c | 2 +-
> include/linux/device.h | 7 ++++---
> 12 files changed, 17 insertions(+), 16 deletions(-)
>
> diff --git a/drivers/base/core.c b/drivers/base/core.c
> index 8a83d7c93361..30825bf83234 100644
> --- a/drivers/base/core.c
> +++ b/drivers/base/core.c
> @@ -5283,7 +5283,7 @@ void device_set_of_node_from_dev(struct device *dev, const struct device *dev2)
> {
> of_node_put(dev->of_node);
> dev->of_node = of_node_get(dev2->of_node);
> - dev->of_node_reused = true;
> + dev_set_of_node_reused(dev);
> }
> EXPORT_SYMBOL_GPL(device_set_of_node_from_dev);
>
> diff --git a/drivers/base/pinctrl.c b/drivers/base/pinctrl.c
> index 6e250272c843..0bbc83231234 100644
> --- a/drivers/base/pinctrl.c
> +++ b/drivers/base/pinctrl.c
> @@ -24,7 +24,7 @@ int pinctrl_bind_pins(struct device *dev)
> {
> int ret;
>
> - if (dev->of_node_reused)
> + if (dev_of_node_reused(dev))
> return 0;
>
> dev->pins = devm_kzalloc(dev, sizeof(*(dev->pins)), GFP_KERNEL);
> diff --git a/drivers/base/platform.c b/drivers/base/platform.c
> index d44591d52e36..199e6fb25770 100644
> --- a/drivers/base/platform.c
> +++ b/drivers/base/platform.c
> @@ -856,7 +856,7 @@ struct platform_device *platform_device_register_full(
> pdev->dev.parent = pdevinfo->parent;
> pdev->dev.fwnode = pdevinfo->fwnode;
> pdev->dev.of_node = of_node_get(to_of_node(pdev->dev.fwnode));
> - pdev->dev.of_node_reused = pdevinfo->of_node_reused;
> + dev_assign_of_node_reused(&pdev->dev, pdevinfo->of_node_reused);
>
> if (pdevinfo->dma_mask) {
> pdev->platform_dma_mask = pdevinfo->dma_mask;
> diff --git a/drivers/net/pcs/pcs-xpcs-plat.c b/drivers/net/pcs/pcs-xpcs-plat.c
> index b8c48f9effbf..f4b1b8246ce9 100644
> --- a/drivers/net/pcs/pcs-xpcs-plat.c
> +++ b/drivers/net/pcs/pcs-xpcs-plat.c
> @@ -349,7 +349,7 @@ static int xpcs_plat_init_dev(struct dw_xpcs_plat *pxpcs)
> * up later. Make sure DD-core is aware of the OF-node being re-used.
> */
> device_set_node(&mdiodev->dev, fwnode_handle_get(dev_fwnode(dev)));
> - mdiodev->dev.of_node_reused = true;
> + dev_set_of_node_reused(&mdiodev->dev);
>
> /* Pass the data further so the DW XPCS driver core could use it */
> mdiodev->dev.platform_data = (void *)device_get_match_data(dev);
> diff --git a/drivers/of/device.c b/drivers/of/device.c
> index f7e75e527667..be4e1584e0af 100644
> --- a/drivers/of/device.c
> +++ b/drivers/of/device.c
> @@ -26,7 +26,7 @@
> const struct of_device_id *of_match_device(const struct of_device_id *matches,
> const struct device *dev)
> {
> - if (!matches || !dev->of_node || dev->of_node_reused)
> + if (!matches || !dev->of_node || dev_of_node_reused(dev))
> return NULL;
> return of_match_node(matches, dev->of_node);
> }
> @@ -192,7 +192,7 @@ ssize_t of_device_modalias(struct device *dev, char *str, ssize_t len)
> {
> ssize_t sl;
>
> - if (!dev || !dev->of_node || dev->of_node_reused)
> + if (!dev || !dev->of_node || dev_of_node_reused(dev))
> return -ENODEV;
>
> sl = of_modalias(dev->of_node, str, len - 2);
> @@ -254,7 +254,7 @@ int of_device_uevent_modalias(const struct device *dev, struct kobj_uevent_env *
> {
> int sl;
>
> - if ((!dev) || (!dev->of_node) || dev->of_node_reused)
> + if ((!dev) || (!dev->of_node) || dev_of_node_reused(dev))
> return -ENODEV;
>
> /* Devicetree modalias is tricky, we add it in 2 steps */
> diff --git a/drivers/pci/of.c b/drivers/pci/of.c
> index 9f8eb5df279e..1f9b669abdb0 100644
> --- a/drivers/pci/of.c
> +++ b/drivers/pci/of.c
> @@ -38,7 +38,7 @@ int pci_set_of_node(struct pci_dev *dev)
> struct device *pdev __free(put_device) =
> bus_find_device_by_of_node(&platform_bus_type, node);
> if (pdev)
> - dev->bus->dev.of_node_reused = true;
> + dev_set_of_node_reused(&dev->bus->dev);
>
> device_set_node(&dev->dev, of_fwnode_handle(no_free_ptr(node)));
> return 0;
> diff --git a/drivers/pci/pwrctrl/core.c b/drivers/pci/pwrctrl/core.c
> index 7754baed67f2..72963a92362a 100644
> --- a/drivers/pci/pwrctrl/core.c
> +++ b/drivers/pci/pwrctrl/core.c
> @@ -39,7 +39,7 @@ static int pci_pwrctrl_notify(struct notifier_block *nb, unsigned long action,
> * If we got here then the PCI device is the second after the
> * power control platform device. Mark its OF node as reused.
> */
> - dev->of_node_reused = true;
> + dev_set_of_node_reused(dev);
> break;
> }
>
> diff --git a/drivers/regulator/bq257xx-regulator.c b/drivers/regulator/bq257xx-regulator.c
> index dab8f1ab4450..40e0f1a7ae81 100644
> --- a/drivers/regulator/bq257xx-regulator.c
> +++ b/drivers/regulator/bq257xx-regulator.c
> @@ -143,7 +143,7 @@ static int bq257xx_regulator_probe(struct platform_device *pdev)
> struct regulator_config cfg = {};
>
> pdev->dev.of_node = pdev->dev.parent->of_node;
> - pdev->dev.of_node_reused = true;
> + dev_set_of_node_reused(&pdev->dev);
>
> pdata = devm_kzalloc(&pdev->dev, sizeof(struct bq257xx_reg_data), GFP_KERNEL);
> if (!pdata)
> diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c
> index e66408f23bb6..8297d31cde9f 100644
> --- a/drivers/regulator/rk808-regulator.c
> +++ b/drivers/regulator/rk808-regulator.c
> @@ -2115,7 +2115,7 @@ static int rk808_regulator_probe(struct platform_device *pdev)
> int ret, i, nregulators;
>
> pdev->dev.of_node = pdev->dev.parent->of_node;
> - pdev->dev.of_node_reused = true;
> + dev_set_of_node_reused(&pdev->dev);
>
> regmap = dev_get_regmap(pdev->dev.parent, NULL);
> if (!regmap)
> diff --git a/drivers/tty/serial/serial_base_bus.c b/drivers/tty/serial/serial_base_bus.c
> index a12935f6b992..5f23284a8778 100644
> --- a/drivers/tty/serial/serial_base_bus.c
> +++ b/drivers/tty/serial/serial_base_bus.c
> @@ -74,7 +74,7 @@ static int serial_base_device_init(struct uart_port *port,
> dev->parent = parent_dev;
> dev->bus = &serial_base_bus_type;
> dev->release = release;
> - dev->of_node_reused = true;
> + dev_set_of_node_reused(dev);
>
> device_set_node(dev, fwnode_handle_get(dev_fwnode(parent_dev)));
>
> diff --git a/drivers/usb/gadget/udc/aspeed-vhub/dev.c b/drivers/usb/gadget/udc/aspeed-vhub/dev.c
> index 2ecd049dacc2..8b9449d16324 100644
> --- a/drivers/usb/gadget/udc/aspeed-vhub/dev.c
> +++ b/drivers/usb/gadget/udc/aspeed-vhub/dev.c
> @@ -593,7 +593,7 @@ int ast_vhub_init_dev(struct ast_vhub *vhub, unsigned int idx)
> d->gadget.max_speed = USB_SPEED_HIGH;
> d->gadget.speed = USB_SPEED_UNKNOWN;
> d->gadget.dev.of_node = vhub->pdev->dev.of_node;
> - d->gadget.dev.of_node_reused = true;
> + dev_set_of_node_reused(&d->gadget.dev);
>
> rc = usb_add_gadget_udc(d->port_dev, &d->gadget);
> if (rc != 0)
> diff --git a/include/linux/device.h b/include/linux/device.h
> index 5b0fb6ad4c72..a79865a212e9 100644
> --- a/include/linux/device.h
> +++ b/include/linux/device.h
> @@ -483,6 +483,8 @@ struct device_physical_location {
> * driver/bus sync_state() callback.
> * @DEV_FLAG_DMA_COHERENT: This particular device is dma coherent, even if the
> * architecture supports non-coherent devices.
> + * @DEV_FLAG_OF_NODE_REUSED: Set if the device-tree node is shared with an
> + * ancestor device.
> */
> enum struct_device_flags {
> DEV_FLAG_READY_TO_PROBE = 0,
> @@ -492,6 +494,7 @@ enum struct_device_flags {
> DEV_FLAG_DMA_OPS_BYPASS = 4,
> DEV_FLAG_STATE_SYNCED = 5,
> DEV_FLAG_DMA_COHERENT = 6,
> + DEV_FLAG_OF_NODE_REUSED = 7,
>
> DEV_FLAG_COUNT
> };
> @@ -573,8 +576,6 @@ enum struct_device_flags {
> *
> * @offline_disabled: If set, the device is permanently online.
> * @offline: Set after successful invocation of bus type's .offline().
> - * @of_node_reused: Set if the device-tree node is shared with an ancestor
> - * device.
> * @flags: DEV_FLAG_XXX flags. Use atomic bitfield operations to modify.
> *
> * At the lowest level, every device in a Linux system is represented by an
> @@ -681,7 +682,6 @@ struct device {
>
> bool offline_disabled:1;
> bool offline:1;
> - bool of_node_reused:1;
>
> DECLARE_BITMAP(flags, DEV_FLAG_COUNT);
> };
> @@ -715,6 +715,7 @@ __create_dev_flag_accessors(dma_skip_sync, DEV_FLAG_DMA_SKIP_SYNC);
> __create_dev_flag_accessors(dma_ops_bypass, DEV_FLAG_DMA_OPS_BYPASS);
> __create_dev_flag_accessors(state_synced, DEV_FLAG_STATE_SYNCED);
> __create_dev_flag_accessors(dma_coherent, DEV_FLAG_DMA_COHERENT);
> +__create_dev_flag_accessors(of_node_reused, DEV_FLAG_OF_NODE_REUSED);
>
> #undef __create_dev_flag_accessors
>
> --
> 2.53.0.1213.gd9a14994de-goog
>
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply
* [PATCH v5 8/9] driver core: Replace dev->of_node_reused with dev_of_node_reused()
From: Douglas Anderson @ 2026-04-06 23:23 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J . Wysocki, Danilo Krummrich,
Alan Stern
Cc: Alexey Kardashevskiy, Johan Hovold, Eric Dumazet, Leon Romanovsky,
Christoph Hellwig, Robin Murphy, maz, Alexander Lobakin,
Saravana Kannan, Douglas Anderson, Mark Brown, alexander.stein,
andrew, andrew, andriy.shevchenko, astewart, bhelgaas, brgl,
davem, devicetree, driver-core, hkallweit1, jirislaby, joel, kees,
kuba, lgirdwood, linux-arm-kernel, linux-aspeed, linux-kernel,
linux-pci, linux-serial, linux-usb, linux, mani, netdev, pabeni,
robh
In-Reply-To: <20260406232444.3117516-1-dianders@chromium.org>
In C, bitfields are not necessarily safe to modify from multiple
threads without locking. Switch "of_node_reused" over to the "flags"
field so modifications are safe.
Cc: Johan Hovold <johan@kernel.org>
Acked-by: Mark Brown <broonie@kernel.org>
Reviewed-by: Rafael J. Wysocki (Intel) <rafael@kernel.org>
Reviewed-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Douglas Anderson <dianders@chromium.org>
---
Not fixing any known bugs; problem is theoretical and found by code
inspection. Change is done somewhat manually and only lightly tested
(mostly compile-time tested).
(no changes since v4)
Changes in v4:
- Use accessor functions for flags
Changes in v3:
- New
drivers/base/core.c | 2 +-
drivers/base/pinctrl.c | 2 +-
drivers/base/platform.c | 2 +-
drivers/net/pcs/pcs-xpcs-plat.c | 2 +-
drivers/of/device.c | 6 +++---
drivers/pci/of.c | 2 +-
drivers/pci/pwrctrl/core.c | 2 +-
drivers/regulator/bq257xx-regulator.c | 2 +-
drivers/regulator/rk808-regulator.c | 2 +-
drivers/tty/serial/serial_base_bus.c | 2 +-
drivers/usb/gadget/udc/aspeed-vhub/dev.c | 2 +-
include/linux/device.h | 7 ++++---
12 files changed, 17 insertions(+), 16 deletions(-)
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 8a83d7c93361..30825bf83234 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -5283,7 +5283,7 @@ void device_set_of_node_from_dev(struct device *dev, const struct device *dev2)
{
of_node_put(dev->of_node);
dev->of_node = of_node_get(dev2->of_node);
- dev->of_node_reused = true;
+ dev_set_of_node_reused(dev);
}
EXPORT_SYMBOL_GPL(device_set_of_node_from_dev);
diff --git a/drivers/base/pinctrl.c b/drivers/base/pinctrl.c
index 6e250272c843..0bbc83231234 100644
--- a/drivers/base/pinctrl.c
+++ b/drivers/base/pinctrl.c
@@ -24,7 +24,7 @@ int pinctrl_bind_pins(struct device *dev)
{
int ret;
- if (dev->of_node_reused)
+ if (dev_of_node_reused(dev))
return 0;
dev->pins = devm_kzalloc(dev, sizeof(*(dev->pins)), GFP_KERNEL);
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index d44591d52e36..199e6fb25770 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -856,7 +856,7 @@ struct platform_device *platform_device_register_full(
pdev->dev.parent = pdevinfo->parent;
pdev->dev.fwnode = pdevinfo->fwnode;
pdev->dev.of_node = of_node_get(to_of_node(pdev->dev.fwnode));
- pdev->dev.of_node_reused = pdevinfo->of_node_reused;
+ dev_assign_of_node_reused(&pdev->dev, pdevinfo->of_node_reused);
if (pdevinfo->dma_mask) {
pdev->platform_dma_mask = pdevinfo->dma_mask;
diff --git a/drivers/net/pcs/pcs-xpcs-plat.c b/drivers/net/pcs/pcs-xpcs-plat.c
index b8c48f9effbf..f4b1b8246ce9 100644
--- a/drivers/net/pcs/pcs-xpcs-plat.c
+++ b/drivers/net/pcs/pcs-xpcs-plat.c
@@ -349,7 +349,7 @@ static int xpcs_plat_init_dev(struct dw_xpcs_plat *pxpcs)
* up later. Make sure DD-core is aware of the OF-node being re-used.
*/
device_set_node(&mdiodev->dev, fwnode_handle_get(dev_fwnode(dev)));
- mdiodev->dev.of_node_reused = true;
+ dev_set_of_node_reused(&mdiodev->dev);
/* Pass the data further so the DW XPCS driver core could use it */
mdiodev->dev.platform_data = (void *)device_get_match_data(dev);
diff --git a/drivers/of/device.c b/drivers/of/device.c
index f7e75e527667..be4e1584e0af 100644
--- a/drivers/of/device.c
+++ b/drivers/of/device.c
@@ -26,7 +26,7 @@
const struct of_device_id *of_match_device(const struct of_device_id *matches,
const struct device *dev)
{
- if (!matches || !dev->of_node || dev->of_node_reused)
+ if (!matches || !dev->of_node || dev_of_node_reused(dev))
return NULL;
return of_match_node(matches, dev->of_node);
}
@@ -192,7 +192,7 @@ ssize_t of_device_modalias(struct device *dev, char *str, ssize_t len)
{
ssize_t sl;
- if (!dev || !dev->of_node || dev->of_node_reused)
+ if (!dev || !dev->of_node || dev_of_node_reused(dev))
return -ENODEV;
sl = of_modalias(dev->of_node, str, len - 2);
@@ -254,7 +254,7 @@ int of_device_uevent_modalias(const struct device *dev, struct kobj_uevent_env *
{
int sl;
- if ((!dev) || (!dev->of_node) || dev->of_node_reused)
+ if ((!dev) || (!dev->of_node) || dev_of_node_reused(dev))
return -ENODEV;
/* Devicetree modalias is tricky, we add it in 2 steps */
diff --git a/drivers/pci/of.c b/drivers/pci/of.c
index 9f8eb5df279e..1f9b669abdb0 100644
--- a/drivers/pci/of.c
+++ b/drivers/pci/of.c
@@ -38,7 +38,7 @@ int pci_set_of_node(struct pci_dev *dev)
struct device *pdev __free(put_device) =
bus_find_device_by_of_node(&platform_bus_type, node);
if (pdev)
- dev->bus->dev.of_node_reused = true;
+ dev_set_of_node_reused(&dev->bus->dev);
device_set_node(&dev->dev, of_fwnode_handle(no_free_ptr(node)));
return 0;
diff --git a/drivers/pci/pwrctrl/core.c b/drivers/pci/pwrctrl/core.c
index 7754baed67f2..72963a92362a 100644
--- a/drivers/pci/pwrctrl/core.c
+++ b/drivers/pci/pwrctrl/core.c
@@ -39,7 +39,7 @@ static int pci_pwrctrl_notify(struct notifier_block *nb, unsigned long action,
* If we got here then the PCI device is the second after the
* power control platform device. Mark its OF node as reused.
*/
- dev->of_node_reused = true;
+ dev_set_of_node_reused(dev);
break;
}
diff --git a/drivers/regulator/bq257xx-regulator.c b/drivers/regulator/bq257xx-regulator.c
index dab8f1ab4450..40e0f1a7ae81 100644
--- a/drivers/regulator/bq257xx-regulator.c
+++ b/drivers/regulator/bq257xx-regulator.c
@@ -143,7 +143,7 @@ static int bq257xx_regulator_probe(struct platform_device *pdev)
struct regulator_config cfg = {};
pdev->dev.of_node = pdev->dev.parent->of_node;
- pdev->dev.of_node_reused = true;
+ dev_set_of_node_reused(&pdev->dev);
pdata = devm_kzalloc(&pdev->dev, sizeof(struct bq257xx_reg_data), GFP_KERNEL);
if (!pdata)
diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c
index e66408f23bb6..8297d31cde9f 100644
--- a/drivers/regulator/rk808-regulator.c
+++ b/drivers/regulator/rk808-regulator.c
@@ -2115,7 +2115,7 @@ static int rk808_regulator_probe(struct platform_device *pdev)
int ret, i, nregulators;
pdev->dev.of_node = pdev->dev.parent->of_node;
- pdev->dev.of_node_reused = true;
+ dev_set_of_node_reused(&pdev->dev);
regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!regmap)
diff --git a/drivers/tty/serial/serial_base_bus.c b/drivers/tty/serial/serial_base_bus.c
index a12935f6b992..5f23284a8778 100644
--- a/drivers/tty/serial/serial_base_bus.c
+++ b/drivers/tty/serial/serial_base_bus.c
@@ -74,7 +74,7 @@ static int serial_base_device_init(struct uart_port *port,
dev->parent = parent_dev;
dev->bus = &serial_base_bus_type;
dev->release = release;
- dev->of_node_reused = true;
+ dev_set_of_node_reused(dev);
device_set_node(dev, fwnode_handle_get(dev_fwnode(parent_dev)));
diff --git a/drivers/usb/gadget/udc/aspeed-vhub/dev.c b/drivers/usb/gadget/udc/aspeed-vhub/dev.c
index 2ecd049dacc2..8b9449d16324 100644
--- a/drivers/usb/gadget/udc/aspeed-vhub/dev.c
+++ b/drivers/usb/gadget/udc/aspeed-vhub/dev.c
@@ -593,7 +593,7 @@ int ast_vhub_init_dev(struct ast_vhub *vhub, unsigned int idx)
d->gadget.max_speed = USB_SPEED_HIGH;
d->gadget.speed = USB_SPEED_UNKNOWN;
d->gadget.dev.of_node = vhub->pdev->dev.of_node;
- d->gadget.dev.of_node_reused = true;
+ dev_set_of_node_reused(&d->gadget.dev);
rc = usb_add_gadget_udc(d->port_dev, &d->gadget);
if (rc != 0)
diff --git a/include/linux/device.h b/include/linux/device.h
index 5b0fb6ad4c72..a79865a212e9 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -483,6 +483,8 @@ struct device_physical_location {
* driver/bus sync_state() callback.
* @DEV_FLAG_DMA_COHERENT: This particular device is dma coherent, even if the
* architecture supports non-coherent devices.
+ * @DEV_FLAG_OF_NODE_REUSED: Set if the device-tree node is shared with an
+ * ancestor device.
*/
enum struct_device_flags {
DEV_FLAG_READY_TO_PROBE = 0,
@@ -492,6 +494,7 @@ enum struct_device_flags {
DEV_FLAG_DMA_OPS_BYPASS = 4,
DEV_FLAG_STATE_SYNCED = 5,
DEV_FLAG_DMA_COHERENT = 6,
+ DEV_FLAG_OF_NODE_REUSED = 7,
DEV_FLAG_COUNT
};
@@ -573,8 +576,6 @@ enum struct_device_flags {
*
* @offline_disabled: If set, the device is permanently online.
* @offline: Set after successful invocation of bus type's .offline().
- * @of_node_reused: Set if the device-tree node is shared with an ancestor
- * device.
* @flags: DEV_FLAG_XXX flags. Use atomic bitfield operations to modify.
*
* At the lowest level, every device in a Linux system is represented by an
@@ -681,7 +682,6 @@ struct device {
bool offline_disabled:1;
bool offline:1;
- bool of_node_reused:1;
DECLARE_BITMAP(flags, DEV_FLAG_COUNT);
};
@@ -715,6 +715,7 @@ __create_dev_flag_accessors(dma_skip_sync, DEV_FLAG_DMA_SKIP_SYNC);
__create_dev_flag_accessors(dma_ops_bypass, DEV_FLAG_DMA_OPS_BYPASS);
__create_dev_flag_accessors(state_synced, DEV_FLAG_STATE_SYNCED);
__create_dev_flag_accessors(dma_coherent, DEV_FLAG_DMA_COHERENT);
+__create_dev_flag_accessors(of_node_reused, DEV_FLAG_OF_NODE_REUSED);
#undef __create_dev_flag_accessors
--
2.53.0.1213.gd9a14994de-goog
^ permalink raw reply related
* [PATCH v5 0/9] driver core: Fix some race conditions
From: Douglas Anderson @ 2026-04-06 23:22 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J . Wysocki, Danilo Krummrich,
Alan Stern
Cc: Alexey Kardashevskiy, Johan Hovold, Eric Dumazet, Leon Romanovsky,
Christoph Hellwig, Robin Murphy, maz, Alexander Lobakin,
Saravana Kannan, Douglas Anderson, Andrew Morton, Frank.Li,
Jason Gunthorpe, alex, alexander.stein, andre.przywara, andrew,
andrew, andriy.shevchenko, aou, ardb, astewart, bhelgaas, brgl,
broonie, catalin.marinas, chleroy, davem, david, devicetree,
dmaengine, driver-core, gbatra, gregory.clement, hkallweit1,
iommu, jirislaby, joel, joro, kees, kevin.brodsky, kuba, lenb,
lgirdwood, linux-acpi, linux-arm-kernel, linux-aspeed, linux-cxl,
linux-kernel, linux-mips, linux-mm, linux-pci, linux-riscv,
linux-serial, linux-snps-arc, linux-usb, linux, linuxppc-dev,
m.szyprowski, maddy, mani, miko.lenczewski, mpe, netdev, npiggin,
osalvador, oupton, pabeni, palmer, peter.ujfalusi, peterz, pjw,
robh, sebastian.hesselbarth, tglx, tsbogend, vgupta, vkoul, will,
willy, yangyicong, yeoreum.yun
The main goal of this series is to fix the observed bug talked about
in the first patch ("driver core: Don't let a device probe until it's
ready"). That patch fixes a problem that has been observed in the real
world and could land even if the rest of the patches are found
unacceptable or need to be spun.
That said, during patch review Danilo correctly pointed out that many
of the bitfield accesses in "struct device" are unsafe. I added a
bunch of patches in the series to address each one.
Danilo said he's most worried about "can_match", so I put that one
first. After that, I tried to transition bitfields to flags in reverse
order to when the bitfield was added.
Even if transitioning from bitfields to flags isn't truly needed for
correctness, it seems silly (and wasteful of space in struct device)
to have some in bitfields and some as flags. Thus I didn't spend time
for each bitfield showing that it's truly needed for correctness.
Transition was done semi manually. Presumably someone skilled at
coccinelle could do a better job, but I just used sed in a heavy-
handed manner and then reviewed/fixed the results, undoing anything my
script got wrong. My terrible/ugly script was:
var=can_match
caps="${var^^}"
for f in $(git grep -l "[>\.]${var}[^1-9_a-zA-Z\[]"); do
echo $f
sed -i~ -e "s/\([a-zA-Z_0-9\.>()-][a-zA-Z_0-9\.>()-]*\)->${var} = true/set_bit(DEV_FLAG_${caps}, \&\\1->flags)/" "$f"
sed -i~ -e "s/\([a-zA-Z_0-9\.>()-][a-zA-Z_0-9\.>()-]*\)\.${var} = true/dev_set_${caps}(\&\\1)/" "$f"
sed -i~ -e "s/\([a-zA-Z_0-9\.>()-][a-zA-Z_0-9\.>()-]*\)->${var} = false/clear_bit(DEV_FLAG_${caps}, \&\\1->flags)/" "$f"
sed -i~ -e "s/\([a-zA-Z_0-9\.>()-][a-zA-Z_0-9\.>()-]*\)\.${var} = false/dev_clear_${caps}(\&\\1)/" "$f"
sed -i~ -e "s/\([a-zA-Z_0-9\.>()-][a-zA-Z_0-9\.>()-]*\)->${var} = \([^;]*\)/assign_bit(DEV_FLAG_${caps}, \&\\1->flags, \\2)/" "$f"
sed -i~ -e "s/\([a-zA-Z_0-9\.>()-][a-zA-Z_0-9\.>()-]*\)\.${var} = \([^;]*\)/dev_assign_${caps}(\&\\1, \\2)/" "$f"
sed -i~ -e "s/\([a-zA-Z_0-9\.>()-][a-zA-Z_0-9\.>()-]*\)->${var}\([^1-9_a-zA-Z\[]\)/test_bit(DEV_FLAG_${caps}, \&\\1->flags)\\2/" "$f"
sed -i~ -e "s/\([a-zA-Z_0-9\.>()-][a-zA-Z_0-9\.>()-]*\)\.${var}\([^1-9_a-zA-Z\[]\)/dev_${caps}(\&\\1)\\2/" "$f"
done
From v3 to v4, I transitioned to accessor functions with another ugly
sed script. I had git format the old patches, then transformed them
with:
for f in *.patch; do
echo $f
sed -i~ -e "s/test_and_set_bit(DEV_FLAG_\([^,]*\), \&\(.*\)->flags)/dev_test_and_set_\\L\\1(\\2)/" "$f"
sed -i~ -e "s/test_and_set_bit(DEV_FLAG_\([^,]*\), \(.*\)\.flags)/dev_test_and_set_\\L\\1(\\2)/" "$f"
sed -i~ -e "s/test_bit(DEV_FLAG_\([^,]*\), \&\(.*\)->flags)/dev_\\L\\1(\\2)/" "$f"
sed -i~ -e "s/test_bit(DEV_FLAG_\([^,]*\), \(.*\)\.flags)/dev_\\L\\1(\\2)/" "$f"
sed -i~ -e "s/set_bit(DEV_FLAG_\([^,]*\), \&\(.*\)->flags)/dev_set_\\L\\1(\\2)/" "$f"
sed -i~ -e "s/set_bit(DEV_FLAG_\([^,]*\), \(.*\)\.flags)/dev_set_\\L\\1(\\2)/" "$f"
sed -i~ -e "s/clear_bit(DEV_FLAG_\([^,]*\), \&\(.*\)->flags)/dev_clear_\\L\\1(\\2)/" "$f"
sed -i~ -e "s/clear_bit(DEV_FLAG_\([^,]*\), \(.*\)\.flags)/dev_clear_\\L\\1(\\2)/" "$f"
sed -i~ -e "s/assign_bit(DEV_FLAG_\([^,]*\), \&\(.*\)->flags, \(.*\))/dev_assign_\\L\\1(\\2, \\3)/" "$f"
sed -i~ -e "s/assign_bit(DEV_FLAG_\([^,]*\), \(.*\)\.flags, \(.*\))/dev_assign_\\L\\1(\\2, \\3)/" "$f"
done
...and then did a few manual touchups for spacing.
I only marked the first patch as a "Fix" since it is the only one
fixing observed problems. Other patches could be considered fixes too
if folks want.
I tested the first patch in the series backported to kernel 6.6 on the
Pixel phone that was experiencing the race. I added extra printouts to
make sure that the problem was hitting / addressed. The rest of the
patches are tested with allmodconfig with arm32, arm64, ppc, and
x86. I boot tested on an arm64 Chromebook running mainline.
Changes in v5:
- ready_to_prove => ready_to_probe typo
- device_lock() while calling dev_set_ready_to_probe()
- Add comment before "can_match = true" from Danilo.
- undef __create_dev_flag_accessors
Changes in v4:
- Use accessor functions for flags
Changes in v3:
- Use a new "flags" bitfield
- Add missing \n in probe error message
Changes in v2:
- Instead of adjusting the ordering, use "ready_to_probe" flag
Douglas Anderson (9):
driver core: Don't let a device probe until it's ready
driver core: Replace dev->can_match with dev_can_match()
driver core: Replace dev->dma_iommu with dev_dma_iommu()
driver core: Replace dev->dma_skip_sync with dev_dma_skip_sync()
driver core: Replace dev->dma_ops_bypass with dev_dma_ops_bypass()
driver core: Replace dev->state_synced with dev_state_synced()
driver core: Replace dev->dma_coherent with dev_dma_coherent()
driver core: Replace dev->of_node_reused with dev_of_node_reused()
driver core: Replace dev->offline + ->offline_disabled with accessors
arch/arc/mm/dma.c | 4 +-
arch/arm/mach-highbank/highbank.c | 2 +-
arch/arm/mach-mvebu/coherency.c | 2 +-
arch/arm/mm/dma-mapping-nommu.c | 4 +-
arch/arm/mm/dma-mapping.c | 28 ++--
arch/arm64/kernel/cpufeature.c | 2 +-
arch/arm64/mm/dma-mapping.c | 2 +-
arch/mips/mm/dma-noncoherent.c | 2 +-
arch/powerpc/kernel/dma-iommu.c | 8 +-
.../platforms/pseries/hotplug-memory.c | 4 +-
arch/riscv/mm/dma-noncoherent.c | 2 +-
drivers/acpi/scan.c | 2 +-
drivers/base/core.c | 55 +++++---
drivers/base/cpu.c | 4 +-
drivers/base/dd.c | 36 ++++--
drivers/base/memory.c | 2 +-
drivers/base/pinctrl.c | 2 +-
drivers/base/platform.c | 2 +-
drivers/dma/ti/k3-udma-glue.c | 6 +-
drivers/dma/ti/k3-udma.c | 6 +-
drivers/iommu/dma-iommu.c | 9 +-
drivers/iommu/iommu.c | 5 +-
drivers/net/pcs/pcs-xpcs-plat.c | 2 +-
drivers/of/device.c | 6 +-
drivers/pci/of.c | 2 +-
drivers/pci/pwrctrl/core.c | 2 +-
drivers/regulator/bq257xx-regulator.c | 2 +-
drivers/regulator/rk808-regulator.c | 2 +-
drivers/tty/serial/serial_base_bus.c | 2 +-
drivers/usb/gadget/udc/aspeed-vhub/dev.c | 2 +-
include/linux/device.h | 122 ++++++++++++------
include/linux/dma-map-ops.h | 6 +-
include/linux/dma-mapping.h | 2 +-
include/linux/iommu-dma.h | 3 +-
kernel/cpu.c | 4 +-
kernel/dma/mapping.c | 12 +-
mm/hmm.c | 2 +-
37 files changed, 218 insertions(+), 142 deletions(-)
--
2.53.0.1213.gd9a14994de-goog
^ permalink raw reply
* Re: [PATCH v2] MIPS: dts: loongson64g-package: Switch to Loongson UART driver
From: Thomas Bogendoerfer @ 2026-04-06 12:32 UTC (permalink / raw)
To: Rong Zhang
Cc: Greg Kroah-Hartman, Jiri Slaby, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Huacai Chen, Jiaxun Yang, linux-kernel,
linux-serial, linux-mips, devicetree, Yao Zi, Icenowy Zheng,
Rong Zhang
In-Reply-To: <20260315184401.413975-1-rongrong@oss.cipunited.com>
On Mon, Mar 16, 2026 at 02:44:00AM +0800, Rong Zhang wrote:
> Loongson64g is Loongson 3A4000, whose UART controller is compatible with
> Loongson 2K1500, which is NS16550A-compatible with an additional
> fractional frequency divisor register.
>
> Update the compatible strings to reflect this, so that 3A4000 can
> benefit from the fractional frequency divisor provided by loongson-uart.
> This is required on some devices, otherwise their UART can't work at
> some high baud rates, e.g., 115200.
>
> Tested on Loongson-LS3A4000-7A1000-NUC-SE with a 25MHz UART clock.
> Without fractional frequency divisor, the actual baud rate was 111607
> (25MHz / 16 / 14, measured value: 111545) and some USB-to-UART
> converters couldn't work with it at all. With fractional frequency
> divisor, the measured baud rate becomes 115207, which is quite accurate.
>
> Signed-off-by: Rong Zhang <rongrong@oss.cipunited.com>
> ---
> This patch targets the MIPS tree.
>
> The series for the serial tree to update dt-bindings and enable building
> 8250_loongson (loongson-uart) on MIPS Loongson64 is sent separately, as
> it's independant of this patch and can be applied in any order (the
> compatible strings here still contain "ns16550a", so no regression will
> be introduced).
>
> Changes in v2:
> - Separated from v1 (patch 3): https://lore.kernel.org/r/20260314234143.651298-1-rongrong@oss.cipunited.com/
> (thanks Krzysztof Kozlowski)
> ---
> arch/mips/boot/dts/loongson/loongson64g-package.dtsi | 4 ++--
> 1 file changed, 2 insertions(+), 2 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
* Re: [PATCH v4 0/9] driver core: Fix some race conditions
From: Doug Anderson @ 2026-04-05 22:43 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: Rafael J . Wysocki, Danilo Krummrich, Alan Stern, Saravana Kannan,
Christoph Hellwig, Eric Dumazet, Johan Hovold, Leon Romanovsky,
Alexander Lobakin, Alexey Kardashevskiy, Robin Murphy,
Andrew Morton, Frank.Li, Jason Gunthorpe, alex, alexander.stein,
andre.przywara, andrew, andrew, andriy.shevchenko, aou, ardb,
bhelgaas, brgl, broonie, catalin.marinas, chleroy, davem, david,
devicetree, dmaengine, driver-core, gbatra, gregory.clement,
hkallweit1, iommu, jirislaby, joel, joro, kees, kevin.brodsky,
kuba, lenb, lgirdwood, linux-acpi, linux-arm-kernel, linux-aspeed,
linux-cxl, linux-kernel, linux-mips, linux-mm, linux-pci,
linux-riscv, linux-serial, linux-snps-arc, linux-usb, linux,
linuxppc-dev, m.szyprowski, maddy, mani, maz, miko.lenczewski,
mpe, netdev, npiggin, osalvador, oupton, pabeni, palmer,
peter.ujfalusi, peterz, pjw, robh, sebastian.hesselbarth, tglx,
tsbogend, vgupta, vkoul, will, willy, yangyicong, yeoreum.yun
In-Reply-To: <2026040539-sponge-publisher-2b42@gregkh>
Hi,
On Sat, Apr 4, 2026 at 10:28 PM Greg Kroah-Hartman
<gregkh@linuxfoundation.org> wrote:
>
> On Fri, Apr 03, 2026 at 05:04:54PM -0700, Douglas Anderson wrote:
> > NOTE: one potentially "controversial" choice I made in some patches
> > was to always reserve a flag ID even if a flag is only used under
> > certain CONFIG_ settings. This is a change from how things were
> > before. Keeping the numbering consistent and allowing easy
> > compile-testing of both CONFIG settings seemed worth it, especially
> > since it won't take up any extra space until we've added a lot more
> > flags.
>
> Nah, this is fine, I don't see any problems with this as the original
> code kind of was doing the same thing with the "hole" in the structure
> if those options were not enabled.
>
> > I only marked the first patch as a "Fix" since it is the only one
> > fixing observed problems. Other patches could be considered fixes too
> > if folks want.
> >
> > I tested the first patch in the series backported to kernel 6.6 on the
> > Pixel phone that was experiencing the race. I added extra printouts to
> > make sure that the problem was hitting / addressed. The rest of the
> > patches are tested with allmodconfig with arm32, arm64, ppc, and
> > x86. I boot tested on an arm64 Chromebook running mainline.
>
> I'm guessing your tests passed? :)
Yup, all the tests that I've run have passed. I also threw in an
"allnoconfig" compile test just for good measure.
> Anyway, this looks great, unless there are any objections, other than
> the "needs to be undefined", which a follow-on patch can handle, I'll
> queue them up next week for 7.1-rc1.
Thanks. As per the other thread, I'm happy if you or Danilo want to
apply it, and I'm happy if you want to make minor fixups when
applying.
When I see the patches applied, I'll send a followup patch to address
the "needs to be undefined" comment, unless Danilo makes that change
himself when applying.
-Doug
^ permalink raw reply
* Re: [GIT PULL] TTY driver fixes for 7.0-rc7
From: pr-tracker-bot @ 2026-04-05 17:13 UTC (permalink / raw)
To: Greg KH
Cc: Linus Torvalds, Jiri Slaby, Andrew Morton, linux-kernel,
linux-serial
In-Reply-To: <adId31g54PFsRJ_s@kroah.com>
The pull request you sent on Sun, 5 Apr 2026 10:31:27 +0200:
> git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tags/tty-7.0-rc7
has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/7a60c79bd0547adba3cefde40ced4a1f376305be
Thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/prtracker.html
^ permalink raw reply
* Re: [PATCH v4 0/9] driver core: Fix some race conditions
From: Danilo Krummrich @ 2026-04-05 12:02 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: Douglas Anderson, Rafael J . Wysocki, Alan Stern, Saravana Kannan,
Christoph Hellwig, Eric Dumazet, Johan Hovold, Leon Romanovsky,
Alexander Lobakin, Alexey Kardashevskiy, Robin Murphy,
Andrew Morton, Frank.Li, Jason Gunthorpe, alex, alexander.stein,
andre.przywara, andrew, andrew, andriy.shevchenko, aou, ardb,
bhelgaas, brgl, broonie, catalin.marinas, chleroy, davem, david,
devicetree, dmaengine, driver-core, gbatra, gregory.clement,
hkallweit1, iommu, jirislaby, joel, joro, kees, kevin.brodsky,
kuba, lenb, lgirdwood, linux-acpi, linux-arm-kernel, linux-aspeed,
linux-cxl, linux-kernel, linux-mips, linux-mm, linux-pci,
linux-riscv, linux-serial, linux-snps-arc, linux-usb, linux,
linuxppc-dev, m.szyprowski, maddy, mani, maz, miko.lenczewski,
mpe, netdev, npiggin, osalvador, oupton, pabeni, palmer,
peter.ujfalusi, peterz, pjw, robh, sebastian.hesselbarth, tglx,
tsbogend, vgupta, vkoul, will, willy, yangyicong, yeoreum.yun
In-Reply-To: <2026040539-sponge-publisher-2b42@gregkh>
On Sun Apr 5, 2026 at 7:27 AM CEST, Greg Kroah-Hartman wrote:
> Anyway, this looks great, unless there are any objections, other than
> the "needs to be undefined", which a follow-on patch can handle, I'll
> queue them up next week for 7.1-rc1.
Sounds good, for the series:
Reviewed-by: Danilo Krummrich <dakr@kernel.org>
^ permalink raw reply
* [GIT PULL] TTY driver fixes for 7.0-rc7
From: Greg KH @ 2026-04-05 8:31 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Jiri Slaby, Andrew Morton, linux-kernel, linux-serial
The following changes since commit c369299895a591d96745d6492d4888259b004a9e:
Linux 7.0-rc5 (2026-03-22 14:42:17 -0700)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tags/tty-7.0-rc7
for you to fetch changes up to 3ddbea7542ae529c1a88ef9a8b1ce169126211f6:
vt: resize saved unicode buffer on alt screen exit after resize (2026-03-30 17:39:44 +0200)
----------------------------------------------------------------
TTY core fixes for 7.0-rc7
Here are 2 small tty vt fixes for 7.0-rc7 to resolve some reported
issues with the resize ability of the alt screen buffer. Both of these
have been in linux-next all week with no reported issues.
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
----------------------------------------------------------------
Liav Mordouch (1):
vt: discard stale unicode buffer on alt screen exit after resize
Nicolas Pitre (1):
vt: resize saved unicode buffer on alt screen exit after resize
drivers/tty/vt/vt.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
^ permalink raw reply
* Re: [PATCH v4 0/9] driver core: Fix some race conditions
From: Greg Kroah-Hartman @ 2026-04-05 5:27 UTC (permalink / raw)
To: Douglas Anderson
Cc: Rafael J . Wysocki, Danilo Krummrich, Alan Stern, Saravana Kannan,
Christoph Hellwig, Eric Dumazet, Johan Hovold, Leon Romanovsky,
Alexander Lobakin, Alexey Kardashevskiy, Robin Murphy,
Andrew Morton, Frank.Li, Jason Gunthorpe, alex, alexander.stein,
andre.przywara, andrew, andrew, andriy.shevchenko, aou, ardb,
bhelgaas, brgl, broonie, catalin.marinas, chleroy, davem, david,
devicetree, dmaengine, driver-core, gbatra, gregory.clement,
hkallweit1, iommu, jirislaby, joel, joro, kees, kevin.brodsky,
kuba, lenb, lgirdwood, linux-acpi, linux-arm-kernel, linux-aspeed,
linux-cxl, linux-kernel, linux-mips, linux-mm, linux-pci,
linux-riscv, linux-serial, linux-snps-arc, linux-usb, linux,
linuxppc-dev, m.szyprowski, maddy, mani, maz, miko.lenczewski,
mpe, netdev, npiggin, osalvador, oupton, pabeni, palmer,
peter.ujfalusi, peterz, pjw, robh, sebastian.hesselbarth, tglx,
tsbogend, vgupta, vkoul, will, willy, yangyicong, yeoreum.yun
In-Reply-To: <20260404000644.522677-1-dianders@chromium.org>
On Fri, Apr 03, 2026 at 05:04:54PM -0700, Douglas Anderson wrote:
> NOTE: one potentially "controversial" choice I made in some patches
> was to always reserve a flag ID even if a flag is only used under
> certain CONFIG_ settings. This is a change from how things were
> before. Keeping the numbering consistent and allowing easy
> compile-testing of both CONFIG settings seemed worth it, especially
> since it won't take up any extra space until we've added a lot more
> flags.
Nah, this is fine, I don't see any problems with this as the original
code kind of was doing the same thing with the "hole" in the structure
if those options were not enabled.
> I only marked the first patch as a "Fix" since it is the only one
> fixing observed problems. Other patches could be considered fixes too
> if folks want.
>
> I tested the first patch in the series backported to kernel 6.6 on the
> Pixel phone that was experiencing the race. I added extra printouts to
> make sure that the problem was hitting / addressed. The rest of the
> patches are tested with allmodconfig with arm32, arm64, ppc, and
> x86. I boot tested on an arm64 Chromebook running mainline.
I'm guessing your tests passed? :)
Anyway, this looks great, unless there are any objections, other than
the "needs to be undefined", which a follow-on patch can handle, I'll
queue them up next week for 7.1-rc1.
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCH v4 0/9] driver core: Fix some race conditions
From: Rafael J. Wysocki @ 2026-04-04 17:11 UTC (permalink / raw)
To: Douglas Anderson
Cc: Greg Kroah-Hartman, Rafael J . Wysocki, Danilo Krummrich,
Alan Stern, Saravana Kannan, Christoph Hellwig, Eric Dumazet,
Johan Hovold, Leon Romanovsky, Alexander Lobakin,
Alexey Kardashevskiy, Robin Murphy, Andrew Morton, Frank.Li,
Jason Gunthorpe, alex, alexander.stein, andre.przywara, andrew,
andrew, andriy.shevchenko, aou, ardb, bhelgaas, brgl, broonie,
catalin.marinas, chleroy, davem, david, devicetree, dmaengine,
driver-core, gbatra, gregory.clement, hkallweit1, iommu,
jirislaby, joel, joro, kees, kevin.brodsky, kuba, lenb, lgirdwood,
linux-acpi, linux-arm-kernel, linux-aspeed, linux-cxl,
linux-kernel, linux-mips, linux-mm, linux-pci, linux-riscv,
linux-serial, linux-snps-arc, linux-usb, linux, linuxppc-dev,
m.szyprowski, maddy, mani, maz, miko.lenczewski, mpe, netdev,
npiggin, osalvador, oupton, pabeni, palmer, peter.ujfalusi,
peterz, pjw, robh, sebastian.hesselbarth, tglx, tsbogend, vgupta,
vkoul, will, willy, yangyicong, yeoreum.yun
In-Reply-To: <20260404000644.522677-1-dianders@chromium.org>
On Sat, Apr 4, 2026 at 2:07 AM Douglas Anderson <dianders@chromium.org> wrote:
>
> The main goal of this series is to fix the observed bug talked about
> in the first patch ("driver core: Don't let a device probe until it's
> ready"). That patch fixes a problem that has been observed in the real
> world and could land even if the rest of the patches are found
> unacceptable or need to be spun.
>
> That said, during patch review Danilo correctly pointed out that many
> of the bitfield accesses in "struct device" are unsafe. I added a
> bunch of patches in the series to address each one.
>
> Danilo said he's most worried about "can_match", so I put that one
> first. After that, I tried to transition bitfields to flags in reverse
> order to when the bitfield was added.
>
> Even if transitioning from bitfields to flags isn't truly needed for
> correctness, it seems silly (and wasteful of space in struct device)
> to have some in bitfields and some as flags. Thus I didn't spend time
> for each bitfield showing that it's truly needed for correctness.
>
> Transition was done semi manually. Presumably someone skilled at
> coccinelle could do a better job, but I just used sed in a heavy-
> handed manner and then reviewed/fixed the results, undoing anything my
> script got wrong. My terrible/ugly script was:
>
> var=can_match
> caps="${var^^}"
> for f in $(git grep -l "[>\.]${var}[^1-9_a-zA-Z\[]"); do
> echo $f
> sed -i~ -e "s/\([a-zA-Z_0-9\.>()-][a-zA-Z_0-9\.>()-]*\)->${var} = true/set_bit(DEV_FLAG_${caps}, \&\\1->flags)/" "$f"
> sed -i~ -e "s/\([a-zA-Z_0-9\.>()-][a-zA-Z_0-9\.>()-]*\)\.${var} = true/dev_set_${caps}(\&\\1)/" "$f"
> sed -i~ -e "s/\([a-zA-Z_0-9\.>()-][a-zA-Z_0-9\.>()-]*\)->${var} = false/clear_bit(DEV_FLAG_${caps}, \&\\1->flags)/" "$f"
> sed -i~ -e "s/\([a-zA-Z_0-9\.>()-][a-zA-Z_0-9\.>()-]*\)\.${var} = false/dev_clear_${caps}(\&\\1)/" "$f"
> sed -i~ -e "s/\([a-zA-Z_0-9\.>()-][a-zA-Z_0-9\.>()-]*\)->${var} = \([^;]*\)/assign_bit(DEV_FLAG_${caps}, \&\\1->flags, \\2)/" "$f"
> sed -i~ -e "s/\([a-zA-Z_0-9\.>()-][a-zA-Z_0-9\.>()-]*\)\.${var} = \([^;]*\)/dev_assign_${caps}(\&\\1, \\2)/" "$f"
> sed -i~ -e "s/\([a-zA-Z_0-9\.>()-][a-zA-Z_0-9\.>()-]*\)->${var}\([^1-9_a-zA-Z\[]\)/test_bit(DEV_FLAG_${caps}, \&\\1->flags)\\2/" "$f"
> sed -i~ -e "s/\([a-zA-Z_0-9\.>()-][a-zA-Z_0-9\.>()-]*\)\.${var}\([^1-9_a-zA-Z\[]\)/dev_${caps}(\&\\1)\\2/" "$f"
> done
>
> From v3 to v4, I transitioned to accessor functions with another ugly
> sed script. I had git format the old patches, then transformed them
> with:
>
> for f in *.patch; do
> echo $f
> sed -i~ -e "s/test_and_set_bit(DEV_FLAG_\([^,]*\), \&\(.*\)->flags)/dev_test_and_set_\\L\\1(\\2)/" "$f"
> sed -i~ -e "s/test_and_set_bit(DEV_FLAG_\([^,]*\), \(.*\)\.flags)/dev_test_and_set_\\L\\1(\\2)/" "$f"
> sed -i~ -e "s/test_bit(DEV_FLAG_\([^,]*\), \&\(.*\)->flags)/dev_\\L\\1(\\2)/" "$f"
> sed -i~ -e "s/test_bit(DEV_FLAG_\([^,]*\), \(.*\)\.flags)/dev_\\L\\1(\\2)/" "$f"
> sed -i~ -e "s/set_bit(DEV_FLAG_\([^,]*\), \&\(.*\)->flags)/dev_set_\\L\\1(\\2)/" "$f"
> sed -i~ -e "s/set_bit(DEV_FLAG_\([^,]*\), \(.*\)\.flags)/dev_set_\\L\\1(\\2)/" "$f"
> sed -i~ -e "s/clear_bit(DEV_FLAG_\([^,]*\), \&\(.*\)->flags)/dev_clear_\\L\\1(\\2)/" "$f"
> sed -i~ -e "s/clear_bit(DEV_FLAG_\([^,]*\), \(.*\)\.flags)/dev_clear_\\L\\1(\\2)/" "$f"
> sed -i~ -e "s/assign_bit(DEV_FLAG_\([^,]*\), \&\(.*\)->flags, \(.*\))/dev_assign_\\L\\1(\\2, \\3)/" "$f"
> sed -i~ -e "s/assign_bit(DEV_FLAG_\([^,]*\), \(.*\)\.flags, \(.*\))/dev_assign_\\L\\1(\\2, \\3)/" "$f"
> done
>
> ...and then did a few manual touchups for spacing.
>
> NOTE: one potentially "controversial" choice I made in some patches
> was to always reserve a flag ID even if a flag is only used under
> certain CONFIG_ settings. This is a change from how things were
> before. Keeping the numbering consistent and allowing easy
> compile-testing of both CONFIG settings seemed worth it, especially
> since it won't take up any extra space until we've added a lot more
> flags.
>
> I only marked the first patch as a "Fix" since it is the only one
> fixing observed problems. Other patches could be considered fixes too
> if folks want.
>
> I tested the first patch in the series backported to kernel 6.6 on the
> Pixel phone that was experiencing the race. I added extra printouts to
> make sure that the problem was hitting / addressed. The rest of the
> patches are tested with allmodconfig with arm32, arm64, ppc, and
> x86. I boot tested on an arm64 Chromebook running mainline.
>
> Changes in v4:
> - Use accessor functions for flags
>
> Changes in v3:
> - Use a new "flags" bitfield
> - Add missing \n in probe error message
>
> Changes in v2:
> - Instead of adjusting the ordering, use "ready_to_probe" flag
>
> Douglas Anderson (9):
> driver core: Don't let a device probe until it's ready
> driver core: Replace dev->can_match with dev_can_match()
> driver core: Replace dev->dma_iommu with dev_dma_iommu()
> driver core: Replace dev->dma_skip_sync with dev_dma_skip_sync()
> driver core: Replace dev->dma_ops_bypass with dev_dma_ops_bypass()
> driver core: Replace dev->state_synced with dev_state_synced()
> driver core: Replace dev->dma_coherent with dev_dma_coherent()
> driver core: Replace dev->of_node_reused with dev_of_node_reused()
> driver core: Replace dev->offline + ->offline_disabled with accessors
>
> arch/arc/mm/dma.c | 4 +-
> arch/arm/mach-highbank/highbank.c | 2 +-
> arch/arm/mach-mvebu/coherency.c | 2 +-
> arch/arm/mm/dma-mapping-nommu.c | 4 +-
> arch/arm/mm/dma-mapping.c | 28 ++--
> arch/arm64/kernel/cpufeature.c | 2 +-
> arch/arm64/mm/dma-mapping.c | 2 +-
> arch/mips/mm/dma-noncoherent.c | 2 +-
> arch/powerpc/kernel/dma-iommu.c | 8 +-
> .../platforms/pseries/hotplug-memory.c | 4 +-
> arch/riscv/mm/dma-noncoherent.c | 2 +-
> drivers/acpi/scan.c | 2 +-
> drivers/base/core.c | 53 +++++---
> drivers/base/cpu.c | 4 +-
> drivers/base/dd.c | 28 ++--
> drivers/base/memory.c | 2 +-
> drivers/base/pinctrl.c | 2 +-
> drivers/base/platform.c | 2 +-
> drivers/dma/ti/k3-udma-glue.c | 6 +-
> drivers/dma/ti/k3-udma.c | 6 +-
> drivers/iommu/dma-iommu.c | 9 +-
> drivers/iommu/iommu.c | 5 +-
> drivers/net/pcs/pcs-xpcs-plat.c | 2 +-
> drivers/of/device.c | 6 +-
> drivers/pci/of.c | 2 +-
> drivers/pci/pwrctrl/core.c | 2 +-
> drivers/regulator/bq257xx-regulator.c | 2 +-
> drivers/regulator/rk808-regulator.c | 2 +-
> drivers/tty/serial/serial_base_bus.c | 2 +-
> drivers/usb/gadget/udc/aspeed-vhub/dev.c | 2 +-
> include/linux/device.h | 120 ++++++++++++------
> include/linux/dma-map-ops.h | 6 +-
> include/linux/dma-mapping.h | 2 +-
> include/linux/iommu-dma.h | 3 +-
> kernel/cpu.c | 4 +-
> kernel/dma/mapping.c | 12 +-
> mm/hmm.c | 2 +-
> 37 files changed, 206 insertions(+), 142 deletions(-)
>
> --
For the whole set
Reviewed-by: Rafael J. Wysocki (Intel) <rafael@kernel.org>
^ permalink raw reply
* [PATCH v4 8/9] driver core: Replace dev->of_node_reused with dev_of_node_reused()
From: Douglas Anderson @ 2026-04-04 0:05 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J . Wysocki, Danilo Krummrich,
Alan Stern
Cc: Saravana Kannan, Christoph Hellwig, Eric Dumazet, Johan Hovold,
Leon Romanovsky, Alexander Lobakin, Alexey Kardashevskiy,
Robin Murphy, Douglas Anderson, Mark Brown, alexander.stein,
andrew, andrew, andriy.shevchenko, bhelgaas, brgl, davem,
devicetree, driver-core, hkallweit1, jirislaby, joel, kees, kuba,
lgirdwood, linux-arm-kernel, linux-aspeed, linux-kernel,
linux-pci, linux-serial, linux-usb, linux, mani, netdev, pabeni,
robh
In-Reply-To: <20260404000644.522677-1-dianders@chromium.org>
In C, bitfields are not necessarily safe to modify from multiple
threads without locking. Switch "of_node_reused" over to the "flags"
field so modifications are safe.
Cc: Johan Hovold <johan@kernel.org>
Acked-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Douglas Anderson <dianders@chromium.org>
---
Not fixing any known bugs; problem is theoretical and found by code
inspection. Change is done somewhat manually and only lightly tested
(mostly compile-time tested).
Changes in v4:
- Use accessor functions for flags
Changes in v3:
- New
drivers/base/core.c | 2 +-
drivers/base/pinctrl.c | 2 +-
drivers/base/platform.c | 2 +-
drivers/net/pcs/pcs-xpcs-plat.c | 2 +-
drivers/of/device.c | 6 +++---
drivers/pci/of.c | 2 +-
drivers/pci/pwrctrl/core.c | 2 +-
drivers/regulator/bq257xx-regulator.c | 2 +-
drivers/regulator/rk808-regulator.c | 2 +-
drivers/tty/serial/serial_base_bus.c | 2 +-
drivers/usb/gadget/udc/aspeed-vhub/dev.c | 2 +-
include/linux/device.h | 7 ++++---
12 files changed, 17 insertions(+), 16 deletions(-)
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 531f02a5469a..f12f3b53b4d0 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -5281,7 +5281,7 @@ void device_set_of_node_from_dev(struct device *dev, const struct device *dev2)
{
of_node_put(dev->of_node);
dev->of_node = of_node_get(dev2->of_node);
- dev->of_node_reused = true;
+ dev_set_of_node_reused(dev);
}
EXPORT_SYMBOL_GPL(device_set_of_node_from_dev);
diff --git a/drivers/base/pinctrl.c b/drivers/base/pinctrl.c
index 6e250272c843..0bbc83231234 100644
--- a/drivers/base/pinctrl.c
+++ b/drivers/base/pinctrl.c
@@ -24,7 +24,7 @@ int pinctrl_bind_pins(struct device *dev)
{
int ret;
- if (dev->of_node_reused)
+ if (dev_of_node_reused(dev))
return 0;
dev->pins = devm_kzalloc(dev, sizeof(*(dev->pins)), GFP_KERNEL);
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index d44591d52e36..199e6fb25770 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -856,7 +856,7 @@ struct platform_device *platform_device_register_full(
pdev->dev.parent = pdevinfo->parent;
pdev->dev.fwnode = pdevinfo->fwnode;
pdev->dev.of_node = of_node_get(to_of_node(pdev->dev.fwnode));
- pdev->dev.of_node_reused = pdevinfo->of_node_reused;
+ dev_assign_of_node_reused(&pdev->dev, pdevinfo->of_node_reused);
if (pdevinfo->dma_mask) {
pdev->platform_dma_mask = pdevinfo->dma_mask;
diff --git a/drivers/net/pcs/pcs-xpcs-plat.c b/drivers/net/pcs/pcs-xpcs-plat.c
index b8c48f9effbf..f4b1b8246ce9 100644
--- a/drivers/net/pcs/pcs-xpcs-plat.c
+++ b/drivers/net/pcs/pcs-xpcs-plat.c
@@ -349,7 +349,7 @@ static int xpcs_plat_init_dev(struct dw_xpcs_plat *pxpcs)
* up later. Make sure DD-core is aware of the OF-node being re-used.
*/
device_set_node(&mdiodev->dev, fwnode_handle_get(dev_fwnode(dev)));
- mdiodev->dev.of_node_reused = true;
+ dev_set_of_node_reused(&mdiodev->dev);
/* Pass the data further so the DW XPCS driver core could use it */
mdiodev->dev.platform_data = (void *)device_get_match_data(dev);
diff --git a/drivers/of/device.c b/drivers/of/device.c
index f7e75e527667..be4e1584e0af 100644
--- a/drivers/of/device.c
+++ b/drivers/of/device.c
@@ -26,7 +26,7 @@
const struct of_device_id *of_match_device(const struct of_device_id *matches,
const struct device *dev)
{
- if (!matches || !dev->of_node || dev->of_node_reused)
+ if (!matches || !dev->of_node || dev_of_node_reused(dev))
return NULL;
return of_match_node(matches, dev->of_node);
}
@@ -192,7 +192,7 @@ ssize_t of_device_modalias(struct device *dev, char *str, ssize_t len)
{
ssize_t sl;
- if (!dev || !dev->of_node || dev->of_node_reused)
+ if (!dev || !dev->of_node || dev_of_node_reused(dev))
return -ENODEV;
sl = of_modalias(dev->of_node, str, len - 2);
@@ -254,7 +254,7 @@ int of_device_uevent_modalias(const struct device *dev, struct kobj_uevent_env *
{
int sl;
- if ((!dev) || (!dev->of_node) || dev->of_node_reused)
+ if ((!dev) || (!dev->of_node) || dev_of_node_reused(dev))
return -ENODEV;
/* Devicetree modalias is tricky, we add it in 2 steps */
diff --git a/drivers/pci/of.c b/drivers/pci/of.c
index 9f8eb5df279e..1f9b669abdb0 100644
--- a/drivers/pci/of.c
+++ b/drivers/pci/of.c
@@ -38,7 +38,7 @@ int pci_set_of_node(struct pci_dev *dev)
struct device *pdev __free(put_device) =
bus_find_device_by_of_node(&platform_bus_type, node);
if (pdev)
- dev->bus->dev.of_node_reused = true;
+ dev_set_of_node_reused(&dev->bus->dev);
device_set_node(&dev->dev, of_fwnode_handle(no_free_ptr(node)));
return 0;
diff --git a/drivers/pci/pwrctrl/core.c b/drivers/pci/pwrctrl/core.c
index 7754baed67f2..72963a92362a 100644
--- a/drivers/pci/pwrctrl/core.c
+++ b/drivers/pci/pwrctrl/core.c
@@ -39,7 +39,7 @@ static int pci_pwrctrl_notify(struct notifier_block *nb, unsigned long action,
* If we got here then the PCI device is the second after the
* power control platform device. Mark its OF node as reused.
*/
- dev->of_node_reused = true;
+ dev_set_of_node_reused(dev);
break;
}
diff --git a/drivers/regulator/bq257xx-regulator.c b/drivers/regulator/bq257xx-regulator.c
index dab8f1ab4450..40e0f1a7ae81 100644
--- a/drivers/regulator/bq257xx-regulator.c
+++ b/drivers/regulator/bq257xx-regulator.c
@@ -143,7 +143,7 @@ static int bq257xx_regulator_probe(struct platform_device *pdev)
struct regulator_config cfg = {};
pdev->dev.of_node = pdev->dev.parent->of_node;
- pdev->dev.of_node_reused = true;
+ dev_set_of_node_reused(&pdev->dev);
pdata = devm_kzalloc(&pdev->dev, sizeof(struct bq257xx_reg_data), GFP_KERNEL);
if (!pdata)
diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c
index e66408f23bb6..8297d31cde9f 100644
--- a/drivers/regulator/rk808-regulator.c
+++ b/drivers/regulator/rk808-regulator.c
@@ -2115,7 +2115,7 @@ static int rk808_regulator_probe(struct platform_device *pdev)
int ret, i, nregulators;
pdev->dev.of_node = pdev->dev.parent->of_node;
- pdev->dev.of_node_reused = true;
+ dev_set_of_node_reused(&pdev->dev);
regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!regmap)
diff --git a/drivers/tty/serial/serial_base_bus.c b/drivers/tty/serial/serial_base_bus.c
index a12935f6b992..5f23284a8778 100644
--- a/drivers/tty/serial/serial_base_bus.c
+++ b/drivers/tty/serial/serial_base_bus.c
@@ -74,7 +74,7 @@ static int serial_base_device_init(struct uart_port *port,
dev->parent = parent_dev;
dev->bus = &serial_base_bus_type;
dev->release = release;
- dev->of_node_reused = true;
+ dev_set_of_node_reused(dev);
device_set_node(dev, fwnode_handle_get(dev_fwnode(parent_dev)));
diff --git a/drivers/usb/gadget/udc/aspeed-vhub/dev.c b/drivers/usb/gadget/udc/aspeed-vhub/dev.c
index 2ecd049dacc2..8b9449d16324 100644
--- a/drivers/usb/gadget/udc/aspeed-vhub/dev.c
+++ b/drivers/usb/gadget/udc/aspeed-vhub/dev.c
@@ -593,7 +593,7 @@ int ast_vhub_init_dev(struct ast_vhub *vhub, unsigned int idx)
d->gadget.max_speed = USB_SPEED_HIGH;
d->gadget.speed = USB_SPEED_UNKNOWN;
d->gadget.dev.of_node = vhub->pdev->dev.of_node;
- d->gadget.dev.of_node_reused = true;
+ dev_set_of_node_reused(&d->gadget.dev);
rc = usb_add_gadget_udc(d->port_dev, &d->gadget);
if (rc != 0)
diff --git a/include/linux/device.h b/include/linux/device.h
index fca986cef2ed..8132aab17e04 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -483,6 +483,8 @@ struct device_physical_location {
* driver/bus sync_state() callback.
* @DEV_FLAG_DMA_COHERENT: This particular device is dma coherent, even if the
* architecture supports non-coherent devices.
+ * @DEV_FLAG_OF_NODE_REUSED: Set if the device-tree node is shared with an
+ * ancestor device.
*/
enum struct_device_flags {
DEV_FLAG_READY_TO_PROBE = 0,
@@ -492,6 +494,7 @@ enum struct_device_flags {
DEV_FLAG_DMA_OPS_BYPASS = 4,
DEV_FLAG_STATE_SYNCED = 5,
DEV_FLAG_DMA_COHERENT = 6,
+ DEV_FLAG_OF_NODE_REUSED = 7,
DEV_FLAG_COUNT
};
@@ -573,8 +576,6 @@ enum struct_device_flags {
*
* @offline_disabled: If set, the device is permanently online.
* @offline: Set after successful invocation of bus type's .offline().
- * @of_node_reused: Set if the device-tree node is shared with an ancestor
- * device.
* @flags: DEV_FLAG_XXX flags. Use atomic bitfield operations to modify.
*
* At the lowest level, every device in a Linux system is represented by an
@@ -681,7 +682,6 @@ struct device {
bool offline_disabled:1;
bool offline:1;
- bool of_node_reused:1;
DECLARE_BITMAP(flags, DEV_FLAG_COUNT);
};
@@ -715,6 +715,7 @@ __create_dev_flag_accessors(dma_skip_sync, DEV_FLAG_DMA_SKIP_SYNC);
__create_dev_flag_accessors(dma_ops_bypass, DEV_FLAG_DMA_OPS_BYPASS);
__create_dev_flag_accessors(state_synced, DEV_FLAG_STATE_SYNCED);
__create_dev_flag_accessors(dma_coherent, DEV_FLAG_DMA_COHERENT);
+__create_dev_flag_accessors(of_node_reused, DEV_FLAG_OF_NODE_REUSED);
/**
* struct device_link - Device link representation.
--
2.53.0.1213.gd9a14994de-goog
^ permalink raw reply related
* [PATCH v4 0/9] driver core: Fix some race conditions
From: Douglas Anderson @ 2026-04-04 0:04 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J . Wysocki, Danilo Krummrich,
Alan Stern
Cc: Saravana Kannan, Christoph Hellwig, Eric Dumazet, Johan Hovold,
Leon Romanovsky, Alexander Lobakin, Alexey Kardashevskiy,
Robin Murphy, Douglas Anderson, Andrew Morton, Frank.Li,
Jason Gunthorpe, alex, alexander.stein, andre.przywara, andrew,
andrew, andriy.shevchenko, aou, ardb, bhelgaas, brgl, broonie,
catalin.marinas, chleroy, davem, david, devicetree, dmaengine,
driver-core, gbatra, gregory.clement, hkallweit1, iommu,
jirislaby, joel, joro, kees, kevin.brodsky, kuba, lenb, lgirdwood,
linux-acpi, linux-arm-kernel, linux-aspeed, linux-cxl,
linux-kernel, linux-mips, linux-mm, linux-pci, linux-riscv,
linux-serial, linux-snps-arc, linux-usb, linux, linuxppc-dev,
m.szyprowski, maddy, mani, maz, miko.lenczewski, mpe, netdev,
npiggin, osalvador, oupton, pabeni, palmer, peter.ujfalusi,
peterz, pjw, robh, sebastian.hesselbarth, tglx, tsbogend, vgupta,
vkoul, will, willy, yangyicong, yeoreum.yun
The main goal of this series is to fix the observed bug talked about
in the first patch ("driver core: Don't let a device probe until it's
ready"). That patch fixes a problem that has been observed in the real
world and could land even if the rest of the patches are found
unacceptable or need to be spun.
That said, during patch review Danilo correctly pointed out that many
of the bitfield accesses in "struct device" are unsafe. I added a
bunch of patches in the series to address each one.
Danilo said he's most worried about "can_match", so I put that one
first. After that, I tried to transition bitfields to flags in reverse
order to when the bitfield was added.
Even if transitioning from bitfields to flags isn't truly needed for
correctness, it seems silly (and wasteful of space in struct device)
to have some in bitfields and some as flags. Thus I didn't spend time
for each bitfield showing that it's truly needed for correctness.
Transition was done semi manually. Presumably someone skilled at
coccinelle could do a better job, but I just used sed in a heavy-
handed manner and then reviewed/fixed the results, undoing anything my
script got wrong. My terrible/ugly script was:
var=can_match
caps="${var^^}"
for f in $(git grep -l "[>\.]${var}[^1-9_a-zA-Z\[]"); do
echo $f
sed -i~ -e "s/\([a-zA-Z_0-9\.>()-][a-zA-Z_0-9\.>()-]*\)->${var} = true/set_bit(DEV_FLAG_${caps}, \&\\1->flags)/" "$f"
sed -i~ -e "s/\([a-zA-Z_0-9\.>()-][a-zA-Z_0-9\.>()-]*\)\.${var} = true/dev_set_${caps}(\&\\1)/" "$f"
sed -i~ -e "s/\([a-zA-Z_0-9\.>()-][a-zA-Z_0-9\.>()-]*\)->${var} = false/clear_bit(DEV_FLAG_${caps}, \&\\1->flags)/" "$f"
sed -i~ -e "s/\([a-zA-Z_0-9\.>()-][a-zA-Z_0-9\.>()-]*\)\.${var} = false/dev_clear_${caps}(\&\\1)/" "$f"
sed -i~ -e "s/\([a-zA-Z_0-9\.>()-][a-zA-Z_0-9\.>()-]*\)->${var} = \([^;]*\)/assign_bit(DEV_FLAG_${caps}, \&\\1->flags, \\2)/" "$f"
sed -i~ -e "s/\([a-zA-Z_0-9\.>()-][a-zA-Z_0-9\.>()-]*\)\.${var} = \([^;]*\)/dev_assign_${caps}(\&\\1, \\2)/" "$f"
sed -i~ -e "s/\([a-zA-Z_0-9\.>()-][a-zA-Z_0-9\.>()-]*\)->${var}\([^1-9_a-zA-Z\[]\)/test_bit(DEV_FLAG_${caps}, \&\\1->flags)\\2/" "$f"
sed -i~ -e "s/\([a-zA-Z_0-9\.>()-][a-zA-Z_0-9\.>()-]*\)\.${var}\([^1-9_a-zA-Z\[]\)/dev_${caps}(\&\\1)\\2/" "$f"
done
From v3 to v4, I transitioned to accessor functions with another ugly
sed script. I had git format the old patches, then transformed them
with:
for f in *.patch; do
echo $f
sed -i~ -e "s/test_and_set_bit(DEV_FLAG_\([^,]*\), \&\(.*\)->flags)/dev_test_and_set_\\L\\1(\\2)/" "$f"
sed -i~ -e "s/test_and_set_bit(DEV_FLAG_\([^,]*\), \(.*\)\.flags)/dev_test_and_set_\\L\\1(\\2)/" "$f"
sed -i~ -e "s/test_bit(DEV_FLAG_\([^,]*\), \&\(.*\)->flags)/dev_\\L\\1(\\2)/" "$f"
sed -i~ -e "s/test_bit(DEV_FLAG_\([^,]*\), \(.*\)\.flags)/dev_\\L\\1(\\2)/" "$f"
sed -i~ -e "s/set_bit(DEV_FLAG_\([^,]*\), \&\(.*\)->flags)/dev_set_\\L\\1(\\2)/" "$f"
sed -i~ -e "s/set_bit(DEV_FLAG_\([^,]*\), \(.*\)\.flags)/dev_set_\\L\\1(\\2)/" "$f"
sed -i~ -e "s/clear_bit(DEV_FLAG_\([^,]*\), \&\(.*\)->flags)/dev_clear_\\L\\1(\\2)/" "$f"
sed -i~ -e "s/clear_bit(DEV_FLAG_\([^,]*\), \(.*\)\.flags)/dev_clear_\\L\\1(\\2)/" "$f"
sed -i~ -e "s/assign_bit(DEV_FLAG_\([^,]*\), \&\(.*\)->flags, \(.*\))/dev_assign_\\L\\1(\\2, \\3)/" "$f"
sed -i~ -e "s/assign_bit(DEV_FLAG_\([^,]*\), \(.*\)\.flags, \(.*\))/dev_assign_\\L\\1(\\2, \\3)/" "$f"
done
...and then did a few manual touchups for spacing.
NOTE: one potentially "controversial" choice I made in some patches
was to always reserve a flag ID even if a flag is only used under
certain CONFIG_ settings. This is a change from how things were
before. Keeping the numbering consistent and allowing easy
compile-testing of both CONFIG settings seemed worth it, especially
since it won't take up any extra space until we've added a lot more
flags.
I only marked the first patch as a "Fix" since it is the only one
fixing observed problems. Other patches could be considered fixes too
if folks want.
I tested the first patch in the series backported to kernel 6.6 on the
Pixel phone that was experiencing the race. I added extra printouts to
make sure that the problem was hitting / addressed. The rest of the
patches are tested with allmodconfig with arm32, arm64, ppc, and
x86. I boot tested on an arm64 Chromebook running mainline.
Changes in v4:
- Use accessor functions for flags
Changes in v3:
- Use a new "flags" bitfield
- Add missing \n in probe error message
Changes in v2:
- Instead of adjusting the ordering, use "ready_to_probe" flag
Douglas Anderson (9):
driver core: Don't let a device probe until it's ready
driver core: Replace dev->can_match with dev_can_match()
driver core: Replace dev->dma_iommu with dev_dma_iommu()
driver core: Replace dev->dma_skip_sync with dev_dma_skip_sync()
driver core: Replace dev->dma_ops_bypass with dev_dma_ops_bypass()
driver core: Replace dev->state_synced with dev_state_synced()
driver core: Replace dev->dma_coherent with dev_dma_coherent()
driver core: Replace dev->of_node_reused with dev_of_node_reused()
driver core: Replace dev->offline + ->offline_disabled with accessors
arch/arc/mm/dma.c | 4 +-
arch/arm/mach-highbank/highbank.c | 2 +-
arch/arm/mach-mvebu/coherency.c | 2 +-
arch/arm/mm/dma-mapping-nommu.c | 4 +-
arch/arm/mm/dma-mapping.c | 28 ++--
arch/arm64/kernel/cpufeature.c | 2 +-
arch/arm64/mm/dma-mapping.c | 2 +-
arch/mips/mm/dma-noncoherent.c | 2 +-
arch/powerpc/kernel/dma-iommu.c | 8 +-
.../platforms/pseries/hotplug-memory.c | 4 +-
arch/riscv/mm/dma-noncoherent.c | 2 +-
drivers/acpi/scan.c | 2 +-
drivers/base/core.c | 53 +++++---
drivers/base/cpu.c | 4 +-
drivers/base/dd.c | 28 ++--
drivers/base/memory.c | 2 +-
drivers/base/pinctrl.c | 2 +-
drivers/base/platform.c | 2 +-
drivers/dma/ti/k3-udma-glue.c | 6 +-
drivers/dma/ti/k3-udma.c | 6 +-
drivers/iommu/dma-iommu.c | 9 +-
drivers/iommu/iommu.c | 5 +-
drivers/net/pcs/pcs-xpcs-plat.c | 2 +-
drivers/of/device.c | 6 +-
drivers/pci/of.c | 2 +-
drivers/pci/pwrctrl/core.c | 2 +-
drivers/regulator/bq257xx-regulator.c | 2 +-
drivers/regulator/rk808-regulator.c | 2 +-
drivers/tty/serial/serial_base_bus.c | 2 +-
drivers/usb/gadget/udc/aspeed-vhub/dev.c | 2 +-
include/linux/device.h | 120 ++++++++++++------
include/linux/dma-map-ops.h | 6 +-
include/linux/dma-mapping.h | 2 +-
include/linux/iommu-dma.h | 3 +-
kernel/cpu.c | 4 +-
kernel/dma/mapping.c | 12 +-
mm/hmm.c | 2 +-
37 files changed, 206 insertions(+), 142 deletions(-)
--
2.53.0.1213.gd9a14994de-goog
^ permalink raw reply
* Re: [moderation] KCSAN: data-race in n_tty_flush_buffer / n_tty_lookahead_flow_ctrl (9)
From: syzbot @ 2026-04-03 13:20 UTC (permalink / raw)
To: andy.shevchenko, gregkh, ilpo.jarvinen, jirislaby, linux-kernel,
linux-serial, osama.abdelkader, syzkaller-upstream-moderation
In-Reply-To: <6985ea97.050a0220.3b3015.003e.GAE@google.com>
Auto-closing this bug as obsolete.
Crashes did not happen for a while, no reproducer and no activity.
^ permalink raw reply
* Re: [PATCH v3 8/9] driver core: Replace dev->of_node_reused with DEV_FLAG_OF_NODE_REUSED
From: Mark Brown @ 2026-04-03 11:56 UTC (permalink / raw)
To: Douglas Anderson
Cc: Greg Kroah-Hartman, Rafael J . Wysocki, Danilo Krummrich,
Alan Stern, Robin Murphy, Leon Romanovsky, Paul Burton,
Saravana Kannan, Alexander Lobakin, Eric Dumazet, Toshi Kani,
Christoph Hellwig, Alexey Kardashevskiy, Johan Hovold,
alexander.stein, andrew, andrew, andriy.shevchenko, astewart,
bhelgaas, brgl, davem, devicetree, driver-core, hkallweit1,
jirislaby, joel, kees, kuba, lgirdwood, linux-arm-kernel,
linux-aspeed, linux-kernel, linux-pci, linux-serial, linux-usb,
linux, mani, netdev, pabeni, robh
In-Reply-To: <20260402174925.v3.8.I806b8636cd3724f6cd1f5e199318ab8694472d90@changeid>
[-- Attachment #1: Type: text/plain, Size: 282 bytes --]
On Thu, Apr 02, 2026 at 05:49:54PM -0700, Douglas Anderson wrote:
> In C, bitfields are not necessarily safe to modify from multiple
> threads without locking. Switch "of_node_reused" over to the "flags"
> field so modifications are safe.
Acked-by: Mark Brown <broonie@kernel.org>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* [tty:tty-testing] BUILD SUCCESS a1a81aef99e853dec84241d701fbf587d713eb5b
From: kernel test robot @ 2026-04-03 3:25 UTC (permalink / raw)
To: Greg Kroah-Hartman; +Cc: linux-serial
tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tty-testing
branch HEAD: a1a81aef99e853dec84241d701fbf587d713eb5b tty: serial: ip22zilog: Fix section mispatch warning
elapsed time: 735m
configs tested: 170
configs skipped: 2
The following configs have been built successfully.
More configs may be tested in the coming days.
tested configs:
alpha allnoconfig gcc-15.2.0
alpha allyesconfig gcc-15.2.0
alpha defconfig gcc-15.2.0
arc allmodconfig clang-16
arc allnoconfig gcc-15.2.0
arc allyesconfig clang-23
arc defconfig gcc-15.2.0
arc randconfig-001-20260403 gcc-10.5.0
arc randconfig-002-20260403 gcc-10.5.0
arm allnoconfig gcc-15.2.0
arm allyesconfig clang-16
arm defconfig gcc-15.2.0
arm orion5x_defconfig clang-23
arm randconfig-001-20260403 gcc-10.5.0
arm randconfig-002-20260403 gcc-10.5.0
arm randconfig-003-20260403 gcc-10.5.0
arm randconfig-004-20260403 gcc-10.5.0
arm64 allmodconfig clang-23
arm64 allnoconfig gcc-15.2.0
arm64 defconfig gcc-15.2.0
arm64 randconfig-001-20260403 gcc-13.4.0
arm64 randconfig-002-20260403 gcc-13.4.0
arm64 randconfig-003-20260403 gcc-13.4.0
arm64 randconfig-004-20260403 gcc-13.4.0
csky allmodconfig gcc-15.2.0
csky allnoconfig gcc-15.2.0
csky defconfig gcc-15.2.0
csky randconfig-001-20260403 gcc-13.4.0
csky randconfig-002-20260403 gcc-13.4.0
hexagon allmodconfig gcc-15.2.0
hexagon allnoconfig gcc-15.2.0
hexagon defconfig gcc-15.2.0
hexagon randconfig-001-20260403 clang-23
hexagon randconfig-002-20260403 clang-23
i386 allmodconfig clang-20
i386 allnoconfig gcc-15.2.0
i386 allyesconfig clang-20
i386 buildonly-randconfig-001-20260403 gcc-14
i386 buildonly-randconfig-002-20260403 gcc-14
i386 buildonly-randconfig-003-20260403 gcc-14
i386 buildonly-randconfig-004-20260403 gcc-14
i386 buildonly-randconfig-005-20260403 gcc-14
i386 buildonly-randconfig-006-20260403 gcc-14
i386 defconfig gcc-15.2.0
i386 randconfig-001-20260403 gcc-14
i386 randconfig-002-20260403 gcc-14
i386 randconfig-003-20260403 gcc-14
i386 randconfig-004-20260403 gcc-14
i386 randconfig-005-20260403 gcc-14
i386 randconfig-006-20260403 gcc-14
i386 randconfig-007-20260403 gcc-14
i386 randconfig-011-20260403 clang-20
i386 randconfig-012-20260403 clang-20
i386 randconfig-013-20260403 clang-20
i386 randconfig-014-20260403 clang-20
i386 randconfig-015-20260403 clang-20
i386 randconfig-016-20260403 clang-20
i386 randconfig-017-20260403 clang-20
loongarch allmodconfig clang-23
loongarch allnoconfig gcc-15.2.0
loongarch defconfig clang-19
loongarch randconfig-001-20260403 clang-23
loongarch randconfig-002-20260403 clang-23
m68k allmodconfig gcc-15.2.0
m68k allnoconfig gcc-15.2.0
m68k allyesconfig clang-16
m68k defconfig clang-19
microblaze allnoconfig gcc-15.2.0
microblaze allyesconfig gcc-15.2.0
microblaze defconfig clang-19
mips allmodconfig gcc-15.2.0
mips allnoconfig gcc-15.2.0
mips allyesconfig gcc-15.2.0
nios2 allmodconfig clang-23
nios2 allnoconfig clang-23
nios2 defconfig clang-19
nios2 randconfig-001-20260403 clang-23
nios2 randconfig-002-20260403 clang-23
openrisc allmodconfig clang-23
openrisc allnoconfig clang-23
openrisc defconfig gcc-15.2.0
parisc allmodconfig gcc-15.2.0
parisc allnoconfig clang-23
parisc allyesconfig clang-19
parisc defconfig gcc-15.2.0
parisc randconfig-001-20260403 gcc-10.5.0
parisc randconfig-002-20260403 gcc-10.5.0
parisc64 defconfig clang-19
powerpc allmodconfig gcc-15.2.0
powerpc allnoconfig clang-23
powerpc randconfig-001-20260403 gcc-10.5.0
powerpc randconfig-002-20260403 gcc-10.5.0
powerpc tqm5200_defconfig gcc-15.2.0
powerpc64 randconfig-001-20260403 gcc-10.5.0
powerpc64 randconfig-002-20260403 gcc-10.5.0
riscv allmodconfig clang-23
riscv allnoconfig clang-23
riscv allyesconfig clang-16
riscv defconfig gcc-15.2.0
riscv randconfig-001-20260403 clang-23
riscv randconfig-002-20260403 clang-23
s390 allmodconfig clang-19
s390 allnoconfig clang-23
s390 allyesconfig gcc-15.2.0
s390 defconfig gcc-15.2.0
s390 randconfig-001-20260403 clang-23
s390 randconfig-002-20260403 clang-23
sh allmodconfig gcc-15.2.0
sh allnoconfig clang-23
sh allyesconfig clang-19
sh defconfig gcc-14
sh magicpanelr2_defconfig gcc-15.2.0
sh randconfig-001-20260403 clang-23
sh randconfig-002-20260403 clang-23
sparc allnoconfig clang-23
sparc defconfig gcc-15.2.0
sparc randconfig-001-20260403 clang-20
sparc randconfig-002-20260403 clang-20
sparc64 allmodconfig clang-23
sparc64 defconfig gcc-14
sparc64 randconfig-001-20260403 clang-20
sparc64 randconfig-002-20260403 clang-20
um allmodconfig clang-19
um allnoconfig clang-23
um allyesconfig gcc-15.2.0
um defconfig gcc-14
um i386_defconfig gcc-14
um randconfig-001-20260403 clang-20
um randconfig-002-20260403 clang-20
um x86_64_defconfig gcc-14
x86_64 allmodconfig clang-20
x86_64 allnoconfig clang-23
x86_64 allyesconfig clang-20
x86_64 buildonly-randconfig-001-20260403 clang-20
x86_64 buildonly-randconfig-002-20260403 clang-20
x86_64 buildonly-randconfig-003-20260403 clang-20
x86_64 buildonly-randconfig-004-20260403 clang-20
x86_64 buildonly-randconfig-005-20260403 clang-20
x86_64 buildonly-randconfig-006-20260403 clang-20
x86_64 defconfig gcc-14
x86_64 kexec clang-20
x86_64 randconfig-001-20260403 clang-20
x86_64 randconfig-002-20260403 clang-20
x86_64 randconfig-003-20260403 clang-20
x86_64 randconfig-004-20260403 clang-20
x86_64 randconfig-005-20260403 clang-20
x86_64 randconfig-006-20260403 clang-20
x86_64 randconfig-011-20260403 gcc-14
x86_64 randconfig-012-20260403 gcc-14
x86_64 randconfig-013-20260403 gcc-14
x86_64 randconfig-014-20260403 gcc-14
x86_64 randconfig-015-20260403 gcc-14
x86_64 randconfig-016-20260403 gcc-14
x86_64 randconfig-071-20260403 gcc-14
x86_64 randconfig-072-20260403 gcc-14
x86_64 randconfig-073-20260403 gcc-14
x86_64 randconfig-074-20260403 gcc-14
x86_64 randconfig-075-20260403 gcc-14
x86_64 randconfig-076-20260403 gcc-14
x86_64 rhel-9.4 clang-20
x86_64 rhel-9.4-bpf gcc-14
x86_64 rhel-9.4-func clang-20
x86_64 rhel-9.4-kselftests clang-20
x86_64 rhel-9.4-kunit gcc-14
x86_64 rhel-9.4-ltp gcc-14
x86_64 rhel-9.4-rust clang-20
xtensa allnoconfig clang-23
xtensa allyesconfig clang-23
xtensa randconfig-001-20260403 clang-20
xtensa randconfig-002-20260403 clang-20
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox