From 174657478cd8425288aeabf93b964b9387e096fa Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:15 +0100 Subject: [PATCH 001/199] vgacon: inline vc_scrolldelta_helper() into vgacon_scrolldelta() Since commit 74d58cd48a8f ("USB: sisusbvga: remove console support"), vgacon_scrolldelta() is the only user of vc_scrolldelta_helper(). Inline the helper into vgacon_scrolldelta() and drop it. Signed-off-by: "Jiri Slaby (SUSE)" Cc: Helge Deller Cc: linux-fbdev@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-2-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 40 ---------------------------------- drivers/video/console/vgacon.c | 36 ++++++++++++++++++++++++++++-- include/linux/vt_kern.h | 3 --- 3 files changed, 34 insertions(+), 45 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 156efda7c80d..3f3f7c216819 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -4748,43 +4748,3 @@ void vcs_scr_updated(struct vc_data *vc) { notify_update(vc); } - -void vc_scrolldelta_helper(struct vc_data *c, int lines, - unsigned int rolled_over, void *base, unsigned int size) -{ - unsigned long ubase = (unsigned long)base; - ptrdiff_t scr_end = (void *)c->vc_scr_end - base; - ptrdiff_t vorigin = (void *)c->vc_visible_origin - base; - ptrdiff_t origin = (void *)c->vc_origin - base; - int margin = c->vc_size_row * 4; - int from, wrap, from_off, avail; - - /* Turn scrollback off */ - if (!lines) { - c->vc_visible_origin = c->vc_origin; - return; - } - - /* Do we have already enough to allow jumping from 0 to the end? */ - if (rolled_over > scr_end + margin) { - from = scr_end; - wrap = rolled_over + c->vc_size_row; - } else { - from = 0; - wrap = size; - } - - from_off = (vorigin - from + wrap) % wrap + lines * c->vc_size_row; - avail = (origin - from + wrap) % wrap; - - /* Only a little piece would be left? Show all incl. the piece! */ - if (avail < 2 * margin) - margin = 0; - if (from_off < margin) - from_off = 0; - if (from_off > avail - margin) - from_off = avail; - - c->vc_visible_origin = ubase + (from + from_off) % wrap; -} -EXPORT_SYMBOL_GPL(vc_scrolldelta_helper); diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 8ef1579fa57f..9176fff9ce6e 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -138,8 +138,40 @@ static inline void vga_set_mem_top(struct vc_data *c) static void vgacon_scrolldelta(struct vc_data *c, int lines) { - vc_scrolldelta_helper(c, lines, vga_rolled_over, (void *)vga_vram_base, - vga_vram_size); + unsigned long scr_end = c->vc_scr_end - vga_vram_base; + unsigned long vorigin = c->vc_visible_origin - vga_vram_base; + unsigned long origin = c->vc_origin - vga_vram_base; + int margin = c->vc_size_row * 4; + int from, wrap, from_off, avail; + + /* Turn scrollback off */ + if (!lines) { + c->vc_visible_origin = c->vc_origin; + return; + } + + /* Do we have already enough to allow jumping from 0 to the end? */ + if (vga_rolled_over > scr_end + margin) { + from = scr_end; + wrap = vga_rolled_over + c->vc_size_row; + } else { + from = 0; + wrap = vga_vram_size; + } + + from_off = (vorigin - from + wrap) % wrap + lines * c->vc_size_row; + avail = (origin - from + wrap) % wrap; + + /* Only a little piece would be left? Show all incl. the piece! */ + if (avail < 2 * margin) + margin = 0; + if (from_off < margin) + from_off = 0; + if (from_off > avail - margin) + from_off = avail; + + c->vc_visible_origin = vga_vram_base + (from + from_off) % wrap; + vga_set_mem_top(c); } diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h index c1f5aebef170..a789ea3ed2a0 100644 --- a/include/linux/vt_kern.h +++ b/include/linux/vt_kern.h @@ -168,7 +168,4 @@ void vt_set_led_state(unsigned int console, int leds); void vt_kbd_con_start(unsigned int console); void vt_kbd_con_stop(unsigned int console); -void vc_scrolldelta_helper(struct vc_data *c, int lines, - unsigned int rolled_over, void *_base, unsigned int size); - #endif /* _VT_KERN_H */ From b041c60590ddb891e361468494c5f6d10305d893 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:16 +0100 Subject: [PATCH 002/199] fbcon: make display_desc a static array in fbcon_startup() display_desc is a pointer to a RO string. Instead, switch display_desc to a static array as we are used to. It BTW saves unnecessary 8B on the stack. Signed-off-by: "Jiri Slaby (SUSE)" Cc: Daniel Vetter Cc: Helge Deller Cc: linux-fbdev@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-3-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/video/fbdev/core/fbcon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index 63af6ab034b5..a8c32cb4c878 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -921,7 +921,7 @@ static void display_to_var(struct fb_var_screeninfo *var, static const char *fbcon_startup(void) { - const char *display_desc = "frame buffer device"; + static const char display_desc[] = "frame buffer device"; struct fbcon_display *p = &fb_display[fg_console]; struct vc_data *vc = vc_cons[fg_console].d; const struct font_desc *font = NULL; From 0e6a92f67c8a94707f7bb27ac29e2bdf3e7c167d Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:17 +0100 Subject: [PATCH 003/199] tty: vt: fix 20 vs 0x20 typo in EScsiignore The if (c >= 20 && c <= 0x3f) test added in commit 7a99565f8732 is wrong. 20 is DC4 in ascii and it makes no sense to consider that as the bottom limit. Instead, it should be 0x20 as in the other test in the commit above. This is supposed to NOT change anything as we handle interesting 20-0x20 asciis far before this if. So for sakeness, change to 0x20 (which is SPACE). Signed-off-by: "Jiri Slaby (SUSE)" Fixes: 7a99565f8732 ("vt: ignore csi sequences with intermediate characters.") Cc: Martin Hostettler Link: https://lore.kernel.org/all/ZaP45QY2WEsDqoxg@neutronstar.dyndns.org/ Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-4-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 3f3f7c216819..55ce6cdecbca 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2469,7 +2469,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) } return; case EScsiignore: - if (c >= 20 && c <= 0x3f) + if (c >= 0x20 && c <= 0x3f) return; vc->vc_state = ESnormal; return; From b3dd9bef75b626cebc3b4720df3c5c010d6a29aa Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:18 +0100 Subject: [PATCH 004/199] tty: vt: expect valid vc when in tty ops At least since commits feebed6515a1 ("tty: shutdown method") and bc1e99d93f09 ("TTY: vt, add ->install"), tty->driver_data in vc is expected to be set since tty_operations::install() till ::cleanup(). So the checks of !tty->driver_data (aka !vc) in: * vc_do_resize() by tty -> ioctl(TIOCSWINSZ) -> vt_resize() * do_con_write() by tty -> tty_operations::write()/::put_char() * con_flush_chars() by tty -> ::flush_chars() are all superfluous. And also, holding a console lock is not needed to fetch tty->driver_data. Note there is even a stale comment in con_flush_chars() about a race between that and con_close(). But con_close() does not set tty->driver_data to NULL for years already. Drop all these in a hope I am not terribly mistaken. Signed-off-by: "Jiri Slaby (SUSE)" Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-5-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 55ce6cdecbca..e131edea00da 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1154,9 +1154,6 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, WARN_CONSOLE_UNLOCKED(); - if (!vc) - return -ENXIO; - user = vc->vc_resize_user; vc->vc_resize_user = 0; @@ -2852,7 +2849,7 @@ static int do_con_write(struct tty_struct *tty, const u8 *buf, int count) }; int c, tc, n = 0; unsigned int currcons; - struct vc_data *vc; + struct vc_data *vc = tty->driver_data; struct vt_notifier_param param; bool rescan; @@ -2860,13 +2857,6 @@ static int do_con_write(struct tty_struct *tty, const u8 *buf, int count) return count; console_lock(); - vc = tty->driver_data; - if (vc == NULL) { - pr_err("vt: argh, driver_data is NULL !\n"); - console_unlock(); - return 0; - } - currcons = vc->vc_num; if (!vc_cons_allocated(currcons)) { /* could this happen? */ @@ -3312,16 +3302,13 @@ static void con_start(struct tty_struct *tty) static void con_flush_chars(struct tty_struct *tty) { - struct vc_data *vc; + struct vc_data *vc = tty->driver_data; if (in_interrupt()) /* from flush_to_ldisc */ return; - /* if we race with con_close(), vt may be null */ console_lock(); - vc = tty->driver_data; - if (vc) - set_cursor(vc); + set_cursor(vc); console_unlock(); } From a0b8a1681254346010edd2f94e799fb6b6568cf1 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:19 +0100 Subject: [PATCH 005/199] tty: vt: pass proper pointers from tioclinux() Pass proper types and proper pointers (the data with an offset) to the TIOCL_* handlers. So that they need not to cast or add anything to the passed pointer. This makes obvious what is passed/consumed. Signed-off-by: "Jiri Slaby (SUSE)" Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-6-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/selection.c | 8 ++++---- drivers/tty/vt/vt.c | 19 ++++++++++--------- include/linux/selection.h | 2 +- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 8967c3a0d916..e172ede235a0 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -7,7 +7,7 @@ * 'int set_selection_kernel(struct tiocl_selection *, struct tty_struct *)' * 'void clear_selection(void)' * 'int paste_selection(struct tty_struct *)' - * 'int sel_loadlut(char __user *)' + * 'int sel_loadlut(u32 __user *)' * * Now that /dev/vcs exists, most of this can disappear again. */ @@ -111,15 +111,15 @@ static inline int inword(const u32 c) /** * sel_loadlut() - load the LUT table - * @p: user table + * @lut: user table * * Load the LUT table from user space. The caller must hold the console * lock. Make a temporary copy so a partial update doesn't make a mess. */ -int sel_loadlut(char __user *p) +int sel_loadlut(u32 __user *lut) { u32 tmplut[ARRAY_SIZE(inwordLut)]; - if (copy_from_user(tmplut, (u32 __user *)(p+4), sizeof(inwordLut))) + if (copy_from_user(tmplut, lut, sizeof(inwordLut))) return -EFAULT; memcpy(inwordLut, tmplut, sizeof(inwordLut)); return 0; diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index e131edea00da..079dbff562fd 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -145,7 +145,7 @@ static void gotoxy(struct vc_data *vc, int new_x, int new_y); static void save_cur(struct vc_data *vc); static void reset_terminal(struct vc_data *vc, int do_clear); static void con_flush_chars(struct tty_struct *tty); -static int set_vesa_blanking(char __user *p); +static int set_vesa_blanking(u8 __user *mode); static void set_cursor(struct vc_data *vc); static void hide_cursor(struct vc_data *vc); static void console_callback(struct work_struct *ignored); @@ -3134,6 +3134,8 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) { char type, data; char __user *p = (char __user *)arg; + void __user *param_aligned32 = (u32 __user *)arg + 1; + void __user *param = (void __user *)arg + 1; int lines; int ret; @@ -3147,8 +3149,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) case TIOCL_SETSEL: if (!capable(CAP_SYS_ADMIN)) return -EPERM; - return set_selection_user((struct tiocl_selection - __user *)(p+1), tty); + return set_selection_user(param, tty); case TIOCL_PASTESEL: if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -3162,7 +3163,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) if (!capable(CAP_SYS_ADMIN)) return -EPERM; console_lock(); - ret = sel_loadlut(p); + ret = sel_loadlut(param_aligned32); console_unlock(); break; case TIOCL_GETSHIFTSTATE: @@ -3181,7 +3182,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) return put_user(data, p); case TIOCL_SETVESABLANK: console_lock(); - ret = set_vesa_blanking(p); + ret = set_vesa_blanking(param); console_unlock(); break; case TIOCL_GETKMSGREDIRECT: @@ -3204,7 +3205,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) */ return fg_console; case TIOCL_SCROLLCONSOLE: - if (get_user(lines, (s32 __user *)(p+4))) + if (get_user(lines, (s32 __user *)param_aligned32)) return -EFAULT; /* @@ -4262,11 +4263,11 @@ postcore_initcall(vtconsole_class_init); * Screen blanking */ -static int set_vesa_blanking(char __user *p) +static int set_vesa_blanking(u8 __user *mode_user) { - unsigned int mode; + u8 mode; - if (get_user(mode, p + 1)) + if (get_user(mode, mode_user)) return -EFAULT; vesa_blank_mode = (mode < 4) ? mode : 0; diff --git a/include/linux/selection.h b/include/linux/selection.h index 170ef28ff26b..b7cd23e56a2b 100644 --- a/include/linux/selection.h +++ b/include/linux/selection.h @@ -20,7 +20,7 @@ extern int set_selection_user(const struct tiocl_selection __user *sel, extern int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty); extern int paste_selection(struct tty_struct *tty); -extern int sel_loadlut(char __user *p); +extern int sel_loadlut(u32 __user *lut); extern int mouse_reporting(void); extern void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry); From d321cd13f6dca3c1b0e9e9735901fb5eee7a501c Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:20 +0100 Subject: [PATCH 006/199] tty: vt: push console lock from tioclinux() down to 2 functions Avoid costly user copies under the console lock. So push the lock down from tioclinux() to sel_loadlut() and set_vesa_blanking(). It is now obvious what is actually protected. Signed-off-by: "Jiri Slaby (SUSE)" Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-7-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/selection.c | 11 +++++++++-- drivers/tty/vt/vt.c | 13 +++++-------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index e172ede235a0..91d789c025c6 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -113,15 +113,22 @@ static inline int inword(const u32 c) * sel_loadlut() - load the LUT table * @lut: user table * - * Load the LUT table from user space. The caller must hold the console - * lock. Make a temporary copy so a partial update doesn't make a mess. + * Load the LUT table from user space. Make a temporary copy so a partial + * update doesn't make a mess. + * + * Locking: The console lock is acquired. */ int sel_loadlut(u32 __user *lut) { u32 tmplut[ARRAY_SIZE(inwordLut)]; + if (copy_from_user(tmplut, lut, sizeof(inwordLut))) return -EFAULT; + + console_lock(); memcpy(inwordLut, tmplut, sizeof(inwordLut)); + console_unlock(); + return 0; } diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 079dbff562fd..3a6f60ad2224 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -3162,10 +3162,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) case TIOCL_SELLOADLUT: if (!capable(CAP_SYS_ADMIN)) return -EPERM; - console_lock(); - ret = sel_loadlut(param_aligned32); - console_unlock(); - break; + return sel_loadlut(param_aligned32); case TIOCL_GETSHIFTSTATE: /* * Make it possible to react to Shift+Mousebutton. Note that @@ -3181,10 +3178,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) console_unlock(); return put_user(data, p); case TIOCL_SETVESABLANK: - console_lock(); - ret = set_vesa_blanking(param); - console_unlock(); - break; + return set_vesa_blanking(param); case TIOCL_GETKMSGREDIRECT: data = vt_get_kmsg_redirect(); return put_user(data, p); @@ -4270,7 +4264,10 @@ static int set_vesa_blanking(u8 __user *mode_user) if (get_user(mode, mode_user)) return -EFAULT; + console_lock(); vesa_blank_mode = (mode < 4) ? mode : 0; + console_unlock(); + return 0; } From beccdcfa15666c442ce79a5f963fcb34ec28084e Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:21 +0100 Subject: [PATCH 007/199] tty: vt: pass vc_resize_user as a parameter It is pretty unfortunate to set vc_data::vc_resize_user in two callers of vc_do_resize(). vc_resize_user is immediately reset there (while remembering it). So instead of this back and forth, pass 'from_user' as a parameter. Notes on 'int user': * The name changes from 'user' to 'from_user' on some places to be consistent. * The type is bool now as 'int user' might evoke user's uid or whatever. Provided vc_resize() is called on many places and they need not to care about this parameter, its prototype is kept unchanged. Instead, it is now an inline calling a new __vc_resize() which implements the above. This patch makes the situation much more obvious. Signed-off-by: "Jiri Slaby (SUSE)" Cc: Helge Deller Cc: Daniel Vetter Cc: linux-fbdev@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-8-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 28 +++++++++++++--------------- drivers/tty/vt/vt_ioctl.c | 6 ++---- drivers/video/console/vgacon.c | 4 ++-- drivers/video/fbdev/core/fbcon.c | 2 +- include/linux/console.h | 2 +- include/linux/console_struct.h | 1 - include/linux/vt_kern.h | 9 ++++++++- 7 files changed, 27 insertions(+), 25 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 3a6f60ad2224..c87837306074 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1115,13 +1115,13 @@ err_free: } static inline int resize_screen(struct vc_data *vc, int width, int height, - int user) + bool from_user) { /* Resizes the resolution of the display adapater */ int err = 0; if (vc->vc_sw->con_resize) - err = vc->vc_sw->con_resize(vc, width, height, user); + err = vc->vc_sw->con_resize(vc, width, height, from_user); return err; } @@ -1132,6 +1132,7 @@ static inline int resize_screen(struct vc_data *vc, int width, int height, * @vc: virtual console private data * @cols: columns * @lines: lines + * @from_user: invoked by a user? * * Resize a virtual console, clipping according to the actual constraints. * If the caller passes a tty structure then update the termios winsize @@ -1142,21 +1143,17 @@ static inline int resize_screen(struct vc_data *vc, int width, int height, */ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, - unsigned int cols, unsigned int lines) + unsigned int cols, unsigned int lines, bool from_user) { unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0; unsigned long end; unsigned int old_rows, old_row_size, first_copied_row; unsigned int new_cols, new_rows, new_row_size, new_screen_size; - unsigned int user; unsigned short *oldscreen, *newscreen; u32 **new_uniscr = NULL; WARN_CONSOLE_UNLOCKED(); - user = vc->vc_resize_user; - vc->vc_resize_user = 0; - if (cols > VC_MAXCOL || lines > VC_MAXROW) return -EINVAL; @@ -1182,7 +1179,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, * to deal with possible errors from the code below, we call * the resize_screen here as well. */ - return resize_screen(vc, new_cols, new_rows, user); + return resize_screen(vc, new_cols, new_rows, from_user); } if (new_screen_size > KMALLOC_MAX_SIZE || !new_screen_size) @@ -1205,7 +1202,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, old_rows = vc->vc_rows; old_row_size = vc->vc_size_row; - err = resize_screen(vc, new_cols, new_rows, user); + err = resize_screen(vc, new_cols, new_rows, from_user); if (err) { kfree(newscreen); vc_uniscr_free(new_uniscr); @@ -1292,22 +1289,23 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, } /** - * vc_resize - resize a VT + * __vc_resize - resize a VT * @vc: virtual console * @cols: columns * @rows: rows + * @from_user: invoked by a user? * * Resize a virtual console as seen from the console end of things. We * use the common vc_do_resize methods to update the structures. The * caller must hold the console sem to protect console internals and * vc->port.tty */ - -int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows) +int __vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows, + bool from_user) { - return vc_do_resize(vc->port.tty, vc, cols, rows); + return vc_do_resize(vc->port.tty, vc, cols, rows, from_user); } -EXPORT_SYMBOL(vc_resize); +EXPORT_SYMBOL(__vc_resize); /** * vt_resize - resize a VT @@ -1327,7 +1325,7 @@ static int vt_resize(struct tty_struct *tty, struct winsize *ws) int ret; console_lock(); - ret = vc_do_resize(tty, vc, ws->ws_col, ws->ws_row); + ret = vc_do_resize(tty, vc, ws->ws_col, ws->ws_row, false); console_unlock(); return ret; } diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 8c685b501404..4b91072f3a4e 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -714,8 +714,7 @@ static int vt_resizex(struct vc_data *vc, struct vt_consize __user *cs) vcp->vc_scan_lines = v.v_vlin; if (v.v_clin) vcp->vc_cell_height = v.v_clin; - vcp->vc_resize_user = 1; - ret = vc_resize(vcp, v.v_cols, v.v_rows); + ret = __vc_resize(vcp, v.v_cols, v.v_rows, true); if (ret) { vcp->vc_scan_lines = save_scan_lines; vcp->vc_cell_height = save_cell_height; @@ -923,9 +922,8 @@ int vt_ioctl(struct tty_struct *tty, vc = vc_cons[i].d; if (vc) { - vc->vc_resize_user = 1; /* FIXME: review v tty lock */ - vc_resize(vc_cons[i].d, cc, ll); + __vc_resize(vc_cons[i].d, cc, ll, true); } } console_unlock(); diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 9176fff9ce6e..0c76e2817b49 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -1081,12 +1081,12 @@ static int vgacon_font_get(struct vc_data *c, struct console_font *font, unsigne } static int vgacon_resize(struct vc_data *c, unsigned int width, - unsigned int height, unsigned int user) + unsigned int height, bool from_user) { if ((width << 1) * height > vga_vram_size) return -EINVAL; - if (user) { + if (from_user) { /* * Ho ho! Someone (svgatextmode, eh?) may have reprogrammed * the video mode! Set the new defaults then and go away. diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index a8c32cb4c878..dd2f4617485c 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -1996,7 +1996,7 @@ static void updatescrollmode(struct fbcon_display *p, #define CALC_FONTSZ(h, p, c) ((h) * (p) * (c)) /* size = height * pitch * charcount */ static int fbcon_resize(struct vc_data *vc, unsigned int width, - unsigned int height, unsigned int user) + unsigned int height, bool from_user) { struct fb_info *info = fbcon_info_from_console(vc->vc_num); struct fbcon_ops *ops = info->fbcon_par; diff --git a/include/linux/console.h b/include/linux/console.h index 779d388af8a0..38b379d6c624 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -66,7 +66,7 @@ struct consw { int (*con_font_default)(struct vc_data *vc, struct console_font *font, char *name); int (*con_resize)(struct vc_data *vc, unsigned int width, - unsigned int height, unsigned int user); + unsigned int height, bool from_user); void (*con_set_palette)(struct vc_data *vc, const unsigned char *table); void (*con_scrolldelta)(struct vc_data *vc, int lines); diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h index 539f1cd45309..20f564e98552 100644 --- a/include/linux/console_struct.h +++ b/include/linux/console_struct.h @@ -151,7 +151,6 @@ struct vc_data { DECLARE_BITMAP(vc_tab_stop, VC_TABSTOPS_COUNT); /* Tab stops. 256 columns. */ unsigned char vc_palette[16*3]; /* Colour palette for VGA+ */ unsigned short * vc_translate; - unsigned int vc_resize_user; /* resize request from user */ unsigned int vc_bell_pitch; /* Console bell pitch */ unsigned int vc_bell_duration; /* Console bell duration */ unsigned short vc_cur_blink_ms; /* Cursor blink duration */ diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h index a789ea3ed2a0..d008c3d0a9bb 100644 --- a/include/linux/vt_kern.h +++ b/include/linux/vt_kern.h @@ -25,7 +25,8 @@ extern int fg_console, last_console, want_console; int vc_allocate(unsigned int console); int vc_cons_allocated(unsigned int console); -int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines); +int __vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines, + bool from_user); struct vc_data *vc_deallocate(unsigned int console); void reset_palette(struct vc_data *vc); void do_blank_screen(int entering_gfx); @@ -42,6 +43,12 @@ void redraw_screen(struct vc_data *vc, int is_switch); #define update_screen(x) redraw_screen(x, 0) #define switch_screen(x) redraw_screen(x, 1) +static inline int vc_resize(struct vc_data *vc, unsigned int cols, + unsigned int lines) +{ + return __vc_resize(vc, cols, lines, false); +} + struct tty_struct; int tioclinux(struct tty_struct *tty, unsigned long arg); From d4c0c481e49fdf483c43e13e4a419ea19c045023 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:22 +0100 Subject: [PATCH 008/199] tty: vt: make vc_is_sel()'s vc const It's only an aid to people reading the header and/or calling vc_is_sel(). vc is only tested there, so having it const makes sense. Signed-off-by: "Jiri Slaby (SUSE)" Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-9-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/selection.c | 2 +- include/linux/selection.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 91d789c025c6..34ee09f5a8f4 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -88,7 +88,7 @@ void clear_selection(void) } EXPORT_SYMBOL_GPL(clear_selection); -bool vc_is_sel(struct vc_data *vc) +bool vc_is_sel(const struct vc_data *vc) { return vc == vc_sel.cons; } diff --git a/include/linux/selection.h b/include/linux/selection.h index b7cd23e56a2b..533509f6ba4f 100644 --- a/include/linux/selection.h +++ b/include/linux/selection.h @@ -24,7 +24,7 @@ extern int sel_loadlut(u32 __user *lut); extern int mouse_reporting(void); extern void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry); -bool vc_is_sel(struct vc_data *vc); +bool vc_is_sel(const struct vc_data *vc); extern int console_blanked; From 09e7f9f6c576bc5d7cc71c007379ca876db8c858 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:23 +0100 Subject: [PATCH 009/199] tty: vt: define an enum for CSI+m codes It's always confusing to read all those case 0:, case 1: etc. in csi_* handlers. Define enum entries for all those constants in CSI+m and use them in csi_m(). Signed-off-by: "Jiri Slaby (SUSE)" Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-10-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 98 +++++++++++++++++++++++++++++++-------------- 1 file changed, 69 insertions(+), 29 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index c87837306074..b2ba1b943eb6 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1676,6 +1676,39 @@ static int vc_t416_color(struct vc_data *vc, int i, return i; } +enum { + CSI_m_DEFAULT = 0, + CSI_m_BOLD = 1, + CSI_m_HALF_BRIGHT = 2, + CSI_m_ITALIC = 3, + CSI_m_UNDERLINE = 4, + CSI_m_BLINK = 5, + CSI_m_REVERSE = 7, + CSI_m_PRI_FONT = 10, + CSI_m_ALT_FONT1 = 11, + CSI_m_ALT_FONT2 = 12, + CSI_m_DOUBLE_UNDERLINE = 21, + CSI_m_NORMAL_INTENSITY = 22, + CSI_m_NO_ITALIC = 23, + CSI_m_NO_UNDERLINE = 24, + CSI_m_NO_BLINK = 25, + CSI_m_NO_REVERSE = 27, + CSI_m_FG_COLOR_BEG = 30, + CSI_m_FG_COLOR_END = 37, + CSI_m_FG_COLOR = 38, + CSI_m_DEFAULT_FG_COLOR = 39, + CSI_m_BG_COLOR_BEG = 40, + CSI_m_BG_COLOR_END = 47, + CSI_m_BG_COLOR = 48, + CSI_m_DEFAULT_BG_COLOR = 49, + CSI_m_BRIGHT_FG_COLOR_BEG = 90, + CSI_m_BRIGHT_FG_COLOR_END = 97, + CSI_m_BRIGHT_FG_COLOR_OFF = CSI_m_BRIGHT_FG_COLOR_BEG - CSI_m_FG_COLOR_BEG, + CSI_m_BRIGHT_BG_COLOR_BEG = 100, + CSI_m_BRIGHT_BG_COLOR_END = 107, + CSI_m_BRIGHT_BG_COLOR_OFF = CSI_m_BRIGHT_BG_COLOR_BEG - CSI_m_BG_COLOR_BEG, +}; + /* console_lock is held */ static void csi_m(struct vc_data *vc) { @@ -1683,33 +1716,33 @@ static void csi_m(struct vc_data *vc) for (i = 0; i <= vc->vc_npar; i++) switch (vc->vc_par[i]) { - case 0: /* all attributes off */ + case CSI_m_DEFAULT: /* all attributes off */ default_attr(vc); break; - case 1: + case CSI_m_BOLD: vc->state.intensity = VCI_BOLD; break; - case 2: + case CSI_m_HALF_BRIGHT: vc->state.intensity = VCI_HALF_BRIGHT; break; - case 3: + case CSI_m_ITALIC: vc->state.italic = true; break; - case 21: + case CSI_m_DOUBLE_UNDERLINE: /* * No console drivers support double underline, so * convert it to a single underline. */ - case 4: + case CSI_m_UNDERLINE: vc->state.underline = true; break; - case 5: + case CSI_m_BLINK: vc->state.blink = true; break; - case 7: + case CSI_m_REVERSE: vc->state.reverse = true; break; - case 10: /* ANSI X3.64-1979 (SCO-ish?) + case CSI_m_PRI_FONT: /* ANSI X3.64-1979 (SCO-ish?) * Select primary font, don't display control chars if * defined, don't set bit 8 on output. */ @@ -1717,7 +1750,7 @@ static void csi_m(struct vc_data *vc) vc->vc_disp_ctrl = 0; vc->vc_toggle_meta = 0; break; - case 11: /* ANSI X3.64-1979 (SCO-ish?) + case CSI_m_ALT_FONT1: /* ANSI X3.64-1979 (SCO-ish?) * Select first alternate font, lets chars < 32 be * displayed as ROM chars. */ @@ -1725,7 +1758,7 @@ static void csi_m(struct vc_data *vc) vc->vc_disp_ctrl = 1; vc->vc_toggle_meta = 0; break; - case 12: /* ANSI X3.64-1979 (SCO-ish?) + case CSI_m_ALT_FONT2: /* ANSI X3.64-1979 (SCO-ish?) * Select second alternate font, toggle high bit * before displaying as ROM char. */ @@ -1733,47 +1766,54 @@ static void csi_m(struct vc_data *vc) vc->vc_disp_ctrl = 1; vc->vc_toggle_meta = 1; break; - case 22: + case CSI_m_NORMAL_INTENSITY: vc->state.intensity = VCI_NORMAL; break; - case 23: + case CSI_m_NO_ITALIC: vc->state.italic = false; break; - case 24: + case CSI_m_NO_UNDERLINE: vc->state.underline = false; break; - case 25: + case CSI_m_NO_BLINK: vc->state.blink = false; break; - case 27: + case CSI_m_NO_REVERSE: vc->state.reverse = false; break; - case 38: + case CSI_m_FG_COLOR: i = vc_t416_color(vc, i, rgb_foreground); break; - case 48: + case CSI_m_BG_COLOR: i = vc_t416_color(vc, i, rgb_background); break; - case 39: + case CSI_m_DEFAULT_FG_COLOR: vc->state.color = (vc->vc_def_color & 0x0f) | (vc->state.color & 0xf0); break; - case 49: + case CSI_m_DEFAULT_BG_COLOR: vc->state.color = (vc->vc_def_color & 0xf0) | (vc->state.color & 0x0f); break; default: - if (vc->vc_par[i] >= 90 && vc->vc_par[i] <= 107) { - if (vc->vc_par[i] < 100) + if (vc->vc_par[i] >= CSI_m_BRIGHT_FG_COLOR_BEG && + vc->vc_par[i] <= CSI_m_BRIGHT_BG_COLOR_END) { + if (vc->vc_par[i] < CSI_m_BRIGHT_BG_COLOR_BEG) vc->state.intensity = VCI_BOLD; - vc->vc_par[i] -= 60; + vc->vc_par[i] -= CSI_m_BRIGHT_FG_COLOR_OFF; } - if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37) - vc->state.color = color_table[vc->vc_par[i] - 30] - | (vc->state.color & 0xf0); - else if (vc->vc_par[i] >= 40 && vc->vc_par[i] <= 47) - vc->state.color = (color_table[vc->vc_par[i] - 40] << 4) - | (vc->state.color & 0x0f); + if (vc->vc_par[i] >= CSI_m_FG_COLOR_BEG && + vc->vc_par[i] <= CSI_m_FG_COLOR_END) { + vc->vc_par[i] -= CSI_m_FG_COLOR_BEG; + vc->state.color = color_table[vc->vc_par[i]] | + (vc->state.color & 0xf0); + } else if (vc->vc_par[i] >= CSI_m_BG_COLOR_BEG && + vc->vc_par[i] <= CSI_m_BG_COLOR_END) { + vc->vc_par[i] -= CSI_m_BG_COLOR_BEG; + vc->state.color = (color_table[vc->vc_par[i]] << 4) | + (vc->state.color & 0x0f); + } + break; } update_attr(vc); From 76ec3a7a51ea3bfcb57a2e736468fdd621c7c396 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:24 +0100 Subject: [PATCH 010/199] tty: vt: use case ranges for CSI+m fg/bg colors Replacing the default case with the iffery by case ranges makes the code more understandable at last. Signed-off-by: "Jiri Slaby (SUSE)" Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-11-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index b2ba1b943eb6..66ebc90a9fe9 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1795,25 +1795,22 @@ static void csi_m(struct vc_data *vc) vc->state.color = (vc->vc_def_color & 0xf0) | (vc->state.color & 0x0f); break; - default: - if (vc->vc_par[i] >= CSI_m_BRIGHT_FG_COLOR_BEG && - vc->vc_par[i] <= CSI_m_BRIGHT_BG_COLOR_END) { - if (vc->vc_par[i] < CSI_m_BRIGHT_BG_COLOR_BEG) - vc->state.intensity = VCI_BOLD; - vc->vc_par[i] -= CSI_m_BRIGHT_FG_COLOR_OFF; - } - if (vc->vc_par[i] >= CSI_m_FG_COLOR_BEG && - vc->vc_par[i] <= CSI_m_FG_COLOR_END) { - vc->vc_par[i] -= CSI_m_FG_COLOR_BEG; - vc->state.color = color_table[vc->vc_par[i]] | - (vc->state.color & 0xf0); - } else if (vc->vc_par[i] >= CSI_m_BG_COLOR_BEG && - vc->vc_par[i] <= CSI_m_BG_COLOR_END) { - vc->vc_par[i] -= CSI_m_BG_COLOR_BEG; - vc->state.color = (color_table[vc->vc_par[i]] << 4) | - (vc->state.color & 0x0f); - } - + case CSI_m_BRIGHT_FG_COLOR_BEG ... CSI_m_BRIGHT_FG_COLOR_END: + vc->state.intensity = VCI_BOLD; + vc->vc_par[i] -= CSI_m_BRIGHT_FG_COLOR_OFF; + fallthrough; + case CSI_m_FG_COLOR_BEG ... CSI_m_FG_COLOR_END: + vc->vc_par[i] -= CSI_m_FG_COLOR_BEG; + vc->state.color = color_table[vc->vc_par[i]] | + (vc->state.color & 0xf0); + break; + case CSI_m_BRIGHT_BG_COLOR_BEG ... CSI_m_BRIGHT_BG_COLOR_END: + vc->vc_par[i] -= CSI_m_BRIGHT_BG_COLOR_OFF; + fallthrough; + case CSI_m_BG_COLOR_BEG ... CSI_m_BG_COLOR_END: + vc->vc_par[i] -= CSI_m_BG_COLOR_BEG; + vc->state.color = (color_table[vc->vc_par[i]] << 4) | + (vc->state.color & 0x0f); break; } update_attr(vc); From 4b8f936185bd0ed319cc0dcedc7ef68cfaed04d3 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:25 +0100 Subject: [PATCH 011/199] tty: vt: define an enum for CSI+J codes Decrypt the constant values by proper enum names. This time in csi_J(). Signed-off-by: "Jiri Slaby (SUSE)" Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-12-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 66ebc90a9fe9..85e89fb9b207 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1498,13 +1498,20 @@ static inline void del(struct vc_data *vc) /* ignored */ } -static void csi_J(struct vc_data *vc, int vpar) +enum CSI_J { + CSI_J_CURSOR_TO_END = 0, + CSI_J_START_TO_CURSOR = 1, + CSI_J_VISIBLE = 2, + CSI_J_FULL = 3, +}; + +static void csi_J(struct vc_data *vc, enum CSI_J vpar) { unsigned int count; unsigned short * start; switch (vpar) { - case 0: /* erase from cursor to end of display */ + case CSI_J_CURSOR_TO_END: vc_uniscr_clear_line(vc, vc->state.x, vc->vc_cols - vc->state.x); vc_uniscr_clear_lines(vc, vc->state.y + 1, @@ -1512,16 +1519,16 @@ static void csi_J(struct vc_data *vc, int vpar) count = (vc->vc_scr_end - vc->vc_pos) >> 1; start = (unsigned short *)vc->vc_pos; break; - case 1: /* erase from start to cursor */ + case CSI_J_START_TO_CURSOR: vc_uniscr_clear_line(vc, 0, vc->state.x + 1); vc_uniscr_clear_lines(vc, 0, vc->state.y); count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1; start = (unsigned short *)vc->vc_origin; break; - case 3: /* include scrollback */ + case CSI_J_FULL: flush_scrollback(vc); fallthrough; - case 2: /* erase whole display */ + case CSI_J_VISIBLE: vc_uniscr_clear_lines(vc, 0, vc->vc_rows); count = vc->vc_cols * vc->vc_rows; start = (unsigned short *)vc->vc_origin; @@ -2110,7 +2117,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear) gotoxy(vc, 0, 0); save_cur(vc); if (do_clear) - csi_J(vc, 2); + csi_J(vc, CSI_J_VISIBLE); } static void vc_setGx(struct vc_data *vc, unsigned int which, int c) @@ -2526,7 +2533,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) /* DEC screen alignment test. kludge :-) */ vc->vc_video_erase_char = (vc->vc_video_erase_char & 0xff00) | 'E'; - csi_J(vc, 2); + csi_J(vc, CSI_J_VISIBLE); vc->vc_video_erase_char = (vc->vc_video_erase_char & 0xff00) | ' '; do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2); @@ -3498,7 +3505,7 @@ static int __init con_init(void) set_origin(vc); save_screen(vc); gotoxy(vc, vc->state.x, vc->state.y); - csi_J(vc, 0); + csi_J(vc, CSI_J_CURSOR_TO_END); update_screen(vc); pr_info("Console: %s %s %dx%d\n", vc->vc_can_do_color ? "colour" : "mono", From fe4f6beb59a95a051c226e70fafe87b3de9dd0d0 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:26 +0100 Subject: [PATCH 012/199] tty: vt: reflow csi_J() Push cases one level left, according to coding style. And reorder local variables. Signed-off-by: "Jiri Slaby (SUSE)" Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-13-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 50 ++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 85e89fb9b207..bf77d962eeb4 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1507,34 +1507,34 @@ enum CSI_J { static void csi_J(struct vc_data *vc, enum CSI_J vpar) { + unsigned short *start; unsigned int count; - unsigned short * start; switch (vpar) { - case CSI_J_CURSOR_TO_END: - vc_uniscr_clear_line(vc, vc->state.x, - vc->vc_cols - vc->state.x); - vc_uniscr_clear_lines(vc, vc->state.y + 1, - vc->vc_rows - vc->state.y - 1); - count = (vc->vc_scr_end - vc->vc_pos) >> 1; - start = (unsigned short *)vc->vc_pos; - break; - case CSI_J_START_TO_CURSOR: - vc_uniscr_clear_line(vc, 0, vc->state.x + 1); - vc_uniscr_clear_lines(vc, 0, vc->state.y); - count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1; - start = (unsigned short *)vc->vc_origin; - break; - case CSI_J_FULL: - flush_scrollback(vc); - fallthrough; - case CSI_J_VISIBLE: - vc_uniscr_clear_lines(vc, 0, vc->vc_rows); - count = vc->vc_cols * vc->vc_rows; - start = (unsigned short *)vc->vc_origin; - break; - default: - return; + case CSI_J_CURSOR_TO_END: + vc_uniscr_clear_line(vc, vc->state.x, + vc->vc_cols - vc->state.x); + vc_uniscr_clear_lines(vc, vc->state.y + 1, + vc->vc_rows - vc->state.y - 1); + count = (vc->vc_scr_end - vc->vc_pos) >> 1; + start = (unsigned short *)vc->vc_pos; + break; + case CSI_J_START_TO_CURSOR: + vc_uniscr_clear_line(vc, 0, vc->state.x + 1); + vc_uniscr_clear_lines(vc, 0, vc->state.y); + count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1; + start = (unsigned short *)vc->vc_origin; + break; + case CSI_J_FULL: + flush_scrollback(vc); + fallthrough; + case CSI_J_VISIBLE: + vc_uniscr_clear_lines(vc, 0, vc->vc_rows); + count = vc->vc_cols * vc->vc_rows; + start = (unsigned short *)vc->vc_origin; + break; + default: + return; } scr_memsetw(start, vc->vc_video_erase_char, 2 * count); if (con_should_update(vc)) From eb881ebab593fdf8325bb35143e5135dcd7a346b Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:27 +0100 Subject: [PATCH 013/199] use clamp() for counts in csi_?() handlers The count to process is supposed to be between 1 and vc->vc_cols - vc->state.x (or rows and .y). clamp() can be used exactly for this, instead of ifs and min(). Signed-off-by: "Jiri Slaby (SUSE)" Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-14-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index bf77d962eeb4..05baf9ca23f2 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1574,12 +1574,7 @@ static void csi_K(struct vc_data *vc, int vpar) /* erase the following vpar positions */ static void csi_X(struct vc_data *vc, unsigned int vpar) { /* not vt100? */ - unsigned int count; - - if (!vpar) - vpar++; - - count = min(vpar, vc->vc_cols - vc->state.x); + unsigned int count = clamp(vpar, 1, vc->vc_cols - vc->state.x); vc_uniscr_clear_line(vc, vc->state.x, count); scr_memsetw((unsigned short *)vc->vc_pos, vc->vc_video_erase_char, 2 * count); @@ -2010,20 +2005,14 @@ static void setterm_command(struct vc_data *vc) /* console_lock is held */ static void csi_at(struct vc_data *vc, unsigned int nr) { - if (nr > vc->vc_cols - vc->state.x) - nr = vc->vc_cols - vc->state.x; - else if (!nr) - nr = 1; + nr = clamp(nr, 1, vc->vc_cols - vc->state.x); insert_char(vc, nr); } /* console_lock is held */ static void csi_L(struct vc_data *vc, unsigned int nr) { - if (nr > vc->vc_rows - vc->state.y) - nr = vc->vc_rows - vc->state.y; - else if (!nr) - nr = 1; + nr = clamp(nr, 1, vc->vc_rows - vc->state.y); con_scroll(vc, vc->state.y, vc->vc_bottom, SM_DOWN, nr); vc->vc_need_wrap = 0; } @@ -2031,20 +2020,14 @@ static void csi_L(struct vc_data *vc, unsigned int nr) /* console_lock is held */ static void csi_P(struct vc_data *vc, unsigned int nr) { - if (nr > vc->vc_cols - vc->state.x) - nr = vc->vc_cols - vc->state.x; - else if (!nr) - nr = 1; + nr = clamp(nr, 1, vc->vc_cols - vc->state.x); delete_char(vc, nr); } /* console_lock is held */ static void csi_M(struct vc_data *vc, unsigned int nr) { - if (nr > vc->vc_rows - vc->state.y) - nr = vc->vc_rows - vc->state.y; - else if (!nr) - nr=1; + nr = clamp(nr, 1, vc->vc_rows - vc->state.y); con_scroll(vc, vc->state.y, vc->vc_bottom, SM_UP, nr); vc->vc_need_wrap = 0; } From 8e6bd49a6132a6b95aa0bb7b705c9ab535396813 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:28 +0100 Subject: [PATCH 014/199] don't pass vc->vc_par[0] to csi_?() handlers Fetch the value directly in the helpers instead. Signed-off-by: "Jiri Slaby (SUSE)" Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-15-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 05baf9ca23f2..16ba3a3666ab 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1542,13 +1542,13 @@ static void csi_J(struct vc_data *vc, enum CSI_J vpar) vc->vc_need_wrap = 0; } -static void csi_K(struct vc_data *vc, int vpar) +static void csi_K(struct vc_data *vc) { unsigned int count; unsigned short *start = (unsigned short *)vc->vc_pos; int offset; - switch (vpar) { + switch (vc->vc_par[0]) { case 0: /* erase from cursor to end of line */ offset = 0; count = vc->vc_cols - vc->state.x; @@ -1571,10 +1571,10 @@ static void csi_K(struct vc_data *vc, int vpar) do_update_region(vc, (unsigned long)(start + offset), count); } -/* erase the following vpar positions */ -static void csi_X(struct vc_data *vc, unsigned int vpar) +/* erase the following count positions */ +static void csi_X(struct vc_data *vc) { /* not vt100? */ - unsigned int count = clamp(vpar, 1, vc->vc_cols - vc->state.x); + unsigned int count = clamp(vc->vc_par[0], 1, vc->vc_cols - vc->state.x); vc_uniscr_clear_line(vc, vc->state.x, count); scr_memsetw((unsigned short *)vc->vc_pos, vc->vc_video_erase_char, 2 * count); @@ -2010,24 +2010,27 @@ static void csi_at(struct vc_data *vc, unsigned int nr) } /* console_lock is held */ -static void csi_L(struct vc_data *vc, unsigned int nr) +static void csi_L(struct vc_data *vc) { - nr = clamp(nr, 1, vc->vc_rows - vc->state.y); + unsigned int nr = clamp(vc->vc_par[0], 1, vc->vc_rows - vc->state.y); + con_scroll(vc, vc->state.y, vc->vc_bottom, SM_DOWN, nr); vc->vc_need_wrap = 0; } /* console_lock is held */ -static void csi_P(struct vc_data *vc, unsigned int nr) +static void csi_P(struct vc_data *vc) { - nr = clamp(nr, 1, vc->vc_cols - vc->state.x); + unsigned int nr = clamp(vc->vc_par[0], 1, vc->vc_cols - vc->state.x); + delete_char(vc, nr); } /* console_lock is held */ -static void csi_M(struct vc_data *vc, unsigned int nr) +static void csi_M(struct vc_data *vc) { - nr = clamp(nr, 1, vc->vc_rows - vc->state.y); + unsigned int nr = clamp(vc->vc_par[0], 1, vc->vc_rows - vc->state.y); + con_scroll(vc, vc->state.y, vc->vc_bottom, SM_UP, nr); vc->vc_need_wrap = 0; } @@ -2430,16 +2433,16 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) csi_J(vc, vc->vc_par[0]); return; case 'K': - csi_K(vc, vc->vc_par[0]); + csi_K(vc); return; case 'L': - csi_L(vc, vc->vc_par[0]); + csi_L(vc); return; case 'M': - csi_M(vc, vc->vc_par[0]); + csi_M(vc); return; case 'P': - csi_P(vc, vc->vc_par[0]); + csi_P(vc); return; case 'c': if (!vc->vc_par[0]) @@ -2480,7 +2483,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) restore_cur(vc); return; case 'X': - csi_X(vc, vc->vc_par[0]); + csi_X(vc); return; case '@': csi_at(vc, vc->vc_par[0]); From 7eb38a765e347baa89a2e72050866ebdb4377cb9 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:29 +0100 Subject: [PATCH 015/199] tty: vt: define an enum for CSI+K codes Decrypt the constant values by proper enum names. This time in csi_K(). Signed-off-by: "Jiri Slaby (SUSE)" Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-16-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 16ba3a3666ab..2f3f5e4817f6 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1542,6 +1542,12 @@ static void csi_J(struct vc_data *vc, enum CSI_J vpar) vc->vc_need_wrap = 0; } +enum { + CSI_K_CURSOR_TO_LINEEND = 0, + CSI_K_LINESTART_TO_CURSOR = 1, + CSI_K_LINE = 2, +}; + static void csi_K(struct vc_data *vc) { unsigned int count; @@ -1549,15 +1555,15 @@ static void csi_K(struct vc_data *vc) int offset; switch (vc->vc_par[0]) { - case 0: /* erase from cursor to end of line */ + case CSI_K_CURSOR_TO_LINEEND: offset = 0; count = vc->vc_cols - vc->state.x; break; - case 1: /* erase from start of line to cursor */ + case CSI_K_LINESTART_TO_CURSOR: offset = -vc->state.x; count = vc->state.x + 1; break; - case 2: /* erase whole line */ + case CSI_K_LINE: offset = -vc->state.x; count = vc->vc_cols; break; From 23672a572f50f3027a5fed4ea7eac2e3ebfba50c Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:30 +0100 Subject: [PATCH 016/199] tty: vt: reflow csi_K() Push cases one level left, according to coding style. Signed-off-by: "Jiri Slaby (SUSE)" Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-17-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 2f3f5e4817f6..8d868aa33733 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1555,20 +1555,20 @@ static void csi_K(struct vc_data *vc) int offset; switch (vc->vc_par[0]) { - case CSI_K_CURSOR_TO_LINEEND: - offset = 0; - count = vc->vc_cols - vc->state.x; - break; - case CSI_K_LINESTART_TO_CURSOR: - offset = -vc->state.x; - count = vc->state.x + 1; - break; - case CSI_K_LINE: - offset = -vc->state.x; - count = vc->vc_cols; - break; - default: - return; + case CSI_K_CURSOR_TO_LINEEND: + offset = 0; + count = vc->vc_cols - vc->state.x; + break; + case CSI_K_LINESTART_TO_CURSOR: + offset = -vc->state.x; + count = vc->state.x + 1; + break; + case CSI_K_LINE: + offset = -vc->state.x; + count = vc->vc_cols; + break; + default: + return; } vc_uniscr_clear_line(vc, vc->state.x + offset, count); scr_memsetw(start + offset, vc->vc_video_erase_char, 2 * count); From bf9e206b8ad95b0bd079eccb03c1859fb3ab9dd6 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:31 +0100 Subject: [PATCH 017/199] tty: vt: define an enum for ascii characters I didn't find definitions for ascii in the kernel yet, so define it for non-printable characters used here. Note we use ' ' instead of 32 on one line too. Signed-off-by: "Jiri Slaby (SUSE)" Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-18-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 62 ++++++++++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 18 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 8d868aa33733..51a2787415db 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2143,6 +2143,28 @@ static bool ansi_control_string(unsigned int state) return false; } +enum { + ASCII_NULL = 0, + ASCII_BELL = 7, + ASCII_BACKSPACE = 8, + ASCII_IGNORE_FIRST = ASCII_BACKSPACE, + ASCII_HTAB = 9, + ASCII_LINEFEED = 10, + ASCII_VTAB = 11, + ASCII_FORMFEED = 12, + ASCII_CAR_RET = 13, + ASCII_IGNORE_LAST = ASCII_CAR_RET, + ASCII_SHIFTOUT = 14, + ASCII_SHIFTIN = 15, + ASCII_CANCEL = 24, + ASCII_SUBSTITUTE = 26, + ASCII_ESCAPE = 27, + ASCII_CSI_IGNORE_FIRST = ' ', /* 0x2x, 0x3a and 0x3c - 0x3f */ + ASCII_CSI_IGNORE_LAST = '?', + ASCII_DEL = 127, + ASCII_EXT_CSI = 128 + ASCII_ESCAPE, +}; + /* console_lock is held */ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) { @@ -2150,21 +2172,22 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) * Control characters can be used in the _middle_ * of an escape sequence, aside from ANSI control strings. */ - if (ansi_control_string(vc->vc_state) && c >= 8 && c <= 13) + if (ansi_control_string(vc->vc_state) && c >= ASCII_IGNORE_FIRST && + c <= ASCII_IGNORE_LAST) return; switch (c) { - case 0: + case ASCII_NULL: return; - case 7: + case ASCII_BELL: if (ansi_control_string(vc->vc_state)) vc->vc_state = ESnormal; else if (vc->vc_bell_duration) kd_mksound(vc->vc_bell_pitch, vc->vc_bell_duration); return; - case 8: + case ASCII_BACKSPACE: bs(vc); return; - case 9: + case ASCII_HTAB: vc->vc_pos -= (vc->state.x << 1); vc->state.x = find_next_bit(vc->vc_tab_stop, @@ -2176,34 +2199,37 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) vc->vc_pos += (vc->state.x << 1); notify_write(vc, '\t'); return; - case 10: case 11: case 12: + case ASCII_LINEFEED: + case ASCII_VTAB: + case ASCII_FORMFEED: lf(vc); if (!is_kbd(vc, lnm)) return; fallthrough; - case 13: + case ASCII_CAR_RET: cr(vc); return; - case 14: + case ASCII_SHIFTOUT: vc->state.charset = 1; vc->vc_translate = set_translate(vc->state.Gx_charset[1], vc); vc->vc_disp_ctrl = 1; return; - case 15: + case ASCII_SHIFTIN: vc->state.charset = 0; vc->vc_translate = set_translate(vc->state.Gx_charset[0], vc); vc->vc_disp_ctrl = 0; return; - case 24: case 26: + case ASCII_CANCEL: + case ASCII_SUBSTITUTE: vc->vc_state = ESnormal; return; - case 27: + case ASCII_ESCAPE: vc->vc_state = ESesc; return; - case 127: + case ASCII_DEL: del(vc); return; - case 128+27: + case ASCII_EXT_CSI: vc->vc_state = ESsquare; return; } @@ -2338,7 +2364,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) vc->vc_par[vc->vc_npar] += c - '0'; return; } - if (c >= 0x20 && c <= 0x3f) { /* 0x2x, 0x3a and 0x3c - 0x3f */ + if (c >= ASCII_CSI_IGNORE_FIRST && c <= ASCII_CSI_IGNORE_LAST) { vc->vc_state = EScsiignore; return; } @@ -2500,7 +2526,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) } return; case EScsiignore: - if (c >= 0x20 && c <= 0x3f) + if (c >= ASCII_CSI_IGNORE_FIRST && c <= ASCII_CSI_IGNORE_LAST) return; vc->vc_state = ESnormal; return; @@ -2761,17 +2787,17 @@ static bool vc_is_control(struct vc_data *vc, int tc, int c) * useless without them; to display an arbitrary font position use the * direct-to-font zone in UTF-8 mode. */ - if (c < 32) { + if (c < ' ') { if (vc->vc_disp_ctrl) return CTRL_ALWAYS & BIT(c); else return vc->vc_utf || (CTRL_ACTION & BIT(c)); } - if (c == 127 && !vc->vc_disp_ctrl) + if (c == ASCII_DEL && !vc->vc_disp_ctrl) return true; - if (c == 128 + 27) + if (c == ASCII_EXT_CSI) return true; return false; From 649f6fbe6abe0c7749120067058709d41111f655 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:32 +0100 Subject: [PATCH 018/199] tty: vt: remove extern from functions in selection.h Remove unneeded 'extern' keyword from function prototypes in selection.h. This makes it more readable as no more wrapping is needed on many places. Signed-off-by: "Jiri Slaby (SUSE)" Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-19-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- include/linux/selection.h | 46 ++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/include/linux/selection.h b/include/linux/selection.h index 533509f6ba4f..bab7d30d3446 100644 --- a/include/linux/selection.h +++ b/include/linux/selection.h @@ -14,15 +14,14 @@ struct tty_struct; struct vc_data; -extern void clear_selection(void); -extern int set_selection_user(const struct tiocl_selection __user *sel, - struct tty_struct *tty); -extern int set_selection_kernel(struct tiocl_selection *v, - struct tty_struct *tty); -extern int paste_selection(struct tty_struct *tty); -extern int sel_loadlut(u32 __user *lut); -extern int mouse_reporting(void); -extern void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry); +void clear_selection(void); +int set_selection_user(const struct tiocl_selection __user *sel, + struct tty_struct *tty); +int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty); +int paste_selection(struct tty_struct *tty); +int sel_loadlut(u32 __user *lut); +int mouse_reporting(void); +void mouse_report(struct tty_struct *tty, int butt, int mrx, int mry); bool vc_is_sel(const struct vc_data *vc); @@ -33,24 +32,21 @@ extern unsigned char default_red[]; extern unsigned char default_grn[]; extern unsigned char default_blu[]; -extern unsigned short *screen_pos(const struct vc_data *vc, int w_offset, - bool viewed); -extern u16 screen_glyph(const struct vc_data *vc, int offset); -extern u32 screen_glyph_unicode(const struct vc_data *vc, int offset); -extern void complement_pos(struct vc_data *vc, int offset); -extern void invert_screen(struct vc_data *vc, int offset, int count, bool viewed); +unsigned short *screen_pos(const struct vc_data *vc, int w_offset, bool viewed); +u16 screen_glyph(const struct vc_data *vc, int offset); +u32 screen_glyph_unicode(const struct vc_data *vc, int offset); +void complement_pos(struct vc_data *vc, int offset); +void invert_screen(struct vc_data *vc, int offset, int count, bool viewed); -extern void getconsxy(const struct vc_data *vc, unsigned char xy[static 2]); -extern void putconsxy(struct vc_data *vc, unsigned char xy[static const 2]); +void getconsxy(const struct vc_data *vc, unsigned char xy[static 2]); +void putconsxy(struct vc_data *vc, unsigned char xy[static const 2]); -extern u16 vcs_scr_readw(const struct vc_data *vc, const u16 *org); -extern void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org); -extern void vcs_scr_updated(struct vc_data *vc); +u16 vcs_scr_readw(const struct vc_data *vc, const u16 *org); +void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org); +void vcs_scr_updated(struct vc_data *vc); -extern int vc_uniscr_check(struct vc_data *vc); -extern void vc_uniscr_copy_line(const struct vc_data *vc, void *dest, - bool viewed, - unsigned int row, unsigned int col, - unsigned int nr); +int vc_uniscr_check(struct vc_data *vc); +void vc_uniscr_copy_line(const struct vc_data *vc, void *dest, bool viewed, + unsigned int row, unsigned int col, unsigned int nr); #endif From 7995c30d8d771c8410d7f2ba5b9d42b69e0074c8 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:33 +0100 Subject: [PATCH 019/199] tty: vt: make consw::con_debug_*() return void The return value of con_debug_enter() and con_debug_leave() is ignored on many fronts. So just don't propagate errors (the current implementations return 0 anyway) and make the return type a void. Signed-off-by: "Jiri Slaby (SUSE)" Cc: Daniel Vetter Cc: Helge Deller Cc: linux-fbdev@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-20-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 21 ++++----------------- drivers/video/fbdev/core/fbcon.c | 6 ++---- include/linux/console.h | 18 ++++++------------ 3 files changed, 12 insertions(+), 33 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 51a2787415db..bbfda0d33ca1 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -4012,15 +4012,9 @@ EXPORT_SYMBOL(con_is_visible); * Called when the console is taken over by the kernel debugger, this * function needs to save the current console state, then put the console * into a state suitable for the kernel debugger. - * - * RETURNS: - * Zero on success, nonzero if a failure occurred when trying to prepare - * the console for the debugger. */ -int con_debug_enter(struct vc_data *vc) +void con_debug_enter(struct vc_data *vc) { - int ret = 0; - saved_fg_console = fg_console; saved_last_console = last_console; saved_want_console = want_console; @@ -4029,7 +4023,7 @@ int con_debug_enter(struct vc_data *vc) vc->vc_mode = KD_TEXT; console_blanked = 0; if (vc->vc_sw->con_debug_enter) - ret = vc->vc_sw->con_debug_enter(vc); + vc->vc_sw->con_debug_enter(vc); #ifdef CONFIG_KGDB_KDB /* Set the initial LINES variable if it is not already set */ if (vc->vc_rows < 999) { @@ -4059,7 +4053,6 @@ int con_debug_enter(struct vc_data *vc) } } #endif /* CONFIG_KGDB_KDB */ - return ret; } EXPORT_SYMBOL_GPL(con_debug_enter); @@ -4068,15 +4061,10 @@ EXPORT_SYMBOL_GPL(con_debug_enter); * * Restore the console state to what it was before the kernel debugger * was invoked. - * - * RETURNS: - * Zero on success, nonzero if a failure occurred when trying to restore - * the console. */ -int con_debug_leave(void) +void con_debug_leave(void) { struct vc_data *vc; - int ret = 0; fg_console = saved_fg_console; last_console = saved_last_console; @@ -4086,8 +4074,7 @@ int con_debug_leave(void) vc = vc_cons[fg_console].d; if (vc->vc_sw->con_debug_leave) - ret = vc->vc_sw->con_debug_leave(vc); - return ret; + vc->vc_sw->con_debug_leave(vc); } EXPORT_SYMBOL_GPL(con_debug_leave); diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index dd2f4617485c..d3fb98084eda 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -2243,7 +2243,7 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch) return 0; } -static int fbcon_debug_enter(struct vc_data *vc) +static void fbcon_debug_enter(struct vc_data *vc) { struct fb_info *info = fbcon_info_from_console(vc->vc_num); struct fbcon_ops *ops = info->fbcon_par; @@ -2253,10 +2253,9 @@ static int fbcon_debug_enter(struct vc_data *vc) if (info->fbops->fb_debug_enter) info->fbops->fb_debug_enter(info); fbcon_set_palette(vc, color_table); - return 0; } -static int fbcon_debug_leave(struct vc_data *vc) +static void fbcon_debug_leave(struct vc_data *vc) { struct fb_info *info = fbcon_info_from_console(vc->vc_num); struct fbcon_ops *ops = info->fbcon_par; @@ -2264,7 +2263,6 @@ static int fbcon_debug_leave(struct vc_data *vc) ops->graphics = ops->save_graphics; if (info->fbops->fb_debug_leave) info->fbops->fb_debug_leave(info); - return 0; } static int fbcon_get_font(struct vc_data *vc, struct console_font *font, unsigned int vpitch) diff --git a/include/linux/console.h b/include/linux/console.h index 38b379d6c624..93a1db5bf3b5 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -88,11 +88,11 @@ struct consw { * limited to, unblanking the console, loading an appropriate * palette, and allowing debugger generated output. */ - int (*con_debug_enter)(struct vc_data *vc); + void (*con_debug_enter)(struct vc_data *vc); /* * Restore the console to its pre-debug state as closely as possible. */ - int (*con_debug_leave)(struct vc_data *vc); + void (*con_debug_leave)(struct vc_data *vc); }; extern const struct consw *conswitchp; @@ -113,17 +113,11 @@ int do_unregister_con_driver(const struct consw *csw); int do_take_over_console(const struct consw *sw, int first, int last, int deflt); void give_up_console(const struct consw *sw); #ifdef CONFIG_HW_CONSOLE -int con_debug_enter(struct vc_data *vc); -int con_debug_leave(void); +void con_debug_enter(struct vc_data *vc); +void con_debug_leave(void); #else -static inline int con_debug_enter(struct vc_data *vc) -{ - return 0; -} -static inline int con_debug_leave(void) -{ - return 0; -} +static inline void con_debug_enter(struct vc_data *vc) { } +static inline void con_debug_leave(void) { } #endif /* cursor */ From dae3e6b6180f1a2394b984c596d39ed2c57d25fe Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:34 +0100 Subject: [PATCH 020/199] tty: vt: make init parameter of consw::con_init() a bool The 'init' parameter of consw::con_init() is true for the first call of the hook on a particular console. So make the parameter a bool. And document the hook. Signed-off-by: "Jiri Slaby (SUSE)" Reviewed-by: Geert Uytterhoeven Cc: Helge Deller Cc: "James E.J. Bottomley" Cc: Daniel Vetter Cc: linux-fbdev@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Cc: linux-parisc@vger.kernel.org Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-21-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 8 ++++---- drivers/video/console/dummycon.c | 2 +- drivers/video/console/mdacon.c | 2 +- drivers/video/console/newport_con.c | 2 +- drivers/video/console/sticon.c | 2 +- drivers/video/console/vgacon.c | 4 ++-- drivers/video/fbdev/core/fbcon.c | 2 +- include/linux/console.h | 4 +++- 8 files changed, 14 insertions(+), 12 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index bbfda0d33ca1..fcb41c8724f3 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -999,7 +999,7 @@ int vc_cons_allocated(unsigned int i) return (i < MAX_NR_CONSOLES && vc_cons[i].d); } -static void visual_init(struct vc_data *vc, int num, int init) +static void visual_init(struct vc_data *vc, int num, bool init) { /* ++Geert: vc->vc_sw->con_init determines console size */ if (vc->vc_sw) @@ -1083,7 +1083,7 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */ vc->port.ops = &vc_port_ops; INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK); - visual_init(vc, currcons, 1); + visual_init(vc, currcons, true); if (!*vc->uni_pagedict_loc) con_set_default_unimap(vc); @@ -3513,7 +3513,7 @@ static int __init con_init(void) vc_cons[currcons].d = vc = kzalloc(sizeof(struct vc_data), GFP_NOWAIT); INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK); tty_port_init(&vc->port); - visual_init(vc, currcons, 1); + visual_init(vc, currcons, true); /* Assuming vc->vc_{cols,rows,screenbuf_size} are sane here. */ vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT); vc_init(vc, currcons || !vc->vc_sw->con_save_screen); @@ -3682,7 +3682,7 @@ static int do_bind_con_driver(const struct consw *csw, int first, int last, old_was_color = vc->vc_can_do_color; vc->vc_sw->con_deinit(vc); vc->vc_origin = (unsigned long)vc->vc_screenbuf; - visual_init(vc, i, 0); + visual_init(vc, i, false); set_origin(vc); update_attr(vc); diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c index 14af5d9e13b0..f2cef9d9a4b5 100644 --- a/drivers/video/console/dummycon.c +++ b/drivers/video/console/dummycon.c @@ -98,7 +98,7 @@ static const char *dummycon_startup(void) return "dummy device"; } -static void dummycon_init(struct vc_data *vc, int init) +static void dummycon_init(struct vc_data *vc, bool init) { vc->vc_can_do_color = 1; if (init) { diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index ef29b321967f..c5b255c96879 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c @@ -352,7 +352,7 @@ static const char *mdacon_startup(void) return "MDA-2"; } -static void mdacon_init(struct vc_data *c, int init) +static void mdacon_init(struct vc_data *c, bool init) { c->vc_complement_mask = 0x0800; /* reverse video */ c->vc_display_fg = &mda_display_fg; diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index e8e4f82cd4a1..12c64ef47087 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -324,7 +324,7 @@ out_unmap: return NULL; } -static void newport_init(struct vc_data *vc, int init) +static void newport_init(struct vc_data *vc, bool init) { int cols, rows; diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index 992a4fa431aa..0bfeabc3f7c7 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c @@ -273,7 +273,7 @@ static int sticon_font_set(struct vc_data *vc, struct console_font *font, return sticon_set_font(vc, font, vpitch); } -static void sticon_init(struct vc_data *c, int init) +static void sticon_init(struct vc_data *c, bool init) { struct sti_struct *sti = sticon_sti; int vc_cols, vc_rows; diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 0c76e2817b49..5d523753def8 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -367,7 +367,7 @@ static const char *vgacon_startup(void) return display_desc; } -static void vgacon_init(struct vc_data *c, int init) +static void vgacon_init(struct vc_data *c, bool init) { struct uni_pagedict *p; @@ -384,7 +384,7 @@ static void vgacon_init(struct vc_data *c, int init) c->vc_scan_lines = vga_scan_lines; c->vc_font.height = c->vc_cell_height = vga_video_font_height; - /* set dimensions manually if init != 0 since vc_resize() will fail */ + /* set dimensions manually if init is true since vc_resize() will fail */ if (init) { c->vc_cols = vga_video_num_columns; c->vc_rows = vga_video_num_lines; diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index d3fb98084eda..939c5d893dfb 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -988,7 +988,7 @@ static const char *fbcon_startup(void) return display_desc; } -static void fbcon_init(struct vc_data *vc, int init) +static void fbcon_init(struct vc_data *vc, bool init) { struct fb_info *info; struct fbcon_ops *ops; diff --git a/include/linux/console.h b/include/linux/console.h index 93a1db5bf3b5..fc9450e0c78f 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -36,6 +36,8 @@ enum vc_intensity; /** * struct consw - callbacks for consoles * + * @con_init: initialize the console on @vc. @init is true for the very first + * call on this @vc. * @con_scroll: move lines from @top to @bottom in direction @dir by @lines. * Return true if no generic handling should be done. * Invoked by csi_M and printing to the console. @@ -46,7 +48,7 @@ enum vc_intensity; struct consw { struct module *owner; const char *(*con_startup)(void); - void (*con_init)(struct vc_data *vc, int init); + void (*con_init)(struct vc_data *vc, bool init); void (*con_deinit)(struct vc_data *vc); void (*con_clear)(struct vc_data *vc, int sy, int sx, int height, int width); From 559f01a0ee6d924c6fec3eaf6a5b078b15e71070 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:35 +0100 Subject: [PATCH 021/199] tty: vt: sanitize arguments of consw::con_clear() In consw::con_clear(): * Height is always 1, so drop it. * Offsets and width are always unsigned values, so re-type them as such. This needs a new __fbcon_clear() in the fbcon code to still handle height which might not be 1 when called internally. Note that tests for negative count/width are left in place -- they are taken care of in the next patches. And document the hook. Signed-off-by: "Jiri Slaby (SUSE)" Cc: Helge Deller Cc: "James E.J. Bottomley" Cc: Daniel Vetter Cc: linux-fbdev@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Cc: linux-parisc@vger.kernel.org Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-22-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 2 +- drivers/video/console/dummycon.c | 4 ++-- drivers/video/console/mdacon.c | 15 +++++--------- drivers/video/console/newport_con.c | 6 +++--- drivers/video/console/sticon.c | 8 ++++---- drivers/video/console/vgacon.c | 4 ++-- drivers/video/fbdev/core/fbcon.c | 32 +++++++++++++++++------------ include/linux/console.h | 5 +++-- 8 files changed, 39 insertions(+), 37 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index fcb41c8724f3..b6f1449421bc 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1585,7 +1585,7 @@ static void csi_X(struct vc_data *vc) vc_uniscr_clear_line(vc, vc->state.x, count); scr_memsetw((unsigned short *)vc->vc_pos, vc->vc_video_erase_char, 2 * count); if (con_should_update(vc)) - vc->vc_sw->con_clear(vc, vc->state.y, vc->state.x, 1, count); + vc->vc_sw->con_clear(vc, vc->state.y, vc->state.x, count); vc->vc_need_wrap = 0; } diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c index f2cef9d9a4b5..0a69d5c216ee 100644 --- a/drivers/video/console/dummycon.c +++ b/drivers/video/console/dummycon.c @@ -109,8 +109,8 @@ static void dummycon_init(struct vc_data *vc, bool init) } static void dummycon_deinit(struct vc_data *vc) { } -static void dummycon_clear(struct vc_data *vc, int sy, int sx, int height, - int width) { } +static void dummycon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx, + unsigned int width) { } static void dummycon_cursor(struct vc_data *vc, int mode) { } static bool dummycon_scroll(struct vc_data *vc, unsigned int top, diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index c5b255c96879..1ddbb6cd5b0c 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c @@ -442,23 +442,18 @@ static void mdacon_putcs(struct vc_data *c, const unsigned short *s, } } -static void mdacon_clear(struct vc_data *c, int y, int x, - int height, int width) +static void mdacon_clear(struct vc_data *c, unsigned int y, unsigned int x, + unsigned int width) { u16 *dest = mda_addr(x, y); u16 eattr = mda_convert_attr(c->vc_video_erase_char); - if (width <= 0 || height <= 0) + if (width <= 0) return; - if (x==0 && width==mda_num_columns) { - scr_memsetw(dest, eattr, height*width*2); - } else { - for (; height > 0; height--, dest+=mda_num_columns) - scr_memsetw(dest, eattr, width*2); - } + scr_memsetw(dest, eattr, width * 2); } - + static int mdacon_switch(struct vc_data *c) { return 1; /* redrawing needed */ diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index 12c64ef47087..55c6106b3507 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -346,12 +346,12 @@ static void newport_deinit(struct vc_data *c) } } -static void newport_clear(struct vc_data *vc, int sy, int sx, int height, - int width) +static void newport_clear(struct vc_data *vc, unsigned int sy, unsigned int sx, + unsigned int width) { int xend = ((sx + width) << 3) - 1; int ystart = ((sy << 4) + topscan) & 0x3ff; - int yend = (((sy + height) << 4) + topscan - 1) & 0x3ff; + int yend = (((sy + 1) << 4) + topscan - 1) & 0x3ff; if (logo_active) return; diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index 0bfeabc3f7c7..d99c2a659bfd 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c @@ -300,13 +300,13 @@ static void sticon_deinit(struct vc_data *c) sticon_set_def_font(i); } -static void sticon_clear(struct vc_data *conp, int sy, int sx, int height, - int width) +static void sticon_clear(struct vc_data *conp, unsigned int sy, unsigned int sx, + unsigned int width) { - if (!height || !width) + if (!width) return; - sti_clear(sticon_sti, sy, sx, height, width, + sti_clear(sticon_sti, sy, sx, 1, width, conp->vc_video_erase_char, font_data[conp->vc_num]); } diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 5d523753def8..85f29dec2c3d 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -1191,8 +1191,8 @@ static bool vgacon_scroll(struct vc_data *c, unsigned int t, unsigned int b, * The console `switch' structure for the VGA based console */ -static void vgacon_clear(struct vc_data *vc, int sy, int sx, int height, - int width) { } +static void vgacon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx, + unsigned int width) { } static void vgacon_putc(struct vc_data *vc, int c, int ypos, int xpos) { } static void vgacon_putcs(struct vc_data *vc, const unsigned short *s, int count, int ypos, int xpos) { } diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index 939c5d893dfb..8a31a36483ea 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -1235,8 +1235,8 @@ finished: * restriction is simplicity & efficiency at the moment. */ -static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height, - int width) +static void __fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx, + unsigned int height, unsigned int width) { struct fb_info *info = fbcon_info_from_console(vc->vc_num); struct fbcon_ops *ops = info->fbcon_par; @@ -1273,6 +1273,12 @@ static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height, ops->clear(vc, info, real_y(p, sy), sx, height, width); } +static void fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx, + unsigned int width) +{ + __fbcon_clear(vc, sy, sx, 1, width); +} + static void fbcon_putcs(struct vc_data *vc, const unsigned short *s, int count, int ypos, int xpos) { @@ -1760,7 +1766,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b, case SCROLL_MOVE: fbcon_redraw_blit(vc, info, p, t, b - t - count, count); - fbcon_clear(vc, b - count, 0, count, vc->vc_cols); + __fbcon_clear(vc, b - count, 0, count, vc->vc_cols); scr_memsetw((unsigned short *) (vc->vc_origin + vc->vc_size_row * (b - count)), @@ -1783,7 +1789,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b, b - t - count, vc->vc_cols); else goto redraw_up; - fbcon_clear(vc, b - count, 0, count, vc->vc_cols); + __fbcon_clear(vc, b - count, 0, count, vc->vc_cols); break; case SCROLL_PAN_REDRAW: @@ -1801,7 +1807,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b, vc->vc_rows - b, b); } else fbcon_redraw_move(vc, p, t + count, b - t - count, t); - fbcon_clear(vc, b - count, 0, count, vc->vc_cols); + __fbcon_clear(vc, b - count, 0, count, vc->vc_cols); break; case SCROLL_PAN_MOVE: @@ -1824,14 +1830,14 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b, b - t - count, vc->vc_cols); else goto redraw_up; - fbcon_clear(vc, b - count, 0, count, vc->vc_cols); + __fbcon_clear(vc, b - count, 0, count, vc->vc_cols); break; case SCROLL_REDRAW: redraw_up: fbcon_redraw(vc, t, b - t - count, count * vc->vc_cols); - fbcon_clear(vc, b - count, 0, count, vc->vc_cols); + __fbcon_clear(vc, b - count, 0, count, vc->vc_cols); scr_memsetw((unsigned short *) (vc->vc_origin + vc->vc_size_row * (b - count)), @@ -1848,7 +1854,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b, case SCROLL_MOVE: fbcon_redraw_blit(vc, info, p, b - 1, b - t - count, -count); - fbcon_clear(vc, t, 0, count, vc->vc_cols); + __fbcon_clear(vc, t, 0, count, vc->vc_cols); scr_memsetw((unsigned short *) (vc->vc_origin + vc->vc_size_row * t), @@ -1871,7 +1877,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b, b - t - count, vc->vc_cols); else goto redraw_down; - fbcon_clear(vc, t, 0, count, vc->vc_cols); + __fbcon_clear(vc, t, 0, count, vc->vc_cols); break; case SCROLL_PAN_MOVE: @@ -1893,7 +1899,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b, b - t - count, vc->vc_cols); else goto redraw_down; - fbcon_clear(vc, t, 0, count, vc->vc_cols); + __fbcon_clear(vc, t, 0, count, vc->vc_cols); break; case SCROLL_PAN_REDRAW: @@ -1910,14 +1916,14 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b, fbcon_redraw_move(vc, p, count, t, 0); } else fbcon_redraw_move(vc, p, t, b - t - count, t + count); - fbcon_clear(vc, t, 0, count, vc->vc_cols); + __fbcon_clear(vc, t, 0, count, vc->vc_cols); break; case SCROLL_REDRAW: redraw_down: fbcon_redraw(vc, b - 1, b - t - count, -count * vc->vc_cols); - fbcon_clear(vc, t, 0, count, vc->vc_cols); + __fbcon_clear(vc, t, 0, count, vc->vc_cols); scr_memsetw((unsigned short *) (vc->vc_origin + vc->vc_size_row * t), @@ -2196,7 +2202,7 @@ static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info, oldc = vc->vc_video_erase_char; vc->vc_video_erase_char &= charmask; - fbcon_clear(vc, 0, 0, vc->vc_rows, vc->vc_cols); + __fbcon_clear(vc, 0, 0, vc->vc_rows, vc->vc_cols); vc->vc_video_erase_char = oldc; } } diff --git a/include/linux/console.h b/include/linux/console.h index fc9450e0c78f..8fd96a5fca5f 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -38,6 +38,7 @@ enum vc_intensity; * * @con_init: initialize the console on @vc. @init is true for the very first * call on this @vc. + * @con_clear: erase @count characters at [@x, @y] on @vc. @count >= 1. * @con_scroll: move lines from @top to @bottom in direction @dir by @lines. * Return true if no generic handling should be done. * Invoked by csi_M and printing to the console. @@ -50,8 +51,8 @@ struct consw { const char *(*con_startup)(void); void (*con_init)(struct vc_data *vc, bool init); void (*con_deinit)(struct vc_data *vc); - void (*con_clear)(struct vc_data *vc, int sy, int sx, int height, - int width); + void (*con_clear)(struct vc_data *vc, unsigned int y, + unsigned int x, unsigned int count); void (*con_putc)(struct vc_data *vc, int c, int ypos, int xpos); void (*con_putcs)(struct vc_data *vc, const unsigned short *s, int count, int ypos, int xpos); From 3ab8a651934f7b18b6716765df3c32391549cf01 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:36 +0100 Subject: [PATCH 022/199] tty: vt: remove checks for count in consw::con_clear() implementations 'count' in consw::con_clear() is guaranteed to be positive. csi_X() (the only caller) takes the minimum of the vc parameter (which is at least 1) and count of characters till the end of the line. The latter is computed as a subtraction of vc->vc_cols (count) and vc->state.x (offset). So for the worst case, full line, it is 1. Therefore, there is no point in checking zero or negative values (width is now unsigned anyway). Signed-off-by: "Jiri Slaby (SUSE)" Cc: Helge Deller Cc: "James E.J. Bottomley" Cc: linux-fbdev@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Cc: linux-parisc@vger.kernel.org Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-23-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/video/console/mdacon.c | 3 --- drivers/video/console/sticon.c | 3 --- 2 files changed, 6 deletions(-) diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index 1ddbb6cd5b0c..2ff2c9394d40 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c @@ -448,9 +448,6 @@ static void mdacon_clear(struct vc_data *c, unsigned int y, unsigned int x, u16 *dest = mda_addr(x, y); u16 eattr = mda_convert_attr(c->vc_video_erase_char); - if (width <= 0) - return; - scr_memsetw(dest, eattr, width * 2); } diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index d99c2a659bfd..b1d972d9a31c 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c @@ -303,9 +303,6 @@ static void sticon_deinit(struct vc_data *c) static void sticon_clear(struct vc_data *conp, unsigned int sy, unsigned int sx, unsigned int width) { - if (!width) - return; - sti_clear(sticon_sti, sy, sx, 1, width, conp->vc_video_erase_char, font_data[conp->vc_num]); } From 387ccbdb634fc6572b02dc38ef0d1c8a80606314 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:37 +0100 Subject: [PATCH 023/199] tty: vt: add con_putc() helper And let it call consw::con_putc() if it exists, otherwise consw::con_putcs(). This is similar to tty_put_char(). It supports dropping unneeded duplication of code like sticon_putc() is (see the next patch). Signed-off-by: "Jiri Slaby (SUSE)" Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-24-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index b6f1449421bc..6091ffcf93d8 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -300,6 +300,14 @@ static inline unsigned short *screenpos(const struct vc_data *vc, int offset, return p; } +static void con_putc(struct vc_data *vc, u16 ca, unsigned int y, unsigned int x) +{ + if (vc->vc_sw->con_putc) + vc->vc_sw->con_putc(vc, ca, y, x); + else + vc->vc_sw->con_putcs(vc, &ca, 1, y, x); +} + /* Called from the keyboard irq path.. */ static inline void scrolldelta(int lines) { @@ -762,7 +770,7 @@ void complement_pos(struct vc_data *vc, int offset) old_offset < vc->vc_screenbuf_size) { scr_writew(old, screenpos(vc, old_offset, true)); if (con_should_update(vc)) - vc->vc_sw->con_putc(vc, old, oldy, oldx); + con_putc(vc, old, oldy, oldx); notify_update(vc); } @@ -779,7 +787,7 @@ void complement_pos(struct vc_data *vc, int offset) if (con_should_update(vc)) { oldx = (offset >> 1) % vc->vc_cols; oldy = (offset >> 1) / vc->vc_cols; - vc->vc_sw->con_putc(vc, new, oldy, oldx); + con_putc(vc, new, oldy, oldx); } notify_update(vc); } @@ -833,7 +841,7 @@ static void add_softcursor(struct vc_data *vc) i ^= CUR_FG; scr_writew(i, (u16 *)vc->vc_pos); if (con_should_update(vc)) - vc->vc_sw->con_putc(vc, i, vc->state.y, vc->state.x); + con_putc(vc, i, vc->state.y, vc->state.x); } static void hide_softcursor(struct vc_data *vc) @@ -841,8 +849,8 @@ static void hide_softcursor(struct vc_data *vc) if (softcursor_original != -1) { scr_writew(softcursor_original, (u16 *)vc->vc_pos); if (con_should_update(vc)) - vc->vc_sw->con_putc(vc, softcursor_original, - vc->state.y, vc->state.x); + con_putc(vc, softcursor_original, vc->state.y, + vc->state.x); softcursor_original = -1; } } From 8bc03a30093024c68f10fb9033ca28f925074c52 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:38 +0100 Subject: [PATCH 024/199] tty: vt: eliminate unneeded consw::con_putc() implementations All these consw::con_putc() implementations do the same as consw::con_putcs() (only for one charattr) or even call consw::con_putcs() on their own. Drop them, as thanks to the new con_putc() helper in the previous patch, the console code performs this already -- exactly if consw::con_putc() is missing (NULL). Signed-off-by: "Jiri Slaby (SUSE)" Cc: Helge Deller Cc: "James E.J. Bottomley" Cc: Daniel Vetter Cc: linux-fbdev@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Cc: linux-parisc@vger.kernel.org Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-25-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/video/console/mdacon.c | 6 ------ drivers/video/console/sticon.c | 12 ------------ drivers/video/console/vgacon.c | 2 -- drivers/video/fbdev/core/fbcon.c | 9 --------- 4 files changed, 29 deletions(-) diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index 2ff2c9394d40..01e779943c00 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c @@ -427,11 +427,6 @@ static inline u16 *mda_addr(unsigned int x, unsigned int y) return mda_vram_base + y * mda_num_columns + x; } -static void mdacon_putc(struct vc_data *c, int ch, int y, int x) -{ - scr_writew(mda_convert_attr(ch), mda_addr(x, y)); -} - static void mdacon_putcs(struct vc_data *c, const unsigned short *s, int count, int y, int x) { @@ -536,7 +531,6 @@ static const struct consw mda_con = { .con_init = mdacon_init, .con_deinit = mdacon_deinit, .con_clear = mdacon_clear, - .con_putc = mdacon_putc, .con_putcs = mdacon_putcs, .con_cursor = mdacon_cursor, .con_scroll = mdacon_scroll, diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index b1d972d9a31c..2f87b5909d0d 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c @@ -71,17 +71,6 @@ static const char *sticon_startup(void) return "STI console"; } -static void sticon_putc(struct vc_data *conp, int c, int ypos, int xpos) -{ - if (vga_is_gfx || console_blanked) - return; - - if (conp->vc_mode != KD_TEXT) - return; - - sti_putc(sticon_sti, c, ypos, xpos, font_data[conp->vc_num]); -} - static void sticon_putcs(struct vc_data *conp, const unsigned short *s, int count, int ypos, int xpos) { @@ -362,7 +351,6 @@ static const struct consw sti_con = { .con_init = sticon_init, .con_deinit = sticon_deinit, .con_clear = sticon_clear, - .con_putc = sticon_putc, .con_putcs = sticon_putcs, .con_cursor = sticon_cursor, .con_scroll = sticon_scroll, diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 85f29dec2c3d..4beab11f87eb 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -1193,7 +1193,6 @@ static bool vgacon_scroll(struct vc_data *c, unsigned int t, unsigned int b, static void vgacon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx, unsigned int width) { } -static void vgacon_putc(struct vc_data *vc, int c, int ypos, int xpos) { } static void vgacon_putcs(struct vc_data *vc, const unsigned short *s, int count, int ypos, int xpos) { } @@ -1203,7 +1202,6 @@ const struct consw vga_con = { .con_init = vgacon_init, .con_deinit = vgacon_deinit, .con_clear = vgacon_clear, - .con_putc = vgacon_putc, .con_putcs = vgacon_putcs, .con_cursor = vgacon_cursor, .con_scroll = vgacon_scroll, diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index 8a31a36483ea..38de0f8723aa 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -1292,14 +1292,6 @@ static void fbcon_putcs(struct vc_data *vc, const unsigned short *s, get_color(vc, info, scr_readw(s), 0)); } -static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos) -{ - unsigned short chr; - - scr_writew(c, &chr); - fbcon_putcs(vc, &chr, 1, ypos, xpos); -} - static void fbcon_clear_margins(struct vc_data *vc, int bottom_only) { struct fb_info *info = fbcon_info_from_console(vc->vc_num); @@ -3159,7 +3151,6 @@ static const struct consw fb_con = { .con_init = fbcon_init, .con_deinit = fbcon_deinit, .con_clear = fbcon_clear, - .con_putc = fbcon_putc, .con_putcs = fbcon_putcs, .con_cursor = fbcon_cursor, .con_scroll = fbcon_scroll, From 338c28107b51083846afdc5fe8f7830cc8abd893 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:39 +0100 Subject: [PATCH 025/199] tty: vt: sanitize consw::con_putc() parameters Make parameters of consw::con_putc() saner: * x and y are unsigned now, as they cannot be negative, and * ca is made u16, as it is composed of two 8bit values (character and attribute). See the con_putcs() hook, u16/ushort is worked on there. And document the hook. Signed-off-by: "Jiri Slaby (SUSE)" Cc: Helge Deller Cc: linux-fbdev@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-26-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/video/console/dummycon.c | 6 ++++-- drivers/video/console/newport_con.c | 4 ++-- include/linux/console.h | 5 ++++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c index 0a69d5c216ee..1874beed0325 100644 --- a/drivers/video/console/dummycon.c +++ b/drivers/video/console/dummycon.c @@ -50,7 +50,8 @@ void dummycon_unregister_output_notifier(struct notifier_block *nb) raw_notifier_chain_unregister(&dummycon_output_nh, nb); } -static void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos) +static void dummycon_putc(struct vc_data *vc, u16 c, unsigned int y, + unsigned int x) { WARN_CONSOLE_UNLOCKED(); @@ -84,7 +85,8 @@ static int dummycon_blank(struct vc_data *vc, int blank, int mode_switch) return 1; } #else -static void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos) { } +static void dummycon_putc(struct vc_data *vc, u16 c, unsigned int y, + unsigned int x) { } static void dummycon_putcs(struct vc_data *vc, const unsigned short *s, int count, int ypos, int xpos) { } static int dummycon_blank(struct vc_data *vc, int blank, int mode_switch) diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index 55c6106b3507..9b5c0118873e 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -367,8 +367,8 @@ static void newport_clear(struct vc_data *vc, unsigned int sy, unsigned int sx, } } -static void newport_putc(struct vc_data *vc, int charattr, int ypos, - int xpos) +static void newport_putc(struct vc_data *vc, u16 charattr, unsigned int ypos, + unsigned int xpos) { unsigned char *p; diff --git a/include/linux/console.h b/include/linux/console.h index 8fd96a5fca5f..92d57e5b3009 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -39,6 +39,8 @@ enum vc_intensity; * @con_init: initialize the console on @vc. @init is true for the very first * call on this @vc. * @con_clear: erase @count characters at [@x, @y] on @vc. @count >= 1. + * @con_putc: emit one character with attributes @ca to [@x, @y] on @vc. + * (optional -- @con_putcs would be called instead) * @con_scroll: move lines from @top to @bottom in direction @dir by @lines. * Return true if no generic handling should be done. * Invoked by csi_M and printing to the console. @@ -53,7 +55,8 @@ struct consw { void (*con_deinit)(struct vc_data *vc); void (*con_clear)(struct vc_data *vc, unsigned int y, unsigned int x, unsigned int count); - void (*con_putc)(struct vc_data *vc, int c, int ypos, int xpos); + void (*con_putc)(struct vc_data *vc, u16 ca, unsigned int y, + unsigned int x); void (*con_putcs)(struct vc_data *vc, const unsigned short *s, int count, int ypos, int xpos); void (*con_cursor)(struct vc_data *vc, int mode); From bfd7de49d7444ce46a48e92ce7cb11266ce79905 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:40 +0100 Subject: [PATCH 026/199] tty: vt: sanitize consw::con_putcs() parameters Similar to con_putc() in the previous patch: * make the pointer to charattr a pointer to u16, and * make x, y, and count unsigned as they are strictly non-negative. And again, document that hook. Signed-off-by: "Jiri Slaby (SUSE)" Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-27-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/video/console/dummycon.c | 10 +++++----- drivers/video/console/mdacon.c | 4 ++-- drivers/video/console/newport_con.c | 9 +++++---- drivers/video/console/sticon.c | 4 ++-- drivers/video/console/vgacon.c | 4 ++-- drivers/video/fbdev/core/fbcon.c | 4 ++-- include/linux/console.h | 6 ++++-- 7 files changed, 22 insertions(+), 19 deletions(-) diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c index 1874beed0325..188d9f3e201c 100644 --- a/drivers/video/console/dummycon.c +++ b/drivers/video/console/dummycon.c @@ -59,10 +59,10 @@ static void dummycon_putc(struct vc_data *vc, u16 c, unsigned int y, raw_notifier_call_chain(&dummycon_output_nh, 0, NULL); } -static void dummycon_putcs(struct vc_data *vc, const unsigned short *s, - int count, int ypos, int xpos) +static void dummycon_putcs(struct vc_data *vc, const u16 *s, unsigned int count, + unsigned int ypos, unsigned int xpos) { - int i; + unsigned int i; if (!dummycon_putc_called) { /* Ignore erases */ @@ -87,8 +87,8 @@ static int dummycon_blank(struct vc_data *vc, int blank, int mode_switch) #else static void dummycon_putc(struct vc_data *vc, u16 c, unsigned int y, unsigned int x) { } -static void dummycon_putcs(struct vc_data *vc, const unsigned short *s, - int count, int ypos, int xpos) { } +static void dummycon_putcs(struct vc_data *vc, const u16 *s, unsigned int count, + unsigned int ypos, unsigned int xpos) { } static int dummycon_blank(struct vc_data *vc, int blank, int mode_switch) { return 0; diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index 01e779943c00..b8822b615b2f 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c @@ -427,8 +427,8 @@ static inline u16 *mda_addr(unsigned int x, unsigned int y) return mda_vram_base + y * mda_num_columns + x; } -static void mdacon_putcs(struct vc_data *c, const unsigned short *s, - int count, int y, int x) +static void mdacon_putcs(struct vc_data *c, const u16 *s, unsigned int count, + unsigned int y, unsigned int x) { u16 *dest = mda_addr(x, y); diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index 9b5c0118873e..5e65ee0b7c07 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -396,12 +396,13 @@ static void newport_putc(struct vc_data *vc, u16 charattr, unsigned int ypos, RENDER(npregs, p); } -static void newport_putcs(struct vc_data *vc, const unsigned short *s, - int count, int ypos, int xpos) +static void newport_putcs(struct vc_data *vc, const u16 *s, + unsigned int count, unsigned int ypos, + unsigned int xpos) { - int i; - int charattr; unsigned char *p; + unsigned int i; + u16 charattr; charattr = (scr_readw(s) >> 8) & 0xff; diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index 2f87b5909d0d..906da1fde7c8 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c @@ -71,8 +71,8 @@ static const char *sticon_startup(void) return "STI console"; } -static void sticon_putcs(struct vc_data *conp, const unsigned short *s, - int count, int ypos, int xpos) +static void sticon_putcs(struct vc_data *conp, const u16 *s, unsigned int count, + unsigned int ypos, unsigned int xpos) { if (vga_is_gfx || console_blanked) return; diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 4beab11f87eb..aa0589085847 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -1193,8 +1193,8 @@ static bool vgacon_scroll(struct vc_data *c, unsigned int t, unsigned int b, static void vgacon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx, unsigned int width) { } -static void vgacon_putcs(struct vc_data *vc, const unsigned short *s, - int count, int ypos, int xpos) { } +static void vgacon_putcs(struct vc_data *vc, const u16 *s, unsigned int count, + unsigned int ypos, unsigned int xpos) { } const struct consw vga_con = { .owner = THIS_MODULE, diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index 38de0f8723aa..7a7b2ac0d7a9 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -1279,8 +1279,8 @@ static void fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx, __fbcon_clear(vc, sy, sx, 1, width); } -static void fbcon_putcs(struct vc_data *vc, const unsigned short *s, - int count, int ypos, int xpos) +static void fbcon_putcs(struct vc_data *vc, const u16 *s, unsigned int count, + unsigned int ypos, unsigned int xpos) { struct fb_info *info = fbcon_info_from_console(vc->vc_num); struct fbcon_display *p = &fb_display[vc->vc_num]; diff --git a/include/linux/console.h b/include/linux/console.h index 92d57e5b3009..82d55764a66f 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -41,6 +41,7 @@ enum vc_intensity; * @con_clear: erase @count characters at [@x, @y] on @vc. @count >= 1. * @con_putc: emit one character with attributes @ca to [@x, @y] on @vc. * (optional -- @con_putcs would be called instead) + * @con_putcs: emit @count characters with attributes @s to [@x, @y] on @vc. * @con_scroll: move lines from @top to @bottom in direction @dir by @lines. * Return true if no generic handling should be done. * Invoked by csi_M and printing to the console. @@ -57,8 +58,9 @@ struct consw { unsigned int x, unsigned int count); void (*con_putc)(struct vc_data *vc, u16 ca, unsigned int y, unsigned int x); - void (*con_putcs)(struct vc_data *vc, const unsigned short *s, - int count, int ypos, int xpos); + void (*con_putcs)(struct vc_data *vc, const u16 *s, + unsigned int count, unsigned int ypos, + unsigned int xpos); void (*con_cursor)(struct vc_data *vc, int mode); bool (*con_scroll)(struct vc_data *vc, unsigned int top, unsigned int bottom, enum con_scroll dir, From 7c5337c9ead8099e310ae38738f956adef41146e Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:41 +0100 Subject: [PATCH 027/199] consoles: use if instead of switch-case in consw::con_cursor() This is only a preparation for the following cleanup patch to make it easier. Provided CM_ERASE is the only different, use 'if' instead of 'switch+case' in all those. Signed-off-by: "Jiri Slaby (SUSE)" Cc: Helge Deller Cc: linux-fbdev@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-28-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/video/console/newport_con.c | 26 +++++------- drivers/video/console/sticon.c | 27 ++++++------ drivers/video/console/vgacon.c | 66 +++++++++++++---------------- 3 files changed, 53 insertions(+), 66 deletions(-) diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index 5e65ee0b7c07..f852717b88f0 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -443,24 +443,20 @@ static void newport_cursor(struct vc_data *vc, int mode) unsigned short treg; int xcurs, ycurs; - switch (mode) { - case CM_ERASE: - treg = newport_vc2_get(npregs, VC2_IREG_CONTROL); + treg = newport_vc2_get(npregs, VC2_IREG_CONTROL); + + if (mode == CM_ERASE) { newport_vc2_set(npregs, VC2_IREG_CONTROL, (treg & ~(VC2_CTRL_ECDISP))); - break; - - case CM_MOVE: - case CM_DRAW: - treg = newport_vc2_get(npregs, VC2_IREG_CONTROL); - newport_vc2_set(npregs, VC2_IREG_CONTROL, - (treg | VC2_CTRL_ECDISP)); - xcurs = (vc->vc_pos - vc->vc_visible_origin) / 2; - ycurs = ((xcurs / vc->vc_cols) << 4) + 31; - xcurs = ((xcurs % vc->vc_cols) << 3) + xcurs_correction; - newport_vc2_set(npregs, VC2_IREG_CURSX, xcurs); - newport_vc2_set(npregs, VC2_IREG_CURSY, ycurs); + return; } + + newport_vc2_set(npregs, VC2_IREG_CONTROL, (treg | VC2_CTRL_ECDISP)); + xcurs = (vc->vc_pos - vc->vc_visible_origin) / 2; + ycurs = ((xcurs / vc->vc_cols) << 4) + 31; + xcurs = ((xcurs % vc->vc_cols) << 3) + xcurs_correction; + newport_vc2_set(npregs, VC2_IREG_CURSX, xcurs); + newport_vc2_set(npregs, VC2_IREG_CURSY, ycurs); } static int newport_switch(struct vc_data *vc) diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index 906da1fde7c8..42480874db00 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c @@ -95,23 +95,20 @@ static void sticon_cursor(struct vc_data *conp, int mode) return; car1 = conp->vc_screenbuf[conp->state.x + conp->state.y * conp->vc_cols]; - switch (mode) { - case CM_ERASE: + if (mode == CM_ERASE) { sti_putc(sticon_sti, car1, conp->state.y, conp->state.x, font_data[conp->vc_num]); - break; - case CM_MOVE: - case CM_DRAW: - switch (CUR_SIZE(conp->vc_cursor_type)) { - case CUR_UNDERLINE: - case CUR_LOWER_THIRD: - case CUR_LOWER_HALF: - case CUR_TWO_THIRDS: - case CUR_BLOCK: - sti_putc(sticon_sti, (car1 & 255) + (0 << 8) + (7 << 11), - conp->state.y, conp->state.x, font_data[conp->vc_num]); - break; - } + return; + } + + switch (CUR_SIZE(conp->vc_cursor_type)) { + case CUR_UNDERLINE: + case CUR_LOWER_THIRD: + case CUR_LOWER_HALF: + case CUR_TWO_THIRDS: + case CUR_BLOCK: + sti_putc(sticon_sti, (car1 & 255) + (0 << 8) + (7 << 11), + conp->state.y, conp->state.x, font_data[conp->vc_num]); break; } } diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index aa0589085847..82d01a9ccd6d 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -514,47 +514,41 @@ static void vgacon_cursor(struct vc_data *c, int mode) c_height = c->vc_cell_height; - switch (mode) { - case CM_ERASE: - write_vga(14, (c->vc_pos - vga_vram_base) / 2); + write_vga(14, (c->vc_pos - vga_vram_base) / 2); + + if (mode == CM_ERASE) { if (vga_video_type >= VIDEO_TYPE_VGAC) vgacon_set_cursor_size(31, 30); else vgacon_set_cursor_size(31, 31); - break; + return; + } - case CM_MOVE: - case CM_DRAW: - write_vga(14, (c->vc_pos - vga_vram_base) / 2); - switch (CUR_SIZE(c->vc_cursor_type)) { - case CUR_UNDERLINE: - vgacon_set_cursor_size(c_height - - (c_height < 10 ? 2 : 3), - c_height - - (c_height < 10 ? 1 : 2)); - break; - case CUR_TWO_THIRDS: - vgacon_set_cursor_size(c_height / 3, c_height - - (c_height < 10 ? 1 : 2)); - break; - case CUR_LOWER_THIRD: - vgacon_set_cursor_size(c_height * 2 / 3, c_height - - (c_height < 10 ? 1 : 2)); - break; - case CUR_LOWER_HALF: - vgacon_set_cursor_size(c_height / 2, c_height - - (c_height < 10 ? 1 : 2)); - break; - case CUR_NONE: - if (vga_video_type >= VIDEO_TYPE_VGAC) - vgacon_set_cursor_size(31, 30); - else - vgacon_set_cursor_size(31, 31); - break; - default: - vgacon_set_cursor_size(1, c_height); - break; - } + switch (CUR_SIZE(c->vc_cursor_type)) { + case CUR_UNDERLINE: + vgacon_set_cursor_size(c_height - (c_height < 10 ? 2 : 3), + c_height - (c_height < 10 ? 1 : 2)); + break; + case CUR_TWO_THIRDS: + vgacon_set_cursor_size(c_height / 3, + c_height - (c_height < 10 ? 1 : 2)); + break; + case CUR_LOWER_THIRD: + vgacon_set_cursor_size(c_height * 2 / 3, + c_height - (c_height < 10 ? 1 : 2)); + break; + case CUR_LOWER_HALF: + vgacon_set_cursor_size(c_height / 2, + c_height - (c_height < 10 ? 1 : 2)); + break; + case CUR_NONE: + if (vga_video_type >= VIDEO_TYPE_VGAC) + vgacon_set_cursor_size(31, 30); + else + vgacon_set_cursor_size(31, 31); + break; + default: + vgacon_set_cursor_size(1, c_height); break; } } From 9aefbaeb30abc3fc8c456920464ddbdd5d0a5786 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:42 +0100 Subject: [PATCH 028/199] fbdev/core: simplify cursor_state setting in fbcon_ops::cursor() There is a switch decicing if cursor should be drawn or not. The whole switch can be simplified to one line. Do this cleanup as a preparatory work for the next patch. There, all the CM_* constants are removed. Signed-off-by: "Jiri Slaby (SUSE)" Cc: Daniel Vetter Cc: Helge Deller Cc: linux-fbdev@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-29-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/video/fbdev/core/bitblit.c | 11 +---------- drivers/video/fbdev/core/fbcon_ccw.c | 11 +---------- drivers/video/fbdev/core/fbcon_cw.c | 11 +---------- drivers/video/fbdev/core/fbcon_ud.c | 11 +---------- 4 files changed, 4 insertions(+), 40 deletions(-) diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c index 8587c9da0670..daff152f4c22 100644 --- a/drivers/video/fbdev/core/bitblit.c +++ b/drivers/video/fbdev/core/bitblit.c @@ -348,16 +348,7 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode, mask[i++] = msk; } - switch (mode) { - case CM_ERASE: - ops->cursor_state.enable = 0; - break; - case CM_DRAW: - case CM_MOVE: - default: - ops->cursor_state.enable = (use_sw) ? 0 : 1; - break; - } + ops->cursor_state.enable = (mode != CM_ERASE) && !use_sw; cursor.image.data = src; cursor.image.fg_color = ops->cursor_state.image.fg_color; diff --git a/drivers/video/fbdev/core/fbcon_ccw.c b/drivers/video/fbdev/core/fbcon_ccw.c index 2789ace79634..889423d580bc 100644 --- a/drivers/video/fbdev/core/fbcon_ccw.c +++ b/drivers/video/fbdev/core/fbcon_ccw.c @@ -349,16 +349,7 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode, kfree(tmp); } - switch (mode) { - case CM_ERASE: - ops->cursor_state.enable = 0; - break; - case CM_DRAW: - case CM_MOVE: - default: - ops->cursor_state.enable = (use_sw) ? 0 : 1; - break; - } + ops->cursor_state.enable = (mode != CM_ERASE) && !use_sw; cursor.image.data = src; cursor.image.fg_color = ops->cursor_state.image.fg_color; diff --git a/drivers/video/fbdev/core/fbcon_cw.c b/drivers/video/fbdev/core/fbcon_cw.c index 86a254c1b2b7..a306ca5802e8 100644 --- a/drivers/video/fbdev/core/fbcon_cw.c +++ b/drivers/video/fbdev/core/fbcon_cw.c @@ -332,16 +332,7 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode, kfree(tmp); } - switch (mode) { - case CM_ERASE: - ops->cursor_state.enable = 0; - break; - case CM_DRAW: - case CM_MOVE: - default: - ops->cursor_state.enable = (use_sw) ? 0 : 1; - break; - } + ops->cursor_state.enable = (mode != CM_ERASE) && !use_sw; cursor.image.data = src; cursor.image.fg_color = ops->cursor_state.image.fg_color; diff --git a/drivers/video/fbdev/core/fbcon_ud.c b/drivers/video/fbdev/core/fbcon_ud.c index 23bc045769d0..f6fc458b46c7 100644 --- a/drivers/video/fbdev/core/fbcon_ud.c +++ b/drivers/video/fbdev/core/fbcon_ud.c @@ -372,16 +372,7 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode, mask[i++] = ~msk; } - switch (mode) { - case CM_ERASE: - ops->cursor_state.enable = 0; - break; - case CM_DRAW: - case CM_MOVE: - default: - ops->cursor_state.enable = (use_sw) ? 0 : 1; - break; - } + ops->cursor_state.enable = (mode != CM_ERASE) && !use_sw; cursor.image.data = src; cursor.image.fg_color = ops->cursor_state.image.fg_color; From a292e3fc94cb9795bbba4ddac075a9055cd58a5e Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:43 +0100 Subject: [PATCH 029/199] tty: vt: remove CM_* constants There is no difference between CM_MOVE and CM_DRAW. Either of them enables the cursor. CM_ERASE then disables cursor. So get rid of all of them and use simple "bool enable". Note that this propagates down to the fbcon code. And document the hook. Signed-off-by: "Jiri Slaby (SUSE)" Cc: Helge Deller Cc: "James E.J. Bottomley" Cc: Daniel Vetter Cc: linux-fbdev@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Cc: linux-parisc@vger.kernel.org Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-30-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 4 ++-- drivers/video/console/dummycon.c | 2 +- drivers/video/console/mdacon.c | 4 ++-- drivers/video/console/newport_con.c | 4 ++-- drivers/video/console/sticon.c | 6 +++--- drivers/video/console/vgacon.c | 6 +++--- drivers/video/fbdev/core/bitblit.c | 4 ++-- drivers/video/fbdev/core/fbcon.c | 19 +++++++++---------- drivers/video/fbdev/core/fbcon.h | 4 ++-- drivers/video/fbdev/core/fbcon_ccw.c | 4 ++-- drivers/video/fbdev/core/fbcon_cw.c | 4 ++-- drivers/video/fbdev/core/fbcon_ud.c | 4 ++-- drivers/video/fbdev/core/tileblit.c | 4 ++-- include/linux/console.h | 8 ++------ 14 files changed, 36 insertions(+), 41 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 6091ffcf93d8..e4edcaf9d0a3 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -860,7 +860,7 @@ static void hide_cursor(struct vc_data *vc) if (vc_is_sel(vc)) clear_selection(); - vc->vc_sw->con_cursor(vc, CM_ERASE); + vc->vc_sw->con_cursor(vc, false); hide_softcursor(vc); } @@ -873,7 +873,7 @@ static void set_cursor(struct vc_data *vc) clear_selection(); add_softcursor(vc); if (CUR_SIZE(vc->vc_cursor_type) != CUR_NONE) - vc->vc_sw->con_cursor(vc, CM_DRAW); + vc->vc_sw->con_cursor(vc, true); } else hide_cursor(vc); } diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c index 188d9f3e201c..1171e27edef7 100644 --- a/drivers/video/console/dummycon.c +++ b/drivers/video/console/dummycon.c @@ -113,7 +113,7 @@ static void dummycon_init(struct vc_data *vc, bool init) static void dummycon_deinit(struct vc_data *vc) { } static void dummycon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx, unsigned int width) { } -static void dummycon_cursor(struct vc_data *vc, int mode) { } +static void dummycon_cursor(struct vc_data *vc, bool enable) { } static bool dummycon_scroll(struct vc_data *vc, unsigned int top, unsigned int bottom, enum con_scroll dir, diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index b8822b615b2f..bc851a1d9f4d 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c @@ -470,9 +470,9 @@ static int mdacon_blank(struct vc_data *c, int blank, int mode_switch) } } -static void mdacon_cursor(struct vc_data *c, int mode) +static void mdacon_cursor(struct vc_data *c, bool enable) { - if (mode == CM_ERASE) { + if (!enable) { mda_set_cursor(mda_vram_len - 1); return; } diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index f852717b88f0..e35406dea7c7 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -438,14 +438,14 @@ static void newport_putcs(struct vc_data *vc, const u16 *s, } } -static void newport_cursor(struct vc_data *vc, int mode) +static void newport_cursor(struct vc_data *vc, bool enable) { unsigned short treg; int xcurs, ycurs; treg = newport_vc2_get(npregs, VC2_IREG_CONTROL); - if (mode == CM_ERASE) { + if (!enable) { newport_vc2_set(npregs, VC2_IREG_CONTROL, (treg & ~(VC2_CTRL_ECDISP))); return; diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index 42480874db00..786e1b3a98ea 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c @@ -86,7 +86,7 @@ static void sticon_putcs(struct vc_data *conp, const u16 *s, unsigned int count, } } -static void sticon_cursor(struct vc_data *conp, int mode) +static void sticon_cursor(struct vc_data *conp, bool enable) { unsigned short car1; @@ -95,7 +95,7 @@ static void sticon_cursor(struct vc_data *conp, int mode) return; car1 = conp->vc_screenbuf[conp->state.x + conp->state.y * conp->vc_cols]; - if (mode == CM_ERASE) { + if (!enable) { sti_putc(sticon_sti, car1, conp->state.y, conp->state.x, font_data[conp->vc_num]); return; @@ -121,7 +121,7 @@ static bool sticon_scroll(struct vc_data *conp, unsigned int t, if (vga_is_gfx) return false; - sticon_cursor(conp, CM_ERASE); + sticon_cursor(conp, false); switch (dir) { case SM_UP: diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 82d01a9ccd6d..d93eb15da435 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -503,7 +503,7 @@ static void vgacon_set_cursor_size(int from, int to) raw_spin_unlock_irqrestore(&vga_lock, flags); } -static void vgacon_cursor(struct vc_data *c, int mode) +static void vgacon_cursor(struct vc_data *c, bool enable) { unsigned int c_height; @@ -516,7 +516,7 @@ static void vgacon_cursor(struct vc_data *c, int mode) write_vga(14, (c->vc_pos - vga_vram_base) / 2); - if (mode == CM_ERASE) { + if (!enable) { if (vga_video_type >= VIDEO_TYPE_VGAC) vgacon_set_cursor_size(31, 30); else @@ -1030,7 +1030,7 @@ static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight) /* void size to cause regs to be rewritten */ cursor_size_lastfrom = 0; cursor_size_lastto = 0; - c->vc_sw->con_cursor(c, CM_DRAW); + c->vc_sw->con_cursor(c, true); } c->vc_font.height = c->vc_cell_height = fontheight; vc_resize(c, 0, rows); /* Adjust console size */ diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c index daff152f4c22..3ff1b2a8659e 100644 --- a/drivers/video/fbdev/core/bitblit.c +++ b/drivers/video/fbdev/core/bitblit.c @@ -233,7 +233,7 @@ static void bit_clear_margins(struct vc_data *vc, struct fb_info *info, } } -static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode, +static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable, int fg, int bg) { struct fb_cursor cursor; @@ -348,7 +348,7 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode, mask[i++] = msk; } - ops->cursor_state.enable = (mode != CM_ERASE) && !use_sw; + ops->cursor_state.enable = enable && !use_sw; cursor.image.data = src; cursor.image.fg_color = ops->cursor_state.image.fg_color; diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index 7a7b2ac0d7a9..c1765a6ef490 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -351,7 +351,7 @@ static void fb_flashcursor(struct work_struct *work) struct fb_info *info; struct vc_data *vc = NULL; int c; - int mode; + bool enable; int ret; /* FIXME: we should sort out the unbind locking instead */ @@ -375,9 +375,8 @@ static void fb_flashcursor(struct work_struct *work) } c = scr_readw((u16 *) vc->vc_pos); - mode = (!ops->cursor_flash || ops->cursor_state.enable) ? - CM_ERASE : CM_DRAW; - ops->cursor(vc, info, mode, get_color(vc, info, c, 1), + enable = ops->cursor_flash && !ops->cursor_state.enable; + ops->cursor(vc, info, enable, get_color(vc, info, c, 1), get_color(vc, info, c, 0)); console_unlock(); @@ -1301,7 +1300,7 @@ static void fbcon_clear_margins(struct vc_data *vc, int bottom_only) ops->clear_margins(vc, info, margin_color, bottom_only); } -static void fbcon_cursor(struct vc_data *vc, int mode) +static void fbcon_cursor(struct vc_data *vc, bool enable) { struct fb_info *info = fbcon_info_from_console(vc->vc_num); struct fbcon_ops *ops = info->fbcon_par; @@ -1317,12 +1316,12 @@ static void fbcon_cursor(struct vc_data *vc, int mode) else fbcon_add_cursor_work(info); - ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1; + ops->cursor_flash = enable; if (!ops->cursor) return; - ops->cursor(vc, info, mode, get_color(vc, info, c, 1), + ops->cursor(vc, info, enable, get_color(vc, info, c, 1), get_color(vc, info, c, 0)); } @@ -1742,7 +1741,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b, if (fbcon_is_inactive(vc, info)) return true; - fbcon_cursor(vc, CM_ERASE); + fbcon_cursor(vc, false); /* * ++Geert: Only use ywrap/ypan if the console is in text mode @@ -2221,7 +2220,7 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch) if (!fbcon_is_inactive(vc, info)) { if (ops->blank_state != blank) { ops->blank_state = blank; - fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW); + fbcon_cursor(vc, !blank); ops->cursor_flash = (!blank); if (fb_blank(info, blank)) @@ -2649,7 +2648,7 @@ void fbcon_suspended(struct fb_info *info) vc = vc_cons[ops->currcon].d; /* Clear cursor, restore saved data */ - fbcon_cursor(vc, CM_ERASE); + fbcon_cursor(vc, false); } void fbcon_resumed(struct fb_info *info) diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h index 0eaf54a21151..df70ea5ec5b3 100644 --- a/drivers/video/fbdev/core/fbcon.h +++ b/drivers/video/fbdev/core/fbcon.h @@ -61,8 +61,8 @@ struct fbcon_ops { int fg, int bg); void (*clear_margins)(struct vc_data *vc, struct fb_info *info, int color, int bottom_only); - void (*cursor)(struct vc_data *vc, struct fb_info *info, int mode, - int fg, int bg); + void (*cursor)(struct vc_data *vc, struct fb_info *info, + bool enable, int fg, int bg); int (*update_start)(struct fb_info *info); int (*rotate_font)(struct fb_info *info, struct vc_data *vc); struct fb_var_screeninfo var; /* copy of the current fb_var_screeninfo */ diff --git a/drivers/video/fbdev/core/fbcon_ccw.c b/drivers/video/fbdev/core/fbcon_ccw.c index 889423d580bc..f9b794ff7d39 100644 --- a/drivers/video/fbdev/core/fbcon_ccw.c +++ b/drivers/video/fbdev/core/fbcon_ccw.c @@ -218,7 +218,7 @@ static void ccw_clear_margins(struct vc_data *vc, struct fb_info *info, } } -static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode, +static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable, int fg, int bg) { struct fb_cursor cursor; @@ -349,7 +349,7 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode, kfree(tmp); } - ops->cursor_state.enable = (mode != CM_ERASE) && !use_sw; + ops->cursor_state.enable = enable && !use_sw; cursor.image.data = src; cursor.image.fg_color = ops->cursor_state.image.fg_color; diff --git a/drivers/video/fbdev/core/fbcon_cw.c b/drivers/video/fbdev/core/fbcon_cw.c index a306ca5802e8..903f6fc174e1 100644 --- a/drivers/video/fbdev/core/fbcon_cw.c +++ b/drivers/video/fbdev/core/fbcon_cw.c @@ -201,7 +201,7 @@ static void cw_clear_margins(struct vc_data *vc, struct fb_info *info, } } -static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode, +static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable, int fg, int bg) { struct fb_cursor cursor; @@ -332,7 +332,7 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode, kfree(tmp); } - ops->cursor_state.enable = (mode != CM_ERASE) && !use_sw; + ops->cursor_state.enable = enable && !use_sw; cursor.image.data = src; cursor.image.fg_color = ops->cursor_state.image.fg_color; diff --git a/drivers/video/fbdev/core/fbcon_ud.c b/drivers/video/fbdev/core/fbcon_ud.c index f6fc458b46c7..594331936fd3 100644 --- a/drivers/video/fbdev/core/fbcon_ud.c +++ b/drivers/video/fbdev/core/fbcon_ud.c @@ -248,7 +248,7 @@ static void ud_clear_margins(struct vc_data *vc, struct fb_info *info, } } -static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode, +static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable, int fg, int bg) { struct fb_cursor cursor; @@ -372,7 +372,7 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode, mask[i++] = ~msk; } - ops->cursor_state.enable = (mode != CM_ERASE) && !use_sw; + ops->cursor_state.enable = enable && !use_sw; cursor.image.data = src; cursor.image.fg_color = ops->cursor_state.image.fg_color; diff --git a/drivers/video/fbdev/core/tileblit.c b/drivers/video/fbdev/core/tileblit.c index 2768eff247ba..eff7ec4da167 100644 --- a/drivers/video/fbdev/core/tileblit.c +++ b/drivers/video/fbdev/core/tileblit.c @@ -79,7 +79,7 @@ static void tile_clear_margins(struct vc_data *vc, struct fb_info *info, return; } -static void tile_cursor(struct vc_data *vc, struct fb_info *info, int mode, +static void tile_cursor(struct vc_data *vc, struct fb_info *info, bool enable, int fg, int bg) { struct fb_tilecursor cursor; @@ -87,7 +87,7 @@ static void tile_cursor(struct vc_data *vc, struct fb_info *info, int mode, cursor.sx = vc->state.x; cursor.sy = vc->state.y; - cursor.mode = (mode == CM_ERASE || use_sw) ? 0 : 1; + cursor.mode = enable && !use_sw; cursor.fg = fg; cursor.bg = bg; diff --git a/include/linux/console.h b/include/linux/console.h index 82d55764a66f..a6a46b5efd66 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -42,6 +42,7 @@ enum vc_intensity; * @con_putc: emit one character with attributes @ca to [@x, @y] on @vc. * (optional -- @con_putcs would be called instead) * @con_putcs: emit @count characters with attributes @s to [@x, @y] on @vc. + * @con_cursor: enable/disable cursor depending on @enable * @con_scroll: move lines from @top to @bottom in direction @dir by @lines. * Return true if no generic handling should be done. * Invoked by csi_M and printing to the console. @@ -61,7 +62,7 @@ struct consw { void (*con_putcs)(struct vc_data *vc, const u16 *s, unsigned int count, unsigned int ypos, unsigned int xpos); - void (*con_cursor)(struct vc_data *vc, int mode); + void (*con_cursor)(struct vc_data *vc, bool enable); bool (*con_scroll)(struct vc_data *vc, unsigned int top, unsigned int bottom, enum con_scroll dir, unsigned int lines); @@ -128,11 +129,6 @@ static inline void con_debug_enter(struct vc_data *vc) { } static inline void con_debug_leave(void) { } #endif -/* cursor */ -#define CM_DRAW (1) -#define CM_ERASE (2) -#define CM_MOVE (3) - /* * The interface for a console, or any other device that wants to capture * console messages (printer driver?) From 8d5cc8eed738e3202379722295c626cba0849785 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:44 +0100 Subject: [PATCH 030/199] tty: vt: make consw::con_switch() return a bool The non-zero (true) return value from consw::con_switch() means a redraw is needed. So make this return type a bool explicitly instead of int. The latter might imply that -Eerrors are expected. They are not. And document the hook. Signed-off-by: "Jiri Slaby (SUSE)" Cc: Helge Deller Cc: "James E.J. Bottomley" Cc: Daniel Vetter Cc: linux-fbdev@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Cc: linux-parisc@vger.kernel.org Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-31-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 2 +- drivers/video/console/dummycon.c | 4 ++-- drivers/video/console/mdacon.c | 4 ++-- drivers/video/console/newport_con.c | 4 ++-- drivers/video/console/sticon.c | 4 ++-- drivers/video/console/vgacon.c | 4 ++-- drivers/video/fbdev/core/fbcon.c | 6 +++--- include/linux/console.h | 4 +++- 8 files changed, 17 insertions(+), 15 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index e4edcaf9d0a3..fd868046f586 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -970,7 +970,7 @@ void redraw_screen(struct vc_data *vc, int is_switch) } if (redraw) { - int update; + bool update; int old_was_color = vc->vc_can_do_color; set_origin(vc); diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c index 1171e27edef7..c8d5aa0e3ed0 100644 --- a/drivers/video/console/dummycon.c +++ b/drivers/video/console/dummycon.c @@ -122,9 +122,9 @@ static bool dummycon_scroll(struct vc_data *vc, unsigned int top, return false; } -static int dummycon_switch(struct vc_data *vc) +static bool dummycon_switch(struct vc_data *vc) { - return 0; + return false; } /* diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index bc851a1d9f4d..4485ef923bb3 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c @@ -446,9 +446,9 @@ static void mdacon_clear(struct vc_data *c, unsigned int y, unsigned int x, scr_memsetw(dest, eattr, width * 2); } -static int mdacon_switch(struct vc_data *c) +static bool mdacon_switch(struct vc_data *c) { - return 1; /* redrawing needed */ + return true; /* redrawing needed */ } static int mdacon_blank(struct vc_data *c, int blank, int mode_switch) diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index e35406dea7c7..039d1c9937d2 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -459,7 +459,7 @@ static void newport_cursor(struct vc_data *vc, bool enable) newport_vc2_set(npregs, VC2_IREG_CURSY, ycurs); } -static int newport_switch(struct vc_data *vc) +static bool newport_switch(struct vc_data *vc) { static int logo_drawn = 0; @@ -473,7 +473,7 @@ static int newport_switch(struct vc_data *vc) } } - return 1; + return true; } static int newport_blank(struct vc_data *c, int blank, int mode_switch) diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index 786e1b3a98ea..f3bb48a0e980 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c @@ -293,9 +293,9 @@ static void sticon_clear(struct vc_data *conp, unsigned int sy, unsigned int sx, conp->vc_video_erase_char, font_data[conp->vc_num]); } -static int sticon_switch(struct vc_data *conp) +static bool sticon_switch(struct vc_data *conp) { - return 1; /* needs refreshing */ + return true; /* needs refreshing */ } static int sticon_blank(struct vc_data *c, int blank, int mode_switch) diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index d93eb15da435..f89eb53c0b79 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -614,7 +614,7 @@ static void vgacon_doresize(struct vc_data *c, raw_spin_unlock_irqrestore(&vga_lock, flags); } -static int vgacon_switch(struct vc_data *c) +static bool vgacon_switch(struct vc_data *c) { int x = c->vc_cols * VGA_FONTWIDTH; int y = c->vc_rows * c->vc_cell_height; @@ -643,7 +643,7 @@ static int vgacon_switch(struct vc_data *c) vgacon_doresize(c, c->vc_cols, c->vc_rows); } - return 0; /* Redrawing not needed */ + return false; /* Redrawing not needed */ } static void vga_set_palette(struct vc_data *vc, const unsigned char *table) diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index c1765a6ef490..d5d924225209 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -2056,7 +2056,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, return 0; } -static int fbcon_switch(struct vc_data *vc) +static bool fbcon_switch(struct vc_data *vc) { struct fb_info *info, *old_info = NULL; struct fbcon_ops *ops; @@ -2178,9 +2178,9 @@ static int fbcon_switch(struct vc_data *vc) vc->vc_origin + vc->vc_size_row * vc->vc_top, vc->vc_size_row * (vc->vc_bottom - vc->vc_top) / 2); - return 0; + return false; } - return 1; + return true; } static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info, diff --git a/include/linux/console.h b/include/linux/console.h index a6a46b5efd66..f7c6b5fc3a36 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -46,6 +46,8 @@ enum vc_intensity; * @con_scroll: move lines from @top to @bottom in direction @dir by @lines. * Return true if no generic handling should be done. * Invoked by csi_M and printing to the console. + * @con_switch: notifier about the console switch; it is supposed to return + * true if a redraw is needed. * @con_set_palette: sets the palette of the console to @table (optional) * @con_scrolldelta: the contents of the console should be scrolled by @lines. * Invoked by user. (optional) @@ -66,7 +68,7 @@ struct consw { bool (*con_scroll)(struct vc_data *vc, unsigned int top, unsigned int bottom, enum con_scroll dir, unsigned int lines); - int (*con_switch)(struct vc_data *vc); + bool (*con_switch)(struct vc_data *vc); int (*con_blank)(struct vc_data *vc, int blank, int mode_switch); int (*con_font_set)(struct vc_data *vc, struct console_font *font, unsigned int vpitch, unsigned int flags); From 735a51943f5626f2b8729e43cc528341f04c8dee Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:45 +0100 Subject: [PATCH 031/199] tty: vt: stop using -1 for blank mode in consw::con_blank() -1 is the same as VESA_VSYNC_SUSPEND in all con_blank() implementations. So we can remove this special case from vgacon now too. Despite con_blank() of fbcon looks complicated, the "if (!fbcon_is_inactive(vc, info))" branch is not taken as we set "ops->graphics = 1;" few lines above. So what matters there (as in all other blank implementations except vgacon) is if 'blank' is zero or not. Signed-off-by: "Jiri Slaby (SUSE)" Cc: Helge Deller Cc: linux-fbdev@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-32-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 2 +- drivers/video/console/vgacon.c | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index fd868046f586..13be125a06aa 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -4347,7 +4347,7 @@ void do_blank_screen(int entering_gfx) if (entering_gfx) { hide_cursor(vc); save_screen(vc); - vc->vc_sw->con_blank(vc, -1, 1); + vc->vc_sw->con_blank(vc, 1, 1); console_blanked = fg_console + 1; blank_state = blank_off; set_origin(vc); diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index f89eb53c0b79..804b6a180b60 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -814,7 +814,6 @@ static int vgacon_blank(struct vc_data *c, int blank, int mode_switch) /* Tell console.c that it has to restore the screen itself */ return 1; case 1: /* Normal blanking */ - case -1: /* Obsolete */ if (!mode_switch && vga_video_type == VIDEO_TYPE_VGAC) { vga_pal_blank(&vgastate); vga_palette_blanked = true; From ace4ebf9b70a7daea12102c09ba5ef6bb73223aa Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:46 +0100 Subject: [PATCH 032/199] tty: vt: define a common enum for VESA blanking constants There are currently two places with VESA blanking constants definitions: fb.h and console.h. Extract/unify the two to a separate header (vesa.h). Given the fb's is in an uapi header, create the common header in uapi too. Note that instead of macros, an enum (vesa_blank_mode) is created. But the macros are kept too (they now expand to the enum constants), just in case someone in userspace performs some #ifdeffery. Signed-off-by: "Jiri Slaby (SUSE)" Cc: Helge Deller Cc: linux-kernel@vger.kernel.org Cc: linux-fbdev@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Cc: Thomas Zimmermann Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-33-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- include/linux/console.h | 7 +------ include/uapi/linux/fb.h | 8 +------- include/uapi/linux/vesa.h | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+), 13 deletions(-) create mode 100644 include/uapi/linux/vesa.h diff --git a/include/linux/console.h b/include/linux/console.h index f7c6b5fc3a36..860f82756c9c 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -18,6 +18,7 @@ #include #include #include +#include struct vc_data; struct console_font_op; @@ -520,12 +521,6 @@ void vcs_remove_sysfs(int index); */ extern atomic_t ignore_console_lock_warning; -/* VESA Blanking Levels */ -#define VESA_NO_BLANKING 0 -#define VESA_VSYNC_SUSPEND 1 -#define VESA_HSYNC_SUSPEND 2 -#define VESA_POWERDOWN 3 - extern void console_init(void); /* For deferred console takeover */ diff --git a/include/uapi/linux/fb.h b/include/uapi/linux/fb.h index 3a49913d006c..cde8f173f566 100644 --- a/include/uapi/linux/fb.h +++ b/include/uapi/linux/fb.h @@ -4,6 +4,7 @@ #include #include +#include /* Definitions of frame buffers */ @@ -293,13 +294,6 @@ struct fb_con2fbmap { __u32 framebuffer; }; -/* VESA Blanking Levels */ -#define VESA_NO_BLANKING 0 -#define VESA_VSYNC_SUSPEND 1 -#define VESA_HSYNC_SUSPEND 2 -#define VESA_POWERDOWN 3 - - enum { /* screen: unblanked, hsync: on, vsync: on */ FB_BLANK_UNBLANK = VESA_NO_BLANKING, diff --git a/include/uapi/linux/vesa.h b/include/uapi/linux/vesa.h new file mode 100644 index 000000000000..81947f5088cd --- /dev/null +++ b/include/uapi/linux/vesa.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_LINUX_VESA_H +#define _UAPI_LINUX_VESA_H + +/* VESA Blanking Levels */ +enum vesa_blank_mode { + VESA_NO_BLANKING = 0, +#define VESA_NO_BLANKING VESA_NO_BLANKING + VESA_VSYNC_SUSPEND = 1, +#define VESA_VSYNC_SUSPEND VESA_VSYNC_SUSPEND + VESA_HSYNC_SUSPEND = 2, +#define VESA_HSYNC_SUSPEND VESA_HSYNC_SUSPEND + VESA_POWERDOWN = VESA_VSYNC_SUSPEND | VESA_HSYNC_SUSPEND, +#define VESA_POWERDOWN VESA_POWERDOWN + VESA_BLANK_MAX = VESA_POWERDOWN, +}; + +#endif From 15d0fff7d688b9b2a975a17308e4d7c6be75aa8f Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:47 +0100 Subject: [PATCH 033/199] tty: vt: use VESA blanking constants There are VESA blanking constants defined in vesa.h. So use them in the console code instead of constant values. Signed-off-by: "Jiri Slaby (SUSE)" Cc: Helge Deller Cc: "James E.J. Bottomley" Cc: linux-fbdev@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Cc: linux-parisc@vger.kernel.org Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-34-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 9 +++++---- drivers/video/console/newport_con.c | 2 +- drivers/video/console/sticon.c | 2 +- drivers/video/console/vgacon.c | 6 +++--- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 13be125a06aa..0d5d7b5074a4 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -4320,7 +4320,7 @@ static int set_vesa_blanking(u8 __user *mode_user) return -EFAULT; console_lock(); - vesa_blank_mode = (mode < 4) ? mode : 0; + vesa_blank_mode = (mode < 4) ? mode : VESA_NO_BLANKING; console_unlock(); return 0; @@ -4347,7 +4347,7 @@ void do_blank_screen(int entering_gfx) if (entering_gfx) { hide_cursor(vc); save_screen(vc); - vc->vc_sw->con_blank(vc, 1, 1); + vc->vc_sw->con_blank(vc, VESA_VSYNC_SUSPEND, 1); console_blanked = fg_console + 1; blank_state = blank_off; set_origin(vc); @@ -4368,7 +4368,8 @@ void do_blank_screen(int entering_gfx) save_screen(vc); /* In case we need to reset origin, blanking hook returns 1 */ - i = vc->vc_sw->con_blank(vc, vesa_off_interval ? 1 : (vesa_blank_mode + 1), 0); + i = vc->vc_sw->con_blank(vc, vesa_off_interval ? VESA_VSYNC_SUSPEND : + (vesa_blank_mode + 1), 0); console_blanked = fg_console + 1; if (i) set_origin(vc); @@ -4419,7 +4420,7 @@ void do_unblank_screen(int leaving_gfx) } console_blanked = 0; - if (vc->vc_sw->con_blank(vc, 0, leaving_gfx)) + if (vc->vc_sw->con_blank(vc, VESA_NO_BLANKING, leaving_gfx)) /* Low-level driver cannot restore -> do it ourselves */ update_screen(vc); if (console_blank_hook) diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index 039d1c9937d2..ad3a09142770 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -480,7 +480,7 @@ static int newport_blank(struct vc_data *c, int blank, int mode_switch) { unsigned short treg; - if (blank == 0) { + if (blank == VESA_NO_BLANKING) { /* unblank console */ treg = newport_vc2_get(npregs, VC2_IREG_CONTROL); newport_vc2_set(npregs, VC2_IREG_CONTROL, diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index f3bb48a0e980..817b89c45e81 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c @@ -300,7 +300,7 @@ static bool sticon_switch(struct vc_data *conp) static int sticon_blank(struct vc_data *c, int blank, int mode_switch) { - if (blank == 0) { + if (blank == VESA_NO_BLANKING) { if (mode_switch) vga_is_gfx = 0; return 1; diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 804b6a180b60..02eccd9b3542 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -800,10 +800,10 @@ static void vga_pal_blank(struct vgastate *state) static int vgacon_blank(struct vc_data *c, int blank, int mode_switch) { switch (blank) { - case 0: /* Unblank */ + case VESA_NO_BLANKING: /* Unblank */ if (vga_vesa_blanked) { vga_vesa_unblank(&vgastate); - vga_vesa_blanked = 0; + vga_vesa_blanked = VESA_NO_BLANKING; } if (vga_palette_blanked) { vga_set_palette(c, color_table); @@ -813,7 +813,7 @@ static int vgacon_blank(struct vc_data *c, int blank, int mode_switch) vga_is_gfx = false; /* Tell console.c that it has to restore the screen itself */ return 1; - case 1: /* Normal blanking */ + case VESA_VSYNC_SUSPEND: /* Normal blanking */ if (!mode_switch && vga_video_type == VIDEO_TYPE_VGAC) { vga_pal_blank(&vgastate); vga_palette_blanked = true; From 0a58d83dfb14ac30126c37b18d4578e5b261459d Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:48 +0100 Subject: [PATCH 034/199] tty: vt: use enum constants for VESA blanking modes Use the new enum for VESA constants. This improves type checking in consw::con_blank(). Signed-off-by: "Jiri Slaby (SUSE)" Cc: Helge Deller Cc: "James E.J. Bottomley" Cc: Daniel Vetter Cc: linux-fbdev@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Cc: linux-parisc@vger.kernel.org Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-35-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 4 ++-- drivers/video/console/dummycon.c | 6 ++++-- drivers/video/console/mdacon.c | 3 ++- drivers/video/console/newport_con.c | 3 ++- drivers/video/console/sticon.c | 3 ++- drivers/video/console/vgacon.c | 7 ++++--- drivers/video/fbdev/core/fbcon.c | 3 ++- include/linux/console.h | 3 ++- 8 files changed, 20 insertions(+), 12 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 0d5d7b5074a4..de9148094c2d 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -175,7 +175,7 @@ int do_poke_blanked_console; int console_blanked; EXPORT_SYMBOL(console_blanked); -static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */ +static enum vesa_blank_mode vesa_blank_mode; static int vesa_off_interval; static int blankinterval; core_param(consoleblank, blankinterval, int, 0444); @@ -4320,7 +4320,7 @@ static int set_vesa_blanking(u8 __user *mode_user) return -EFAULT; console_lock(); - vesa_blank_mode = (mode < 4) ? mode : VESA_NO_BLANKING; + vesa_blank_mode = (mode <= VESA_BLANK_MAX) ? mode : VESA_NO_BLANKING; console_unlock(); return 0; diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c index c8d5aa0e3ed0..d86c1d798690 100644 --- a/drivers/video/console/dummycon.c +++ b/drivers/video/console/dummycon.c @@ -79,7 +79,8 @@ static void dummycon_putcs(struct vc_data *vc, const u16 *s, unsigned int count, raw_notifier_call_chain(&dummycon_output_nh, 0, NULL); } -static int dummycon_blank(struct vc_data *vc, int blank, int mode_switch) +static int dummycon_blank(struct vc_data *vc, enum vesa_blank_mode blank, + int mode_switch) { /* Redraw, so that we get putc(s) for output done while blanked */ return 1; @@ -89,7 +90,8 @@ static void dummycon_putc(struct vc_data *vc, u16 c, unsigned int y, unsigned int x) { } static void dummycon_putcs(struct vc_data *vc, const u16 *s, unsigned int count, unsigned int ypos, unsigned int xpos) { } -static int dummycon_blank(struct vc_data *vc, int blank, int mode_switch) +static int dummycon_blank(struct vc_data *vc, enum vesa_blank_mode blank, + int mode_switch) { return 0; } diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index 4485ef923bb3..63e3ce678aab 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c @@ -451,7 +451,8 @@ static bool mdacon_switch(struct vc_data *c) return true; /* redrawing needed */ } -static int mdacon_blank(struct vc_data *c, int blank, int mode_switch) +static int mdacon_blank(struct vc_data *c, enum vesa_blank_mode blank, + int mode_switch) { if (mda_type == TYPE_MDA) { if (blank) diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index ad3a09142770..38437a53b7f1 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -476,7 +476,8 @@ static bool newport_switch(struct vc_data *vc) return true; } -static int newport_blank(struct vc_data *c, int blank, int mode_switch) +static int newport_blank(struct vc_data *c, enum vesa_blank_mode blank, + int mode_switch) { unsigned short treg; diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index 817b89c45e81..e9d5d1f92883 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c @@ -298,7 +298,8 @@ static bool sticon_switch(struct vc_data *conp) return true; /* needs refreshing */ } -static int sticon_blank(struct vc_data *c, int blank, int mode_switch) +static int sticon_blank(struct vc_data *c, enum vesa_blank_mode blank, + int mode_switch) { if (blank == VESA_NO_BLANKING) { if (mode_switch) diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 02eccd9b3542..84f3682704c7 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -81,7 +81,7 @@ static unsigned int vga_video_num_lines; /* Number of text lines */ static bool vga_can_do_color; /* Do we support colors? */ static unsigned int vga_default_font_height __read_mostly; /* Height of default screen font */ static unsigned char vga_video_type __read_mostly; /* Card type */ -static int vga_vesa_blanked; +static enum vesa_blank_mode vga_vesa_blanked; static bool vga_palette_blanked; static bool vga_is_gfx; static bool vga_512_chars; @@ -683,7 +683,7 @@ static struct { unsigned char ClockingMode; /* Seq-Controller:01h */ } vga_state; -static void vga_vesa_blank(struct vgastate *state, int mode) +static void vga_vesa_blank(struct vgastate *state, enum vesa_blank_mode mode) { /* save original values of VGA controller registers */ if (!vga_vesa_blanked) { @@ -797,7 +797,8 @@ static void vga_pal_blank(struct vgastate *state) } } -static int vgacon_blank(struct vc_data *c, int blank, int mode_switch) +static int vgacon_blank(struct vc_data *c, enum vesa_blank_mode blank, + int mode_switch) { switch (blank) { case VESA_NO_BLANKING: /* Unblank */ diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index d5d924225209..69be5f2106bc 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -2198,7 +2198,8 @@ static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info, } } -static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch) +static int fbcon_blank(struct vc_data *vc, enum vesa_blank_mode blank, + int mode_switch) { struct fb_info *info = fbcon_info_from_console(vc->vc_num); struct fbcon_ops *ops = info->fbcon_par; diff --git a/include/linux/console.h b/include/linux/console.h index 860f82756c9c..69040d7c8f97 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -70,7 +70,8 @@ struct consw { unsigned int bottom, enum con_scroll dir, unsigned int lines); bool (*con_switch)(struct vc_data *vc); - int (*con_blank)(struct vc_data *vc, int blank, int mode_switch); + int (*con_blank)(struct vc_data *vc, enum vesa_blank_mode blank, + int mode_switch); int (*con_font_set)(struct vc_data *vc, struct console_font *font, unsigned int vpitch, unsigned int flags); int (*con_font_get)(struct vc_data *vc, struct console_font *font, From 77e110936a42b212c0fb576356ed274eb1d90c54 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:49 +0100 Subject: [PATCH 035/199] tty: vt: make types around consw::con_blank() bool Both the mode_switch parameter and the return value (a redraw needed) are true/false. So switch them to bool, so that users won't return -Eerrors or anything else. And document the hook. Signed-off-by: "Jiri Slaby (SUSE)" Cc: Helge Deller Cc: "James E.J. Bottomley" Cc: Daniel Vetter Cc: linux-fbdev@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Cc: linux-parisc@vger.kernel.org Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-36-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/video/console/dummycon.c | 12 ++++++------ drivers/video/console/mdacon.c | 8 ++++---- drivers/video/console/newport_con.c | 7 ++++--- drivers/video/console/sticon.c | 9 +++++---- drivers/video/console/vgacon.c | 4 ++-- drivers/video/fbdev/core/fbcon.c | 6 +++--- include/linux/console.h | 7 +++++-- 7 files changed, 29 insertions(+), 24 deletions(-) diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c index d86c1d798690..139049368fdc 100644 --- a/drivers/video/console/dummycon.c +++ b/drivers/video/console/dummycon.c @@ -79,21 +79,21 @@ static void dummycon_putcs(struct vc_data *vc, const u16 *s, unsigned int count, raw_notifier_call_chain(&dummycon_output_nh, 0, NULL); } -static int dummycon_blank(struct vc_data *vc, enum vesa_blank_mode blank, - int mode_switch) +static bool dummycon_blank(struct vc_data *vc, enum vesa_blank_mode blank, + bool mode_switch) { /* Redraw, so that we get putc(s) for output done while blanked */ - return 1; + return true; } #else static void dummycon_putc(struct vc_data *vc, u16 c, unsigned int y, unsigned int x) { } static void dummycon_putcs(struct vc_data *vc, const u16 *s, unsigned int count, unsigned int ypos, unsigned int xpos) { } -static int dummycon_blank(struct vc_data *vc, enum vesa_blank_mode blank, - int mode_switch) +static bool dummycon_blank(struct vc_data *vc, enum vesa_blank_mode blank, + bool mode_switch) { - return 0; + return false; } #endif diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index 63e3ce678aab..c0e1f4554a44 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c @@ -451,8 +451,8 @@ static bool mdacon_switch(struct vc_data *c) return true; /* redrawing needed */ } -static int mdacon_blank(struct vc_data *c, enum vesa_blank_mode blank, - int mode_switch) +static bool mdacon_blank(struct vc_data *c, enum vesa_blank_mode blank, + bool mode_switch) { if (mda_type == TYPE_MDA) { if (blank) @@ -460,14 +460,14 @@ static int mdacon_blank(struct vc_data *c, enum vesa_blank_mode blank, mda_convert_attr(c->vc_video_erase_char), c->vc_screenbuf_size); /* Tell console.c that it has to restore the screen itself */ - return 1; + return true; } else { if (blank) outb_p(0x00, mda_mode_port); /* disable video */ else outb_p(MDA_MODE_VIDEO_EN | MDA_MODE_BLINK_EN, mda_mode_port); - return 0; + return false; } } diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index 38437a53b7f1..dbb31bf87bf1 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -476,8 +476,8 @@ static bool newport_switch(struct vc_data *vc) return true; } -static int newport_blank(struct vc_data *c, enum vesa_blank_mode blank, - int mode_switch) +static bool newport_blank(struct vc_data *c, enum vesa_blank_mode blank, + bool mode_switch) { unsigned short treg; @@ -492,7 +492,8 @@ static int newport_blank(struct vc_data *c, enum vesa_blank_mode blank, newport_vc2_set(npregs, VC2_IREG_CONTROL, (treg & ~(VC2_CTRL_EDISP))); } - return 1; + + return true; } static int newport_set_font(int unit, struct console_font *op, unsigned int vpitch) diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index e9d5d1f92883..cbb9ef438214 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c @@ -298,19 +298,20 @@ static bool sticon_switch(struct vc_data *conp) return true; /* needs refreshing */ } -static int sticon_blank(struct vc_data *c, enum vesa_blank_mode blank, - int mode_switch) +static bool sticon_blank(struct vc_data *c, enum vesa_blank_mode blank, + bool mode_switch) { if (blank == VESA_NO_BLANKING) { if (mode_switch) vga_is_gfx = 0; - return 1; + return true; } sti_clear(sticon_sti, 0, 0, c->vc_rows, c->vc_cols, BLANK, font_data[c->vc_num]); if (mode_switch) vga_is_gfx = 1; - return 1; + + return true; } static u8 sticon_build_attr(struct vc_data *conp, u8 color, diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 84f3682704c7..c9a22118102f 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -797,8 +797,8 @@ static void vga_pal_blank(struct vgastate *state) } } -static int vgacon_blank(struct vc_data *c, enum vesa_blank_mode blank, - int mode_switch) +static bool vgacon_blank(struct vc_data *c, enum vesa_blank_mode blank, + bool mode_switch) { switch (blank) { case VESA_NO_BLANKING: /* Unblank */ diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index 69be5f2106bc..eee2adf5c682 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -2198,8 +2198,8 @@ static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info, } } -static int fbcon_blank(struct vc_data *vc, enum vesa_blank_mode blank, - int mode_switch) +static bool fbcon_blank(struct vc_data *vc, enum vesa_blank_mode blank, + bool mode_switch) { struct fb_info *info = fbcon_info_from_console(vc->vc_num); struct fbcon_ops *ops = info->fbcon_par; @@ -2238,7 +2238,7 @@ static int fbcon_blank(struct vc_data *vc, enum vesa_blank_mode blank, else fbcon_add_cursor_work(info); - return 0; + return false; } static void fbcon_debug_enter(struct vc_data *vc) diff --git a/include/linux/console.h b/include/linux/console.h index 69040d7c8f97..6392bcd2fe7c 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -49,6 +49,9 @@ enum vc_intensity; * Invoked by csi_M and printing to the console. * @con_switch: notifier about the console switch; it is supposed to return * true if a redraw is needed. + * @con_blank: blank/unblank the console. The target mode is passed in @blank. + * @mode_switch is set if changing from/to text/graphics. The hook + * is supposed to return true if a redraw is needed. * @con_set_palette: sets the palette of the console to @table (optional) * @con_scrolldelta: the contents of the console should be scrolled by @lines. * Invoked by user. (optional) @@ -70,8 +73,8 @@ struct consw { unsigned int bottom, enum con_scroll dir, unsigned int lines); bool (*con_switch)(struct vc_data *vc); - int (*con_blank)(struct vc_data *vc, enum vesa_blank_mode blank, - int mode_switch); + bool (*con_blank)(struct vc_data *vc, enum vesa_blank_mode blank, + bool mode_switch); int (*con_font_set)(struct vc_data *vc, struct console_font *font, unsigned int vpitch, unsigned int flags); int (*con_font_get)(struct vc_data *vc, struct console_font *font, From fd0f631fffa87f1c26045c3c88c0c4a7706d14de Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:50 +0100 Subject: [PATCH 036/199] tty: vt: make font of consw::con_font_set() const Provided the font parameter of consw::con_font_set() is not supposed to be changed, make it const. Signed-off-by: "Jiri Slaby (SUSE)" Cc: Helge Deller Cc: "James E.J. Bottomley" Cc: Daniel Vetter Cc: linux-fbdev@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Cc: linux-parisc@vger.kernel.org Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-37-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 2 +- drivers/video/console/newport_con.c | 5 +++-- drivers/video/console/sticon.c | 4 ++-- drivers/video/console/vgacon.c | 2 +- drivers/video/fbdev/core/fbcon.c | 2 +- include/linux/console.h | 5 +++-- 6 files changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index de9148094c2d..0ac537f82f7a 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -4625,7 +4625,7 @@ out: return rc; } -static int con_font_set(struct vc_data *vc, struct console_font_op *op) +static int con_font_set(struct vc_data *vc, const struct console_font_op *op) { struct console_font font; int rc = -EINVAL; diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index dbb31bf87bf1..4203bd5fd0a1 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -496,7 +496,8 @@ static bool newport_blank(struct vc_data *c, enum vesa_blank_mode blank, return true; } -static int newport_set_font(int unit, struct console_font *op, unsigned int vpitch) +static int newport_set_font(int unit, const struct console_font *op, + unsigned int vpitch) { int w = op->width; int h = op->height; @@ -568,7 +569,7 @@ static int newport_font_default(struct vc_data *vc, struct console_font *op, cha return newport_set_def_font(vc->vc_num, op); } -static int newport_font_set(struct vc_data *vc, struct console_font *font, +static int newport_font_set(struct vc_data *vc, const struct console_font *font, unsigned int vpitch, unsigned int flags) { return newport_set_font(vc->vc_num, font, vpitch); diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index cbb9ef438214..710201fb8ce4 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c @@ -153,7 +153,7 @@ static void sticon_set_def_font(int unit) } } -static int sticon_set_font(struct vc_data *vc, struct console_font *op, +static int sticon_set_font(struct vc_data *vc, const struct console_font *op, unsigned int vpitch) { struct sti_struct *sti = sticon_sti; @@ -253,7 +253,7 @@ static int sticon_font_default(struct vc_data *vc, struct console_font *op, char return 0; } -static int sticon_font_set(struct vc_data *vc, struct console_font *font, +static int sticon_font_set(struct vc_data *vc, const struct console_font *font, unsigned int vpitch, unsigned int flags) { return sticon_set_font(vc, font, vpitch); diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index c9a22118102f..4d1c8f5863af 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -1039,7 +1039,7 @@ static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight) return 0; } -static int vgacon_font_set(struct vc_data *c, struct console_font *font, +static int vgacon_font_set(struct vc_data *c, const struct console_font *font, unsigned int vpitch, unsigned int flags) { unsigned charcount = font->charcount; diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index eee2adf5c682..62474630c4d4 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -2460,7 +2460,7 @@ err_out: * but lets not assume that, since charcount of 512 is small for unicode support. */ -static int fbcon_set_font(struct vc_data *vc, struct console_font *font, +static int fbcon_set_font(struct vc_data *vc, const struct console_font *font, unsigned int vpitch, unsigned int flags) { struct fb_info *info = fbcon_info_from_console(vc->vc_num); diff --git a/include/linux/console.h b/include/linux/console.h index 6392bcd2fe7c..0a9f4cbdde83 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -75,8 +75,9 @@ struct consw { bool (*con_switch)(struct vc_data *vc); bool (*con_blank)(struct vc_data *vc, enum vesa_blank_mode blank, bool mode_switch); - int (*con_font_set)(struct vc_data *vc, struct console_font *font, - unsigned int vpitch, unsigned int flags); + int (*con_font_set)(struct vc_data *vc, + const struct console_font *font, + unsigned int vpitch, unsigned int flags); int (*con_font_get)(struct vc_data *vc, struct console_font *font, unsigned int vpitch); int (*con_font_default)(struct vc_data *vc, From 4f59617065592c446cd8450e9e6bac229cbc1383 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:51 +0100 Subject: [PATCH 037/199] tty: vt: make consw::con_font_default()'s name const It's a name after all and that is not supposed to be changed. So make it const to make this obvious. Signed-off-by: "Jiri Slaby (SUSE)" Cc: "James E.J. Bottomley" Cc: Daniel Vetter Cc: linux-fbdev@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Cc: linux-parisc@vger.kernel.org Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-38-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/video/console/newport_con.c | 3 ++- drivers/video/console/sticon.c | 3 ++- drivers/video/fbdev/core/fbcon.c | 3 ++- include/linux/console.h | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index 4203bd5fd0a1..a51cfc1d560e 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -564,7 +564,8 @@ static int newport_set_def_font(int unit, struct console_font *op) return 0; } -static int newport_font_default(struct vc_data *vc, struct console_font *op, char *name) +static int newport_font_default(struct vc_data *vc, struct console_font *op, + const char *name) { return newport_set_def_font(vc->vc_num, op); } diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index 710201fb8ce4..4c7b4959a1aa 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c @@ -246,7 +246,8 @@ static int sticon_set_font(struct vc_data *vc, const struct console_font *op, return 0; } -static int sticon_font_default(struct vc_data *vc, struct console_font *op, char *name) +static int sticon_font_default(struct vc_data *vc, struct console_font *op, + const char *name) { sticon_set_def_font(vc->vc_num); diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index 62474630c4d4..657160eec0a5 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -2533,7 +2533,8 @@ static int fbcon_set_font(struct vc_data *vc, const struct console_font *font, return fbcon_do_set_font(vc, font->width, font->height, charcount, new_data, 1); } -static int fbcon_set_def_font(struct vc_data *vc, struct console_font *font, char *name) +static int fbcon_set_def_font(struct vc_data *vc, struct console_font *font, + const char *name) { struct fb_info *info = fbcon_info_from_console(vc->vc_num); const struct font_desc *f; diff --git a/include/linux/console.h b/include/linux/console.h index 0a9f4cbdde83..6bb7e5e37ae4 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -81,7 +81,7 @@ struct consw { int (*con_font_get)(struct vc_data *vc, struct console_font *font, unsigned int vpitch); int (*con_font_default)(struct vc_data *vc, - struct console_font *font, char *name); + struct console_font *font, const char *name); int (*con_resize)(struct vc_data *vc, unsigned int width, unsigned int height, bool from_user); void (*con_set_palette)(struct vc_data *vc, From 42822fabfc24f4fc8d5404d9359fa17a0bcfcea8 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:52 +0100 Subject: [PATCH 038/199] tty: vt: change consw::con_set_origin() return type The return value of consw::con_set_origin() is only true/false, meaining if vc->vc_origin is set to vc->vc_screenbuf or not. So switch the type and returned values accordingly. And document the hook. Signed-off-by: "Jiri Slaby (SUSE)" Cc: Helge Deller Cc: linux-fbdev@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-39-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/video/console/vgacon.c | 8 ++++---- include/linux/console.h | 5 ++++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 4d1c8f5863af..7597f04b0dc7 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -65,7 +65,7 @@ static struct vgastate vgastate; * Interface used by the world */ -static int vgacon_set_origin(struct vc_data *c); +static bool vgacon_set_origin(struct vc_data *c); static struct uni_pagedict *vgacon_uni_pagedir; static int vgacon_refcount; @@ -1100,15 +1100,15 @@ static int vgacon_resize(struct vc_data *c, unsigned int width, return 0; } -static int vgacon_set_origin(struct vc_data *c) +static bool vgacon_set_origin(struct vc_data *c) { if (vga_is_gfx || /* We don't play origin tricks in graphic modes */ (console_blanked && !vga_palette_blanked)) /* Nor we write to blanked screens */ - return 0; + return false; c->vc_origin = c->vc_visible_origin = vga_vram_base; vga_set_mem_top(c); vga_rolled_over = 0; - return 1; + return true; } static void vgacon_save_screen(struct vc_data *c) diff --git a/include/linux/console.h b/include/linux/console.h index 6bb7e5e37ae4..82e4b554a801 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -55,6 +55,9 @@ enum vc_intensity; * @con_set_palette: sets the palette of the console to @table (optional) * @con_scrolldelta: the contents of the console should be scrolled by @lines. * Invoked by user. (optional) + * @con_set_origin: set origin (see &vc_data::vc_origin) of the @vc. If not + * provided or returns false, the origin is set to + * @vc->vc_screenbuf. (optional) */ struct consw { struct module *owner; @@ -87,7 +90,7 @@ struct consw { void (*con_set_palette)(struct vc_data *vc, const unsigned char *table); void (*con_scrolldelta)(struct vc_data *vc, int lines); - int (*con_set_origin)(struct vc_data *vc); + bool (*con_set_origin)(struct vc_data *vc); void (*con_save_screen)(struct vc_data *vc); u8 (*con_build_attr)(struct vc_data *vc, u8 color, enum vc_intensity intensity, From d62808ba9ebca537607678207d2deb25d949d923 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:53 +0100 Subject: [PATCH 039/199] fbcon: remove consw::con_screen_pos() fbcon_screen_pos() performs the same as the default implementation. The only difference in the default implementation is that is considers both vc->vc_origin and vc->vc_visible_origin. But given fbcon's softscroll code was already removed in commit 50145474f6ef (fbcon: remove soft scrollback code), both are always the same. So remove fbcon_screen_pos() too. Signed-off-by: "Jiri Slaby (SUSE)" Cc: Daniel Vetter Cc: Helge Deller Cc: linux-fbdev@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-40-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/video/fbdev/core/fbcon.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index 657160eec0a5..2166ea1a5430 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -2593,11 +2593,6 @@ static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table) fb_set_cmap(&palette_cmap, info); } -static u16 *fbcon_screen_pos(const struct vc_data *vc, int offset) -{ - return (u16 *) (vc->vc_origin + offset); -} - static unsigned long fbcon_getxy(struct vc_data *vc, unsigned long pos, int *px, int *py) { @@ -3162,7 +3157,6 @@ static const struct consw fb_con = { .con_font_default = fbcon_set_def_font, .con_set_palette = fbcon_set_palette, .con_invert_region = fbcon_invert_region, - .con_screen_pos = fbcon_screen_pos, .con_getxy = fbcon_getxy, .con_resize = fbcon_resize, .con_debug_enter = fbcon_debug_enter, From 7cf01c92addb73c3055ff0fc596441c80ce82113 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:54 +0100 Subject: [PATCH 040/199] tty: vt: remove consw::con_screen_pos() After the previous patch, nobody sets that hook. So drop it completely. Signed-off-by: "Jiri Slaby (SUSE)" Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-41-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 12 +++--------- include/linux/console.h | 1 - 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 0ac537f82f7a..4e9d689143e0 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -289,15 +289,9 @@ static inline bool con_should_update(const struct vc_data *vc) static inline unsigned short *screenpos(const struct vc_data *vc, int offset, bool viewed) { - unsigned short *p; - - if (!viewed) - p = (unsigned short *)(vc->vc_origin + offset); - else if (!vc->vc_sw->con_screen_pos) - p = (unsigned short *)(vc->vc_visible_origin + offset); - else - p = vc->vc_sw->con_screen_pos(vc, offset); - return p; + unsigned long origin = viewed ? vc->vc_visible_origin : vc->vc_origin; + + return (unsigned short *)(origin + offset); } static void con_putc(struct vc_data *vc, u16 ca, unsigned int y, unsigned int x) diff --git a/include/linux/console.h b/include/linux/console.h index 82e4b554a801..b2d8621cea57 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -96,7 +96,6 @@ struct consw { enum vc_intensity intensity, bool blink, bool underline, bool reverse, bool italic); void (*con_invert_region)(struct vc_data *vc, u16 *p, int count); - u16 *(*con_screen_pos)(const struct vc_data *vc, int offset); unsigned long (*con_getxy)(struct vc_data *vc, unsigned long position, int *px, int *py); /* From fd1ca819710a435cf14988caa7f0d984464015b6 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:55 +0100 Subject: [PATCH 041/199] tty: vt: make types of screenpos() more consistent * parameter offset: it is expected to be non-negative, so switch to unsigned * return type: switch from ushort to explicit u16. This is expected on most places. And fix the remaining two places too. Signed-off-by: "Jiri Slaby (SUSE)" Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-42-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 4e9d689143e0..f6fa76c0eb5b 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -286,12 +286,12 @@ static inline bool con_should_update(const struct vc_data *vc) return con_is_visible(vc) && !console_blanked; } -static inline unsigned short *screenpos(const struct vc_data *vc, int offset, - bool viewed) +static inline u16 *screenpos(const struct vc_data *vc, unsigned int offset, + bool viewed) { unsigned long origin = viewed ? vc->vc_visible_origin : vc->vc_origin; - return (unsigned short *)(origin + offset); + return (u16 *)(origin + offset); } static void con_putc(struct vc_data *vc, u16 ca, unsigned int y, unsigned int x) @@ -705,7 +705,7 @@ static void update_attr(struct vc_data *vc) /* Note: inverting the screen twice should revert to the original state */ void invert_screen(struct vc_data *vc, int offset, int count, bool viewed) { - unsigned short *p; + u16 *p; WARN_CONSOLE_UNLOCKED(); @@ -773,8 +773,7 @@ void complement_pos(struct vc_data *vc, int offset) if (offset != -1 && offset >= 0 && offset < vc->vc_screenbuf_size) { unsigned short new; - unsigned short *p; - p = screenpos(vc, offset, true); + u16 *p = screenpos(vc, offset, true); old = scr_readw(p); new = old ^ vc->vc_complement_mask; scr_writew(new, p); From af757ca6b274bc3db025617a7f8960166734cf9e Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:56 +0100 Subject: [PATCH 042/199] fbcon: remove fbcon_getxy() Again, fbcon_getxy() is the same as the default implementation since the softscroll removal in commit 50145474f6ef (fbcon: remove soft scrollback code). Drop that. Signed-off-by: "Jiri Slaby (SUSE)" Cc: Daniel Vetter Cc: Helge Deller Cc: linux-fbdev@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-43-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/video/fbdev/core/fbcon.c | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index 2166ea1a5430..9c2962900d13 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -2593,30 +2593,6 @@ static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table) fb_set_cmap(&palette_cmap, info); } -static unsigned long fbcon_getxy(struct vc_data *vc, unsigned long pos, - int *px, int *py) -{ - unsigned long ret; - int x, y; - - if (pos >= vc->vc_origin && pos < vc->vc_scr_end) { - unsigned long offset = (pos - vc->vc_origin) / 2; - - x = offset % vc->vc_cols; - y = offset / vc->vc_cols; - ret = pos + (vc->vc_cols - x) * 2; - } else { - /* Should not happen */ - x = y = 0; - ret = vc->vc_origin; - } - if (px) - *px = x; - if (py) - *py = y; - return ret; -} - /* As we might be inside of softback, we may work with non-contiguous buffer, that's why we have to use a separate routine. */ static void fbcon_invert_region(struct vc_data *vc, u16 * p, int cnt) @@ -3157,7 +3133,6 @@ static const struct consw fb_con = { .con_font_default = fbcon_set_def_font, .con_set_palette = fbcon_set_palette, .con_invert_region = fbcon_invert_region, - .con_getxy = fbcon_getxy, .con_resize = fbcon_resize, .con_debug_enter = fbcon_debug_enter, .con_debug_leave = fbcon_debug_leave, From f441aa3b441306e35e8fcbec5ac13c68b5f48245 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:57 +0100 Subject: [PATCH 043/199] tty: vt: remove consw::con_getxy() After the previous patch, nobody sets that hook. So drop it completely. Signed-off-by: "Jiri Slaby (SUSE)" Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-44-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 20 +++++--------------- include/linux/console.h | 2 -- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index f6fa76c0eb5b..cbe1a1106d53 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -593,18 +593,12 @@ static void con_scroll(struct vc_data *vc, unsigned int top, static void do_update_region(struct vc_data *vc, unsigned long start, int count) { unsigned int xx, yy, offset; - u16 *p; + u16 *p = (u16 *)start; + + offset = (start - vc->vc_origin) / 2; + xx = offset % vc->vc_cols; + yy = offset / vc->vc_cols; - p = (u16 *) start; - if (!vc->vc_sw->con_getxy) { - offset = (start - vc->vc_origin) / 2; - xx = offset % vc->vc_cols; - yy = offset / vc->vc_cols; - } else { - int nxx, nyy; - start = vc->vc_sw->con_getxy(vc, start, &nxx, &nyy); - xx = nxx; yy = nyy; - } for(;;) { u16 attrib = scr_readw(p) & 0xff00; int startx = xx; @@ -627,10 +621,6 @@ static void do_update_region(struct vc_data *vc, unsigned long start, int count) break; xx = 0; yy++; - if (vc->vc_sw->con_getxy) { - p = (u16 *)start; - start = vc->vc_sw->con_getxy(vc, start, NULL, NULL); - } } } diff --git a/include/linux/console.h b/include/linux/console.h index b2d8621cea57..fa2cd81102b8 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -96,8 +96,6 @@ struct consw { enum vc_intensity intensity, bool blink, bool underline, bool reverse, bool italic); void (*con_invert_region)(struct vc_data *vc, u16 *p, int count); - unsigned long (*con_getxy)(struct vc_data *vc, unsigned long position, - int *px, int *py); /* * Flush the video console driver's scrollback buffer */ From b23bf1a43bdbce1a281f11169dd9d426018b00c9 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:58 +0100 Subject: [PATCH 044/199] tty: vt: remove unused consw::con_flush_scrollback() consw::con_flush_scrollback() is unused since commit 973c096f6a85 (vgacon: remove software scrollback support). Drop it. Signed-off-by: "Jiri Slaby (SUSE)" Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-45-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 27 ++++++++++++--------------- include/linux/console.h | 4 ---- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index cbe1a1106d53..bfe51af9a0f3 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -888,21 +888,18 @@ static void flush_scrollback(struct vc_data *vc) WARN_CONSOLE_UNLOCKED(); set_origin(vc); - if (vc->vc_sw->con_flush_scrollback) { - vc->vc_sw->con_flush_scrollback(vc); - } else if (con_is_visible(vc)) { - /* - * When no con_flush_scrollback method is provided then the - * legacy way for flushing the scrollback buffer is to use - * a side effect of the con_switch method. We do it only on - * the foreground console as background consoles have no - * scrollback buffers in that case and we obviously don't - * want to switch to them. - */ - hide_cursor(vc); - vc->vc_sw->con_switch(vc); - set_cursor(vc); - } + if (!con_is_visible(vc)) + return; + + /* + * The legacy way for flushing the scrollback buffer is to use a side + * effect of the con_switch method. We do it only on the foreground + * console as background consoles have no scrollback buffers in that + * case and we obviously don't want to switch to them. + */ + hide_cursor(vc); + vc->vc_sw->con_switch(vc); + set_cursor(vc); } /* diff --git a/include/linux/console.h b/include/linux/console.h index fa2cd81102b8..1eac3e6e32a2 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -96,10 +96,6 @@ struct consw { enum vc_intensity intensity, bool blink, bool underline, bool reverse, bool italic); void (*con_invert_region)(struct vc_data *vc, u16 *p, int count); - /* - * Flush the video console driver's scrollback buffer - */ - void (*con_flush_scrollback)(struct vc_data *vc); /* * Prepare the console for the debugger. This includes, but is not * limited to, unblanking the console, loading an appropriate From d1e2221644c490a73d2968fe316f0af170e0ebcf Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:03:59 +0100 Subject: [PATCH 045/199] tty: vt: document the rest of struct consw There are still members of struct consw which are not documented yet. Fix that up, so we can generate kernel-doc for that struct. Signed-off-by: "Jiri Slaby (SUSE)" Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-46-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- include/linux/console.h | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/include/linux/console.h b/include/linux/console.h index 1eac3e6e32a2..f1a334ad268d 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -37,8 +37,11 @@ enum vc_intensity; /** * struct consw - callbacks for consoles * + * @owner: the module to get references of when this console is used + * @con_startup: set up the console and return its name (like VGA, EGA, ...) * @con_init: initialize the console on @vc. @init is true for the very first * call on this @vc. + * @con_deinit: deinitialize the console from @vc. * @con_clear: erase @count characters at [@x, @y] on @vc. @count >= 1. * @con_putc: emit one character with attributes @ca to [@x, @y] on @vc. * (optional -- @con_putcs would be called instead) @@ -52,12 +55,33 @@ enum vc_intensity; * @con_blank: blank/unblank the console. The target mode is passed in @blank. * @mode_switch is set if changing from/to text/graphics. The hook * is supposed to return true if a redraw is needed. - * @con_set_palette: sets the palette of the console to @table (optional) + * @con_font_set: set console @vc font to @font with height @vpitch. @flags can + * be %KD_FONT_FLAG_DONT_RECALC. (optional) + * @con_font_get: fetch the current font on @vc of height @vpitch into @font. + * (optional) + * @con_font_default: set default font on @vc. @name can be %NULL or font name + * to search for. @font can be filled back. (optional) + * @con_resize: resize the @vc console to @width x @height. @from_user is true + * when this change comes from the user space. + * @con_set_palette: sets the palette of the console @vc to @table (optional) * @con_scrolldelta: the contents of the console should be scrolled by @lines. * Invoked by user. (optional) * @con_set_origin: set origin (see &vc_data::vc_origin) of the @vc. If not * provided or returns false, the origin is set to * @vc->vc_screenbuf. (optional) + * @con_save_screen: save screen content into @vc->vc_screenbuf. Called e.g. + * upon entering graphics. (optional) + * @con_build_attr: build attributes based on @color, @intensity and other + * parameters. The result is used for both normal and erase + * characters. (optional) + * @con_invert_region: invert a region of length @count on @vc starting at @p. + * (optional) + * @con_debug_enter: prepare the console for the debugger. This includes, but + * is not limited to, unblanking the console, loading an + * appropriate palette, and allowing debugger generated output. + * (optional) + * @con_debug_leave: restore the console to its pre-debug state as closely as + * possible. (optional) */ struct consw { struct module *owner; @@ -96,15 +120,7 @@ struct consw { enum vc_intensity intensity, bool blink, bool underline, bool reverse, bool italic); void (*con_invert_region)(struct vc_data *vc, u16 *p, int count); - /* - * Prepare the console for the debugger. This includes, but is not - * limited to, unblanking the console, loading an appropriate - * palette, and allowing debugger generated output. - */ void (*con_debug_enter)(struct vc_data *vc); - /* - * Restore the console to its pre-debug state as closely as possible. - */ void (*con_debug_leave)(struct vc_data *vc); }; From 60234365aee22c9ac576491f787f20a17279d28e Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:04:00 +0100 Subject: [PATCH 046/199] tty: vt: fix up kernel-doc selection.c and vt.c still uses tabs in the kernel-doc. This misrenders the functions in the output -- sphinx misinterprets the description. So remove these tabs, incl. those around dashes. 'enum' keyword is needed before enum names. Fix that. Superfluous \n after the comments are also removed. They are not completely faulty, but this unifies all the kernel-doc in the files. Finally fix up the cross references. Signed-off-by: "Jiri Slaby (SUSE)" Reviewed-by: Randy Dunlap Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-47-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/selection.c | 30 ++++++------- drivers/tty/vt/vt.c | 86 +++++++++++++++++++------------------- include/linux/console.h | 6 +-- 3 files changed, 62 insertions(+), 60 deletions(-) diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 34ee09f5a8f4..564341f1a74f 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -73,10 +73,12 @@ sel_pos(int n, bool unicode) } /** - * clear_selection - remove current selection + * clear_selection - remove current selection * - * Remove the current selection highlight, if any from the console - * holding the selection. The caller must hold the console lock. + * Remove the current selection highlight, if any from the console holding the + * selection. + * + * Locking: The caller must hold the console lock. */ void clear_selection(void) { @@ -110,13 +112,13 @@ static inline int inword(const u32 c) } /** - * sel_loadlut() - load the LUT table - * @lut: user table + * sel_loadlut() - load the LUT table + * @lut: user table * - * Load the LUT table from user space. Make a temporary copy so a partial - * update doesn't make a mess. + * Load the LUT table from user space. Make a temporary copy so a partial + * update doesn't make a mess. * - * Locking: The console lock is acquired. + * Locking: The console lock is acquired. */ int sel_loadlut(u32 __user *lut) { @@ -173,14 +175,14 @@ static int store_utf8(u32 c, char *p) } /** - * set_selection_user - set the current selection. - * @sel: user selection info - * @tty: the console tty + * set_selection_user - set the current selection. + * @sel: user selection info + * @tty: the console tty * - * Invoked by the ioctl handle for the vt layer. + * Invoked by the ioctl handle for the vt layer. * - * The entire selection process is managed under the console_lock. It's - * a lot under the lock but its hardly a performance path + * Locking: The entire selection process is managed under the console_lock. + * It's a lot under the lock but its hardly a performance path. */ int set_selection_user(const struct tiocl_selection __user *sel, struct tty_struct *tty) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index bfe51af9a0f3..e9cdcf40fe14 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1115,21 +1115,20 @@ static inline int resize_screen(struct vc_data *vc, int width, int height, } /** - * vc_do_resize - resizing method for the tty - * @tty: tty being resized - * @vc: virtual console private data - * @cols: columns - * @lines: lines - * @from_user: invoked by a user? + * vc_do_resize - resizing method for the tty + * @tty: tty being resized + * @vc: virtual console private data + * @cols: columns + * @lines: lines + * @from_user: invoked by a user? * - * Resize a virtual console, clipping according to the actual constraints. - * If the caller passes a tty structure then update the termios winsize - * information and perform any necessary signal handling. + * Resize a virtual console, clipping according to the actual constraints. If + * the caller passes a tty structure then update the termios winsize + * information and perform any necessary signal handling. * - * Caller must hold the console semaphore. Takes the termios rwsem and - * ctrl.lock of the tty IFF a tty is passed. + * Locking: Caller must hold the console semaphore. Takes the termios rwsem and + * ctrl.lock of the tty IFF a tty is passed. */ - static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, unsigned int cols, unsigned int lines, bool from_user) { @@ -1277,16 +1276,17 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, } /** - * __vc_resize - resize a VT - * @vc: virtual console - * @cols: columns - * @rows: rows - * @from_user: invoked by a user? + * __vc_resize - resize a VT + * @vc: virtual console + * @cols: columns + * @rows: rows + * @from_user: invoked by a user? * - * Resize a virtual console as seen from the console end of things. We - * use the common vc_do_resize methods to update the structures. The - * caller must hold the console sem to protect console internals and - * vc->port.tty + * Resize a virtual console as seen from the console end of things. We use the + * common vc_do_resize() method to update the structures. + * + * Locking: The caller must hold the console sem to protect console internals + * and @vc->port.tty. */ int __vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows, bool from_user) @@ -1296,16 +1296,15 @@ int __vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows, EXPORT_SYMBOL(__vc_resize); /** - * vt_resize - resize a VT - * @tty: tty to resize - * @ws: winsize attributes + * vt_resize - resize a VT + * @tty: tty to resize + * @ws: winsize attributes * - * Resize a virtual terminal. This is called by the tty layer as we - * register our own handler for resizing. The mutual helper does all - * the actual work. + * Resize a virtual terminal. This is called by the tty layer as we register + * our own handler for resizing. The mutual helper does all the actual work. * - * Takes the console sem and the called methods then take the tty - * termios_rwsem and the tty ctrl.lock in that order. + * Locking: Takes the console sem and the called methods then take the tty + * termios_rwsem and the tty ctrl.lock in that order. */ static int vt_resize(struct tty_struct *tty, struct winsize *ws) { @@ -2633,8 +2632,8 @@ static inline int vc_translate_ascii(const struct vc_data *vc, int c) /** - * vc_sanitize_unicode - Replace invalid Unicode code points with U+FFFD - * @c: the received character, or U+FFFD for invalid sequences. + * vc_sanitize_unicode - Replace invalid Unicode code points with ``U+FFFD`` + * @c: the received character, or ``U+FFFD`` for invalid sequences. */ static inline int vc_sanitize_unicode(const int c) { @@ -2645,14 +2644,15 @@ static inline int vc_sanitize_unicode(const int c) } /** - * vc_translate_unicode - Combine UTF-8 into Unicode in @vc_utf_char + * vc_translate_unicode - Combine UTF-8 into Unicode in &vc_data.vc_utf_char * @vc: virtual console * @c: character to translate * @rescan: we return true if we need more (continuation) data * - * @vc_utf_char is the being-constructed unicode character. - * @vc_utf_count is the number of continuation bytes still expected to arrive. - * @vc_npar is the number of continuation bytes arrived so far. + * * &vc_data.vc_utf_char is the being-constructed unicode character. + * * &vc_data.vc_utf_count is the number of continuation bytes still expected to + * arrive. + * * &vc_data.vc_npar is the number of continuation bytes arrived so far. */ static int vc_translate_unicode(struct vc_data *vc, int c, bool *rescan) { @@ -3030,16 +3030,16 @@ struct tty_driver *console_driver; #ifdef CONFIG_VT_CONSOLE /** - * vt_kmsg_redirect() - Sets/gets the kernel message console - * @new: The new virtual terminal number or -1 if the console should stay - * unchanged + * vt_kmsg_redirect() - sets/gets the kernel message console + * @new: the new virtual terminal number or -1 if the console should stay + * unchanged * * By default, the kernel messages are always printed on the current virtual * console. However, the user may modify that default with the - * TIOCL_SETKMSGREDIRECT ioctl call. + * %TIOCL_SETKMSGREDIRECT ioctl call. * * This function sets the kernel message console to be @new. It returns the old - * virtual console number. The virtual terminal number 0 (both as parameter and + * virtual console number. The virtual terminal number %0 (both as parameter and * return value) means no redirection (i.e. always printed on the currently * active console). * @@ -3047,8 +3047,8 @@ struct tty_driver *console_driver; * value is not modified. You may use the macro vt_get_kmsg_redirect() in that * case to make the code more understandable. * - * When the kernel is compiled without CONFIG_VT_CONSOLE, this function ignores - * the parameter and always returns 0. + * When the kernel is compiled without %CONFIG_VT_CONSOLE, this function ignores + * the parameter and always returns %0. */ int vt_kmsg_redirect(int new) { @@ -3960,7 +3960,7 @@ static void vtconsole_deinit_device(struct con_driver *con) * RETURNS: zero if unbound, nonzero if bound * * Drivers can call this and if zero, they should release - * all resources allocated on con_startup() + * all resources allocated on &consw.con_startup() */ int con_is_bound(const struct consw *csw) { diff --git a/include/linux/console.h b/include/linux/console.h index f1a334ad268d..d6d8b7e6b93b 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -155,7 +155,7 @@ static inline void con_debug_leave(void) { } */ /** - * cons_flags - General console flags + * enum cons_flags - General console flags * @CON_PRINTBUFFER: Used by newly registered consoles to avoid duplicate * output of messages that were already shown by boot * consoles or read by userspace via syslog() syscall. @@ -236,7 +236,7 @@ struct nbcon_state { static_assert(sizeof(struct nbcon_state) <= sizeof(int)); /** - * nbcon_prio - console owner priority for nbcon consoles + * enum nbcon_prio - console owner priority for nbcon consoles * @NBCON_PRIO_NONE: Unused * @NBCON_PRIO_NORMAL: Normal (non-emergency) usage * @NBCON_PRIO_EMERGENCY: Emergency output (WARN/OOPS...) @@ -468,7 +468,7 @@ static inline bool console_is_registered(const struct console *con) * for_each_console() - Iterator over registered consoles * @con: struct console pointer used as loop cursor * - * The console list and the console->flags are immutable while iterating. + * The console list and the &console.flags are immutable while iterating. * * Requires console_list_lock to be held. */ From cf066f9334b9632ca1a8185118083a9218504e0a Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 22 Jan 2024 12:04:01 +0100 Subject: [PATCH 047/199] Documentation: add console.rst Now, that the console kernel-doc is in better shape, include it in the tty/ docs. It's not supernice, but it is what it is. At least for the beginning. Signed-off-by: "Jiri Slaby (SUSE)" Cc: Jonathan Corbet Cc: linux-doc@vger.kernel.org Tested-by: Helge Deller # parisc STI console Link: https://lore.kernel.org/r/20240122110401.7289-48-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/tty/console.rst | 45 ++++++++++++++++++++++++ Documentation/driver-api/tty/index.rst | 1 + 2 files changed, 46 insertions(+) create mode 100644 Documentation/driver-api/tty/console.rst diff --git a/Documentation/driver-api/tty/console.rst b/Documentation/driver-api/tty/console.rst new file mode 100644 index 000000000000..4348e36cd33b --- /dev/null +++ b/Documentation/driver-api/tty/console.rst @@ -0,0 +1,45 @@ +.. SPDX-License-Identifier: GPL-2.0 + +======= +Console +======= + +.. contents:: :local: + +Struct Console +============== + +.. kernel-doc:: include/linux/console.h + :identifiers: console cons_flags + +Internals +--------- + +.. kernel-doc:: include/linux/console.h + :identifiers: nbcon_state nbcon_prio nbcon_context nbcon_write_context + +Struct Consw +============ + +.. kernel-doc:: include/linux/console.h + :identifiers: consw + +Console functions +================= + +.. kernel-doc:: include/linux/console.h + :identifiers: console_srcu_read_flags console_srcu_write_flags + console_is_registered for_each_console_srcu for_each_console + +.. kernel-doc:: drivers/tty/vt/selection.c + :export: +.. kernel-doc:: drivers/tty/vt/vt.c + :export: + +Internals +--------- + +.. kernel-doc:: drivers/tty/vt/selection.c + :internal: +.. kernel-doc:: drivers/tty/vt/vt.c + :internal: diff --git a/Documentation/driver-api/tty/index.rst b/Documentation/driver-api/tty/index.rst index b490da11f257..c1ffe3d1ec46 100644 --- a/Documentation/driver-api/tty/index.rst +++ b/Documentation/driver-api/tty/index.rst @@ -38,6 +38,7 @@ In-detail description of the named TTY structures is in separate documents: tty_buffer tty_ioctl tty_internals + console Writing TTY Driver ================== From fed99212acae832607817b24fa589f8aaf03103f Mon Sep 17 00:00:00 2001 From: Francesco Dolcini Date: Mon, 22 Jan 2024 19:05:51 +0100 Subject: [PATCH 048/199] treewide, serdev: change receive_buf() return type to size_t MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit receive_buf() is called from ttyport_receive_buf() that expects values ">= 0" from serdev_controller_receive_buf(), change its return type from ssize_t to size_t. The need for this clean-up was noticed while fixing a warning, see commit 94d053942544 ("Bluetooth: btnxpuart: fix recv_buf() return value"). Changing the callback prototype to return an unsigned seems the best way to document the API and ensure that is properly used. GNSS drivers implementation of serdev receive_buf() callback return directly the return value of gnss_insert_raw(). gnss_insert_raw() returns a signed int, however this is not an issue since the value returned is always positive, because of the kfifo_in() implementation. gnss_insert_raw() could be changed to return also an unsigned, however this is not implemented here as request by the GNSS maintainer Johan Hovold. Suggested-by: Jiri Slaby Link: https://lore.kernel.org/all/087be419-ec6b-47ad-851a-5e1e3ea5cfcc@kernel.org/ Signed-off-by: Francesco Dolcini Acked-by: Jonathan Cameron #for-iio Reviewed-by: Johan Hovold Reviewed-by: Rob Herring Reviewed-by: Alex Elder Acked-by: Maximilian Luz # for platform/surface Acked-by: Lee Jones Acked-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20240122180551.34429-1-francesco@dolcini.it Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/btmtkuart.c | 4 ++-- drivers/bluetooth/btnxpuart.c | 4 ++-- drivers/bluetooth/hci_serdev.c | 4 ++-- drivers/gnss/serial.c | 2 +- drivers/gnss/sirf.c | 2 +- drivers/greybus/gb-beagleplay.c | 6 +++--- drivers/iio/chemical/pms7003.c | 4 ++-- drivers/iio/chemical/scd30_serial.c | 4 ++-- drivers/iio/chemical/sps30_serial.c | 4 ++-- drivers/iio/imu/bno055/bno055_ser_core.c | 4 ++-- drivers/mfd/rave-sp.c | 4 ++-- drivers/net/ethernet/qualcomm/qca_uart.c | 2 +- drivers/nfc/pn533/uart.c | 4 ++-- drivers/nfc/s3fwrn5/uart.c | 4 ++-- drivers/platform/chrome/cros_ec_uart.c | 4 ++-- drivers/platform/surface/aggregator/core.c | 4 ++-- drivers/tty/serdev/serdev-ttyport.c | 10 ++++------ include/linux/serdev.h | 8 ++++---- sound/drivers/serial-generic.c | 4 ++-- 19 files changed, 40 insertions(+), 42 deletions(-) diff --git a/drivers/bluetooth/btmtkuart.c b/drivers/bluetooth/btmtkuart.c index 3c84fcbda01a..e6bc4a73c9fc 100644 --- a/drivers/bluetooth/btmtkuart.c +++ b/drivers/bluetooth/btmtkuart.c @@ -383,8 +383,8 @@ static void btmtkuart_recv(struct hci_dev *hdev, const u8 *data, size_t count) } } -static ssize_t btmtkuart_receive_buf(struct serdev_device *serdev, - const u8 *data, size_t count) +static size_t btmtkuart_receive_buf(struct serdev_device *serdev, + const u8 *data, size_t count) { struct btmtkuart_dev *bdev = serdev_device_get_drvdata(serdev); diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c index 1d592ac413d1..056bef5b2919 100644 --- a/drivers/bluetooth/btnxpuart.c +++ b/drivers/bluetooth/btnxpuart.c @@ -1264,8 +1264,8 @@ static const struct h4_recv_pkt nxp_recv_pkts[] = { { NXP_RECV_FW_REQ_V3, .recv = nxp_recv_fw_req_v3 }, }; -static ssize_t btnxpuart_receive_buf(struct serdev_device *serdev, - const u8 *data, size_t count) +static size_t btnxpuart_receive_buf(struct serdev_device *serdev, + const u8 *data, size_t count) { struct btnxpuart_dev *nxpdev = serdev_device_get_drvdata(serdev); diff --git a/drivers/bluetooth/hci_serdev.c b/drivers/bluetooth/hci_serdev.c index 39c8b567da3c..a3c3beb2806d 100644 --- a/drivers/bluetooth/hci_serdev.c +++ b/drivers/bluetooth/hci_serdev.c @@ -271,8 +271,8 @@ static void hci_uart_write_wakeup(struct serdev_device *serdev) * * Return: number of processed bytes */ -static ssize_t hci_uart_receive_buf(struct serdev_device *serdev, - const u8 *data, size_t count) +static size_t hci_uart_receive_buf(struct serdev_device *serdev, + const u8 *data, size_t count) { struct hci_uart *hu = serdev_device_get_drvdata(serdev); diff --git a/drivers/gnss/serial.c b/drivers/gnss/serial.c index baa956494e79..0e43bf6294f8 100644 --- a/drivers/gnss/serial.c +++ b/drivers/gnss/serial.c @@ -80,7 +80,7 @@ static const struct gnss_operations gnss_serial_gnss_ops = { .write_raw = gnss_serial_write_raw, }; -static ssize_t gnss_serial_receive_buf(struct serdev_device *serdev, +static size_t gnss_serial_receive_buf(struct serdev_device *serdev, const u8 *buf, size_t count) { struct gnss_serial *gserial = serdev_device_get_drvdata(serdev); diff --git a/drivers/gnss/sirf.c b/drivers/gnss/sirf.c index 6801a8fb2040..79375d14bbb6 100644 --- a/drivers/gnss/sirf.c +++ b/drivers/gnss/sirf.c @@ -160,7 +160,7 @@ static const struct gnss_operations sirf_gnss_ops = { .write_raw = sirf_write_raw, }; -static ssize_t sirf_receive_buf(struct serdev_device *serdev, +static size_t sirf_receive_buf(struct serdev_device *serdev, const u8 *buf, size_t count) { struct sirf_data *data = serdev_device_get_drvdata(serdev); diff --git a/drivers/greybus/gb-beagleplay.c b/drivers/greybus/gb-beagleplay.c index c3e90025064b..33f8fad70260 100644 --- a/drivers/greybus/gb-beagleplay.c +++ b/drivers/greybus/gb-beagleplay.c @@ -271,7 +271,7 @@ static void hdlc_rx_frame(struct gb_beagleplay *bg) } } -static ssize_t hdlc_rx(struct gb_beagleplay *bg, const u8 *data, size_t count) +static size_t hdlc_rx(struct gb_beagleplay *bg, const u8 *data, size_t count) { size_t i; u8 c; @@ -331,8 +331,8 @@ static void hdlc_deinit(struct gb_beagleplay *bg) flush_work(&bg->tx_work); } -static ssize_t gb_tty_receive(struct serdev_device *sd, const u8 *data, - size_t count) +static size_t gb_tty_receive(struct serdev_device *sd, const u8 *data, + size_t count) { struct gb_beagleplay *bg = serdev_device_get_drvdata(sd); diff --git a/drivers/iio/chemical/pms7003.c b/drivers/iio/chemical/pms7003.c index b5cf15a515d2..43025866d5b7 100644 --- a/drivers/iio/chemical/pms7003.c +++ b/drivers/iio/chemical/pms7003.c @@ -211,8 +211,8 @@ static bool pms7003_frame_is_okay(struct pms7003_frame *frame) return checksum == pms7003_calc_checksum(frame); } -static ssize_t pms7003_receive_buf(struct serdev_device *serdev, const u8 *buf, - size_t size) +static size_t pms7003_receive_buf(struct serdev_device *serdev, const u8 *buf, + size_t size) { struct iio_dev *indio_dev = serdev_device_get_drvdata(serdev); struct pms7003_state *state = iio_priv(indio_dev); diff --git a/drivers/iio/chemical/scd30_serial.c b/drivers/iio/chemical/scd30_serial.c index a47654591e55..2adb76dbb020 100644 --- a/drivers/iio/chemical/scd30_serial.c +++ b/drivers/iio/chemical/scd30_serial.c @@ -174,8 +174,8 @@ static int scd30_serdev_command(struct scd30_state *state, enum scd30_cmd cmd, u return 0; } -static ssize_t scd30_serdev_receive_buf(struct serdev_device *serdev, - const u8 *buf, size_t size) +static size_t scd30_serdev_receive_buf(struct serdev_device *serdev, + const u8 *buf, size_t size) { struct iio_dev *indio_dev = serdev_device_get_drvdata(serdev); struct scd30_serdev_priv *priv; diff --git a/drivers/iio/chemical/sps30_serial.c b/drivers/iio/chemical/sps30_serial.c index 3afa89f8acc3..a6dfbe28c914 100644 --- a/drivers/iio/chemical/sps30_serial.c +++ b/drivers/iio/chemical/sps30_serial.c @@ -210,8 +210,8 @@ static int sps30_serial_command(struct sps30_state *state, unsigned char cmd, return rsp_size; } -static ssize_t sps30_serial_receive_buf(struct serdev_device *serdev, - const u8 *buf, size_t size) +static size_t sps30_serial_receive_buf(struct serdev_device *serdev, + const u8 *buf, size_t size) { struct iio_dev *indio_dev = dev_get_drvdata(&serdev->dev); struct sps30_serial_priv *priv; diff --git a/drivers/iio/imu/bno055/bno055_ser_core.c b/drivers/iio/imu/bno055/bno055_ser_core.c index 5677bdf4f846..694ff14a3aa2 100644 --- a/drivers/iio/imu/bno055/bno055_ser_core.c +++ b/drivers/iio/imu/bno055/bno055_ser_core.c @@ -378,8 +378,8 @@ static void bno055_ser_handle_rx(struct bno055_ser_priv *priv, int status) * Also, we assume to RX one pkt per time (i.e. the HW doesn't send anything * unless we require to AND we don't queue more than one request per time). */ -static ssize_t bno055_ser_receive_buf(struct serdev_device *serdev, - const u8 *buf, size_t size) +static size_t bno055_ser_receive_buf(struct serdev_device *serdev, + const u8 *buf, size_t size) { int status; struct bno055_ser_priv *priv = serdev_device_get_drvdata(serdev); diff --git a/drivers/mfd/rave-sp.c b/drivers/mfd/rave-sp.c index 6ff84b2600c5..62a6613fb070 100644 --- a/drivers/mfd/rave-sp.c +++ b/drivers/mfd/rave-sp.c @@ -471,8 +471,8 @@ static void rave_sp_receive_frame(struct rave_sp *sp, rave_sp_receive_reply(sp, data, length); } -static ssize_t rave_sp_receive_buf(struct serdev_device *serdev, - const u8 *buf, size_t size) +static size_t rave_sp_receive_buf(struct serdev_device *serdev, + const u8 *buf, size_t size) { struct device *dev = &serdev->dev; struct rave_sp *sp = dev_get_drvdata(dev); diff --git a/drivers/net/ethernet/qualcomm/qca_uart.c b/drivers/net/ethernet/qualcomm/qca_uart.c index 223321897b96..20f50bde82ac 100644 --- a/drivers/net/ethernet/qualcomm/qca_uart.c +++ b/drivers/net/ethernet/qualcomm/qca_uart.c @@ -58,7 +58,7 @@ struct qcauart { unsigned char *tx_buffer; }; -static ssize_t +static size_t qca_tty_receive(struct serdev_device *serdev, const u8 *data, size_t count) { struct qcauart *qca = serdev_device_get_drvdata(serdev); diff --git a/drivers/nfc/pn533/uart.c b/drivers/nfc/pn533/uart.c index 2eb5978bd79e..cfbbe0713317 100644 --- a/drivers/nfc/pn533/uart.c +++ b/drivers/nfc/pn533/uart.c @@ -203,8 +203,8 @@ static int pn532_uart_rx_is_frame(struct sk_buff *skb) return 0; } -static ssize_t pn532_receive_buf(struct serdev_device *serdev, - const u8 *data, size_t count) +static size_t pn532_receive_buf(struct serdev_device *serdev, + const u8 *data, size_t count) { struct pn532_uart_phy *dev = serdev_device_get_drvdata(serdev); size_t i; diff --git a/drivers/nfc/s3fwrn5/uart.c b/drivers/nfc/s3fwrn5/uart.c index 456d3947116c..9c09c10c2a46 100644 --- a/drivers/nfc/s3fwrn5/uart.c +++ b/drivers/nfc/s3fwrn5/uart.c @@ -51,8 +51,8 @@ static const struct s3fwrn5_phy_ops uart_phy_ops = { .write = s3fwrn82_uart_write, }; -static ssize_t s3fwrn82_uart_read(struct serdev_device *serdev, - const u8 *data, size_t count) +static size_t s3fwrn82_uart_read(struct serdev_device *serdev, + const u8 *data, size_t count) { struct s3fwrn82_uart_phy *phy = serdev_device_get_drvdata(serdev); size_t i; diff --git a/drivers/platform/chrome/cros_ec_uart.c b/drivers/platform/chrome/cros_ec_uart.c index 68d80559fddc..8ea867c2a01a 100644 --- a/drivers/platform/chrome/cros_ec_uart.c +++ b/drivers/platform/chrome/cros_ec_uart.c @@ -81,8 +81,8 @@ struct cros_ec_uart { struct response_info response; }; -static ssize_t cros_ec_uart_rx_bytes(struct serdev_device *serdev, - const u8 *data, size_t count) +static size_t cros_ec_uart_rx_bytes(struct serdev_device *serdev, + const u8 *data, size_t count) { struct ec_host_response *host_response; struct cros_ec_device *ec_dev = serdev_device_get_drvdata(serdev); diff --git a/drivers/platform/surface/aggregator/core.c b/drivers/platform/surface/aggregator/core.c index 9591a28bc38a..ba550eaa06fc 100644 --- a/drivers/platform/surface/aggregator/core.c +++ b/drivers/platform/surface/aggregator/core.c @@ -227,8 +227,8 @@ EXPORT_SYMBOL_GPL(ssam_client_bind); /* -- Glue layer (serdev_device -> ssam_controller). ------------------------ */ -static ssize_t ssam_receive_buf(struct serdev_device *dev, const u8 *buf, - size_t n) +static size_t ssam_receive_buf(struct serdev_device *dev, const u8 *buf, + size_t n) { struct ssam_controller *ctrl; int ret; diff --git a/drivers/tty/serdev/serdev-ttyport.c b/drivers/tty/serdev/serdev-ttyport.c index e94e090cf0a1..3d7ae7fa5018 100644 --- a/drivers/tty/serdev/serdev-ttyport.c +++ b/drivers/tty/serdev/serdev-ttyport.c @@ -27,19 +27,17 @@ static size_t ttyport_receive_buf(struct tty_port *port, const u8 *cp, { struct serdev_controller *ctrl = port->client_data; struct serport *serport = serdev_controller_get_drvdata(ctrl); - int ret; + size_t ret; if (!test_bit(SERPORT_ACTIVE, &serport->flags)) return 0; ret = serdev_controller_receive_buf(ctrl, cp, count); - dev_WARN_ONCE(&ctrl->dev, ret < 0 || ret > count, - "receive_buf returns %d (count = %zu)\n", + dev_WARN_ONCE(&ctrl->dev, ret > count, + "receive_buf returns %zu (count = %zu)\n", ret, count); - if (ret < 0) - return 0; - else if (ret > count) + if (ret > count) return count; return ret; diff --git a/include/linux/serdev.h b/include/linux/serdev.h index 3fab88ba265e..ff78efc1f60d 100644 --- a/include/linux/serdev.h +++ b/include/linux/serdev.h @@ -27,7 +27,7 @@ struct serdev_device; * not sleep. */ struct serdev_device_ops { - ssize_t (*receive_buf)(struct serdev_device *, const u8 *, size_t); + size_t (*receive_buf)(struct serdev_device *, const u8 *, size_t); void (*write_wakeup)(struct serdev_device *); }; @@ -185,9 +185,9 @@ static inline void serdev_controller_write_wakeup(struct serdev_controller *ctrl serdev->ops->write_wakeup(serdev); } -static inline ssize_t serdev_controller_receive_buf(struct serdev_controller *ctrl, - const u8 *data, - size_t count) +static inline size_t serdev_controller_receive_buf(struct serdev_controller *ctrl, + const u8 *data, + size_t count) { struct serdev_device *serdev = ctrl->serdev; diff --git a/sound/drivers/serial-generic.c b/sound/drivers/serial-generic.c index d6e5aafd697c..36409a56c675 100644 --- a/sound/drivers/serial-generic.c +++ b/sound/drivers/serial-generic.c @@ -100,8 +100,8 @@ static void snd_serial_generic_write_wakeup(struct serdev_device *serdev) snd_serial_generic_tx_wakeup(drvdata); } -static ssize_t snd_serial_generic_receive_buf(struct serdev_device *serdev, - const u8 *buf, size_t count) +static size_t snd_serial_generic_receive_buf(struct serdev_device *serdev, + const u8 *buf, size_t count) { int ret; struct snd_serial_generic *drvdata = serdev_device_get_drvdata(serdev); From e9e873eadced9389b819685a762c9892500f12d0 Mon Sep 17 00:00:00 2001 From: Lizhe Date: Fri, 12 Jan 2024 05:39:23 -0800 Subject: [PATCH 049/199] serial: linflexuart: Remove redundant uart type assignment In linflex_config_port() the member variable type will be assigned again. Remove redundant uart type assignment from linflex_probe(). Signed-off-by: Lizhe Link: https://lore.kernel.org/r/20240112133923.190852-1-sensor1010@163.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_linflexuart.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c index 52c87876a88d..5426322b5f0c 100644 --- a/drivers/tty/serial/fsl_linflexuart.c +++ b/drivers/tty/serial/fsl_linflexuart.c @@ -837,7 +837,6 @@ static int linflex_probe(struct platform_device *pdev) return ret; sport->dev = &pdev->dev; - sport->type = PORT_LINFLEXUART; sport->iotype = UPIO_MEM; sport->irq = ret; sport->ops = &linflex_pops; From c01e71b49c37e3b9c9652d28c42a88197a9d7f02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roman=20=C5=BDilka?= Date: Tue, 9 Jan 2024 11:43:46 +0100 Subject: [PATCH 050/199] tty/vt: UTF-8 parsing update according to RFC 3629, modern Unicode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vc_translate_unicode() and vc_sanitize_unicode() parse input to the UTF-8-enabled console, marking invalid byte sequences and producing Unicode codepoints. The current algorithm follows ancient Unicode and may accept invalid byte sequences, pass on non-existent codepoints and reject valid sequences. The patch restores the functions' compliance with modern Unicode (v15.1 [1] + many previous versions) as well as RFC 3629 [2]. 1. Codepoint space is limited to 0x10FFFF. 2. "Noncharacters", such as U+FFFE, U+FFFF, are no longer invalid in Unicode and will be accepted. Another option was to complete the set of noncharacters (used to be just those two, now there's more) and preserve the rejection step. This is indeed what Unicode suggests ([1] chap. 23.7) (not requires), but most codepoints are !iswprint(), so selecting just the noncharacters seemed arbitrary and futile (and unnecessary). This is not a security patch. I'm not aware of any present security implications of the old code. [1] https://www.unicode.org/versions/Unicode15.1.0 [2] https://datatracker.ietf.org/doc/html/rfc3629 Signed-off-by: Roman Žilka Link: https://lore.kernel.org/r/598ab459-6ba9-4a17-b4a1-08f26a356fc0@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index e9cdcf40fe14..65cd40cac96b 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2637,7 +2637,7 @@ static inline int vc_translate_ascii(const struct vc_data *vc, int c) */ static inline int vc_sanitize_unicode(const int c) { - if ((c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff) + if (c >= 0xd800 && c <= 0xdfff) return 0xfffd; return c; @@ -2656,10 +2656,7 @@ static inline int vc_sanitize_unicode(const int c) */ static int vc_translate_unicode(struct vc_data *vc, int c, bool *rescan) { - static const u32 utf8_length_changes[] = { - 0x0000007f, 0x000007ff, 0x0000ffff, - 0x001fffff, 0x03ffffff, 0x7fffffff - }; + static const u32 utf8_length_changes[] = {0x7f, 0x7ff, 0xffff, 0x10ffff}; /* Continuation byte received */ if ((c & 0xc0) == 0x80) { @@ -2705,14 +2702,7 @@ static int vc_translate_unicode(struct vc_data *vc, int c, bool *rescan) } else if ((c & 0xf8) == 0xf0) { vc->vc_utf_count = 3; vc->vc_utf_char = (c & 0x07); - } else if ((c & 0xfc) == 0xf8) { - vc->vc_utf_count = 4; - vc->vc_utf_char = (c & 0x03); - } else if ((c & 0xfe) == 0xfc) { - vc->vc_utf_count = 5; - vc->vc_utf_char = (c & 0x01); } else { - /* 254 and 255 are invalid */ return 0xfffd; } From 85725449f3e5faf385210d535f266430be71cebb Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 10 Jan 2024 14:21:46 +0100 Subject: [PATCH 051/199] serial: 8250: Move hp300_setup_serial_console() to MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If CONFIG_SERIAL_8250_HP300=y and CONFIG_SERIAL_8250_CONSOLE=y (e.g. m68k/allyesconfig): drivers/tty/serial/8250/8250_hp300.c:91:12: error: no previous prototype for ‘hp300_setup_serial_console’ [-Werror=missing-prototypes] 91 | int __init hp300_setup_serial_console(void) | ^~~~~~~~~~~~~~~~~~~~~~~~~~ Fix this by moving the existing prototype in arch/m68k/hp300/config.c to , so it is visible to both caller and implementor. While at it, provide a dummy in case CONFIG_SERIAL_8250_CONSOLE is not enabled, to reduce #ifdef clutter in the caller. Exposed by commit 0fcb70851fbfea17 ("Makefile.extrawarn: turn on missing-prototypes globally"). Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/c17469f8e47b2ef49234a85a7a14882ddf374e41.1704892597.git.geert@linux-m68k.org Signed-off-by: Greg Kroah-Hartman --- arch/m68k/hp300/config.c | 6 +----- include/linux/serial_8250.h | 6 ++++++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/arch/m68k/hp300/config.c b/arch/m68k/hp300/config.c index e4bd6913f50e..1a2739852351 100644 --- a/arch/m68k/hp300/config.c +++ b/arch/m68k/hp300/config.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -67,9 +68,6 @@ static char *hp300_models[] __initdata = { static char hp300_model_name[13] = "HP9000/"; extern void hp300_reset(void); -#ifdef CONFIG_SERIAL_8250_CONSOLE -extern int hp300_setup_serial_console(void) __init; -#endif int __init hp300_parse_bootinfo(const struct bi_record *record) { @@ -263,7 +261,5 @@ void __init config_hp300(void) } else { panic("Unknown HP9000 Model"); } -#ifdef CONFIG_SERIAL_8250_CONSOLE hp300_setup_serial_console(); -#endif } diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index be65de65fe61..fd59ed2cca53 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -210,6 +210,12 @@ int serial8250_console_exit(struct uart_port *port); void serial8250_set_isa_configurator(void (*v)(int port, struct uart_port *up, u32 *capabilities)); +#ifdef CONFIG_SERIAL_8250_CONSOLE +extern int hp300_setup_serial_console(void) __init; +#else +static inline int hp300_setup_serial_console(void) { return 0; } +#endif + #ifdef CONFIG_SERIAL_8250_RT288X int rt288x_setup(struct uart_port *p); int au_platform_setup(struct plat_serial8250_port *p); From 486676116f4852d4198690c2c98af060cd96ab83 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Fri, 12 Jan 2024 15:03:07 -0800 Subject: [PATCH 052/199] soc: qcom: geni-se: Add M_TX_FIFO_NOT_EMPTY bit definition According to the docs I have, bit 21 of the status register is asserted when the FIFO is _not_ empty. Add the definition. Signed-off-by: Douglas Anderson Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20240112150307.1.I7dc0993c1e758a1efedd651e7e1670deb1b430fb@changeid Signed-off-by: Greg Kroah-Hartman --- include/linux/soc/qcom/geni-se.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/soc/qcom/geni-se.h b/include/linux/soc/qcom/geni-se.h index 29e06905bc1f..0f038a1a0330 100644 --- a/include/linux/soc/qcom/geni-se.h +++ b/include/linux/soc/qcom/geni-se.h @@ -178,6 +178,7 @@ struct geni_se { #define M_GP_IRQ_3_EN BIT(12) #define M_GP_IRQ_4_EN BIT(13) #define M_GP_IRQ_5_EN BIT(14) +#define M_TX_FIFO_NOT_EMPTY_EN BIT(21) #define M_IO_DATA_DEASSERT_EN BIT(22) #define M_IO_DATA_ASSERT_EN BIT(23) #define M_RX_FIFO_RD_ERR_EN BIT(24) From 9e957a155005b16af057e86c6bcc1197cd70a6af Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Fri, 12 Jan 2024 15:03:08 -0800 Subject: [PATCH 053/199] serial: qcom-geni: Don't cancel/abort if we can't get the port lock As of commit d7402513c935 ("arm64: smp: IPI_CPU_STOP and IPI_CPU_CRASH_STOP should try for NMI"), if we've got pseudo-NMI enabled then we'll use it to stop CPUs at panic time. This is nice, but it does mean that there's a pretty good chance that we'll end up stopping a CPU while it holds the port lock for the console UART. Specifically, I see a CPU get stopped while holding the port lock nearly 100% of the time on my sc7180-trogdor based Chromebook by enabling the "buddy" hardlockup detector and then doing: sysctl -w kernel.hardlockup_all_cpu_backtrace=1 sysctl -w kernel.hardlockup_panic=1 echo HARDLOCKUP > /sys/kernel/debug/provoke-crash/DIRECT UART drivers are _supposed_ to handle this case OK and this is why UART drivers check "oops_in_progress" and only do a "trylock" in that case. However, before we enabled pseudo-NMI to stop CPUs it wasn't a very well-tested situation. Now that we're testing the situation a lot, it can be seen that the Qualcomm GENI UART driver is pretty broken. Specifically, when I run my test case and look at the console output I just see a bunch of garbled output like: [ 201.069084] NMI backtrace[ 201.069084] NM[ 201.069087] CPU: 6 PID: 10296 Comm: dnsproxyd Not tainted 6.7.0-06265-gb13e8c0ede12 #1 01112b9f14923cbd0b[ 201.069090] Hardware name: Google Lazor ([ 201.069092] pstate: 80400009 (Nzcv daif +PAN -UAO -TCO -DI[ 201.069095] pc : smp_call_function_man[ 201.069099] That's obviously not so great. This happens because each call to the console driver exits after the data has been written to the FIFO but before it's actually been flushed out of the serial port. When we have multiple calls into the console one after the other then (if we can't get the lock) each call tells the UART to throw away any data in the FIFO that hadn't been transferred yet. I've posted up a patch to change the arm64 core to avoid this situation most of the time [1] much like x86 seems to do, but even if that patch lands the GENI driver should still be fixed. >From testing, it appears that we can just delete the cancel/abort in the case where we weren't able to get the UART lock and the output looks good. It makes sense that we'd be able to do this since that means we'll just call into __qcom_geni_serial_console_write() and __qcom_geni_serial_console_write() looks much like qcom_geni_serial_poll_put_char() but with a loop. However, it seems safest to poll the FIFO and make sure it's empty before our transfer. This should reliably make sure that we're not interrupting/clobbering any existing transfers. As part of this change, we'll also avoid re-setting up a TX at the end of the console write function if we weren't able to get the lock, since accessing "port->tx_remaining" without the lock is not safe. This is only needed to re-start userspace initiated transfers. [1] https://lore.kernel.org/r/20231207170251.1.Id4817adef610302554b8aa42b090d57270dc119c@changeid Signed-off-by: Douglas Anderson Link: https://lore.kernel.org/r/20240112150307.2.Idb1553d1d22123c377f31eacb4486432f6c9ac8d@changeid Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/qcom_geni_serial.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index e63a8fbe63bd..fdc75bb26c69 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -488,18 +488,16 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s, geni_status = readl(uport->membase + SE_GENI_STATUS); - /* Cancel the current write to log the fault */ if (!locked) { - geni_se_cancel_m_cmd(&port->se); - if (!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, - M_CMD_CANCEL_EN, true)) { - geni_se_abort_m_cmd(&port->se); - qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, - M_CMD_ABORT_EN, true); - writel(M_CMD_ABORT_EN, uport->membase + - SE_GENI_M_IRQ_CLEAR); - } - writel(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); + /* + * We can only get here if an oops is in progress then we were + * unable to get the lock. This means we can't safely access + * our state variables like tx_remaining. About the best we + * can do is wait for the FIFO to be empty before we start our + * transfer, so we'll do that. + */ + qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, + M_TX_FIFO_NOT_EMPTY_EN, false); } else if ((geni_status & M_GENI_CMD_ACTIVE) && !port->tx_remaining) { /* * It seems we can't interrupt existing transfers if all data @@ -516,11 +514,12 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s, __qcom_geni_serial_console_write(uport, s, count); - if (port->tx_remaining) - qcom_geni_serial_setup_tx(uport, port->tx_remaining); - if (locked) + if (locked) { + if (port->tx_remaining) + qcom_geni_serial_setup_tx(uport, port->tx_remaining); uart_port_unlock_irqrestore(uport, flags); + } } static void handle_rx_console(struct uart_port *uport, u32 bytes, bool drop) From 5c49b6a4a4bcf368f85cfe7a0e5ac3a7016f30fd Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Mon, 8 Jan 2024 14:41:02 +0100 Subject: [PATCH 054/199] vt: remove superfluous CONFIG_HW_CONSOLE The config HW_CONSOLE is always identical to the config VT and is not visible in the kernel's build menuconfig. So, CONFIG_HW_CONSOLE is redundant. Replace all references to CONFIG_HW_CONSOLE with CONFIG_VT and remove CONFIG_HW_CONSOLE. Signed-off-by: Lukas Bulwahn Reviewed-by: Javier Martinez Canillas Acked-by: Dmitry Torokhov Reviewed-by: Geert Uytterhoeven Acked-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20240108134102.601-1-lukas.bulwahn@gmail.com Signed-off-by: Greg Kroah-Hartman --- arch/m68k/amiga/config.c | 2 +- drivers/input/keyboard/amikbd.c | 6 +++--- drivers/tty/Kconfig | 7 +------ drivers/tty/vt/Makefile | 4 ++-- drivers/video/fbdev/tgafb.c | 2 +- include/linux/console.h | 2 +- lib/Kconfig.kgdb | 2 +- 7 files changed, 10 insertions(+), 15 deletions(-) diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c index 7791673e547b..99718f3dc686 100644 --- a/arch/m68k/amiga/config.c +++ b/arch/m68k/amiga/config.c @@ -846,6 +846,6 @@ static void amiga_get_hardware_list(struct seq_file *m) * The Amiga keyboard driver needs key_maps, but we cannot export it in * drivers/char/defkeymap.c, as it is autogenerated */ -#ifdef CONFIG_HW_CONSOLE +#ifdef CONFIG_VT EXPORT_SYMBOL_GPL(key_maps); #endif diff --git a/drivers/input/keyboard/amikbd.c b/drivers/input/keyboard/amikbd.c index e305c44cd0aa..ecfae0b0b6aa 100644 --- a/drivers/input/keyboard/amikbd.c +++ b/drivers/input/keyboard/amikbd.c @@ -26,7 +26,7 @@ MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("Amiga keyboard driver"); MODULE_LICENSE("GPL"); -#ifdef CONFIG_HW_CONSOLE +#ifdef CONFIG_VT static unsigned char amikbd_keycode[0x78] __initdata = { [0] = KEY_GRAVE, [1] = KEY_1, @@ -148,9 +148,9 @@ static void __init amikbd_init_console_keymaps(void) memcpy(key_maps[i], temp_map, sizeof(temp_map)); } } -#else /* !CONFIG_HW_CONSOLE */ +#else /* !CONFIG_VT */ static inline void amikbd_init_console_keymaps(void) {} -#endif /* !CONFIG_HW_CONSOLE */ +#endif /* !CONFIG_VT */ static const char *amikbd_messages[8] = { [0] = KERN_ALERT "amikbd: Ctrl-Amiga-Amiga reset warning!!\n", diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index 5646dc6242cd..a45d423ad10f 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -75,14 +75,9 @@ config VT_CONSOLE_SLEEP def_bool y depends on VT_CONSOLE && PM_SLEEP -config HW_CONSOLE - bool - depends on VT - default y - config VT_HW_CONSOLE_BINDING bool "Support for binding and unbinding console drivers" - depends on HW_CONSOLE + depends on VT help The virtual terminal is the device that interacts with the physical terminal through console drivers. On these systems, at least one diff --git a/drivers/tty/vt/Makefile b/drivers/tty/vt/Makefile index b3dfe9d5717e..2c8ce8b592ed 100644 --- a/drivers/tty/vt/Makefile +++ b/drivers/tty/vt/Makefile @@ -5,9 +5,9 @@ FONTMAPFILE = cp437.uni obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o \ - selection.o keyboard.o + selection.o keyboard.o \ + vt.o defkeymap.o obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o consolemap_deftbl.o -obj-$(CONFIG_HW_CONSOLE) += vt.o defkeymap.o # Files generated that shall be removed upon make clean clean-files := consolemap_deftbl.c defkeymap.c diff --git a/drivers/video/fbdev/tgafb.c b/drivers/video/fbdev/tgafb.c index ca43774f3156..dccfc38cfbd5 100644 --- a/drivers/video/fbdev/tgafb.c +++ b/drivers/video/fbdev/tgafb.c @@ -380,7 +380,7 @@ tgafb_set_par(struct fb_info *info) BT463_LOAD_ADDR(par, 0x0000); TGA_WRITE_REG(par, BT463_PALETTE << 2, TGA_RAMDAC_SETUP_REG); -#ifdef CONFIG_HW_CONSOLE +#ifdef CONFIG_VT for (i = 0; i < 16; i++) { int j = color_table[i]; diff --git a/include/linux/console.h b/include/linux/console.h index d6d8b7e6b93b..31a8f5b85f5d 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -141,7 +141,7 @@ int con_is_bound(const struct consw *csw); int do_unregister_con_driver(const struct consw *csw); int do_take_over_console(const struct consw *sw, int first, int last, int deflt); void give_up_console(const struct consw *sw); -#ifdef CONFIG_HW_CONSOLE +#ifdef CONFIG_VT void con_debug_enter(struct vc_data *vc); void con_debug_leave(void); #else diff --git a/lib/Kconfig.kgdb b/lib/Kconfig.kgdb index 3b9a44008433..b5c0e6576749 100644 --- a/lib/Kconfig.kgdb +++ b/lib/Kconfig.kgdb @@ -43,7 +43,7 @@ config KGDB_SERIAL_CONSOLE tristate "KGDB: use kgdb over the serial console" select CONSOLE_POLL select MAGIC_SYSRQ - depends on TTY && HW_CONSOLE + depends on TTY && VT default y help Share a serial console with kgdb. Sysrq-g must be used From ec240f88934f6ecda5cd21514cc6f30e0ec5d955 Mon Sep 17 00:00:00 2001 From: Valentin Caron Date: Fri, 12 Jan 2024 10:52:57 +0100 Subject: [PATCH 055/199] serial: stm32: implement prescaler tuning to compute low baudrate In the case of high USART input clock and low baud rate, BRR value is not enough to get correct baud rate. So here we use USART prescaler to divide USART input clock to get the correct baud rate. PRESC register is only available since stm32h7. Signed-off-by: Valentin Caron Link: https://lore.kernel.org/r/20240112095300.2004878-2-valentin.caron@foss.st.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/stm32-usart.c | 71 ++++++++++++++++++++++---------- drivers/tty/serial/stm32-usart.h | 6 +++ 2 files changed, 56 insertions(+), 21 deletions(-) diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 794b77512740..19a45e1b7102 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -9,6 +9,7 @@ * Inspired by st-asc.c from STMicroelectronics (c) */ +#include #include #include #include @@ -50,6 +51,7 @@ static struct stm32_usart_info __maybe_unused stm32f4_info = { .rtor = UNDEF_REG, .rqr = UNDEF_REG, .icr = UNDEF_REG, + .presc = UNDEF_REG, }, .cfg = { .uart_enable_bit = 13, @@ -71,6 +73,7 @@ static struct stm32_usart_info __maybe_unused stm32f7_info = { .icr = 0x20, .rdr = 0x24, .tdr = 0x28, + .presc = UNDEF_REG, }, .cfg = { .uart_enable_bit = 0, @@ -93,6 +96,7 @@ static struct stm32_usart_info __maybe_unused stm32h7_info = { .icr = 0x20, .rdr = 0x24, .tdr = 0x28, + .presc = 0x2c, }, .cfg = { .uart_enable_bit = 0, @@ -1145,6 +1149,8 @@ static void stm32_usart_shutdown(struct uart_port *port) free_irq(port->irq, port); } +static const unsigned int stm32_usart_presc_val[] = {1, 2, 4, 6, 8, 10, 12, 16, 32, 64, 128, 256}; + static void stm32_usart_set_termios(struct uart_port *port, struct ktermios *termios, const struct ktermios *old) @@ -1153,17 +1159,19 @@ static void stm32_usart_set_termios(struct uart_port *port, const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; const struct stm32_usart_config *cfg = &stm32_port->info->cfg; struct serial_rs485 *rs485conf = &port->rs485; - unsigned int baud, bits; + unsigned int baud, bits, uart_clk, uart_clk_pres; u32 usartdiv, mantissa, fraction, oversampling; tcflag_t cflag = termios->c_cflag; - u32 cr1, cr2, cr3, isr; + u32 cr1, cr2, cr3, isr, brr, presc; unsigned long flags; int ret; if (!stm32_port->hw_flow_control) cflag &= ~CRTSCTS; - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 8); + uart_clk = clk_get_rate(stm32_port->clk); + + baud = uart_get_baud_rate(port, termios, old, 0, uart_clk / 8); uart_port_lock_irqsave(port, &flags); @@ -1265,27 +1273,48 @@ static void stm32_usart_set_termios(struct uart_port *port, cr3 |= USART_CR3_CTSE | USART_CR3_RTSE; } - usartdiv = DIV_ROUND_CLOSEST(port->uartclk, baud); + for (presc = 0; presc <= USART_PRESC_MAX; presc++) { + uart_clk_pres = DIV_ROUND_CLOSEST(uart_clk, stm32_usart_presc_val[presc]); + usartdiv = DIV_ROUND_CLOSEST(uart_clk_pres, baud); - /* - * The USART supports 16 or 8 times oversampling. - * By default we prefer 16 times oversampling, so that the receiver - * has a better tolerance to clock deviations. - * 8 times oversampling is only used to achieve higher speeds. - */ - if (usartdiv < 16) { - oversampling = 8; - cr1 |= USART_CR1_OVER8; - stm32_usart_set_bits(port, ofs->cr1, USART_CR1_OVER8); - } else { - oversampling = 16; - cr1 &= ~USART_CR1_OVER8; - stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_OVER8); + /* + * The USART supports 16 or 8 times oversampling. + * By default we prefer 16 times oversampling, so that the receiver + * has a better tolerance to clock deviations. + * 8 times oversampling is only used to achieve higher speeds. + */ + if (usartdiv < 16) { + oversampling = 8; + cr1 |= USART_CR1_OVER8; + stm32_usart_set_bits(port, ofs->cr1, USART_CR1_OVER8); + } else { + oversampling = 16; + cr1 &= ~USART_CR1_OVER8; + stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_OVER8); + } + + mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT; + fraction = usartdiv % oversampling; + brr = mantissa | fraction; + + if (FIELD_FIT(USART_BRR_MASK, brr)) { + if (ofs->presc != UNDEF_REG) { + port->uartclk = uart_clk_pres; + writel_relaxed(presc, port->membase + ofs->presc); + } else if (presc) { + /* We need a prescaler but we don't have it (STM32F4, STM32F7) */ + dev_err(port->dev, + "unable to set baudrate, input clock is too high"); + } + break; + } else if (presc == USART_PRESC_MAX) { + /* Even with prescaler and brr at max value we can't set baudrate */ + dev_err(port->dev, "unable to set baudrate, input clock is too high"); + break; + } } - mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT; - fraction = usartdiv % oversampling; - writel_relaxed(mantissa | fraction, port->membase + ofs->brr); + writel_relaxed(brr, port->membase + ofs->brr); uart_update_timeout(port, cflag, baud); diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h index f59f831b2a10..8cecfdce9386 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -20,6 +20,7 @@ struct stm32_usart_offsets { u8 icr; u8 rdr; u8 tdr; + u8 presc; }; struct stm32_usart_config { @@ -71,6 +72,7 @@ struct stm32_usart_info { #define USART_BRR_DIV_M_MASK GENMASK(15, 4) #define USART_BRR_DIV_M_SHIFT 4 #define USART_BRR_04_R_SHIFT 1 +#define USART_BRR_MASK (USART_BRR_DIV_M_MASK | USART_BRR_DIV_F_MASK) /* USART_CR1 */ #define USART_CR1_SBK BIT(0) @@ -176,6 +178,10 @@ struct stm32_usart_info { #define USART_ICR_CMCF BIT(17) /* F7 */ #define USART_ICR_WUCF BIT(20) /* H7 */ +/* USART_PRESC */ +#define USART_PRESC GENMASK(3, 0) /* H7 */ +#define USART_PRESC_MAX 0b1011 + #define STM32_SERIAL_NAME "ttySTM" #define STM32_MAX_PORTS 8 From 7316888fa44f48bd00070290d2eb229f44a55135 Mon Sep 17 00:00:00 2001 From: Valentin Caron Date: Fri, 12 Jan 2024 10:52:58 +0100 Subject: [PATCH 056/199] serial: stm32: extend max number of U(S)ART to 9 STM32MP25x got 9 instances of U(S)ART. So extend STM32_MAX_PORTS to 9, in order to handle all instances. Signed-off-by: Valentin Caron Link: https://lore.kernel.org/r/20240112095300.2004878-3-valentin.caron@foss.st.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/stm32-usart.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h index 8cecfdce9386..5ce1d3aae07e 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -183,7 +183,7 @@ struct stm32_usart_info { #define USART_PRESC_MAX 0b1011 #define STM32_SERIAL_NAME "ttySTM" -#define STM32_MAX_PORTS 8 +#define STM32_MAX_PORTS 9 #define RX_BUF_L 4096 /* dma rx buffer length */ #define RX_BUF_P (RX_BUF_L / 2) /* dma rx buffer period */ From 7be985bd7cd5c6c605ec710e691620b8afb983fd Mon Sep 17 00:00:00 2001 From: Valentin Caron Date: Fri, 12 Jan 2024 10:52:59 +0100 Subject: [PATCH 057/199] serial: stm32: change register's offset type from u8 to u16 USART has registers above 0xff offset, so extend variable type to u16. And change UNDEF_REG to 0xffff. Signed-off-by: Valentin Caron Link: https://lore.kernel.org/r/20240112095300.2004878-4-valentin.caron@foss.st.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/stm32-usart.h | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h index 5ce1d3aae07e..bf3720948704 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -9,18 +9,18 @@ #define DRIVER_NAME "stm32-usart" struct stm32_usart_offsets { - u8 cr1; - u8 cr2; - u8 cr3; - u8 brr; - u8 gtpr; - u8 rtor; - u8 rqr; - u8 isr; - u8 icr; - u8 rdr; - u8 tdr; - u8 presc; + u16 cr1; + u16 cr2; + u16 cr3; + u16 brr; + u16 gtpr; + u16 rtor; + u16 rqr; + u16 isr; + u16 icr; + u16 rdr; + u16 tdr; + u16 presc; }; struct stm32_usart_config { @@ -37,7 +37,7 @@ struct stm32_usart_info { struct stm32_usart_config cfg; }; -#define UNDEF_REG 0xff +#define UNDEF_REG 0xffff /* USART_SR (F4) / USART_ISR (F7) */ #define USART_SR_PE BIT(0) From 5d207f62cec8d6e6f0fb6f35495723bf3960daf7 Mon Sep 17 00:00:00 2001 From: Valentin Caron Date: Fri, 12 Jan 2024 10:53:00 +0100 Subject: [PATCH 058/199] serial: stm32: get FIFO size from hwcfg register Since STM32MP25, FIFO size could vary regarding the STM32MPxx version. So we get this size from "hwcfgr1" register and compute threshold values corresponding to the ratio given by reference manual. As STM32MP1x, STM32MP25 and STM32H7 share the same compatible and STM32H7 doesn't have a register to get FIFO size, we force FIFO size to 16 in case of zero read from hwcfgr1 register. Signed-off-by: Valentin Caron Link: https://lore.kernel.org/r/20240112095300.2004878-5-valentin.caron@foss.st.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/stm32-usart.c | 158 +++++++++++++++++-------------- drivers/tty/serial/stm32-usart.h | 6 +- 2 files changed, 94 insertions(+), 70 deletions(-) diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 19a45e1b7102..3cbb498c6ea6 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -40,63 +40,64 @@ /* Register offsets */ static struct stm32_usart_info __maybe_unused stm32f4_info = { .ofs = { - .isr = 0x00, - .rdr = 0x04, - .tdr = 0x04, - .brr = 0x08, - .cr1 = 0x0c, - .cr2 = 0x10, - .cr3 = 0x14, - .gtpr = 0x18, - .rtor = UNDEF_REG, - .rqr = UNDEF_REG, - .icr = UNDEF_REG, - .presc = UNDEF_REG, + .isr = 0x00, + .rdr = 0x04, + .tdr = 0x04, + .brr = 0x08, + .cr1 = 0x0c, + .cr2 = 0x10, + .cr3 = 0x14, + .gtpr = 0x18, + .rtor = UNDEF_REG, + .rqr = UNDEF_REG, + .icr = UNDEF_REG, + .presc = UNDEF_REG, + .hwcfgr1 = UNDEF_REG, }, .cfg = { .uart_enable_bit = 13, .has_7bits_data = false, - .fifosize = 1, } }; static struct stm32_usart_info __maybe_unused stm32f7_info = { .ofs = { - .cr1 = 0x00, - .cr2 = 0x04, - .cr3 = 0x08, - .brr = 0x0c, - .gtpr = 0x10, - .rtor = 0x14, - .rqr = 0x18, - .isr = 0x1c, - .icr = 0x20, - .rdr = 0x24, - .tdr = 0x28, - .presc = UNDEF_REG, + .cr1 = 0x00, + .cr2 = 0x04, + .cr3 = 0x08, + .brr = 0x0c, + .gtpr = 0x10, + .rtor = 0x14, + .rqr = 0x18, + .isr = 0x1c, + .icr = 0x20, + .rdr = 0x24, + .tdr = 0x28, + .presc = UNDEF_REG, + .hwcfgr1 = UNDEF_REG, }, .cfg = { .uart_enable_bit = 0, .has_7bits_data = true, .has_swap = true, - .fifosize = 1, } }; static struct stm32_usart_info __maybe_unused stm32h7_info = { .ofs = { - .cr1 = 0x00, - .cr2 = 0x04, - .cr3 = 0x08, - .brr = 0x0c, - .gtpr = 0x10, - .rtor = 0x14, - .rqr = 0x18, - .isr = 0x1c, - .icr = 0x20, - .rdr = 0x24, - .tdr = 0x28, - .presc = 0x2c, + .cr1 = 0x00, + .cr2 = 0x04, + .cr3 = 0x08, + .brr = 0x0c, + .gtpr = 0x10, + .rtor = 0x14, + .rqr = 0x18, + .isr = 0x1c, + .icr = 0x20, + .rdr = 0x24, + .tdr = 0x28, + .presc = 0x2c, + .hwcfgr1 = 0x3f0, }, .cfg = { .uart_enable_bit = 0, @@ -104,7 +105,6 @@ static struct stm32_usart_info __maybe_unused stm32h7_info = { .has_swap = true, .has_wakeup = true, .has_fifo = true, - .fifosize = 16, } }; @@ -1498,37 +1498,57 @@ static const struct uart_ops stm32_uart_ops = { #endif /* CONFIG_CONSOLE_POLL */ }; -/* - * STM32H7 RX & TX FIFO threshold configuration (CR3 RXFTCFG / TXFTCFG) - * Note: 1 isn't a valid value in RXFTCFG / TXFTCFG. In this case, - * RXNEIE / TXEIE can be used instead of threshold irqs: RXFTIE / TXFTIE. - * So, RXFTCFG / TXFTCFG bitfields values are encoded as array index + 1. - */ -static const u32 stm32h7_usart_fifo_thresh_cfg[] = { 1, 2, 4, 8, 12, 14, 16 }; +struct stm32_usart_thresh_ratio { + int mul; + int div; +}; -static void stm32_usart_get_ftcfg(struct platform_device *pdev, const char *p, - int *ftcfg) +static const struct stm32_usart_thresh_ratio stm32h7_usart_fifo_thresh_cfg[] = { + {1, 8}, {1, 4}, {1, 2}, {3, 4}, {7, 8}, {1, 1} }; + +static int stm32_usart_get_thresh_value(u32 fifo_size, int index) { - u32 bytes, i; + return fifo_size * stm32h7_usart_fifo_thresh_cfg[index].mul / + stm32h7_usart_fifo_thresh_cfg[index].div; +} - /* DT option to get RX & TX FIFO threshold (default to 8 bytes) */ +static int stm32_usart_get_ftcfg(struct platform_device *pdev, struct stm32_port *stm32port, + const char *p, int *ftcfg) +{ + const struct stm32_usart_offsets *ofs = &stm32port->info->ofs; + u32 bytes, i, cfg8; + int fifo_size; + + if (WARN_ON(ofs->hwcfgr1 == UNDEF_REG)) + return 1; + + cfg8 = FIELD_GET(USART_HWCFGR1_CFG8, + readl_relaxed(stm32port->port.membase + ofs->hwcfgr1)); + + /* On STM32H7, hwcfgr is not present, so returned value will be 0 */ + fifo_size = cfg8 ? 1 << cfg8 : STM32H7_USART_FIFO_SIZE; + + /* DT option to get RX & TX FIFO threshold (default to half fifo size) */ if (of_property_read_u32(pdev->dev.of_node, p, &bytes)) - bytes = 8; + bytes = fifo_size / 2; - for (i = 0; i < ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg); i++) - if (stm32h7_usart_fifo_thresh_cfg[i] >= bytes) + if (bytes < stm32_usart_get_thresh_value(fifo_size, 0)) { + *ftcfg = -EINVAL; + return fifo_size; + } + + for (i = 0; i < ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg); i++) { + if (stm32_usart_get_thresh_value(fifo_size, i) >= bytes) break; + } if (i >= ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg)) i = ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg) - 1; - dev_dbg(&pdev->dev, "%s set to %d bytes\n", p, - stm32h7_usart_fifo_thresh_cfg[i]); + dev_dbg(&pdev->dev, "%s set to %d/%d bytes\n", p, + stm32_usart_get_thresh_value(fifo_size, i), fifo_size); - /* Provide FIFO threshold ftcfg (1 is invalid: threshold irq unused) */ - if (i) - *ftcfg = i - 1; - else - *ftcfg = -EINVAL; + *ftcfg = i; + return fifo_size; } static void stm32_usart_deinit_port(struct stm32_port *stm32port) @@ -1558,7 +1578,6 @@ static int stm32_usart_init_port(struct stm32_port *stm32port, port->flags = UPF_BOOT_AUTOCONF; port->ops = &stm32_uart_ops; port->dev = &pdev->dev; - port->fifosize = stm32port->info->cfg.fifosize; port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_STM32_CONSOLE); port->irq = irq; port->rs485_config = stm32_usart_config_rs485; @@ -1574,14 +1593,6 @@ static int stm32_usart_init_port(struct stm32_port *stm32port, stm32port->swap = stm32port->info->cfg.has_swap && of_property_read_bool(pdev->dev.of_node, "rx-tx-swap"); - stm32port->fifoen = stm32port->info->cfg.has_fifo; - if (stm32port->fifoen) { - stm32_usart_get_ftcfg(pdev, "rx-threshold", - &stm32port->rxftcfg); - stm32_usart_get_ftcfg(pdev, "tx-threshold", - &stm32port->txftcfg); - } - port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(port->membase)) return PTR_ERR(port->membase); @@ -1604,6 +1615,15 @@ static int stm32_usart_init_port(struct stm32_port *stm32port, goto err_clk; } + stm32port->fifoen = stm32port->info->cfg.has_fifo; + if (stm32port->fifoen) { + stm32_usart_get_ftcfg(pdev, stm32port, "rx-threshold", &stm32port->rxftcfg); + port->fifosize = stm32_usart_get_ftcfg(pdev, stm32port, "tx-threshold", + &stm32port->txftcfg); + } else { + port->fifosize = 1; + } + stm32port->gpios = mctrl_gpio_init(&stm32port->port, 0); if (IS_ERR(stm32port->gpios)) { ret = PTR_ERR(stm32port->gpios); diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h index bf3720948704..af20258ccc7a 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -21,6 +21,7 @@ struct stm32_usart_offsets { u16 rdr; u16 tdr; u16 presc; + u16 hwcfgr1; }; struct stm32_usart_config { @@ -29,7 +30,6 @@ struct stm32_usart_config { bool has_swap; bool has_wakeup; bool has_fifo; - int fifosize; }; struct stm32_usart_info { @@ -182,8 +182,12 @@ struct stm32_usart_info { #define USART_PRESC GENMASK(3, 0) /* H7 */ #define USART_PRESC_MAX 0b1011 +/* USART_HWCFCR1 */ +#define USART_HWCFGR1_CFG8 GENMASK(31, 28) /* MP1 */ + #define STM32_SERIAL_NAME "ttySTM" #define STM32_MAX_PORTS 9 +#define STM32H7_USART_FIFO_SIZE 16 #define RX_BUF_L 4096 /* dma rx buffer length */ #define RX_BUF_P (RX_BUF_L / 2) /* dma rx buffer period */ From 0d27056c24efd3d63a03f3edfbcfc4827086b110 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 18 Jan 2024 10:21:57 -0500 Subject: [PATCH 059/199] serial: max310x: fix NULL pointer dereference in I2C instantiation When trying to instantiate a max14830 device from userspace: echo max14830 0x60 > /sys/bus/i2c/devices/i2c-2/new_device we get the following error: Unable to handle kernel NULL pointer dereference at virtual address... ... Call trace: max310x_i2c_probe+0x48/0x170 [max310x] i2c_device_probe+0x150/0x2a0 ... Add check for validity of devtype to prevent the error, and abort probe with a meaningful error message. Fixes: 2e1f2d9a9bdb ("serial: max310x: implement I2C support") Cc: stable@vger.kernel.org Reviewed-by: Andy Shevchenko Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20240118152213.2644269-2-hugo@hugovil.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index f3a99daebdaa..4a33fd950ed2 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1602,13 +1602,16 @@ static unsigned short max310x_i2c_slave_addr(unsigned short addr, static int max310x_i2c_probe(struct i2c_client *client) { - const struct max310x_devtype *devtype = - device_get_match_data(&client->dev); + const struct max310x_devtype *devtype; struct i2c_client *port_client; struct regmap *regmaps[4]; unsigned int i; u8 port_addr; + devtype = device_get_match_data(&client->dev); + if (!devtype) + return dev_err_probe(&client->dev, -ENODEV, "Failed to match device\n"); + if (client->addr < devtype->slave_addr.min || client->addr > devtype->slave_addr.max) return dev_err_probe(&client->dev, -EINVAL, From 60a389a5c82bc75894cb5568fdb5feb138b91c73 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 18 Jan 2024 10:21:58 -0500 Subject: [PATCH 060/199] serial: max310x: add I2C device table for instantiation from userspace This allows to instantiate a max14830 I2C device from userspace. Helpful when testing driver with i2c-stub. Reviewed-by: Andy Shevchenko Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20240118152213.2644269-3-hugo@hugovil.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 4a33fd950ed2..053cf2458264 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1639,6 +1639,15 @@ static void max310x_i2c_remove(struct i2c_client *client) max310x_remove(&client->dev); } +static const struct i2c_device_id max310x_i2c_id_table[] = { + { "max3107", (kernel_ulong_t)&max3107_devtype, }, + { "max3108", (kernel_ulong_t)&max3108_devtype, }, + { "max3109", (kernel_ulong_t)&max3109_devtype, }, + { "max14830", (kernel_ulong_t)&max14830_devtype, }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max310x_i2c_id_table); + static struct i2c_driver max310x_i2c_driver = { .driver = { .name = MAX310X_NAME, @@ -1647,6 +1656,7 @@ static struct i2c_driver max310x_i2c_driver = { }, .probe = max310x_i2c_probe, .remove = max310x_i2c_remove, + .id_table = max310x_i2c_id_table, }; #endif From 754500bf73e351e5ba29560d3e8fc7931f8d3a1d Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 18 Jan 2024 10:21:59 -0500 Subject: [PATCH 061/199] serial: max310x: use i2c_get_match_data() Use preferred i2c_get_match_data() instead of device_get_match_data() to get the driver match data. Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20240118152213.2644269-4-hugo@hugovil.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 053cf2458264..a051bc773c4b 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1608,7 +1608,7 @@ static int max310x_i2c_probe(struct i2c_client *client) unsigned int i; u8 port_addr; - devtype = device_get_match_data(&client->dev); + devtype = i2c_get_match_data(client); if (!devtype) return dev_err_probe(&client->dev, -ENODEV, "Failed to match device\n"); From fc7c3921074cd1166703bb1bda19b1800aa95674 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 18 Jan 2024 10:22:00 -0500 Subject: [PATCH 062/199] serial: max310x: use spi_get_device_match_data() Use preferred spi_get_device_match_data() instead of device_get_match_data() and spi_get_device_id() to get the driver match data. Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20240118152213.2644269-5-hugo@hugovil.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index a051bc773c4b..2314ec2afd3f 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1514,9 +1514,9 @@ static int max310x_spi_probe(struct spi_device *spi) if (ret) return ret; - devtype = device_get_match_data(&spi->dev); + devtype = spi_get_device_match_data(spi); if (!devtype) - devtype = (struct max310x_devtype *)spi_get_device_id(spi)->driver_data; + return dev_err_probe(&spi->dev, -ENODEV, "Failed to match device\n"); for (i = 0; i < devtype->nr; i++) { u8 port_mask = i * 0x20; From 8ede8c6f474255b2213cccd7997b993272a8e2f9 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 18 Jan 2024 10:22:01 -0500 Subject: [PATCH 063/199] serial: max310x: fix syntax error in IRQ error message Replace g with q. Helpful when grepping thru source code or logs for "request" keyword. Fixes: f65444187a66 ("serial: New serial driver MAX310X") Reviewed-by: Andy Shevchenko Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20240118152213.2644269-6-hugo@hugovil.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 2314ec2afd3f..27c8ec956691 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1428,7 +1428,7 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty if (!ret) return 0; - dev_err(dev, "Unable to reguest IRQ %i\n", irq); + dev_err(dev, "Unable to request IRQ %i\n", irq); out_uart: for (i = 0; i < devtype->nr; i++) { From eaf29135abb1c152a05572a5454c61dcd65bdeea Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 18 Jan 2024 10:22:02 -0500 Subject: [PATCH 064/199] serial: max310x: remove holes in struct max310x_devtype Running pahole shows that there are some holes within the max310x_devtype structure. Remove holes and optimize alignment by reorganizing structure members. This can also lead to data structure size reduction for some CPUs. On 64-bit CPU (arm64): Before: /* size: 40, cachelines: 1, members: 6 */ /* sum members: 34, holes: 2, sum holes: 6 */ /* last cacheline: 40 bytes */ After: /* size: 40, cachelines: 1, members: 6 */ /* padding: 6 */ /* last cacheline: 40 bytes */ On 32-bit CPU (i386): Before: /* size: 32, cachelines: 1, members: 6 */ /* sum members: 26, holes: 2, sum holes: 6 */ /* last cacheline: 32 bytes */ After: /* size: 24, cachelines: 1, members: 8 */ /* padding: 2 */ /* last cacheline: 24 bytes */ Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20240118152213.2644269-7-hugo@hugovil.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 27c8ec956691..21f2fa3a91e5 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -258,11 +258,11 @@ struct max310x_devtype { unsigned short min; unsigned short max; } slave_addr; - char name[9]; int nr; - u8 mode1; int (*detect)(struct device *); void (*power)(struct uart_port *, int); + char name[9]; + u8 mode1; }; struct max310x_one { From dbaa0083896cb44d2b9023c04fc15d1324c88d10 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 18 Jan 2024 10:22:03 -0500 Subject: [PATCH 065/199] serial: max310x: add macro for max number of ports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add macro to hold the maximum number of UART ports per IC/device. Reviewed-by: Andy Shevchenko Reviewed-by: Jan Kundrát Tested-by: Jan Kundrát Link: https://lore.kernel.org/all/ddbc67dd-f8a3-4a6a-954a-bee49260ecab@cesnet.cz/ Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20240118152213.2644269-8-hugo@hugovil.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 21f2fa3a91e5..6549eee4f6a6 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -30,6 +30,7 @@ #define MAX310X_MAJOR 204 #define MAX310X_MINOR 209 #define MAX310X_UART_NRMAX 16 +#define MAX310X_MAX_PORTS 4 /* Maximum number of UART ports per IC. */ /* MAX310X register definitions */ #define MAX310X_RHR_REG (0x00) /* RX FIFO */ @@ -1502,7 +1503,7 @@ static const struct max310x_if_cfg __maybe_unused max310x_spi_if_cfg = { static int max310x_spi_probe(struct spi_device *spi) { const struct max310x_devtype *devtype; - struct regmap *regmaps[4]; + struct regmap *regmaps[MAX310X_MAX_PORTS]; unsigned int i; int ret; @@ -1604,7 +1605,7 @@ static int max310x_i2c_probe(struct i2c_client *client) { const struct max310x_devtype *devtype; struct i2c_client *port_client; - struct regmap *regmaps[4]; + struct regmap *regmaps[MAX310X_MAX_PORTS]; unsigned int i; u8 port_addr; From 609aabb259d497578ffa2d66ced57c22044f821c Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 18 Jan 2024 10:22:04 -0500 Subject: [PATCH 066/199] serial: max310x: use separate regmap name for each port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use a separate regmap name for each port so they can each have their own debugfs entry, allowing to access each port registers independently. For example, a four channels/ports device like the MAX14830 will have four entries in its regmap debugfs: $ find /sys/kernel/debug/regmap -type d | grep spi0.0 /sys/kernel/debug/regmap/spi0.0-port0 /sys/kernel/debug/regmap/spi0.0-port1 /sys/kernel/debug/regmap/spi0.0-port2 /sys/kernel/debug/regmap/spi0.0-port3 Cc: Jan Kundrát Link: https://lore.kernel.org/all/77f101f1-897d-4e6d-a8fd-27b818caf768@cesnet.cz/ Reviewed-by: Andy Shevchenko Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20240118152213.2644269-9-hugo@hugovil.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 6549eee4f6a6..d6219077d23c 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1486,6 +1486,19 @@ static struct regmap_config regcfg = { .max_raw_write = MAX310X_FIFO_SIZE, }; +static const char *max310x_regmap_name(u8 port_id) +{ + switch (port_id) { + case 0: return "port0"; + case 1: return "port1"; + case 2: return "port2"; + case 3: return "port3"; + default: + WARN_ON(true); + return NULL; + } +} + #ifdef CONFIG_SPI_MASTER static int max310x_spi_extended_reg_enable(struct device *dev, bool enable) { @@ -1521,6 +1534,8 @@ static int max310x_spi_probe(struct spi_device *spi) for (i = 0; i < devtype->nr; i++) { u8 port_mask = i * 0x20; + + regcfg.name = max310x_regmap_name(i); regcfg.read_flag_mask = port_mask; regcfg.write_flag_mask = port_mask | MAX310X_WRITE_BIT; regmaps[i] = devm_regmap_init_spi(spi, ®cfg); @@ -1620,6 +1635,7 @@ static int max310x_i2c_probe(struct i2c_client *client) client->addr, devtype->slave_addr.min, devtype->slave_addr.max); + regcfg_i2c.name = max310x_regmap_name(0); regmaps[0] = devm_regmap_init_i2c(client, ®cfg_i2c); for (i = 1; i < devtype->nr; i++) { @@ -1628,6 +1644,7 @@ static int max310x_i2c_probe(struct i2c_client *client) client->adapter, port_addr); + regcfg_i2c.name = max310x_regmap_name(i); regmaps[i] = devm_regmap_init_i2c(port_client, ®cfg_i2c); } From 5d888f1c32e2281843d58eef963e3ebd625b77a9 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 18 Jan 2024 10:22:05 -0500 Subject: [PATCH 067/199] serial: max310x: simplify probe() and remove() error handling Simplify error handling and only call uart_remove_one_port() if line bit is set, instead of having to manually set s->p[i].port.dev to NULL. Reviewed-by: Andy Shevchenko Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20240118152213.2644269-10-hugo@hugovil.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index d6219077d23c..9ef146f09d5b 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1395,10 +1395,9 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty /* Register port */ ret = uart_add_one_port(&max310x_uart, &s->p[i].port); - if (ret) { - s->p[i].port.dev = NULL; + if (ret) goto out_uart; - } + set_bit(line, max310x_lines); /* Go to suspend mode */ @@ -1433,10 +1432,8 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty out_uart: for (i = 0; i < devtype->nr; i++) { - if (s->p[i].port.dev) { + if (test_and_clear_bit(s->p[i].port.line, max310x_lines)) uart_remove_one_port(&max310x_uart, &s->p[i].port); - clear_bit(s->p[i].port.line, max310x_lines); - } } out_clk: @@ -1454,8 +1451,10 @@ static void max310x_remove(struct device *dev) cancel_work_sync(&s->p[i].tx_work); cancel_work_sync(&s->p[i].md_work); cancel_work_sync(&s->p[i].rs_work); - uart_remove_one_port(&max310x_uart, &s->p[i].port); - clear_bit(s->p[i].port.line, max310x_lines); + + if (test_and_clear_bit(s->p[i].port.line, max310x_lines)) + uart_remove_one_port(&max310x_uart, &s->p[i].port); + s->devtype->power(&s->p[i].port, 0); } From d5dd265cda8083ce63d49232e8957d9702e48a55 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 18 Jan 2024 10:22:06 -0500 Subject: [PATCH 068/199] serial: max310x: add explicit return for some switch default cases Allows to simplify code by removing the break statement in the default switch/case in some functions. Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20240118152213.2644269-11-hugo@hugovil.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 9ef146f09d5b..048ae432ba48 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -483,10 +483,8 @@ static bool max310x_reg_writeable(struct device *dev, unsigned int reg) case MAX310X_RXFIFOLVL_REG: return false; default: - break; + return true; } - - return true; } static bool max310x_reg_volatile(struct device *dev, unsigned int reg) @@ -505,10 +503,8 @@ static bool max310x_reg_volatile(struct device *dev, unsigned int reg) case MAX310X_REG_1F: return true; default: - break; + return false; } - - return false; } static bool max310x_reg_precious(struct device *dev, unsigned int reg) @@ -520,10 +516,8 @@ static bool max310x_reg_precious(struct device *dev, unsigned int reg) case MAX310X_STS_IRQSTS_REG: return true; default: - break; + return false; } - - return false; } static bool max310x_reg_noinc(struct device *dev, unsigned int reg) From e16b9c8ca378e44b92edd95743f6f0160ce616e7 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 18 Jan 2024 10:22:07 -0500 Subject: [PATCH 069/199] serial: max310x: use dev_err_probe() instead of dev_err() Replace dev_err() with dev_err_probe(). This helps in simplifing code and standardizing the error output. Reviewed-by: Andy Shevchenko Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20240118152213.2644269-12-hugo@hugovil.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 048ae432ba48..701bf54e4084 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1275,10 +1275,9 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty /* Alloc port structure */ s = devm_kzalloc(dev, struct_size(s, p, devtype->nr), GFP_KERNEL); - if (!s) { - dev_err(dev, "Error allocating port structure\n"); - return -ENOMEM; - } + if (!s) + return dev_err_probe(dev, -ENOMEM, + "Error allocating port structure\n"); /* Always ask for fixed clock rate from a property. */ device_property_read_u32(dev, "clock-frequency", &uartclk); @@ -1299,8 +1298,7 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty if (freq == 0) freq = uartclk; if (freq == 0) { - dev_err(dev, "Cannot get clock rate\n"); - ret = -EINVAL; + ret = dev_err_probe(dev, -EINVAL, "Cannot get clock rate\n"); goto out_clk; } From 08ad4824f74dd64bde06f8530505ae2b663953c2 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 18 Jan 2024 10:22:08 -0500 Subject: [PATCH 070/199] serial: max310x: replace hardcoded masks with preferred GENMASK() GENMASK() is preferred when defining bitmasks. Of all the masks changed, only MAX310x_REV_MASK is actually used. No functional change. Reviewed-by: Andy Shevchenko Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20240118152213.2644269-13-hugo@hugovil.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 701bf54e4084..c93b326faf89 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -161,14 +161,14 @@ #define MAX310X_IRDA_SIR_BIT (1 << 1) /* SIR mode enable */ /* Flow control trigger level register masks */ -#define MAX310X_FLOWLVL_HALT_MASK (0x000f) /* Flow control halt level */ -#define MAX310X_FLOWLVL_RES_MASK (0x00f0) /* Flow control resume level */ +#define MAX310X_FLOWLVL_HALT_MASK GENMASK(3, 0) /* Flow control halt level */ +#define MAX310X_FLOWLVL_RES_MASK GENMASK(7, 4) /* Flow control resume level */ #define MAX310X_FLOWLVL_HALT(words) ((words / 8) & 0x0f) #define MAX310X_FLOWLVL_RES(words) (((words / 8) & 0x0f) << 4) /* FIFO interrupt trigger level register masks */ -#define MAX310X_FIFOTRIGLVL_TX_MASK (0x0f) /* TX FIFO trigger level */ -#define MAX310X_FIFOTRIGLVL_RX_MASK (0xf0) /* RX FIFO trigger level */ +#define MAX310X_FIFOTRIGLVL_TX_MASK GENMASK(3, 0) /* TX FIFO trigger level */ +#define MAX310X_FIFOTRIGLVL_RX_MASK GENMASK(7, 4) /* RX FIFO trigger level */ #define MAX310X_FIFOTRIGLVL_TX(words) ((words / 8) & 0x0f) #define MAX310X_FIFOTRIGLVL_RX(words) (((words / 8) & 0x0f) << 4) @@ -215,8 +215,8 @@ */ /* PLL configuration register masks */ -#define MAX310X_PLLCFG_PREDIV_MASK (0x3f) /* PLL predivision value */ -#define MAX310X_PLLCFG_PLLFACTOR_MASK (0xc0) /* PLL multiplication factor */ +#define MAX310X_PLLCFG_PREDIV_MASK GENMASK(5, 0) /* PLL predivision value */ +#define MAX310X_PLLCFG_PLLFACTOR_MASK GENMASK(7, 6) /* PLL multiplication factor */ /* Baud rate generator configuration register bits */ #define MAX310X_BRGCFG_2XMODE_BIT (1 << 4) /* Double baud rate */ @@ -235,7 +235,7 @@ /* Misc definitions */ #define MAX310X_FIFO_SIZE (128) -#define MAX310x_REV_MASK (0xf8) +#define MAX310x_REV_MASK GENMASK(7, 3) #define MAX310X_WRITE_BIT 0x80 /* MAX3107 specific */ From 74fe93eae5389c96d4cfd4bc0cc5a547373ab96a Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 18 Jan 2024 10:22:09 -0500 Subject: [PATCH 071/199] serial: max310x: use common detect function for all variants Simplify driver by defining a common function to handle the detection of all variants. Reviewed-by: Andy Shevchenko Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20240118152213.2644269-14-hugo@hugovil.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 134 ++++++++++++++--------------------- 1 file changed, 54 insertions(+), 80 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index c93b326faf89..83beaab3a0c5 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -67,6 +67,7 @@ #define MAX310X_BRGDIVMSB_REG (0x1d) /* Baud rate divisor MSB */ #define MAX310X_CLKSRC_REG (0x1e) /* Clock source */ #define MAX310X_REG_1F (0x1f) +#define MAX310X_EXTREG_START (0x20) /* Only relevant in SPI mode. */ #define MAX310X_REVID_REG MAX310X_REG_1F /* Revision ID */ @@ -74,9 +75,9 @@ #define MAX310X_GLOBALCMD_REG MAX310X_REG_1F /* Global Command (WO) */ /* Extended registers */ -#define MAX310X_SPI_REVID_EXTREG MAX310X_REG_05 /* Revision ID */ -#define MAX310X_I2C_REVID_EXTREG (0x25) /* Revision ID */ - +#define MAX310X_REVID_EXTREG (0x25) /* Revision ID + * (extended addressing space) + */ /* IRQ register bits */ #define MAX310X_IRQ_LSR_BIT (1 << 0) /* LSR interrupt */ #define MAX310X_IRQ_SPCHR_BIT (1 << 1) /* Special char interrupt */ @@ -250,8 +251,7 @@ struct max310x_if_cfg { int (*extended_reg_enable)(struct device *dev, bool enable); - - unsigned int rev_id_reg; + u8 rev_id_offset; }; struct max310x_devtype { @@ -260,10 +260,11 @@ struct max310x_devtype { unsigned short max; } slave_addr; int nr; - int (*detect)(struct device *); void (*power)(struct uart_port *, int); char name[9]; u8 mode1; + u8 rev_id_val; + u8 rev_id_reg; /* Relevant only if rev_id_val is defined. */ }; struct max310x_one { @@ -324,62 +325,52 @@ static void max310x_port_update(struct uart_port *port, u8 reg, u8 mask, u8 val) regmap_update_bits(one->regmap, reg, mask, val); } -static int max3107_detect(struct device *dev) +static int max310x_detect(struct device *dev) { struct max310x_port *s = dev_get_drvdata(dev); unsigned int val = 0; int ret; - ret = regmap_read(s->regmap, MAX310X_REVID_REG, &val); - if (ret) - return ret; + /* Check if variant supports REV ID register: */ + if (s->devtype->rev_id_val) { + u8 rev_id_reg = s->devtype->rev_id_reg; - if (((val & MAX310x_REV_MASK) != MAX3107_REV_ID)) { - dev_err(dev, - "%s ID 0x%02x does not match\n", s->devtype->name, val); - return -ENODEV; - } + /* Check if REV ID is in extended addressing space: */ + if (s->devtype->rev_id_reg >= MAX310X_EXTREG_START) { + ret = s->if_cfg->extended_reg_enable(dev, true); + if (ret) + return ret; - return 0; -} + /* Adjust REV ID extended addressing space address: */ + if (s->if_cfg->rev_id_offset) + rev_id_reg -= s->if_cfg->rev_id_offset; + } -static int max3108_detect(struct device *dev) -{ - struct max310x_port *s = dev_get_drvdata(dev); - unsigned int val = 0; - int ret; + regmap_read(s->regmap, rev_id_reg, &val); - /* MAX3108 have not REV ID register, we just check default value - * from clocksource register to make sure everything works. - */ - ret = regmap_read(s->regmap, MAX310X_CLKSRC_REG, &val); - if (ret) - return ret; + if (s->devtype->rev_id_reg >= MAX310X_EXTREG_START) { + ret = s->if_cfg->extended_reg_enable(dev, false); + if (ret) + return ret; + } - if (val != (MAX310X_CLKSRC_EXTCLK_BIT | MAX310X_CLKSRC_PLLBYP_BIT)) { - dev_err(dev, "%s not present\n", s->devtype->name); - return -ENODEV; - } + if (((val & MAX310x_REV_MASK) != s->devtype->rev_id_val)) + return dev_err_probe(dev, -ENODEV, + "%s ID 0x%02x does not match\n", + s->devtype->name, val); + } else { + /* + * For variant without REV ID register, just check default value + * from clocksource register to make sure everything works. + */ + ret = regmap_read(s->regmap, MAX310X_CLKSRC_REG, &val); + if (ret) + return ret; - return 0; -} - -static int max3109_detect(struct device *dev) -{ - struct max310x_port *s = dev_get_drvdata(dev); - unsigned int val = 0; - int ret; - - ret = s->if_cfg->extended_reg_enable(dev, true); - if (ret) - return ret; - - regmap_read(s->regmap, s->if_cfg->rev_id_reg, &val); - s->if_cfg->extended_reg_enable(dev, false); - if (((val & MAX310x_REV_MASK) != MAX3109_REV_ID)) { - dev_err(dev, - "%s ID 0x%02x does not match\n", s->devtype->name, val); - return -ENODEV; + if (val != (MAX310X_CLKSRC_EXTCLK_BIT | MAX310X_CLKSRC_PLLBYP_BIT)) + return dev_err_probe(dev, -ENODEV, + "%s not present\n", + s->devtype->name); } return 0; @@ -394,27 +385,6 @@ static void max310x_power(struct uart_port *port, int on) msleep(50); } -static int max14830_detect(struct device *dev) -{ - struct max310x_port *s = dev_get_drvdata(dev); - unsigned int val = 0; - int ret; - - ret = s->if_cfg->extended_reg_enable(dev, true); - if (ret) - return ret; - - regmap_read(s->regmap, s->if_cfg->rev_id_reg, &val); - s->if_cfg->extended_reg_enable(dev, false); - if (((val & MAX310x_REV_MASK) != MAX14830_REV_ID)) { - dev_err(dev, - "%s ID 0x%02x does not match\n", s->devtype->name, val); - return -ENODEV; - } - - return 0; -} - static void max14830_power(struct uart_port *port, int on) { max310x_port_update(port, MAX310X_BRGCFG_REG, @@ -428,7 +398,8 @@ static const struct max310x_devtype max3107_devtype = { .name = "MAX3107", .nr = 1, .mode1 = MAX310X_MODE1_AUTOSLEEP_BIT | MAX310X_MODE1_IRQSEL_BIT, - .detect = max3107_detect, + .rev_id_val = MAX3107_REV_ID, + .rev_id_reg = MAX310X_REVID_REG, .power = max310x_power, .slave_addr = { .min = 0x2c, @@ -440,7 +411,8 @@ static const struct max310x_devtype max3108_devtype = { .name = "MAX3108", .nr = 1, .mode1 = MAX310X_MODE1_AUTOSLEEP_BIT, - .detect = max3108_detect, + .rev_id_val = 0, /* Unsupported. */ + .rev_id_reg = 0, /* Irrelevant when rev_id_val is not defined. */ .power = max310x_power, .slave_addr = { .min = 0x60, @@ -452,7 +424,8 @@ static const struct max310x_devtype max3109_devtype = { .name = "MAX3109", .nr = 2, .mode1 = MAX310X_MODE1_AUTOSLEEP_BIT, - .detect = max3109_detect, + .rev_id_val = MAX3109_REV_ID, + .rev_id_reg = MAX310X_REVID_EXTREG, .power = max310x_power, .slave_addr = { .min = 0x60, @@ -464,7 +437,8 @@ static const struct max310x_devtype max14830_devtype = { .name = "MAX14830", .nr = 4, .mode1 = MAX310X_MODE1_IRQSEL_BIT, - .detect = max14830_detect, + .rev_id_val = MAX14830_REV_ID, + .rev_id_reg = MAX310X_REVID_EXTREG, .power = max14830_power, .slave_addr = { .min = 0x60, @@ -1322,7 +1296,7 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty dev_set_drvdata(dev, s); /* Check device to ensure we are talking to what we expect */ - ret = devtype->detect(dev); + ret = max310x_detect(dev); if (ret) goto out_clk; @@ -1501,7 +1475,7 @@ static int max310x_spi_extended_reg_enable(struct device *dev, bool enable) static const struct max310x_if_cfg __maybe_unused max310x_spi_if_cfg = { .extended_reg_enable = max310x_spi_extended_reg_enable, - .rev_id_reg = MAX310X_SPI_REVID_EXTREG, + .rev_id_offset = MAX310X_EXTREG_START, }; static int max310x_spi_probe(struct spi_device *spi) @@ -1574,7 +1548,7 @@ static struct regmap_config regcfg_i2c = { .writeable_reg = max310x_reg_writeable, .volatile_reg = max310x_reg_volatile, .precious_reg = max310x_reg_precious, - .max_register = MAX310X_I2C_REVID_EXTREG, + .max_register = MAX310X_REVID_EXTREG, .writeable_noinc_reg = max310x_reg_noinc, .readable_noinc_reg = max310x_reg_noinc, .max_raw_read = MAX310X_FIFO_SIZE, @@ -1583,7 +1557,7 @@ static struct regmap_config regcfg_i2c = { static const struct max310x_if_cfg max310x_i2c_if_cfg = { .extended_reg_enable = max310x_i2c_extended_reg_enable, - .rev_id_reg = MAX310X_I2C_REVID_EXTREG, + .rev_id_offset = 0, /* No offset in I2C mode. */ }; static unsigned short max310x_i2c_slave_addr(unsigned short addr, From 9464833a765f66a9fbc0b972e89c1e1a13f4d3a0 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 18 Jan 2024 10:22:10 -0500 Subject: [PATCH 072/199] serial: max310x: use common power function for all variants Simplify driver by defining a common function to handle the power control of all variants. Reviewed-by: Andy Shevchenko Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20240118152213.2644269-15-hugo@hugovil.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 44 ++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 83beaab3a0c5..e39d8ea51e4e 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -260,11 +260,12 @@ struct max310x_devtype { unsigned short max; } slave_addr; int nr; - void (*power)(struct uart_port *, int); char name[9]; u8 mode1; u8 rev_id_val; u8 rev_id_reg; /* Relevant only if rev_id_val is defined. */ + u8 power_reg; /* Register address for power/sleep control. */ + u8 power_bit; /* Bit for sleep or power-off mode (active high). */ }; struct max310x_one { @@ -378,18 +379,10 @@ static int max310x_detect(struct device *dev) static void max310x_power(struct uart_port *port, int on) { - max310x_port_update(port, MAX310X_MODE1_REG, - MAX310X_MODE1_FORCESLEEP_BIT, - on ? 0 : MAX310X_MODE1_FORCESLEEP_BIT); - if (on) - msleep(50); -} + struct max310x_port *s = dev_get_drvdata(port->dev); -static void max14830_power(struct uart_port *port, int on) -{ - max310x_port_update(port, MAX310X_BRGCFG_REG, - MAX14830_BRGCFG_CLKDIS_BIT, - on ? 0 : MAX14830_BRGCFG_CLKDIS_BIT); + max310x_port_update(port, s->devtype->power_reg, s->devtype->power_bit, + on ? 0 : s->devtype->power_bit); if (on) msleep(50); } @@ -400,7 +393,8 @@ static const struct max310x_devtype max3107_devtype = { .mode1 = MAX310X_MODE1_AUTOSLEEP_BIT | MAX310X_MODE1_IRQSEL_BIT, .rev_id_val = MAX3107_REV_ID, .rev_id_reg = MAX310X_REVID_REG, - .power = max310x_power, + .power_reg = MAX310X_MODE1_REG, + .power_bit = MAX310X_MODE1_FORCESLEEP_BIT, .slave_addr = { .min = 0x2c, .max = 0x2f, @@ -413,7 +407,8 @@ static const struct max310x_devtype max3108_devtype = { .mode1 = MAX310X_MODE1_AUTOSLEEP_BIT, .rev_id_val = 0, /* Unsupported. */ .rev_id_reg = 0, /* Irrelevant when rev_id_val is not defined. */ - .power = max310x_power, + .power_reg = MAX310X_MODE1_REG, + .power_bit = MAX310X_MODE1_FORCESLEEP_BIT, .slave_addr = { .min = 0x60, .max = 0x6f, @@ -426,7 +421,8 @@ static const struct max310x_devtype max3109_devtype = { .mode1 = MAX310X_MODE1_AUTOSLEEP_BIT, .rev_id_val = MAX3109_REV_ID, .rev_id_reg = MAX310X_REVID_EXTREG, - .power = max310x_power, + .power_reg = MAX310X_MODE1_REG, + .power_bit = MAX310X_MODE1_FORCESLEEP_BIT, .slave_addr = { .min = 0x60, .max = 0x6f, @@ -439,7 +435,8 @@ static const struct max310x_devtype max14830_devtype = { .mode1 = MAX310X_MODE1_IRQSEL_BIT, .rev_id_val = MAX14830_REV_ID, .rev_id_reg = MAX310X_REVID_EXTREG, - .power = max14830_power, + .power_reg = MAX310X_BRGCFG_REG, + .power_bit = MAX14830_BRGCFG_CLKDIS_BIT, .slave_addr = { .min = 0x60, .max = 0x6f, @@ -1025,10 +1022,9 @@ static int max310x_rs485_config(struct uart_port *port, struct ktermios *termios static int max310x_startup(struct uart_port *port) { - struct max310x_port *s = dev_get_drvdata(port->dev); unsigned int val; - s->devtype->power(port, 1); + max310x_power(port, 1); /* Configure MODE1 register */ max310x_port_update(port, MAX310X_MODE1_REG, @@ -1073,12 +1069,10 @@ static int max310x_startup(struct uart_port *port) static void max310x_shutdown(struct uart_port *port) { - struct max310x_port *s = dev_get_drvdata(port->dev); - /* Disable all interrupts */ max310x_port_write(port, MAX310X_IRQEN_REG, 0); - s->devtype->power(port, 0); + max310x_power(port, 0); } static const char *max310x_type(struct uart_port *port) @@ -1140,7 +1134,7 @@ static int __maybe_unused max310x_suspend(struct device *dev) for (i = 0; i < s->devtype->nr; i++) { uart_suspend_port(&max310x_uart, &s->p[i].port); - s->devtype->power(&s->p[i].port, 0); + max310x_power(&s->p[i].port, 0); } return 0; @@ -1152,7 +1146,7 @@ static int __maybe_unused max310x_resume(struct device *dev) int i; for (i = 0; i < s->devtype->nr; i++) { - s->devtype->power(&s->p[i].port, 1); + max310x_power(&s->p[i].port, 1); uart_resume_port(&max310x_uart, &s->p[i].port); } @@ -1367,7 +1361,7 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty set_bit(line, max310x_lines); /* Go to suspend mode */ - devtype->power(&s->p[i].port, 0); + max310x_power(&s->p[i].port, 0); } #ifdef CONFIG_GPIOLIB @@ -1421,7 +1415,7 @@ static void max310x_remove(struct device *dev) if (test_and_clear_bit(s->p[i].port.line, max310x_lines)) uart_remove_one_port(&max310x_uart, &s->p[i].port); - s->devtype->power(&s->p[i].port, 0); + max310x_power(&s->p[i].port, 0); } clk_disable_unprepare(s->clk); From 79b69eb09cf5b6a77e621b2838b7e0d38113debb Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 18 Jan 2024 10:22:11 -0500 Subject: [PATCH 073/199] serial: max310x: replace bare use of 'unsigned' with 'unsigned int' (checkpatch) Fixes the following checkpatch warnings: WARNING: Prefer 'unsigned int' to bare use of 'unsigned' With this change, the affected functions now match the prototypes in struct gpio_chip. Reviewed-by: Andy Shevchenko Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20240118152213.2644269-16-hugo@hugovil.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index e39d8ea51e4e..9faea1224a58 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1156,7 +1156,7 @@ static int __maybe_unused max310x_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(max310x_pm_ops, max310x_suspend, max310x_resume); #ifdef CONFIG_GPIOLIB -static int max310x_gpio_get(struct gpio_chip *chip, unsigned offset) +static int max310x_gpio_get(struct gpio_chip *chip, unsigned int offset) { unsigned int val; struct max310x_port *s = gpiochip_get_data(chip); @@ -1167,7 +1167,7 @@ static int max310x_gpio_get(struct gpio_chip *chip, unsigned offset) return !!((val >> 4) & (1 << (offset % 4))); } -static void max310x_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +static void max310x_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) { struct max310x_port *s = gpiochip_get_data(chip); struct uart_port *port = &s->p[offset / 4].port; @@ -1176,7 +1176,7 @@ static void max310x_gpio_set(struct gpio_chip *chip, unsigned offset, int value) value ? 1 << (offset % 4) : 0); } -static int max310x_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +static int max310x_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) { struct max310x_port *s = gpiochip_get_data(chip); struct uart_port *port = &s->p[offset / 4].port; @@ -1187,7 +1187,7 @@ static int max310x_gpio_direction_input(struct gpio_chip *chip, unsigned offset) } static int max310x_gpio_direction_output(struct gpio_chip *chip, - unsigned offset, int value) + unsigned int offset, int value) { struct max310x_port *s = gpiochip_get_data(chip); struct uart_port *port = &s->p[offset / 4].port; From 9d9b9f5ac2f8120f73d9f3ca3fe2f0e51aa5f335 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 18 Jan 2024 10:22:12 -0500 Subject: [PATCH 074/199] serial: max310x: reformat and improve comments Add comments about I2C slave address structure, and reformat to improve readability. Also reformat some comments according to kernel coding style. Reviewed-by: Andy Shevchenko Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20240118152213.2644269-17-hugo@hugovil.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 40 ++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 9faea1224a58..37007b25fbee 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -179,7 +179,8 @@ #define MAX310X_FLOWCTRL_GPIADDR_BIT (1 << 2) /* Enables that GPIO inputs * are used in conjunction with * XOFF2 for definition of - * special character */ + * special character + */ #define MAX310X_FLOWCTRL_SWFLOWEN_BIT (1 << 3) /* Auto SW flow ctrl enable */ #define MAX310X_FLOWCTRL_SWFLOW0_BIT (1 << 4) /* SWFLOW bit 0 */ #define MAX310X_FLOWCTRL_SWFLOW1_BIT (1 << 5) /* SWFLOW bit 1 @@ -258,7 +259,7 @@ struct max310x_devtype { struct { unsigned short min; unsigned short max; - } slave_addr; + } slave_addr; /* Relevant only in I2C mode. */ int nr; char name[9]; u8 mode1; @@ -639,7 +640,8 @@ static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen) u8 ch, flag; if (port->read_status_mask == MAX310X_LSR_RXOVR_BIT) { - /* We are just reading, happily ignoring any error conditions. + /* + * We are just reading, happily ignoring any error conditions. * Break condition, parity checking, framing errors -- they * are all ignored. That means that we can do a batch-read. * @@ -648,7 +650,7 @@ static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen) * that the LSR register applies to the "current" character. * That's also the reason why we cannot do batched reads when * asked to check the individual statuses. - * */ + */ sts = max310x_port_read(port, MAX310X_LSR_IRQSTS_REG); max310x_batch_read(port, one->rx_buf, rxlen); @@ -752,8 +754,10 @@ static void max310x_handle_tx(struct uart_port *port) to_send = (to_send > txlen) ? txlen : to_send; if (until_end < to_send) { - /* It's a circ buffer -- wrap around. - * We could do that in one SPI transaction, but meh. */ + /* + * It's a circ buffer -- wrap around. + * We could do that in one SPI transaction, but meh. + */ max310x_batch_write(port, xmit->buf + xmit->tail, until_end); max310x_batch_write(port, xmit->buf, to_send - until_end); } else { @@ -842,7 +846,8 @@ static unsigned int max310x_tx_empty(struct uart_port *port) static unsigned int max310x_get_mctrl(struct uart_port *port) { - /* DCD and DSR are not wired and CTS/RTS is handled automatically + /* + * DCD and DSR are not wired and CTS/RTS is handled automatically * so just indicate DSR and CAR asserted */ return TIOCM_DSR | TIOCM_CAR; @@ -934,7 +939,8 @@ static void max310x_set_termios(struct uart_port *port, max310x_port_write(port, MAX310X_XON1_REG, termios->c_cc[VSTART]); max310x_port_write(port, MAX310X_XOFF1_REG, termios->c_cc[VSTOP]); - /* Disable transmitter before enabling AutoCTS or auto transmitter + /* + * Disable transmitter before enabling AutoCTS or auto transmitter * flow control */ if (termios->c_cflag & CRTSCTS || termios->c_iflag & IXOFF) { @@ -961,7 +967,8 @@ static void max310x_set_termios(struct uart_port *port, } max310x_port_write(port, MAX310X_FLOWCTRL_REG, flow); - /* Enable transmitter after disabling AutoCTS and auto transmitter + /* + * Enable transmitter after disabling AutoCTS and auto transmitter * flow control */ if (!(termios->c_cflag & CRTSCTS) && !(termios->c_iflag & IXOFF)) { @@ -1052,8 +1059,11 @@ static int max310x_startup(struct uart_port *port) MAX310X_MODE2_ECHOSUPR_BIT); } - /* Configure flow control levels */ - /* Flow control halt level 96, resume level 48 */ + /* + * Configure flow control levels: + * resume: 48 + * halt: 96 + */ max310x_port_write(port, MAX310X_FLOWLVL_REG, MAX310X_FLOWLVL_RES(48) | MAX310X_FLOWLVL_HALT(96)); @@ -1561,10 +1571,10 @@ static unsigned short max310x_i2c_slave_addr(unsigned short addr, * For MAX14830 and MAX3109, the slave address depends on what the * A0 and A1 pins are tied to. * See Table I2C Address Map of the datasheet. - * Based on that table, the following formulas were determined. - * UART1 - UART0 = 0x10 - * UART2 - UART1 = 0x20 + 0x10 - * UART3 - UART2 = 0x10 + * Based on that table, the following formulas were determined: + * UART1 - UART0 = 0x10 + * UART2 - UART1 = 0x20 + 0x10 + * UART3 - UART2 = 0x10 */ addr -= nr * 0x10; From 248bd076a70ccd6e30f766350b8844060366a7da Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 18 Jan 2024 10:22:13 -0500 Subject: [PATCH 075/199] serial: max310x: fix indentation Fix indentation and add line after do/while() block. Reviewed-by: Andy Shevchenko Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20240118152213.2644269-18-hugo@hugovil.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 37007b25fbee..0065e17572be 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -802,6 +802,7 @@ static irqreturn_t max310x_port_irq(struct max310x_port *s, int portno) if (ists & MAX310X_IRQ_TXEMPTY_BIT) max310x_start_tx(port); } while (1); + return res; } @@ -1598,7 +1599,7 @@ static int max310x_i2c_probe(struct i2c_client *client) return dev_err_probe(&client->dev, -ENODEV, "Failed to match device\n"); if (client->addr < devtype->slave_addr.min || - client->addr > devtype->slave_addr.max) + client->addr > devtype->slave_addr.max) return dev_err_probe(&client->dev, -EINVAL, "Slave addr 0x%x outside of range [0x%x, 0x%x]\n", client->addr, devtype->slave_addr.min, From 314c2b399288f0058a8c5b6683292cbde5f1531b Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 19 Jan 2024 10:45:08 +0000 Subject: [PATCH 076/199] tty: serial: samsung: fix tx_empty() to return TIOCSER_TEMT The core expects for tx_empty() either TIOCSER_TEMT when the tx is empty or 0 otherwise. s3c24xx_serial_txempty_nofifo() might return 0x4, and at least uart_get_lsr_info() tries to clear exactly TIOCSER_TEMT (BIT(1)). Fix tx_empty() to return TIOCSER_TEMT. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Tudor Ambarus Reviewed-by: Sam Protsenko Link: https://lore.kernel.org/r/20240119104526.1221243-2-tudor.ambarus@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 71d17d804fda..6fdb32b83346 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -987,11 +987,10 @@ static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port) if ((ufstat & info->tx_fifomask) != 0 || (ufstat & info->tx_fifofull)) return 0; - - return 1; + return TIOCSER_TEMT; } - return s3c24xx_serial_txempty_nofifo(port); + return s3c24xx_serial_txempty_nofifo(port) ? TIOCSER_TEMT : 0; } /* no modem control lines */ From 1d3f02abd551c69c6a82b9f22430b497b0bf7c55 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 19 Jan 2024 10:45:09 +0000 Subject: [PATCH 077/199] dt-bindings: serial: samsung: do not allow reg-io-width for gs101 All gs101 serial ports are restricted to 32-bit register accesses. This requirement will be inferred from the compatible. Do not allow the reg-io-width property for the google,gs101-uart compatible. Suggested-by: Krzysztof Kozlowski Reviewed-by: Krzysztof Kozlowski Reviewed-by: Peter Griffin Signed-off-by: Tudor Ambarus Reviewed-by: Sam Protsenko Link: https://lore.kernel.org/r/20240119104526.1221243-3-tudor.ambarus@linaro.org Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/samsung_uart.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/serial/samsung_uart.yaml b/Documentation/devicetree/bindings/serial/samsung_uart.yaml index 133259ed3a34..0f0131026911 100644 --- a/Documentation/devicetree/bindings/serial/samsung_uart.yaml +++ b/Documentation/devicetree/bindings/serial/samsung_uart.yaml @@ -143,6 +143,8 @@ allOf: then: required: - samsung,uart-fifosize + properties: + reg-io-width: false unevaluatedProperties: false From 4f6f9a3f8fc70c2497b30f190702b8321aae16fe Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 19 Jan 2024 10:45:10 +0000 Subject: [PATCH 078/199] tty: serial: samsung: prepare for different IO types GS101's Connectivity Peripheral blocks (peric0/1 blocks) which include the I3C and USI (I2C, SPI, UART) only allow 32-bit register accesses. If using 8-bit register accesses, a SError Interrupt is raised causing the system unusable. Instead of specifying the reg-io-width = 4 everywhere, for each node, the requirement should be deduced from the compatible. Prepare the samsung tty driver to allow IO types different than UPIO_MEM. ``struct uart_port::iotype`` is an unsigned char where all its 8 bits are exposed to uapi. We can't make NULL checks on it to verify if it's set, thus always set it from the driver's data. Use u8 for the ``iotype`` member of ``struct s3c24xx_uart_info`` to emphasize that the iotype is an 8 bit mask. Reviewed-by: Krzysztof Kozlowski Reviewed-by: Sam Protsenko Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/20240119104526.1221243-4-tudor.ambarus@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 6fdb32b83346..9d3767021f9c 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -84,6 +84,7 @@ struct s3c24xx_uart_info { unsigned long clksel_mask; unsigned long clksel_shift; unsigned long ucon_mask; + u8 iotype; /* uart port features */ @@ -1741,7 +1742,6 @@ static void s3c24xx_serial_init_port_default(int index) { spin_lock_init(&port->lock); - port->iotype = UPIO_MEM; port->uartclk = 0; port->fifosize = 16; port->flags = UPF_BOOT_AUTOCONF; @@ -1988,6 +1988,8 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) break; } + ourport->port.iotype = ourport->info->iotype; + if (np) { of_property_read_u32(np, "samsung,uart-fifosize", &ourport->port.fifosize); @@ -2398,6 +2400,7 @@ static const struct s3c24xx_serial_drv_data s3c6400_serial_drv_data = { .name = "Samsung S3C6400 UART", .type = TYPE_S3C6400, .port_type = PORT_S3C6400, + .iotype = UPIO_MEM, .fifosize = 64, .has_divslot = 1, .rx_fifomask = S3C2440_UFSTAT_RXMASK, @@ -2427,6 +2430,7 @@ static const struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = { .name = "Samsung S5PV210 UART", .type = TYPE_S3C6400, .port_type = PORT_S3C6400, + .iotype = UPIO_MEM, .has_divslot = 1, .rx_fifomask = S5PV210_UFSTAT_RXMASK, .rx_fifoshift = S5PV210_UFSTAT_RXSHIFT, @@ -2456,6 +2460,7 @@ static const struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = { .name = "Samsung Exynos UART", \ .type = TYPE_S3C6400, \ .port_type = PORT_S3C6400, \ + .iotype = UPIO_MEM, \ .has_divslot = 1, \ .rx_fifomask = S5PV210_UFSTAT_RXMASK, \ .rx_fifoshift = S5PV210_UFSTAT_RXSHIFT, \ @@ -2516,6 +2521,7 @@ static const struct s3c24xx_serial_drv_data s5l_serial_drv_data = { .name = "Apple S5L UART", .type = TYPE_APPLE_S5L, .port_type = PORT_8250, + .iotype = UPIO_MEM, .fifosize = 16, .rx_fifomask = S3C2410_UFSTAT_RXMASK, .rx_fifoshift = S3C2410_UFSTAT_RXSHIFT, @@ -2545,6 +2551,7 @@ static const struct s3c24xx_serial_drv_data artpec8_serial_drv_data = { .name = "Axis ARTPEC-8 UART", .type = TYPE_S3C6400, .port_type = PORT_S3C6400, + .iotype = UPIO_MEM, .fifosize = 64, .has_divslot = 1, .rx_fifomask = S5PV210_UFSTAT_RXMASK, From 0b87a9fd670abe939f6ffae7d4ab4af2c1ca6996 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 19 Jan 2024 10:45:11 +0000 Subject: [PATCH 079/199] tty: serial: samsung: set UPIO_MEM32 iotype for gs101 GS101's Connectivity Peripheral blocks (peric0/1 blocks) which include the I3C and USI (I2C, SPI, UART) only allow 32-bit register accesses. Instead of specifying the reg-io-width = 4 everywhere, for each node, the requirement should be deduced from the compatible. Infer UPIO_MEM32 iotype from the "google,gs101-uart" compatible. Update the uart info name to be GS101 specific in order to differentiate from the other exynos platforms. All the other settings are not changed. exynos_fifoszdt_serial_drv_data was replaced by gs101_serial_drv_data because the iotype restriction is gs101 specific and there was no other user of exynos_fifoszdt_serial_drv_data. Reviewed-by: Peter Griffin Reviewed-by: Krzysztof Kozlowski Reviewed-by: Sam Protsenko Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/20240119104526.1221243-5-tudor.ambarus@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 38 +++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 9d3767021f9c..7a1b1ca82511 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -2494,25 +2494,43 @@ static const struct s3c24xx_serial_drv_data exynos850_serial_drv_data = { .fifosize = { 256, 64, 64, 64 }, }; -/* - * Common drv_data struct for platforms that specify samsung,uart-fifosize in - * device tree. - */ -static const struct s3c24xx_serial_drv_data exynos_fifoszdt_serial_drv_data = { - EXYNOS_COMMON_SERIAL_DRV_DATA(), +static const struct s3c24xx_serial_drv_data gs101_serial_drv_data = { + .info = { + .name = "Google GS101 UART", + .type = TYPE_S3C6400, + .port_type = PORT_S3C6400, + .iotype = UPIO_MEM32, + .has_divslot = 1, + .rx_fifomask = S5PV210_UFSTAT_RXMASK, + .rx_fifoshift = S5PV210_UFSTAT_RXSHIFT, + .rx_fifofull = S5PV210_UFSTAT_RXFULL, + .tx_fifofull = S5PV210_UFSTAT_TXFULL, + .tx_fifomask = S5PV210_UFSTAT_TXMASK, + .tx_fifoshift = S5PV210_UFSTAT_TXSHIFT, + .def_clk_sel = S3C2410_UCON_CLKSEL0, + .num_clks = 1, + .clksel_mask = 0, + .clksel_shift = 0, + }, + .def_cfg = { + .ucon = S5PV210_UCON_DEFAULT, + .ufcon = S5PV210_UFCON_DEFAULT, + .has_fracval = 1, + }, + /* samsung,uart-fifosize must be specified in the device tree. */ .fifosize = { 0 }, }; #define EXYNOS4210_SERIAL_DRV_DATA (&exynos4210_serial_drv_data) #define EXYNOS5433_SERIAL_DRV_DATA (&exynos5433_serial_drv_data) #define EXYNOS850_SERIAL_DRV_DATA (&exynos850_serial_drv_data) -#define EXYNOS_FIFOSZDT_DRV_DATA (&exynos_fifoszdt_serial_drv_data) +#define GS101_SERIAL_DRV_DATA (&gs101_serial_drv_data) #else #define EXYNOS4210_SERIAL_DRV_DATA NULL #define EXYNOS5433_SERIAL_DRV_DATA NULL #define EXYNOS850_SERIAL_DRV_DATA NULL -#define EXYNOS_FIFOSZDT_DRV_DATA NULL +#define GS101_SERIAL_DRV_DATA NULL #endif #ifdef CONFIG_ARCH_APPLE @@ -2600,7 +2618,7 @@ static const struct platform_device_id s3c24xx_serial_driver_ids[] = { .driver_data = (kernel_ulong_t)ARTPEC8_SERIAL_DRV_DATA, }, { .name = "gs101-uart", - .driver_data = (kernel_ulong_t)EXYNOS_FIFOSZDT_DRV_DATA, + .driver_data = (kernel_ulong_t)GS101_SERIAL_DRV_DATA, }, { }, }; @@ -2623,7 +2641,7 @@ static const struct of_device_id s3c24xx_uart_dt_match[] = { { .compatible = "axis,artpec8-uart", .data = ARTPEC8_SERIAL_DRV_DATA }, { .compatible = "google,gs101-uart", - .data = EXYNOS_FIFOSZDT_DRV_DATA }, + .data = GS101_SERIAL_DRV_DATA }, {}, }; MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match); From 5887cab232f7abf4ff2e7701dec38b8f0feb4cff Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 19 Jan 2024 10:45:12 +0000 Subject: [PATCH 080/199] tty: serial: samsung: add gs101 earlycon support The entire bus (PERIC) on which the GS101 serial resides only allows 32-bit register accesses. The reg-io-width dt property is disallowed for the "google,gs101-uart" compatible and instead the iotype is inferred from the compatible. Always set UPIO_MEM32 iotype for the gs101 earlycon. Reviewed-by: Peter Griffin Reviewed-by: Krzysztof Kozlowski Reviewed-by: Sam Protsenko Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/20240119104526.1221243-6-tudor.ambarus@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 7a1b1ca82511..80b8fcf9e025 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -2809,6 +2809,17 @@ OF_EARLYCON_DECLARE(exynos4210, "samsung,exynos4210-uart", OF_EARLYCON_DECLARE(artpec8, "axis,artpec8-uart", s5pv210_early_console_setup); +static int __init gs101_early_console_setup(struct earlycon_device *device, + const char *opt) +{ + /* gs101 always expects MMIO32 register accesses. */ + device->port.iotype = UPIO_MEM32; + + return s5pv210_early_console_setup(device, opt); +} + +OF_EARLYCON_DECLARE(gs101, "google,gs101-uart", gs101_early_console_setup); + /* Apple S5L */ static int __init apple_s5l_early_console_setup(struct earlycon_device *device, const char *opt) From 1f42ff30ba52f57fcd1c8fdeb65a5e8e6f3f5ada Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 19 Jan 2024 10:45:13 +0000 Subject: [PATCH 081/199] tty: serial: samsung: sort headers alphabetically Sorting headers alphabetically helps locating duplicates, and makes it easier to figure out where to insert new headers. Reviewed-by: Sam Protsenko Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/20240119104526.1221243-7-tudor.ambarus@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 33 ++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 80b8fcf9e025..bd9064d4efe7 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -21,26 +21,27 @@ * BJD, 04-Nov-2004 */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include + #include /* UART name and device definitions */ From e88538e3c5e135ea9e3014f14962f0ab911c98d6 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 19 Jan 2024 10:45:14 +0000 Subject: [PATCH 082/199] tty: serial: samsung: explicitly include samsung_tty.c uses u32 and relies on to include . Explicitly include . We shall aim to have the driver self contained. Reviewed-by: Sam Protsenko Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/20240119104526.1221243-8-tudor.ambarus@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index bd9064d4efe7..b9b91ff6a1d7 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -41,6 +41,7 @@ #include #include #include +#include #include From 032a725c16add79332d774348d7ad7d0d4b86479 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 19 Jan 2024 10:45:15 +0000 Subject: [PATCH 083/199] tty: serial: samsung: use u32 for register interactions All registers of the IP have 32 bits. Use u32 variables when reading or writing from/to the registers. The purpose of those variables becomes clearer. Reviewed-by: Sam Protsenko Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/20240119104526.1221243-9-tudor.ambarus@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 79 ++++++++++++++++---------------- 1 file changed, 39 insertions(+), 40 deletions(-) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index b9b91ff6a1d7..8b396c950933 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -199,7 +199,7 @@ static void wr_reg(const struct uart_port *port, u32 reg, u32 val) /* Byte-order aware bit setting/clearing functions. */ static inline void s3c24xx_set_bit(const struct uart_port *port, int idx, - unsigned int reg) + u32 reg) { unsigned long flags; u32 val; @@ -212,7 +212,7 @@ static inline void s3c24xx_set_bit(const struct uart_port *port, int idx, } static inline void s3c24xx_clear_bit(const struct uart_port *port, int idx, - unsigned int reg) + u32 reg) { unsigned long flags; u32 val; @@ -245,8 +245,8 @@ static void s3c24xx_serial_rx_enable(struct uart_port *port) { struct s3c24xx_uart_port *ourport = to_ourport(port); unsigned long flags; - unsigned int ucon, ufcon; int count = 10000; + u32 ucon, ufcon; uart_port_lock_irqsave(port, &flags); @@ -269,7 +269,7 @@ static void s3c24xx_serial_rx_disable(struct uart_port *port) { struct s3c24xx_uart_port *ourport = to_ourport(port); unsigned long flags; - unsigned int ucon; + u32 ucon; uart_port_lock_irqsave(port, &flags); @@ -591,7 +591,7 @@ static inline const struct s3c2410_uartcfg } static int s3c24xx_serial_rx_fifocnt(const struct s3c24xx_uart_port *ourport, - unsigned long ufstat) + u32 ufstat) { const struct s3c24xx_uart_info *info = ourport->info; @@ -663,7 +663,7 @@ static void s3c64xx_start_rx_dma(struct s3c24xx_uart_port *ourport) static void enable_rx_dma(struct s3c24xx_uart_port *ourport) { struct uart_port *port = &ourport->port; - unsigned int ucon; + u32 ucon; /* set Rx mode to DMA mode */ ucon = rd_regl(port, S3C2410_UCON); @@ -686,7 +686,7 @@ static void enable_rx_dma(struct s3c24xx_uart_port *ourport) static void enable_rx_pio(struct s3c24xx_uart_port *ourport) { struct uart_port *port = &ourport->port; - unsigned int ucon; + u32 ucon; /* set Rx mode to DMA mode */ ucon = rd_regl(port, S3C2410_UCON); @@ -711,13 +711,14 @@ static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport); static irqreturn_t s3c24xx_serial_rx_chars_dma(void *dev_id) { - unsigned int utrstat, received; struct s3c24xx_uart_port *ourport = dev_id; struct uart_port *port = &ourport->port; struct s3c24xx_uart_dma *dma = ourport->dma; struct tty_struct *tty = tty_port_tty_get(&ourport->port.state->port); struct tty_port *t = &port->state->port; struct dma_tx_state state; + unsigned int received; + u32 utrstat; utrstat = rd_regl(port, S3C2410_UTRSTAT); rd_regl(port, S3C2410_UFSTAT); @@ -759,9 +760,9 @@ finish: static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport) { struct uart_port *port = &ourport->port; - unsigned int ufcon, ufstat, uerstat; unsigned int fifocnt = 0; int max_count = port->fifosize; + u32 ufcon, ufstat, uerstat; u8 ch, flag; while (max_count-- > 0) { @@ -945,7 +946,7 @@ static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id) { const struct s3c24xx_uart_port *ourport = id; const struct uart_port *port = &ourport->port; - unsigned int pend = rd_regl(port, S3C64XX_UINTP); + u32 pend = rd_regl(port, S3C64XX_UINTP); irqreturn_t ret = IRQ_HANDLED; if (pend & S3C64XX_UINTM_RXD_MSK) { @@ -964,7 +965,7 @@ static irqreturn_t apple_serial_handle_irq(int irq, void *id) { const struct s3c24xx_uart_port *ourport = id; const struct uart_port *port = &ourport->port; - unsigned int pend = rd_regl(port, S3C2410_UTRSTAT); + u32 pend = rd_regl(port, S3C2410_UTRSTAT); irqreturn_t ret = IRQ_NONE; if (pend & (APPLE_S5L_UTRSTAT_RXTHRESH | APPLE_S5L_UTRSTAT_RXTO)) { @@ -983,8 +984,8 @@ static irqreturn_t apple_serial_handle_irq(int irq, void *id) static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port) { const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); - unsigned long ufstat = rd_regl(port, S3C2410_UFSTAT); - unsigned long ufcon = rd_regl(port, S3C2410_UFCON); + u32 ufstat = rd_regl(port, S3C2410_UFSTAT); + u32 ufcon = rd_regl(port, S3C2410_UFCON); if (ufcon & S3C2410_UFCON_FIFOMODE) { if ((ufstat & info->tx_fifomask) != 0 || @@ -999,7 +1000,7 @@ static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port) /* no modem control lines */ static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port) { - unsigned int umstat = rd_reg(port, S3C2410_UMSTAT); + u32 umstat = rd_reg(port, S3C2410_UMSTAT); if (umstat & S3C2410_UMSTAT_CTS) return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; @@ -1009,8 +1010,8 @@ static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port) static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl) { - unsigned int umcon = rd_regl(port, S3C2410_UMCON); - unsigned int ucon = rd_regl(port, S3C2410_UCON); + u32 umcon = rd_regl(port, S3C2410_UMCON); + u32 ucon = rd_regl(port, S3C2410_UCON); if (mctrl & TIOCM_RTS) umcon |= S3C2410_UMCOM_RTS_LOW; @@ -1030,7 +1031,7 @@ static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl) static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state) { unsigned long flags; - unsigned int ucon; + u32 ucon; uart_port_lock_irqsave(port, &flags); @@ -1188,7 +1189,7 @@ static void apple_s5l_serial_shutdown(struct uart_port *port) { struct s3c24xx_uart_port *ourport = to_ourport(port); - unsigned int ucon; + u32 ucon; ucon = rd_regl(port, S3C2410_UCON); ucon &= ~(APPLE_S5L_UCON_TXTHRESH_ENA_MSK | @@ -1214,7 +1215,7 @@ static int s3c64xx_serial_startup(struct uart_port *port) { struct s3c24xx_uart_port *ourport = to_ourport(port); unsigned long flags; - unsigned int ufcon; + u32 ufcon; int ret; wr_regl(port, S3C64XX_UINTM, 0xf); @@ -1259,7 +1260,7 @@ static int apple_s5l_serial_startup(struct uart_port *port) { struct s3c24xx_uart_port *ourport = to_ourport(port); unsigned long flags; - unsigned int ufcon; + u32 ufcon; int ret; wr_regl(port, S3C2410_UTRSTAT, APPLE_S5L_UTRSTAT_ALL_FLAGS); @@ -1344,7 +1345,7 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, static inline int s3c24xx_serial_getsource(struct uart_port *port) { const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); - unsigned int ucon; + u32 ucon; if (info->num_clks == 1) return 0; @@ -1358,7 +1359,7 @@ static void s3c24xx_serial_setsource(struct uart_port *port, unsigned int clk_sel) { const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); - unsigned int ucon; + u32 ucon; if (info->num_clks == 1) return; @@ -1475,9 +1476,8 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, struct clk *clk = ERR_PTR(-EINVAL); unsigned long flags; unsigned int baud, quot, clk_sel = 0; - unsigned int ulcon; - unsigned int umcon; unsigned int udivslot = 0; + u32 ulcon, umcon; /* * We don't support modem control lines. @@ -1759,7 +1759,7 @@ static void s3c24xx_serial_resetport(struct uart_port *port, const struct s3c2410_uartcfg *cfg) { const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); - unsigned long ucon = rd_regl(port, S3C2410_UCON); + u32 ucon = rd_regl(port, S3C2410_UCON); ucon &= (info->clksel_mask | info->ucon_mask); wr_regl(port, S3C2410_UCON, ucon | cfg->ucon); @@ -1905,7 +1905,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, wr_regl(port, S3C64XX_UINTSP, 0xf); break; case TYPE_APPLE_S5L: { - unsigned int ucon; + u32 ucon; ucon = rd_regl(port, S3C2410_UCON); ucon &= ~(APPLE_S5L_UCON_TXTHRESH_ENA_MSK | @@ -2109,7 +2109,7 @@ static int s3c24xx_serial_resume_noirq(struct device *dev) /* restore IRQ mask */ switch (ourport->info->type) { case TYPE_S3C6400: { - unsigned int uintm = 0xf; + u32 uintm = 0xf; if (ourport->tx_enabled) uintm &= ~S3C64XX_UINTM_TXD_MSK; @@ -2125,7 +2125,7 @@ static int s3c24xx_serial_resume_noirq(struct device *dev) break; } case TYPE_APPLE_S5L: { - unsigned int ucon; + u32 ucon; int ret; ret = clk_prepare_enable(ourport->clk); @@ -2187,10 +2187,10 @@ static const struct dev_pm_ops s3c24xx_serial_pm_ops = { static struct uart_port *cons_uart; static int -s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon) +s3c24xx_serial_console_txrdy(struct uart_port *port, u32 ufcon) { const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); - unsigned long ufstat, utrstat; + u32 ufstat, utrstat; if (ufcon & S3C2410_UFCON_FIFOMODE) { /* fifo mode - check amount of data in fifo registers... */ @@ -2206,7 +2206,7 @@ s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon) } static bool -s3c24xx_port_configured(unsigned int ucon) +s3c24xx_port_configured(u32 ucon) { /* consider the serial port configured if the tx/rx mode set */ return (ucon & 0xf) != 0; @@ -2221,7 +2221,7 @@ s3c24xx_port_configured(unsigned int ucon) static int s3c24xx_serial_get_poll_char(struct uart_port *port) { const struct s3c24xx_uart_port *ourport = to_ourport(port); - unsigned int ufstat; + u32 ufstat; ufstat = rd_regl(port, S3C2410_UFSTAT); if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0) @@ -2233,8 +2233,8 @@ static int s3c24xx_serial_get_poll_char(struct uart_port *port) static void s3c24xx_serial_put_poll_char(struct uart_port *port, unsigned char c) { - unsigned int ufcon = rd_regl(port, S3C2410_UFCON); - unsigned int ucon = rd_regl(port, S3C2410_UCON); + u32 ufcon = rd_regl(port, S3C2410_UFCON); + u32 ucon = rd_regl(port, S3C2410_UCON); /* not possible to xmit on unconfigured port */ if (!s3c24xx_port_configured(ucon)) @@ -2250,7 +2250,7 @@ static void s3c24xx_serial_put_poll_char(struct uart_port *port, static void s3c24xx_serial_console_putchar(struct uart_port *port, unsigned char ch) { - unsigned int ufcon = rd_regl(port, S3C2410_UFCON); + u32 ufcon = rd_regl(port, S3C2410_UFCON); while (!s3c24xx_serial_console_txrdy(port, ufcon)) cpu_relax(); @@ -2261,7 +2261,7 @@ static void s3c24xx_serial_console_write(struct console *co, const char *s, unsigned int count) { - unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON); + u32 ucon = rd_regl(cons_uart, S3C2410_UCON); unsigned long flags; bool locked = true; @@ -2288,11 +2288,9 @@ s3c24xx_serial_get_options(struct uart_port *port, int *baud, int *parity, int *bits) { struct clk *clk; - unsigned int ulcon; - unsigned int ucon; - unsigned int ubrdiv; unsigned long rate; unsigned int clk_sel; + u32 ulcon, ucon, ubrdiv; char clk_name[MAX_CLK_NAME_LENGTH]; ulcon = rd_regl(port, S3C2410_ULCON); @@ -2742,7 +2740,8 @@ static int samsung_early_read(struct console *con, char *s, unsigned int n) { struct earlycon_device *dev = con->data; const struct samsung_early_console_data *data = dev->port.private_data; - int ch, ufstat, num_read = 0; + int num_read = 0; + u32 ch, ufstat; while (num_read < n) { ufstat = rd_regl(&dev->port, S3C2410_UFSTAT); From b1617c7888476e69e5b03b89eedef2bd2c60901e Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 19 Jan 2024 10:45:16 +0000 Subject: [PATCH 084/199] tty: serial: samsung: remove braces on single statement block Braces {} are not necessary for single statement blocks. Remove braces on single statement block. Reviewed-by: Sam Protsenko Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/20240119104526.1221243-10-tudor.ambarus@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 8b396c950933..303b67498c65 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -2061,9 +2061,8 @@ static void s3c24xx_serial_remove(struct platform_device *dev) { struct uart_port *port = s3c24xx_dev_to_port(&dev->dev); - if (port) { + if (port) uart_remove_one_port(&s3c24xx_uart_drv, port); - } uart_unregister_driver(&s3c24xx_uart_drv); } From 048dc68709a0c7ed80f327d4b7ff5af7461107e3 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 19 Jan 2024 10:45:17 +0000 Subject: [PATCH 085/199] tty: serial: samsung: move open brace '{' on the next line Move open brace '{' following function definition on the next line. Reviewed-by: Sam Protsenko Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/20240119104526.1221243-11-tudor.ambarus@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 303b67498c65..b6d34c9f46ea 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -1739,7 +1739,8 @@ static struct uart_driver s3c24xx_uart_drv = { static struct s3c24xx_uart_port s3c24xx_serial_ports[UART_NR]; -static void s3c24xx_serial_init_port_default(int index) { +static void s3c24xx_serial_init_port_default(int index) +{ struct uart_port *port = &s3c24xx_serial_ports[index].port; spin_lock_init(&port->lock); From 16db7adb77643c735fc521aecddd1e51ae4534b5 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 19 Jan 2024 10:45:18 +0000 Subject: [PATCH 086/199] tty: serial: samsung: drop superfluous comment The comment brings no benefit as we can already see from the method's name, ``s3c24xx_serial_pm``, that it deals with power management. Drop the superfluous comment. Reviewed-by: Sam Protsenko Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/20240119104526.1221243-12-tudor.ambarus@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index b6d34c9f46ea..4bb75b1eceef 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -1295,8 +1295,6 @@ static int apple_s5l_serial_startup(struct uart_port *port) return ret; } -/* power power management control */ - static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, unsigned int old) { From b3296e7681d80c95432ad04263ac24ad61664b9a Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 19 Jan 2024 10:45:19 +0000 Subject: [PATCH 087/199] tty: serial: samsung: make max_count unsigned int ``max_count`` negative values are not used. Since ``port->fifosize`` is an unsigned int, make ``max_count`` the same. Reviewed-by: Sam Protsenko Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/20240119104526.1221243-13-tudor.ambarus@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 4bb75b1eceef..f8a8b459a86b 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -760,8 +760,8 @@ finish: static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport) { struct uart_port *port = &ourport->port; + unsigned int max_count = port->fifosize; unsigned int fifocnt = 0; - int max_count = port->fifosize; u32 ufcon, ufstat, uerstat; u8 ch, flag; From ece5cc2ac1e665d936d3c795bab55aeee743bca6 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 19 Jan 2024 10:45:20 +0000 Subject: [PATCH 088/199] tty: serial: samsung: don't compare with zero an if (bitwise expression) The bitwise AND with the fifo mask is used to check if the fifo is empty or not, it doesn't care about the length, thus the comparison with zero is implicit. Rely on the implicit comparison instead. Reviewed-by: Sam Protsenko Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/20240119104526.1221243-14-tudor.ambarus@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index f8a8b459a86b..333ffa3a76a3 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -988,7 +988,7 @@ static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port) u32 ufcon = rd_regl(port, S3C2410_UFCON); if (ufcon & S3C2410_UFCON_FIFOMODE) { - if ((ufstat & info->tx_fifomask) != 0 || + if ((ufstat & info->tx_fifomask) || (ufstat & info->tx_fifofull)) return 0; return TIOCSER_TEMT; From f09e8da69bb47c5e9b0c46af641fa0b6c0b12f94 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 19 Jan 2024 10:45:21 +0000 Subject: [PATCH 089/199] tty: serial: samsung: return bool for s3c24xx_serial_txempty_nofifo() s3c24xx_serial_txempty_nofifo() returned either 0 or BIT(2), which is counterintuitive. Make the method return bool, and return true when TX is empty and false otherwise. Reviewed-by: Sam Protsenko Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/20240119104526.1221243-15-tudor.ambarus@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 333ffa3a76a3..90d697def5c7 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -236,7 +236,7 @@ static inline const char *s3c24xx_serial_portname(const struct uart_port *port) return to_platform_device(port->dev)->name; } -static int s3c24xx_serial_txempty_nofifo(const struct uart_port *port) +static bool s3c24xx_serial_txempty_nofifo(const struct uart_port *port) { return rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE; } @@ -782,7 +782,7 @@ static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport) ch = rd_reg(port, S3C2410_URXH); if (port->flags & UPF_CONS_FLOW) { - int txe = s3c24xx_serial_txempty_nofifo(port); + bool txe = s3c24xx_serial_txempty_nofifo(port); if (ourport->rx_enabled) { if (!txe) { From be96d89451040d58bbaf81f1c48c5c836cf6d520 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 19 Jan 2024 10:45:22 +0000 Subject: [PATCH 090/199] tty: serial: samsung: return bool for s3c24xx_serial_console_txrdy() s3c24xx_serial_console_txrdy() returned just 0 or 1 to indicate whether the TX is empty or not. Change its return type to bool. Reviewed-by: Sam Protsenko Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/20240119104526.1221243-16-tudor.ambarus@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 90d697def5c7..bdc81ab4af91 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -2184,7 +2184,7 @@ static const struct dev_pm_ops s3c24xx_serial_pm_ops = { static struct uart_port *cons_uart; -static int +static bool s3c24xx_serial_console_txrdy(struct uart_port *port, u32 ufcon) { const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); @@ -2194,13 +2194,13 @@ s3c24xx_serial_console_txrdy(struct uart_port *port, u32 ufcon) /* fifo mode - check amount of data in fifo registers... */ ufstat = rd_regl(port, S3C2410_UFSTAT); - return (ufstat & info->tx_fifofull) ? 0 : 1; + return !(ufstat & info->tx_fifofull); } /* in non-fifo mode, we go and use the tx buffer empty */ utrstat = rd_regl(port, S3C2410_UTRSTAT); - return (utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0; + return utrstat & S3C2410_UTRSTAT_TXE; } static bool From 92e32ed303a6c4dc5a5ad9ec54785a6245bcd8fa Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 19 Jan 2024 10:45:23 +0000 Subject: [PATCH 091/199] tty: serial: samsung: change return type for s3c24xx_serial_rx_fifocnt() Change the return type of the s3c24xx_serial_rx_fifocnt() method to ``unsigned int`` as the method only returns the fifo size and does not handle error codes. Reviewed-by: Sam Protsenko Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/20240119104526.1221243-17-tudor.ambarus@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index bdc81ab4af91..149f618e22ce 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -590,8 +590,8 @@ static inline const struct s3c2410_uartcfg return ourport->cfg; } -static int s3c24xx_serial_rx_fifocnt(const struct s3c24xx_uart_port *ourport, - u32 ufstat) +static unsigned int +s3c24xx_serial_rx_fifocnt(const struct s3c24xx_uart_port *ourport, u32 ufstat) { const struct s3c24xx_uart_info *info = ourport->info; From 6e1e48b6ef2613ff4c28a34f7a57c29a4367ad87 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 19 Jan 2024 10:45:24 +0000 Subject: [PATCH 092/199] tty: serial: samsung: shrink the clock selection to 8 clocks provides a clock selection pool of maximum 4 clocks. Update the driver to consider a pool selection of maximum 8 clocks. u8 is large enough to allow more clocks than are supported by the driver now, and not too big to cause spanning of ``struct s3c24xx_uart_info`` through 2 cachelines when compiled for arm64. The goal is to reduce the memory footprint of ``struct s3c24xx_uart_info``. Reviewed-by: Sam Protsenko Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/20240119104526.1221243-18-tudor.ambarus@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 149f618e22ce..c429029c0207 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -81,11 +81,11 @@ struct s3c24xx_uart_info { unsigned long tx_fifomask; unsigned long tx_fifoshift; unsigned long tx_fifofull; - unsigned int def_clk_sel; - unsigned long num_clks; unsigned long clksel_mask; unsigned long clksel_shift; unsigned long ucon_mask; + u8 def_clk_sel; + u8 num_clks; u8 iotype; /* uart port features */ @@ -1340,7 +1340,7 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, #define MAX_CLK_NAME_LENGTH 15 -static inline int s3c24xx_serial_getsource(struct uart_port *port) +static inline u8 s3c24xx_serial_getsource(struct uart_port *port) { const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); u32 ucon; @@ -1353,8 +1353,7 @@ static inline int s3c24xx_serial_getsource(struct uart_port *port) return ucon >> info->clksel_shift; } -static void s3c24xx_serial_setsource(struct uart_port *port, - unsigned int clk_sel) +static void s3c24xx_serial_setsource(struct uart_port *port, u8 clk_sel) { const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); u32 ucon; @@ -1373,14 +1372,15 @@ static void s3c24xx_serial_setsource(struct uart_port *port, static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport, unsigned int req_baud, struct clk **best_clk, - unsigned int *clk_num) + u8 *clk_num) { const struct s3c24xx_uart_info *info = ourport->info; struct clk *clk; unsigned long rate; - unsigned int cnt, baud, quot, best_quot = 0; + unsigned int baud, quot, best_quot = 0; char clkname[MAX_CLK_NAME_LENGTH]; int calc_deviation, deviation = (1 << 30) - 1; + u8 cnt; for (cnt = 0; cnt < info->num_clks; cnt++) { /* Keep selected clock if provided */ @@ -1473,9 +1473,10 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, struct s3c24xx_uart_port *ourport = to_ourport(port); struct clk *clk = ERR_PTR(-EINVAL); unsigned long flags; - unsigned int baud, quot, clk_sel = 0; + unsigned int baud, quot; unsigned int udivslot = 0; u32 ulcon, umcon; + u8 clk_sel = 0; /* * We don't support modem control lines. @@ -1776,10 +1777,9 @@ static int s3c24xx_serial_enable_baudclk(struct s3c24xx_uart_port *ourport) struct device *dev = ourport->port.dev; const struct s3c24xx_uart_info *info = ourport->info; char clk_name[MAX_CLK_NAME_LENGTH]; - unsigned int clk_sel; struct clk *clk; - int clk_num; int ret; + u8 clk_sel, clk_num; clk_sel = ourport->cfg->clk_sel ? : info->def_clk_sel; for (clk_num = 0; clk_num < info->num_clks; clk_num++) { @@ -2287,9 +2287,9 @@ s3c24xx_serial_get_options(struct uart_port *port, int *baud, { struct clk *clk; unsigned long rate; - unsigned int clk_sel; u32 ulcon, ucon, ubrdiv; char clk_name[MAX_CLK_NAME_LENGTH]; + u8 clk_sel; ulcon = rd_regl(port, S3C2410_ULCON); ucon = rd_regl(port, S3C2410_UCON); From 4d0cfff7df32d8d126b547f61505473a91c6e797 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 19 Jan 2024 10:45:25 +0000 Subject: [PATCH 093/199] tty: serial: samsung: change has_divslot type to bool Since the driver was introduced the port features flags never extended. As we don't expect more flags soon that would bypass the first cacheline of ``struct s3c24xx_uart_info``, change the type of ``has_divslot`` to bool. Bitfields operations incur performance penalty when set or read as compared to direct types. Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/20240119104526.1221243-19-tudor.ambarus@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index c429029c0207..0a03df44211d 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -89,8 +89,7 @@ struct s3c24xx_uart_info { u8 iotype; /* uart port features */ - - unsigned int has_divslot:1; + bool has_divslot; }; struct s3c24xx_serial_drv_data { @@ -2400,7 +2399,7 @@ static const struct s3c24xx_serial_drv_data s3c6400_serial_drv_data = { .port_type = PORT_S3C6400, .iotype = UPIO_MEM, .fifosize = 64, - .has_divslot = 1, + .has_divslot = true, .rx_fifomask = S3C2440_UFSTAT_RXMASK, .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT, .rx_fifofull = S3C2440_UFSTAT_RXFULL, @@ -2429,7 +2428,7 @@ static const struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = { .type = TYPE_S3C6400, .port_type = PORT_S3C6400, .iotype = UPIO_MEM, - .has_divslot = 1, + .has_divslot = true, .rx_fifomask = S5PV210_UFSTAT_RXMASK, .rx_fifoshift = S5PV210_UFSTAT_RXSHIFT, .rx_fifofull = S5PV210_UFSTAT_RXFULL, @@ -2459,7 +2458,7 @@ static const struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = { .type = TYPE_S3C6400, \ .port_type = PORT_S3C6400, \ .iotype = UPIO_MEM, \ - .has_divslot = 1, \ + .has_divslot = true, \ .rx_fifomask = S5PV210_UFSTAT_RXMASK, \ .rx_fifoshift = S5PV210_UFSTAT_RXSHIFT, \ .rx_fifofull = S5PV210_UFSTAT_RXFULL, \ @@ -2498,7 +2497,7 @@ static const struct s3c24xx_serial_drv_data gs101_serial_drv_data = { .type = TYPE_S3C6400, .port_type = PORT_S3C6400, .iotype = UPIO_MEM32, - .has_divslot = 1, + .has_divslot = true, .rx_fifomask = S5PV210_UFSTAT_RXMASK, .rx_fifoshift = S5PV210_UFSTAT_RXSHIFT, .rx_fifofull = S5PV210_UFSTAT_RXFULL, @@ -2569,7 +2568,7 @@ static const struct s3c24xx_serial_drv_data artpec8_serial_drv_data = { .port_type = PORT_S3C6400, .iotype = UPIO_MEM, .fifosize = 64, - .has_divslot = 1, + .has_divslot = true, .rx_fifomask = S5PV210_UFSTAT_RXMASK, .rx_fifoshift = S5PV210_UFSTAT_RXSHIFT, .rx_fifofull = S5PV210_UFSTAT_RXFULL, From 79821c8a45807655c25d6bae2b13a3f98a5c01cd Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 19 Jan 2024 10:45:26 +0000 Subject: [PATCH 094/199] tty: serial: samsung: shrink memory footprint of ``struct s3c24xx_uart_info`` Use u32 for the members of ``struct s3c24xx_uart_info`` that are used for register interactions. The purpose of these members becomes clearer. The greater benefit of this change is that it also reduces the memory footprint of the struct, allowing 64-bit architectures to use a single cacheline for the entire struct. struct s3c24xx_uart_info { const char * name; /* 0 8 */ enum s3c24xx_port_type type; /* 8 4 */ unsigned int port_type; /* 12 4 */ unsigned int fifosize; /* 16 4 */ u32 rx_fifomask; /* 20 4 */ u32 rx_fifoshift; /* 24 4 */ u32 rx_fifofull; /* 28 4 */ u32 tx_fifomask; /* 32 4 */ u32 tx_fifoshift; /* 36 4 */ u32 tx_fifofull; /* 40 4 */ u32 clksel_mask; /* 44 4 */ u32 clksel_shift; /* 48 4 */ u32 ucon_mask; /* 52 4 */ u8 def_clk_sel; /* 56 1 */ u8 num_clks; /* 57 1 */ u8 iotype; /* 58 1 */ bool has_divslot; /* 59 1 */ /* size: 64, cachelines: 1, members: 17 */ /* padding: 4 */ }; Reviewed-by: Sam Protsenko Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/20240119104526.1221243-20-tudor.ambarus@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 0a03df44211d..fcc675603b14 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -75,15 +75,15 @@ struct s3c24xx_uart_info { enum s3c24xx_port_type type; unsigned int port_type; unsigned int fifosize; - unsigned long rx_fifomask; - unsigned long rx_fifoshift; - unsigned long rx_fifofull; - unsigned long tx_fifomask; - unsigned long tx_fifoshift; - unsigned long tx_fifofull; - unsigned long clksel_mask; - unsigned long clksel_shift; - unsigned long ucon_mask; + u32 rx_fifomask; + u32 rx_fifoshift; + u32 rx_fifofull; + u32 tx_fifomask; + u32 tx_fifoshift; + u32 tx_fifofull; + u32 clksel_mask; + u32 clksel_shift; + u32 ucon_mask; u8 def_clk_sel; u8 num_clks; u8 iotype; From 09aec324b60f4309eeba8d2d5c897e882cce23bc Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sun, 21 Jan 2024 19:53:01 +0800 Subject: [PATCH 095/199] dt-bindings: serial: fsl-lpuart: support i.MX95 Add i.MX95 compatible string. Same as i.MX93, it is compatible with i.MX8ULP. Signed-off-by: Peng Fan Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240121115301.1420502-1-peng.fan@oss.nxp.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/fsl-lpuart.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/serial/fsl-lpuart.yaml b/Documentation/devicetree/bindings/serial/fsl-lpuart.yaml index 3a5b59f5d3e3..3f9ace89dee9 100644 --- a/Documentation/devicetree/bindings/serial/fsl-lpuart.yaml +++ b/Documentation/devicetree/bindings/serial/fsl-lpuart.yaml @@ -30,6 +30,7 @@ properties: - items: - enum: - fsl,imx93-lpuart + - fsl,imx95-lpuart - const: fsl,imx8ulp-lpuart - const: fsl,imx7ulp-lpuart - items: From 196f34af2bf4c87ac4299a9775503d81b446980c Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Mon, 22 Jan 2024 15:27:20 +0100 Subject: [PATCH 096/199] tty: serial: amba-pl011: Remove QDF2xxx workarounds This SoC family was destined for server use, featuring Qualcomm's very interesting Kryo cores (before "Kryo" became a marketing term for Arm cores with small modifications). It did however not leave the labs of Qualcomm and presumably some partners, nor was it ever productized. Remove the workarounds, as they are long obsolete. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20240122-topic-qdf_cleanup_tty-v1-1-0415503184be@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 82 --------------------------------- 1 file changed, 82 deletions(-) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index fccec1698a54..c4df9cbc264b 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -152,23 +152,6 @@ static const struct vendor_data vendor_sbsa = { .fixed_options = true, }; -#ifdef CONFIG_ACPI_SPCR_TABLE -static const struct vendor_data vendor_qdt_qdf2400_e44 = { - .reg_offset = pl011_std_offsets, - .fr_busy = UART011_FR_TXFE, - .fr_dsr = UART01x_FR_DSR, - .fr_cts = UART01x_FR_CTS, - .fr_ri = UART011_FR_RI, - .inv_fr = UART011_FR_TXFE, - .access_32b = true, - .oversampling = false, - .dma_threshold = false, - .cts_event_workaround = false, - .always_enabled = true, - .fixed_options = true, -}; -#endif - static u16 pl011_st_offsets[REG_ARRAY_SIZE] = { [REG_DR] = UART01x_DR, [REG_ST_DMAWM] = ST_UART011_DMAWM, @@ -2468,15 +2451,6 @@ static int pl011_console_match(struct console *co, char *name, int idx, resource_size_t addr; int i; - /* - * Systems affected by the Qualcomm Technologies QDF2400 E44 erratum - * have a distinct console name, so make sure we check for that. - * The actual implementation of the erratum occurs in the probe - * function. - */ - if ((strcmp(name, "qdf2400_e44") != 0) && (strcmp(name, "pl011") != 0)) - return -ENODEV; - if (uart_parse_earlycon(options, &iotype, &addr, &options)) return -ENODEV; @@ -2517,22 +2491,6 @@ static struct console amba_console = { #define AMBA_CONSOLE (&amba_console) -static void qdf2400_e44_putc(struct uart_port *port, unsigned char c) -{ - while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF) - cpu_relax(); - writel(c, port->membase + UART01x_DR); - while (!(readl(port->membase + UART01x_FR) & UART011_FR_TXFE)) - cpu_relax(); -} - -static void qdf2400_e44_early_write(struct console *con, const char *s, unsigned int n) -{ - struct earlycon_device *dev = con->data; - - uart_console_write(&dev->port, s, n, qdf2400_e44_putc); -} - static void pl011_putc(struct uart_port *port, unsigned char c) { while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF) @@ -2611,29 +2569,6 @@ OF_EARLYCON_DECLARE(pl011, "arm,pl011", pl011_early_console_setup); OF_EARLYCON_DECLARE(pl011, "arm,sbsa-uart", pl011_early_console_setup); -/* - * On Qualcomm Datacenter Technologies QDF2400 SOCs affected by - * Erratum 44, traditional earlycon can be enabled by specifying - * "earlycon=qdf2400_e44,
". Any options are ignored. - * - * Alternatively, you can just specify "earlycon", and the early console - * will be enabled with the information from the SPCR table. In this - * case, the SPCR code will detect the need for the E44 work-around, - * and set the console name to "qdf2400_e44". - */ -static int __init -qdf2400_e44_early_console_setup(struct earlycon_device *device, - const char *opt) -{ - if (!device->port.membase) - return -ENODEV; - - device->con->write = qdf2400_e44_early_write; - return 0; -} - -EARLYCON_DECLARE(qdf2400_e44, qdf2400_e44_early_console_setup); - #else #define AMBA_CONSOLE NULL #endif @@ -2869,22 +2804,6 @@ static int pl011_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(pl011_dev_pm_ops, pl011_suspend, pl011_resume); -#ifdef CONFIG_ACPI_SPCR_TABLE -static void qpdf2400_erratum44_workaround(struct device *dev, - struct uart_amba_port *uap) -{ - if (!qdf2400_e44_present) - return; - - dev_info(dev, "working around QDF2400 SoC erratum 44\n"); - uap->vendor = &vendor_qdt_qdf2400_e44; -} -#else -static void qpdf2400_erratum44_workaround(struct device *dev, - struct uart_amba_port *uap) -{ /* empty */ } -#endif - static int sbsa_uart_probe(struct platform_device *pdev) { struct uart_amba_port *uap; @@ -2921,7 +2840,6 @@ static int sbsa_uart_probe(struct platform_device *pdev) uap->port.irq = ret; uap->vendor = &vendor_sbsa; - qpdf2400_erratum44_workaround(&pdev->dev, uap); uap->reg_offset = uap->vendor->reg_offset; uap->fifosize = 32; From 59fdea965eee9908d904b94828c69f641f1e92fa Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 23 Jan 2024 21:09:15 +0100 Subject: [PATCH 097/199] serial: txx9: Add missing #include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/tty/serial/serial_txx9.c:933:12: error: no previous prototype for ‘early_serial_txx9_setup’ [-Werror=missing-prototypes] 933 | int __init early_serial_txx9_setup(struct uart_port *port) | ^~~~~~~~~~~~~~~~~~~~~~~ This function is called from arch/mips/txx9/generic/setup.c, and does have a forward declaration in arch/mips/include/asm/txx9/generic.h. As the TXX9 serial driver does not support compile-testing, and thus can only be built on MIPS, fix this by including the MIPS-only header file. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/818be2380061c19fe65819f7b7f10ab6e7aaa082.1706040343.git.geert+renesas@glider.be Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_txx9.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c index e1897894a4ef..abba39722958 100644 --- a/drivers/tty/serial/serial_txx9.c +++ b/drivers/tty/serial/serial_txx9.c @@ -23,9 +23,10 @@ #include #include #include - #include +#include + #define PASS_LIMIT 256 #if !defined(CONFIG_SERIAL_TXX9_STDSERIAL) From d2a2a5602cfe7fed309c81135b5ecb62556ce89b Mon Sep 17 00:00:00 2001 From: Nghia Nguyen Date: Wed, 24 Jan 2024 12:27:15 +0100 Subject: [PATCH 098/199] dt-bindings: serial: renesas,hscif: Document r8a779h0 bindings The R-Car V4M (R8A779H0) SoC has R-Car Gen4 compatible HSCIF ports, so document the SoC-specific bindings. Signed-off-by: Nghia Nguyen Signed-off-by: Geert Uytterhoeven Reviewed-by: Wolfram Sang Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/55b458e0ba9824e1246e556075bf882032c37279.1706095578.git.geert@linux-m68k.org Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/renesas,hscif.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/serial/renesas,hscif.yaml b/Documentation/devicetree/bindings/serial/renesas,hscif.yaml index 2046e2dc0a3d..9480ed30915c 100644 --- a/Documentation/devicetree/bindings/serial/renesas,hscif.yaml +++ b/Documentation/devicetree/bindings/serial/renesas,hscif.yaml @@ -59,6 +59,7 @@ properties: - renesas,hscif-r8a779a0 # R-Car V3U - renesas,hscif-r8a779f0 # R-Car S4-8 - renesas,hscif-r8a779g0 # R-Car V4H + - renesas,hscif-r8a779h0 # R-Car V4M - const: renesas,rcar-gen4-hscif # R-Car Gen4 - const: renesas,hscif # generic HSCIF compatible UART From 90d051b63519b0e653432168ecee8a4c0abc24dd Mon Sep 17 00:00:00 2001 From: Rengarajan S Date: Thu, 25 Jan 2024 15:30:06 +0530 Subject: [PATCH 099/199] 8250: microchip: pci1xxxx: Add Burst mode transmission support in uart driver for reading from FIFO pci1xxxx_handle_irq reads the burst status and checks if the FIFO is empty and is ready to accept the incoming data. The handling is done in pci1xxxx_tx_burst where each transaction processes data in block of DWORDs, while any remaining bytes are processed individually, one byte at a time. Signed-off-by: Rengarajan S Link: https://lore.kernel.org/r/20240125100006.153342-1-rengarajan.s@microchip.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci1xxxx.c | 106 ++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/drivers/tty/serial/8250/8250_pci1xxxx.c b/drivers/tty/serial/8250/8250_pci1xxxx.c index 558c4c7f3104..d53605bf908d 100644 --- a/drivers/tty/serial/8250/8250_pci1xxxx.c +++ b/drivers/tty/serial/8250/8250_pci1xxxx.c @@ -67,6 +67,7 @@ #define SYSLOCK_RETRY_CNT 1000 #define UART_RX_BYTE_FIFO 0x00 +#define UART_TX_BYTE_FIFO 0x00 #define UART_FIFO_CTL 0x02 #define UART_ACTV_REG 0x11 @@ -100,6 +101,7 @@ #define UART_RESET_D3_RESET_DISABLE BIT(16) #define UART_BURST_STATUS_REG 0x9C +#define UART_TX_BURST_FIFO 0xA0 #define UART_RX_BURST_FIFO 0xA4 #define MAX_PORTS 4 @@ -109,6 +111,7 @@ #define UART_BURST_SIZE 4 #define UART_BST_STAT_RX_COUNT_MASK 0x00FF +#define UART_BST_STAT_TX_COUNT_MASK 0xFF00 #define UART_BST_STAT_IIR_INT_PEND 0x100000 #define UART_LSR_OVERRUN_ERR_CLR 0x43 #define UART_BST_STAT_LSR_RX_MASK 0x9F000000 @@ -116,6 +119,7 @@ #define UART_BST_STAT_LSR_OVERRUN_ERR 0x2000000 #define UART_BST_STAT_LSR_PARITY_ERR 0x4000000 #define UART_BST_STAT_LSR_FRAME_ERR 0x8000000 +#define UART_BST_STAT_LSR_THRE 0x20000000 struct pci1xxxx_8250 { unsigned int nr; @@ -344,6 +348,105 @@ static void pci1xxxx_rx_burst(struct uart_port *port, u32 uart_status) } } +static void pci1xxxx_process_write_data(struct uart_port *port, + struct circ_buf *xmit, + int *data_empty_count, + u32 *valid_byte_count) +{ + u32 valid_burst_count = *valid_byte_count / UART_BURST_SIZE; + + /* + * Each transaction transfers data in DWORDs. If there are less than + * four remaining valid_byte_count to transfer or if the circular + * buffer has insufficient space for a DWORD, the data is transferred + * one byte at a time. + */ + while (valid_burst_count) { + if (*data_empty_count - UART_BURST_SIZE < 0) + break; + if (xmit->tail > (UART_XMIT_SIZE - UART_BURST_SIZE)) + break; + writel(*(unsigned int *)&xmit->buf[xmit->tail], + port->membase + UART_TX_BURST_FIFO); + *valid_byte_count -= UART_BURST_SIZE; + *data_empty_count -= UART_BURST_SIZE; + valid_burst_count -= UART_BYTE_SIZE; + + xmit->tail = (xmit->tail + UART_BURST_SIZE) & + (UART_XMIT_SIZE - 1); + } + + while (*valid_byte_count) { + if (*data_empty_count - UART_BYTE_SIZE < 0) + break; + writeb(xmit->buf[xmit->tail], port->membase + + UART_TX_BYTE_FIFO); + *data_empty_count -= UART_BYTE_SIZE; + *valid_byte_count -= UART_BYTE_SIZE; + + /* + * When the tail of the circular buffer is reached, the next + * byte is transferred to the beginning of the buffer. + */ + xmit->tail = (xmit->tail + UART_BYTE_SIZE) & + (UART_XMIT_SIZE - 1); + + /* + * If there are any pending burst count, data is handled by + * transmitting DWORDs at a time. + */ + if (valid_burst_count && (xmit->tail < + (UART_XMIT_SIZE - UART_BURST_SIZE))) + break; + } +} + +static void pci1xxxx_tx_burst(struct uart_port *port, u32 uart_status) +{ + struct uart_8250_port *up = up_to_u8250p(port); + u32 valid_byte_count; + int data_empty_count; + struct circ_buf *xmit; + + xmit = &port->state->xmit; + + if (port->x_char) { + writeb(port->x_char, port->membase + UART_TX); + port->icount.tx++; + port->x_char = 0; + return; + } + + if ((uart_tx_stopped(port)) || (uart_circ_empty(xmit))) { + port->ops->stop_tx(port); + } else { + data_empty_count = (pci1xxxx_read_burst_status(port) & + UART_BST_STAT_TX_COUNT_MASK) >> 8; + do { + valid_byte_count = uart_circ_chars_pending(xmit); + + pci1xxxx_process_write_data(port, xmit, + &data_empty_count, + &valid_byte_count); + + port->icount.tx++; + if (uart_circ_empty(xmit)) + break; + } while (data_empty_count && valid_byte_count); + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + /* + * With RPM enabled, we have to wait until the FIFO is empty before + * the HW can go idle. So we get here once again with empty FIFO and + * disable the interrupt and RPM in __stop_tx() + */ + if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM)) + port->ops->stop_tx(port); +} + static int pci1xxxx_handle_irq(struct uart_port *port) { unsigned long flags; @@ -359,6 +462,9 @@ static int pci1xxxx_handle_irq(struct uart_port *port) if (status & UART_BST_STAT_LSR_RX_MASK) pci1xxxx_rx_burst(port, status); + if (status & UART_BST_STAT_LSR_THRE) + pci1xxxx_tx_burst(port, status); + spin_unlock_irqrestore(&port->lock, flags); return 1; From 1ed67ecd13490daaac0b56891bbe1c1666c8cee3 Mon Sep 17 00:00:00 2001 From: Rengarajan S Date: Thu, 25 Jan 2024 15:36:19 +0530 Subject: [PATCH 100/199] 8250: microchip: Add 4 Mbps support in PCI1XXXX UART The current clock input is set to 62.5 MHz for supporting fractional divider, which enables generation of an acceptable baud rate from any frequency. With the current clock input the baud rate range is limited to 3.9 Mbps. Hence, the current range is extended to support 4 Mbps with Burst mode operation. Divisor calculation for a given baud rate is updated as the sampling rate is reduced from 16 to 8 for 4 Mbps. Signed-off-by: Rengarajan S Link: https://lore.kernel.org/r/20240125100619.154873-1-rengarajan.s@microchip.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci1xxxx.c | 34 +++++++++++++++++++++---- drivers/tty/serial/8250/8250_port.c | 7 +++++ 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/drivers/tty/serial/8250/8250_pci1xxxx.c b/drivers/tty/serial/8250/8250_pci1xxxx.c index d53605bf908d..6cfeba058dba 100644 --- a/drivers/tty/serial/8250/8250_pci1xxxx.c +++ b/drivers/tty/serial/8250/8250_pci1xxxx.c @@ -82,7 +82,8 @@ #define ADCL_CFG_PIN_SEL BIT(1) #define ADCL_CFG_EN BIT(0) -#define UART_BIT_SAMPLE_CNT 16 +#define UART_BIT_SAMPLE_CNT_8 8 +#define UART_BIT_SAMPLE_CNT_16 16 #define BAUD_CLOCK_DIV_INT_MSK GENMASK(31, 8) #define ADCL_CFG_RTS_DELAY_MASK GENMASK(11, 8) #define UART_CLOCK_DEFAULT (62500 * HZ_PER_KHZ) @@ -96,6 +97,7 @@ (UART_WAKE_N_PIN | UART_WAKE_NCTS | UART_WAKE_INT) #define UART_BAUD_CLK_DIVISOR_REG 0x54 +#define FRAC_DIV_CFG_REG 0x58 #define UART_RESET_REG 0x94 #define UART_RESET_D3_RESET_DISABLE BIT(16) @@ -104,6 +106,10 @@ #define UART_TX_BURST_FIFO 0xA0 #define UART_RX_BURST_FIFO 0xA4 +#define UART_BIT_DIVISOR_8 0x26731000 +#define UART_BIT_DIVISOR_16 0x6ef71000 +#define UART_BAUD_4MBPS 4000000 + #define MAX_PORTS 4 #define PORT_OFFSET 0x100 #define RX_BUF_SIZE 512 @@ -210,15 +216,24 @@ static int pci1xxxx_get_num_ports(struct pci_dev *dev) static unsigned int pci1xxxx_get_divisor(struct uart_port *port, unsigned int baud, unsigned int *frac) { + unsigned int uart_sample_cnt; unsigned int quot; + if (baud >= UART_BAUD_4MBPS) { + uart_sample_cnt = UART_BIT_SAMPLE_CNT_8; + writel(UART_BIT_DIVISOR_8, (port->membase + FRAC_DIV_CFG_REG)); + } else { + uart_sample_cnt = UART_BIT_SAMPLE_CNT_16; + writel(UART_BIT_DIVISOR_16, (port->membase + FRAC_DIV_CFG_REG)); + } + /* * Calculate baud rate sampling period in nanoseconds. * Fractional part x denotes x/255 parts of a nanosecond. */ - quot = NSEC_PER_SEC / (baud * UART_BIT_SAMPLE_CNT); - *frac = (NSEC_PER_SEC - quot * baud * UART_BIT_SAMPLE_CNT) * - 255 / UART_BIT_SAMPLE_CNT / baud; + quot = NSEC_PER_SEC / (baud * uart_sample_cnt); + *frac = (NSEC_PER_SEC - quot * baud * uart_sample_cnt) * + 255 / uart_sample_cnt / baud; return quot; } @@ -237,7 +252,16 @@ static int pci1xxxx_rs485_config(struct uart_port *port, u32 delay_in_baud_periods; u32 baud_period_in_ns; u32 mode_cfg = 0; + u32 sample_cnt; u32 clock_div; + u32 frac_div; + + frac_div = readl(port->membase + FRAC_DIV_CFG_REG); + + if (frac_div == UART_BIT_DIVISOR_16) + sample_cnt = UART_BIT_SAMPLE_CNT_16; + else + sample_cnt = UART_BIT_SAMPLE_CNT_8; /* * pci1xxxx's uart hardware supports only RTS delay after @@ -253,7 +277,7 @@ static int pci1xxxx_rs485_config(struct uart_port *port, clock_div = readl(port->membase + UART_BAUD_CLK_DIVISOR_REG); baud_period_in_ns = FIELD_GET(BAUD_CLOCK_DIV_INT_MSK, clock_div) * - UART_BIT_SAMPLE_CNT; + sample_cnt; delay_in_baud_periods = rs485->delay_rts_after_send * NSEC_PER_MSEC / baud_period_in_ns; diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 8ca061d3bbb9..c37905ea3cae 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -2681,6 +2681,7 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port, struct ktermios *termios, const struct ktermios *old) { + struct uart_8250_port *up = up_to_u8250p(port); unsigned int tolerance = port->uartclk / 100; unsigned int min; unsigned int max; @@ -2698,6 +2699,12 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port, max = (port->uartclk + tolerance) / 16; } + /* + * Microchip PCI1XXXX UART supports maximum baud rate up to 4 Mbps + */ + if (up->port.type == PORT_MCHP16550A) + max = 4000000; + /* * Ask the core to calculate the divisor for us. * Allow 1% tolerance at the upper limit so uart clks marginally From 32152467ffac3b79eae7313959c310946b0e6072 Mon Sep 17 00:00:00 2001 From: Manikanta Guntupalli Date: Tue, 23 Jan 2024 11:46:53 +0530 Subject: [PATCH 101/199] dt-bindings: Add reference to rs485.yaml Xilinx/AMD Kria SOM KD240 board has a rs485 compatible peripheral. Update the binding to have rs485 support. Acked-by: Conor Dooley Signed-off-by: Manikanta Guntupalli Link: https://lore.kernel.org/r/20240123061655.2150946-2-manikanta.guntupalli@amd.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/cdns,uart.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/serial/cdns,uart.yaml b/Documentation/devicetree/bindings/serial/cdns,uart.yaml index e35ad1109efc..2129247d7c81 100644 --- a/Documentation/devicetree/bindings/serial/cdns,uart.yaml +++ b/Documentation/devicetree/bindings/serial/cdns,uart.yaml @@ -55,6 +55,7 @@ required: allOf: - $ref: serial.yaml# + - $ref: rs485.yaml# - if: properties: compatible: From 74231ab6cc2d02303ddf1fabd878756c52f788a5 Mon Sep 17 00:00:00 2001 From: Manikanta Guntupalli Date: Tue, 23 Jan 2024 11:46:54 +0530 Subject: [PATCH 102/199] tty: serial: uartps: Relocate cdns_uart_tx_empty to facilitate rs485 Relocate cdns_uart_tx_empty function to avoid prototype statement in rs485 changes. Update return check with uart_tx_stopped() in cdns_uart_handle_tx(). Signed-off-by: Manikanta Guntupalli Link: https://lore.kernel.org/r/20240123061655.2150946-3-manikanta.guntupalli@amd.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/xilinx_uartps.c | 36 ++++++++++++++++-------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 920762d7b4a4..765a6e174052 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -306,7 +306,22 @@ static void cdns_uart_handle_rx(void *dev_id, unsigned int isrstatus) } /** - * cdns_uart_handle_tx - Handle the bytes to be Txed. + * cdns_uart_tx_empty - Check whether TX is empty + * @port: Handle to the uart port structure + * + * Return: TIOCSER_TEMT on success, 0 otherwise + */ +static unsigned int cdns_uart_tx_empty(struct uart_port *port) +{ + unsigned int status; + + status = readl(port->membase + CDNS_UART_SR); + status &= (CDNS_UART_SR_TXEMPTY | CDNS_UART_SR_TACTIVE); + return (status == CDNS_UART_SR_TXEMPTY) ? TIOCSER_TEMT : 0; +} + +/** + * cdns_uart_handle_tx - Handle the bytes to be transmitted. * @dev_id: Id of the UART port * Return: None */ @@ -316,7 +331,8 @@ static void cdns_uart_handle_tx(void *dev_id) struct circ_buf *xmit = &port->state->xmit; unsigned int numbytes; - if (uart_circ_empty(xmit)) { + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + /* Disable the TX Empty interrupt */ writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR); return; } @@ -587,6 +603,7 @@ static void cdns_uart_start_tx(struct uart_port *port) if (uart_circ_empty(&port->state->xmit)) return; + /* Clear the TX Empty interrupt */ writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_ISR); cdns_uart_handle_tx(port); @@ -626,21 +643,6 @@ static void cdns_uart_stop_rx(struct uart_port *port) writel(regval, port->membase + CDNS_UART_CR); } -/** - * cdns_uart_tx_empty - Check whether TX is empty - * @port: Handle to the uart port structure - * - * Return: TIOCSER_TEMT on success, 0 otherwise - */ -static unsigned int cdns_uart_tx_empty(struct uart_port *port) -{ - unsigned int status; - - status = readl(port->membase + CDNS_UART_SR) & - (CDNS_UART_SR_TXEMPTY | CDNS_UART_SR_TACTIVE); - return (status == CDNS_UART_SR_TXEMPTY) ? TIOCSER_TEMT : 0; -} - /** * cdns_uart_break_ctl - Based on the input ctl we have to start or stop * transmitting char breaks From fccc9d9233f918ee50cf2955ae7134a7f3418351 Mon Sep 17 00:00:00 2001 From: Manikanta Guntupalli Date: Tue, 23 Jan 2024 11:46:55 +0530 Subject: [PATCH 103/199] tty: serial: uartps: Add rs485 support to uartps driver Add rs485 support to uartps driver. Use either rts-gpios or RTS to control RS485 phy as driver or a receiver. Signed-off-by: Manikanta Guntupalli Link: https://lore.kernel.org/r/20240123061655.2150946-4-manikanta.guntupalli@amd.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/xilinx_uartps.c | 200 ++++++++++++++++++++++++++++- 1 file changed, 196 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 765a6e174052..5f48ec37cb25 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -22,7 +22,9 @@ #include #include #include -#include +#include +#include +#include #define CDNS_UART_TTY_NAME "ttyPS" #define CDNS_UART_NAME "xuartps" @@ -193,6 +195,9 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255"); * @clk_rate_change_nb: Notifier block for clock changes * @quirks: Flags for RXBS support. * @cts_override: Modem control state override + * @gpiod_rts: Pointer to the gpio descriptor + * @rs485_tx_started: RS485 tx state + * @tx_timer: Timer for tx */ struct cdns_uart { struct uart_port *port; @@ -203,10 +208,21 @@ struct cdns_uart { struct notifier_block clk_rate_change_nb; u32 quirks; bool cts_override; + struct gpio_desc *gpiod_rts; + bool rs485_tx_started; + struct hrtimer tx_timer; }; struct cdns_platform_data { u32 quirks; }; + +struct serial_rs485 cdns_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | + SER_RS485_RTS_AFTER_SEND, + .delay_rts_before_send = 1, + .delay_rts_after_send = 1, +}; + #define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \ clk_rate_change_nb) @@ -305,6 +321,55 @@ static void cdns_uart_handle_rx(void *dev_id, unsigned int isrstatus) tty_flip_buffer_push(&port->state->port); } +/** + * cdns_rts_gpio_enable - Configure RTS/GPIO to high/low + * @cdns_uart: Handle to the cdns_uart + * @enable: Value to be set to RTS/GPIO + */ +static void cdns_rts_gpio_enable(struct cdns_uart *cdns_uart, bool enable) +{ + u32 val; + + if (cdns_uart->gpiod_rts) { + gpiod_set_value(cdns_uart->gpiod_rts, enable); + } else { + val = readl(cdns_uart->port->membase + CDNS_UART_MODEMCR); + if (enable) + val |= CDNS_UART_MODEMCR_RTS; + else + val &= ~CDNS_UART_MODEMCR_RTS; + writel(val, cdns_uart->port->membase + CDNS_UART_MODEMCR); + } +} + +/** + * cdns_rs485_tx_setup - Tx setup specific to rs485 + * @cdns_uart: Handle to the cdns_uart + */ +static void cdns_rs485_tx_setup(struct cdns_uart *cdns_uart) +{ + bool enable; + + enable = cdns_uart->port->rs485.flags & SER_RS485_RTS_ON_SEND; + cdns_rts_gpio_enable(cdns_uart, enable); + + cdns_uart->rs485_tx_started = true; +} + +/** + * cdns_rs485_rx_setup - Rx setup specific to rs485 + * @cdns_uart: Handle to the cdns_uart + */ +static void cdns_rs485_rx_setup(struct cdns_uart *cdns_uart) +{ + bool enable; + + enable = cdns_uart->port->rs485.flags & SER_RS485_RTS_AFTER_SEND; + cdns_rts_gpio_enable(cdns_uart, enable); + + cdns_uart->rs485_tx_started = false; +} + /** * cdns_uart_tx_empty - Check whether TX is empty * @port: Handle to the uart port structure @@ -320,6 +385,37 @@ static unsigned int cdns_uart_tx_empty(struct uart_port *port) return (status == CDNS_UART_SR_TXEMPTY) ? TIOCSER_TEMT : 0; } +/** + * cdns_rs485_rx_callback - Timer rx callback handler for rs485. + * @t: Handle to the hrtimer structure + */ +static enum hrtimer_restart cdns_rs485_rx_callback(struct hrtimer *t) +{ + struct cdns_uart *cdns_uart = container_of(t, struct cdns_uart, tx_timer); + + /* + * Default Rx should be setup, because Rx signaling path + * need to enable to receive data. + */ + cdns_rs485_rx_setup(cdns_uart); + + return HRTIMER_NORESTART; +} + +/** + * cdns_calc_after_tx_delay - calculate delay required for after tx. + * @cdns_uart: Handle to the cdns_uart + */ +static u64 cdns_calc_after_tx_delay(struct cdns_uart *cdns_uart) +{ + /* + * Frame time + stop bit time + rs485.delay_rts_after_send + */ + return cdns_uart->port->frame_time + + DIV_ROUND_UP(cdns_uart->port->frame_time, 7) + + (u64)cdns_uart->port->rs485.delay_rts_after_send * NSEC_PER_MSEC; +} + /** * cdns_uart_handle_tx - Handle the bytes to be transmitted. * @dev_id: Id of the UART port @@ -328,6 +424,7 @@ static unsigned int cdns_uart_tx_empty(struct uart_port *port) static void cdns_uart_handle_tx(void *dev_id) { struct uart_port *port = (struct uart_port *)dev_id; + struct cdns_uart *cdns_uart = port->private_data; struct circ_buf *xmit = &port->state->xmit; unsigned int numbytes; @@ -348,6 +445,16 @@ static void cdns_uart_handle_tx(void *dev_id) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); + + /* Enable the TX Empty interrupt */ + writel(CDNS_UART_IXR_TXEMPTY, cdns_uart->port->membase + CDNS_UART_IER); + + if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED && + (uart_circ_empty(xmit) || uart_tx_stopped(port))) { + cdns_uart->tx_timer.function = &cdns_rs485_rx_callback; + hrtimer_start(&cdns_uart->tx_timer, + ns_to_ktime(cdns_calc_after_tx_delay(cdns_uart)), HRTIMER_MODE_REL); + } } /** @@ -580,6 +687,21 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb, } #endif +/** + * cdns_rs485_tx_callback - Timer tx callback handler for rs485. + * @t: Handle to the hrtimer structure + */ +static enum hrtimer_restart cdns_rs485_tx_callback(struct hrtimer *t) +{ + struct cdns_uart *cdns_uart = container_of(t, struct cdns_uart, tx_timer); + + uart_port_lock(cdns_uart->port); + cdns_uart_handle_tx(cdns_uart->port); + uart_port_unlock(cdns_uart->port); + + return HRTIMER_NORESTART; +} + /** * cdns_uart_start_tx - Start transmitting bytes * @port: Handle to the uart port structure @@ -587,6 +709,7 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb, static void cdns_uart_start_tx(struct uart_port *port) { unsigned int status; + struct cdns_uart *cdns_uart = port->private_data; if (uart_tx_stopped(port)) return; @@ -606,10 +729,16 @@ static void cdns_uart_start_tx(struct uart_port *port) /* Clear the TX Empty interrupt */ writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_ISR); + if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) { + if (!cdns_uart->rs485_tx_started) { + cdns_uart->tx_timer.function = &cdns_rs485_tx_callback; + cdns_rs485_tx_setup(cdns_uart); + return hrtimer_start(&cdns_uart->tx_timer, + ms_to_ktime(port->rs485.delay_rts_before_send), + HRTIMER_MODE_REL); + } + } cdns_uart_handle_tx(port); - - /* Enable the TX Empty interrupt */ - writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IER); } /** @@ -619,6 +748,10 @@ static void cdns_uart_start_tx(struct uart_port *port) static void cdns_uart_stop_tx(struct uart_port *port) { unsigned int regval; + struct cdns_uart *cdns_uart = port->private_data; + + if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) + cdns_rs485_rx_setup(cdns_uart); regval = readl(port->membase + CDNS_UART_CR); regval |= CDNS_UART_CR_TX_DIS; @@ -831,6 +964,9 @@ static int cdns_uart_startup(struct uart_port *port) (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST)) cpu_relax(); + if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) + cdns_rs485_rx_setup(cdns_uart); + /* * Clear the RX disable bit and then set the RX enable bit to enable * the receiver. @@ -890,6 +1026,10 @@ static void cdns_uart_shutdown(struct uart_port *port) { int status; unsigned long flags; + struct cdns_uart *cdns_uart = port->private_data; + + if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) + hrtimer_cancel(&cdns_uart->tx_timer); uart_port_lock_irqsave(port, &flags); @@ -1035,6 +1175,8 @@ static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) if (mctrl & TIOCM_RTS) val |= CDNS_UART_MODEMCR_RTS; + if (cdns_uart_data->gpiod_rts) + gpiod_set_value(cdns_uart_data->gpiod_rts, !(mctrl & TIOCM_RTS)); if (mctrl & TIOCM_DTR) val |= CDNS_UART_MODEMCR_DTR; if (mctrl & TIOCM_LOOP) @@ -1457,6 +1599,39 @@ MODULE_DEVICE_TABLE(of, cdns_uart_of_match); /* Temporary variable for storing number of instances */ static int instances; +/** + * cdns_rs485_config - Called when an application calls TIOCSRS485 ioctl. + * @port: Pointer to the uart_port structure + * @termios: Pointer to the ktermios structure + * @rs485: Pointer to the serial_rs485 structure + * + * Return: 0 + */ +static int cdns_rs485_config(struct uart_port *port, struct ktermios *termios, + struct serial_rs485 *rs485) +{ + u32 val; + struct cdns_uart *cdns_uart = port->private_data; + + if (rs485->flags & SER_RS485_ENABLED) { + dev_dbg(port->dev, "Setting UART to RS485\n"); + /* Make sure auto RTS is disabled */ + val = readl(port->membase + CDNS_UART_MODEMCR); + val &= ~CDNS_UART_MODEMCR_FCM; + writel(val, port->membase + CDNS_UART_MODEMCR); + + /* Timer setup */ + hrtimer_init(&cdns_uart->tx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + cdns_uart->tx_timer.function = &cdns_rs485_tx_callback; + + /* Disable transmitter and make Rx setup*/ + cdns_uart_stop_tx(port); + } else { + hrtimer_cancel(&cdns_uart->tx_timer); + } + return 0; +} + /** * cdns_uart_probe - Platform driver probe * @pdev: Pointer to the platform device structure @@ -1599,9 +1774,23 @@ static int cdns_uart_probe(struct platform_device *pdev) port->private_data = cdns_uart_data; port->read_status_mask = CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_RXTRIG | CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_TOUT; + port->rs485_config = cdns_rs485_config; + port->rs485_supported = cdns_rs485_supported; cdns_uart_data->port = port; platform_set_drvdata(pdev, port); + rc = uart_get_rs485_mode(port); + if (rc) + goto err_out_clk_notifier; + + cdns_uart_data->gpiod_rts = devm_gpiod_get_optional(&pdev->dev, "rts", + GPIOD_OUT_LOW); + if (IS_ERR(cdns_uart_data->gpiod_rts)) { + rc = PTR_ERR(cdns_uart_data->gpiod_rts); + dev_err(port->dev, "xuartps: devm_gpiod_get_optional failed\n"); + goto err_out_clk_notifier; + } + pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT); pm_runtime_set_active(&pdev->dev); @@ -1620,6 +1809,8 @@ static int cdns_uart_probe(struct platform_device *pdev) console_port = port; } #endif + if (cdns_uart_data->port->rs485.flags & SER_RS485_ENABLED) + cdns_rs485_rx_setup(cdns_uart_data); rc = uart_add_one_port(&cdns_uart_uart_driver, port); if (rc) { @@ -1648,6 +1839,7 @@ err_out_pm_disable: pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); pm_runtime_dont_use_autosuspend(&pdev->dev); +err_out_clk_notifier: #ifdef CONFIG_COMMON_CLK clk_notifier_unregister(cdns_uart_data->uartclk, &cdns_uart_data->clk_rate_change_nb); From 52b56990d214c7403b20f691ac61861a37c0f0db Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Thu, 1 Feb 2024 18:01:12 +0100 Subject: [PATCH 104/199] Revert "tty: serial: amba-pl011: Remove QDF2xxx workarounds" The original commit assumed this hardware is long rotting in the junkyards, but apparently Qualcomm is still using some of these old servers internally and the thing can still run upstream. Adding insult to injury, I apparently managed to overdelete code and broke non-QDF2xxx platforms [1]. Revert the removal to keep things going, at least for now. This reverts commit 196f34af2bf4c87ac4299a9775503d81b446980c. [1] https://lore.kernel.org/lkml/20240131213543.958051-1-m.szyprowski@samsung.com/ Signed-off-by: Konrad Dybcio Tested-by: Mark Brown Link: https://lore.kernel.org/r/20240201-topic-qdf24xx_is_back_apparently-v1-1-edb112a2ef90@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 82 +++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index c4df9cbc264b..fccec1698a54 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -152,6 +152,23 @@ static const struct vendor_data vendor_sbsa = { .fixed_options = true, }; +#ifdef CONFIG_ACPI_SPCR_TABLE +static const struct vendor_data vendor_qdt_qdf2400_e44 = { + .reg_offset = pl011_std_offsets, + .fr_busy = UART011_FR_TXFE, + .fr_dsr = UART01x_FR_DSR, + .fr_cts = UART01x_FR_CTS, + .fr_ri = UART011_FR_RI, + .inv_fr = UART011_FR_TXFE, + .access_32b = true, + .oversampling = false, + .dma_threshold = false, + .cts_event_workaround = false, + .always_enabled = true, + .fixed_options = true, +}; +#endif + static u16 pl011_st_offsets[REG_ARRAY_SIZE] = { [REG_DR] = UART01x_DR, [REG_ST_DMAWM] = ST_UART011_DMAWM, @@ -2451,6 +2468,15 @@ static int pl011_console_match(struct console *co, char *name, int idx, resource_size_t addr; int i; + /* + * Systems affected by the Qualcomm Technologies QDF2400 E44 erratum + * have a distinct console name, so make sure we check for that. + * The actual implementation of the erratum occurs in the probe + * function. + */ + if ((strcmp(name, "qdf2400_e44") != 0) && (strcmp(name, "pl011") != 0)) + return -ENODEV; + if (uart_parse_earlycon(options, &iotype, &addr, &options)) return -ENODEV; @@ -2491,6 +2517,22 @@ static struct console amba_console = { #define AMBA_CONSOLE (&amba_console) +static void qdf2400_e44_putc(struct uart_port *port, unsigned char c) +{ + while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF) + cpu_relax(); + writel(c, port->membase + UART01x_DR); + while (!(readl(port->membase + UART01x_FR) & UART011_FR_TXFE)) + cpu_relax(); +} + +static void qdf2400_e44_early_write(struct console *con, const char *s, unsigned int n) +{ + struct earlycon_device *dev = con->data; + + uart_console_write(&dev->port, s, n, qdf2400_e44_putc); +} + static void pl011_putc(struct uart_port *port, unsigned char c) { while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF) @@ -2569,6 +2611,29 @@ OF_EARLYCON_DECLARE(pl011, "arm,pl011", pl011_early_console_setup); OF_EARLYCON_DECLARE(pl011, "arm,sbsa-uart", pl011_early_console_setup); +/* + * On Qualcomm Datacenter Technologies QDF2400 SOCs affected by + * Erratum 44, traditional earlycon can be enabled by specifying + * "earlycon=qdf2400_e44,
". Any options are ignored. + * + * Alternatively, you can just specify "earlycon", and the early console + * will be enabled with the information from the SPCR table. In this + * case, the SPCR code will detect the need for the E44 work-around, + * and set the console name to "qdf2400_e44". + */ +static int __init +qdf2400_e44_early_console_setup(struct earlycon_device *device, + const char *opt) +{ + if (!device->port.membase) + return -ENODEV; + + device->con->write = qdf2400_e44_early_write; + return 0; +} + +EARLYCON_DECLARE(qdf2400_e44, qdf2400_e44_early_console_setup); + #else #define AMBA_CONSOLE NULL #endif @@ -2804,6 +2869,22 @@ static int pl011_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(pl011_dev_pm_ops, pl011_suspend, pl011_resume); +#ifdef CONFIG_ACPI_SPCR_TABLE +static void qpdf2400_erratum44_workaround(struct device *dev, + struct uart_amba_port *uap) +{ + if (!qdf2400_e44_present) + return; + + dev_info(dev, "working around QDF2400 SoC erratum 44\n"); + uap->vendor = &vendor_qdt_qdf2400_e44; +} +#else +static void qpdf2400_erratum44_workaround(struct device *dev, + struct uart_amba_port *uap) +{ /* empty */ } +#endif + static int sbsa_uart_probe(struct platform_device *pdev) { struct uart_amba_port *uap; @@ -2840,6 +2921,7 @@ static int sbsa_uart_probe(struct platform_device *pdev) uap->port.irq = ret; uap->vendor = &vendor_sbsa; + qpdf2400_erratum44_workaround(&pdev->dev, uap); uap->reg_offset = uap->vendor->reg_offset; uap->fifosize = 32; From 2e71508bbf57e349e0bf7bd070ba1ef2510ee168 Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Thu, 1 Feb 2024 19:05:07 -0600 Subject: [PATCH 105/199] tty: serial: samsung: Remove superfluous braces in macro Commit 59f37b7370ef ("tty: serial: samsung: Remove USI initialization") removes parameters from EXYNOS_COMMON_SERIAL_DRV_DATA() macro, but leaves unnecessary empty braces. Remove those to fix the style. No functional change. Signed-off-by: Sam Protsenko Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240202010507.22638-1-semen.protsenko@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index fcc675603b14..23cabdab44ff 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -2452,7 +2452,7 @@ static const struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = { #endif #if defined(CONFIG_ARCH_EXYNOS) -#define EXYNOS_COMMON_SERIAL_DRV_DATA() \ +#define EXYNOS_COMMON_SERIAL_DRV_DATA \ .info = { \ .name = "Samsung Exynos UART", \ .type = TYPE_S3C6400, \ @@ -2477,17 +2477,17 @@ static const struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = { } \ static const struct s3c24xx_serial_drv_data exynos4210_serial_drv_data = { - EXYNOS_COMMON_SERIAL_DRV_DATA(), + EXYNOS_COMMON_SERIAL_DRV_DATA, .fifosize = { 256, 64, 16, 16 }, }; static const struct s3c24xx_serial_drv_data exynos5433_serial_drv_data = { - EXYNOS_COMMON_SERIAL_DRV_DATA(), + EXYNOS_COMMON_SERIAL_DRV_DATA, .fifosize = { 64, 256, 16, 256 }, }; static const struct s3c24xx_serial_drv_data exynos850_serial_drv_data = { - EXYNOS_COMMON_SERIAL_DRV_DATA(), + EXYNOS_COMMON_SERIAL_DRV_DATA, .fifosize = { 256, 64, 64, 64 }, }; From 88cddfb7bf23b06876da6c3e9f296e666d0f6332 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sat, 3 Feb 2024 16:14:50 -0300 Subject: [PATCH 106/199] serdev: make serdev_bus_type const Now that the driver core can properly handle constant struct bus_type, move the serdev_bus_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Suggested-by: Greg Kroah-Hartman Signed-off-by: "Ricardo B. Marliere" Link: https://lore.kernel.org/r/20240203-bus_cleanup-tty-v1-1-86b698c82efe@marliere.net Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serdev/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index 822a5cd05566..613cb356b918 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -431,7 +431,7 @@ static void serdev_drv_remove(struct device *dev) dev_pm_domain_detach(dev, true); } -static struct bus_type serdev_bus_type = { +static const struct bus_type serdev_bus_type = { .name = "serial", .match = serdev_device_match, .probe = serdev_drv_probe, From f60ce0e4bbf385a938e89b6dcead1eea89b83741 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sat, 3 Feb 2024 16:14:51 -0300 Subject: [PATCH 107/199] serial: core: make serial_base_bus_type const Now that the driver core can properly handle constant struct bus_type, move the serial_base_bus_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Suggested-by: Greg Kroah-Hartman Signed-off-by: "Ricardo B. Marliere" Link: https://lore.kernel.org/r/20240203-bus_cleanup-tty-v1-2-86b698c82efe@marliere.net Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_base_bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/serial_base_bus.c b/drivers/tty/serial/serial_base_bus.c index 3dfcf20c4eb6..4df2a4b10445 100644 --- a/drivers/tty/serial/serial_base_bus.c +++ b/drivers/tty/serial/serial_base_bus.c @@ -41,7 +41,7 @@ static int serial_base_match(struct device *dev, struct device_driver *drv) return 0; } -static struct bus_type serial_base_bus_type = { +static const struct bus_type serial_base_bus_type = { .name = "serial-base", .match = serial_base_match, }; From fb8fa9093a4d2b5be4516a66c64b10cc35458333 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 2 Feb 2024 07:55:47 +0100 Subject: [PATCH 108/199] tty: vt: make rgb_from_256() slighly more comprehensible * make the parameter unsigned, as it is expected to be unsigned, * make the computation easier to follow -- step-by-step, and * don't use 85 / 2 which is only a reduced form of 255 / 6 (by a factor 3). Unlike the former, the latter can be understood. Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20240202065608.14019-2-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 65cd40cac96b..7d42f148559a 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1588,7 +1588,7 @@ static void default_attr(struct vc_data *vc) struct rgb { u8 r; u8 g; u8 b; }; -static void rgb_from_256(int i, struct rgb *c) +static void rgb_from_256(unsigned int i, struct rgb *c) { if (i < 8) { /* Standard colours. */ c->r = i&1 ? 0xaa : 0x00; @@ -1599,9 +1599,12 @@ static void rgb_from_256(int i, struct rgb *c) c->g = i&2 ? 0xff : 0x55; c->b = i&4 ? 0xff : 0x55; } else if (i < 232) { /* 6x6x6 colour cube. */ - c->r = (i - 16) / 36 * 85 / 2; - c->g = (i - 16) / 6 % 6 * 85 / 2; - c->b = (i - 16) % 6 * 85 / 2; + i -= 16; + c->b = i % 6 * 255 / 6; + i /= 6; + c->g = i % 6 * 255 / 6; + i /= 6; + c->r = i * 255 / 6; } else /* Grayscale ramp. */ c->r = c->g = c->b = i * 10 - 2312; } From 608053e1944edce7e301112457de89025efa9db1 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 2 Feb 2024 07:55:48 +0100 Subject: [PATCH 109/199] tty: vt: define enums for CSI+h/l codes Decrypt the constant values by proper enum names. This time in set_mode(). Define two of them as DEC ('CSI ?') is about to be split away in the next patches. Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20240202065608.14019-3-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 7d42f148559a..7b55d87248f8 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1862,6 +1862,24 @@ int mouse_reporting(void) return vc_cons[fg_console].d->vc_report_mouse; } +enum { + CSI_DEC_hl_CURSOR_KEYS = 1, /* CKM: cursor keys send ^[Ox/^[[x */ + CSI_DEC_hl_132_COLUMNS = 3, /* COLM: 80/132 mode switch */ + CSI_DEC_hl_REVERSE_VIDEO = 5, /* SCNM */ + CSI_DEC_hl_ORIGIN_MODE = 6, /* OM: origin relative/absolute */ + CSI_DEC_hl_AUTOWRAP = 7, /* AWM */ + CSI_DEC_hl_AUTOREPEAT = 8, /* ARM */ + CSI_DEC_hl_MOUSE_X10 = 9, + CSI_DEC_hl_SHOW_CURSOR = 25, /* TCEM */ + CSI_DEC_hl_MOUSE_VT200 = 1000, +}; + +enum { + CSI_hl_DISPLAY_CTRL = 3, /* handle ansi control chars */ + CSI_hl_INSERT = 4, /* IRM: insert/replace */ + CSI_hl_AUTO_NL = 20, /* LNM: Enter == CrLf/Lf */ +}; + /* console_lock is held */ static void set_mode(struct vc_data *vc, int on_off) { @@ -1870,20 +1888,20 @@ static void set_mode(struct vc_data *vc, int on_off) for (i = 0; i <= vc->vc_npar; i++) if (vc->vc_priv == EPdec) { switch(vc->vc_par[i]) { /* DEC private modes set/reset */ - case 1: /* Cursor keys send ^[Ox/^[[x */ + case CSI_DEC_hl_CURSOR_KEYS: if (on_off) set_kbd(vc, decckm); else clr_kbd(vc, decckm); break; - case 3: /* 80/132 mode switch unimplemented */ + case CSI_DEC_hl_132_COLUMNS: /* unimplemented */ #if 0 vc_resize(deccolm ? 132 : 80, vc->vc_rows); /* this alone does not suffice; some user mode utility has to change the hardware regs */ #endif break; - case 5: /* Inverted screen on/off */ + case CSI_DEC_hl_REVERSE_VIDEO: if (vc->vc_decscnm != on_off) { vc->vc_decscnm = on_off; invert_screen(vc, 0, @@ -1892,38 +1910,38 @@ static void set_mode(struct vc_data *vc, int on_off) update_attr(vc); } break; - case 6: /* Origin relative/absolute */ + case CSI_DEC_hl_ORIGIN_MODE: vc->vc_decom = on_off; gotoxay(vc, 0, 0); break; - case 7: /* Autowrap on/off */ + case CSI_DEC_hl_AUTOWRAP: vc->vc_decawm = on_off; break; - case 8: /* Autorepeat on/off */ + case CSI_DEC_hl_AUTOREPEAT: if (on_off) set_kbd(vc, decarm); else clr_kbd(vc, decarm); break; - case 9: + case CSI_DEC_hl_MOUSE_X10: vc->vc_report_mouse = on_off ? 1 : 0; break; - case 25: /* Cursor on/off */ + case CSI_DEC_hl_SHOW_CURSOR: vc->vc_deccm = on_off; break; - case 1000: + case CSI_DEC_hl_MOUSE_VT200: vc->vc_report_mouse = on_off ? 2 : 0; break; } } else { switch(vc->vc_par[i]) { /* ANSI modes set/reset */ - case 3: /* Monitor (display ctrls) */ + case CSI_hl_DISPLAY_CTRL: vc->vc_disp_ctrl = on_off; break; - case 4: /* Insert Mode on/off */ + case CSI_hl_INSERT: vc->vc_decim = on_off; break; - case 20: /* Lf, Enter == CrLf/Lf */ + case CSI_hl_AUTO_NL: if (on_off) set_kbd(vc, lnm); else From 69b2c2693ad83be07863102b12e7a36711e3e678 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 2 Feb 2024 07:55:49 +0100 Subject: [PATCH 110/199] tty: vt: rename set_mode() to csi_hl() It's how the other CSI handling functions are named, so unify to that. Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20240202065608.14019-4-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 7b55d87248f8..ae333f49790a 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1881,7 +1881,7 @@ enum { }; /* console_lock is held */ -static void set_mode(struct vc_data *vc, int on_off) +static void csi_hl(struct vc_data *vc, bool on_off) { int i; @@ -2380,11 +2380,11 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) switch(c) { case 'h': if (vc->vc_priv <= EPdec) - set_mode(vc, 1); + csi_hl(vc, true); return; case 'l': if (vc->vc_priv <= EPdec) - set_mode(vc, 0); + csi_hl(vc, false); return; case 'c': if (vc->vc_priv == EPdec) { From 58d1af93199334f235be345f6470bdcb9cc4b25d Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 2 Feb 2024 07:55:50 +0100 Subject: [PATCH 111/199] tty: vt: split DEC CSI+h/l handling into csi_DEC_hl() The DEC and ECMA handling of CSI+h/l is needlessly complicated. Split these two, so that DEC is handled when the state is EPdec ('CSI ?' was seen) and ECMA is handled in the EPecma state (no '?'). Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20240202065608.14019-5-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 144 +++++++++++++++++++++++--------------------- 1 file changed, 77 insertions(+), 67 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index ae333f49790a..d04dbafc0517 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1874,6 +1874,59 @@ enum { CSI_DEC_hl_MOUSE_VT200 = 1000, }; +/* console_lock is held */ +static void csi_DEC_hl(struct vc_data *vc, bool on_off) +{ + unsigned int i; + + for (i = 0; i <= vc->vc_npar; i++) + switch (vc->vc_par[i]) { + case CSI_DEC_hl_CURSOR_KEYS: + if (on_off) + set_kbd(vc, decckm); + else + clr_kbd(vc, decckm); + break; + case CSI_DEC_hl_132_COLUMNS: /* unimplemented */ +#if 0 + vc_resize(deccolm ? 132 : 80, vc->vc_rows); + /* this alone does not suffice; some user mode + utility has to change the hardware regs */ +#endif + break; + case CSI_DEC_hl_REVERSE_VIDEO: + if (vc->vc_decscnm != on_off) { + vc->vc_decscnm = on_off; + invert_screen(vc, 0, vc->vc_screenbuf_size, + false); + update_attr(vc); + } + break; + case CSI_DEC_hl_ORIGIN_MODE: + vc->vc_decom = on_off; + gotoxay(vc, 0, 0); + break; + case CSI_DEC_hl_AUTOWRAP: + vc->vc_decawm = on_off; + break; + case CSI_DEC_hl_AUTOREPEAT: + if (on_off) + set_kbd(vc, decarm); + else + clr_kbd(vc, decarm); + break; + case CSI_DEC_hl_MOUSE_X10: + vc->vc_report_mouse = on_off ? 1 : 0; + break; + case CSI_DEC_hl_SHOW_CURSOR: + vc->vc_deccm = on_off; + break; + case CSI_DEC_hl_MOUSE_VT200: + vc->vc_report_mouse = on_off ? 2 : 0; + break; + } +} + enum { CSI_hl_DISPLAY_CTRL = 3, /* handle ansi control chars */ CSI_hl_INSERT = 4, /* IRM: insert/replace */ @@ -1883,71 +1936,22 @@ enum { /* console_lock is held */ static void csi_hl(struct vc_data *vc, bool on_off) { - int i; + unsigned int i; for (i = 0; i <= vc->vc_npar; i++) - if (vc->vc_priv == EPdec) { - switch(vc->vc_par[i]) { /* DEC private modes set/reset */ - case CSI_DEC_hl_CURSOR_KEYS: - if (on_off) - set_kbd(vc, decckm); - else - clr_kbd(vc, decckm); - break; - case CSI_DEC_hl_132_COLUMNS: /* unimplemented */ -#if 0 - vc_resize(deccolm ? 132 : 80, vc->vc_rows); - /* this alone does not suffice; some user mode - utility has to change the hardware regs */ -#endif - break; - case CSI_DEC_hl_REVERSE_VIDEO: - if (vc->vc_decscnm != on_off) { - vc->vc_decscnm = on_off; - invert_screen(vc, 0, - vc->vc_screenbuf_size, - false); - update_attr(vc); - } - break; - case CSI_DEC_hl_ORIGIN_MODE: - vc->vc_decom = on_off; - gotoxay(vc, 0, 0); - break; - case CSI_DEC_hl_AUTOWRAP: - vc->vc_decawm = on_off; - break; - case CSI_DEC_hl_AUTOREPEAT: - if (on_off) - set_kbd(vc, decarm); - else - clr_kbd(vc, decarm); - break; - case CSI_DEC_hl_MOUSE_X10: - vc->vc_report_mouse = on_off ? 1 : 0; - break; - case CSI_DEC_hl_SHOW_CURSOR: - vc->vc_deccm = on_off; - break; - case CSI_DEC_hl_MOUSE_VT200: - vc->vc_report_mouse = on_off ? 2 : 0; - break; - } - } else { - switch(vc->vc_par[i]) { /* ANSI modes set/reset */ - case CSI_hl_DISPLAY_CTRL: - vc->vc_disp_ctrl = on_off; - break; - case CSI_hl_INSERT: - vc->vc_decim = on_off; - break; - case CSI_hl_AUTO_NL: - if (on_off) - set_kbd(vc, lnm); - else - clr_kbd(vc, lnm); - break; - } + switch (vc->vc_par[i]) { /* ANSI modes set/reset */ + case CSI_hl_DISPLAY_CTRL: + vc->vc_disp_ctrl = on_off; + break; + case CSI_hl_INSERT: + vc->vc_decim = on_off; + break; + case CSI_hl_AUTO_NL: + if (on_off) + set_kbd(vc, lnm); + else + clr_kbd(vc, lnm); + break; } } @@ -2379,12 +2383,12 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) vc->vc_state = ESnormal; switch(c) { case 'h': - if (vc->vc_priv <= EPdec) - csi_hl(vc, true); + if (vc->vc_priv == EPdec) + csi_DEC_hl(vc, true); return; case 'l': - if (vc->vc_priv <= EPdec) - csi_hl(vc, false); + if (vc->vc_priv == EPdec) + csi_DEC_hl(vc, false); return; case 'c': if (vc->vc_priv == EPdec) { @@ -2494,6 +2498,12 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) else if (vc->vc_par[0] == 3) bitmap_zero(vc->vc_tab_stop, VC_TABSTOPS_COUNT); return; + case 'h': + csi_hl(vc, true); + return; + case 'l': + csi_hl(vc, false); + return; case 'm': csi_m(vc); return; From 9abe9bf5741932a4bb7d4959d1bc53715248686c Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 2 Feb 2024 07:55:51 +0100 Subject: [PATCH 112/199] tty: vt: remove unneeded assignment of EPecma to vc_priv vc_data::vc_priv is _always_ assigned before the ESgetpars case is entered (in ESsquare). Therefore, there is no need to reset it when leaving the ESgetpars case. Note the state is set to ESnormal few lines above, so ESgetpars is entered only by the next CSI. Therefore, this obfuscation can be removed. Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20240202065608.14019-6-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index d04dbafc0517..69ebce0878f2 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2421,10 +2421,9 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) } return; } - if (vc->vc_priv != EPecma) { - vc->vc_priv = EPecma; + if (vc->vc_priv != EPecma) return; - } + switch(c) { case 'G': case '`': if (vc->vc_par[0]) From 0afaeb78d1286002310c190a2cf1c9e5c882bfad Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 2 Feb 2024 07:55:52 +0100 Subject: [PATCH 113/199] tty: vt: move CSI+n handling along to other ECMA CSIs CSIs without [<=>?] modifiers (ECMA) are handled in the switch-case below this DEC switch+case handler. So move this ECMA CSI+n there too as it fits there better. Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20240202065608.14019-7-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 69ebce0878f2..04d109464994 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2412,14 +2412,6 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) return; } break; - case 'n': - if (vc->vc_priv == EPecma) { - if (vc->vc_par[0] == 5) - status_report(tty); - else if (vc->vc_par[0] == 6) - cursor_report(vc, tty); - } - return; } if (vc->vc_priv != EPecma) return; @@ -2506,6 +2498,12 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) case 'm': csi_m(vc); return; + case 'n': + if (vc->vc_par[0] == 5) + status_report(tty); + else if (vc->vc_par[0] == 6) + cursor_report(vc, tty); + return; case 'q': /* DECLL - but only 3 leds */ /* map 0,1,2,3 to 0,1,2,4 */ if (vc->vc_par[0] < 4) From f9ac8d4e9f42cb0356ea530fdb31b0cb445a1c30 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 2 Feb 2024 07:55:53 +0100 Subject: [PATCH 114/199] tty: vt: define an enum for CSI+] codes Decrypt the constant values by proper enum names. This time in setterm_command() (to be renamed to csi_RSB() in the next patches). Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20240202065608.14019-8-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 04d109464994..9db545f305dc 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1955,62 +1955,76 @@ static void csi_hl(struct vc_data *vc, bool on_off) } } +enum CSI_right_square_bracket { + CSI_RSB_COLOR_FOR_UNDERLINE = 1, + CSI_RSB_COLOR_FOR_HALF_BRIGHT = 2, + CSI_RSB_MAKE_CUR_COLOR_DEFAULT = 8, + CSI_RSB_BLANKING_INTERVAL = 9, + CSI_RSB_BELL_FREQUENCY = 10, + CSI_RSB_BELL_DURATION = 11, + CSI_RSB_BRING_CONSOLE_TO_FRONT = 12, + CSI_RSB_UNBLANK = 13, + CSI_RSB_VESA_OFF_INTERVAL = 14, + CSI_RSB_BRING_PREV_CONSOLE_TO_FRONT = 15, + CSI_RSB_CURSOR_BLINK_INTERVAL = 16, +}; + /* console_lock is held */ static void setterm_command(struct vc_data *vc) { switch (vc->vc_par[0]) { - case 1: /* set color for underline mode */ + case CSI_RSB_COLOR_FOR_UNDERLINE: if (vc->vc_can_do_color && vc->vc_par[1] < 16) { vc->vc_ulcolor = color_table[vc->vc_par[1]]; if (vc->state.underline) update_attr(vc); } break; - case 2: /* set color for half intensity mode */ + case CSI_RSB_COLOR_FOR_HALF_BRIGHT: if (vc->vc_can_do_color && vc->vc_par[1] < 16) { vc->vc_halfcolor = color_table[vc->vc_par[1]]; if (vc->state.intensity == VCI_HALF_BRIGHT) update_attr(vc); } break; - case 8: /* store colors as defaults */ + case CSI_RSB_MAKE_CUR_COLOR_DEFAULT: vc->vc_def_color = vc->vc_attr; if (vc->vc_hi_font_mask == 0x100) vc->vc_def_color >>= 1; default_attr(vc); update_attr(vc); break; - case 9: /* set blanking interval */ + case CSI_RSB_BLANKING_INTERVAL: blankinterval = min(vc->vc_par[1], 60U) * 60; poke_blanked_console(); break; - case 10: /* set bell frequency in Hz */ + case CSI_RSB_BELL_FREQUENCY: if (vc->vc_npar >= 1) vc->vc_bell_pitch = vc->vc_par[1]; else vc->vc_bell_pitch = DEFAULT_BELL_PITCH; break; - case 11: /* set bell duration in msec */ + case CSI_RSB_BELL_DURATION: if (vc->vc_npar >= 1) vc->vc_bell_duration = (vc->vc_par[1] < 2000) ? msecs_to_jiffies(vc->vc_par[1]) : 0; else vc->vc_bell_duration = DEFAULT_BELL_DURATION; break; - case 12: /* bring specified console to the front */ + case CSI_RSB_BRING_CONSOLE_TO_FRONT: if (vc->vc_par[1] >= 1 && vc_cons_allocated(vc->vc_par[1] - 1)) set_console(vc->vc_par[1] - 1); break; - case 13: /* unblank the screen */ + case CSI_RSB_UNBLANK: poke_blanked_console(); break; - case 14: /* set vesa powerdown interval */ + case CSI_RSB_VESA_OFF_INTERVAL: vesa_off_interval = min(vc->vc_par[1], 60U) * 60 * HZ; break; - case 15: /* activate the previous console */ + case CSI_RSB_BRING_PREV_CONSOLE_TO_FRONT: set_console(last_console); break; - case 16: /* set cursor blink duration in msec */ + case CSI_RSB_CURSOR_BLINK_INTERVAL: if (vc->vc_npar >= 1 && vc->vc_par[1] >= 50 && vc->vc_par[1] <= USHRT_MAX) vc->vc_cur_blink_ms = vc->vc_par[1]; From cc8539cab4a2094ab1a841af6c67e54be41b2c49 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 2 Feb 2024 07:55:54 +0100 Subject: [PATCH 115/199] tty: vt: rename setterm_command() to csi_RSB() It follows naming of other similar functions. RSB stands here for Right Square Bracket as (obviously) ']' cannot be in the function name. Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20240202065608.14019-9-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 9db545f305dc..c072007807e1 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1969,8 +1969,14 @@ enum CSI_right_square_bracket { CSI_RSB_CURSOR_BLINK_INTERVAL = 16, }; -/* console_lock is held */ -static void setterm_command(struct vc_data *vc) +/* + * csi_RSB - csi+] (Right Square Bracket) handler + * + * These are linux console private sequences. + * + * console_lock is held + */ +static void csi_RSB(struct vc_data *vc) { switch (vc->vc_par[0]) { case CSI_RSB_COLOR_FOR_UNDERLINE: @@ -2549,8 +2555,8 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) case '@': csi_at(vc, vc->vc_par[0]); return; - case ']': /* setterm functions */ - setterm_command(vc); + case ']': + csi_RSB(vc); return; } return; From 9156792bcf941d445c3c3045bb289e09f070adba Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 2 Feb 2024 07:55:55 +0100 Subject: [PATCH 116/199] tty: vt: put cases on separate lines Some cases of the CSI switch are stuffed on one line. Put them all to a separate line as is dictated by the coding style (and for better readability). Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20240202065608.14019-10-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index c072007807e1..42bc0957a654 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2437,7 +2437,8 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) return; switch(c) { - case 'G': case '`': + case 'G': + case '`': if (vc->vc_par[0]) vc->vc_par[0]--; gotoxy(vc, vc->vc_par[0], vc->state.y); @@ -2447,12 +2448,14 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) vc->vc_par[0]++; gotoxy(vc, vc->state.x, vc->state.y - vc->vc_par[0]); return; - case 'B': case 'e': + case 'B': + case 'e': if (!vc->vc_par[0]) vc->vc_par[0]++; gotoxy(vc, vc->state.x, vc->state.y + vc->vc_par[0]); return; - case 'C': case 'a': + case 'C': + case 'a': if (!vc->vc_par[0]) vc->vc_par[0]++; gotoxy(vc, vc->state.x + vc->vc_par[0], vc->state.y); @@ -2477,7 +2480,8 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) vc->vc_par[0]--; gotoxay(vc, vc->state.x ,vc->vc_par[0]); return; - case 'H': case 'f': + case 'H': + case 'f': if (vc->vc_par[0]) vc->vc_par[0]--; if (vc->vc_par[1]) From a8ccce55a8d87df4013ac277ed382e8cbf672a96 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 2 Feb 2024 07:55:56 +0100 Subject: [PATCH 117/199] tty: vt: accept u8 in do_con_trol() and vc_setGx() These functions expect u8 as the control character. Switch the type from 'int' appropriately. The caller passing the value (do_con_write()) is fixed as well. Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20240202065608.14019-11-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 42bc0957a654..451a852ed234 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2144,7 +2144,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear) csi_J(vc, CSI_J_VISIBLE); } -static void vc_setGx(struct vc_data *vc, unsigned int which, int c) +static void vc_setGx(struct vc_data *vc, unsigned int which, u8 c) { unsigned char *charset = &vc->state.Gx_charset[which]; @@ -2198,7 +2198,7 @@ enum { }; /* console_lock is held */ -static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) +static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, u8 c) { /* * Control characters can be used in the _middle_ @@ -2963,7 +2963,7 @@ static int do_con_write(struct tty_struct *tty, const u8 *buf, int count) param.vc = vc; while (!tty->flow.stopped && count) { - int orig = *buf; + u8 orig = *buf; buf++; n++; count--; From ce66f8e387cda44e01a0db4d506b1d0a130d5005 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 2 Feb 2024 07:55:57 +0100 Subject: [PATCH 118/199] tty: vt: extract ascii handling to handle_ascii() To make the do_con_trol() a bit more understandable, extract the ASCII handling (the switch-case) to a separate function. Other nested switch-cases will follow in the next patches. Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20240202065608.14019-12-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 58 +++++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 451a852ed234..7cda1a958c5e 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2197,28 +2197,26 @@ enum { ASCII_EXT_CSI = 128 + ASCII_ESCAPE, }; -/* console_lock is held */ -static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, u8 c) +/* + * Handle ascii characters in control sequences and change states accordingly. + * E.g. ESC sets the state of vc to ESesc. + * + * Returns: true if @c handled. + */ +static bool handle_ascii(struct tty_struct *tty, struct vc_data *vc, u8 c) { - /* - * Control characters can be used in the _middle_ - * of an escape sequence, aside from ANSI control strings. - */ - if (ansi_control_string(vc->vc_state) && c >= ASCII_IGNORE_FIRST && - c <= ASCII_IGNORE_LAST) - return; switch (c) { case ASCII_NULL: - return; + return true; case ASCII_BELL: if (ansi_control_string(vc->vc_state)) vc->vc_state = ESnormal; else if (vc->vc_bell_duration) kd_mksound(vc->vc_bell_pitch, vc->vc_bell_duration); - return; + return true; case ASCII_BACKSPACE: bs(vc); - return; + return true; case ASCII_HTAB: vc->vc_pos -= (vc->state.x << 1); @@ -2230,41 +2228,59 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, u8 c) vc->vc_pos += (vc->state.x << 1); notify_write(vc, '\t'); - return; + return true; case ASCII_LINEFEED: case ASCII_VTAB: case ASCII_FORMFEED: lf(vc); if (!is_kbd(vc, lnm)) - return; + return true; fallthrough; case ASCII_CAR_RET: cr(vc); - return; + return true; case ASCII_SHIFTOUT: vc->state.charset = 1; vc->vc_translate = set_translate(vc->state.Gx_charset[1], vc); vc->vc_disp_ctrl = 1; - return; + return true; case ASCII_SHIFTIN: vc->state.charset = 0; vc->vc_translate = set_translate(vc->state.Gx_charset[0], vc); vc->vc_disp_ctrl = 0; - return; + return true; case ASCII_CANCEL: case ASCII_SUBSTITUTE: vc->vc_state = ESnormal; - return; + return true; case ASCII_ESCAPE: vc->vc_state = ESesc; - return; + return true; case ASCII_DEL: del(vc); - return; + return true; case ASCII_EXT_CSI: vc->vc_state = ESsquare; - return; + return true; } + + return false; +} + +/* console_lock is held */ +static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, u8 c) +{ + /* + * Control characters can be used in the _middle_ + * of an escape sequence, aside from ANSI control strings. + */ + if (ansi_control_string(vc->vc_state) && c >= ASCII_IGNORE_FIRST && + c <= ASCII_IGNORE_LAST) + return; + + if (handle_ascii(tty, vc, c)) + return; + switch(vc->vc_state) { case ESesc: vc->vc_state = ESnormal; From a9ffb2234773b39c5de7b09506a467663d6bc2f7 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 2 Feb 2024 07:55:58 +0100 Subject: [PATCH 119/199] tty: vt: separate ESesc state handling into handle_esc() Similar to the ASCII handling, the ESC handling can be easily moved away from do_con_trol(). So create a new handle_esc() for that. And add a comment with an example. Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20240202065608.14019-13-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 134 ++++++++++++++++++++++++-------------------- 1 file changed, 72 insertions(+), 62 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 7cda1a958c5e..3dddb7128234 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2267,6 +2267,77 @@ static bool handle_ascii(struct tty_struct *tty, struct vc_data *vc, u8 c) return false; } +/* + * Handle a character (@c) following an ESC (when @vc is in the ESesc state). + * E.g. previous ESC with @c == '[' here yields the ESsquare state (that is: + * CSI). + */ +static void handle_esc(struct tty_struct *tty, struct vc_data *vc, u8 c) +{ + vc->vc_state = ESnormal; + switch (c) { + case '[': + vc->vc_state = ESsquare; + break; + case ']': + vc->vc_state = ESnonstd; + break; + case '_': + vc->vc_state = ESapc; + break; + case '^': + vc->vc_state = ESpm; + break; + case '%': + vc->vc_state = ESpercent; + break; + case 'E': + cr(vc); + lf(vc); + break; + case 'M': + ri(vc); + break; + case 'D': + lf(vc); + break; + case 'H': + if (vc->state.x < VC_TABSTOPS_COUNT) + set_bit(vc->state.x, vc->vc_tab_stop); + break; + case 'P': + vc->vc_state = ESdcs; + break; + case 'Z': + respond_ID(tty); + break; + case '7': + save_cur(vc); + break; + case '8': + restore_cur(vc); + break; + case '(': + vc->vc_state = ESsetG0; + break; + case ')': + vc->vc_state = ESsetG1; + break; + case '#': + vc->vc_state = EShash; + break; + case 'c': + reset_terminal(vc, 1); + break; + case '>': /* Numeric keypad */ + clr_kbd(vc, kbdapplic); + break; + case '=': /* Appl. keypad */ + set_kbd(vc, kbdapplic); + break; + } +} + /* console_lock is held */ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, u8 c) { @@ -2283,68 +2354,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, u8 c) switch(vc->vc_state) { case ESesc: - vc->vc_state = ESnormal; - switch (c) { - case '[': - vc->vc_state = ESsquare; - return; - case ']': - vc->vc_state = ESnonstd; - return; - case '_': - vc->vc_state = ESapc; - return; - case '^': - vc->vc_state = ESpm; - return; - case '%': - vc->vc_state = ESpercent; - return; - case 'E': - cr(vc); - lf(vc); - return; - case 'M': - ri(vc); - return; - case 'D': - lf(vc); - return; - case 'H': - if (vc->state.x < VC_TABSTOPS_COUNT) - set_bit(vc->state.x, vc->vc_tab_stop); - return; - case 'P': - vc->vc_state = ESdcs; - return; - case 'Z': - respond_ID(tty); - return; - case '7': - save_cur(vc); - return; - case '8': - restore_cur(vc); - return; - case '(': - vc->vc_state = ESsetG0; - return; - case ')': - vc->vc_state = ESsetG1; - return; - case '#': - vc->vc_state = EShash; - return; - case 'c': - reset_terminal(vc, 1); - return; - case '>': /* Numeric keypad */ - clr_kbd(vc, kbdapplic); - return; - case '=': /* Appl. keypad */ - set_kbd(vc, kbdapplic); - return; - } + handle_esc(tty, vc, c); return; case ESnonstd: if (c=='P') { /* palette escape sequence */ From de0f61f342078aff5bbaf69bd749e91b324128df Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 2 Feb 2024 07:55:59 +0100 Subject: [PATCH 120/199] tty: vt: move CSI DEC handling to a separate function The handling of "CSI ? ..." (i.e. vc_priv == EPdec) can be easily moved out of do_con_trol() into a separate function. This again increases readability of do_con_trol(). Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20240202065608.14019-14-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 75 ++++++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 31 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 3dddb7128234..7cdd0eb1e423 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2338,6 +2338,43 @@ static void handle_esc(struct tty_struct *tty, struct vc_data *vc, u8 c) } } +/* + * Handle special DEC control sequences ("ESC [ ? parameters char"). Parameters + * are in @vc->vc_par and the char is in @c here. + */ +static void csi_DEC(struct tty_struct *tty, struct vc_data *vc, u8 c) +{ + switch (c) { + case 'h': + csi_DEC_hl(vc, true); + break; + case 'l': + csi_DEC_hl(vc, false); + break; + case 'c': + if (vc->vc_par[0]) + vc->vc_cursor_type = CUR_MAKE(vc->vc_par[0], + vc->vc_par[1], + vc->vc_par[2]); + else + vc->vc_cursor_type = cur_default; + break; + case 'm': + clear_selection(); + if (vc->vc_par[0]) + vc->vc_complement_mask = vc->vc_par[0] << 8 | vc->vc_par[1]; + else + vc->vc_complement_mask = vc->vc_s_complement_mask; + break; + case 'n': + if (vc->vc_par[0] == 5) + status_report(tty); + else if (vc->vc_par[0] == 6) + cursor_report(vc, tty); + break; + } +} + /* console_lock is held */ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, u8 c) { @@ -2427,40 +2464,16 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, u8 c) return; } vc->vc_state = ESnormal; - switch(c) { - case 'h': - if (vc->vc_priv == EPdec) - csi_DEC_hl(vc, true); + + switch (vc->vc_priv) { + case EPdec: + csi_DEC(tty, vc, c); return; - case 'l': - if (vc->vc_priv == EPdec) - csi_DEC_hl(vc, false); + case EPecma: + break; + default: return; - case 'c': - if (vc->vc_priv == EPdec) { - if (vc->vc_par[0]) - vc->vc_cursor_type = - CUR_MAKE(vc->vc_par[0], - vc->vc_par[1], - vc->vc_par[2]); - else - vc->vc_cursor_type = cur_default; - return; - } - break; - case 'm': - if (vc->vc_priv == EPdec) { - clear_selection(); - if (vc->vc_par[0]) - vc->vc_complement_mask = vc->vc_par[0] << 8 | vc->vc_par[1]; - else - vc->vc_complement_mask = vc->vc_s_complement_mask; - return; - } - break; } - if (vc->vc_priv != EPecma) - return; switch(c) { case 'G': From 7c1c9c14944730219b14732018829acac89ee550 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 2 Feb 2024 07:56:00 +0100 Subject: [PATCH 121/199] tty: vt: move CSI ECMA handling to a separate function Similar to previous moves, move also "CSI ..." (i.e. vc_priv == EPecma) handling to a separate function. This is the last large move of code out of do_con_trol(). And despite it is still 151 lines of code (down from 407!), it is now quite easy to folllow the transitions of the state machine in there. ESnonstd and ESpalette handling still can be moved away, but it won't improve that much. Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20240202065608.14019-15-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 269 +++++++++++++++++++++++--------------------- 1 file changed, 139 insertions(+), 130 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 7cdd0eb1e423..1c832d04c0dc 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2375,6 +2375,143 @@ static void csi_DEC(struct tty_struct *tty, struct vc_data *vc, u8 c) } } +/* + * Handle Control Sequence Introducer control characters. That is + * "ESC [ parameters char". Parameters are in @vc->vc_par and the char is in + * @c here. + */ +static void csi_ECMA(struct tty_struct *tty, struct vc_data *vc, u8 c) +{ + switch (c) { + case 'G': + case '`': + if (vc->vc_par[0]) + vc->vc_par[0]--; + gotoxy(vc, vc->vc_par[0], vc->state.y); + break; + case 'A': + if (!vc->vc_par[0]) + vc->vc_par[0]++; + gotoxy(vc, vc->state.x, vc->state.y - vc->vc_par[0]); + break; + case 'B': + case 'e': + if (!vc->vc_par[0]) + vc->vc_par[0]++; + gotoxy(vc, vc->state.x, vc->state.y + vc->vc_par[0]); + break; + case 'C': + case 'a': + if (!vc->vc_par[0]) + vc->vc_par[0]++; + gotoxy(vc, vc->state.x + vc->vc_par[0], vc->state.y); + break; + case 'D': + if (!vc->vc_par[0]) + vc->vc_par[0]++; + gotoxy(vc, vc->state.x - vc->vc_par[0], vc->state.y); + break; + case 'E': + if (!vc->vc_par[0]) + vc->vc_par[0]++; + gotoxy(vc, 0, vc->state.y + vc->vc_par[0]); + break; + case 'F': + if (!vc->vc_par[0]) + vc->vc_par[0]++; + gotoxy(vc, 0, vc->state.y - vc->vc_par[0]); + break; + case 'd': + if (vc->vc_par[0]) + vc->vc_par[0]--; + gotoxay(vc, vc->state.x ,vc->vc_par[0]); + break; + case 'H': + case 'f': + if (vc->vc_par[0]) + vc->vc_par[0]--; + if (vc->vc_par[1]) + vc->vc_par[1]--; + gotoxay(vc, vc->vc_par[1], vc->vc_par[0]); + break; + case 'J': + csi_J(vc, vc->vc_par[0]); + break; + case 'K': + csi_K(vc); + break; + case 'L': + csi_L(vc); + break; + case 'M': + csi_M(vc); + break; + case 'P': + csi_P(vc); + break; + case 'c': + if (!vc->vc_par[0]) + respond_ID(tty); + break; + case 'g': + if (!vc->vc_par[0] && vc->state.x < VC_TABSTOPS_COUNT) + set_bit(vc->state.x, vc->vc_tab_stop); + else if (vc->vc_par[0] == 3) + bitmap_zero(vc->vc_tab_stop, VC_TABSTOPS_COUNT); + break; + case 'h': + csi_hl(vc, true); + break; + case 'l': + csi_hl(vc, false); + break; + case 'm': + csi_m(vc); + break; + case 'n': + if (vc->vc_par[0] == 5) + status_report(tty); + else if (vc->vc_par[0] == 6) + cursor_report(vc, tty); + break; + case 'q': /* DECLL - but only 3 leds */ + /* map 0,1,2,3 to 0,1,2,4 */ + if (vc->vc_par[0] < 4) + vt_set_led_state(vc->vc_num, + (vc->vc_par[0] < 3) ? vc->vc_par[0] : 4); + break; + case 'r': + if (!vc->vc_par[0]) + vc->vc_par[0]++; + if (!vc->vc_par[1]) + vc->vc_par[1] = vc->vc_rows; + /* Minimum allowed region is 2 lines */ + if (vc->vc_par[0] < vc->vc_par[1] && + vc->vc_par[1] <= vc->vc_rows) { + vc->vc_top = vc->vc_par[0] - 1; + vc->vc_bottom = vc->vc_par[1]; + gotoxay(vc, 0, 0); + } + break; + case 's': + save_cur(vc); + break; + case 'u': + restore_cur(vc); + break; + case 'X': + csi_X(vc); + break; + case '@': + csi_at(vc, vc->vc_par[0]); + break; + case ']': + csi_RSB(vc); + break; + } + +} + /* console_lock is held */ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, u8 c) { @@ -2470,139 +2607,11 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, u8 c) csi_DEC(tty, vc, c); return; case EPecma: - break; + csi_ECMA(tty, vc, c); + return; default: return; } - - switch(c) { - case 'G': - case '`': - if (vc->vc_par[0]) - vc->vc_par[0]--; - gotoxy(vc, vc->vc_par[0], vc->state.y); - return; - case 'A': - if (!vc->vc_par[0]) - vc->vc_par[0]++; - gotoxy(vc, vc->state.x, vc->state.y - vc->vc_par[0]); - return; - case 'B': - case 'e': - if (!vc->vc_par[0]) - vc->vc_par[0]++; - gotoxy(vc, vc->state.x, vc->state.y + vc->vc_par[0]); - return; - case 'C': - case 'a': - if (!vc->vc_par[0]) - vc->vc_par[0]++; - gotoxy(vc, vc->state.x + vc->vc_par[0], vc->state.y); - return; - case 'D': - if (!vc->vc_par[0]) - vc->vc_par[0]++; - gotoxy(vc, vc->state.x - vc->vc_par[0], vc->state.y); - return; - case 'E': - if (!vc->vc_par[0]) - vc->vc_par[0]++; - gotoxy(vc, 0, vc->state.y + vc->vc_par[0]); - return; - case 'F': - if (!vc->vc_par[0]) - vc->vc_par[0]++; - gotoxy(vc, 0, vc->state.y - vc->vc_par[0]); - return; - case 'd': - if (vc->vc_par[0]) - vc->vc_par[0]--; - gotoxay(vc, vc->state.x ,vc->vc_par[0]); - return; - case 'H': - case 'f': - if (vc->vc_par[0]) - vc->vc_par[0]--; - if (vc->vc_par[1]) - vc->vc_par[1]--; - gotoxay(vc, vc->vc_par[1], vc->vc_par[0]); - return; - case 'J': - csi_J(vc, vc->vc_par[0]); - return; - case 'K': - csi_K(vc); - return; - case 'L': - csi_L(vc); - return; - case 'M': - csi_M(vc); - return; - case 'P': - csi_P(vc); - return; - case 'c': - if (!vc->vc_par[0]) - respond_ID(tty); - return; - case 'g': - if (!vc->vc_par[0] && vc->state.x < VC_TABSTOPS_COUNT) - set_bit(vc->state.x, vc->vc_tab_stop); - else if (vc->vc_par[0] == 3) - bitmap_zero(vc->vc_tab_stop, VC_TABSTOPS_COUNT); - return; - case 'h': - csi_hl(vc, true); - return; - case 'l': - csi_hl(vc, false); - return; - case 'm': - csi_m(vc); - return; - case 'n': - if (vc->vc_par[0] == 5) - status_report(tty); - else if (vc->vc_par[0] == 6) - cursor_report(vc, tty); - return; - case 'q': /* DECLL - but only 3 leds */ - /* map 0,1,2,3 to 0,1,2,4 */ - if (vc->vc_par[0] < 4) - vt_set_led_state(vc->vc_num, - (vc->vc_par[0] < 3) ? vc->vc_par[0] : 4); - return; - case 'r': - if (!vc->vc_par[0]) - vc->vc_par[0]++; - if (!vc->vc_par[1]) - vc->vc_par[1] = vc->vc_rows; - /* Minimum allowed region is 2 lines */ - if (vc->vc_par[0] < vc->vc_par[1] && - vc->vc_par[1] <= vc->vc_rows) { - vc->vc_top = vc->vc_par[0] - 1; - vc->vc_bottom = vc->vc_par[1]; - gotoxay(vc, 0, 0); - } - return; - case 's': - save_cur(vc); - return; - case 'u': - restore_cur(vc); - return; - case 'X': - csi_X(vc); - return; - case '@': - csi_at(vc, vc->vc_par[0]); - return; - case ']': - csi_RSB(vc); - return; - } - return; case EScsiignore: if (c >= ASCII_CSI_IGNORE_FIRST && c <= ASCII_CSI_IGNORE_LAST) return; From 22795b3c4738849283c63274c6af98b9d28c4c3c Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 2 Feb 2024 07:56:01 +0100 Subject: [PATCH 122/199] tty: vt: name, reflow and document enum vc_ctl_state The enum for states is currently compact and undocumented. Put each definition on a separate line and document them all using kernel-doc. Document the same on the use sites. Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20240202065608.14019-16-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 72 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 55 insertions(+), 17 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 1c832d04c0dc..6d08290fdfdf 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2091,9 +2091,44 @@ static void restore_cur(struct vc_data *vc) vc->vc_need_wrap = 0; } -enum { ESnormal, ESesc, ESsquare, ESgetpars, ESfunckey, - EShash, ESsetG0, ESsetG1, ESpercent, EScsiignore, ESnonstd, - ESpalette, ESosc, ESapc, ESpm, ESdcs }; +/** + * enum vc_ctl_state - control characters state of a vt + * + * @ESnormal: initial state, no control characters parsed + * @ESesc: ESC parsed + * @ESsquare: CSI parsed -- modifiers/parameters/ctrl chars expected + * @ESgetpars: CSI parsed -- parameters/ctrl chars expected + * @ESfunckey: CSI [ parsed + * @EShash: ESC # parsed + * @ESsetG0: ESC ( parsed + * @ESsetG1: ESC ) parsed + * @ESpercent: ESC % parsed + * @EScsiignore: CSI [0x20-0x3f] parsed + * @ESnonstd: OSC parsed + * @ESpalette: OSC P parsed + * @ESosc: OSC [0-9] parsed + * @ESapc: ESC _ parsed + * @ESpm: ESC ^ parsed + * @ESdcs: ESC P parsed + */ +enum vc_ctl_state { + ESnormal, + ESesc, + ESsquare, + ESgetpars, + ESfunckey, + EShash, + ESsetG0, + ESsetG1, + ESpercent, + EScsiignore, + ESnonstd, + ESpalette, + ESosc, + ESapc, + ESpm, + ESdcs, +}; /* console_lock is held (except via vc_init()) */ static void reset_terminal(struct vc_data *vc, int do_clear) @@ -2527,10 +2562,10 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, u8 c) return; switch(vc->vc_state) { - case ESesc: + case ESesc: /* ESC */ handle_esc(tty, vc, c); return; - case ESnonstd: + case ESnonstd: /* ESC ] aka OSC */ if (c=='P') { /* palette escape sequence */ for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++) vc->vc_par[vc->vc_npar] = 0; @@ -2545,7 +2580,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, u8 c) else vc->vc_state = ESnormal; return; - case ESpalette: + case ESpalette: /* ESC ] P aka OSC P */ if (isxdigit(c)) { vc->vc_par[vc->vc_npar++] = hex_to_bin(c); if (vc->vc_npar == 7) { @@ -2562,7 +2597,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, u8 c) } else vc->vc_state = ESnormal; return; - case ESsquare: + case ESsquare: /* ESC [ aka CSI, parameters or modifiers expected */ for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++) vc->vc_par[vc->vc_npar] = 0; vc->vc_npar = 0; @@ -2587,7 +2622,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, u8 c) } vc->vc_priv = EPecma; fallthrough; - case ESgetpars: + case ESgetpars: /* ESC [ aka CSI, parameters expected */ if (c == ';' && vc->vc_npar < NPAR - 1) { vc->vc_npar++; return; @@ -2600,6 +2635,9 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, u8 c) vc->vc_state = EScsiignore; return; } + + /* parameters done, handle the control char @c */ + vc->vc_state = ESnormal; switch (vc->vc_priv) { @@ -2617,7 +2655,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, u8 c) return; vc->vc_state = ESnormal; return; - case ESpercent: + case ESpercent: /* ESC % */ vc->vc_state = ESnormal; switch (c) { case '@': /* defined in ISO 2022 */ @@ -2629,10 +2667,10 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, u8 c) return; } return; - case ESfunckey: + case ESfunckey: /* ESC [ [ aka CSI [ */ vc->vc_state = ESnormal; return; - case EShash: + case EShash: /* ESC # */ vc->vc_state = ESnormal; if (c == '8') { /* DEC screen alignment test. kludge :-) */ @@ -2644,21 +2682,21 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, u8 c) do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2); } return; - case ESsetG0: + case ESsetG0: /* ESC ( */ vc_setGx(vc, 0, c); vc->vc_state = ESnormal; return; - case ESsetG1: + case ESsetG1: /* ESC ) */ vc_setGx(vc, 1, c); vc->vc_state = ESnormal; return; - case ESapc: + case ESapc: /* ESC _ */ return; - case ESosc: + case ESosc: /* ESC ] [0-9] aka OSC [0-9] */ return; - case ESpm: + case ESpm: /* ESC ^ */ return; - case ESdcs: + case ESdcs: /* ESC P */ return; default: vc->vc_state = ESnormal; From fd5b40251a02f7652adba88bc09802fcff004a7f Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 2 Feb 2024 07:56:02 +0100 Subject: [PATCH 123/199] tty: vt: simplify ansi_control_string() Given all the ANSI control states are sequential in the vc_ctl_state enum, we can define first/last constants and use them in ansi_control_string(). It makes the test simple and allows for removal of the 'if' (which was unnecessary at all -- the 'return' should have returned the 'if' content directly anyway). And remove the useless comment -- it's clear from the function prototype. Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20240202065608.14019-17-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 6d08290fdfdf..e1cbe966bc84 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2107,9 +2107,11 @@ static void restore_cur(struct vc_data *vc) * @ESnonstd: OSC parsed * @ESpalette: OSC P parsed * @ESosc: OSC [0-9] parsed + * @ESANSI_first: first state for ignoring ansi control sequences * @ESapc: ESC _ parsed * @ESpm: ESC ^ parsed * @ESdcs: ESC P parsed + * @ESANSI_last: last state for ignoring ansi control sequences */ enum vc_ctl_state { ESnormal, @@ -2125,9 +2127,11 @@ enum vc_ctl_state { ESnonstd, ESpalette, ESosc, + ESANSI_first = ESosc, ESapc, ESpm, ESdcs, + ESANSI_last = ESdcs, }; /* console_lock is held (except via vc_init()) */ @@ -2202,12 +2206,9 @@ static void vc_setGx(struct vc_data *vc, unsigned int which, u8 c) vc->vc_translate = set_translate(*charset, vc); } -/* is this state an ANSI control string? */ -static bool ansi_control_string(unsigned int state) +static bool ansi_control_string(enum vc_ctl_state state) { - if (state == ESosc || state == ESapc || state == ESpm || state == ESdcs) - return true; - return false; + return state >= ESANSI_first && state <= ESANSI_last; } enum { From bc9d077a8d171765b11f3b2fc52ba483bc1a31f6 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 2 Feb 2024 07:56:03 +0100 Subject: [PATCH 124/199] tty: vt: handle CSI+[ inside preexisting switch-case In do_con_trol()'s ESsquare case, there is already a switch (c). It is preceded by an 'if (c == '[')'. Despite this 'if' handles a state transition and not a modifier, move it as one of the switch cases. This makes all the 'c' decision making more obvious there. Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20240202065608.14019-18-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index e1cbe966bc84..4d020a9967a2 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2603,11 +2603,10 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, u8 c) vc->vc_par[vc->vc_npar] = 0; vc->vc_npar = 0; vc->vc_state = ESgetpars; - if (c == '[') { /* Function key */ - vc->vc_state=ESfunckey; - return; - } switch (c) { + case '[': /* Function key */ + vc->vc_state = ESfunckey; + return; case '?': vc->vc_priv = EPdec; return; From 798d8b1cfecc45ede0d32ee1375bae3c39649d7d Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 2 Feb 2024 07:56:04 +0100 Subject: [PATCH 125/199] tty: vt: add new helper for reseting vc parameters The code to reset the vc parameter parsing is repeated on two locations. Create a helper vc_reset_params() and use it on both of them. And instead of a 'for' loop to clear the array of parameters, use simpler memset(). Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20240202065608.14019-19-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 4d020a9967a2..b0f691d79bf2 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2548,6 +2548,12 @@ static void csi_ECMA(struct tty_struct *tty, struct vc_data *vc, u8 c) } +static void vc_reset_params(struct vc_data *vc) +{ + memset(vc->vc_par, 0, sizeof(vc->vc_par)); + vc->vc_npar = 0; +} + /* console_lock is held */ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, u8 c) { @@ -2568,9 +2574,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, u8 c) return; case ESnonstd: /* ESC ] aka OSC */ if (c=='P') { /* palette escape sequence */ - for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++) - vc->vc_par[vc->vc_npar] = 0; - vc->vc_npar = 0; + vc_reset_params(vc); vc->vc_state = ESpalette; return; } else if (c=='R') { /* reset palette */ @@ -2599,9 +2603,8 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, u8 c) vc->vc_state = ESnormal; return; case ESsquare: /* ESC [ aka CSI, parameters or modifiers expected */ - for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++) - vc->vc_par[vc->vc_npar] = 0; - vc->vc_npar = 0; + vc_reset_params(vc); + vc->vc_state = ESgetpars; switch (c) { case '[': /* Function key */ From 3d5f5b9711e46800d7e602e95f26698cc6ff2ed3 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 2 Feb 2024 07:56:05 +0100 Subject: [PATCH 126/199] tty: vt: use switch+case in the ESnonstd case To be uniform in the 'c' handling, use switch-case (with ranges) even in the ESnonstd case in do_con_trol(). Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20240202065608.14019-20-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index b0f691d79bf2..b5fc3b896e26 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2573,17 +2573,19 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, u8 c) handle_esc(tty, vc, c); return; case ESnonstd: /* ESC ] aka OSC */ - if (c=='P') { /* palette escape sequence */ + switch (c) { + case 'P': /* palette escape sequence */ vc_reset_params(vc); vc->vc_state = ESpalette; return; - } else if (c=='R') { /* reset palette */ + case 'R': /* reset palette */ reset_palette(vc); - vc->vc_state = ESnormal; - } else if (c>='0' && c<='9') + break; + case '0' ... '9': vc->vc_state = ESosc; - else - vc->vc_state = ESnormal; + return; + } + vc->vc_state = ESnormal; return; case ESpalette: /* ESC ] P aka OSC P */ if (isxdigit(c)) { From 137eb9ad22bf2b2e0e613afc076e5f51390954ad Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 2 Feb 2024 07:56:06 +0100 Subject: [PATCH 127/199] tty: vt: use switch+case in the ESgetpars case To be uniform in the 'c' handling, use switch-case (with ranges) even in the ESgetpars case in do_con_trol(). Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20240202065608.14019-21-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index b5fc3b896e26..b3c61ec92df9 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2628,10 +2628,14 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, u8 c) vc->vc_priv = EPecma; fallthrough; case ESgetpars: /* ESC [ aka CSI, parameters expected */ - if (c == ';' && vc->vc_npar < NPAR - 1) { - vc->vc_npar++; - return; - } else if (c>='0' && c<='9') { + switch (c) { + case ';': + if (vc->vc_npar < NPAR - 1) { + vc->vc_npar++; + return; + } + break; + case '0' ... '9': vc->vc_par[vc->vc_npar] *= 10; vc->vc_par[vc->vc_npar] += c - '0'; return; From 3701400a39d5964be767f9c085dffb9dd21c7f59 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 2 Feb 2024 07:56:07 +0100 Subject: [PATCH 128/199] tty: vt: use ASCII enum constants in vt_console_print() There are still numbers used for ASCII characters in vt_console_print(). As we have an ASCII enum now, use the constant names from the enum instead. Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20240202065608.14019-22-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index b3c61ec92df9..e35f7a31a7bd 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -3240,22 +3240,23 @@ static void vt_console_print(struct console *co, const char *b, unsigned count) cnt = 0; while (count--) { c = *b++; - if (c == 10 || c == 13 || c == 8 || vc->vc_need_wrap) { + if (c == ASCII_LINEFEED || c == ASCII_CAR_RET || + c == ASCII_BACKSPACE || vc->vc_need_wrap) { if (cnt && con_is_visible(vc)) vc->vc_sw->con_putcs(vc, start, cnt, vc->state.y, start_x); cnt = 0; - if (c == 8) { /* backspace */ + if (c == ASCII_BACKSPACE) { bs(vc); start = (ushort *)vc->vc_pos; start_x = vc->state.x; continue; } - if (c != 13) + if (c != ASCII_CAR_RET) lf(vc); cr(vc); start = (ushort *)vc->vc_pos; start_x = vc->state.x; - if (c == 10 || c == 13) + if (c == ASCII_LINEFEED || c == ASCII_CAR_RET) continue; } vc_uniscr_putc(vc, c); From 6cc3028f797a549f256d593867a769ab6a8265f2 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 2 Feb 2024 07:56:08 +0100 Subject: [PATCH 129/199] tty: vt: decrypt magic constants in vc_is_control() 0x0d00ff81 and 0x0800f501 are bitmasks of ASCII characters. Spell them explicitly using BIT() + ASCII constants. GENMASK() is used for the 9-bit range in CTRL_ACTION. This also modifies the 'if' checking if the masks should be applied. >From a "random" ' ' to the actual size of the bitmasks' type. Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20240202065608.14019-23-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index e35f7a31a7bd..463be4e48dc8 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2893,9 +2893,13 @@ static bool vc_is_control(struct vc_data *vc, int tc, int c) * as cursor movement) and should not be displayed as a glyph unless * the disp_ctrl mode is explicitly enabled. */ - static const u32 CTRL_ACTION = 0x0d00ff81; + static const u32 CTRL_ACTION = BIT(ASCII_NULL) | + GENMASK(ASCII_SHIFTIN, ASCII_BELL) | BIT(ASCII_CANCEL) | + BIT(ASCII_SUBSTITUTE) | BIT(ASCII_ESCAPE); /* Cannot be overridden by disp_ctrl */ - static const u32 CTRL_ALWAYS = 0x0800f501; + static const u32 CTRL_ALWAYS = BIT(ASCII_NULL) | BIT(ASCII_BACKSPACE) | + BIT(ASCII_LINEFEED) | BIT(ASCII_SHIFTIN) | BIT(ASCII_SHIFTOUT) | + BIT(ASCII_CAR_RET) | BIT(ASCII_FORMFEED) | BIT(ASCII_ESCAPE); if (vc->vc_state != ESnormal) return true; @@ -2912,7 +2916,7 @@ static bool vc_is_control(struct vc_data *vc, int tc, int c) * useless without them; to display an arbitrary font position use the * direct-to-font zone in UTF-8 mode. */ - if (c < ' ') { + if (c < BITS_PER_TYPE(CTRL_ALWAYS)) { if (vc->vc_disp_ctrl) return CTRL_ALWAYS & BIT(c); else From a5251cd9614cf2ac24a513359b5265b44605cf82 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sun, 4 Feb 2024 17:55:22 -0300 Subject: [PATCH 130/199] w1: make w1_bus_type const Now that the driver core can properly handle constant struct bus_type, move the w1_bus_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Link: https://lore.kernel.org/r/20240204-bus_cleanup-w1-v1-1-a0f4c84d7db3@marliere.net Signed-off-by: Krzysztof Kozlowski --- drivers/w1/w1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index 5353cbd75126..afb1cc4606c5 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -167,7 +167,7 @@ static struct w1_family w1_default_family = { static int w1_uevent(const struct device *dev, struct kobj_uevent_env *env); -static struct bus_type w1_bus_type = { +static const struct bus_type w1_bus_type = { .name = "w1", .uevent = w1_uevent, }; From 12d2a81c57042337b68ef7d1b400a6f2b707dc94 Mon Sep 17 00:00:00 2001 From: Christoph Winklhofer Date: Fri, 9 Feb 2024 07:22:37 +0100 Subject: [PATCH 131/199] dt-bindings: serial: allow onewire as child node The UART 1-Wire bus utilizes the Serial Device Bus to create the 1-wire timing patterns. Acked-by: Rob Herring Signed-off-by: Christoph Winklhofer Link: https://lore.kernel.org/r/20240209-w1-uart-v6-1-3e753c149196@gmail.com Signed-off-by: Krzysztof Kozlowski --- Documentation/devicetree/bindings/serial/serial.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/serial/serial.yaml b/Documentation/devicetree/bindings/serial/serial.yaml index 65804ca274ae..ffc9198ae214 100644 --- a/Documentation/devicetree/bindings/serial/serial.yaml +++ b/Documentation/devicetree/bindings/serial/serial.yaml @@ -88,7 +88,7 @@ properties: TX FIFO threshold configuration (in bytes). patternProperties: - "^(bluetooth|bluetooth-gnss|gnss|gps|mcu)$": + "^(bluetooth|bluetooth-gnss|gnss|gps|mcu|onewire)$": if: type: object then: From 23b333375317f6c2866e1ede7e7c4a726fc22aa8 Mon Sep 17 00:00:00 2001 From: Christoph Winklhofer Date: Fri, 9 Feb 2024 07:22:38 +0100 Subject: [PATCH 132/199] dt-bindings: w1: UART 1-Wire bus Add device tree binding for UART 1-Wire bus. Reviewed-by: Rob Herring Signed-off-by: Christoph Winklhofer Link: https://lore.kernel.org/r/20240209-w1-uart-v6-2-3e753c149196@gmail.com Signed-off-by: Krzysztof Kozlowski --- .../devicetree/bindings/w1/w1-uart.yaml | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 Documentation/devicetree/bindings/w1/w1-uart.yaml diff --git a/Documentation/devicetree/bindings/w1/w1-uart.yaml b/Documentation/devicetree/bindings/w1/w1-uart.yaml new file mode 100644 index 000000000000..bd7c62d780b8 --- /dev/null +++ b/Documentation/devicetree/bindings/w1/w1-uart.yaml @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/w1/w1-uart.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: UART 1-Wire Bus + +maintainers: + - Christoph Winklhofer + +description: | + UART 1-wire bus. Utilizes the UART interface via the Serial Device Bus + to create the 1-Wire timing patterns. + + The UART peripheral must support full-duplex and operate in open-drain + mode. The timing patterns are generated by a specific combination of + baud-rate and transmitted byte, which corresponds to a 1-Wire read bit, + write bit or reset pulse. + + The default baud-rate for reset and presence detection is 9600 and for + a 1-Wire read or write operation 115200. In case the actual baud-rate + is different from the requested one, the transmitted byte is adapted + to generate the 1-Wire timing patterns. + + https://www.analog.com/en/technical-articles/using-a-uart-to-implement-a-1wire-bus-master.html + +properties: + compatible: + const: w1-uart + + reset-bps: + default: 9600 + description: + The baud rate for the 1-Wire reset and presence detect. + + write-0-bps: + default: 115200 + description: + The baud rate for the 1-Wire write-0 cycle. + + write-1-bps: + default: 115200 + description: + The baud rate for the 1-Wire write-1 and read cycle. + +required: + - compatible + +additionalProperties: + type: object + +examples: + - | + serial { + onewire { + compatible = "w1-uart"; + }; + }; From a3c08804364e80328a9ffdac59bb26676b938195 Mon Sep 17 00:00:00 2001 From: Christoph Winklhofer Date: Wed, 14 Feb 2024 07:36:15 +0100 Subject: [PATCH 133/199] w1: add UART w1 bus driver Add a UART 1-Wire bus driver. The driver utilizes the UART interface via the Serial Device Bus to create the 1-Wire timing patterns. The driver was tested on a "Raspberry Pi 3B" with a DS18B20 and on a "Variscite DART-6UL" with a DS18S20 temperature sensor. The 1-Wire timing pattern and the corresponding UART baud-rate with the interpretation of the transferred bytes are described in the document: Link: https://www.analog.com/en/technical-articles/using-a-uart-to-implement-a-1wire-bus-master.html In short, the UART peripheral must support full-duplex and operate in open-drain mode. The timing patterns are generated by a specific combination of baud-rate and transmitted byte, which corresponds to a 1-Wire read bit, write bit or reset. Signed-off-by: Christoph Winklhofer Link: https://lore.kernel.org/r/20240214-w1-uart-v7-3-6e21fa24e066@gmail.com [krzysztof: w1_uart_serdev_receive_buf() return type fixup] Signed-off-by: Krzysztof Kozlowski --- Documentation/w1/masters/index.rst | 1 + Documentation/w1/masters/w1-uart.rst | 54 ++++ drivers/w1/masters/Kconfig | 10 + drivers/w1/masters/Makefile | 1 + drivers/w1/masters/w1-uart.c | 415 +++++++++++++++++++++++++++ 5 files changed, 481 insertions(+) create mode 100644 Documentation/w1/masters/w1-uart.rst create mode 100644 drivers/w1/masters/w1-uart.c diff --git a/Documentation/w1/masters/index.rst b/Documentation/w1/masters/index.rst index 4442a98850ad..cc40189909fd 100644 --- a/Documentation/w1/masters/index.rst +++ b/Documentation/w1/masters/index.rst @@ -12,3 +12,4 @@ mxc-w1 omap-hdq w1-gpio + w1-uart diff --git a/Documentation/w1/masters/w1-uart.rst b/Documentation/w1/masters/w1-uart.rst new file mode 100644 index 000000000000..8d0f122178d4 --- /dev/null +++ b/Documentation/w1/masters/w1-uart.rst @@ -0,0 +1,54 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +===================== +Kernel driver w1-uart +===================== + +Author: Christoph Winklhofer + + +Description +----------- + +UART 1-Wire bus driver. The driver utilizes the UART interface via the +Serial Device Bus to create the 1-Wire timing patterns as described in +the document `"Using a UART to Implement a 1-Wire Bus Master"`_. + +.. _"Using a UART to Implement a 1-Wire Bus Master": https://www.analog.com/en/technical-articles/using-a-uart-to-implement-a-1wire-bus-master.html + +In short, the UART peripheral must support full-duplex and operate in +open-drain mode. The timing patterns are generated by a specific +combination of baud-rate and transmitted byte, which corresponds to a +1-Wire read bit, write bit or reset pulse. + +For instance the timing pattern for a 1-Wire reset and presence detect uses +the baud-rate 9600, i.e. 104.2 us per bit. The transmitted byte 0xf0 over +UART (least significant bit first, start-bit low) sets the reset low time +for 1-Wire to 521 us. A present 1-Wire device changes the received byte by +pulling the line low, which is used by the driver to evaluate the result of +the 1-Wire operation. + +Similar for a 1-Wire read bit or write bit, which uses the baud-rate +115200, i.e. 8.7 us per bit. The transmitted byte 0x80 is used for a +Write-0 operation (low time 69.6us) and the byte 0xff for Read-0, Read-1 +and Write-1 (low time 8.7us). + +The default baud-rate for reset and presence detection is 9600 and for +a 1-Wire read or write operation 115200. In case the actual baud-rate +is different from the requested one, the transmitted byte is adapted +to generate the 1-Wire timing patterns. + + +Usage +----- + +Specify the UART 1-wire bus in the device tree by adding the single child +onewire to the serial node (e.g. uart0). For example: +:: + + @uart0 { + ... + onewire { + compatible = "w1-uart"; + }; + }; diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig index 513c0b114337..e6049a75b35b 100644 --- a/drivers/w1/masters/Kconfig +++ b/drivers/w1/masters/Kconfig @@ -78,5 +78,15 @@ config W1_MASTER_SGI This support is also available as a module. If so, the module will be called sgi_w1. +config W1_MASTER_UART + tristate "UART 1-wire driver" + depends on SERIAL_DEV_BUS + help + Say Y here if you want to communicate with your 1-wire devices using + UART interface. + + This support is also available as a module. If so, the module + will be called w1-uart. + endmenu diff --git a/drivers/w1/masters/Makefile b/drivers/w1/masters/Makefile index 6c5a21f9b88c..227f80987e69 100644 --- a/drivers/w1/masters/Makefile +++ b/drivers/w1/masters/Makefile @@ -12,3 +12,4 @@ obj-$(CONFIG_W1_MASTER_MXC) += mxc_w1.o obj-$(CONFIG_W1_MASTER_GPIO) += w1-gpio.o obj-$(CONFIG_HDQ_MASTER_OMAP) += omap_hdq.o obj-$(CONFIG_W1_MASTER_SGI) += sgi_w1.o +obj-$(CONFIG_W1_MASTER_UART) += w1-uart.o diff --git a/drivers/w1/masters/w1-uart.c b/drivers/w1/masters/w1-uart.c new file mode 100644 index 000000000000..a31782e56ba7 --- /dev/null +++ b/drivers/w1/masters/w1-uart.c @@ -0,0 +1,415 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * w1-uart - UART 1-Wire bus driver + * + * Uses the UART interface (via Serial Device Bus) to create the 1-Wire + * timing patterns. Implements the following 1-Wire master interface: + * + * - reset_bus: requests baud-rate 9600 + * + * - touch_bit: requests baud-rate 115200 + * + * Author: Christoph Winklhofer + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* UART packet contains start and stop bit */ +#define W1_UART_BITS_PER_PACKET (BITS_PER_BYTE + 2) + +/* Timeout to wait for completion of serdev-receive */ +#define W1_UART_TIMEOUT msecs_to_jiffies(500) + +/** + * struct w1_uart_config - configuration for 1-Wire operation + * @baudrate: baud-rate returned from serdev + * @delay_us: delay to complete a 1-Wire cycle (in us) + * @tx_byte: byte to generate 1-Wire timing pattern + */ +struct w1_uart_config { + unsigned int baudrate; + unsigned int delay_us; + u8 tx_byte; +}; + +/** + * struct w1_uart_device - 1-Wire UART device structure + * @serdev: serial device + * @bus: w1-bus master + * @cfg_reset: config for 1-Wire reset + * @cfg_touch_0: config for 1-Wire write-0 cycle + * @cfg_touch_1: config for 1-Wire write-1 and read cycle + * @rx_byte_received: completion for serdev receive + * @rx_mutex: mutex to protect rx_err and rx_byte + * @rx_err: indicates an error in serdev-receive + * @rx_byte: result byte from serdev-receive + */ +struct w1_uart_device { + struct serdev_device *serdev; + struct w1_bus_master bus; + + struct w1_uart_config cfg_reset; + struct w1_uart_config cfg_touch_0; + struct w1_uart_config cfg_touch_1; + + struct completion rx_byte_received; + /* + * protect rx_err and rx_byte from concurrent access in + * w1-callbacks and serdev-receive. + */ + struct mutex rx_mutex; + int rx_err; + u8 rx_byte; +}; + +/** + * struct w1_uart_limits - limits for 1-Wire operations + * @baudrate: Requested baud-rate to create 1-Wire timing pattern + * @bit_min_us: minimum time for a bit (in us) + * @bit_max_us: maximum time for a bit (in us) + * @sample_us: timespan to sample 1-Wire response + * @cycle_us: duration of the 1-Wire cycle + */ +struct w1_uart_limits { + unsigned int baudrate; + unsigned int bit_min_us; + unsigned int bit_max_us; + unsigned int sample_us; + unsigned int cycle_us; +}; + +static inline unsigned int baud_to_bit_ns(unsigned int baud) +{ + return NSEC_PER_SEC / baud; +} + +static inline unsigned int to_ns(unsigned int us) +{ + return us * NSEC_PER_USEC; +} + +/* + * Set baud-rate, delay and tx-byte to create a 1-Wire pulse and adapt + * the tx-byte according to the actual baud-rate. + * + * Reject when: + * - time for a bit outside min/max range + * - a 1-Wire response is not detectable for sent byte + */ +static int w1_uart_set_config(struct serdev_device *serdev, + const struct w1_uart_limits *limits, + struct w1_uart_config *w1cfg) +{ + unsigned int packet_ns; + unsigned int bits_low; + unsigned int bit_ns; + unsigned int low_ns; + + w1cfg->baudrate = serdev_device_set_baudrate(serdev, limits->baudrate); + if (w1cfg->baudrate == 0) + return -EINVAL; + + /* Compute in nanoseconds for accuracy */ + bit_ns = baud_to_bit_ns(w1cfg->baudrate); + bits_low = to_ns(limits->bit_min_us) / bit_ns; + /* start bit is always low */ + low_ns = bit_ns * (bits_low + 1); + + if (low_ns < to_ns(limits->bit_min_us)) + return -EINVAL; + + if (low_ns > to_ns(limits->bit_max_us)) + return -EINVAL; + + /* 1-Wire response detectable for sent byte */ + if (limits->sample_us > 0 && + bit_ns * BITS_PER_BYTE < low_ns + to_ns(limits->sample_us)) + return -EINVAL; + + /* delay: 1-Wire cycle takes longer than the UART packet */ + packet_ns = bit_ns * W1_UART_BITS_PER_PACKET; + w1cfg->delay_us = 0; + if (to_ns(limits->cycle_us) > packet_ns) + w1cfg->delay_us = + (to_ns(limits->cycle_us) - packet_ns) / NSEC_PER_USEC; + + /* byte to create 1-Wire pulse */ + w1cfg->tx_byte = 0xff << bits_low; + + return 0; +} + +/* + * Configuration for reset and presence detect + * - bit_min_us is 480us, add margin and use 485us + * - limits for sample time 60us-75us, use 65us + */ +static int w1_uart_set_config_reset(struct w1_uart_device *w1dev) +{ + struct serdev_device *serdev = w1dev->serdev; + struct device_node *np = serdev->dev.of_node; + + struct w1_uart_limits limits = { .baudrate = 9600, + .bit_min_us = 485, + .bit_max_us = 640, + .sample_us = 65, + .cycle_us = 960 }; + + of_property_read_u32(np, "reset-bps", &limits.baudrate); + + return w1_uart_set_config(serdev, &limits, &w1dev->cfg_reset); +} + +/* + * Configuration for write-0 cycle (touch bit 0) + * - bit_min_us is 60us, add margin and use 65us + * - no sampling required, sample_us = 0 + */ +static int w1_uart_set_config_touch_0(struct w1_uart_device *w1dev) +{ + struct serdev_device *serdev = w1dev->serdev; + struct device_node *np = serdev->dev.of_node; + + struct w1_uart_limits limits = { .baudrate = 115200, + .bit_min_us = 65, + .bit_max_us = 120, + .sample_us = 0, + .cycle_us = 70 }; + + of_property_read_u32(np, "write-0-bps", &limits.baudrate); + + return w1_uart_set_config(serdev, &limits, &w1dev->cfg_touch_0); +} + +/* + * Configuration for write-1 and read cycle (touch bit 1) + * - bit_min_us is 5us, add margin and use 6us + * - limits for sample time 5us-15us, use 15us + */ +static int w1_uart_set_config_touch_1(struct w1_uart_device *w1dev) +{ + struct serdev_device *serdev = w1dev->serdev; + struct device_node *np = serdev->dev.of_node; + + struct w1_uart_limits limits = { .baudrate = 115200, + .bit_min_us = 6, + .bit_max_us = 15, + .sample_us = 15, + .cycle_us = 70 }; + + of_property_read_u32(np, "write-1-bps", &limits.baudrate); + + return w1_uart_set_config(serdev, &limits, &w1dev->cfg_touch_1); +} + +/* + * Configure and open the serial device + */ +static int w1_uart_serdev_open(struct w1_uart_device *w1dev) +{ + struct serdev_device *serdev = w1dev->serdev; + struct device *dev = &serdev->dev; + int ret; + + ret = devm_serdev_device_open(dev, serdev); + if (ret < 0) + return ret; + + ret = serdev_device_set_parity(serdev, SERDEV_PARITY_NONE); + if (ret < 0) { + dev_err(dev, "set parity failed\n"); + return ret; + } + + ret = w1_uart_set_config_reset(w1dev); + if (ret < 0) { + dev_err(dev, "config for reset failed\n"); + return ret; + } + + ret = w1_uart_set_config_touch_0(w1dev); + if (ret < 0) { + dev_err(dev, "config for touch-0 failed\n"); + return ret; + } + + ret = w1_uart_set_config_touch_1(w1dev); + if (ret < 0) { + dev_err(dev, "config for touch-1 failed\n"); + return ret; + } + + serdev_device_set_flow_control(serdev, false); + + return 0; +} + +/* + * Send one byte (tx_byte) and read one byte (rx_byte) via serdev. + */ +static int w1_uart_serdev_tx_rx(struct w1_uart_device *w1dev, + const struct w1_uart_config *w1cfg, u8 *rx_byte) +{ + struct serdev_device *serdev = w1dev->serdev; + int ret; + + serdev_device_write_flush(serdev); + serdev_device_set_baudrate(serdev, w1cfg->baudrate); + + /* write and immediately read one byte */ + reinit_completion(&w1dev->rx_byte_received); + ret = serdev_device_write_buf(serdev, &w1cfg->tx_byte, 1); + if (ret != 1) + return -EIO; + ret = wait_for_completion_interruptible_timeout( + &w1dev->rx_byte_received, W1_UART_TIMEOUT); + if (ret <= 0) + return -EIO; + + /* locking could fail when serdev is unexpectedly receiving. */ + if (!mutex_trylock(&w1dev->rx_mutex)) + return -EIO; + + ret = w1dev->rx_err; + if (ret == 0) + *rx_byte = w1dev->rx_byte; + + mutex_unlock(&w1dev->rx_mutex); + + if (w1cfg->delay_us > 0) + fsleep(w1cfg->delay_us); + + return ret; +} + +static size_t w1_uart_serdev_receive_buf(struct serdev_device *serdev, + const u8 *buf, size_t count) +{ + struct w1_uart_device *w1dev = serdev_device_get_drvdata(serdev); + + mutex_lock(&w1dev->rx_mutex); + + /* sent a single byte and receive one single byte */ + if (count == 1) { + w1dev->rx_byte = buf[0]; + w1dev->rx_err = 0; + } else { + w1dev->rx_err = -EIO; + } + + mutex_unlock(&w1dev->rx_mutex); + complete(&w1dev->rx_byte_received); + + return count; +} + +static const struct serdev_device_ops w1_uart_serdev_ops = { + .receive_buf = w1_uart_serdev_receive_buf, + .write_wakeup = serdev_device_write_wakeup, +}; + +/* + * 1-wire reset and presence detect: A present slave will manipulate + * the received byte by pulling the 1-Wire low. + */ +static u8 w1_uart_reset_bus(void *data) +{ + struct w1_uart_device *w1dev = data; + const struct w1_uart_config *w1cfg = &w1dev->cfg_reset; + int ret; + u8 val; + + ret = w1_uart_serdev_tx_rx(w1dev, w1cfg, &val); + if (ret < 0) + return -1; + + /* Device present (0) or no device (1) */ + return val != w1cfg->tx_byte ? 0 : 1; +} + +/* + * 1-Wire read and write cycle: Only the read-0 manipulates the + * received byte, all others left the line untouched. + */ +static u8 w1_uart_touch_bit(void *data, u8 bit) +{ + struct w1_uart_device *w1dev = data; + const struct w1_uart_config *w1cfg = bit ? &w1dev->cfg_touch_1 : + &w1dev->cfg_touch_0; + int ret; + u8 val; + + ret = w1_uart_serdev_tx_rx(w1dev, w1cfg, &val); + + /* return inactive bus state on error */ + if (ret < 0) + return 1; + + return val == w1cfg->tx_byte ? 1 : 0; +} + +static int w1_uart_probe(struct serdev_device *serdev) +{ + struct device *dev = &serdev->dev; + struct w1_uart_device *w1dev; + int ret; + + w1dev = devm_kzalloc(dev, sizeof(*w1dev), GFP_KERNEL); + if (!w1dev) + return -ENOMEM; + w1dev->bus.data = w1dev; + w1dev->bus.reset_bus = w1_uart_reset_bus; + w1dev->bus.touch_bit = w1_uart_touch_bit; + w1dev->serdev = serdev; + + init_completion(&w1dev->rx_byte_received); + mutex_init(&w1dev->rx_mutex); + + ret = w1_uart_serdev_open(w1dev); + if (ret < 0) + return ret; + serdev_device_set_drvdata(serdev, w1dev); + serdev_device_set_client_ops(serdev, &w1_uart_serdev_ops); + + return w1_add_master_device(&w1dev->bus); +} + +static void w1_uart_remove(struct serdev_device *serdev) +{ + struct w1_uart_device *w1dev = serdev_device_get_drvdata(serdev); + + /* + * Waits until w1-uart callbacks are finished, serdev is closed + * and its device data released automatically by devres (waits + * until serdev-receive is finished). + */ + w1_remove_master_device(&w1dev->bus); +} + +static const struct of_device_id w1_uart_of_match[] = { + { .compatible = "w1-uart" }, + {}, +}; +MODULE_DEVICE_TABLE(of, w1_uart_of_match); + +static struct serdev_device_driver w1_uart_driver = { + .driver = { + .name = "w1-uart", + .of_match_table = w1_uart_of_match, + }, + .probe = w1_uart_probe, + .remove = w1_uart_remove, +}; + +module_serdev_device_driver(w1_uart_driver); + +MODULE_DESCRIPTION("UART w1 bus driver"); +MODULE_AUTHOR("Christoph Winklhofer "); +MODULE_LICENSE("GPL"); From 8524788abf564fb7927873ff3fbc8056c6f02195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roman=20=C5=BDilka?= Date: Sun, 11 Feb 2024 16:51:04 +0100 Subject: [PATCH 134/199] tty/vt: Corrected doc of vc_sanitize_unicode(), vc_translate_unicode() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Corrected the doc of vc_sanitize_unicode() and vc_translate_unicode(), tightly coupled functions which parse UTF-8 byte sequences. 1. Desc. of @rescan corresponded to the meaning of the return value -1. Corrected + added "Return:" section. 2. Replaced the ambiguous "character" with "code point" or "byte". Signed-off-by: Roman Žilka Link: https://lore.kernel.org/r/bee9faa8-0ea7-4411-bf77-3cb2e06385c7@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 463be4e48dc8..4342c47285fe 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2780,7 +2780,7 @@ static inline int vc_translate_ascii(const struct vc_data *vc, int c) /** * vc_sanitize_unicode - Replace invalid Unicode code points with ``U+FFFD`` - * @c: the received character, or ``U+FFFD`` for invalid sequences. + * @c: the received code point */ static inline int vc_sanitize_unicode(const int c) { @@ -2793,13 +2793,21 @@ static inline int vc_sanitize_unicode(const int c) /** * vc_translate_unicode - Combine UTF-8 into Unicode in &vc_data.vc_utf_char * @vc: virtual console - * @c: character to translate - * @rescan: we return true if we need more (continuation) data + * @c: UTF-8 byte to translate + * @rescan: set to true iff @c wasn't consumed here and needs to be re-processed * - * * &vc_data.vc_utf_char is the being-constructed unicode character. + * * &vc_data.vc_utf_char is the being-constructed Unicode code point. * * &vc_data.vc_utf_count is the number of continuation bytes still expected to * arrive. * * &vc_data.vc_npar is the number of continuation bytes arrived so far. + * + * Return: + * * %-1 - Input OK so far, @c consumed, further bytes expected. + * * %0xFFFD - Possibility 1: input invalid, @c may have been consumed (see + * desc. of @rescan). Possibility 2: input OK, @c consumed, + * ``U+FFFD`` is the resulting code point. ``U+FFFD`` is valid, + * ``REPLACEMENT CHARACTER``. + * * otherwise - Input OK, @c consumed, resulting code point returned. */ static int vc_translate_unicode(struct vc_data *vc, int c, bool *rescan) { From 42af6bcbc351d544889fcbcfc9c3d4bd39191b7d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 13 Feb 2024 11:17:49 +0100 Subject: [PATCH 135/199] tty: hvc-iucv: fix function pointer casts clang warns about explicitly casting between incompatible function pointers: drivers/tty/hvc/hvc_iucv.c:1100:23: error: cast from 'void (*)(const void *)' to 'void (*)(struct device *)' converts to incompatible function type [-Werror,-Wcast-function-type-strict] 1100 | priv->dev->release = (void (*)(struct device *)) kfree; | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Add a separate function to handle this correctly. Signed-off-by: Arnd Bergmann Reviewed-by: Jiri Slaby Link: https://lore.kernel.org/r/20240213101756.461701-1-arnd@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/hvc/hvc_iucv.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c index fdecc0d63731..b1149bc62ca1 100644 --- a/drivers/tty/hvc/hvc_iucv.c +++ b/drivers/tty/hvc/hvc_iucv.c @@ -1035,6 +1035,10 @@ static const struct attribute_group *hvc_iucv_dev_attr_groups[] = { NULL, }; +static void hvc_iucv_free(struct device *data) +{ + kfree(data); +} /** * hvc_iucv_alloc() - Allocates a new struct hvc_iucv_private instance @@ -1097,7 +1101,7 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console) priv->dev->bus = &iucv_bus; priv->dev->parent = iucv_root; priv->dev->groups = hvc_iucv_dev_attr_groups; - priv->dev->release = (void (*)(struct device *)) kfree; + priv->dev->release = hvc_iucv_free; rc = device_register(priv->dev); if (rc) { put_device(priv->dev); From 394e3dbac214e6144a4a0fd27cfd5e5164daea3d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 13 Feb 2024 21:38:27 +0200 Subject: [PATCH 136/199] serial: 8250_pci1xxxx: Don't use "proxy" headers Update header inclusions to follow IWYU (Include What You Use) principle. Signed-off-by: Andy Shevchenko Reviewed-by: Jiri Slaby Link: https://lore.kernel.org/r/20240213193827.3207353-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci1xxxx.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/8250/8250_pci1xxxx.c b/drivers/tty/serial/8250/8250_pci1xxxx.c index 5cf0580f21cd..2181eda41d9f 100644 --- a/drivers/tty/serial/8250/8250_pci1xxxx.c +++ b/drivers/tty/serial/8250/8250_pci1xxxx.c @@ -7,23 +7,31 @@ * Copyright (C) 2022 Microchip Technology Inc., All Rights Reserved. */ +#include #include -#include -#include +#include +#include +#include +#include +#include #include #include -#include +#include #include +#include +#include #include +#include #include #include #include -#include +#include #include -#include +#include #include #include -#include +#include +#include #include From 0b38539633dbe1c9b88741c9b96a92135c42a369 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 15 Feb 2024 18:02:34 +0200 Subject: [PATCH 137/199] serial: 8250_bcm7271: Replace custom unit definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace custom unit definitions that are available via units.h. Signed-off-by: Andy Shevchenko Reviewed-by: Ilpo Järvinen Reviewed-by: Florian Fainelli Link: https://lore.kernel.org/r/20240215160234.653305-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_bcm7271.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/tty/serial/8250/8250_bcm7271.c b/drivers/tty/serial/8250/8250_bcm7271.c index 504c4c020857..1532fa2e8ec4 100644 --- a/drivers/tty/serial/8250/8250_bcm7271.c +++ b/drivers/tty/serial/8250/8250_bcm7271.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "8250.h" @@ -187,21 +188,19 @@ #define TX_BUF_SIZE 4096 #define RX_BUF_SIZE 4096 #define RX_BUFS_COUNT 2 -#define KHZ 1000 -#define MHZ(x) ((x) * KHZ * KHZ) static const u32 brcmstb_rate_table[] = { - MHZ(81), - MHZ(108), - MHZ(64), /* Actually 64285715 for some chips */ - MHZ(48), + 81 * HZ_PER_MHZ, + 108 * HZ_PER_MHZ, + 64 * HZ_PER_MHZ, /* Actually 64285715 for some chips */ + 48 * HZ_PER_MHZ, }; static const u32 brcmstb_rate_table_7278[] = { - MHZ(81), - MHZ(108), + 81 * HZ_PER_MHZ, + 108 * HZ_PER_MHZ, 0, - MHZ(48), + 48 * HZ_PER_MHZ, }; struct brcmuart_priv { From 1364ea8a561356760c86a38c76ddb553bb17c646 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 15 Feb 2024 23:29:44 +0000 Subject: [PATCH 138/199] serial: lpc32xx_hs: remove redundant check and assignment of hsu_rate Variable hsu_rate is being checked for an upper limit and is assigned a value that is never read. The if statement and assignment are redundant and can be removed. Cleans up clang scan build warning: drivers/tty/serial/lpc32xx_hs.c:237:3: warning: Value stored to 'hsu_rate' is never read [deadcode.DeadStores] Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20240215232944.2075789-1-colin.i.king@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/lpc32xx_hs.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c index ec20329f0603..269efc5e2d51 100644 --- a/drivers/tty/serial/lpc32xx_hs.c +++ b/drivers/tty/serial/lpc32xx_hs.c @@ -233,8 +233,6 @@ static unsigned int __serial_get_clock_div(unsigned long uartclk, hsu_rate++; } - if (hsu_rate > 0xFF) - hsu_rate = 0xFF; return goodrate; } From 5fcd6e71e8c5ac9091933dc44997f9ed68d9384a Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 16 Feb 2024 12:17:32 +0000 Subject: [PATCH 139/199] tty: jsm: Remove redundant assignment to variable linestatus The variable linestate being assigned a value that is never read, the following continue statement jumps to the end of the while-loop and then it is re-assigned a new value. The assignment is redundant and can be removed. Cleans up clang scan build warning: drivers/tty/serial/jsm/jsm_cls.c:398:4: warning: Value stored to 'linestatus' is never read [deadcode.DeadStores] Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20240216121732.2106445-1-colin.i.king@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/jsm/jsm_cls.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/tty/serial/jsm/jsm_cls.c b/drivers/tty/serial/jsm/jsm_cls.c index 1eda48964c0b..ddbd42c09637 100644 --- a/drivers/tty/serial/jsm/jsm_cls.c +++ b/drivers/tty/serial/jsm/jsm_cls.c @@ -395,7 +395,6 @@ static void cls_copy_data_from_uart_to_queue(struct jsm_channel *ch) * which in this case is the break signal. */ if (linestatus & error_mask) { - linestatus = 0; readb(&ch->ch_cls_uart->txrx); continue; } From cd0eb354d441488feed6685adbeb1acd45db1b8d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 15 Feb 2024 16:50:08 +0200 Subject: [PATCH 140/199] serial: 8250_of: Drop quirk fot NPCM from 8250_port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are not supposed to spread quirks in 8250_port module especially when we have a separate driver for the hardware in question. Move quirk from generic module to the driver that uses it. Signed-off-by: Andy Shevchenko Reviewed-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20240215145029.581389-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_of.c | 44 +++++++++++++++++++++++++++-- drivers/tty/serial/8250/8250_port.c | 24 ---------------- 2 files changed, 42 insertions(+), 26 deletions(-) diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c index 34f17a9785e7..9dcc17e33269 100644 --- a/drivers/tty/serial/8250/8250_of.c +++ b/drivers/tty/serial/8250/8250_of.c @@ -4,7 +4,10 @@ * * Copyright (C) 2006 Arnd Bergmann , IBM Corp. */ + +#include #include +#include #include #include #include @@ -25,6 +28,36 @@ struct of_serial_info { int line; }; +/* Nuvoton NPCM timeout register */ +#define UART_NPCM_TOR 7 +#define UART_NPCM_TOIE BIT(7) /* Timeout Interrupt Enable */ + +static int npcm_startup(struct uart_port *port) +{ + /* + * Nuvoton calls the scratch register 'UART_TOR' (timeout + * register). Enable it, and set TIOC (timeout interrupt + * comparator) to be 0x20 for correct operation. + */ + serial_port_out(port, UART_NPCM_TOR, UART_NPCM_TOIE | 0x20); + + return serial8250_do_startup(port); +} + +/* Nuvoton NPCM UARTs have a custom divisor calculation */ +static unsigned int npcm_get_divisor(struct uart_port *port, unsigned int baud, + unsigned int *frac) +{ + return DIV_ROUND_CLOSEST(port->uartclk, 16 * baud + 2) - 2; +} + +static int npcm_setup(struct uart_port *port) +{ + port->get_divisor = npcm_get_divisor; + port->startup = npcm_startup; + return 0; +} + /* * Fill a struct uart_port for a given device node */ @@ -164,10 +197,17 @@ static int of_platform_serial_setup(struct platform_device *ofdev, switch (type) { case PORT_RT2880: ret = rt288x_setup(port); - if (ret) - goto err_pmruntime; + break; + case PORT_NPCM: + ret = npcm_setup(port); + break; + default: + /* Nothing to do */ + ret = 0; break; } + if (ret) + goto err_pmruntime; if (IS_REACHABLE(CONFIG_SERIAL_8250_FSL) && (of_device_is_compatible(np, "fsl,ns16550") || diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index c37905ea3cae..d9e886f2424e 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -38,10 +38,6 @@ #include "8250.h" -/* Nuvoton NPCM timeout register */ -#define UART_NPCM_TOR 7 -#define UART_NPCM_TOIE BIT(7) /* Timeout Interrupt Enable */ - /* * Debugging. */ @@ -2235,15 +2231,6 @@ int serial8250_do_startup(struct uart_port *port) UART_DA830_PWREMU_MGMT_FREE); } - if (port->type == PORT_NPCM) { - /* - * Nuvoton calls the scratch register 'UART_TOR' (timeout - * register). Enable it, and set TIOC (timeout interrupt - * comparator) to be 0x20 for correct operation. - */ - serial_port_out(port, UART_NPCM_TOR, UART_NPCM_TOIE | 0x20); - } - #ifdef CONFIG_SERIAL_8250_RSA /* * If this is an RSA port, see if we can kick it up to the @@ -2545,15 +2532,6 @@ static void serial8250_shutdown(struct uart_port *port) serial8250_do_shutdown(port); } -/* Nuvoton NPCM UARTs have a custom divisor calculation */ -static unsigned int npcm_get_divisor(struct uart_8250_port *up, - unsigned int baud) -{ - struct uart_port *port = &up->port; - - return DIV_ROUND_CLOSEST(port->uartclk, 16 * baud + 2) - 2; -} - static unsigned int serial8250_do_get_divisor(struct uart_port *port, unsigned int baud, unsigned int *frac) @@ -2598,8 +2576,6 @@ static unsigned int serial8250_do_get_divisor(struct uart_port *port, quot = 0x8001; else if (magic_multiplier && baud >= port->uartclk / 12) quot = 0x8002; - else if (up->port.type == PORT_NPCM) - quot = npcm_get_divisor(up, baud); else quot = uart_get_divisor(port, baud); From 548fcf037b3f8592e9fe41469110453a777416d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Thu, 15 Feb 2024 13:15:38 +0200 Subject: [PATCH 141/199] tty: Don't include tty_buffer.h in tty.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's no need to include linux/tty_buffer.h in linux/tty.h. Move the include into tty_buffer.c that is actually using it. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20240215111538.1920-1-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_buffer.c | 1 + include/linux/tty.h | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index f8883afbeeba..79f0ff94ce00 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include diff --git a/include/linux/tty.h b/include/linux/tty.h index 8c76fd97d4ad..2b2e6f0a54d6 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include From d4c22ec3fc7c6692273945925cd4bbf8f7888a54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 18 Feb 2024 09:53:54 +0100 Subject: [PATCH 142/199] tty: amiserial: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/f2ad92c97086c42dab23cdb165d9f978bbf3d3b5.1708246007.git.u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/amiserial.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 7716ce0d35bc..e27360652d9b 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1566,7 +1566,7 @@ fail_tty_driver_kref_put: return error; } -static int __exit amiga_serial_remove(struct platform_device *pdev) +static void __exit amiga_serial_remove(struct platform_device *pdev) { struct serial_state *state = platform_get_drvdata(pdev); @@ -1576,12 +1576,10 @@ static int __exit amiga_serial_remove(struct platform_device *pdev) free_irq(IRQ_AMIGA_TBE, state); free_irq(IRQ_AMIGA_RBF, state); - - return 0; } static struct platform_driver amiga_serial_driver = { - .remove = __exit_p(amiga_serial_remove), + .remove_new = __exit_p(amiga_serial_remove), .driver = { .name = "amiga-serial", }, From 138ab8af698d0139c6d73694128605c384e6c2c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 18 Feb 2024 09:53:55 +0100 Subject: [PATCH 143/199] tty: goldfish: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/60d0657daf8f4f9e2e3e282941ba542f08dc7f96.1708246007.git.u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/goldfish.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c index d27979eabfdf..34421ec06a69 100644 --- a/drivers/tty/goldfish.c +++ b/drivers/tty/goldfish.c @@ -408,7 +408,7 @@ err_unmap: return ret; } -static int goldfish_tty_remove(struct platform_device *pdev) +static void goldfish_tty_remove(struct platform_device *pdev) { struct goldfish_tty *qtty = platform_get_drvdata(pdev); @@ -424,7 +424,6 @@ static int goldfish_tty_remove(struct platform_device *pdev) if (goldfish_tty_current_line_count == 0) goldfish_tty_delete_driver(); mutex_unlock(&goldfish_tty_lock); - return 0; } #ifdef CONFIG_GOLDFISH_TTY_EARLY_CONSOLE @@ -462,7 +461,7 @@ MODULE_DEVICE_TABLE(of, goldfish_tty_of_match); static struct platform_driver goldfish_tty_platform_driver = { .probe = goldfish_tty_probe, - .remove = goldfish_tty_remove, + .remove_new = goldfish_tty_remove, .driver = { .name = "goldfish_tty", .of_match_table = goldfish_tty_of_match, From 1643281347f80116a500e6a17726351a7265a55c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 18 Feb 2024 09:53:56 +0100 Subject: [PATCH 144/199] serial: pmac_zilog: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Note that pmz_detach() is only called once pmz_attach() was successfully called. In that case platform_set_drvdata() was called and so platform_get_drvdata() won't return NULL. This allows to drop the respective check and so get rid of the only error path in pmz_detach(). After that the driver can be trivially converted from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/90b9a65ad8800b4d047aa5219959008a01588a94.1708246007.git.u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pmac_zilog.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index c8bf08c19c64..05b5b3b456ac 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -1717,18 +1717,13 @@ static int __init pmz_attach(struct platform_device *pdev) return uart_add_one_port(&pmz_uart_reg, &uap->port); } -static int __exit pmz_detach(struct platform_device *pdev) +static void __exit pmz_detach(struct platform_device *pdev) { struct uart_pmac_port *uap = platform_get_drvdata(pdev); - if (!uap) - return -ENODEV; - uart_remove_one_port(&pmz_uart_reg, &uap->port); uap->port.dev = NULL; - - return 0; } #endif /* !CONFIG_PPC_PMAC */ @@ -1797,7 +1792,7 @@ static struct macio_driver pmz_driver = { #else static struct platform_driver pmz_driver = { - .remove = __exit_p(pmz_detach), + .remove_new = __exit_p(pmz_detach), .driver = { .name = "scc", }, From 63724bbfb1e6b5e202f9393da4b25d4e7a46f5ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 19 Feb 2024 21:28:35 +0100 Subject: [PATCH 145/199] w1: mxc_w1: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/d805f3ccc5bc59584c2575b7b33a56a33f6812c7.1708340114.git.u.kleine-koenig@pengutronix.de Signed-off-by: Krzysztof Kozlowski --- drivers/w1/masters/mxc_w1.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/w1/masters/mxc_w1.c b/drivers/w1/masters/mxc_w1.c index 090cbbf9e1e2..ba1d0866d1c4 100644 --- a/drivers/w1/masters/mxc_w1.c +++ b/drivers/w1/masters/mxc_w1.c @@ -151,15 +151,13 @@ out_disable_clk: /* * disassociate the w1 device from the driver */ -static int mxc_w1_remove(struct platform_device *pdev) +static void mxc_w1_remove(struct platform_device *pdev) { struct mxc_w1_device *mdev = platform_get_drvdata(pdev); w1_remove_master_device(&mdev->bus_master); clk_disable_unprepare(mdev->clk); - - return 0; } static const struct of_device_id mxc_w1_dt_ids[] = { @@ -174,7 +172,7 @@ static struct platform_driver mxc_w1_driver = { .of_match_table = mxc_w1_dt_ids, }, .probe = mxc_w1_probe, - .remove = mxc_w1_remove, + .remove_new = mxc_w1_remove, }; module_platform_driver(mxc_w1_driver); From aa68465cf3d39996b291fb2080946c2e4d7cc100 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 19 Feb 2024 11:59:28 +0100 Subject: [PATCH 146/199] w1: omap_hdq: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/f3a7eaee59020bf879249304eaaf9839c7e17222.1708340114.git.u.kleine-koenig@pengutronix.de Signed-off-by: Krzysztof Kozlowski --- drivers/w1/masters/omap_hdq.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c index 6a39b71eb718..d1cb5190445a 100644 --- a/drivers/w1/masters/omap_hdq.c +++ b/drivers/w1/masters/omap_hdq.c @@ -647,7 +647,7 @@ err_w1: return ret; } -static int omap_hdq_remove(struct platform_device *pdev) +static void omap_hdq_remove(struct platform_device *pdev) { int active; @@ -661,8 +661,6 @@ static int omap_hdq_remove(struct platform_device *pdev) if (active >= 0) pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); - - return 0; } static const struct of_device_id omap_hdq_dt_ids[] = { @@ -674,7 +672,7 @@ MODULE_DEVICE_TABLE(of, omap_hdq_dt_ids); static struct platform_driver omap_hdq_driver = { .probe = omap_hdq_probe, - .remove = omap_hdq_remove, + .remove_new = omap_hdq_remove, .driver = { .name = "omap_hdq", .of_match_table = omap_hdq_dt_ids, From d7516044f167b219dae13010e6ff790e3fc96ef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 19 Feb 2024 21:28:36 +0100 Subject: [PATCH 147/199] w1: sgi_w1: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/68632fffa01f69eeaddfc0ad9de8f067b164e4fb.1708340114.git.u.kleine-koenig@pengutronix.de Signed-off-by: Krzysztof Kozlowski --- drivers/w1/masters/sgi_w1.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/w1/masters/sgi_w1.c b/drivers/w1/masters/sgi_w1.c index d7fbc3c146e1..7bb7876aa70e 100644 --- a/drivers/w1/masters/sgi_w1.c +++ b/drivers/w1/masters/sgi_w1.c @@ -105,13 +105,11 @@ static int sgi_w1_probe(struct platform_device *pdev) /* * disassociate the w1 device from the driver */ -static int sgi_w1_remove(struct platform_device *pdev) +static void sgi_w1_remove(struct platform_device *pdev) { struct sgi_w1_device *sdev = platform_get_drvdata(pdev); w1_remove_master_device(&sdev->bus_master); - - return 0; } static struct platform_driver sgi_w1_driver = { @@ -119,7 +117,7 @@ static struct platform_driver sgi_w1_driver = { .name = "sgi_w1", }, .probe = sgi_w1_probe, - .remove = sgi_w1_remove, + .remove_new = sgi_w1_remove, }; module_platform_driver(sgi_w1_driver); From d97d263132a69a0bda54efce3df04e55fa6341f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 19 Feb 2024 11:59:30 +0100 Subject: [PATCH 148/199] w1: w1-gpio: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/bd69ccde7395cf4bf63765e29c1ce83834d3669b.1708340114.git.u.kleine-koenig@pengutronix.de Signed-off-by: Krzysztof Kozlowski --- drivers/w1/masters/w1-gpio.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c index 05c67038ed20..34128e6bbbfa 100644 --- a/drivers/w1/masters/w1-gpio.c +++ b/drivers/w1/masters/w1-gpio.c @@ -141,7 +141,7 @@ static int w1_gpio_probe(struct platform_device *pdev) return 0; } -static int w1_gpio_remove(struct platform_device *pdev) +static void w1_gpio_remove(struct platform_device *pdev) { struct w1_bus_master *master = platform_get_drvdata(pdev); struct w1_gpio_ddata *ddata = master->data; @@ -150,8 +150,6 @@ static int w1_gpio_remove(struct platform_device *pdev) gpiod_set_value(ddata->pullup_gpiod, 0); w1_remove_master_device(master); - - return 0; } static struct platform_driver w1_gpio_driver = { @@ -160,7 +158,7 @@ static struct platform_driver w1_gpio_driver = { .of_match_table = of_match_ptr(w1_gpio_dt_ids), }, .probe = w1_gpio_probe, - .remove = w1_gpio_remove, + .remove_new = w1_gpio_remove, }; module_platform_driver(w1_gpio_driver); From 73b5a5c00be39e23b194bad10e1ea8bb73eee176 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 19 Feb 2024 17:04:57 +0200 Subject: [PATCH 149/199] serial: 8250_exar: Don't remove GPIO device on suspend It seems a copy&paste mistake that suspend callback removes the GPIO device. There is no counterpart of this action, means once suspended there is no more GPIO device available untile full unbind-bind cycle is performed. Remove suspicious GPIO device removal in suspend. Fixes: d0aeaa83f0b0 ("serial: exar: split out the exar code from 8250_pci") Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240219150627.2101198-2-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_exar.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index 23366f868ae3..dab94835b6f5 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -753,6 +753,7 @@ static void exar_pci_remove(struct pci_dev *pcidev) for (i = 0; i < priv->nr; i++) serial8250_unregister_port(priv->line[i]); + /* Ensure that every init quirk is properly torn down */ if (priv->board->exit) priv->board->exit(pcidev); } @@ -767,10 +768,6 @@ static int __maybe_unused exar_suspend(struct device *dev) if (priv->line[i] >= 0) serial8250_suspend_port(priv->line[i]); - /* Ensure that every init quirk is properly torn down */ - if (priv->board->exit) - priv->board->exit(pcidev); - return 0; } From 7a345dc19a7c01a04a2d7bcd79238389b0838b78 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 19 Feb 2024 17:04:58 +0200 Subject: [PATCH 150/199] serial: 8250_exar: Use dev_get_drvdata() directly in PM callbacks PM callbacks take struct device pointer as a parameter, use dev_get_drvdata() to retrieve it instead of unneeded double loop of referencing via pci_get_drvdata(to_pci_dev(dev)). Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240219150627.2101198-3-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_exar.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index dab94835b6f5..5687b21b328d 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -760,8 +760,7 @@ static void exar_pci_remove(struct pci_dev *pcidev) static int __maybe_unused exar_suspend(struct device *dev) { - struct pci_dev *pcidev = to_pci_dev(dev); - struct exar8250 *priv = pci_get_drvdata(pcidev); + struct exar8250 *priv = dev_get_drvdata(dev); unsigned int i; for (i = 0; i < priv->nr; i++) From 5bc430afeba5d5101765c1f1a4437a90218b00b9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 19 Feb 2024 17:04:59 +0200 Subject: [PATCH 151/199] serial: 8250_exar: Clear interrupts before registering handler While now there is no issue if IRQ is fired before we clearing the interrupts as the handler does the same, but strictly speaking it might be problematic if IRQ handler wants to do something more. Move clearing interrupt code to be called before registering the IRQ handler. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240219150627.2101198-4-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_exar.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index 5687b21b328d..9ab30d974e29 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -713,14 +713,14 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) uart.port.irq = pci_irq_vector(pcidev, 0); uart.port.dev = &pcidev->dev; + /* Clear interrupts */ + exar_misc_clear(priv); + rc = devm_request_irq(&pcidev->dev, uart.port.irq, exar_misc_handler, IRQF_SHARED, "exar_uart", priv); if (rc) return rc; - /* Clear interrupts */ - exar_misc_clear(priv); - for (i = 0; i < nr_ports && i < maxnr; i++) { rc = board->setup(priv, pcidev, &uart, i); if (rc) { From 73f76db8404b26d2257915f4cde25c6e00afed14 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 19 Feb 2024 17:05:00 +0200 Subject: [PATCH 152/199] serial: 8250_exar: Use generic function to set firmware node Use generic function to set firmware node instead of ACPI specific one. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240219150627.2101198-5-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_exar.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index 9ab30d974e29..cf3cd569c395 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -6,12 +6,12 @@ * * Copyright (C) 2017 Sudip Mukherjee, All Rights Reserved. */ -#include #include #include #include #include #include +#include #include #include #include @@ -375,7 +375,7 @@ static struct platform_device *__xr17v35x_register_gpio(struct pci_dev *pcidev, return NULL; pdev->dev.parent = &pcidev->dev; - ACPI_COMPANION_SET(&pdev->dev, ACPI_COMPANION(&pcidev->dev)); + device_set_node(&pdev->dev, dev_fwnode(&pcidev->dev)); if (device_add_software_node(&pdev->dev, node) < 0 || platform_device_add(pdev) < 0) { From 82f9cefadac4e7e360bb1b4266c2e2d35a862425 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 19 Feb 2024 17:05:01 +0200 Subject: [PATCH 153/199] serial: 8250_exar: switch to DEFINE_SIMPLE_DEV_PM_OPS() SIMPLE_DEV_PM_OPS() is deprecated, replace it with DEFINE_SIMPLE_DEV_PM_OPS() and use pm_sleep_ptr() for setting the driver's PM routines. We can now remove the __maybe_unused qualifier in the suspend and resume functions. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240219150627.2101198-6-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_exar.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index cf3cd569c395..cf00335d953f 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -758,7 +759,7 @@ static void exar_pci_remove(struct pci_dev *pcidev) priv->board->exit(pcidev); } -static int __maybe_unused exar_suspend(struct device *dev) +static int exar_suspend(struct device *dev) { struct exar8250 *priv = dev_get_drvdata(dev); unsigned int i; @@ -770,7 +771,7 @@ static int __maybe_unused exar_suspend(struct device *dev) return 0; } -static int __maybe_unused exar_resume(struct device *dev) +static int exar_resume(struct device *dev) { struct exar8250 *priv = dev_get_drvdata(dev); unsigned int i; @@ -784,7 +785,7 @@ static int __maybe_unused exar_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(exar_pci_pm, exar_suspend, exar_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(exar_pci_pm, exar_suspend, exar_resume); static const struct exar8250_board pbn_fastcom335_2 = { .num_ports = 2, @@ -934,7 +935,7 @@ static struct pci_driver exar_pci_driver = { .probe = exar_pci_probe, .remove = exar_pci_remove, .driver = { - .pm = &exar_pci_pm, + .pm = pm_sleep_ptr(&exar_pci_pm), }, .id_table = exar_pci_tbl, }; From d813d90085aefacc3500db94d82c60e0702965fa Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 19 Feb 2024 17:05:02 +0200 Subject: [PATCH 154/199] serial: 8250_exar: Use 8250 PCI library to map and assign resources 8250 PCI library provides a common code to map and assign resources. Use it in order to deduplicate existing code and support IO port variants. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240219150627.2101198-7-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_exar.c | 11 ++++++----- drivers/tty/serial/8250/Kconfig | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index cf00335d953f..afe577860ac5 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -24,6 +24,7 @@ #include #include "8250.h" +#include "8250_pcilib.h" #define PCI_DEVICE_ID_ACCESSIO_COM_2S 0x1052 #define PCI_DEVICE_ID_ACCESSIO_COM_4S 0x105d @@ -230,13 +231,12 @@ static int default_setup(struct exar8250 *priv, struct pci_dev *pcidev, struct uart_8250_port *port) { const struct exar8250_board *board = priv->board; - unsigned int bar = 0; unsigned char status; + int err; - port->port.iotype = UPIO_MEM; - port->port.mapbase = pci_resource_start(pcidev, bar) + offset; - port->port.membase = priv->virt + offset; - port->port.regshift = board->reg_shift; + err = serial8250_pci_setup_port(pcidev, port, 0, offset, board->reg_shift); + if (err) + return err; /* * XR17V35x UARTs have an extra divisor register, DLD that gets enabled @@ -941,6 +941,7 @@ static struct pci_driver exar_pci_driver = { }; module_pci_driver(exar_pci_driver); +MODULE_IMPORT_NS(SERIAL_8250_PCI); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Exar Serial Driver"); MODULE_AUTHOR("Sudip Mukherjee "); diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index 8b9a2c4902e2..47ff50763c04 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -149,6 +149,7 @@ config SERIAL_8250_PCI config SERIAL_8250_EXAR tristate "8250/16550 Exar/Commtech PCI/PCIe device support" depends on SERIAL_8250 && PCI + select SERIAL_8250_PCILIB default SERIAL_8250 help This builds support for XR17C1xx, XR17V3xx and some Commtech From 66c736daae0d1dd5dda53a1982398f383d82c42d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 19 Feb 2024 17:05:03 +0200 Subject: [PATCH 155/199] serial: 8250_exar: Don't use "proxy" headers Update header inclusions to follow IWYU (Include What You Use) principle. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240219150627.2101198-8-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_exar.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index afe577860ac5..0440df7de1ed 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -6,20 +6,24 @@ * * Copyright (C) 2017 Sudip Mukherjee, All Rights Reserved. */ +#include +#include +#include #include +#include #include -#include +#include #include #include #include #include #include +#include +#include + +#include #include #include -#include -#include -#include -#include #include From d676822a714af27e346407a4054cb2846d1ab0e5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 19 Feb 2024 18:28:34 +0200 Subject: [PATCH 156/199] serial: 8250_pci1xxxx: Drop quirk from 8250_port We are not supposed to spread quirks in 8250_port module especially when we have a separate driver for the hardware in question. Move quirk from generic module to the driver that uses it. While at it, move IO to ->set_divisor() callback as it has to be from day 1. ->get_divisor() is not supposed to perform any IO as UART port: - might not be powered on - is not locked by a spin lock Fixes: 1ed67ecd1349 ("8250: microchip: Add 4 Mbps support in PCI1XXXX UART") Signed-off-by: Andy Shevchenko Acked-by: Rengarajan S Link: https://lore.kernel.org/r/20240219162917.2159736-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci1xxxx.c | 25 ++++++++++++++++++------- drivers/tty/serial/8250/8250_port.c | 7 ------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/drivers/tty/serial/8250/8250_pci1xxxx.c b/drivers/tty/serial/8250/8250_pci1xxxx.c index 55eada1dba56..2fbb5851f788 100644 --- a/drivers/tty/serial/8250/8250_pci1xxxx.c +++ b/drivers/tty/serial/8250/8250_pci1xxxx.c @@ -94,7 +94,6 @@ #define UART_BIT_SAMPLE_CNT_16 16 #define BAUD_CLOCK_DIV_INT_MSK GENMASK(31, 8) #define ADCL_CFG_RTS_DELAY_MASK GENMASK(11, 8) -#define UART_CLOCK_DEFAULT (62500 * HZ_PER_KHZ) #define UART_WAKE_REG 0x8C #define UART_WAKE_MASK_REG 0x90 @@ -227,13 +226,10 @@ static unsigned int pci1xxxx_get_divisor(struct uart_port *port, unsigned int uart_sample_cnt; unsigned int quot; - if (baud >= UART_BAUD_4MBPS) { + if (baud >= UART_BAUD_4MBPS) uart_sample_cnt = UART_BIT_SAMPLE_CNT_8; - writel(UART_BIT_DIVISOR_8, (port->membase + FRAC_DIV_CFG_REG)); - } else { + else uart_sample_cnt = UART_BIT_SAMPLE_CNT_16; - writel(UART_BIT_DIVISOR_16, (port->membase + FRAC_DIV_CFG_REG)); - } /* * Calculate baud rate sampling period in nanoseconds. @@ -249,6 +245,11 @@ static unsigned int pci1xxxx_get_divisor(struct uart_port *port, static void pci1xxxx_set_divisor(struct uart_port *port, unsigned int baud, unsigned int quot, unsigned int frac) { + if (baud >= UART_BAUD_4MBPS) + writel(UART_BIT_DIVISOR_8, port->membase + FRAC_DIV_CFG_REG); + else + writel(UART_BIT_DIVISOR_16, port->membase + FRAC_DIV_CFG_REG); + writel(FIELD_PREP(BAUD_CLOCK_DIV_INT_MSK, quot) | frac, port->membase + UART_BAUD_CLK_DIVISOR_REG); } @@ -619,6 +620,17 @@ static int pci1xxxx_setup(struct pci_dev *pdev, port->port.flags |= UPF_FIXED_TYPE | UPF_SKIP_TEST; port->port.type = PORT_MCHP16550A; + /* + * 8250 core considers prescaller value to be always 16. + * The MCHP ports support downscaled mode and hence the + * functional UART clock can be lower, i.e. 62.5MHz, than + * software expects in order to support higher baud rates. + * Assign here 64MHz to support 4Mbps. + * + * The value itself is not really used anywhere except baud + * rate calculations, so we can mangle it as we wish. + */ + port->port.uartclk = 64 * HZ_PER_MHZ; port->port.set_termios = serial8250_do_set_termios; port->port.get_divisor = pci1xxxx_get_divisor; port->port.set_divisor = pci1xxxx_set_divisor; @@ -732,7 +744,6 @@ static int pci1xxxx_serial_probe(struct pci_dev *pdev, memset(&uart, 0, sizeof(uart)); uart.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT; - uart.port.uartclk = UART_CLOCK_DEFAULT; uart.port.dev = dev; if (num_vectors == max_vec_reqd) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index d9e886f2424e..4164f8650476 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -2657,7 +2657,6 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port, struct ktermios *termios, const struct ktermios *old) { - struct uart_8250_port *up = up_to_u8250p(port); unsigned int tolerance = port->uartclk / 100; unsigned int min; unsigned int max; @@ -2675,12 +2674,6 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port, max = (port->uartclk + tolerance) / 16; } - /* - * Microchip PCI1XXXX UART supports maximum baud rate up to 4 Mbps - */ - if (up->port.type == PORT_MCHP16550A) - max = 4000000; - /* * Ask the core to calculate the divisor for us. * Allow 1% tolerance at the upper limit so uart clks marginally From f75a010dcba0270c403cb680a0c662293dd98a60 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 19 Feb 2024 17:40:02 +0100 Subject: [PATCH 157/199] drivers/tty/serial: Remove unused function early_mcf_setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Compiling a kernel for the ColdFire causes a compiler warning: drivers/tty/serial/mcf.c:473:12: warning: no previous prototype for ‘early_mcf_setup’ [-Wmissing-prototypes] 473 | int __init early_mcf_setup(struct mcf_platform_uart *platp) | ^~~~~~~~~~~~~~~ This function seems to be completely unused, so let's remove it to silence the warning. Signed-off-by: Thomas Huth Reviewed-by: Jiri Slaby Acked-by: Greg Ungerer Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20240219164002.520342-1-thuth@redhat.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/mcf.c | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c index 8690a45239e0..b0604d6da025 100644 --- a/drivers/tty/serial/mcf.c +++ b/drivers/tty/serial/mcf.c @@ -470,33 +470,6 @@ static struct mcf_uart mcf_ports[4]; #if defined(CONFIG_SERIAL_MCF_CONSOLE) /****************************************************************************/ -int __init early_mcf_setup(struct mcf_platform_uart *platp) -{ - struct uart_port *port; - int i; - - for (i = 0; ((i < MCF_MAXPORTS) && (platp[i].mapbase)); i++) { - port = &mcf_ports[i].port; - - port->line = i; - port->type = PORT_MCF; - port->mapbase = platp[i].mapbase; - port->membase = (platp[i].membase) ? platp[i].membase : - (unsigned char __iomem *) port->mapbase; - port->iotype = SERIAL_IO_MEM; - port->irq = platp[i].irq; - port->uartclk = MCF_BUSCLK; - port->flags = UPF_BOOT_AUTOCONF; - port->rs485_config = mcf_config_rs485; - port->rs485_supported = mcf_rs485_supported; - port->ops = &mcf_uart_ops; - } - - return 0; -} - -/****************************************************************************/ - static void mcf_console_putc(struct console *co, const char c) { struct uart_port *port = &(mcf_ports + co->index)->port; From b8a4ed3405d5f3f92a211ccc2579e54345bc3aeb Mon Sep 17 00:00:00 2001 From: Tamseel Shams Date: Tue, 20 Feb 2024 15:42:27 +0530 Subject: [PATCH 158/199] serial: samsung: honor fifosize from dts at first Currently for platforms which passes UART fifosize from DT gets override by local driver structure "s3c24xx_serial_drv_data", which is not intended. Change the code to honor fifosize from device tree at first. Signed-off-by: Tamseel Shams Link: https://lore.kernel.org/r/20240220101227.80741-1-m.shams@samsung.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 23cabdab44ff..a2d07e05c502 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -1951,7 +1951,7 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct s3c24xx_uart_port *ourport; int index = probe_index; - int ret, prop = 0; + int ret, prop = 0, fifosize_prop = 1; if (np) { ret = of_alias_get_id(np, "serial"); @@ -1991,8 +1991,8 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) ourport->port.iotype = ourport->info->iotype; if (np) { - of_property_read_u32(np, - "samsung,uart-fifosize", &ourport->port.fifosize); + fifosize_prop = of_property_read_u32(np, "samsung,uart-fifosize", + &ourport->port.fifosize); if (of_property_read_u32(np, "reg-io-width", &prop) == 0) { switch (prop) { @@ -2010,10 +2010,13 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) } } - if (ourport->drv_data->fifosize[index]) - ourport->port.fifosize = ourport->drv_data->fifosize[index]; - else if (ourport->info->fifosize) - ourport->port.fifosize = ourport->info->fifosize; + if (fifosize_prop) { + if (ourport->drv_data->fifosize[index]) + ourport->port.fifosize = ourport->drv_data->fifosize[index]; + else if (ourport->info->fifosize) + ourport->port.fifosize = ourport->info->fifosize; + } + ourport->port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_SAMSUNG_CONSOLE); /* From 4e489a6e93e85726a41f85d1aaaab6f603ec2d33 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 20 Feb 2024 12:34:10 +0100 Subject: [PATCH 159/199] serial: st-asc: don't get/put GPIOs in atomic context Since commit 1f2bcb8c8ccd ("gpio: protect the descriptor label with SRCU") gpiod_set_consumer_name() calls synchronize_srcu() which led to a "sleeping in atomic context" smatch warning. This function (along with gpiod_get/put() and all other GPIO APIs apart from gpiod_get/set_value() and gpiod_direction_input/output()) should have never been called with a spinlock taken. We're only fixing this now as GPIOLIB has been rebuilt to use SRCU for access serialization which uncovered this problem. Move the calls to gpiod_get/put() outside the spinlock critical section. Reported-by: Dan Carpenter Closes: https://lore.kernel.org/linux-gpio/deee1438-efc1-47c4-8d80-0ab2cf01d60a@moroto.mountain/ Signed-off-by: Bartosz Golaszewski Reviewed-by: Patrice Chotard Link: https://lore.kernel.org/r/20240220113410.16613-1-brgl@bgdev.pl Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/st-asc.c | 40 ++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c index bbb5595d7e24..a23e59551848 100644 --- a/drivers/tty/serial/st-asc.c +++ b/drivers/tty/serial/st-asc.c @@ -465,6 +465,7 @@ static void asc_set_termios(struct uart_port *port, struct ktermios *termios, const struct ktermios *old) { struct asc_port *ascport = to_asc_port(port); + bool manual_rts, toggle_rts = false; struct gpio_desc *gpiod; unsigned int baud; u32 ctrl_val; @@ -518,25 +519,13 @@ static void asc_set_termios(struct uart_port *port, struct ktermios *termios, /* If flow-control selected, stop handling RTS manually */ if (ascport->rts) { - devm_gpiod_put(port->dev, ascport->rts); - ascport->rts = NULL; - - pinctrl_select_state(ascport->pinctrl, - ascport->states[DEFAULT]); + toggle_rts = true; + manual_rts = false; } } else { /* If flow-control disabled, it's safe to handle RTS manually */ - if (!ascport->rts && ascport->states[NO_HW_FLOWCTRL]) { - pinctrl_select_state(ascport->pinctrl, - ascport->states[NO_HW_FLOWCTRL]); - - gpiod = devm_gpiod_get(port->dev, "rts", GPIOD_OUT_LOW); - if (!IS_ERR(gpiod)) { - gpiod_set_consumer_name(gpiod, - port->dev->of_node->name); - ascport->rts = gpiod; - } - } + if (!ascport->rts && ascport->states[NO_HW_FLOWCTRL]) + manual_rts = toggle_rts = true; } if ((baud < 19200) && !ascport->force_m1) { @@ -595,6 +584,25 @@ static void asc_set_termios(struct uart_port *port, struct ktermios *termios, asc_out(port, ASC_CTL, (ctrl_val | ASC_CTL_RUN)); uart_port_unlock_irqrestore(port, flags); + + if (toggle_rts) { + if (manual_rts) { + pinctrl_select_state(ascport->pinctrl, + ascport->states[NO_HW_FLOWCTRL]); + + gpiod = devm_gpiod_get(port->dev, "rts", GPIOD_OUT_LOW); + if (!IS_ERR(gpiod)) { + gpiod_set_consumer_name(gpiod, + port->dev->of_node->name); + ascport->rts = gpiod; + } + } else { + devm_gpiod_put(port->dev, ascport->rts); + ascport->rts = NULL; + pinctrl_select_state(ascport->pinctrl, + ascport->states[DEFAULT]); + } + } } static const char *asc_type(struct uart_port *port) From 675c00eb70534042be06c497605e35aa44aae19b Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Thu, 22 Feb 2024 17:50:56 +0300 Subject: [PATCH 160/199] serial: 8250: Use serial8250_do_set_termios for uartclk updating The serial8250_update_uartclk() body was created based on the several method calls copied from the serial8250_do_set_termios() function. Seeing aside with some other things the later method can update the baud rate based on the new reference clock let's just call it instead thus simplifying the code a bit. Suggested-by: Andy Shevchenko Link: https://lore.kernel.org/linux-serial/ZczD7KPbeRnY4CFc@black.fi.intel.com Signed-off-by: Serge Semin Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240222145058.28307-1-fancer.lancer@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 4164f8650476..336a0bd4d172 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -2690,12 +2690,8 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port, */ void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk) { - struct uart_8250_port *up = up_to_u8250p(port); struct tty_port *tport = &port->state->port; - unsigned int baud, quot, frac = 0; - struct ktermios *termios; struct tty_struct *tty; - unsigned long flags; tty = tty_port_tty_get(tport); if (!tty) { @@ -2716,21 +2712,7 @@ void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk) if (!tty_port_initialized(tport)) goto out_unlock; - termios = &tty->termios; - - baud = serial8250_get_baud_rate(port, termios, NULL); - quot = serial8250_get_divisor(port, baud, &frac); - - serial8250_rpm_get(up); - uart_port_lock_irqsave(port, &flags); - - uart_update_timeout(port, termios->c_cflag, baud); - - serial8250_set_divisor(port, baud, quot, frac); - serial_port_out(port, UART_LCR, up->lcr); - - uart_port_unlock_irqrestore(port, flags); - serial8250_rpm_put(up); + serial8250_do_set_termios(port, &tty->termios, NULL); out_unlock: mutex_unlock(&tport->mutex); From 28e4c31e53151aef19ce61464e396ccc035903b6 Mon Sep 17 00:00:00 2001 From: Raphael Gallais-Pou Date: Mon, 26 Feb 2024 16:21:35 +0100 Subject: [PATCH 161/199] dt-bindings: serial: convert st,asc to DT schema 'clocks' property is required regarding the device. Convert st,asc binding to DT schema format in order to add this property, and update example. Signed-off-by: Raphael Gallais-Pou Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240226152135.8671-1-rgallaispou@gmail.com Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/serial/st,asc.yaml | 55 +++++++++++++++++++ .../devicetree/bindings/serial/st-asc.txt | 18 ------ 2 files changed, 55 insertions(+), 18 deletions(-) create mode 100644 Documentation/devicetree/bindings/serial/st,asc.yaml delete mode 100644 Documentation/devicetree/bindings/serial/st-asc.txt diff --git a/Documentation/devicetree/bindings/serial/st,asc.yaml b/Documentation/devicetree/bindings/serial/st,asc.yaml new file mode 100644 index 000000000000..f2083388f36b --- /dev/null +++ b/Documentation/devicetree/bindings/serial/st,asc.yaml @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/serial/st,asc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: STMicroelectronics STi SoCs Serial Port + +maintainers: + - Patrice Chotard + +allOf: + - $ref: serial.yaml# + +properties: + compatible: + const: st,asc + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + st,hw-flow-ctrl: + description: When set, enable hardware flow control. + type: boolean + + st,force-m1: + description: When set, force asc to be in Mode-1. This is recommended for + high bit rates above 19.2K. + type: boolean + +required: + - compatible + - reg + - interrupts + - clocks + +unevaluatedProperties: false + +examples: + - | + #include + #include + serial@9830000 { + compatible = "st,asc"; + reg = <0x9830000 0x2c>; + interrupts = ; + clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>; + }; +... diff --git a/Documentation/devicetree/bindings/serial/st-asc.txt b/Documentation/devicetree/bindings/serial/st-asc.txt deleted file mode 100644 index a1b9b6f3490a..000000000000 --- a/Documentation/devicetree/bindings/serial/st-asc.txt +++ /dev/null @@ -1,18 +0,0 @@ -*st-asc(Serial Port) - -Required properties: -- compatible : Should be "st,asc". -- reg, reg-names, interrupts, interrupt-names : Standard way to define device - resources with names. look in - Documentation/devicetree/bindings/resource-names.txt - -Optional properties: -- st,hw-flow-ctrl bool flag to enable hardware flow control. -- st,force-m1 bool flat to force asc to be in Mode-1 recommended - for high bit rates (above 19.2K) -Example: -serial@fe440000{ - compatible = "st,asc"; - reg = <0xfe440000 0x2c>; - interrupts = <0 209 0>; -}; From 65295eba1915cf27c363f26727f6da43d144d03b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 22 Feb 2024 12:19:23 +0100 Subject: [PATCH 162/199] serial: 8250_dw: Emit an error message if getting the baudclk failed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of silently giving up, at least tell what the problem is. Signed-off-by: Uwe Kleine-König Reviewed-by: Ilpo Järvinen Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240222111922.2016122-2-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 2d1f350a4bea..94aa3dddb71e 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -597,7 +597,8 @@ static int dw8250_probe(struct platform_device *pdev) if (data->clk == NULL) data->clk = devm_clk_get_optional_enabled(dev, NULL); if (IS_ERR(data->clk)) - return PTR_ERR(data->clk); + return dev_err_probe(dev, PTR_ERR(data->clk), + "failed to get baudclk\n"); INIT_WORK(&data->clk_work, dw8250_clk_work_cb); data->clk_notifier.notifier_call = dw8250_clk_notifier_cb; From 2432f71c22d0543a86353ed0c505eda32d25af7c Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 1 Mar 2024 22:45:14 +0100 Subject: [PATCH 163/199] serial: amba-pl011: Use uart_prepare_sysrq_char(). The port lock is a spinlock_t which is becomes a sleeping lock on PREEMPT_RT. The driver splits the locking function into two parts: local_irq_save() and uart_port_lock() and this breaks PREEMPT_RT. Delay handling sysrq until port lock is dropped. Remove the special case in the console write routine an always use the complete locking function. Cc: Russell King Signed-off-by: Sebastian Andrzej Siewior Link: https://lore.kernel.org/r/20240301215246.891055-2-bigeasy@linutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index cf2c890a560f..2fa3fb30dc6c 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -348,10 +348,7 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap) flag = TTY_FRAME; } - uart_port_unlock(&uap->port); - sysrq = uart_handle_sysrq_char(&uap->port, ch & 255); - uart_port_lock(&uap->port); - + sysrq = uart_prepare_sysrq_char(&uap->port, ch & 255); if (!sysrq) uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag); } @@ -1017,7 +1014,7 @@ static void pl011_dma_rx_callback(void *data) ret = pl011_dma_rx_trigger_dma(uap); pl011_dma_rx_chars(uap, pending, lastbuf, false); - uart_port_unlock_irq(&uap->port); + uart_unlock_and_check_sysrq(&uap->port); /* * Do this check after we picked the DMA chars so we don't * get some IRQ immediately from RX. @@ -1540,11 +1537,10 @@ static void check_apply_cts_event_workaround(struct uart_amba_port *uap) static irqreturn_t pl011_int(int irq, void *dev_id) { struct uart_amba_port *uap = dev_id; - unsigned long flags; unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT; int handled = 0; - uart_port_lock_irqsave(&uap->port, &flags); + uart_port_lock(&uap->port); status = pl011_read(uap, REG_RIS) & uap->im; if (status) { do { @@ -1573,7 +1569,7 @@ static irqreturn_t pl011_int(int irq, void *dev_id) handled = 1; } - uart_port_unlock_irqrestore(&uap->port, flags); + uart_unlock_and_check_sysrq(&uap->port); return IRQ_RETVAL(handled); } @@ -2322,13 +2318,10 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) clk_enable(uap->clk); - local_irq_save(flags); - if (uap->port.sysrq) - locked = 0; - else if (oops_in_progress) - locked = uart_port_trylock(&uap->port); + if (oops_in_progress) + locked = uart_port_trylock_irqsave(&uap->port, &flags); else - uart_port_lock(&uap->port); + uart_port_lock_irqsave(&uap->port, &flags); /* * First save the CR then disable the interrupts @@ -2354,8 +2347,7 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) pl011_write(old_cr, uap, REG_CR); if (locked) - uart_port_unlock(&uap->port); - local_irq_restore(flags); + uart_port_unlock_irqrestore(&uap->port, flags); clk_disable(uap->clk); } From 244a758b3d0550b008c304bfd522209927f512b4 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 1 Mar 2024 22:45:15 +0100 Subject: [PATCH 164/199] serial: ar933x: Use uart_prepare_sysrq_char(). The port lock is a spinlock_t which is becomes a sleeping lock on PREEMPT_RT. The driver splits the locking function into two parts: local_irq_save() and uart_port_lock() and this breaks PREEMPT_RT. Delay handling sysrq until port lock is dropped. Remove the special case in the console write routine an always use the complete locking function. Signed-off-by: Sebastian Andrzej Siewior Link: https://lore.kernel.org/r/20240301215246.891055-3-bigeasy@linutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/ar933x_uart.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c index 8d09ace062e5..7790cbc57391 100644 --- a/drivers/tty/serial/ar933x_uart.c +++ b/drivers/tty/serial/ar933x_uart.c @@ -378,7 +378,7 @@ static void ar933x_uart_rx_chars(struct ar933x_uart_port *up) up->port.icount.rx++; ch = rdata & AR933X_UART_DATA_TX_RX_MASK; - if (uart_handle_sysrq_char(&up->port, ch)) + if (uart_prepare_sysrq_char(&up->port, ch)) continue; if ((up->port.ignore_status_mask & AR933X_DUMMY_STATUS_RD) == 0) @@ -468,7 +468,7 @@ static irqreturn_t ar933x_uart_interrupt(int irq, void *dev_id) ar933x_uart_tx_chars(up); } - uart_port_unlock(&up->port); + uart_unlock_and_check_sysrq(&up->port); return IRQ_HANDLED; } @@ -627,14 +627,10 @@ static void ar933x_uart_console_write(struct console *co, const char *s, unsigned int int_en; int locked = 1; - local_irq_save(flags); - - if (up->port.sysrq) - locked = 0; - else if (oops_in_progress) - locked = uart_port_trylock(&up->port); + if (oops_in_progress) + locked = uart_port_trylock_irqsave(&up->port, &flags); else - uart_port_lock(&up->port); + uart_port_lock_irqsave(&up->port, &flags); /* * First save the IER then disable the interrupts @@ -654,9 +650,7 @@ static void ar933x_uart_console_write(struct console *co, const char *s, ar933x_uart_write(up, AR933X_UART_INT_REG, AR933X_UART_INT_ALLINTS); if (locked) - uart_port_unlock(&up->port); - - local_irq_restore(flags); + uart_port_unlock_irqrestore(&up->port, flags); } static int ar933x_uart_console_setup(struct console *co, char *options) From 8c1cbc5a2b7b4980b05bd0587c458c8cd89b59da Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 1 Mar 2024 22:45:16 +0100 Subject: [PATCH 165/199] serial: bcm63xx: Use uart_prepare_sysrq_char(). The port lock is a spinlock_t which is becomes a sleeping lock on PREEMPT_RT. The driver splits the locking function into two parts: local_irq_save() and uart_port_lock() and this breaks PREEMPT_RT. Delay handling sysrq until port lock is dropped. Remove the special case in the console write routine an always use the complete locking function. Signed-off-by: Sebastian Andrzej Siewior Link: https://lore.kernel.org/r/20240301215246.891055-4-bigeasy@linutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/bcm63xx_uart.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c index a3cefa153456..34801a6f300b 100644 --- a/drivers/tty/serial/bcm63xx_uart.c +++ b/drivers/tty/serial/bcm63xx_uart.c @@ -285,10 +285,9 @@ static void bcm_uart_do_rx(struct uart_port *port) flag = TTY_PARITY; } - if (uart_handle_sysrq_char(port, c)) + if (uart_prepare_sysrq_char(port, c)) continue; - if ((cstat & port->ignore_status_mask) == 0) tty_insert_flip_char(tty_port, c, flag); @@ -353,7 +352,7 @@ static irqreturn_t bcm_uart_interrupt(int irq, void *dev_id) estat & UART_EXTINP_DCD_MASK); } - uart_port_unlock(port); + uart_unlock_and_check_sysrq(port); return IRQ_HANDLED; } @@ -703,20 +702,14 @@ static void bcm_console_write(struct console *co, const char *s, { struct uart_port *port; unsigned long flags; - int locked; + int locked = 1; port = &ports[co->index]; - local_irq_save(flags); - if (port->sysrq) { - /* bcm_uart_interrupt() already took the lock */ - locked = 0; - } else if (oops_in_progress) { - locked = uart_port_trylock(port); - } else { - uart_port_lock(port); - locked = 1; - } + if (oops_in_progress) + locked = uart_port_trylock_irqsave(port, &flags); + else + uart_port_lock_irqsave(port, &flags); /* call helper to deal with \r\n */ uart_console_write(port, s, count, bcm_console_putchar); @@ -725,8 +718,7 @@ static void bcm_console_write(struct console *co, const char *s, wait_for_xmitr(port); if (locked) - uart_port_unlock(port); - local_irq_restore(flags); + uart_port_unlock_irqrestore(port, flags); } /* From fb793b952a330e6c87aec98aeb300aaa5c2ac960 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 1 Mar 2024 22:45:17 +0100 Subject: [PATCH 166/199] serial: meson: Use uart_prepare_sysrq_char(). The port lock is a spinlock_t which is becomes a sleeping lock on PREEMPT_RT. The driver splits the locking function into two parts: local_irq_save() and uart_port_lock() and this breaks PREEMPT_RT. Delay handling sysrq until port lock is dropped. Remove the special case in the console write routine an always use the complete locking function. Cc: Kevin Hilman Cc: Jerome Brunet Cc: linux-arm-kernel@lists.infradead.org Cc: linux-amlogic@lists.infradead.org Signed-off-by: Sebastian Andrzej Siewior Link: https://lore.kernel.org/r/20240301215246.891055-5-bigeasy@linutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/meson_uart.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c index 8395688f5ee9..6feac459c0cf 100644 --- a/drivers/tty/serial/meson_uart.c +++ b/drivers/tty/serial/meson_uart.c @@ -220,7 +220,7 @@ static void meson_receive_chars(struct uart_port *port) continue; } - if (uart_handle_sysrq_char(port, ch)) + if (uart_prepare_sysrq_char(port, ch)) continue; if ((status & port->ignore_status_mask) == 0) @@ -248,7 +248,7 @@ static irqreturn_t meson_uart_interrupt(int irq, void *dev_id) meson_uart_start_tx(port); } - uart_port_unlock(port); + uart_unlock_and_check_sysrq(port); return IRQ_HANDLED; } @@ -556,18 +556,13 @@ static void meson_serial_port_write(struct uart_port *port, const char *s, u_int count) { unsigned long flags; - int locked; + int locked = 1; u32 val, tmp; - local_irq_save(flags); - if (port->sysrq) { - locked = 0; - } else if (oops_in_progress) { - locked = uart_port_trylock(port); - } else { - uart_port_lock(port); - locked = 1; - } + if (oops_in_progress) + locked = uart_port_trylock_irqsave(port, &flags); + else + uart_port_lock_irqsave(port, &flags); val = readl(port->membase + AML_UART_CONTROL); tmp = val & ~(AML_UART_TX_INT_EN | AML_UART_RX_INT_EN); @@ -577,8 +572,7 @@ static void meson_serial_port_write(struct uart_port *port, const char *s, writel(val, port->membase + AML_UART_CONTROL); if (locked) - uart_port_unlock(port); - local_irq_restore(flags); + uart_port_unlock_irqrestore(port, flags); } static void meson_serial_console_write(struct console *co, const char *s, From 4e5788c0993c0c83c3d91c090cfb6ff70f99b427 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 1 Mar 2024 22:45:18 +0100 Subject: [PATCH 167/199] serial: msm: Use uart_prepare_sysrq_char(). The port lock is a spinlock_t which is becomes a sleeping lock on PREEMPT_RT. The driver splits the locking function into two parts: local_irq_save() and uart_port_lock() and this breaks PREEMPT_RT. Delay handling sysrq until port lock is dropped. Remove the special case in the console write routine an always use the complete locking function. Cc: Bjorn Andersson Cc: Konrad Dybcio Cc: linux-arm-msm@vger.kernel.org Signed-off-by: Sebastian Andrzej Siewior Link: https://lore.kernel.org/r/20240301215246.891055-6-bigeasy@linutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/msm_serial.c | 33 ++++++++++----------------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index e24204ad35de..d27c4c8c84e1 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -588,16 +588,14 @@ static void msm_complete_rx_dma(void *args) if (!(port->read_status_mask & MSM_UART_SR_RX_BREAK)) flag = TTY_NORMAL; - uart_port_unlock_irqrestore(port, flags); - sysrq = uart_handle_sysrq_char(port, dma->virt[i]); - uart_port_lock_irqsave(port, &flags); + sysrq = uart_prepare_sysrq_char(port, dma->virt[i]); if (!sysrq) tty_insert_flip_char(tport, dma->virt[i], flag); } msm_start_rx_dma(msm_port); done: - uart_port_unlock_irqrestore(port, flags); + uart_unlock_and_check_sysrq_irqrestore(port, flags); if (count) tty_flip_buffer_push(tport); @@ -763,9 +761,7 @@ static void msm_handle_rx_dm(struct uart_port *port, unsigned int misr) if (!(port->read_status_mask & MSM_UART_SR_RX_BREAK)) flag = TTY_NORMAL; - uart_port_unlock(port); - sysrq = uart_handle_sysrq_char(port, buf[i]); - uart_port_lock(port); + sysrq = uart_prepare_sysrq_char(port, buf[i]); if (!sysrq) tty_insert_flip_char(tport, buf[i], flag); } @@ -825,9 +821,7 @@ static void msm_handle_rx(struct uart_port *port) else if (sr & MSM_UART_SR_PAR_FRAME_ERR) flag = TTY_FRAME; - uart_port_unlock(port); - sysrq = uart_handle_sysrq_char(port, c); - uart_port_lock(port); + sysrq = uart_prepare_sysrq_char(port, c); if (!sysrq) tty_insert_flip_char(tport, c, flag); } @@ -948,11 +942,10 @@ static irqreturn_t msm_uart_irq(int irq, void *dev_id) struct uart_port *port = dev_id; struct msm_port *msm_port = to_msm_port(port); struct msm_dma *dma = &msm_port->rx_dma; - unsigned long flags; unsigned int misr; u32 val; - uart_port_lock_irqsave(port, &flags); + uart_port_lock(port); misr = msm_read(port, MSM_UART_MISR); msm_write(port, 0, MSM_UART_IMR); /* disable interrupt */ @@ -984,7 +977,7 @@ static irqreturn_t msm_uart_irq(int irq, void *dev_id) msm_handle_delta_cts(port); msm_write(port, msm_port->imr, MSM_UART_IMR); /* restore interrupt */ - uart_port_unlock_irqrestore(port, flags); + uart_unlock_and_check_sysrq(port); return IRQ_HANDLED; } @@ -1621,14 +1614,10 @@ static void __msm_console_write(struct uart_port *port, const char *s, num_newlines++; count += num_newlines; - local_irq_save(flags); - - if (port->sysrq) - locked = 0; - else if (oops_in_progress) - locked = uart_port_trylock(port); + if (oops_in_progress) + locked = uart_port_trylock_irqsave(port, &flags); else - uart_port_lock(port); + uart_port_lock_irqsave(port, &flags); if (is_uartdm) msm_reset_dm_count(port, count); @@ -1667,9 +1656,7 @@ static void __msm_console_write(struct uart_port *port, const char *s, } if (locked) - uart_port_unlock(port); - - local_irq_restore(flags); + uart_port_unlock_irqrestore(port, flags); } static void msm_console_write(struct console *co, const char *s, From 63bd93ac6148ccfe0fe7268907c3517d42ec4fee Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 1 Mar 2024 22:45:19 +0100 Subject: [PATCH 168/199] serial: omap: Use uart_prepare_sysrq_char(). The port lock is a spinlock_t which is becomes a sleeping lock on PREEMPT_RT. The driver splits the locking function into two parts: local_irq_save() and uart_port_lock() and this breaks PREEMPT_RT. Delay handling sysrq until port lock is dropped. Remove the special case in the console write routine an always use the complete locking function. Signed-off-by: Sebastian Andrzej Siewior Link: https://lore.kernel.org/r/20240301215246.891055-7-bigeasy@linutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/omap-serial.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index f5a0b401af63..9be1c871cf11 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -508,7 +508,7 @@ static void serial_omap_rdi(struct uart_omap_port *up, unsigned int lsr) up->port.icount.rx++; - if (uart_handle_sysrq_char(&up->port, ch)) + if (uart_prepare_sysrq_char(&up->port, ch)) return; uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, TTY_NORMAL); @@ -563,7 +563,7 @@ static irqreturn_t serial_omap_irq(int irq, void *dev_id) } } while (max_count--); - uart_port_unlock(&up->port); + uart_unlock_and_check_sysrq(&up->port); tty_flip_buffer_push(&up->port.state->port); @@ -1212,13 +1212,10 @@ serial_omap_console_write(struct console *co, const char *s, unsigned int ier; int locked = 1; - local_irq_save(flags); - if (up->port.sysrq) - locked = 0; - else if (oops_in_progress) - locked = uart_port_trylock(&up->port); + if (oops_in_progress) + locked = uart_port_trylock_irqsave(&up->port, &flags); else - uart_port_lock(&up->port); + uart_port_lock_irqsave(&up->port, &flags); /* * First save the IER then disable the interrupts @@ -1245,8 +1242,7 @@ serial_omap_console_write(struct console *co, const char *s, check_modem_status(up); if (locked) - uart_port_unlock(&up->port); - local_irq_restore(flags); + uart_port_unlock_irqrestore(&up->port, flags); } static int __init From 51f7ed071c34ae0a3efd9c21ba07efeda4dd1773 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 1 Mar 2024 22:45:20 +0100 Subject: [PATCH 169/199] serial: pxa: Use uart_prepare_sysrq_char(). The port lock is a spinlock_t which is becomes a sleeping lock on PREEMPT_RT. The driver splits the locking function into two parts: local_irq_save() and uart_port_lock() and this breaks PREEMPT_RT. Delay handling sysrq until port lock is dropped. Remove the special case in the console write routine an always use the complete locking function. Signed-off-by: Sebastian Andrzej Siewior Link: https://lore.kernel.org/r/20240301215246.891055-8-bigeasy@linutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pxa.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c index 46e70e155aab..e395ff29c1a2 100644 --- a/drivers/tty/serial/pxa.c +++ b/drivers/tty/serial/pxa.c @@ -151,7 +151,7 @@ static inline void receive_chars(struct uart_pxa_port *up, int *status) flag = TTY_FRAME; } - if (uart_handle_sysrq_char(&up->port, ch)) + if (uart_prepare_sysrq_char(&up->port, ch)) goto ignore_char; uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag); @@ -232,7 +232,7 @@ static inline irqreturn_t serial_pxa_irq(int irq, void *dev_id) check_modem_status(up); if (lsr & UART_LSR_THRE) transmit_chars(up); - uart_port_unlock(&up->port); + uart_unlock_and_check_sysrq(&up->port); return IRQ_HANDLED; } @@ -604,13 +604,10 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count) int locked = 1; clk_enable(up->clk); - local_irq_save(flags); - if (up->port.sysrq) - locked = 0; - else if (oops_in_progress) - locked = uart_port_trylock(&up->port); + if (oops_in_progress) + locked = uart_port_trylock_irqsave(&up->port, &flags); else - uart_port_lock(&up->port); + uart_port_lock_irqsave(&up->port, &flags); /* * First save the IER then disable the interrupts @@ -628,10 +625,8 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count) serial_out(up, UART_IER, ier); if (locked) - uart_port_unlock(&up->port); - local_irq_restore(flags); + uart_port_unlock_irqrestore(&up->port, flags); clk_disable(up->clk); - } #ifdef CONFIG_CONSOLE_POLL From e544127cc1365083ae675e8fe484146d8658cc62 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 1 Mar 2024 22:45:21 +0100 Subject: [PATCH 170/199] serial: sunplus: Use uart_prepare_sysrq_char(). The port lock is a spinlock_t which is becomes a sleeping lock on PREEMPT_RT. The driver splits the locking function into two parts: local_irq_save() and uart_port_lock() and this breaks PREEMPT_RT. Delay handling sysrq until port lock is dropped. Remove the special case in the console write routine an always use the complete locking function. Cc: Hammer Hsieh Signed-off-by: Sebastian Andrzej Siewior Link: https://lore.kernel.org/r/20240301215246.891055-9-bigeasy@linutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sunplus-uart.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/tty/serial/sunplus-uart.c b/drivers/tty/serial/sunplus-uart.c index 99f5285819d4..f5e29eb4a4ce 100644 --- a/drivers/tty/serial/sunplus-uart.c +++ b/drivers/tty/serial/sunplus-uart.c @@ -260,7 +260,7 @@ static void receive_chars(struct uart_port *port) if (port->ignore_status_mask & SUP_DUMMY_READ) goto ignore_char; - if (uart_handle_sysrq_char(port, ch)) + if (uart_prepare_sysrq_char(port, ch)) goto ignore_char; uart_insert_char(port, lsr, SUP_UART_LSR_OE, ch, flag); @@ -287,7 +287,7 @@ static irqreturn_t sunplus_uart_irq(int irq, void *args) if (isc & SUP_UART_ISC_TX) transmit_chars(port); - uart_port_unlock(port); + uart_unlock_and_check_sysrq(port); return IRQ_HANDLED; } @@ -512,22 +512,16 @@ static void sunplus_console_write(struct console *co, unsigned long flags; int locked = 1; - local_irq_save(flags); - - if (sunplus_console_ports[co->index]->port.sysrq) - locked = 0; - else if (oops_in_progress) - locked = uart_port_trylock(&sunplus_console_ports[co->index]->port); + if (oops_in_progress) + locked = uart_port_trylock_irqsave(&sunplus_console_ports[co->index]->port, &flags); else - uart_port_lock(&sunplus_console_ports[co->index]->port); + uart_port_lock_irqsave(&sunplus_console_ports[co->index]->port, &flags); uart_console_write(&sunplus_console_ports[co->index]->port, s, count, sunplus_uart_console_putchar); if (locked) - uart_port_unlock(&sunplus_console_ports[co->index]->port); - - local_irq_restore(flags); + uart_port_unlock_irqrestore(&sunplus_console_ports[co->index]->port, flags); } static int __init sunplus_console_setup(struct console *co, char *options) From 6ba52968601ad3851d0b1da7dbe227b47a7dc918 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 1 Mar 2024 22:45:22 +0100 Subject: [PATCH 171/199] serial: lpc32xx_hs: Use uart_prepare_sysrq_char() to handle sysrq. The port lock is a spinlock_t which is becomes a sleeping lock on PREEMPT_RT. The driver splits the locking function into two parts: local_irq_save() and uart_port_lock() and this breaks PREEMPT_RT. Handle sysrq requests sysrq once the port lock is dropped. Remove the special case in the console write routine an always use the complete locking function. Cc: Vladimir Zapolskiy Cc: linux-arm-kernel@lists.infradead.org Signed-off-by: Sebastian Andrzej Siewior Link: https://lore.kernel.org/r/20240301215246.891055-10-bigeasy@linutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/lpc32xx_hs.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c index 269efc5e2d51..3e4ac46de1bc 100644 --- a/drivers/tty/serial/lpc32xx_hs.c +++ b/drivers/tty/serial/lpc32xx_hs.c @@ -136,20 +136,16 @@ static void lpc32xx_hsuart_console_write(struct console *co, const char *s, int locked = 1; touch_nmi_watchdog(); - local_irq_save(flags); - if (up->port.sysrq) - locked = 0; - else if (oops_in_progress) - locked = uart_port_trylock(&up->port); + if (oops_in_progress) + locked = uart_port_trylock_irqsave(&up->port, &flags); else - uart_port_lock(&up->port); + uart_port_lock_irqsave(&up->port, &flags); uart_console_write(&up->port, s, count, lpc32xx_hsuart_console_putchar); wait_for_xmit_empty(&up->port); if (locked) - uart_port_unlock(&up->port); - local_irq_restore(flags); + uart_port_unlock_irqrestore(&up->port, flags); } static int __init lpc32xx_hsuart_console_setup(struct console *co, @@ -266,7 +262,8 @@ static void __serial_lpc32xx_rx(struct uart_port *port) tty_insert_flip_char(tport, 0, TTY_FRAME); } - tty_insert_flip_char(tport, (tmp & 0xFF), flag); + if (!uart_prepare_sysrq_char(port, tmp & 0xff)) + tty_insert_flip_char(tport, (tmp & 0xFF), flag); tmp = readl(LPC32XX_HSUART_FIFO(port->membase)); } @@ -331,7 +328,7 @@ static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id) __serial_lpc32xx_tx(port); } - uart_port_unlock(port); + uart_unlock_and_check_sysrq(port); return IRQ_HANDLED; } From 2af521486761f6f40ff00faa0cd3d52465dfd461 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 1 Mar 2024 22:45:23 +0100 Subject: [PATCH 172/199] serial: owl: Use uart_prepare_sysrq_char() to handle sysrq. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The port lock is a spinlock_t which is becomes a sleeping lock on PREEMPT_RT. The driver splits the locking function into two parts: local_irq_save() and uart_port_lock() and this breaks PREEMPT_RT. Handle sysrq requests sysrq once the port lock is dropped. Remove the special case in the console write routine an always use the complete locking function. Cc: Andreas Färber Cc: Manivannan Sadhasivam Cc: linux-arm-kernel@lists.infradead.org Cc: linux-actions@lists.infradead.org Signed-off-by: Sebastian Andrzej Siewior Link: https://lore.kernel.org/r/20240301215246.891055-11-bigeasy@linutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/owl-uart.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/drivers/tty/serial/owl-uart.c b/drivers/tty/serial/owl-uart.c index d9fe85397741..8b60ac0ad7cd 100644 --- a/drivers/tty/serial/owl-uart.c +++ b/drivers/tty/serial/owl-uart.c @@ -199,6 +199,7 @@ static void owl_uart_receive_chars(struct uart_port *port) stat = owl_uart_read(port, OWL_UART_STAT); while (!(stat & OWL_UART_STAT_RFEM)) { char flag = TTY_NORMAL; + bool sysrq; if (stat & OWL_UART_STAT_RXER) port->icount.overrun++; @@ -217,7 +218,9 @@ static void owl_uart_receive_chars(struct uart_port *port) val = owl_uart_read(port, OWL_UART_RXDAT); val &= 0xff; - if ((stat & port->ignore_status_mask) == 0) + sysrq = uart_prepare_sysrq_char(port, val); + + if (!sysrq && (stat & port->ignore_status_mask) == 0) tty_insert_flip_char(&port->state->port, val, flag); stat = owl_uart_read(port, OWL_UART_STAT); @@ -229,10 +232,9 @@ static void owl_uart_receive_chars(struct uart_port *port) static irqreturn_t owl_uart_irq(int irq, void *dev_id) { struct uart_port *port = dev_id; - unsigned long flags; u32 stat; - uart_port_lock_irqsave(port, &flags); + uart_port_lock(port); stat = owl_uart_read(port, OWL_UART_STAT); @@ -246,7 +248,7 @@ static irqreturn_t owl_uart_irq(int irq, void *dev_id) stat |= OWL_UART_STAT_RIP | OWL_UART_STAT_TIP; owl_uart_write(port, stat, OWL_UART_STAT); - uart_port_unlock_irqrestore(port, flags); + uart_unlock_and_check_sysrq(port); return IRQ_HANDLED; } @@ -508,18 +510,12 @@ static void owl_uart_port_write(struct uart_port *port, const char *s, { u32 old_ctl, val; unsigned long flags; - int locked; + int locked = 1; - local_irq_save(flags); - - if (port->sysrq) - locked = 0; - else if (oops_in_progress) - locked = uart_port_trylock(port); - else { - uart_port_lock(port); - locked = 1; - } + if (oops_in_progress) + locked = uart_port_trylock_irqsave(port, &flags); + else + uart_port_lock_irqsave(port, &flags); old_ctl = owl_uart_read(port, OWL_UART_CTL); val = old_ctl | OWL_UART_CTL_TRFS_TX; @@ -541,9 +537,7 @@ static void owl_uart_port_write(struct uart_port *port, const char *s, owl_uart_write(port, old_ctl, OWL_UART_CTL); if (locked) - uart_port_unlock(port); - - local_irq_restore(flags); + uart_port_unlock_irqrestore(port, flags); } static void owl_uart_console_write(struct console *co, const char *s, From bb0b3142055d006431ac05663d38c069602b5967 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 1 Mar 2024 22:45:24 +0100 Subject: [PATCH 173/199] serial: rda: Use uart_prepare_sysrq_char() to handle sysrq. The port lock is a spinlock_t which is becomes a sleeping lock on PREEMPT_RT. The driver splits the locking function into two parts: local_irq_save() and uart_port_lock() and this breaks PREEMPT_RT. Handle sysrq requests sysrq once the port lock is dropped. Remove the special case in the console write routine an always use the complete locking function. Cc: Manivannan Sadhasivam Cc: linux-arm-kernel@lists.infradead.org Cc: linux-unisoc@lists.infradead.org Signed-off-by: Sebastian Andrzej Siewior Link: https://lore.kernel.org/r/20240301215246.891055-12-bigeasy@linutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/rda-uart.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/drivers/tty/serial/rda-uart.c b/drivers/tty/serial/rda-uart.c index 13deb355cf1b..82def9b8632a 100644 --- a/drivers/tty/serial/rda-uart.c +++ b/drivers/tty/serial/rda-uart.c @@ -394,7 +394,8 @@ static void rda_uart_receive_chars(struct uart_port *port) val &= 0xff; port->icount.rx++; - tty_insert_flip_char(&port->state->port, val, flag); + if (!uart_prepare_sysrq_char(port, val)) + tty_insert_flip_char(&port->state->port, val, flag); status = rda_uart_read(port, RDA_UART_STATUS); } @@ -405,10 +406,9 @@ static void rda_uart_receive_chars(struct uart_port *port) static irqreturn_t rda_interrupt(int irq, void *dev_id) { struct uart_port *port = dev_id; - unsigned long flags; u32 val, irq_mask; - uart_port_lock_irqsave(port, &flags); + uart_port_lock(port); /* Clear IRQ cause */ val = rda_uart_read(port, RDA_UART_IRQ_CAUSE); @@ -425,7 +425,7 @@ static irqreturn_t rda_interrupt(int irq, void *dev_id) rda_uart_send_chars(port); } - uart_port_unlock_irqrestore(port, flags); + uart_unlock_and_check_sysrq(port); return IRQ_HANDLED; } @@ -590,18 +590,12 @@ static void rda_uart_port_write(struct uart_port *port, const char *s, { u32 old_irq_mask; unsigned long flags; - int locked; + int locked = 1; - local_irq_save(flags); - - if (port->sysrq) { - locked = 0; - } else if (oops_in_progress) { - locked = uart_port_trylock(port); - } else { - uart_port_lock(port); - locked = 1; - } + if (oops_in_progress) + locked = uart_port_trylock_irqsave(port, &flags); + else + uart_port_lock_irqsave(port, &flags); old_irq_mask = rda_uart_read(port, RDA_UART_IRQ_MASK); rda_uart_write(port, 0, RDA_UART_IRQ_MASK); @@ -615,9 +609,7 @@ static void rda_uart_port_write(struct uart_port *port, const char *s, rda_uart_write(port, old_irq_mask, RDA_UART_IRQ_MASK); if (locked) - uart_port_unlock(port); - - local_irq_restore(flags); + uart_port_unlock_irqrestore(port, flags); } static void rda_uart_console_write(struct console *co, const char *s, From 32c694ec3efc2b7cdf921da50371297ba70e7d50 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 1 Mar 2024 22:45:25 +0100 Subject: [PATCH 174/199] serial: sifive: Use uart_prepare_sysrq_char() to handle sysrq. The port lock is a spinlock_t which is becomes a sleeping lock on PREEMPT_RT. The driver splits the locking function into two parts: local_irq_save() and uart_port_lock() and this breaks PREEMPT_RT. Handle sysrq requests sysrq once the port lock is dropped. Remove the special case in the console write routine an always use the complete locking function. Cc: Palmer Dabbelt Cc: Paul Walmsley Cc: linux-riscv@lists.infradead.org Signed-off-by: Sebastian Andrzej Siewior Link: https://lore.kernel.org/r/20240301215246.891055-13-bigeasy@linutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sifive.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c index a4cc569a78a2..0670fd9f8496 100644 --- a/drivers/tty/serial/sifive.c +++ b/drivers/tty/serial/sifive.c @@ -412,7 +412,8 @@ static void __ssp_receive_chars(struct sifive_serial_port *ssp) break; ssp->port.icount.rx++; - uart_insert_char(&ssp->port, 0, 0, ch, TTY_NORMAL); + if (!uart_prepare_sysrq_char(&ssp->port, ch)) + uart_insert_char(&ssp->port, 0, 0, ch, TTY_NORMAL); } tty_flip_buffer_push(&ssp->port.state->port); @@ -534,7 +535,7 @@ static irqreturn_t sifive_serial_irq(int irq, void *dev_id) if (ip & SIFIVE_SERIAL_IP_TXWM_MASK) __ssp_transmit_chars(ssp); - uart_port_unlock(&ssp->port); + uart_unlock_and_check_sysrq(&ssp->port); return IRQ_HANDLED; } @@ -791,13 +792,10 @@ static void sifive_serial_console_write(struct console *co, const char *s, if (!ssp) return; - local_irq_save(flags); - if (ssp->port.sysrq) - locked = 0; - else if (oops_in_progress) - locked = uart_port_trylock(&ssp->port); + if (oops_in_progress) + locked = uart_port_trylock_irqsave(&ssp->port, &flags); else - uart_port_lock(&ssp->port); + uart_port_lock_irqsave(&ssp->port, &flags); ier = __ssp_readl(ssp, SIFIVE_SERIAL_IE_OFFS); __ssp_writel(0, SIFIVE_SERIAL_IE_OFFS, ssp); @@ -807,8 +805,7 @@ static void sifive_serial_console_write(struct console *co, const char *s, __ssp_writel(ier, SIFIVE_SERIAL_IE_OFFS, ssp); if (locked) - uart_port_unlock(&ssp->port); - local_irq_restore(flags); + uart_port_unlock_irqrestore(&ssp->port, flags); } static int sifive_serial_console_setup(struct console *co, char *options) From 1155f8ef1f9a3b4795f9e758b1393b6acb1afef9 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 1 Mar 2024 22:45:26 +0100 Subject: [PATCH 175/199] serial: pch: Invoke handle_rx_to() directly. handle_rx() is only a wrapper around handle_rx_to() without any additional functionality. Invoke handle_rx_to() directly and remove handle_rx(). Signed-off-by: Sebastian Andrzej Siewior Link: https://lore.kernel.org/r/20240301215246.891055-14-bigeasy@linutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pch_uart.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 436cc6d52a11..29ed6f8621d7 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -778,11 +778,6 @@ static int handle_rx_to(struct eg20t_port *priv) return PCH_UART_HANDLED_RX_INT; } -static int handle_rx(struct eg20t_port *priv) -{ - return handle_rx_to(priv); -} - static int dma_handle_rx(struct eg20t_port *priv) { struct uart_port *port = &priv->port; @@ -1051,7 +1046,7 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) PCH_UART_HAL_RX_INT | PCH_UART_HAL_RX_ERR_INT); } else { - ret = handle_rx(priv); + ret = handle_rx_to(priv); } break; case PCH_UART_IID_RDR_TO: /* Received Data Ready From 09b8ff269401b2064afb5df42529bc18f6ad7d76 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 1 Mar 2024 22:45:27 +0100 Subject: [PATCH 176/199] serial: pch: Make push_rx() return void. push_rx() returns always 0. Make push_rx() return void. Signed-off-by: Sebastian Andrzej Siewior Link: https://lore.kernel.org/r/20240301215246.891055-15-bigeasy@linutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pch_uart.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 29ed6f8621d7..124eb816fca7 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -599,16 +599,14 @@ static void pch_uart_hal_set_break(struct eg20t_port *priv, int on) iowrite8(lcr, priv->membase + UART_LCR); } -static int push_rx(struct eg20t_port *priv, const unsigned char *buf, - int size) +static void push_rx(struct eg20t_port *priv, const unsigned char *buf, + int size) { struct uart_port *port = &priv->port; struct tty_port *tport = &port->state->port; tty_insert_flip_string(tport, buf, size); tty_flip_buffer_push(tport); - - return 0; } static int dma_push_rx(struct eg20t_port *priv, int size) @@ -761,7 +759,7 @@ static int handle_rx_to(struct eg20t_port *priv) { struct pch_uart_buffer *buf; int rx_size; - int ret; + if (!priv->start_rx) { pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT | PCH_UART_HAL_RX_ERR_INT); @@ -770,9 +768,7 @@ static int handle_rx_to(struct eg20t_port *priv) buf = &priv->rxbuf; do { rx_size = pch_uart_hal_read(priv, buf->buf, buf->size); - ret = push_rx(priv, buf->buf, rx_size); - if (ret) - return 0; + push_rx(priv, buf->buf, rx_size); } while (rx_size == buf->size); return PCH_UART_HANDLED_RX_INT; From f8ff23ebce8c305383c8070e1ea3b08a69eb1e8d Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 1 Mar 2024 22:45:28 +0100 Subject: [PATCH 177/199] serial: pch: Don't disable interrupts while acquiring lock in ISR. The interrupt service routine is always invoked with disabled interrupts. Remove the _irqsave() from the locking functions in the interrupts service routine/ pch_uart_interrupt(). Signed-off-by: Sebastian Andrzej Siewior Link: https://lore.kernel.org/r/20240301215246.891055-16-bigeasy@linutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pch_uart.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 124eb816fca7..6e259f413915 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -1010,11 +1010,10 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) u8 lsr; int ret = 0; unsigned char iid; - unsigned long flags; int next = 1; u8 msr; - spin_lock_irqsave(&priv->lock, flags); + spin_lock(&priv->lock); handled = 0; while (next) { iid = pch_uart_hal_get_iid(priv); @@ -1074,7 +1073,7 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) handled |= (unsigned int)ret; } - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock(&priv->lock); return IRQ_RETVAL(handled); } From 38f3fc2e82a03d6dbb30c1fecacc630bd0ac9c28 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 1 Mar 2024 22:45:29 +0100 Subject: [PATCH 178/199] serial: pch: Don't initialize uart_port's spin_lock. There is no need to directly initialize the spinlock_t in struct uart_port. The structure is later passed to uart_add_one_port() which initialize the complete struct including the lock member. Remove spin_lock_init() on uart_port's internal lock. Signed-off-by: Sebastian Andrzej Siewior Link: https://lore.kernel.org/r/20240301215246.891055-17-bigeasy@linutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pch_uart.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 6e259f413915..391170391876 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -1725,8 +1725,6 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, KBUILD_MODNAME ":" PCH_UART_DRIVER_DEVICE "%d", priv->port.line); - spin_lock_init(&priv->port.lock); - pci_set_drvdata(pdev, priv); priv->trigger_level = 1; priv->fcr = 0; From 06d28ca0c66cbb4e3716454f365f9cbb1e57a681 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 1 Mar 2024 22:45:30 +0100 Subject: [PATCH 179/199] serial: pch: Remove eg20t_port::lock. The struct eg20t_port has a spinlock_t which is used for locking while access I/O of the device. Then there is the uart_portlock which is sometimes and nests within eg20t_port's lock. The uart_port lock is not used while using the struct in pch_uart_hal_read() which might be okay. Then both locks are used in pch_console_write() which looks odd especially the double try_lock part. All in all it looks like the uart_port's lock could replace eg20t_port's lock and simplify the code. Remove eg20t_port::lock and use uart_port's lock for the lock scope. Signed-off-by: Sebastian Andrzej Siewior Link: https://lore.kernel.org/r/20240301215246.891055-18-bigeasy@linutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pch_uart.c | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 391170391876..92cb3c623cc3 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -237,9 +237,6 @@ struct eg20t_port { #define IRQ_NAME_SIZE 17 char irq_name[IRQ_NAME_SIZE]; - - /* protect the eg20t_port private structure and io access to membase */ - spinlock_t lock; }; /** @@ -1013,7 +1010,7 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) int next = 1; u8 msr; - spin_lock(&priv->lock); + uart_port_lock(&priv->port); handled = 0; while (next) { iid = pch_uart_hal_get_iid(priv); @@ -1073,7 +1070,7 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) handled |= (unsigned int)ret; } - spin_unlock(&priv->lock); + uart_port_unlock(&priv->port); return IRQ_RETVAL(handled); } @@ -1184,9 +1181,9 @@ static void pch_uart_break_ctl(struct uart_port *port, int ctl) unsigned long flags; priv = container_of(port, struct eg20t_port, port); - spin_lock_irqsave(&priv->lock, flags); + uart_port_lock_irqsave(&priv->port, &flags); pch_uart_hal_set_break(priv, ctl); - spin_unlock_irqrestore(&priv->lock, flags); + uart_port_unlock_irqrestore(&priv->port, flags); } /* Grab any interrupt resources and initialise any low level driver state. */ @@ -1336,8 +1333,7 @@ static void pch_uart_set_termios(struct uart_port *port, baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); - spin_lock_irqsave(&priv->lock, flags); - uart_port_lock(port); + uart_port_lock_irqsave(port, &flags); uart_update_timeout(port, termios->c_cflag, baud); rtn = pch_uart_hal_set_line(priv, baud, parity, bits, stb); @@ -1350,8 +1346,7 @@ static void pch_uart_set_termios(struct uart_port *port, tty_termios_encode_baud_rate(termios, baud, baud); out: - uart_port_unlock(port); - spin_unlock_irqrestore(&priv->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static const char *pch_uart_type(struct uart_port *port) @@ -1555,7 +1550,6 @@ pch_console_write(struct console *co, const char *s, unsigned int count) { struct eg20t_port *priv; unsigned long flags; - int priv_locked = 1; int port_locked = 1; u8 ier; @@ -1565,15 +1559,11 @@ pch_console_write(struct console *co, const char *s, unsigned int count) local_irq_save(flags); if (priv->port.sysrq) { - /* call to uart_handle_sysrq_char already took the priv lock */ - priv_locked = 0; /* serial8250_handle_port() already took the port lock */ port_locked = 0; } else if (oops_in_progress) { - priv_locked = spin_trylock(&priv->lock); port_locked = uart_port_trylock(&priv->port); } else { - spin_lock(&priv->lock); uart_port_lock(&priv->port); } @@ -1595,8 +1585,6 @@ pch_console_write(struct console *co, const char *s, unsigned int count) if (port_locked) uart_port_unlock(&priv->port); - if (priv_locked) - spin_unlock(&priv->lock); local_irq_restore(flags); } @@ -1694,8 +1682,6 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, pci_enable_msi(pdev); pci_set_master(pdev); - spin_lock_init(&priv->lock); - iobase = pci_resource_start(pdev, 0); mapbase = pci_resource_start(pdev, 1); priv->mapbase = mapbase; From d47dd323bf959dbf5f3e7f83373c8ed5f3bec9c0 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 1 Mar 2024 22:45:31 +0100 Subject: [PATCH 180/199] serial: pch: Use uart_prepare_sysrq_char(). The port lock is a spinlock_t which is becomes a sleeping lock on PREEMPT_RT. The driver splits the locking function into two parts: local_irq_save() and uart_port_lock() and this breaks PREEMPT_RT. Delay handling sysrq until port lock is dropped. Remove the special case in the console write routine an always use the complete locking function. Signed-off-by: Sebastian Andrzej Siewior Link: https://lore.kernel.org/r/20240301215246.891055-19-bigeasy@linutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pch_uart.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 92cb3c623cc3..89257cddf540 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -564,7 +564,7 @@ static int pch_uart_hal_read(struct eg20t_port *priv, unsigned char *buf, if (uart_handle_break(port)) continue; } - if (uart_handle_sysrq_char(port, rbr)) + if (uart_prepare_sysrq_char(port, rbr)) continue; buf[i++] = rbr; @@ -1070,7 +1070,7 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) handled |= (unsigned int)ret; } - uart_port_unlock(&priv->port); + uart_unlock_and_check_sysrq(&priv->port); return IRQ_RETVAL(handled); } @@ -1550,22 +1550,17 @@ pch_console_write(struct console *co, const char *s, unsigned int count) { struct eg20t_port *priv; unsigned long flags; - int port_locked = 1; + int locked = 1; u8 ier; priv = pch_uart_ports[co->index]; touch_nmi_watchdog(); - local_irq_save(flags); - if (priv->port.sysrq) { - /* serial8250_handle_port() already took the port lock */ - port_locked = 0; - } else if (oops_in_progress) { - port_locked = uart_port_trylock(&priv->port); - } else { - uart_port_lock(&priv->port); - } + if (oops_in_progress) + locked = uart_port_trylock_irqsave(&priv->port, &flags); + else + uart_port_lock_irqsave(&priv->port, &flags); /* * First save the IER then disable the interrupts @@ -1583,9 +1578,8 @@ pch_console_write(struct console *co, const char *s, unsigned int count) wait_for_xmitr(priv, UART_LSR_BOTH_EMPTY); iowrite8(ier, priv->membase + UART_IER); - if (port_locked) - uart_port_unlock(&priv->port); - local_irq_restore(flags); + if (locked) + uart_port_unlock_irqrestore(&priv->port, flags); } static int __init pch_console_setup(struct console *co, char *options) From 7bfb915a597a301abb892f620fe5c283a9fdbd77 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Sun, 3 Mar 2024 16:08:07 +0100 Subject: [PATCH 181/199] serial: core: only stop transmit when HW fifo is empty If the circular buffer is empty, it just means we fit all characters to send into the HW fifo, but not that the hardware finished transmitting them. So if we immediately call stop_tx() after that, this may abort any pending characters in the HW fifo, and cause dropped characters on the console. Fix this by only stopping tx when the tx HW fifo is actually empty. Fixes: 8275b48b2780 ("tty: serial: introduce transmit helpers") Cc: stable@vger.kernel.org Signed-off-by: Jonas Gorski Link: https://lore.kernel.org/r/20240303150807.68117-1-jonas.gorski@gmail.com Signed-off-by: Greg Kroah-Hartman --- include/linux/serial_core.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 55b1f3ba48ac..bb0f2d4ac62f 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -786,7 +786,8 @@ enum UART_TX_FLAGS { if (pending < WAKEUP_CHARS) { \ uart_write_wakeup(__port); \ \ - if (!((flags) & UART_TX_NOSTOP) && pending == 0) \ + if (!((flags) & UART_TX_NOSTOP) && pending == 0 && \ + __port->ops->tx_empty(__port)) \ __port->ops->stop_tx(__port); \ } \ \ From 6deab51402b129abea0e2f0a5e2ce27c06918973 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 4 Mar 2024 11:52:44 +0100 Subject: [PATCH 182/199] serial: sh-sci: Call sci_serial_{in,out}() directly Unlike the 8250 serial driver complex, the sh-sci driver uses only a single pair of functions to read and write serial port registers. Hence there is no need to incur the overhead of calling them through indirection, like the serial_port_{in,out}() wrappers do. Replace all calls to these wrappers by direct calls to sci_serial_{in,out}(). Remove the setup of the uart_port.serial_{in,out}() callbacks. After removal of all calls to serial_port_{in,out}() in the sh-sci driver, the only remaining user is uart_xchar_out(), which the sh-sci driver does not use. Signed-off-by: Geert Uytterhoeven Acked-by: John Paul Adrian Glaubitz Link: https://lore.kernel.org/r/51e79d601cb9d9d63822d3773d3cf05a96868612.1709548811.git.geert+renesas@glider.be Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 245 ++++++++++++++++++------------------ 1 file changed, 119 insertions(+), 126 deletions(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index a85e7b9a2e49..e512eaa57ed5 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -576,13 +576,13 @@ static void sci_start_tx(struct uart_port *port) #ifdef CONFIG_SERIAL_SH_SCI_DMA if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - u16 new, scr = serial_port_in(port, SCSCR); + u16 new, scr = sci_serial_in(port, SCSCR); if (s->chan_tx) new = scr | SCSCR_TDRQE; else new = scr & ~SCSCR_TDRQE; if (new != scr) - serial_port_out(port, SCSCR, new); + sci_serial_out(port, SCSCR, new); } if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) && @@ -599,7 +599,7 @@ static void sci_start_tx(struct uart_port *port) if (!s->chan_tx || s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE || port->type == PORT_SCIFA || port->type == PORT_SCIFB) { /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */ - ctrl = serial_port_in(port, SCSCR); + ctrl = sci_serial_in(port, SCSCR); /* * For SCI, TE (transmit enable) must be set after setting TIE @@ -609,7 +609,7 @@ static void sci_start_tx(struct uart_port *port) if (port->type == PORT_SCI) ctrl |= SCSCR_TE; - serial_port_out(port, SCSCR, ctrl | SCSCR_TIE); + sci_serial_out(port, SCSCR, ctrl | SCSCR_TIE); } } @@ -618,14 +618,14 @@ static void sci_stop_tx(struct uart_port *port) unsigned short ctrl; /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */ - ctrl = serial_port_in(port, SCSCR); + ctrl = sci_serial_in(port, SCSCR); if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) ctrl &= ~SCSCR_TDRQE; ctrl &= ~SCSCR_TIE; - serial_port_out(port, SCSCR, ctrl); + sci_serial_out(port, SCSCR, ctrl); #ifdef CONFIG_SERIAL_SH_SCI_DMA if (to_sci_port(port)->chan_tx && @@ -640,41 +640,40 @@ static void sci_start_rx(struct uart_port *port) { unsigned short ctrl; - ctrl = serial_port_in(port, SCSCR) | port_rx_irq_mask(port); + ctrl = sci_serial_in(port, SCSCR) | port_rx_irq_mask(port); if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) ctrl &= ~SCSCR_RDRQE; - serial_port_out(port, SCSCR, ctrl); + sci_serial_out(port, SCSCR, ctrl); } static void sci_stop_rx(struct uart_port *port) { unsigned short ctrl; - ctrl = serial_port_in(port, SCSCR); + ctrl = sci_serial_in(port, SCSCR); if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) ctrl &= ~SCSCR_RDRQE; ctrl &= ~port_rx_irq_mask(port); - serial_port_out(port, SCSCR, ctrl); + sci_serial_out(port, SCSCR, ctrl); } static void sci_clear_SCxSR(struct uart_port *port, unsigned int mask) { if (port->type == PORT_SCI) { /* Just store the mask */ - serial_port_out(port, SCxSR, mask); + sci_serial_out(port, SCxSR, mask); } else if (to_sci_port(port)->params->overrun_mask == SCIFA_ORER) { /* SCIFA/SCIFB and SCIF on SH7705/SH7720/SH7721 */ /* Only clear the status bits we want to clear */ - serial_port_out(port, SCxSR, - serial_port_in(port, SCxSR) & mask); + sci_serial_out(port, SCxSR, sci_serial_in(port, SCxSR) & mask); } else { /* Store the mask, clear parity/framing errors */ - serial_port_out(port, SCxSR, mask & ~(SCIF_FERC | SCIF_PERC)); + sci_serial_out(port, SCxSR, mask & ~(SCIF_FERC | SCIF_PERC)); } } @@ -688,7 +687,7 @@ static int sci_poll_get_char(struct uart_port *port) int c; do { - status = serial_port_in(port, SCxSR); + status = sci_serial_in(port, SCxSR); if (status & SCxSR_ERRORS(port)) { sci_clear_SCxSR(port, SCxSR_ERROR_CLEAR(port)); continue; @@ -699,10 +698,10 @@ static int sci_poll_get_char(struct uart_port *port) if (!(status & SCxSR_RDxF(port))) return NO_POLL_CHAR; - c = serial_port_in(port, SCxRDR); + c = sci_serial_in(port, SCxRDR); /* Dummy read */ - serial_port_in(port, SCxSR); + sci_serial_in(port, SCxSR); sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); return c; @@ -714,10 +713,10 @@ static void sci_poll_put_char(struct uart_port *port, unsigned char c) unsigned short status; do { - status = serial_port_in(port, SCxSR); + status = sci_serial_in(port, SCxSR); } while (!(status & SCxSR_TDxE(port))); - serial_port_out(port, SCxTDR, c); + sci_serial_out(port, SCxTDR, c); sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port)); } #endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE || @@ -736,8 +735,8 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag) } if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - u16 data = serial_port_in(port, SCPDR); - u16 ctrl = serial_port_in(port, SCPCR); + u16 data = sci_serial_in(port, SCPDR); + u16 ctrl = sci_serial_in(port, SCPCR); /* Enable RXD and TXD pin functions */ ctrl &= ~(SCPCR_RXDC | SCPCR_TXDC); @@ -756,10 +755,10 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag) /* Enable CTS# pin function */ ctrl &= ~SCPCR_CTSC; } - serial_port_out(port, SCPDR, data); - serial_port_out(port, SCPCR, ctrl); + sci_serial_out(port, SCPDR, data); + sci_serial_out(port, SCPCR, ctrl); } else if (sci_getreg(port, SCSPTR)->size) { - u16 status = serial_port_in(port, SCSPTR); + u16 status = sci_serial_in(port, SCSPTR); /* RTS# is always output; and active low, unless autorts */ status |= SCSPTR_RTSIO; @@ -769,7 +768,7 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag) status &= ~SCSPTR_RTSDT; /* CTS# and SCK are inputs */ status &= ~(SCSPTR_CTSIO | SCSPTR_SCKIO); - serial_port_out(port, SCSPTR, status); + sci_serial_out(port, SCSPTR, status); } } @@ -781,13 +780,13 @@ static int sci_txfill(struct uart_port *port) reg = sci_getreg(port, SCTFDR); if (reg->size) - return serial_port_in(port, SCTFDR) & fifo_mask; + return sci_serial_in(port, SCTFDR) & fifo_mask; reg = sci_getreg(port, SCFDR); if (reg->size) - return serial_port_in(port, SCFDR) >> 8; + return sci_serial_in(port, SCFDR) >> 8; - return !(serial_port_in(port, SCxSR) & SCI_TDRE); + return !(sci_serial_in(port, SCxSR) & SCI_TDRE); } static int sci_txroom(struct uart_port *port) @@ -803,13 +802,13 @@ static int sci_rxfill(struct uart_port *port) reg = sci_getreg(port, SCRFDR); if (reg->size) - return serial_port_in(port, SCRFDR) & fifo_mask; + return sci_serial_in(port, SCRFDR) & fifo_mask; reg = sci_getreg(port, SCFDR); if (reg->size) - return serial_port_in(port, SCFDR) & fifo_mask; + return sci_serial_in(port, SCFDR) & fifo_mask; - return (serial_port_in(port, SCxSR) & SCxSR_RDxF(port)) != 0; + return (sci_serial_in(port, SCxSR) & SCxSR_RDxF(port)) != 0; } /* ********************************************************************** * @@ -824,14 +823,14 @@ static void sci_transmit_chars(struct uart_port *port) unsigned short ctrl; int count; - status = serial_port_in(port, SCxSR); + status = sci_serial_in(port, SCxSR); if (!(status & SCxSR_TDxE(port))) { - ctrl = serial_port_in(port, SCSCR); + ctrl = sci_serial_in(port, SCSCR); if (uart_circ_empty(xmit)) ctrl &= ~SCSCR_TIE; else ctrl |= SCSCR_TIE; - serial_port_out(port, SCSCR, ctrl); + sci_serial_out(port, SCSCR, ctrl); return; } @@ -847,15 +846,15 @@ static void sci_transmit_chars(struct uart_port *port) c = xmit->buf[xmit->tail]; xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); } else if (port->type == PORT_SCI && uart_circ_empty(xmit)) { - ctrl = serial_port_in(port, SCSCR); + ctrl = sci_serial_in(port, SCSCR); ctrl &= ~SCSCR_TE; - serial_port_out(port, SCSCR, ctrl); + sci_serial_out(port, SCSCR, ctrl); return; } else { break; } - serial_port_out(port, SCxTDR, c); + sci_serial_out(port, SCxTDR, c); port->icount.tx++; } while (--count > 0); @@ -866,10 +865,10 @@ static void sci_transmit_chars(struct uart_port *port) uart_write_wakeup(port); if (uart_circ_empty(xmit)) { if (port->type == PORT_SCI) { - ctrl = serial_port_in(port, SCSCR); + ctrl = sci_serial_in(port, SCSCR); ctrl &= ~SCSCR_TIE; ctrl |= SCSCR_TEIE; - serial_port_out(port, SCSCR, ctrl); + sci_serial_out(port, SCSCR, ctrl); } sci_stop_tx(port); @@ -883,7 +882,7 @@ static void sci_receive_chars(struct uart_port *port) unsigned short status; unsigned char flag; - status = serial_port_in(port, SCxSR); + status = sci_serial_in(port, SCxSR); if (!(status & SCxSR_RDxF(port))) return; @@ -896,7 +895,7 @@ static void sci_receive_chars(struct uart_port *port) break; if (port->type == PORT_SCI) { - char c = serial_port_in(port, SCxRDR); + char c = sci_serial_in(port, SCxRDR); if (uart_handle_sysrq_char(port, c)) count = 0; else @@ -907,11 +906,11 @@ static void sci_receive_chars(struct uart_port *port) if (port->type == PORT_SCIF || port->type == PORT_HSCIF) { - status = serial_port_in(port, SCxSR); - c = serial_port_in(port, SCxRDR); + status = sci_serial_in(port, SCxSR); + c = sci_serial_in(port, SCxRDR); } else { - c = serial_port_in(port, SCxRDR); - status = serial_port_in(port, SCxSR); + c = sci_serial_in(port, SCxRDR); + status = sci_serial_in(port, SCxSR); } if (uart_handle_sysrq_char(port, c)) { count--; i--; @@ -932,7 +931,7 @@ static void sci_receive_chars(struct uart_port *port) } } - serial_port_in(port, SCxSR); /* dummy read */ + sci_serial_in(port, SCxSR); /* dummy read */ sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); copied += count; @@ -944,8 +943,8 @@ static void sci_receive_chars(struct uart_port *port) tty_flip_buffer_push(tport); } else { /* TTY buffers full; read from RX reg to prevent lockup */ - serial_port_in(port, SCxRDR); - serial_port_in(port, SCxSR); /* dummy read */ + sci_serial_in(port, SCxRDR); + sci_serial_in(port, SCxSR); /* dummy read */ sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); } } @@ -953,7 +952,7 @@ static void sci_receive_chars(struct uart_port *port) static int sci_handle_errors(struct uart_port *port) { int copied = 0; - unsigned short status = serial_port_in(port, SCxSR); + unsigned short status = sci_serial_in(port, SCxSR); struct tty_port *tport = &port->state->port; struct sci_port *s = to_sci_port(port); @@ -1000,10 +999,10 @@ static int sci_handle_fifo_overrun(struct uart_port *port) if (!reg->size) return 0; - status = serial_port_in(port, s->params->overrun_reg); + status = sci_serial_in(port, s->params->overrun_reg); if (status & s->params->overrun_mask) { status &= ~s->params->overrun_mask; - serial_port_out(port, s->params->overrun_reg, status); + sci_serial_out(port, s->params->overrun_reg, status); port->icount.overrun++; @@ -1018,7 +1017,7 @@ static int sci_handle_fifo_overrun(struct uart_port *port) static int sci_handle_breaks(struct uart_port *port) { int copied = 0; - unsigned short status = serial_port_in(port, SCxSR); + unsigned short status = sci_serial_in(port, SCxSR); struct tty_port *tport = &port->state->port; if (uart_handle_break(port)) @@ -1051,7 +1050,7 @@ static int scif_set_rtrg(struct uart_port *port, int rx_trig) /* HSCIF can be set to an arbitrary level. */ if (sci_getreg(port, HSRTRGR)->size) { - serial_port_out(port, HSRTRGR, rx_trig); + sci_serial_out(port, HSRTRGR, rx_trig); return rx_trig; } @@ -1092,9 +1091,9 @@ static int scif_set_rtrg(struct uart_port *port, int rx_trig) return 1; } - serial_port_out(port, SCFCR, - (serial_port_in(port, SCFCR) & - ~(SCFCR_RTRG1 | SCFCR_RTRG0)) | bits); + sci_serial_out(port, SCFCR, + (sci_serial_in(port, SCFCR) & + ~(SCFCR_RTRG1 | SCFCR_RTRG0)) | bits); return rx_trig; } @@ -1102,9 +1101,9 @@ static int scif_set_rtrg(struct uart_port *port, int rx_trig) static int scif_rtrg_enabled(struct uart_port *port) { if (sci_getreg(port, HSRTRGR)->size) - return serial_port_in(port, HSRTRGR) != 0; + return sci_serial_in(port, HSRTRGR) != 0; else - return (serial_port_in(port, SCFCR) & + return (sci_serial_in(port, SCFCR) & (SCFCR_RTRG0 | SCFCR_RTRG1)) != 0; } @@ -1219,8 +1218,8 @@ static void sci_dma_tx_complete(void *arg) s->cookie_tx = -EINVAL; if (port->type == PORT_SCIFA || port->type == PORT_SCIFB || s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) { - u16 ctrl = serial_port_in(port, SCSCR); - serial_port_out(port, SCSCR, ctrl & ~SCSCR_TIE); + u16 ctrl = sci_serial_in(port, SCSCR); + sci_serial_out(port, SCSCR, ctrl & ~SCSCR_TIE); if (s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) { /* Switch irq from DMA to SCIF */ dmaengine_pause(s->chan_tx_saved); @@ -1296,7 +1295,7 @@ static void sci_dma_rx_reenable_irq(struct sci_port *s) u16 scr; /* Direct new serial port interrupts back to CPU */ - scr = serial_port_in(port, SCSCR); + scr = sci_serial_in(port, SCSCR); if (port->type == PORT_SCIFA || port->type == PORT_SCIFB || s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) { enable_irq(s->irqs[SCIx_RXI_IRQ]); @@ -1305,7 +1304,7 @@ static void sci_dma_rx_reenable_irq(struct sci_port *s) else scr &= ~SCSCR_RDRQE; } - serial_port_out(port, SCSCR, scr | SCSCR_RIE); + sci_serial_out(port, SCSCR, scr | SCSCR_RIE); } static void sci_dma_rx_complete(void *arg) @@ -1714,8 +1713,8 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr) #ifdef CONFIG_SERIAL_SH_SCI_DMA if (s->chan_rx) { - u16 scr = serial_port_in(port, SCSCR); - u16 ssr = serial_port_in(port, SCxSR); + u16 scr = sci_serial_in(port, SCSCR); + u16 ssr = sci_serial_in(port, SCxSR); /* Disable future Rx interrupts */ if (port->type == PORT_SCIFA || port->type == PORT_SCIFB || @@ -1733,10 +1732,10 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr) scr &= ~SCSCR_RIE; } - serial_port_out(port, SCSCR, scr); + sci_serial_out(port, SCSCR, scr); /* Clear current interrupt */ - serial_port_out(port, SCxSR, - ssr & ~(SCIF_DR | SCxSR_RDxF(port))); + sci_serial_out(port, SCxSR, + ssr & ~(SCIF_DR | SCxSR_RDxF(port))); dev_dbg(port->dev, "Rx IRQ %lu: setup t-out in %u us\n", jiffies, s->rx_timeout); start_hrtimer_us(&s->rx_timer, s->rx_timeout); @@ -1786,9 +1785,9 @@ static irqreturn_t sci_tx_end_interrupt(int irq, void *ptr) return sci_tx_interrupt(irq, ptr); uart_port_lock_irqsave(port, &flags); - ctrl = serial_port_in(port, SCSCR); + ctrl = sci_serial_in(port, SCSCR); ctrl &= ~(SCSCR_TE | SCSCR_TEIE); - serial_port_out(port, SCSCR, ctrl); + sci_serial_out(port, SCSCR, ctrl); uart_port_unlock_irqrestore(port, flags); return IRQ_HANDLED; @@ -1802,7 +1801,7 @@ static irqreturn_t sci_br_interrupt(int irq, void *ptr) sci_handle_breaks(port); /* drop invalid character received before break was detected */ - serial_port_in(port, SCxRDR); + sci_serial_in(port, SCxRDR); sci_clear_SCxSR(port, SCxSR_BREAK_CLEAR(port)); @@ -1816,7 +1815,7 @@ static irqreturn_t sci_er_interrupt(int irq, void *ptr) if (s->irqs[SCIx_ERI_IRQ] == s->irqs[SCIx_BRI_IRQ]) { /* Break and Error interrupts are muxed */ - unsigned short ssr_status = serial_port_in(port, SCxSR); + unsigned short ssr_status = sci_serial_in(port, SCxSR); /* Break Interrupt */ if (ssr_status & SCxSR_BRK(port)) @@ -1831,7 +1830,7 @@ static irqreturn_t sci_er_interrupt(int irq, void *ptr) if (port->type == PORT_SCI) { if (sci_handle_errors(port)) { /* discard character in rx buffer */ - serial_port_in(port, SCxSR); + sci_serial_in(port, SCxSR); sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); } } else { @@ -1856,12 +1855,12 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) struct sci_port *s = to_sci_port(port); irqreturn_t ret = IRQ_NONE; - ssr_status = serial_port_in(port, SCxSR); - scr_status = serial_port_in(port, SCSCR); + ssr_status = sci_serial_in(port, SCxSR); + scr_status = sci_serial_in(port, SCSCR); if (s->params->overrun_reg == SCxSR) orer_status = ssr_status; else if (sci_getreg(port, s->params->overrun_reg)->size) - orer_status = serial_port_in(port, s->params->overrun_reg); + orer_status = sci_serial_in(port, s->params->overrun_reg); err_enabled = scr_status & port_rx_irq_mask(port); @@ -2038,7 +2037,7 @@ static void sci_free_irq(struct sci_port *port) static unsigned int sci_tx_empty(struct uart_port *port) { - unsigned short status = serial_port_in(port, SCxSR); + unsigned short status = sci_serial_in(port, SCxSR); unsigned short in_tx_fifo = sci_txfill(port); return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0; @@ -2047,27 +2046,27 @@ static unsigned int sci_tx_empty(struct uart_port *port) static void sci_set_rts(struct uart_port *port, bool state) { if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - u16 data = serial_port_in(port, SCPDR); + u16 data = sci_serial_in(port, SCPDR); /* Active low */ if (state) data &= ~SCPDR_RTSD; else data |= SCPDR_RTSD; - serial_port_out(port, SCPDR, data); + sci_serial_out(port, SCPDR, data); /* RTS# is output */ - serial_port_out(port, SCPCR, - serial_port_in(port, SCPCR) | SCPCR_RTSC); + sci_serial_out(port, SCPCR, + sci_serial_in(port, SCPCR) | SCPCR_RTSC); } else if (sci_getreg(port, SCSPTR)->size) { - u16 ctrl = serial_port_in(port, SCSPTR); + u16 ctrl = sci_serial_in(port, SCSPTR); /* Active low */ if (state) ctrl &= ~SCSPTR_RTSDT; else ctrl |= SCSPTR_RTSDT; - serial_port_out(port, SCSPTR, ctrl); + sci_serial_out(port, SCSPTR, ctrl); } } @@ -2075,10 +2074,10 @@ static bool sci_get_cts(struct uart_port *port) { if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { /* Active low */ - return !(serial_port_in(port, SCPDR) & SCPDR_CTSD); + return !(sci_serial_in(port, SCPDR) & SCPDR_CTSD); } else if (sci_getreg(port, SCSPTR)->size) { /* Active low */ - return !(serial_port_in(port, SCSPTR) & SCSPTR_CTSDT); + return !(sci_serial_in(port, SCSPTR) & SCSPTR_CTSDT); } return true; @@ -2108,9 +2107,8 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl) */ reg = sci_getreg(port, SCFCR); if (reg->size) - serial_port_out(port, SCFCR, - serial_port_in(port, SCFCR) | - SCFCR_LOOP); + sci_serial_out(port, SCFCR, + sci_serial_in(port, SCFCR) | SCFCR_LOOP); } mctrl_gpio_set(s->gpios, mctrl); @@ -2120,21 +2118,21 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl) if (!(mctrl & TIOCM_RTS)) { /* Disable Auto RTS */ - serial_port_out(port, SCFCR, - serial_port_in(port, SCFCR) & ~SCFCR_MCE); + sci_serial_out(port, SCFCR, + sci_serial_in(port, SCFCR) & ~SCFCR_MCE); /* Clear RTS */ sci_set_rts(port, 0); } else if (s->autorts) { if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { /* Enable RTS# pin function */ - serial_port_out(port, SCPCR, - serial_port_in(port, SCPCR) & ~SCPCR_RTSC); + sci_serial_out(port, SCPCR, + sci_serial_in(port, SCPCR) & ~SCPCR_RTSC); } /* Enable Auto RTS */ - serial_port_out(port, SCFCR, - serial_port_in(port, SCFCR) | SCFCR_MCE); + sci_serial_out(port, SCFCR, + sci_serial_in(port, SCFCR) | SCFCR_MCE); } else { /* Set RTS */ sci_set_rts(port, 1); @@ -2187,8 +2185,8 @@ static void sci_break_ctl(struct uart_port *port, int break_state) } uart_port_lock_irqsave(port, &flags); - scsptr = serial_port_in(port, SCSPTR); - scscr = serial_port_in(port, SCSCR); + scsptr = sci_serial_in(port, SCSPTR); + scscr = sci_serial_in(port, SCSCR); if (break_state == -1) { scsptr = (scsptr | SCSPTR_SPB2IO) & ~SCSPTR_SPB2DT; @@ -2198,8 +2196,8 @@ static void sci_break_ctl(struct uart_port *port, int break_state) scscr |= SCSCR_TE; } - serial_port_out(port, SCSPTR, scsptr); - serial_port_out(port, SCSCR, scscr); + sci_serial_out(port, SCSPTR, scsptr); + sci_serial_out(port, SCSCR, scscr); uart_port_unlock_irqrestore(port, flags); } @@ -2239,9 +2237,9 @@ static void sci_shutdown(struct uart_port *port) * Stop RX and TX, disable related interrupts, keep clock source * and HSCIF TOT bits */ - scr = serial_port_in(port, SCSCR); - serial_port_out(port, SCSCR, scr & - (SCSCR_CKE1 | SCSCR_CKE0 | s->hscif_tot)); + scr = sci_serial_in(port, SCSCR); + sci_serial_out(port, SCSCR, + scr & (SCSCR_CKE1 | SCSCR_CKE0 | s->hscif_tot)); uart_port_unlock_irqrestore(port, flags); #ifdef CONFIG_SERIAL_SH_SCI_DMA @@ -2390,19 +2388,19 @@ static void sci_reset(struct uart_port *port) unsigned int status; struct sci_port *s = to_sci_port(port); - serial_port_out(port, SCSCR, s->hscif_tot); /* TE=0, RE=0, CKE1=0 */ + sci_serial_out(port, SCSCR, s->hscif_tot); /* TE=0, RE=0, CKE1=0 */ reg = sci_getreg(port, SCFCR); if (reg->size) - serial_port_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST); + sci_serial_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST); sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port) & SCxSR_ERROR_CLEAR(port) & SCxSR_BREAK_CLEAR(port)); if (sci_getreg(port, SCLSR)->size) { - status = serial_port_in(port, SCLSR); + status = sci_serial_in(port, SCLSR); status &= ~(SCLSR_TO | SCLSR_ORER); - serial_port_out(port, SCLSR, status); + sci_serial_out(port, SCLSR, status); } if (s->rx_trigger > 1) { @@ -2540,8 +2538,8 @@ done: * It controls the mux to select (H)SCK or frequency divided clock. */ if (best_clk >= 0 && sci_getreg(port, SCCKS)->size) { - serial_port_out(port, SCDL, dl); - serial_port_out(port, SCCKS, sccks); + sci_serial_out(port, SCDL, dl); + sci_serial_out(port, SCCKS, sccks); } uart_port_lock_irqsave(port, &flags); @@ -2554,7 +2552,7 @@ done: bits = tty_get_frame_size(termios->c_cflag); if (sci_getreg(port, SEMR)->size) - serial_port_out(port, SEMR, 0); + sci_serial_out(port, SEMR, 0); if (best_clk >= 0) { if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) @@ -2569,9 +2567,9 @@ done: case 27: smr_val |= SCSMR_SRC_27; break; } smr_val |= cks; - serial_port_out(port, SCSCR, scr_val | s->hscif_tot); - serial_port_out(port, SCSMR, smr_val); - serial_port_out(port, SCBRR, brr); + sci_serial_out(port, SCSCR, scr_val | s->hscif_tot); + sci_serial_out(port, SCSMR, smr_val); + sci_serial_out(port, SCBRR, brr); if (sci_getreg(port, HSSRR)->size) { unsigned int hssrr = srr | HSCIF_SRE; /* Calculate deviation from intended rate at the @@ -2593,7 +2591,7 @@ done: HSCIF_SRHP_MASK; hssrr |= HSCIF_SRDE; } - serial_port_out(port, HSSRR, hssrr); + sci_serial_out(port, HSSRR, hssrr); } /* Wait one bit interval */ @@ -2601,10 +2599,10 @@ done: } else { /* Don't touch the bit rate configuration */ scr_val = s->cfg->scscr & (SCSCR_CKE1 | SCSCR_CKE0); - smr_val |= serial_port_in(port, SCSMR) & + smr_val |= sci_serial_in(port, SCSMR) & (SCSMR_CKEDG | SCSMR_SRC_MASK | SCSMR_CKS); - serial_port_out(port, SCSCR, scr_val | s->hscif_tot); - serial_port_out(port, SCSMR, smr_val); + sci_serial_out(port, SCSCR, scr_val | s->hscif_tot); + sci_serial_out(port, SCSMR, smr_val); } sci_init_pins(port, termios->c_cflag); @@ -2613,7 +2611,7 @@ done: s->autorts = false; reg = sci_getreg(port, SCFCR); if (reg->size) { - unsigned short ctrl = serial_port_in(port, SCFCR); + unsigned short ctrl = sci_serial_in(port, SCFCR); if ((port->flags & UPF_HARD_FLOW) && (termios->c_cflag & CRTSCTS)) { @@ -2630,7 +2628,7 @@ done: */ ctrl &= ~(SCFCR_RFRST | SCFCR_TFRST); - serial_port_out(port, SCFCR, ctrl); + sci_serial_out(port, SCFCR, ctrl); } if (port->flags & UPF_HARD_FLOW) { /* Refresh (Auto) RTS */ @@ -2645,7 +2643,7 @@ done: if (port->type != PORT_SCI) scr_val |= SCSCR_TE; scr_val |= SCSCR_RE | (s->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0)); - serial_port_out(port, SCSCR, scr_val | s->hscif_tot); + sci_serial_out(port, SCSCR, scr_val | s->hscif_tot); if ((srr + 1 == 5) && (port->type == PORT_SCIFA || port->type == PORT_SCIFB)) { /* @@ -3017,9 +3015,6 @@ static int sci_init_single(struct platform_device *dev, port->irq = sci_port->irqs[SCIx_RXI_IRQ]; port->irqflags = 0; - port->serial_in = sci_serial_in; - port->serial_out = sci_serial_out; - return 0; } @@ -3056,21 +3051,21 @@ static void serial_console_write(struct console *co, const char *s, uart_port_lock_irqsave(port, &flags); /* first save SCSCR then disable interrupts, keep clock source */ - ctrl = serial_port_in(port, SCSCR); + ctrl = sci_serial_in(port, SCSCR); ctrl_temp = SCSCR_RE | SCSCR_TE | (sci_port->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0)) | (ctrl & (SCSCR_CKE1 | SCSCR_CKE0)); - serial_port_out(port, SCSCR, ctrl_temp | sci_port->hscif_tot); + sci_serial_out(port, SCSCR, ctrl_temp | sci_port->hscif_tot); uart_console_write(port, s, count, serial_console_putchar); /* wait until fifo is empty and last bit has been transmitted */ bits = SCxSR_TDxE(port) | SCxSR_TEND(port); - while ((serial_port_in(port, SCxSR) & bits) != bits) + while ((sci_serial_in(port, SCxSR) & bits) != bits) cpu_relax(); /* restore the SCSCR */ - serial_port_out(port, SCSCR, ctrl); + sci_serial_out(port, SCSCR, ctrl); if (locked) uart_port_unlock_irqrestore(port, flags); @@ -3503,8 +3498,6 @@ static int __init early_console_setup(struct earlycon_device *device, if (!device->port.membase) return -ENODEV; - device->port.serial_in = sci_serial_in; - device->port.serial_out = sci_serial_out; device->port.type = type; memcpy(&sci_ports[0].port, &device->port, sizeof(struct uart_port)); port_cfg.type = type; From 35c822a34b2293aedf475238c395e75858d1e8c8 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 4 Mar 2024 14:27:02 +0200 Subject: [PATCH 183/199] serial: core: Move struct uart_port::quirks closer to possible values Currently it's not crystal clear what UPIO_* and UPQ_* definitions belong to. Reindent the code, so it will be easy to read and understand. No functional changes intended. Reviewed-by: Andi Shyti Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240304123035.758700-2-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- include/linux/serial_core.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index bb0f2d4ac62f..f9d7f0a625fd 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -467,8 +467,8 @@ struct uart_port { unsigned int fifosize; /* tx fifo size */ unsigned char x_char; /* xon/xoff char */ unsigned char regshift; /* reg offset shift */ + unsigned char iotype; /* io access style */ - unsigned char quirks; /* internal quirks */ #define UPIO_PORT (SERIAL_IO_PORT) /* 8b I/O port access */ #define UPIO_HUB6 (SERIAL_IO_HUB6) /* Hub6 ISA card */ @@ -479,7 +479,9 @@ struct uart_port { #define UPIO_MEM32BE (SERIAL_IO_MEM32BE) /* 32b big endian */ #define UPIO_MEM16 (SERIAL_IO_MEM16) /* 16b little endian */ - /* quirks must be updated while holding port mutex */ + unsigned char quirks; /* internal quirks */ + + /* internal quirks must be updated while holding port mutex */ #define UPQ_NO_TXEN_TEST BIT(0) unsigned int read_status_mask; /* driver specific */ From 79d713baf63c8f23cc58b304c40be33d64a12aaf Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 4 Mar 2024 14:27:03 +0200 Subject: [PATCH 184/199] serial: core: Add UPIO_UNKNOWN constant for unknown port type In some APIs we would like to assign the special value to iotype and compare against it in another places. Introduce UPIO_UNKNOWN for this purpose. Note, we can't use 0, because it's a valid value for IO port access. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240304123035.758700-3-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- include/linux/serial_core.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index f9d7f0a625fd..3b64c9a26945 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -470,6 +470,7 @@ struct uart_port { unsigned char iotype; /* io access style */ +#define UPIO_UNKNOWN ((unsigned char)~0U) /* UCHAR_MAX */ #define UPIO_PORT (SERIAL_IO_PORT) /* 8b I/O port access */ #define UPIO_HUB6 (SERIAL_IO_HUB6) /* Hub6 ISA card */ #define UPIO_MEM (SERIAL_IO_MEM) /* driver-specific */ From e894b6005dce0ed621b2788d6a249708fb6f95f9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 4 Mar 2024 14:27:04 +0200 Subject: [PATCH 185/199] serial: port: Introduce a common helper to read properties Several serial drivers want to read the same or similar set of the port properties. Make a common helper for them. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240304123035.758700-4-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_port.c | 145 +++++++++++++++++++++++++++++++ include/linux/serial_core.h | 2 + 2 files changed, 147 insertions(+) diff --git a/drivers/tty/serial/serial_port.c b/drivers/tty/serial/serial_port.c index 88975a4df306..6779a008e67a 100644 --- a/drivers/tty/serial/serial_port.c +++ b/drivers/tty/serial/serial_port.c @@ -8,7 +8,10 @@ #include #include +#include +#include #include +#include #include #include @@ -82,6 +85,148 @@ void uart_remove_one_port(struct uart_driver *drv, struct uart_port *port) } EXPORT_SYMBOL(uart_remove_one_port); +/** + * __uart_read_properties - read firmware properties of the given UART port + * @port: corresponding port + * @use_defaults: apply defaults (when %true) or validate the values (when %false) + * + * The following device properties are supported: + * - clock-frequency (optional) + * - fifo-size (optional) + * - no-loopback-test (optional) + * - reg-shift (defaults may apply) + * - reg-offset (value may be validated) + * - reg-io-width (defaults may apply or value may be validated) + * - interrupts (OF only) + * - serial [alias ID] (OF only) + * + * If the port->dev is of struct platform_device type the interrupt line + * will be retrieved via platform_get_irq() call against that device. + * Otherwise it will be assigned by fwnode_irq_get() call. In both cases + * the index 0 of the resource is used. + * + * The caller is responsible to initialize the following fields of the @port + * ->dev (must be valid) + * ->flags + * ->mapbase + * ->mapsize + * ->regshift (if @use_defaults is false) + * before calling this function. Alternatively the above mentioned fields + * may be zeroed, in such case the only ones, that have associated properties + * found, will be set to the respective values. + * + * If no error happened, the ->irq, ->mapbase, ->mapsize will be altered. + * The ->iotype is always altered. + * + * When @use_defaults is true and the respective property is not found + * the following values will be applied: + * ->regshift = 0 + * In this case IRQ must be provided, otherwise an error will be returned. + * + * When @use_defaults is false and the respective property is found + * the following values will be validated: + * - reg-io-width (->iotype) + * - reg-offset (->mapsize against ->mapbase) + * + * Returns: 0 on success or negative errno on failure + */ +static int __uart_read_properties(struct uart_port *port, bool use_defaults) +{ + struct device *dev = port->dev; + u32 value; + int ret; + + /* Read optional UART functional clock frequency */ + device_property_read_u32(dev, "clock-frequency", &port->uartclk); + + /* Read the registers alignment (default: 8-bit) */ + ret = device_property_read_u32(dev, "reg-shift", &value); + if (ret) + port->regshift = use_defaults ? 0 : port->regshift; + else + port->regshift = value; + + /* Read the registers I/O access type (default: MMIO 8-bit) */ + ret = device_property_read_u32(dev, "reg-io-width", &value); + if (ret) { + port->iotype = UPIO_MEM; + } else { + switch (value) { + case 1: + port->iotype = UPIO_MEM; + break; + case 2: + port->iotype = UPIO_MEM16; + break; + case 4: + port->iotype = device_is_big_endian(dev) ? UPIO_MEM32BE : UPIO_MEM32; + break; + default: + if (!use_defaults) { + dev_err(dev, "Unsupported reg-io-width (%u)\n", value); + return -EINVAL; + } + port->iotype = UPIO_UNKNOWN; + break; + } + } + + /* Read the address mapping base offset (default: no offset) */ + ret = device_property_read_u32(dev, "reg-offset", &value); + if (ret) + value = 0; + + /* Check for shifted address mapping overflow */ + if (!use_defaults && port->mapsize < value) { + dev_err(dev, "reg-offset %u exceeds region size %pa\n", value, &port->mapsize); + return -EINVAL; + } + + port->mapbase += value; + port->mapsize -= value; + + /* Read optional FIFO size */ + device_property_read_u32(dev, "fifo-size", &port->fifosize); + + if (device_property_read_bool(dev, "no-loopback-test")) + port->flags |= UPF_SKIP_TEST; + + /* Get index of serial line, if found in DT aliases */ + ret = of_alias_get_id(dev_of_node(dev), "serial"); + if (ret >= 0) + port->line = ret; + + if (dev_is_platform(dev)) + ret = platform_get_irq(to_platform_device(dev), 0); + else + ret = fwnode_irq_get(dev_fwnode(dev), 0); + if (ret == -EPROBE_DEFER) + return ret; + if (ret > 0) + port->irq = ret; + else if (use_defaults) + /* By default IRQ support is mandatory */ + return ret; + else + port->irq = 0; + + port->flags |= UPF_SHARE_IRQ; + + return 0; +} + +int uart_read_port_properties(struct uart_port *port) +{ + return __uart_read_properties(port, true); +} +EXPORT_SYMBOL_GPL(uart_read_port_properties); + +int uart_read_and_validate_port_properties(struct uart_port *port) +{ + return __uart_read_properties(port, false); +} +EXPORT_SYMBOL_GPL(uart_read_and_validate_port_properties); + static struct device_driver serial_port_driver = { .name = "port", .suppress_bind_attrs = true, diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 3b64c9a26945..0a0f6e21d40e 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -963,6 +963,8 @@ int uart_register_driver(struct uart_driver *uart); void uart_unregister_driver(struct uart_driver *uart); int uart_add_one_port(struct uart_driver *reg, struct uart_port *port); void uart_remove_one_port(struct uart_driver *reg, struct uart_port *port); +int uart_read_port_properties(struct uart_port *port); +int uart_read_and_validate_port_properties(struct uart_port *port); bool uart_match_port(const struct uart_port *port1, const struct uart_port *port2); From dcdc7e09cfe31aa402f9b827a9c76ef7b9374859 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 4 Mar 2024 14:27:05 +0200 Subject: [PATCH 186/199] serial: 8250_aspeed_vuart: Switch to use uart_read_port_properties() Since we have now a common helper to read port properties use it instead of sparse home grown solution. Reviewed-by: Andi Shyti Signed-off-by: Andy Shevchenko Reviewed-by: Andrew Jeffery Link: https://lore.kernel.org/r/20240304123035.758700-5-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_aspeed_vuart.c | 50 +++++++-------------- 1 file changed, 15 insertions(+), 35 deletions(-) diff --git a/drivers/tty/serial/8250/8250_aspeed_vuart.c b/drivers/tty/serial/8250/8250_aspeed_vuart.c index 8c2aaf7af7b7..53d8eee9b1c8 100644 --- a/drivers/tty/serial/8250/8250_aspeed_vuart.c +++ b/drivers/tty/serial/8250/8250_aspeed_vuart.c @@ -419,8 +419,8 @@ static int aspeed_vuart_probe(struct platform_device *pdev) struct aspeed_vuart *vuart; struct device_node *np; struct resource *res; - u32 clk, prop, sirq[2]; int rc, sirq_polarity; + u32 prop, sirq[2]; struct clk *vclk; np = pdev->dev.of_node; @@ -447,53 +447,35 @@ static int aspeed_vuart_probe(struct platform_device *pdev) port.port.status = UPSTAT_SYNC_FIFO; port.port.dev = &pdev->dev; port.port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE); + port.port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_FIXED_PORT | UPF_FIXED_TYPE | + UPF_NO_THRE_TEST; port.bugs |= UART_BUG_TXRACE; rc = sysfs_create_group(&vuart->dev->kobj, &aspeed_vuart_attr_group); if (rc < 0) return rc; - if (of_property_read_u32(np, "clock-frequency", &clk)) { + rc = uart_read_port_properties(&port.port); + if (rc) + goto err_sysfs_remove; + + /* Get clk rate through clk driver if present */ + if (!port.port.uartclk) { vclk = devm_clk_get_enabled(dev, NULL); if (IS_ERR(vclk)) { rc = dev_err_probe(dev, PTR_ERR(vclk), "clk or clock-frequency not defined\n"); goto err_sysfs_remove; } - clk = clk_get_rate(vclk); + port.port.uartclk = clk_get_rate(vclk); } /* If current-speed was set, then try not to change it. */ if (of_property_read_u32(np, "current-speed", &prop) == 0) - port.port.custom_divisor = clk / (16 * prop); + port.port.custom_divisor = port.port.uartclk / (16 * prop); - /* Check for shifted address mapping */ - if (of_property_read_u32(np, "reg-offset", &prop) == 0) - port.port.mapbase += prop; - - /* Check for registers offset within the devices address range */ - if (of_property_read_u32(np, "reg-shift", &prop) == 0) - port.port.regshift = prop; - - /* Check for fifo size */ - if (of_property_read_u32(np, "fifo-size", &prop) == 0) - port.port.fifosize = prop; - - /* Check for a fixed line number */ - rc = of_alias_get_id(np, "serial"); - if (rc >= 0) - port.port.line = rc; - - port.port.irq = irq_of_parse_and_map(np, 0); port.port.handle_irq = aspeed_vuart_handle_irq; - port.port.iotype = UPIO_MEM; port.port.type = PORT_ASPEED_VUART; - port.port.uartclk = clk; - port.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP - | UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_NO_THRE_TEST; - - if (of_property_read_bool(np, "no-loopback-test")) - port.port.flags |= UPF_SKIP_TEST; if (port.port.fifosize) port.capabilities = UART_CAP_FIFO; @@ -503,7 +485,7 @@ static int aspeed_vuart_probe(struct platform_device *pdev) rc = serial8250_register_8250_port(&port); if (rc < 0) - goto err_clk_disable; + goto err_sysfs_remove; vuart->line = rc; vuart->port = serial8250_get_port(vuart->line); @@ -529,7 +511,7 @@ static int aspeed_vuart_probe(struct platform_device *pdev) rc = aspeed_vuart_set_lpc_address(vuart, prop); if (rc < 0) { dev_err_probe(dev, rc, "invalid value in aspeed,lpc-io-reg property\n"); - goto err_clk_disable; + goto err_sysfs_remove; } rc = of_property_read_u32_array(np, "aspeed,lpc-interrupts", sirq, 2); @@ -541,14 +523,14 @@ static int aspeed_vuart_probe(struct platform_device *pdev) rc = aspeed_vuart_set_sirq(vuart, sirq[0]); if (rc < 0) { dev_err_probe(dev, rc, "invalid sirq number in aspeed,lpc-interrupts property\n"); - goto err_clk_disable; + goto err_sysfs_remove; } sirq_polarity = aspeed_vuart_map_irq_polarity(sirq[1]); if (sirq_polarity < 0) { rc = dev_err_probe(dev, sirq_polarity, "invalid sirq polarity in aspeed,lpc-interrupts property\n"); - goto err_clk_disable; + goto err_sysfs_remove; } aspeed_vuart_set_sirq_polarity(vuart, sirq_polarity); @@ -559,8 +541,6 @@ static int aspeed_vuart_probe(struct platform_device *pdev) return 0; -err_clk_disable: - irq_dispose_mapping(port.port.irq); err_sysfs_remove: sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group); return rc; From eb687309136b9f4abcc081630ee31a139c54c400 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 4 Mar 2024 14:27:06 +0200 Subject: [PATCH 187/199] serial: 8250_bcm2835aux: Switch to use uart_read_port_properties() Since we have now a common helper to read port properties use it instead of sparse home grown solution. Signed-off-by: Andy Shevchenko Reviewed-by: Florian Fainelli Tested-by: Florian Fainelli Link: https://lore.kernel.org/r/20240304123035.758700-6-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_bcm2835aux.c | 92 +++++++++++------------ 1 file changed, 42 insertions(+), 50 deletions(-) diff --git a/drivers/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c index beac6b340ace..121a5ce86050 100644 --- a/drivers/tty/serial/8250/8250_bcm2835aux.c +++ b/drivers/tty/serial/8250/8250_bcm2835aux.c @@ -45,10 +45,6 @@ struct bcm2835aux_data { u32 cntl; }; -struct bcm2835_aux_serial_driver_data { - resource_size_t offset; -}; - static void bcm2835aux_rs485_start_tx(struct uart_8250_port *up) { if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) { @@ -85,10 +81,9 @@ static void bcm2835aux_rs485_stop_tx(struct uart_8250_port *up) static int bcm2835aux_serial_probe(struct platform_device *pdev) { - const struct bcm2835_aux_serial_driver_data *bcm_data; + const struct software_node *bcm2835_swnode; struct uart_8250_port up = { }; struct bcm2835aux_data *data; - resource_size_t offset = 0; struct resource *res; unsigned int uartclk; int ret; @@ -101,12 +96,8 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev) /* initialize data */ up.capabilities = UART_CAP_FIFO | UART_CAP_MINI; up.port.dev = &pdev->dev; - up.port.regshift = 2; up.port.type = PORT_16550; - up.port.iotype = UPIO_MEM; - up.port.fifosize = 8; - up.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE | - UPF_SKIP_TEST | UPF_IOREMAP; + up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SKIP_TEST | UPF_IOREMAP; up.port.rs485_config = serial8250_em485_config; up.port.rs485_supported = serial8250_em485_supported; up.rs485_start_tx = bcm2835aux_rs485_start_tx; @@ -122,12 +113,6 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev) if (IS_ERR(data->clk)) return dev_err_probe(&pdev->dev, PTR_ERR(data->clk), "could not get clk\n"); - /* get the interrupt */ - ret = platform_get_irq(pdev, 0); - if (ret < 0) - return ret; - up.port.irq = ret; - /* map the main registers */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { @@ -135,52 +120,40 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev) return -EINVAL; } - bcm_data = device_get_match_data(&pdev->dev); + up.port.mapbase = res->start; + up.port.mapsize = resource_size(res); - /* Some UEFI implementations (e.g. tianocore/edk2 for the Raspberry Pi) - * describe the miniuart with a base address that encompasses the auxiliary - * registers shared between the miniuart and spi. - * - * This is due to historical reasons, see discussion here : - * https://edk2.groups.io/g/devel/topic/87501357#84349 - * - * We need to add the offset between the miniuart and auxiliary - * registers to get the real miniuart base address. - */ - if (bcm_data) - offset = bcm_data->offset; + bcm2835_swnode = device_get_match_data(&pdev->dev); + if (bcm2835_swnode) { + ret = device_add_software_node(&pdev->dev, bcm2835_swnode); + if (ret) + return ret; + } - up.port.mapbase = res->start + offset; - up.port.mapsize = resource_size(res) - offset; + ret = uart_read_port_properties(&up.port); + if (ret) + goto rm_swnode; - /* Check for a fixed line number */ - ret = of_alias_get_id(pdev->dev.of_node, "serial"); - if (ret >= 0) - up.port.line = ret; + up.port.regshift = 2; + up.port.fifosize = 8; /* enable the clock as a last step */ ret = clk_prepare_enable(data->clk); if (ret) { - dev_err(&pdev->dev, "unable to enable uart clock - %d\n", - ret); - return ret; + dev_err_probe(&pdev->dev, ret, "unable to enable uart clock\n"); + goto rm_swnode; } uartclk = clk_get_rate(data->clk); - if (!uartclk) { - ret = device_property_read_u32(&pdev->dev, "clock-frequency", &uartclk); - if (ret) { - dev_err_probe(&pdev->dev, ret, "could not get clk rate\n"); - goto dis_clk; - } - } + if (uartclk) + up.port.uartclk = uartclk; /* the HW-clock divider for bcm2835aux is 8, * but 8250 expects a divider of 16, * so we have to multiply the actual clock by 2 * to get identical baudrates. */ - up.port.uartclk = uartclk * 2; + up.port.uartclk *= 2; /* register the port */ ret = serial8250_register_8250_port(&up); @@ -194,6 +167,8 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev) dis_clk: clk_disable_unprepare(data->clk); +rm_swnode: + device_remove_software_node(&pdev->dev); return ret; } @@ -203,10 +178,27 @@ static void bcm2835aux_serial_remove(struct platform_device *pdev) serial8250_unregister_port(data->line); clk_disable_unprepare(data->clk); + device_remove_software_node(&pdev->dev); } -static const struct bcm2835_aux_serial_driver_data bcm2835_acpi_data = { - .offset = 0x40, +/* + * Some UEFI implementations (e.g. tianocore/edk2 for the Raspberry Pi) + * describe the miniuart with a base address that encompasses the auxiliary + * registers shared between the miniuart and spi. + * + * This is due to historical reasons, see discussion here: + * https://edk2.groups.io/g/devel/topic/87501357#84349 + * + * We need to add the offset between the miniuart and auxiliary registers + * to get the real miniuart base address. + */ +static const struct property_entry bcm2835_acpi_properties[] = { + PROPERTY_ENTRY_U32("reg-offset", 0x40), + { } +}; + +static const struct software_node bcm2835_acpi_node = { + .properties = bcm2835_acpi_properties, }; static const struct of_device_id bcm2835aux_serial_match[] = { @@ -216,7 +208,7 @@ static const struct of_device_id bcm2835aux_serial_match[] = { MODULE_DEVICE_TABLE(of, bcm2835aux_serial_match); static const struct acpi_device_id bcm2835aux_serial_acpi_match[] = { - { "BCM2836", (kernel_ulong_t)&bcm2835_acpi_data }, + { "BCM2836", (kernel_ulong_t)&bcm2835_acpi_node }, { } }; MODULE_DEVICE_TABLE(acpi, bcm2835aux_serial_acpi_match); From 573d97545c2ec53ab5c7c5870287e81eff0d6d00 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 4 Mar 2024 14:27:07 +0200 Subject: [PATCH 188/199] serial: 8250_bcm7271: Switch to use uart_read_port_properties() Since we have now a common helper to read port properties use it instead of sparse home grown solution. Signed-off-by: Andy Shevchenko Reviewed-by: Florian Fainelli Tested-by: Florian Fainelli Link: https://lore.kernel.org/r/20240304123035.758700-7-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_bcm7271.c | 56 +++++++++----------------- 1 file changed, 19 insertions(+), 37 deletions(-) diff --git a/drivers/tty/serial/8250/8250_bcm7271.c b/drivers/tty/serial/8250/8250_bcm7271.c index 1532fa2e8ec4..5daa38d9c64e 100644 --- a/drivers/tty/serial/8250/8250_bcm7271.c +++ b/drivers/tty/serial/8250/8250_bcm7271.c @@ -935,17 +935,14 @@ static void brcmuart_init_debugfs(struct brcmuart_priv *priv, static int brcmuart_probe(struct platform_device *pdev) { struct resource *regs; - struct device_node *np = pdev->dev.of_node; const struct of_device_id *of_id = NULL; struct uart_8250_port *new_port; struct device *dev = &pdev->dev; struct brcmuart_priv *priv; struct clk *baud_mux_clk; struct uart_8250_port up; - int irq; void __iomem *membase = NULL; resource_size_t mapbase = 0; - u32 clk_rate = 0; int ret; int x; int dma_irq; @@ -953,15 +950,12 @@ static int brcmuart_probe(struct platform_device *pdev) "uart", "dma_rx", "dma_tx", "dma_intr2", "dma_arb" }; - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; priv = devm_kzalloc(dev, sizeof(struct brcmuart_priv), GFP_KERNEL); if (!priv) return -ENOMEM; - of_id = of_match_node(brcmuart_dt_ids, np); + of_id = of_match_node(brcmuart_dt_ids, dev->of_node); if (!of_id || !of_id->data) priv->rate_table = brcmstb_rate_table; else @@ -1011,7 +1005,23 @@ static int brcmuart_probe(struct platform_device *pdev) } } - of_property_read_u32(np, "clock-frequency", &clk_rate); + dev_dbg(dev, "DMA is %senabled\n", priv->dma_enabled ? "" : "not "); + + memset(&up, 0, sizeof(up)); + up.port.type = PORT_BCM7271; + up.port.dev = dev; + up.port.mapbase = mapbase; + up.port.membase = membase; + up.port.handle_irq = brcmuart_handle_irq; + up.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_FIXED_TYPE; + up.port.private_data = priv; + + ret = uart_read_port_properties(&up.port); + if (ret) + goto release_dma; + + up.port.regshift = 2; + up.port.iotype = device_is_big_endian(dev) ? UPIO_MEM32BE : UPIO_MEM32; /* See if a Baud clock has been specified */ baud_mux_clk = devm_clk_get_optional_enabled(dev, "sw_baud"); @@ -1023,39 +1033,11 @@ static int brcmuart_probe(struct platform_device *pdev) priv->baud_mux_clk = baud_mux_clk; init_real_clk_rates(dev, priv); - clk_rate = priv->default_mux_rate; + up.port.uartclk = priv->default_mux_rate; } else { dev_dbg(dev, "BAUD MUX clock not specified\n"); } - if (clk_rate == 0) { - ret = dev_err_probe(dev, -EINVAL, "clock-frequency or clk not defined\n"); - goto release_dma; - } - - dev_dbg(dev, "DMA is %senabled\n", priv->dma_enabled ? "" : "not "); - - memset(&up, 0, sizeof(up)); - up.port.type = PORT_BCM7271; - up.port.uartclk = clk_rate; - up.port.dev = dev; - up.port.mapbase = mapbase; - up.port.membase = membase; - up.port.irq = irq; - up.port.handle_irq = brcmuart_handle_irq; - up.port.regshift = 2; - up.port.iotype = of_device_is_big_endian(np) ? - UPIO_MEM32BE : UPIO_MEM32; - up.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF - | UPF_FIXED_PORT | UPF_FIXED_TYPE; - up.port.dev = dev; - up.port.private_data = priv; - - /* Check for a fixed line number */ - ret = of_alias_get_id(np, "serial"); - if (ret >= 0) - up.port.line = ret; - /* setup HR timer */ hrtimer_init(&priv->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); priv->hrt.function = brcmuart_hrtimer_func; From e6a46d073e11baba785245860c9f51adbbb8b68d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 4 Mar 2024 14:27:08 +0200 Subject: [PATCH 189/199] serial: 8250_dw: Switch to use uart_read_port_properties() Since we have now a common helper to read port properties use it instead of sparse home grown solution. Reviewed-by: Andi Shyti Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240304123035.758700-8-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 67 +++++++++++++------------------ 1 file changed, 27 insertions(+), 40 deletions(-) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 94aa3dddb71e..e369b429e060 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -449,12 +448,7 @@ static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data) if (np) { unsigned int quirks = data->pdata->quirks; - int id; - /* get index of serial line, if found in DT aliases */ - id = of_alias_get_id(np, "serial"); - if (id >= 0) - p->line = id; #ifdef CONFIG_64BIT if (quirks & DW_UART_QUIRK_OCTEON) { p->serial_in = dw8250_serial_inq; @@ -465,12 +459,6 @@ static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data) } #endif - if (of_device_is_big_endian(np)) { - p->iotype = UPIO_MEM32BE; - p->serial_in = dw8250_serial_in32be; - p->serial_out = dw8250_serial_out32be; - } - if (quirks & DW_UART_QUIRK_ARMADA_38X) p->serial_out = dw8250_serial_out38x; if (quirks & DW_UART_QUIRK_SKIP_SET_RATE) @@ -510,39 +498,21 @@ static int dw8250_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct dw8250_data *data; struct resource *regs; - int irq; int err; - u32 val; regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!regs) return dev_err_probe(dev, -EINVAL, "no registers defined\n"); - irq = platform_get_irq_optional(pdev, 0); - /* no interrupt -> fall back to polling */ - if (irq == -ENXIO) - irq = 0; - if (irq < 0) - return irq; - spin_lock_init(&p->lock); - p->mapbase = regs->start; - p->irq = irq; p->handle_irq = dw8250_handle_irq; p->pm = dw8250_do_pm; p->type = PORT_8250; - p->flags = UPF_SHARE_IRQ | UPF_FIXED_PORT; + p->flags = UPF_FIXED_PORT; p->dev = dev; - p->iotype = UPIO_MEM; - p->serial_in = dw8250_serial_in; - p->serial_out = dw8250_serial_out; p->set_ldisc = dw8250_set_ldisc; p->set_termios = dw8250_set_termios; - p->membase = devm_ioremap(dev, regs->start, resource_size(regs)); - if (!p->membase) - return -ENOMEM; - data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; @@ -554,15 +524,35 @@ static int dw8250_probe(struct platform_device *pdev) data->uart_16550_compatible = device_property_read_bool(dev, "snps,uart-16550-compatible"); - err = device_property_read_u32(dev, "reg-shift", &val); - if (!err) - p->regshift = val; + p->mapbase = regs->start; + p->mapsize = resource_size(regs); - err = device_property_read_u32(dev, "reg-io-width", &val); - if (!err && val == 4) { - p->iotype = UPIO_MEM32; + p->membase = devm_ioremap(dev, p->mapbase, p->mapsize); + if (!p->membase) + return -ENOMEM; + + err = uart_read_port_properties(p); + /* no interrupt -> fall back to polling */ + if (err == -ENXIO) + err = 0; + if (err) + return err; + + switch (p->iotype) { + case UPIO_MEM: + p->serial_in = dw8250_serial_in; + p->serial_out = dw8250_serial_out; + break; + case UPIO_MEM32: p->serial_in = dw8250_serial_in32; p->serial_out = dw8250_serial_out32; + break; + case UPIO_MEM32BE: + p->serial_in = dw8250_serial_in32be; + p->serial_out = dw8250_serial_out32be; + break; + default: + return -ENODEV; } if (device_property_read_bool(dev, "dcd-override")) { @@ -589,9 +579,6 @@ static int dw8250_probe(struct platform_device *pdev) data->msr_mask_off |= UART_MSR_TERI; } - /* Always ask for fixed clock rate from a property. */ - device_property_read_u32(dev, "clock-frequency", &p->uartclk); - /* If there is separate baudclk, get the rate from it. */ data->clk = devm_clk_get_optional_enabled(dev, "baudclk"); if (data->clk == NULL) From d6bd42f2c2a8f26d49516dd055420f0d6743b8c7 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 4 Mar 2024 14:27:09 +0200 Subject: [PATCH 190/199] serial: 8250_ingenic: Switch to use uart_read_port_properties() Since we have now a common helper to read port properties use it instead of sparse home grown solution. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240304123035.758700-9-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_ingenic.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c index a12f737924c0..a2783e38a2e3 100644 --- a/drivers/tty/serial/8250/8250_ingenic.c +++ b/drivers/tty/serial/8250/8250_ingenic.c @@ -234,7 +234,7 @@ static int ingenic_uart_probe(struct platform_device *pdev) struct ingenic_uart_data *data; const struct ingenic_uart_config *cdata; struct resource *regs; - int irq, err, line; + int err; cdata = of_device_get_match_data(&pdev->dev); if (!cdata) { @@ -242,10 +242,6 @@ static int ingenic_uart_probe(struct platform_device *pdev) return -ENODEV; } - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; - regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!regs) { dev_err(&pdev->dev, "no registers defined\n"); @@ -259,21 +255,19 @@ static int ingenic_uart_probe(struct platform_device *pdev) spin_lock_init(&uart.port.lock); uart.port.type = PORT_16550A; uart.port.flags = UPF_SKIP_TEST | UPF_IOREMAP | UPF_FIXED_TYPE; - uart.port.iotype = UPIO_MEM; uart.port.mapbase = regs->start; - uart.port.regshift = 2; uart.port.serial_out = ingenic_uart_serial_out; uart.port.serial_in = ingenic_uart_serial_in; - uart.port.irq = irq; uart.port.dev = &pdev->dev; - uart.port.fifosize = cdata->fifosize; uart.tx_loadsz = cdata->tx_loadsz; uart.capabilities = UART_CAP_FIFO | UART_CAP_RTOIE; - /* Check for a fixed line number */ - line = of_alias_get_id(pdev->dev.of_node, "serial"); - if (line >= 0) - uart.port.line = line; + err = uart_read_port_properties(&uart.port); + if (err) + return err; + + uart.port.regshift = 2; + uart.port.fifosize = cdata->fifosize; uart.port.membase = devm_ioremap(&pdev->dev, regs->start, resource_size(regs)); From 0087b9e694ee01c61fa4e954198293fff172496d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 4 Mar 2024 14:27:10 +0200 Subject: [PATCH 191/199] serial: 8250_lpc18xx: Switch to use uart_read_port_properties() Since we have now a common helper to read port properties use it instead of sparse home grown solution. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240304123035.758700-10-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_lpc18xx.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/tty/serial/8250/8250_lpc18xx.c b/drivers/tty/serial/8250/8250_lpc18xx.c index 8d728a6a5991..7984ee05af1d 100644 --- a/drivers/tty/serial/8250/8250_lpc18xx.c +++ b/drivers/tty/serial/8250/8250_lpc18xx.c @@ -92,11 +92,7 @@ static int lpc18xx_serial_probe(struct platform_device *pdev) struct lpc18xx_uart_data *data; struct uart_8250_port uart; struct resource *res; - int irq, ret; - - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; + int ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { @@ -139,19 +135,12 @@ static int lpc18xx_serial_probe(struct platform_device *pdev) goto dis_clk_reg; } - ret = of_alias_get_id(pdev->dev.of_node, "serial"); - if (ret >= 0) - uart.port.line = ret; - data->dma.rx_param = data; data->dma.tx_param = data; spin_lock_init(&uart.port.lock); uart.port.dev = &pdev->dev; - uart.port.irq = irq; - uart.port.iotype = UPIO_MEM32; uart.port.mapbase = res->start; - uart.port.regshift = 2; uart.port.type = PORT_16550A; uart.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SKIP_TEST; uart.port.uartclk = clk_get_rate(data->clk_uart); @@ -160,6 +149,13 @@ static int lpc18xx_serial_probe(struct platform_device *pdev) uart.port.rs485_supported = lpc18xx_rs485_supported; uart.port.serial_out = lpc18xx_uart_serial_out; + ret = uart_read_port_properties(&uart.port); + if (ret) + return ret; + + uart.port.iotype = UPIO_MEM32; + uart.port.regshift = 2; + uart.dma = &data->dma; uart.dma->rxconf.src_maxburst = 1; uart.dma->txconf.dst_maxburst = 1; From 1117a6fdc7c14d6fa336cf135e81e716d20d11c1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 4 Mar 2024 14:27:11 +0200 Subject: [PATCH 192/199] serial: 8250_of: Switch to use uart_read_port_properties() Since we have now a common helper to read port properties use it instead of sparse home grown solution. Reviewed-by: Andi Shyti Signed-off-by: Andy Shevchenko Reviewed-by: Florian Fainelli Tested-by: Florian Fainelli Link: https://lore.kernel.org/r/20240304123035.758700-11-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_of.c | 105 +++++++----------------------- 1 file changed, 22 insertions(+), 83 deletions(-) diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c index 9dcc17e33269..5d1dd992d8fb 100644 --- a/drivers/tty/serial/8250/8250_of.c +++ b/drivers/tty/serial/8250/8250_of.c @@ -69,37 +69,22 @@ static int of_platform_serial_setup(struct platform_device *ofdev, struct device *dev = &ofdev->dev; struct device_node *np = dev->of_node; struct uart_port *port = &up->port; - u32 clk, spd, prop; - int ret, irq; + u32 spd; + int ret; memset(port, 0, sizeof *port); pm_runtime_enable(&ofdev->dev); pm_runtime_get_sync(&ofdev->dev); - if (of_property_read_u32(np, "clock-frequency", &clk)) { - - /* Get clk rate through clk driver if present */ - info->clk = devm_clk_get_enabled(dev, NULL); - if (IS_ERR(info->clk)) { - ret = dev_err_probe(dev, PTR_ERR(info->clk), "failed to get clock\n"); - goto err_pmruntime; - } - - clk = clk_get_rate(info->clk); - } - /* If current-speed was set, then try not to change it. */ - if (of_property_read_u32(np, "current-speed", &spd) == 0) - port->custom_divisor = clk / (16 * spd); - ret = of_address_to_resource(np, 0, &resource); if (ret) { dev_err_probe(dev, ret, "invalid address\n"); goto err_pmruntime; } - port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | - UPF_FIXED_TYPE; + port->dev = &ofdev->dev; + port->flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_FIXED_TYPE; spin_lock_init(&port->lock); if (resource_type(&resource) == IORESOURCE_IO) { @@ -108,70 +93,31 @@ static int of_platform_serial_setup(struct platform_device *ofdev, } else { port->mapbase = resource.start; port->mapsize = resource_size(&resource); - - /* Check for shifted address mapping */ - if (of_property_read_u32(np, "reg-offset", &prop) == 0) { - if (prop >= port->mapsize) { - ret = dev_err_probe(dev, -EINVAL, "reg-offset %u exceeds region size %pa\n", - prop, &port->mapsize); - goto err_pmruntime; - } - - port->mapbase += prop; - port->mapsize -= prop; - } - - port->iotype = UPIO_MEM; - if (of_property_read_u32(np, "reg-io-width", &prop) == 0) { - switch (prop) { - case 1: - port->iotype = UPIO_MEM; - break; - case 2: - port->iotype = UPIO_MEM16; - break; - case 4: - port->iotype = of_device_is_big_endian(np) ? - UPIO_MEM32BE : UPIO_MEM32; - break; - default: - ret = dev_err_probe(dev, -EINVAL, "unsupported reg-io-width (%u)\n", - prop); - goto err_pmruntime; - } - } port->flags |= UPF_IOREMAP; } + ret = uart_read_and_validate_port_properties(port); + if (ret) + goto err_pmruntime; + + /* Get clk rate through clk driver if present */ + if (!port->uartclk) { + info->clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(info->clk)) { + ret = dev_err_probe(dev, PTR_ERR(info->clk), "failed to get clock\n"); + goto err_pmruntime; + } + + port->uartclk = clk_get_rate(info->clk); + } + /* If current-speed was set, then try not to change it. */ + if (of_property_read_u32(np, "current-speed", &spd) == 0) + port->custom_divisor = port->uartclk / (16 * spd); + /* Compatibility with the deprecated pxa driver and 8250_pxa drivers. */ if (of_device_is_compatible(np, "mrvl,mmp-uart")) port->regshift = 2; - /* Check for registers offset within the devices address range */ - if (of_property_read_u32(np, "reg-shift", &prop) == 0) - port->regshift = prop; - - /* Check for fifo size */ - if (of_property_read_u32(np, "fifo-size", &prop) == 0) - port->fifosize = prop; - - /* Check for a fixed line number */ - ret = of_alias_get_id(np, "serial"); - if (ret >= 0) - port->line = ret; - - irq = of_irq_get(np, 0); - if (irq < 0) { - if (irq == -EPROBE_DEFER) { - ret = -EPROBE_DEFER; - goto err_pmruntime; - } - /* IRQ support not mandatory */ - irq = 0; - } - - port->irq = irq; - info->rst = devm_reset_control_get_optional_shared(&ofdev->dev, NULL); if (IS_ERR(info->rst)) { ret = PTR_ERR(info->rst); @@ -183,12 +129,6 @@ static int of_platform_serial_setup(struct platform_device *ofdev, goto err_pmruntime; port->type = type; - port->uartclk = clk; - - if (of_property_read_bool(np, "no-loopback-test")) - port->flags |= UPF_SKIP_TEST; - - port->dev = &ofdev->dev; port->rs485_config = serial8250_em485_config; port->rs485_supported = serial8250_em485_supported; up->rs485_start_tx = serial8250_em485_start_tx; @@ -280,7 +220,6 @@ static int of_platform_serial_probe(struct platform_device *ofdev) platform_set_drvdata(ofdev, info); return 0; err_dispose: - irq_dispose_mapping(port8250.port.irq); pm_runtime_put_sync(&ofdev->dev); pm_runtime_disable(&ofdev->dev); err_free: From 664f5d035f456af4aabad981db1cbd9cb7956888 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 4 Mar 2024 14:27:12 +0200 Subject: [PATCH 193/199] serial: 8250_omap: Switch to use uart_read_port_properties() Since we have now a common helper to read port properties use it instead of sparse home grown solution. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240304123035.758700-12-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_omap.c | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 6942990a333c..66901d93089a 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -1394,11 +1394,7 @@ static int omap8250_probe(struct platform_device *pdev) struct uart_8250_port up; struct resource *regs; void __iomem *membase; - int irq, ret; - - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; + int ret; regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!regs) { @@ -1419,7 +1415,6 @@ static int omap8250_probe(struct platform_device *pdev) up.port.dev = &pdev->dev; up.port.mapbase = regs->start; up.port.membase = membase; - up.port.irq = irq; /* * It claims to be 16C750 compatible however it is a little different. * It has EFR and has no FCR7_64byte bit. The AFE (which it claims to @@ -1429,13 +1424,9 @@ static int omap8250_probe(struct platform_device *pdev) * or pm callback. */ up.port.type = PORT_8250; - up.port.iotype = UPIO_MEM; - up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SOFT_FLOW | - UPF_HARD_FLOW; + up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SOFT_FLOW | UPF_HARD_FLOW; up.port.private_data = priv; - up.port.regshift = OMAP_UART_REGSHIFT; - up.port.fifosize = 64; up.tx_loadsz = 64; up.capabilities = UART_CAP_FIFO; #ifdef CONFIG_PM @@ -1461,14 +1452,14 @@ static int omap8250_probe(struct platform_device *pdev) up.rs485_stop_tx = serial8250_em485_stop_tx; up.port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE); - ret = of_alias_get_id(np, "serial"); - if (ret < 0) { - dev_err(&pdev->dev, "failed to get alias\n"); + ret = uart_read_port_properties(&up.port); + if (ret) return ret; - } - up.port.line = ret; - if (of_property_read_u32(np, "clock-frequency", &up.port.uartclk)) { + up.port.regshift = OMAP_UART_REGSHIFT; + up.port.fifosize = 64; + + if (!up.port.uartclk) { struct clk *clk; clk = devm_clk_get(&pdev->dev, NULL); @@ -1560,8 +1551,8 @@ static int omap8250_probe(struct platform_device *pdev) } #endif - irq_set_status_flags(irq, IRQ_NOAUTOEN); - ret = devm_request_irq(&pdev->dev, irq, omap8250_irq, 0, + irq_set_status_flags(up.port.irq, IRQ_NOAUTOEN); + ret = devm_request_irq(&pdev->dev, up.port.irq, omap8250_irq, 0, dev_name(&pdev->dev), priv); if (ret < 0) return ret; From cc6628f07e0d994f92f04cd71755a3bf95667a14 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 4 Mar 2024 14:27:13 +0200 Subject: [PATCH 194/199] serial: 8250_pxa: Switch to use uart_read_port_properties() Since we have now a common helper to read port properties use it instead of sparse home grown solution. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240304123035.758700-13-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pxa.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/drivers/tty/serial/8250/8250_pxa.c b/drivers/tty/serial/8250/8250_pxa.c index 77686da42ce8..f1a51b00b1b9 100644 --- a/drivers/tty/serial/8250/8250_pxa.c +++ b/drivers/tty/serial/8250/8250_pxa.c @@ -92,11 +92,7 @@ static int serial_pxa_probe(struct platform_device *pdev) struct uart_8250_port uart = {}; struct pxa8250_data *data; struct resource *mmres; - int irq, ret; - - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; + int ret; mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mmres) @@ -114,21 +110,21 @@ static int serial_pxa_probe(struct platform_device *pdev) if (ret) return ret; - ret = of_alias_get_id(pdev->dev.of_node, "serial"); - if (ret >= 0) - uart.port.line = ret; - uart.port.type = PORT_XSCALE; - uart.port.iotype = UPIO_MEM32; uart.port.mapbase = mmres->start; - uart.port.regshift = 2; - uart.port.irq = irq; - uart.port.fifosize = 64; uart.port.flags = UPF_IOREMAP | UPF_SKIP_TEST | UPF_FIXED_TYPE; uart.port.dev = &pdev->dev; uart.port.uartclk = clk_get_rate(data->clk); uart.port.pm = serial_pxa_pm; uart.port.private_data = data; + + ret = uart_read_port_properties(&uart.port); + if (ret) + return ret; + + uart.port.iotype = UPIO_MEM32; + uart.port.regshift = 2; + uart.port.fifosize = 64; uart.dl_write = serial_pxa_dl_write; ret = serial8250_register_8250_port(&uart); From 266bc29dad6a74951bd23260ea5da89964898808 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 4 Mar 2024 14:27:14 +0200 Subject: [PATCH 195/199] serial: 8250_tegra: Switch to use uart_read_port_properties() Since we have now a common helper to read port properties use it instead of sparse home grown solution. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240304123035.758700-14-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_tegra.c | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/drivers/tty/serial/8250/8250_tegra.c b/drivers/tty/serial/8250/8250_tegra.c index ba352262df75..60a80d00d251 100644 --- a/drivers/tty/serial/8250/8250_tegra.c +++ b/drivers/tty/serial/8250/8250_tegra.c @@ -57,25 +57,11 @@ static int tegra_uart_probe(struct platform_device *pdev) port = &port8250.port; spin_lock_init(&port->lock); - port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | - UPF_FIXED_TYPE; - port->iotype = UPIO_MEM32; - port->regshift = 2; + port->flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_FIXED_TYPE; port->type = PORT_TEGRA; - port->irqflags |= IRQF_SHARED; port->dev = &pdev->dev; port->handle_break = tegra_uart_handle_break; - ret = of_alias_get_id(pdev->dev.of_node, "serial"); - if (ret >= 0) - port->line = ret; - - ret = platform_get_irq(pdev, 0); - if (ret < 0) - return ret; - - port->irq = ret; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENODEV; @@ -88,12 +74,18 @@ static int tegra_uart_probe(struct platform_device *pdev) port->mapbase = res->start; port->mapsize = resource_size(res); + ret = uart_read_port_properties(port); + if (ret) + return ret; + + port->iotype = UPIO_MEM32; + port->regshift = 2; + uart->rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL); if (IS_ERR(uart->rst)) return PTR_ERR(uart->rst); - if (device_property_read_u32(&pdev->dev, "clock-frequency", - &port->uartclk)) { + if (!port->uartclk) { uart->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(uart->clk)) { dev_err(&pdev->dev, "failed to get clock!\n"); From 26e8349c0d7624322e2daf9f062bc0338919a952 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 4 Mar 2024 14:27:15 +0200 Subject: [PATCH 196/199] serial: 8250_uniphier: Switch to use uart_read_port_properties() Since we have now a common helper to read port properties use it instead of sparse home grown solution. Signed-off-by: Andy Shevchenko Reviewed-by: Kunihiko Hayashi Tested-by: Kunihiko Hayashi Link: https://lore.kernel.org/r/20240304123035.758700-15-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_uniphier.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c index 6399a38ecce2..670d2ca0f757 100644 --- a/drivers/tty/serial/8250/8250_uniphier.c +++ b/drivers/tty/serial/8250/8250_uniphier.c @@ -162,7 +162,6 @@ static int uniphier_uart_probe(struct platform_device *pdev) struct uniphier8250_priv *priv; struct resource *regs; void __iomem *membase; - int irq; int ret; regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -175,23 +174,12 @@ static int uniphier_uart_probe(struct platform_device *pdev) if (!membase) return -ENOMEM; - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; memset(&up, 0, sizeof(up)); - ret = of_alias_get_id(dev->of_node, "serial"); - if (ret < 0) { - dev_err(dev, "failed to get alias id\n"); - return ret; - } - up.port.line = ret; - priv->clk = devm_clk_get(dev, NULL); if (IS_ERR(priv->clk)) { dev_err(dev, "failed to get clock\n"); @@ -211,7 +199,10 @@ static int uniphier_uart_probe(struct platform_device *pdev) up.port.mapbase = regs->start; up.port.mapsize = resource_size(regs); up.port.membase = membase; - up.port.irq = irq; + + ret = uart_read_port_properties(&up.port); + if (ret) + return ret; up.port.type = PORT_16550A; up.port.iotype = UPIO_MEM32; From 801410b26a0e8b8a16f7915b2b55c9528b69ca87 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Mon, 4 Mar 2024 13:43:49 -0800 Subject: [PATCH 197/199] serial: Lock console when calling into driver before registration During the handoff from earlycon to the real console driver, we have two separate drivers operating on the same device concurrently. In the case of the 8250 driver these concurrent accesses cause problems due to the driver's use of banked registers, controlled by LCR.DLAB. It is possible for the setup(), config_port(), pm() and set_mctrl() callbacks to set DLAB, which can cause the earlycon code that intends to access TX to instead access DLL, leading to missed output and corruption on the serial line due to unintended modifications to the baud rate. In particular, for setup() we have: univ8250_console_setup() -> serial8250_console_setup() -> uart_set_options() -> serial8250_set_termios() -> serial8250_do_set_termios() -> serial8250_do_set_divisor() For config_port() we have: serial8250_config_port() -> autoconfig() For pm() we have: serial8250_pm() -> serial8250_do_pm() -> serial8250_set_sleep() For set_mctrl() we have (for some devices): serial8250_set_mctrl() -> omap8250_set_mctrl() -> __omap8250_set_mctrl() To avoid such problems, let's make it so that the console is locked during pre-registration calls to these callbacks, which will prevent the earlycon driver from running concurrently. Remove the partial solution to this problem in the 8250 driver that locked the console only during autoconfig_irq(), as this would result in a deadlock with the new approach. The console continues to be locked during autoconfig_irq() because it can only be called through uart_configure_port(). Although this patch introduces more locking than strictly necessary (and in particular it also locks during the call to rs485_config() which is not affected by this issue as far as I can tell), it follows the principle that it is the responsibility of the generic console code to manage the earlycon handoff by ensuring that earlycon and real console driver code cannot run concurrently, and not the individual drivers. Signed-off-by: Peter Collingbourne Reviewed-by: John Ogness Link: https://linux-review.googlesource.com/id/I7cf8124dcebf8618e6b2ee543fa5b25532de55d8 Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20240304214350.501253-1-pcc@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 6 ------ drivers/tty/serial/serial_core.c | 12 ++++++++++++ kernel/printk/printk.c | 21 ++++++++++++++++++--- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 336a0bd4d172..fc9dd5d45295 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1325,9 +1325,6 @@ static void autoconfig_irq(struct uart_8250_port *up) inb_p(ICP); } - if (uart_console(port)) - console_lock(); - /* forget possible initially masked and pending IRQ */ probe_irq_off(probe_irq_on()); save_mcr = serial8250_in_MCR(up); @@ -1367,9 +1364,6 @@ static void autoconfig_irq(struct uart_8250_port *up) if (port->flags & UPF_FOURPORT) outb_p(save_ICP, ICP); - if (uart_console(port)) - console_unlock(); - port->irq = (irq > 0) ? irq : 0; } diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index d6a58a9e072a..ff85ebd3a007 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2608,7 +2608,12 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state, port->type = PORT_UNKNOWN; flags |= UART_CONFIG_TYPE; } + /* Synchronize with possible boot console. */ + if (uart_console(port)) + console_lock(); port->ops->config_port(port, flags); + if (uart_console(port)) + console_unlock(); } if (port->type != PORT_UNKNOWN) { @@ -2616,6 +2621,10 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state, uart_report_port(drv, port); + /* Synchronize with possible boot console. */ + if (uart_console(port)) + console_lock(); + /* Power up port for set_mctrl() */ uart_change_pm(state, UART_PM_STATE_ON); @@ -2632,6 +2641,9 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state, uart_rs485_config(port); + if (uart_console(port)) + console_unlock(); + /* * If this driver supports console, and it hasn't been * successfully registered yet, try to re-register it. diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index f2444b581e16..89f2aa2e1172 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -3263,6 +3263,21 @@ static int __init keep_bootcon_setup(char *str) early_param("keep_bootcon", keep_bootcon_setup); +static int console_call_setup(struct console *newcon, char *options) +{ + int err; + + if (!newcon->setup) + return 0; + + /* Synchronize with possible boot console. */ + console_lock(); + err = newcon->setup(newcon, options); + console_unlock(); + + return err; +} + /* * This is called by register_console() to try to match * the newly registered console with any of the ones selected @@ -3298,8 +3313,8 @@ static int try_enable_preferred_console(struct console *newcon, if (_braille_register_console(newcon, c)) return 0; - if (newcon->setup && - (err = newcon->setup(newcon, c->options)) != 0) + err = console_call_setup(newcon, c->options); + if (err) return err; } newcon->flags |= CON_ENABLED; @@ -3325,7 +3340,7 @@ static void try_enable_default_console(struct console *newcon) if (newcon->index < 0) newcon->index = 0; - if (newcon->setup && newcon->setup(newcon, NULL) != 0) + if (console_call_setup(newcon, NULL) != 0) return; newcon->flags |= CON_ENABLED; From 173b097dcc8d74d6e135aed1bad38dbfa21c4d04 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 6 Mar 2024 16:33:22 +0200 Subject: [PATCH 198/199] serial: 8250_dw: Replace ACPI device check by a quirk Instead of checking for APMC0D08 ACPI device presence, use a quirk based on driver data. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240306143322.3291123-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 51 ++++++++++++++++--------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index e369b429e060..1300c92b8702 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -9,7 +9,6 @@ * LCR is written whilst busy. If it is, then a busy detect interrupt is * raised, the LCR needs to be rewritten and the uart status register read. */ -#include #include #include #include @@ -55,6 +54,7 @@ #define DW_UART_QUIRK_ARMADA_38X BIT(1) #define DW_UART_QUIRK_SKIP_SET_RATE BIT(2) #define DW_UART_QUIRK_IS_DMA_FC BIT(3) +#define DW_UART_QUIRK_APMC0D08 BIT(4) static inline struct dw8250_data *clk_to_dw8250_data(struct notifier_block *nb) { @@ -444,33 +444,29 @@ static void dw8250_prepare_rx_dma(struct uart_8250_port *p) static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data) { - struct device_node *np = p->dev->of_node; - - if (np) { - unsigned int quirks = data->pdata->quirks; + unsigned int quirks = data->pdata ? data->pdata->quirks : 0; #ifdef CONFIG_64BIT - if (quirks & DW_UART_QUIRK_OCTEON) { - p->serial_in = dw8250_serial_inq; - p->serial_out = dw8250_serial_outq; - p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE; - p->type = PORT_OCTEON; - data->skip_autocfg = true; - } + if (quirks & DW_UART_QUIRK_OCTEON) { + p->serial_in = dw8250_serial_inq; + p->serial_out = dw8250_serial_outq; + p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE; + p->type = PORT_OCTEON; + data->skip_autocfg = true; + } #endif - if (quirks & DW_UART_QUIRK_ARMADA_38X) - p->serial_out = dw8250_serial_out38x; - if (quirks & DW_UART_QUIRK_SKIP_SET_RATE) - p->set_termios = dw8250_do_set_termios; - if (quirks & DW_UART_QUIRK_IS_DMA_FC) { - data->data.dma.txconf.device_fc = 1; - data->data.dma.rxconf.device_fc = 1; - data->data.dma.prepare_tx_dma = dw8250_prepare_tx_dma; - data->data.dma.prepare_rx_dma = dw8250_prepare_rx_dma; - } - - } else if (acpi_dev_present("APMC0D08", NULL, -1)) { + if (quirks & DW_UART_QUIRK_ARMADA_38X) + p->serial_out = dw8250_serial_out38x; + if (quirks & DW_UART_QUIRK_SKIP_SET_RATE) + p->set_termios = dw8250_do_set_termios; + if (quirks & DW_UART_QUIRK_IS_DMA_FC) { + data->data.dma.txconf.device_fc = 1; + data->data.dma.rxconf.device_fc = 1; + data->data.dma.prepare_tx_dma = dw8250_prepare_tx_dma; + data->data.dma.prepare_rx_dma = dw8250_prepare_rx_dma; + } + if (quirks & DW_UART_QUIRK_APMC0D08) { p->iotype = UPIO_MEM32; p->regshift = 2; p->serial_in = dw8250_serial_in32; @@ -750,13 +746,18 @@ static const struct of_device_id dw8250_of_match[] = { }; MODULE_DEVICE_TABLE(of, dw8250_of_match); +static const struct dw8250_platform_data dw8250_apmc0d08 = { + .usr_reg = DW_UART_USR, + .quirks = DW_UART_QUIRK_APMC0D08, +}; + static const struct acpi_device_id dw8250_acpi_match[] = { { "80860F0A", (kernel_ulong_t)&dw8250_dw_apb }, { "8086228A", (kernel_ulong_t)&dw8250_dw_apb }, { "AMD0020", (kernel_ulong_t)&dw8250_dw_apb }, { "AMDI0020", (kernel_ulong_t)&dw8250_dw_apb }, { "AMDI0022", (kernel_ulong_t)&dw8250_dw_apb }, - { "APMC0D08", (kernel_ulong_t)&dw8250_dw_apb}, + { "APMC0D08", (kernel_ulong_t)&dw8250_apmc0d08 }, { "BRCM2032", (kernel_ulong_t)&dw8250_dw_apb }, { "HISI0031", (kernel_ulong_t)&dw8250_dw_apb }, { "INT33C4", (kernel_ulong_t)&dw8250_dw_apb }, From d6c0d892b44cd16e0421909cf7f2883b9e625e4a Mon Sep 17 00:00:00 2001 From: Valentin Caron Date: Thu, 18 Jan 2024 10:11:35 +0100 Subject: [PATCH 199/199] dt-bindings: serial: stm32: add power-domains property STM32 serial may be in a power domain. Allow a single 'power-domains' entry for STM32 serial devices. Signed-off-by: Valentin Caron Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20240118091135.3314330-1-valentin.caron@foss.st.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/st,stm32-uart.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml b/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml index 1df8ffe95fc6..62f97da1b2fd 100644 --- a/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml +++ b/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml @@ -58,6 +58,9 @@ properties: wakeup-source: true + power-domains: + maxItems: 1 + rx-threshold: description: If value is set to 1, RX FIFO threshold is disabled.