From da1bb4ed23564f2937a4a3fa8d5ccdd0c167fe6a Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 21 May 2022 13:11:45 +0200 Subject: tty: fix typos in comments Spelling mistakes (triple letters) in comments. Detected with the help of Coccinelle. Signed-off-by: Julia Lawall Link: https://lore.kernel.org/r/20220521111145.81697-95-Julia.Lawall@inria.fr Signed-off-by: Greg Kroah-Hartman --- drivers/tty/mips_ejtag_fdc.c | 2 +- drivers/tty/tty_io.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/mips_ejtag_fdc.c b/drivers/tty/mips_ejtag_fdc.c index 31dceb5039b5..49907427a165 100644 --- a/drivers/tty/mips_ejtag_fdc.c +++ b/drivers/tty/mips_ejtag_fdc.c @@ -1222,7 +1222,7 @@ static void kgdbfdc_push_one(void) /* Construct a word from any data in buffer */ word = mips_ejtag_fdc_encode(bufs, &kgdbfdc_wbuflen, 1); - /* Relocate any remaining data to beginnning of buffer */ + /* Relocate any remaining data to beginning of buffer */ kgdbfdc_wbuflen -= word.bytes; for (i = 0; i < kgdbfdc_wbuflen; ++i) kgdbfdc_wbuf[i] = kgdbfdc_wbuf[i + word.bytes]; diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 8fec1d8648f5..82a8855981f7 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1663,7 +1663,7 @@ void tty_kclose(struct tty_struct *tty) */ tty_ldisc_release(tty); - /* Wait for pending work before tty destruction commmences */ + /* Wait for pending work before tty destruction commences */ tty_flush_works(tty); tty_debug_hangup(tty, "freeing structure\n"); -- cgit v1.2.3 From d93e612d13baabe76a8f414aa5dfc5726d4845da Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 21 May 2022 13:10:33 +0200 Subject: serial: tegra: fix typos in comments Spelling mistakes (triple letters) in comments. Detected with the help of Coccinelle. Signed-off-by: Julia Lawall Link: https://lore.kernel.org/r/20220521111145.81697-23-Julia.Lawall@inria.fr Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial-tegra.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c index d942ab152f5a..101fb585e6f9 100644 --- a/drivers/tty/serial/serial-tegra.c +++ b/drivers/tty/serial/serial-tegra.c @@ -441,7 +441,7 @@ static char tegra_uart_decode_rx_error(struct tegra_uart_port *tup, if (unlikely(lsr & TEGRA_UART_LSR_ANY)) { if (lsr & UART_LSR_OE) { - /* Overrrun error */ + /* Overrun error */ flag = TTY_OVERRUN; tup->uport.icount.overrun++; dev_dbg(tup->uport.dev, "Got overrun errors\n"); @@ -1080,7 +1080,7 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup) tup->rx_in_progress = 1; /* - * Enable IE_RXS for the receive status interrupts like line errros. + * Enable IE_RXS for the receive status interrupts like line errors. * Enable IE_RX_TIMEOUT to get the bytes which cannot be DMA'd. * * EORD is different interrupt than RX_TIMEOUT - RX_TIMEOUT occurs when -- cgit v1.2.3 From 6f3cdf2bf1ba9b70de6c2921a415951a0d59873b Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 25 May 2022 10:12:04 +0800 Subject: serial: pic32: fix missing clk_disable_unprepare() on error in pic32_uart_startup() Fix the missing clk_disable_unprepare() before return from pic32_uart_startup() in the error handling case. Fixes: 157b9394709e ("serial: pic32_uart: Add PIC32 UART driver") Reported-by: Hulk Robot Reviewed-by: Jiri Slaby Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20220525021204.2407631-1-yangyingliang@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pic32_uart.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/pic32_uart.c b/drivers/tty/serial/pic32_uart.c index b399aac530fe..f418f1de66b3 100644 --- a/drivers/tty/serial/pic32_uart.c +++ b/drivers/tty/serial/pic32_uart.c @@ -503,7 +503,7 @@ static int pic32_uart_startup(struct uart_port *port) if (!sport->irq_fault_name) { dev_err(port->dev, "%s: kasprintf err!", __func__); ret = -ENOMEM; - goto out_done; + goto out_disable_clk; } irq_set_status_flags(sport->irq_fault, IRQ_NOAUTOEN); ret = request_irq(sport->irq_fault, pic32_uart_fault_interrupt, @@ -579,6 +579,8 @@ out_r: out_f: free_irq(sport->irq_fault, port); kfree(sport->irq_fault_name); +out_disable_clk: + clk_disable_unprepare(sport->clk); out_done: return ret; } -- cgit v1.2.3 From 7fd6c24bae8fff0c12c61bc69388d9f3c045ce21 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 2 Jun 2022 10:31:20 +0200 Subject: serial: pmac_zilog: remove unused header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After commit a5ddc498e792 (serial: pmac_zilog: remove unfinished DBDMA support), the header is unused and can be removed. So do so. Cc: Michael Ellerman Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Suggested-by: "Ilpo Järvinen" Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220602083120.22519-1-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pmac_zilog.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index 3133446e806c..f63257b8e872 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -52,7 +52,6 @@ #ifdef CONFIG_PPC_PMAC #include #include -#include #include #else #include -- cgit v1.2.3 From 0d49ee83a450224fcd28e1dcc210f9bbef86f338 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 2 Jun 2022 10:31:27 +0200 Subject: tty/vt: defkeymap.c_shipped, little unification with loadkeys loadkeys 2.4.0 currently: * notes the use of --unicode to the output, and * uses "unsigned short" for key_maps instead of "ushort". So make our shipped file consistent with the generated output in this regard. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220602083128.22540-1-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/defkeymap.c_shipped | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/defkeymap.c_shipped b/drivers/tty/vt/defkeymap.c_shipped index 094d95bf0005..0c043e4f292e 100644 --- a/drivers/tty/vt/defkeymap.c_shipped +++ b/drivers/tty/vt/defkeymap.c_shipped @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 -/* Do not edit this file! It was automatically generated by */ -/* loadkeys --mktable defkeymap.map > defkeymap.c */ +/* Do not edit this file! It was automatically generated by */ +/* loadkeys --mktable --unicode defkeymap.map > defkeymap.c */ #include #include @@ -139,7 +139,7 @@ static unsigned short ctrl_alt_map[NR_KEYS] = { 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, }; -ushort *key_maps[MAX_NR_KEYMAPS] = { +unsigned short *key_maps[MAX_NR_KEYMAPS] = { plain_map, shift_map, altgr_map, NULL, ctrl_map, shift_ctrl_map, NULL, NULL, alt_map, NULL, NULL, NULL, -- cgit v1.2.3 From 5c4d7b049dce57816171ba4374cecfddd6e6faed Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 2 Jun 2022 10:31:28 +0200 Subject: tty/vt: Makefile, add --unicode for loadkeys invocation For a long time, we generate unicode tables using loadkeys. So fix Makefile to use that flag too. Reviewed-by: Andy Shevchenko Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220602083128.22540-2-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/Makefile b/drivers/tty/vt/Makefile index fe30ce512819..b3dfe9d5717e 100644 --- a/drivers/tty/vt/Makefile +++ b/drivers/tty/vt/Makefile @@ -30,6 +30,6 @@ $(obj)/defkeymap.o: $(obj)/defkeymap.c ifdef GENERATE_KEYMAP $(obj)/defkeymap.c: $(obj)/%.c: $(src)/%.map - loadkeys --mktable $< > $@ + loadkeys --mktable --unicode $< > $@ endif -- cgit v1.2.3 From 17945d317a523212831049147d7d9dd0fff9969f Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:11 +0200 Subject: tty/vt: consolemap: use ARRAY_SIZE() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code uses constants as bounds in loops. Use ARRAY_SIZE() with appropriate parameters instead. This makes the loop bounds obvious. Reviewed-by: Ilpo Järvinen Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-1-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index d815ac98b39e..839d75d1a6c0 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -408,7 +408,7 @@ static void con_release_unimap(struct uni_pagedir *p) } p->uni_pgdir[i] = NULL; } - for (i = 0; i < 4; i++) { + for (i = 0; i < ARRAY_SIZE(p->inverse_translations); i++) { kfree(p->inverse_translations[i]); p->inverse_translations[i] = NULL; } @@ -798,7 +798,7 @@ u32 conv_8bit_to_uni(unsigned char c) int conv_uni_to_8bit(u32 uni) { int c; - for (c = 0; c < 0x100; c++) + for (c = 0; c < ARRAY_SIZE(translations[USER_MAP]); c++) if (translations[USER_MAP][c] == uni || (translations[USER_MAP][c] == (c | 0xf000) && uni == c)) return c; -- cgit v1.2.3 From 4173f018aae16b6496d292c234b858241f85254f Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:12 +0200 Subject: tty/vt: consolemap: rename and document struct uni_pagedir struct uni_pagedir contains 32 unicode page directories, so the name of the structure is a bit misleading. Rename the structure to uni_pagedict, so it looks like this: struct uni_pagedict -> 32 page dirs -> 32 rows -> 64 glyphs Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-2-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 47 +++++++++++++++++++++++++----------------- drivers/video/console/vgacon.c | 4 ++-- include/linux/console_struct.h | 6 +++--- 3 files changed, 33 insertions(+), 24 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 839d75d1a6c0..5acafeea9afc 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -186,17 +186,26 @@ static unsigned short translations[][256] = { static int inv_translate[MAX_NR_CONSOLES]; -struct uni_pagedir { - u16 **uni_pgdir[32]; +/** + * struct uni_pagedict -- unicode directory + * + * @uni_pgdir: 32*32*64 table with glyphs + * @refcount: reference count of this structure + * @sum: checksum + * @inverse_translations: best-effort inverse mapping + * @inverse_trans_unicode: best-effort inverse mapping to unicode + */ +struct uni_pagedict { + u16 **uni_pgdir[32]; unsigned long refcount; unsigned long sum; unsigned char *inverse_translations[4]; u16 *inverse_trans_unicode; }; -static struct uni_pagedir *dflt; +static struct uni_pagedict *dflt; -static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int i) +static void set_inverse_transl(struct vc_data *conp, struct uni_pagedict *p, int i) { int j, glyph; unsigned short *t = translations[i]; @@ -221,7 +230,7 @@ static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int } static void set_inverse_trans_unicode(struct vc_data *conp, - struct uni_pagedir *p) + struct uni_pagedict *p) { int i, j, k, glyph; u16 **p1, *p2; @@ -270,7 +279,7 @@ unsigned short *set_translate(int m, struct vc_data *vc) */ u16 inverse_translate(const struct vc_data *conp, int glyph, int use_unicode) { - struct uni_pagedir *p; + struct uni_pagedict *p; int m; if (glyph < 0 || glyph >= MAX_GLYPH) return 0; @@ -297,7 +306,7 @@ EXPORT_SYMBOL_GPL(inverse_translate); static void update_user_maps(void) { int i; - struct uni_pagedir *p, *q = NULL; + struct uni_pagedict *p, *q = NULL; for (i = 0; i < MAX_NR_CONSOLES; i++) { if (!vc_cons_allocated(i)) @@ -393,7 +402,7 @@ int con_get_trans_new(ushort __user * arg) extern u8 dfont_unicount[]; /* Defined in console_defmap.c */ extern u16 dfont_unitable[]; -static void con_release_unimap(struct uni_pagedir *p) +static void con_release_unimap(struct uni_pagedict *p) { u16 **p1; int i, j; @@ -419,7 +428,7 @@ static void con_release_unimap(struct uni_pagedir *p) /* Caller must hold the console lock */ void con_free_unimap(struct vc_data *vc) { - struct uni_pagedir *p; + struct uni_pagedict *p; p = *vc->vc_uni_pagedir_loc; if (!p) @@ -431,10 +440,10 @@ void con_free_unimap(struct vc_data *vc) kfree(p); } -static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p) +static int con_unify_unimap(struct vc_data *conp, struct uni_pagedict *p) { int i, j, k; - struct uni_pagedir *q; + struct uni_pagedict *q; for (i = 0; i < MAX_NR_CONSOLES; i++) { if (!vc_cons_allocated(i)) @@ -472,7 +481,7 @@ static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p) } static int -con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos) +con_insert_unipair(struct uni_pagedict *p, u_short unicode, u_short fontpos) { int i, n; u16 **p1, *p2; @@ -503,7 +512,7 @@ con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos) /* Caller must hold the lock */ static int con_do_clear_unimap(struct vc_data *vc) { - struct uni_pagedir *p, *q; + struct uni_pagedict *p, *q; p = *vc->vc_uni_pagedir_loc; if (!p || --p->refcount) { @@ -536,7 +545,7 @@ int con_clear_unimap(struct vc_data *vc) int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) { int err = 0, err1, i; - struct uni_pagedir *p, *q; + struct uni_pagedict *p, *q; struct unipair *unilist, *plist; if (!ct) @@ -569,7 +578,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) /* * Since refcount was > 1, con_clear_unimap() allocated a - * a new uni_pagedir for this vc. Re: p != q + * a new uni_pagedict for this vc. Re: p != q */ q = *vc->vc_uni_pagedir_loc; @@ -660,7 +669,7 @@ int con_set_default_unimap(struct vc_data *vc) { int i, j, err = 0, err1; u16 *q; - struct uni_pagedir *p; + struct uni_pagedict *p; if (dflt) { p = *vc->vc_uni_pagedir_loc; @@ -714,7 +723,7 @@ EXPORT_SYMBOL(con_set_default_unimap); */ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc) { - struct uni_pagedir *q; + struct uni_pagedict *q; if (!*src_vc->vc_uni_pagedir_loc) return -EINVAL; @@ -739,7 +748,7 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni int i, j, k, ret = 0; ushort ect; u16 **p1, *p2; - struct uni_pagedir *p; + struct uni_pagedict *p; struct unipair *unilist; unilist = kvmalloc_array(ct, sizeof(struct unipair), GFP_KERNEL); @@ -810,7 +819,7 @@ conv_uni_to_pc(struct vc_data *conp, long ucs) { int h; u16 **p1, *p2; - struct uni_pagedir *p; + struct uni_pagedict *p; /* Only 16-bit codes supported at this time */ if (ucs > 0xffff) diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 576612f18d59..058a78b8dbcf 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -75,7 +75,7 @@ static void vgacon_scrolldelta(struct vc_data *c, int lines); static int vgacon_set_origin(struct vc_data *c); static void vgacon_save_screen(struct vc_data *c); static void vgacon_invert_region(struct vc_data *c, u16 * p, int count); -static struct uni_pagedir *vgacon_uni_pagedir; +static struct uni_pagedict *vgacon_uni_pagedir; static int vgacon_refcount; /* Description of the hardware situation */ @@ -342,7 +342,7 @@ static const char *vgacon_startup(void) static void vgacon_init(struct vc_data *c, int init) { - struct uni_pagedir *p; + struct uni_pagedict *p; /* * We cannot be loaded as a module, therefore init will be 1 diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h index d5b9c8d40c18..f75033f0277f 100644 --- a/include/linux/console_struct.h +++ b/include/linux/console_struct.h @@ -17,7 +17,7 @@ #include #include -struct uni_pagedir; +struct uni_pagedict; struct uni_screen; #define NPAR 16 @@ -157,8 +157,8 @@ struct vc_data { unsigned int vc_bell_duration; /* Console bell duration */ unsigned short vc_cur_blink_ms; /* Cursor blink duration */ struct vc_data **vc_display_fg; /* [!] Ptr to var holding fg console for this display */ - struct uni_pagedir *vc_uni_pagedir; - struct uni_pagedir **vc_uni_pagedir_loc; /* [!] Location of uni_pagedir variable for this console */ + struct uni_pagedict *vc_uni_pagedir; + struct uni_pagedict **vc_uni_pagedir_loc; /* [!] Location of uni_pagedict variable for this console */ struct uni_screen *vc_uni_screen; /* unicode screen content */ /* additional information is in vt_kern.h */ }; -- cgit v1.2.3 From db8f597a47127d0554f9c059a6da35f3ff34e773 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:13 +0200 Subject: tty/vt: consolemap: define UNI_* macros for constants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code uses constants for sizes of dictionary substructures on many places. Define 3 macros and use them in the code, so that loop bounds, local variables and the dictionary always match. (And the loop bounds are obvious now too.) Reviewed-by: Ilpo Järvinen Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-3-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 54 +++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 24 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 5acafeea9afc..15aa10ff87ad 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -186,6 +186,10 @@ static unsigned short translations[][256] = { static int inv_translate[MAX_NR_CONSOLES]; +#define UNI_DIRS 32U +#define UNI_DIR_ROWS 32U +#define UNI_ROW_GLYPHS 64U + /** * struct uni_pagedict -- unicode directory * @@ -196,7 +200,7 @@ static int inv_translate[MAX_NR_CONSOLES]; * @inverse_trans_unicode: best-effort inverse mapping to unicode */ struct uni_pagedict { - u16 **uni_pgdir[32]; + u16 **uni_pgdir[UNI_DIRS]; unsigned long refcount; unsigned long sum; unsigned char *inverse_translations[4]; @@ -246,15 +250,15 @@ static void set_inverse_trans_unicode(struct vc_data *conp, } memset(q, 0, MAX_GLYPH * sizeof(u16)); - for (i = 0; i < 32; i++) { + for (i = 0; i < UNI_DIRS; i++) { p1 = p->uni_pgdir[i]; if (!p1) continue; - for (j = 0; j < 32; j++) { + for (j = 0; j < UNI_DIR_ROWS; j++) { p2 = p1[j]; if (!p2) continue; - for (k = 0; k < 64; k++) { + for (k = 0; k < UNI_ROW_GLYPHS; k++) { glyph = p2[k]; if (glyph >= 0 && glyph < MAX_GLYPH && q[glyph] < 32) @@ -408,10 +412,10 @@ static void con_release_unimap(struct uni_pagedict *p) int i, j; if (p == dflt) dflt = NULL; - for (i = 0; i < 32; i++) { + for (i = 0; i < UNI_DIRS; i++) { p1 = p->uni_pgdir[i]; if (p1 != NULL) { - for (j = 0; j < 32; j++) + for (j = 0; j < UNI_DIR_ROWS; j++) kfree(p1[j]); kfree(p1); } @@ -451,25 +455,26 @@ static int con_unify_unimap(struct vc_data *conp, struct uni_pagedict *p) q = *vc_cons[i].d->vc_uni_pagedir_loc; if (!q || q == p || q->sum != p->sum) continue; - for (j = 0; j < 32; j++) { + for (j = 0; j < UNI_DIRS; j++) { u16 **p1, **q1; p1 = p->uni_pgdir[j]; q1 = q->uni_pgdir[j]; if (!p1 && !q1) continue; if (!p1 || !q1) break; - for (k = 0; k < 32; k++) { + for (k = 0; k < UNI_DIR_ROWS; k++) { if (!p1[k] && !q1[k]) continue; if (!p1[k] || !q1[k]) break; - if (memcmp(p1[k], q1[k], 64*sizeof(u16))) + if (memcmp(p1[k], q1[k], + UNI_ROW_GLYPHS * sizeof(u16))) break; } - if (k < 32) + if (k < UNI_DIR_ROWS) break; } - if (j == 32) { + if (j == UNI_DIRS) { q->refcount++; *conp->vc_uni_pagedir_loc = q; con_release_unimap(p); @@ -488,18 +493,19 @@ con_insert_unipair(struct uni_pagedict *p, u_short unicode, u_short fontpos) p1 = p->uni_pgdir[n = unicode >> 11]; if (!p1) { - p1 = p->uni_pgdir[n] = kmalloc_array(32, sizeof(u16 *), - GFP_KERNEL); + p1 = p->uni_pgdir[n] = kmalloc_array(UNI_DIR_ROWS, + sizeof(u16 *), GFP_KERNEL); if (!p1) return -ENOMEM; - for (i = 0; i < 32; i++) + for (i = 0; i < UNI_DIR_ROWS; i++) p1[i] = NULL; } p2 = p1[n = (unicode >> 6) & 0x1f]; if (!p2) { - p2 = p1[n] = kmalloc_array(64, sizeof(u16), GFP_KERNEL); + p2 = p1[n] = kmalloc_array(UNI_ROW_GLYPHS, sizeof(u16), GFP_KERNEL); if (!p2) return -ENOMEM; - memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */ + /* No glyphs for the characters (yet) */ + memset(p2, 0xff, UNI_ROW_GLYPHS * sizeof(u16)); } p2[unicode & 0x3f] = fontpos; @@ -589,13 +595,13 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) * entries from "p" (old) to "q" (new). */ l = 0; /* unicode value */ - for (i = 0; i < 32; i++) { + for (i = 0; i < UNI_DIRS; i++) { p1 = p->uni_pgdir[i]; if (p1) - for (j = 0; j < 32; j++) { + for (j = 0; j < UNI_DIR_ROWS; j++) { p2 = p1[j]; if (p2) { - for (k = 0; k < 64; k++, l++) + for (k = 0; k < UNI_ROW_GLYPHS; k++, l++) if (p2[k] != 0xffff) { /* * Found one, copy entry for unicode @@ -613,12 +619,12 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) } } else { /* Account for row of 64 empty entries */ - l += 64; + l += UNI_ROW_GLYPHS; } } else /* Account for empty table */ - l += 32 * 64; + l += UNI_DIR_ROWS * UNI_ROW_GLYPHS; } /* @@ -760,13 +766,13 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni ect = 0; if (*vc->vc_uni_pagedir_loc) { p = *vc->vc_uni_pagedir_loc; - for (i = 0; i < 32; i++) { + for (i = 0; i < UNI_DIRS; i++) { p1 = p->uni_pgdir[i]; if (p1) - for (j = 0; j < 32; j++) { + for (j = 0; j < UNI_DIR_ROWS; j++) { p2 = *(p1++); if (p2) - for (k = 0; k < 64; k++, p2++) { + for (k = 0; k < UNI_ROW_GLYPHS; k++, p2++) { if (*p2 >= MAX_GLYPH) continue; if (ect < ct) { -- cgit v1.2.3 From 2097dc2273a5b5254d0fad79afdedd223035b2d5 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:14 +0200 Subject: tty/vt: consolemap: decrypt inverse_translate() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix invalid indentation and demystify the code by removing superfluous "else"s. The "else"s are unneeded as they always follow an "if"-true branch containing a "return". The code is now way more readable. Reviewed-by: Ilpo Järvinen Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-4-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 15aa10ff87ad..fb61158f4dc6 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -285,25 +285,26 @@ u16 inverse_translate(const struct vc_data *conp, int glyph, int use_unicode) { struct uni_pagedict *p; int m; + if (glyph < 0 || glyph >= MAX_GLYPH) return 0; - else { - p = *conp->vc_uni_pagedir_loc; - if (!p) + + p = *conp->vc_uni_pagedir_loc; + if (!p) + return glyph; + + if (use_unicode) { + if (!p->inverse_trans_unicode) return glyph; - else if (use_unicode) { - if (!p->inverse_trans_unicode) - return glyph; - else - return p->inverse_trans_unicode[glyph]; - } else { - m = inv_translate[conp->vc_num]; - if (!p->inverse_translations[m]) - return glyph; - else - return p->inverse_translations[m][glyph]; - } + + return p->inverse_trans_unicode[glyph]; } + + m = inv_translate[conp->vc_num]; + if (!p->inverse_translations[m]) + return glyph; + + return p->inverse_translations[m][glyph]; } EXPORT_SYMBOL_GPL(inverse_translate); -- cgit v1.2.3 From d9ebb906a45adc71a62aceb1e3608c847cafa660 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:17 +0200 Subject: tty/vt: consolemap: make parameters of inverse_translate() saner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - int use_unicode -> bool: it's used as bool at some places already, so make it explicit. - int glyph -> u16: every caller passes a u16 in. So make it explicit too. And remove a negative check from inverse_translate() as it never could be negative. Reviewed-by: Ilpo Järvinen Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-7-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/accessibility/braille/braille_console.c | 2 +- drivers/accessibility/speakup/main.c | 2 +- drivers/tty/vt/consolemap.c | 4 ++-- drivers/tty/vt/selection.c | 3 ++- drivers/tty/vt/vt.c | 2 +- include/linux/consolemap.h | 6 +++--- 6 files changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/accessibility/braille/braille_console.c b/drivers/accessibility/braille/braille_console.c index fdc6b593f500..c4d54a5326b1 100644 --- a/drivers/accessibility/braille/braille_console.c +++ b/drivers/accessibility/braille/braille_console.c @@ -131,7 +131,7 @@ static void vc_refresh(struct vc_data *vc) for (i = 0; i < WIDTH; i++) { u16 glyph = screen_glyph(vc, 2 * (vc_x + i) + vc_y * vc->vc_size_row); - buf[i] = inverse_translate(vc, glyph, 1); + buf[i] = inverse_translate(vc, glyph, true); } braille_write(buf); } diff --git a/drivers/accessibility/speakup/main.c b/drivers/accessibility/speakup/main.c index d726537fa16c..f52265293482 100644 --- a/drivers/accessibility/speakup/main.c +++ b/drivers/accessibility/speakup/main.c @@ -470,7 +470,7 @@ static u16 get_char(struct vc_data *vc, u16 *pos, u_char *attribs) c |= 0x100; } - ch = inverse_translate(vc, c, 1); + ch = inverse_translate(vc, c, true); *attribs = (w & 0xff00) >> 8; } return ch; diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index fb61158f4dc6..157c7f936294 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -281,12 +281,12 @@ unsigned short *set_translate(int m, struct vc_data *vc) * was active. * Still, it is now possible to a certain extent to cut and paste non-ASCII. */ -u16 inverse_translate(const struct vc_data *conp, int glyph, int use_unicode) +u16 inverse_translate(const struct vc_data *conp, u16 glyph, bool use_unicode) { struct uni_pagedict *p; int m; - if (glyph < 0 || glyph >= MAX_GLYPH) + if (glyph >= MAX_GLYPH) return 0; p = *conp->vc_uni_pagedir_loc; diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index f7755e73696e..6ef22f01cc51 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -68,7 +68,8 @@ sel_pos(int n, bool unicode) { if (unicode) return screen_glyph_unicode(vc_sel.cons, n / 2); - return inverse_translate(vc_sel.cons, screen_glyph(vc_sel.cons, n), 0); + return inverse_translate(vc_sel.cons, screen_glyph(vc_sel.cons, n), + false); } /** diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index f8c87c4d7399..1ea1c11c42fd 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -4741,7 +4741,7 @@ u32 screen_glyph_unicode(const struct vc_data *vc, int n) if (uniscr) return uniscr->lines[n / vc->vc_cols][n % vc->vc_cols]; - return inverse_translate(vc, screen_glyph(vc, n * 2), 1); + return inverse_translate(vc, screen_glyph(vc, n * 2), true); } EXPORT_SYMBOL_GPL(screen_glyph_unicode); diff --git a/include/linux/consolemap.h b/include/linux/consolemap.h index 98171dbed51f..1ff2bf55eb85 100644 --- a/include/linux/consolemap.h +++ b/include/linux/consolemap.h @@ -17,15 +17,15 @@ struct vc_data; #ifdef CONFIG_CONSOLE_TRANSLATIONS -u16 inverse_translate(const struct vc_data *conp, int glyph, int use_unicode); +u16 inverse_translate(const struct vc_data *conp, u16 glyph, bool use_unicode); unsigned short *set_translate(int m, struct vc_data *vc); int conv_uni_to_pc(struct vc_data *conp, long ucs); u32 conv_8bit_to_uni(unsigned char c); int conv_uni_to_8bit(u32 uni); void console_map_init(void); #else -static inline u16 inverse_translate(const struct vc_data *conp, int glyph, - int use_unicode) +static inline u16 inverse_translate(const struct vc_data *conp, u16 glyph, + bool use_unicode) { return glyph; } -- cgit v1.2.3 From e16cb6fe315821ef3148fa83892adca1f2a2e35a Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:18 +0200 Subject: tty/vt: consolemap: one line = one statement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some lines combine more statements on one line. This makes the code hard to follow. Do it properly in the "one line = one statement" fashion. Reviewed-by: Ilpo Järvinen Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-8-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 157c7f936294..f97081e01b71 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -215,12 +215,14 @@ static void set_inverse_transl(struct vc_data *conp, struct uni_pagedict *p, int unsigned short *t = translations[i]; unsigned char *q; - if (!p) return; + if (!p) + return; q = p->inverse_translations[i]; if (!q) { q = p->inverse_translations[i] = kmalloc(MAX_GLYPH, GFP_KERNEL); - if (!q) return; + if (!q) + return; } memset(q, 0, MAX_GLYPH); @@ -240,7 +242,8 @@ static void set_inverse_trans_unicode(struct vc_data *conp, u16 **p1, *p2; u16 *q; - if (!p) return; + if (!p) + return; q = p->inverse_trans_unicode; if (!q) { q = p->inverse_trans_unicode = @@ -412,7 +415,8 @@ static void con_release_unimap(struct uni_pagedict *p) u16 **p1; int i, j; - if (p == dflt) dflt = NULL; + if (p == dflt) + dflt = NULL; for (i = 0; i < UNI_DIRS; i++) { p1 = p->uni_pgdir[i]; if (p1 != NULL) { @@ -458,7 +462,8 @@ static int con_unify_unimap(struct vc_data *conp, struct uni_pagedict *p) continue; for (j = 0; j < UNI_DIRS; j++) { u16 **p1, **q1; - p1 = p->uni_pgdir[j]; q1 = q->uni_pgdir[j]; + p1 = p->uni_pgdir[j]; + q1 = q->uni_pgdir[j]; if (!p1 && !q1) continue; if (!p1 || !q1) @@ -492,19 +497,23 @@ con_insert_unipair(struct uni_pagedict *p, u_short unicode, u_short fontpos) int i, n; u16 **p1, *p2; - p1 = p->uni_pgdir[n = unicode >> 11]; + n = unicode >> 11; + p1 = p->uni_pgdir[n]; if (!p1) { p1 = p->uni_pgdir[n] = kmalloc_array(UNI_DIR_ROWS, sizeof(u16 *), GFP_KERNEL); - if (!p1) return -ENOMEM; + if (!p1) + return -ENOMEM; for (i = 0; i < UNI_DIR_ROWS; i++) p1[i] = NULL; } - p2 = p1[n = (unicode >> 6) & 0x1f]; + n = (unicode >> 6) & 0x1f; + p2 = p1[n]; if (!p2) { p2 = p1[n] = kmalloc_array(UNI_ROW_GLYPHS, sizeof(u16), GFP_KERNEL); - if (!p2) return -ENOMEM; + if (!p2) + return -ENOMEM; /* No glyphs for the characters (yet) */ memset(p2, 0xff, UNI_ROW_GLYPHS * sizeof(u16)); } @@ -532,7 +541,8 @@ static int con_do_clear_unimap(struct vc_data *vc) q->refcount=1; *vc->vc_uni_pagedir_loc = q; } else { - if (p == dflt) dflt = NULL; + if (p == dflt) + dflt = NULL; p->refcount++; p->sum = 0; con_release_unimap(p); -- cgit v1.2.3 From ad8a2142ba57212b73e614d5d86160a9c0ff8617 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:19 +0200 Subject: tty/vt: consolemap: use | for binary addition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unicode letters are composed as a bit shifts and sums of three values. Use "|" and not "+" for these bit operations. The former is indeed more appropriate. Reviewed-by: Ilpo Järvinen Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-9-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index f97081e01b71..016c1a0b4290 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -265,7 +265,7 @@ static void set_inverse_trans_unicode(struct vc_data *conp, glyph = p2[k]; if (glyph >= 0 && glyph < MAX_GLYPH && q[glyph] < 32) - q[glyph] = (i << 11) + (j << 6) + k; + q[glyph] = (i << 11) | (j << 6) | k; } } } @@ -788,7 +788,7 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni continue; if (ect < ct) { unilist[ect].unicode = - (i<<11)+(j<<6)+k; + (i<<11) | (j<<6) | k; unilist[ect].fontpos = *p2; } ect++; -- cgit v1.2.3 From 9254365443f72838a276bb2d9a9935c802e3adc8 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:20 +0200 Subject: tty/vt: consolemap: introduce UNI_*() macros The code currently does shift, OR, and AND logic directly in the code. It is not much obvious what happens there. Therefore define four macros for that purpose and use them in the code. We use GENMASK() so that it is clear which bits serve what purpose: - UNI_GLYPH: bits 0.. 5 - UNI_ROW: bits 6..10 - UNI_DIR: bits 11..31 Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-10-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 016c1a0b4290..e5fd225e87bd 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -190,6 +190,11 @@ static int inv_translate[MAX_NR_CONSOLES]; #define UNI_DIR_ROWS 32U #define UNI_ROW_GLYPHS 64U +#define UNI_DIR(uni) ( (uni) >> 11) +#define UNI_ROW(uni) (((uni) & GENMASK(10, 6)) >> 6) +#define UNI_GLYPH(uni) ( (uni) & GENMASK( 5, 0)) +#define UNI(dir, row, glyph) (((dir) << 11) | ((row) << 6) | (glyph)) + /** * struct uni_pagedict -- unicode directory * @@ -265,7 +270,7 @@ static void set_inverse_trans_unicode(struct vc_data *conp, glyph = p2[k]; if (glyph >= 0 && glyph < MAX_GLYPH && q[glyph] < 32) - q[glyph] = (i << 11) | (j << 6) | k; + q[glyph] = UNI(i, j, k); } } } @@ -497,7 +502,7 @@ con_insert_unipair(struct uni_pagedict *p, u_short unicode, u_short fontpos) int i, n; u16 **p1, *p2; - n = unicode >> 11; + n = UNI_DIR(unicode); p1 = p->uni_pgdir[n]; if (!p1) { p1 = p->uni_pgdir[n] = kmalloc_array(UNI_DIR_ROWS, @@ -508,7 +513,7 @@ con_insert_unipair(struct uni_pagedict *p, u_short unicode, u_short fontpos) p1[i] = NULL; } - n = (unicode >> 6) & 0x1f; + n = UNI_ROW(unicode); p2 = p1[n]; if (!p2) { p2 = p1[n] = kmalloc_array(UNI_ROW_GLYPHS, sizeof(u16), GFP_KERNEL); @@ -518,7 +523,7 @@ con_insert_unipair(struct uni_pagedict *p, u_short unicode, u_short fontpos) memset(p2, 0xff, UNI_ROW_GLYPHS * sizeof(u16)); } - p2[unicode & 0x3f] = fontpos; + p2[UNI_GLYPH(unicode)] = fontpos; p->sum += (fontpos << 20U) + unicode; @@ -788,7 +793,7 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni continue; if (ect < ct) { unilist[ect].unicode = - (i<<11) | (j<<6) | k; + UNI(i, j, k); unilist[ect].fontpos = *p2; } ect++; @@ -857,9 +862,9 @@ conv_uni_to_pc(struct vc_data *conp, long ucs) return -3; p = *conp->vc_uni_pagedir_loc; - if ((p1 = p->uni_pgdir[ucs >> 11]) && - (p2 = p1[(ucs >> 6) & 0x1f]) && - (h = p2[ucs & 0x3f]) < MAX_GLYPH) + if ((p1 = p->uni_pgdir[UNI_DIR(ucs)]) && + (p2 = p1[UNI_ROW(ucs)]) && + (h = p2[UNI_GLYPH(ucs)]) < MAX_GLYPH) return h; return -4; /* not found */ -- cgit v1.2.3 From 32bd78fc4948471be2853ba8b5229e4e1327e13e Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:21 +0200 Subject: tty/vt: consolemap: zero uni_pgdir using kcalloc() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The newly allocated p->uni_pgdir[n] is initialized to NULLs right after a kmalloc_array() allocation. Combine these two using kcalloc(). Reviewed-by: Ilpo Järvinen Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-11-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index e5fd225e87bd..097ab7d01f8b 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -499,18 +499,16 @@ static int con_unify_unimap(struct vc_data *conp, struct uni_pagedict *p) static int con_insert_unipair(struct uni_pagedict *p, u_short unicode, u_short fontpos) { - int i, n; + int n; u16 **p1, *p2; n = UNI_DIR(unicode); p1 = p->uni_pgdir[n]; if (!p1) { - p1 = p->uni_pgdir[n] = kmalloc_array(UNI_DIR_ROWS, - sizeof(u16 *), GFP_KERNEL); + p1 = p->uni_pgdir[n] = kcalloc(UNI_DIR_ROWS, sizeof(u16 *), + GFP_KERNEL); if (!p1) return -ENOMEM; - for (i = 0; i < UNI_DIR_ROWS; i++) - p1[i] = NULL; } n = UNI_ROW(unicode); -- cgit v1.2.3 From acf90b4d52e6965cbc3b115a68e0f063f703719c Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:22 +0200 Subject: tty/vt: consolemap: use sizeof(*pointer) instead of sizeof(type) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is preferred to use sizeof(*pointer) instead of sizeof(type). First, the type of the variable can change and one needs not change the former (unlike the latter). Second, the latter is error-prone due to (u16), (u16 *), and (u16 **) mixture here. Reviewed-by: Ilpo Järvinen Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-12-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 097ab7d01f8b..79a62dcca046 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -251,12 +251,12 @@ static void set_inverse_trans_unicode(struct vc_data *conp, return; q = p->inverse_trans_unicode; if (!q) { - q = p->inverse_trans_unicode = - kmalloc_array(MAX_GLYPH, sizeof(u16), GFP_KERNEL); + q = p->inverse_trans_unicode = kmalloc_array(MAX_GLYPH, + sizeof(*q), GFP_KERNEL); if (!q) return; } - memset(q, 0, MAX_GLYPH * sizeof(u16)); + memset(q, 0, MAX_GLYPH * sizeof(*q)); for (i = 0; i < UNI_DIRS; i++) { p1 = p->uni_pgdir[i]; @@ -478,8 +478,8 @@ static int con_unify_unimap(struct vc_data *conp, struct uni_pagedict *p) continue; if (!p1[k] || !q1[k]) break; - if (memcmp(p1[k], q1[k], - UNI_ROW_GLYPHS * sizeof(u16))) + if (memcmp(p1[k], q1[k], UNI_ROW_GLYPHS * + sizeof(*p1[k]))) break; } if (k < UNI_DIR_ROWS) @@ -505,7 +505,7 @@ con_insert_unipair(struct uni_pagedict *p, u_short unicode, u_short fontpos) n = UNI_DIR(unicode); p1 = p->uni_pgdir[n]; if (!p1) { - p1 = p->uni_pgdir[n] = kcalloc(UNI_DIR_ROWS, sizeof(u16 *), + p1 = p->uni_pgdir[n] = kcalloc(UNI_DIR_ROWS, sizeof(*p1), GFP_KERNEL); if (!p1) return -ENOMEM; @@ -514,11 +514,12 @@ con_insert_unipair(struct uni_pagedict *p, u_short unicode, u_short fontpos) n = UNI_ROW(unicode); p2 = p1[n]; if (!p2) { - p2 = p1[n] = kmalloc_array(UNI_ROW_GLYPHS, sizeof(u16), GFP_KERNEL); + p2 = p1[n] = kmalloc_array(UNI_ROW_GLYPHS, sizeof(*p2), + GFP_KERNEL); if (!p2) return -ENOMEM; /* No glyphs for the characters (yet) */ - memset(p2, 0xff, UNI_ROW_GLYPHS * sizeof(u16)); + memset(p2, 0xff, UNI_ROW_GLYPHS * sizeof(*p2)); } p2[UNI_GLYPH(unicode)] = fontpos; @@ -571,7 +572,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) if (!ct) return 0; - unilist = vmemdup_user(list, array_size(sizeof(struct unipair), ct)); + unilist = vmemdup_user(list, array_size(sizeof(*unilist), ct)); if (IS_ERR(unilist)) return PTR_ERR(unilist); @@ -771,7 +772,7 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni struct uni_pagedict *p; struct unipair *unilist; - unilist = kvmalloc_array(ct, sizeof(struct unipair), GFP_KERNEL); + unilist = kvmalloc_array(ct, sizeof(*unilist), GFP_KERNEL); if (!unilist) return -ENOMEM; @@ -800,7 +801,7 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni } } console_unlock(); - if (copy_to_user(list, unilist, min(ect, ct) * sizeof(struct unipair))) + if (copy_to_user(list, unilist, min(ect, ct) * sizeof(*unilist))) ret = -EFAULT; put_user(ect, uct); kvfree(unilist); -- cgit v1.2.3 From 6e4e8d74664a2bf46c74dfcf0d8a600acbbc4d6d Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:23 +0200 Subject: tty/vt: consolemap: make con_set_unimap() more readable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The indentation was completely broken in con_set_unimap(). Reorder the code using 'if (!cond) continue;'s so that the code makes sense. Not that it is perfect now, but it can be followed at least. More cleanup to come. And remove all those useless whitespaces at the EOLs too. Reviewed-by: Ilpo Järvinen Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-13-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 79a62dcca046..3730a1c0f223 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -580,23 +580,21 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) /* Save original vc_unipagdir_loc in case we allocate a new one */ p = *vc->vc_uni_pagedir_loc; - if (!p) { err = -EINVAL; - goto out_unlock; } - + if (p->refcount > 1) { int j, k; u16 **p1, *p2, l; - + err1 = con_do_clear_unimap(vc); if (err1) { err = err1; goto out_unlock; } - + /* * Since refcount was > 1, con_clear_unimap() allocated a * a new uni_pagedict for this vc. Re: p != q @@ -611,13 +609,26 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) */ l = 0; /* unicode value */ for (i = 0; i < UNI_DIRS; i++) { - p1 = p->uni_pgdir[i]; - if (p1) + p1 = p->uni_pgdir[i]; + if (!p1) { + /* Account for empty table */ + l += UNI_DIR_ROWS * UNI_ROW_GLYPHS; + continue; + } + for (j = 0; j < UNI_DIR_ROWS; j++) { - p2 = p1[j]; - if (p2) { - for (k = 0; k < UNI_ROW_GLYPHS; k++, l++) - if (p2[k] != 0xffff) { + p2 = p1[j]; + if (!p2) { + /* + * Account for row of 64 empty entries + */ + l += UNI_ROW_GLYPHS; + continue; + } + + for (k = 0; k < UNI_ROW_GLYPHS; k++, l++) { + if (p2[k] == 0xffff) + continue; /* * Found one, copy entry for unicode * l with fontpos value p2[k]. @@ -632,15 +643,8 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) goto out_unlock; } } - } else { - /* Account for row of 64 empty entries */ - l += UNI_ROW_GLYPHS; } } - else - /* Account for empty table */ - l += UNI_DIR_ROWS * UNI_ROW_GLYPHS; - } /* * Finished copying font table, set vc_uni_pagedir to new table @@ -658,7 +662,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) if (err1) err = err1; } - + /* * Merge with fontmaps of any other virtual consoles. */ -- cgit v1.2.3 From 6364d391363a0ac498a852ff4bec32d82e913ee8 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:24 +0200 Subject: tty/vt: consolemap: make con_get_unimap() more readable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The indentation is completely broken in con_get_unimap(). Reorder the code using "if (!cond) continue;"s so that the code makes sense. Switch also the "p" assignment and add a short path using goto. This makes the code readable again. Reviewed-by: Ilpo Järvinen Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-14-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 3730a1c0f223..84c8043a36d0 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -768,7 +768,8 @@ EXPORT_SYMBOL(con_copy_unimap); * Read the console unicode data for this console. Called from the ioctl * handlers. */ -int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list) +int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, + struct unipair __user *list) { int i, j, k, ret = 0; ushort ect; @@ -783,27 +784,32 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni console_lock(); ect = 0; - if (*vc->vc_uni_pagedir_loc) { - p = *vc->vc_uni_pagedir_loc; - for (i = 0; i < UNI_DIRS; i++) { + p = *vc->vc_uni_pagedir_loc; + if (!p) + goto unlock; + + for (i = 0; i < UNI_DIRS; i++) { p1 = p->uni_pgdir[i]; - if (p1) - for (j = 0; j < UNI_DIR_ROWS; j++) { + if (!p1) + continue; + + for (j = 0; j < UNI_DIR_ROWS; j++) { p2 = *(p1++); - if (p2) - for (k = 0; k < UNI_ROW_GLYPHS; k++, p2++) { - if (*p2 >= MAX_GLYPH) - continue; - if (ect < ct) { - unilist[ect].unicode = - UNI(i, j, k); - unilist[ect].fontpos = *p2; - } - ect++; + if (!p2) + continue; + + for (k = 0; k < UNI_ROW_GLYPHS; k++, p2++) { + if (*p2 >= MAX_GLYPH) + continue; + if (ect < ct) { + unilist[ect].unicode = UNI(i, j, k); + unilist[ect].fontpos = *p2; } + ect++; } } } +unlock: console_unlock(); if (copy_to_user(list, unilist, min(ect, ct) * sizeof(*unilist))) ret = -EFAULT; -- cgit v1.2.3 From cb47d81f0f0fa293e18fe8828715a6509f480b3f Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:25 +0200 Subject: tty/vt: consolemap: make p1 increment less confusing in con_get_unimap() p2 is already incremented like this few lines below, so do the same for p1. This makes the code easier to follow. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-15-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 84c8043a36d0..831450f2bfd1 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -793,8 +793,8 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, if (!p1) continue; - for (j = 0; j < UNI_DIR_ROWS; j++) { - p2 = *(p1++); + for (j = 0; j < UNI_DIR_ROWS; j++, p1++) { + p2 = *p1; if (!p2) continue; -- cgit v1.2.3 From 949fafcd7fa310e68bfd8828304150cdc9de5629 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:26 +0200 Subject: tty/vt: consolemap: check put_user() in con_get_unimap() Only the return value of copy_to_user() is checked in con_get_unimap(). Do the same for put_user() of the count too. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-16-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 831450f2bfd1..92b5dddb00d9 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -813,7 +813,8 @@ unlock: console_unlock(); if (copy_to_user(list, unilist, min(ect, ct) * sizeof(*unilist))) ret = -EFAULT; - put_user(ect, uct); + if (put_user(ect, uct)) + ret = -EFAULT; kvfree(unilist); return ret ? ret : (ect <= ct) ? 0 : -ENOMEM; } -- cgit v1.2.3 From 5a904a936b407624cd1ff5ee3f1675ca3d2366a5 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:27 +0200 Subject: tty/vt: consolemap: introduce enum translation_map and use it Again, instead of magic constants in the code, declare an enum and be a little bit more explicit. Both in the translations definition and in the loops etc. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-17-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 39 ++++++++++++++++++++------------------- include/linux/consolemap.h | 18 ++++++++++++------ 2 files changed, 32 insertions(+), 25 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 92b5dddb00d9..80536687acef 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -38,7 +38,7 @@ static unsigned short translations[][256] = { /* 8-bit Latin-1 mapped to Unicode -- trivial mapping */ - { + [LAT1_MAP] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, @@ -71,9 +71,9 @@ static unsigned short translations[][256] = { 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff - }, + }, /* VT100 graphics mapped to Unicode */ - { + [GRAF_MAP] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, @@ -108,8 +108,8 @@ static unsigned short translations[][256] = { 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff }, /* IBM Codepage 437 mapped to Unicode */ - { - 0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, + [IBMPC_MAP] = { + 0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, 0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c, 0x25b6, 0x25c0, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8, 0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2, 0x25bc, @@ -141,9 +141,9 @@ static unsigned short translations[][256] = { 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 - }, + }, /* User mapping -- default to codes for direct font mapping */ - { + [USER_MAP] = { 0xf000, 0xf001, 0xf002, 0xf003, 0xf004, 0xf005, 0xf006, 0xf007, 0xf008, 0xf009, 0xf00a, 0xf00b, 0xf00c, 0xf00d, 0xf00e, 0xf00f, 0xf010, 0xf011, 0xf012, 0xf013, 0xf014, 0xf015, 0xf016, 0xf017, @@ -184,7 +184,7 @@ static unsigned short translations[][256] = { #define MAX_GLYPH 512 /* Max possible glyph value */ -static int inv_translate[MAX_NR_CONSOLES]; +static enum translation_map inv_translate[MAX_NR_CONSOLES]; #define UNI_DIRS 32U #define UNI_DIR_ROWS 32U @@ -208,24 +208,25 @@ struct uni_pagedict { u16 **uni_pgdir[UNI_DIRS]; unsigned long refcount; unsigned long sum; - unsigned char *inverse_translations[4]; + unsigned char *inverse_translations[LAST_MAP + 1]; u16 *inverse_trans_unicode; }; static struct uni_pagedict *dflt; -static void set_inverse_transl(struct vc_data *conp, struct uni_pagedict *p, int i) +static void set_inverse_transl(struct vc_data *conp, struct uni_pagedict *p, + enum translation_map m) { int j, glyph; - unsigned short *t = translations[i]; + unsigned short *t = translations[m]; unsigned char *q; if (!p) return; - q = p->inverse_translations[i]; + q = p->inverse_translations[m]; if (!q) { - q = p->inverse_translations[i] = kmalloc(MAX_GLYPH, GFP_KERNEL); + q = p->inverse_translations[m] = kmalloc(MAX_GLYPH, GFP_KERNEL); if (!q) return; } @@ -276,7 +277,7 @@ static void set_inverse_trans_unicode(struct vc_data *conp, } } -unsigned short *set_translate(int m, struct vc_data *vc) +unsigned short *set_translate(enum translation_map m, struct vc_data *vc) { inv_translate[vc->vc_num] = m; return translations[m]; @@ -292,7 +293,7 @@ unsigned short *set_translate(int m, struct vc_data *vc) u16 inverse_translate(const struct vc_data *conp, u16 glyph, bool use_unicode) { struct uni_pagedict *p; - int m; + enum translation_map m; if (glyph >= MAX_GLYPH) return 0; @@ -669,8 +670,8 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) if (con_unify_unimap(vc, p)) goto out_unlock; - for (i = 0; i <= 3; i++) - set_inverse_transl(vc, p, i); /* Update inverse translations */ + for (enum translation_map m = FIRST_MAP; m <= LAST_MAP; m++) + set_inverse_transl(vc, p, m); /* Update inverse translations */ set_inverse_trans_unicode(vc, p); out_unlock: @@ -731,8 +732,8 @@ int con_set_default_unimap(struct vc_data *vc) return err; } - for (i = 0; i <= 3; i++) - set_inverse_transl(vc, p, i); /* Update all inverse translations */ + for (enum translation_map m = FIRST_MAP; m <= LAST_MAP; m++) + set_inverse_transl(vc, p, m); /* Update all inverse translations */ set_inverse_trans_unicode(vc, p); dflt = p; return err; diff --git a/include/linux/consolemap.h b/include/linux/consolemap.h index 1ff2bf55eb85..c35db4896c37 100644 --- a/include/linux/consolemap.h +++ b/include/linux/consolemap.h @@ -7,10 +7,15 @@ #ifndef __LINUX_CONSOLEMAP_H__ #define __LINUX_CONSOLEMAP_H__ -#define LAT1_MAP 0 -#define GRAF_MAP 1 -#define IBMPC_MAP 2 -#define USER_MAP 3 +enum translation_map { + LAT1_MAP, + GRAF_MAP, + IBMPC_MAP, + USER_MAP, + + FIRST_MAP = LAT1_MAP, + LAST_MAP = USER_MAP, +}; #include @@ -18,7 +23,7 @@ struct vc_data; #ifdef CONFIG_CONSOLE_TRANSLATIONS u16 inverse_translate(const struct vc_data *conp, u16 glyph, bool use_unicode); -unsigned short *set_translate(int m, struct vc_data *vc); +unsigned short *set_translate(enum translation_map m, struct vc_data *vc); int conv_uni_to_pc(struct vc_data *conp, long ucs); u32 conv_8bit_to_uni(unsigned char c); int conv_uni_to_8bit(u32 uni); @@ -30,7 +35,8 @@ static inline u16 inverse_translate(const struct vc_data *conp, u16 glyph, return glyph; } -static inline unsigned short *set_translate(int m, struct vc_data *vc) +static inline unsigned short *set_translate(enum translation_map m, + struct vc_data *vc) { return NULL; } -- cgit v1.2.3 From f052f62c23b330717773b61bea19003e2e6a9ba2 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:28 +0200 Subject: tty/vt: consolemap: remove glyph < 0 check from set_inverse_trans_unicode() glyph is now an int casted from u16. It can never be negative. So remove the check and type glyph as u16 properly in set_inverse_trans_unicode(). Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-18-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 80536687acef..733795a3dc68 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -244,7 +244,7 @@ static void set_inverse_transl(struct vc_data *conp, struct uni_pagedict *p, static void set_inverse_trans_unicode(struct vc_data *conp, struct uni_pagedict *p) { - int i, j, k, glyph; + int i, j, k; u16 **p1, *p2; u16 *q; @@ -268,9 +268,8 @@ static void set_inverse_trans_unicode(struct vc_data *conp, if (!p2) continue; for (k = 0; k < UNI_ROW_GLYPHS; k++) { - glyph = p2[k]; - if (glyph >= 0 && glyph < MAX_GLYPH - && q[glyph] < 32) + u16 glyph = p2[k]; + if (glyph < MAX_GLYPH && q[glyph] < 32) q[glyph] = UNI(i, j, k); } } -- cgit v1.2.3 From dca141917301cc476cdc34d980470a4cd7dd9d75 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:29 +0200 Subject: tty/vt: consolemap: extract dict unsharing to con_unshare_unimap() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code in con_set_unimap() is too nested. Extract its obvious part into a separate function and name it after what the code does: con_unshare_unimap(). Reviewed-by: Ilpo Järvinen Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-19-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 133 ++++++++++++++++++++++---------------------- 1 file changed, 68 insertions(+), 65 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 733795a3dc68..eb5b4b519baf 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -562,11 +562,73 @@ int con_clear_unimap(struct vc_data *vc) console_unlock(); return ret; } - + +static struct uni_pagedict *con_unshare_unimap(struct vc_data *vc, + struct uni_pagedict *p) +{ + struct uni_pagedict *q; + u16 **p1, *p2, l; + int ret; + int i, j, k; + + ret = con_do_clear_unimap(vc); + if (ret) + return ERR_PTR(ret); + + /* + * Since refcount was > 1, con_clear_unimap() allocated a new + * uni_pagedict for this vc. Re: p != q + */ + q = *vc->vc_uni_pagedir_loc; + + /* + * uni_pgdir is a 32*32*64 table with rows allocated when its first + * entry is added. The unicode value must still be incremented for + * empty rows. We are copying entries from "p" (old) to "q" (new). + */ + l = 0; /* unicode value */ + for (i = 0; i < UNI_DIRS; i++) { + p1 = p->uni_pgdir[i]; + if (!p1) { + /* Account for empty table */ + l += UNI_DIR_ROWS * UNI_ROW_GLYPHS; + continue; + } + + for (j = 0; j < UNI_DIR_ROWS; j++) { + p2 = p1[j]; + if (!p2) { + /* Account for row of 64 empty entries */ + l += UNI_ROW_GLYPHS; + continue; + } + + for (k = 0; k < UNI_ROW_GLYPHS; k++, l++) { + if (p2[k] == 0xffff) + continue; + /* + * Found one, copy entry for unicode l with + * fontpos value p2[k]. + */ + ret = con_insert_unipair(q, l, p2[k]); + if (ret) { + p->refcount++; + *vc->vc_uni_pagedir_loc = p; + con_release_unimap(q); + kfree(q); + return ERR_PTR(ret); + } + } + } + } + + return q; +} + int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) { - int err = 0, err1, i; - struct uni_pagedict *p, *q; + int err = 0, err1; + struct uni_pagedict *p; struct unipair *unilist, *plist; if (!ct) @@ -586,70 +648,11 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) } if (p->refcount > 1) { - int j, k; - u16 **p1, *p2, l; - - err1 = con_do_clear_unimap(vc); - if (err1) { - err = err1; + p = con_unshare_unimap(vc, p); + if (IS_ERR(p)) { + err = PTR_ERR(p); goto out_unlock; } - - /* - * Since refcount was > 1, con_clear_unimap() allocated a - * a new uni_pagedict for this vc. Re: p != q - */ - q = *vc->vc_uni_pagedir_loc; - - /* - * uni_pgdir is a 32*32*64 table with rows allocated - * when its first entry is added. The unicode value must - * still be incremented for empty rows. We are copying - * entries from "p" (old) to "q" (new). - */ - l = 0; /* unicode value */ - for (i = 0; i < UNI_DIRS; i++) { - p1 = p->uni_pgdir[i]; - if (!p1) { - /* Account for empty table */ - l += UNI_DIR_ROWS * UNI_ROW_GLYPHS; - continue; - } - - for (j = 0; j < UNI_DIR_ROWS; j++) { - p2 = p1[j]; - if (!p2) { - /* - * Account for row of 64 empty entries - */ - l += UNI_ROW_GLYPHS; - continue; - } - - for (k = 0; k < UNI_ROW_GLYPHS; k++, l++) { - if (p2[k] == 0xffff) - continue; - /* - * Found one, copy entry for unicode - * l with fontpos value p2[k]. - */ - err1 = con_insert_unipair(q, l, p2[k]); - if (err1) { - p->refcount++; - *vc->vc_uni_pagedir_loc = p; - con_release_unimap(q); - kfree(q); - err = err1; - goto out_unlock; - } - } - } - } - - /* - * Finished copying font table, set vc_uni_pagedir to new table - */ - p = q; } else if (p == dflt) { dflt = NULL; } -- cgit v1.2.3 From 50c92a1b2d50611d49a8027027536c7a5003d049 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:30 +0200 Subject: tty/vt: consolemap: saner variable names in set_inverse_trans_unicode() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function uses too vague variable names like i, j, k for iterators, p, q, p1, p2 for pointers etc. Rename all these, so that it is clear what is going on: - dict: for dictionaries. - d, r, g: for dir, row, glyph iterators -- these are unsigned now. - dir, row: for directory and row pointers. - glyph: for the glyph. - and so on... This is a lot of shuffling, but the result pays off, IMO. Reviewed-by: Ilpo Järvinen Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-20-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index eb5b4b519baf..3763a73706b2 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -244,33 +244,33 @@ static void set_inverse_transl(struct vc_data *conp, struct uni_pagedict *p, static void set_inverse_trans_unicode(struct vc_data *conp, struct uni_pagedict *p) { - int i, j, k; - u16 **p1, *p2; - u16 *q; + unsigned int d, r, g; + u16 *inv; if (!p) return; - q = p->inverse_trans_unicode; - if (!q) { - q = p->inverse_trans_unicode = kmalloc_array(MAX_GLYPH, - sizeof(*q), GFP_KERNEL); - if (!q) + + inv = p->inverse_trans_unicode; + if (!inv) { + inv = p->inverse_trans_unicode = kmalloc_array(MAX_GLYPH, + sizeof(*inv), GFP_KERNEL); + if (!inv) return; } - memset(q, 0, MAX_GLYPH * sizeof(*q)); + memset(inv, 0, MAX_GLYPH * sizeof(*inv)); - for (i = 0; i < UNI_DIRS; i++) { - p1 = p->uni_pgdir[i]; - if (!p1) + for (d = 0; d < UNI_DIRS; d++) { + u16 **dir = p->uni_pgdir[d]; + if (!dir) continue; - for (j = 0; j < UNI_DIR_ROWS; j++) { - p2 = p1[j]; - if (!p2) + for (r = 0; r < UNI_DIR_ROWS; r++) { + u16 *row = dir[r]; + if (!row) continue; - for (k = 0; k < UNI_ROW_GLYPHS; k++) { - u16 glyph = p2[k]; - if (glyph < MAX_GLYPH && q[glyph] < 32) - q[glyph] = UNI(i, j, k); + for (g = 0; g < UNI_ROW_GLYPHS; g++) { + u16 glyph = row[g]; + if (glyph < MAX_GLYPH && inv[glyph] < 32) + inv[glyph] = UNI(d, r, g); } } } -- cgit v1.2.3 From 61fe4a6bb16fd411ba9c779413006a503649f862 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:31 +0200 Subject: tty/vt: consolemap: saner variable names in conv_uni_to_pc() The function uses too vague variable names like i, j, k for iterators, p, q, p1, p2 for pointers etc. Rename all these, so that it is clear what is going on: - dict: for dictionaries. - d, r, g: for dir, row, glyph iterators -- these are unsigned now. - dir, row: for directory and row pointers. - glyph: for the glyph. - and so on... Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-21-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 3763a73706b2..374b1ba20635 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -852,10 +852,9 @@ int conv_uni_to_8bit(u32 uni) int conv_uni_to_pc(struct vc_data *conp, long ucs) { - int h; - u16 **p1, *p2; - struct uni_pagedict *p; - + struct uni_pagedict *dict; + u16 **dir, *row, glyph; + /* Only 16-bit codes supported at this time */ if (ucs > 0xffff) return -4; /* Not found */ @@ -874,11 +873,11 @@ conv_uni_to_pc(struct vc_data *conp, long ucs) if (!*conp->vc_uni_pagedir_loc) return -3; - p = *conp->vc_uni_pagedir_loc; - if ((p1 = p->uni_pgdir[UNI_DIR(ucs)]) && - (p2 = p1[UNI_ROW(ucs)]) && - (h = p2[UNI_GLYPH(ucs)]) < MAX_GLYPH) - return h; + dict = *conp->vc_uni_pagedir_loc; + if ((dir = dict->uni_pgdir[UNI_DIR(ucs)]) && + (row = dir[UNI_ROW(ucs)]) && + (glyph = row[UNI_GLYPH(ucs)]) < MAX_GLYPH) + return glyph; return -4; /* not found */ } -- cgit v1.2.3 From d4a2245b8bccca61744a96a3bdc33a0b0534fa6e Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:32 +0200 Subject: tty/vt: consolemap: saner variable names in con_insert_unipair() The function uses too vague variable names like i, j, k for iterators, p, q, p1, p2 for pointers etc. Rename all these, so that it is clear what is going on: - dict: for dictionaries. - d, r, g: for dir, row, glyph iterators -- these are unsigned now. - dir, row: for directory and row pointers. - glyph: for the glyph. - and so on... This is a lot of shuffling, but the result pays off, IMO. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-22-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 374b1ba20635..2454a4395722 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -499,31 +499,31 @@ static int con_unify_unimap(struct vc_data *conp, struct uni_pagedict *p) static int con_insert_unipair(struct uni_pagedict *p, u_short unicode, u_short fontpos) { - int n; - u16 **p1, *p2; + u16 **dir, *row; + unsigned int n; n = UNI_DIR(unicode); - p1 = p->uni_pgdir[n]; - if (!p1) { - p1 = p->uni_pgdir[n] = kcalloc(UNI_DIR_ROWS, sizeof(*p1), + dir = p->uni_pgdir[n]; + if (!dir) { + dir = p->uni_pgdir[n] = kcalloc(UNI_DIR_ROWS, sizeof(*dir), GFP_KERNEL); - if (!p1) + if (!dir) return -ENOMEM; } n = UNI_ROW(unicode); - p2 = p1[n]; - if (!p2) { - p2 = p1[n] = kmalloc_array(UNI_ROW_GLYPHS, sizeof(*p2), + row = dir[n]; + if (!row) { + row = dir[n] = kmalloc_array(UNI_ROW_GLYPHS, sizeof(*row), GFP_KERNEL); - if (!p2) + if (!row) return -ENOMEM; /* No glyphs for the characters (yet) */ - memset(p2, 0xff, UNI_ROW_GLYPHS * sizeof(*p2)); + memset(row, 0xff, UNI_ROW_GLYPHS * sizeof(*row)); } - p2[UNI_GLYPH(unicode)] = fontpos; - + row[UNI_GLYPH(unicode)] = fontpos; + p->sum += (fontpos << 20U) + unicode; return 0; -- cgit v1.2.3 From c3fd9f7121f0a9619f8a8ef53c9f543bcc522dfe Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:33 +0200 Subject: tty/vt: consolemap: saner variable names in con_unify_unimap() The function uses too vague variable names like i, j, k for iterators, p, q, p1, p2 for pointers etc. Rename all these, so that it is clear what is going on: - dict: for dictionaries. - d, r, g: for dir, row, glyph iterators -- these are unsigned now. - dir, row: for directory and row pointers. - glyph: for the glyph. - and so on... This is a lot of shuffling, but the result pays off, IMO. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-23-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 49 ++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 25 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 2454a4395722..cbdc73605148 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -454,42 +454,41 @@ void con_free_unimap(struct vc_data *vc) kfree(p); } -static int con_unify_unimap(struct vc_data *conp, struct uni_pagedict *p) +static int con_unify_unimap(struct vc_data *conp, struct uni_pagedict *dict1) { - int i, j, k; - struct uni_pagedict *q; - - for (i = 0; i < MAX_NR_CONSOLES; i++) { - if (!vc_cons_allocated(i)) + struct uni_pagedict *dict2; + unsigned int cons, d, r; + + for (cons = 0; cons < MAX_NR_CONSOLES; cons++) { + if (!vc_cons_allocated(cons)) continue; - q = *vc_cons[i].d->vc_uni_pagedir_loc; - if (!q || q == p || q->sum != p->sum) + dict2 = *vc_cons[cons].d->vc_uni_pagedir_loc; + if (!dict2 || dict2 == dict1 || dict2->sum != dict1->sum) continue; - for (j = 0; j < UNI_DIRS; j++) { - u16 **p1, **q1; - p1 = p->uni_pgdir[j]; - q1 = q->uni_pgdir[j]; - if (!p1 && !q1) + for (d = 0; d < UNI_DIRS; d++) { + u16 **dir1 = dict1->uni_pgdir[d]; + u16 **dir2 = dict2->uni_pgdir[d]; + if (!dir1 && !dir2) continue; - if (!p1 || !q1) + if (!dir1 || !dir2) break; - for (k = 0; k < UNI_DIR_ROWS; k++) { - if (!p1[k] && !q1[k]) + for (r = 0; r < UNI_DIR_ROWS; r++) { + if (!dir1[r] && !dir2[r]) continue; - if (!p1[k] || !q1[k]) + if (!dir1[r] || !dir2[r]) break; - if (memcmp(p1[k], q1[k], UNI_ROW_GLYPHS * - sizeof(*p1[k]))) + if (memcmp(dir1[r], dir2[r], UNI_ROW_GLYPHS * + sizeof(*dir1[r]))) break; } - if (k < UNI_DIR_ROWS) + if (r < UNI_DIR_ROWS) break; } - if (j == UNI_DIRS) { - q->refcount++; - *conp->vc_uni_pagedir_loc = q; - con_release_unimap(p); - kfree(p); + if (d == UNI_DIRS) { + dict2->refcount++; + *conp->vc_uni_pagedir_loc = dict2; + con_release_unimap(dict1); + kfree(dict1); return 1; } } -- cgit v1.2.3 From 01ddc0dabd1bd3bb8a1c0ad87887882653034c01 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:34 +0200 Subject: tty/vt: consolemap: saner variable names in con_do_clear_unimap() The function uses too vague variable names like i, j, k for iterators, p, q, p1, p2 for pointers etc. Rename all these, so that it is clear what is going on: - dict: for dictionaries. - d, r, g: for dir, row, glyph iterators -- these are unsigned now. - dir, row: for directory and row pointers. - glyph: for the glyph. - and so on... This is a lot of shuffling, but the result pays off, IMO. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-24-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index cbdc73605148..456aed3f717c 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -531,24 +531,23 @@ con_insert_unipair(struct uni_pagedict *p, u_short unicode, u_short fontpos) /* Caller must hold the lock */ static int con_do_clear_unimap(struct vc_data *vc) { - struct uni_pagedict *p, *q; + struct uni_pagedict *old = *vc->vc_uni_pagedir_loc; - p = *vc->vc_uni_pagedir_loc; - if (!p || --p->refcount) { - q = kzalloc(sizeof(*p), GFP_KERNEL); - if (!q) { - if (p) - p->refcount++; + if (!old || --old->refcount) { + struct uni_pagedict *new = kzalloc(sizeof(*new), GFP_KERNEL); + if (!new) { + if (old) + old->refcount++; return -ENOMEM; } - q->refcount=1; - *vc->vc_uni_pagedir_loc = q; + new->refcount = 1; + *vc->vc_uni_pagedir_loc = new; } else { - if (p == dflt) + if (old == dflt) dflt = NULL; - p->refcount++; - p->sum = 0; - con_release_unimap(p); + old->refcount++; + old->sum = 0; + con_release_unimap(old); } return 0; } -- cgit v1.2.3 From cded789c6889272412702a72cb84170ee746ce79 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:35 +0200 Subject: tty/vt: consolemap: saner variable names in con_unshare_unimap() The function uses too vague variable names like i, j, k for iterators, p, q, p1, p2 for pointers etc. Rename all these, so that it is clear what is going on: - dict: for dictionaries. - d, r, g: for dir, row, glyph iterators -- these are unsigned now. - dir, row: for directory and row pointers. - glyph: for the glyph. - and so on... This is a lot of shuffling, but the result pays off, IMO. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-25-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 51 ++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 26 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 456aed3f717c..7e353455945d 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -562,12 +562,12 @@ int con_clear_unimap(struct vc_data *vc) } static struct uni_pagedict *con_unshare_unimap(struct vc_data *vc, - struct uni_pagedict *p) + struct uni_pagedict *old) { - struct uni_pagedict *q; - u16 **p1, *p2, l; + struct uni_pagedict *new; + unsigned int d, r, g; int ret; - int i, j, k; + u16 uni = 0; ret = con_do_clear_unimap(vc); if (ret) @@ -575,52 +575,51 @@ static struct uni_pagedict *con_unshare_unimap(struct vc_data *vc, /* * Since refcount was > 1, con_clear_unimap() allocated a new - * uni_pagedict for this vc. Re: p != q + * uni_pagedict for this vc. Re: old != new */ - q = *vc->vc_uni_pagedir_loc; + new = *vc->vc_uni_pagedir_loc; /* * uni_pgdir is a 32*32*64 table with rows allocated when its first * entry is added. The unicode value must still be incremented for - * empty rows. We are copying entries from "p" (old) to "q" (new). + * empty rows. We are copying entries from "old" to "new". */ - l = 0; /* unicode value */ - for (i = 0; i < UNI_DIRS; i++) { - p1 = p->uni_pgdir[i]; - if (!p1) { + for (d = 0; d < UNI_DIRS; d++) { + u16 **dir = old->uni_pgdir[d]; + if (!dir) { /* Account for empty table */ - l += UNI_DIR_ROWS * UNI_ROW_GLYPHS; + uni += UNI_DIR_ROWS * UNI_ROW_GLYPHS; continue; } - for (j = 0; j < UNI_DIR_ROWS; j++) { - p2 = p1[j]; - if (!p2) { + for (r = 0; r < UNI_DIR_ROWS; r++) { + u16 *row = dir[r]; + if (!row) { /* Account for row of 64 empty entries */ - l += UNI_ROW_GLYPHS; + uni += UNI_ROW_GLYPHS; continue; } - for (k = 0; k < UNI_ROW_GLYPHS; k++, l++) { - if (p2[k] == 0xffff) + for (g = 0; g < UNI_ROW_GLYPHS; g++, uni++) { + if (row[g] == 0xffff) continue; /* - * Found one, copy entry for unicode l with - * fontpos value p2[k]. + * Found one, copy entry for unicode uni with + * fontpos value row[g]. */ - ret = con_insert_unipair(q, l, p2[k]); + ret = con_insert_unipair(new, uni, row[g]); if (ret) { - p->refcount++; - *vc->vc_uni_pagedir_loc = p; - con_release_unimap(q); - kfree(q); + old->refcount++; + *vc->vc_uni_pagedir_loc = old; + con_release_unimap(new); + kfree(new); return ERR_PTR(ret); } } } } - return q; + return new; } int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) -- cgit v1.2.3 From 447e9a7c668113e85e2b6a7a330a3b517cae6c93 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:36 +0200 Subject: tty/vt: consolemap: saner variable names in con_release_unimap() The function uses too vague variable names like i, j, k for iterators, p, q, p1, p2 for pointers etc. Rename all these, so that it is clear what is going on: - dict: for dictionaries. - d, r, g: for dir, row, glyph iterators -- these are unsigned now. - dir, row: for directory and row pointers. - glyph: for the glyph. - and so on... This is a lot of shuffling, but the result pays off, IMO. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-26-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 7e353455945d..255d4e92a9d0 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -415,28 +415,30 @@ int con_get_trans_new(ushort __user * arg) extern u8 dfont_unicount[]; /* Defined in console_defmap.c */ extern u16 dfont_unitable[]; -static void con_release_unimap(struct uni_pagedict *p) +static void con_release_unimap(struct uni_pagedict *dict) { - u16 **p1; - int i, j; + unsigned int d, r; - if (p == dflt) + if (dict == dflt) dflt = NULL; - for (i = 0; i < UNI_DIRS; i++) { - p1 = p->uni_pgdir[i]; - if (p1 != NULL) { - for (j = 0; j < UNI_DIR_ROWS; j++) - kfree(p1[j]); - kfree(p1); + + for (d = 0; d < UNI_DIRS; d++) { + u16 **dir = dict->uni_pgdir[d]; + if (dir != NULL) { + for (r = 0; r < UNI_DIR_ROWS; r++) + kfree(dir[r]); + kfree(dir); } - p->uni_pgdir[i] = NULL; + dict->uni_pgdir[d] = NULL; } - for (i = 0; i < ARRAY_SIZE(p->inverse_translations); i++) { - kfree(p->inverse_translations[i]); - p->inverse_translations[i] = NULL; + + for (r = 0; r < ARRAY_SIZE(dict->inverse_translations); r++) { + kfree(dict->inverse_translations[r]); + dict->inverse_translations[r] = NULL; } - kfree(p->inverse_trans_unicode); - p->inverse_trans_unicode = NULL; + + kfree(dict->inverse_trans_unicode); + dict->inverse_trans_unicode = NULL; } /* Caller must hold the console lock */ -- cgit v1.2.3 From 3315f1aa85212960d1d0978f068f605e8ce000ea Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:37 +0200 Subject: tty/vt: consolemap: saner variable names in con_copy_unimap() The function uses too vague variable names like i, j, k for iterators, p, q, p1, p2 for pointers etc. Rename all these, so that it is clear what is going on: - dict: for dictionaries. - d, r, g: for dir, row, glyph iterators -- these are unsigned now. - dir, row: for directory and row pointers. - glyph: for the glyph. - and so on... This is a lot of shuffling, but the result pays off, IMO. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-27-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 255d4e92a9d0..dcbeb38a3a0a 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -750,16 +750,16 @@ EXPORT_SYMBOL(con_set_default_unimap); */ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc) { - struct uni_pagedict *q; + struct uni_pagedict *src; if (!*src_vc->vc_uni_pagedir_loc) return -EINVAL; if (*dst_vc->vc_uni_pagedir_loc == *src_vc->vc_uni_pagedir_loc) return 0; con_free_unimap(dst_vc); - q = *src_vc->vc_uni_pagedir_loc; - q->refcount++; - *dst_vc->vc_uni_pagedir_loc = q; + src = *src_vc->vc_uni_pagedir_loc; + src->refcount++; + *dst_vc->vc_uni_pagedir_loc = src; return 0; } EXPORT_SYMBOL(con_copy_unimap); -- cgit v1.2.3 From 5a79458c5613d965786eadc277c4b6473cecbb52 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:38 +0200 Subject: tty/vt: consolemap: saner variable names in con_get_unimap() The function uses too vague variable names like i, j, k for iterators, p, q, p1, p2 for pointers etc. Rename all these, so that it is clear what is going on: - dict: for dictionaries. - d, r, g: for dir, row, glyph iterators -- these are unsigned now. - dir, row: for directory and row pointers. - glyph: for the glyph. - and so on... Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-28-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index dcbeb38a3a0a..b8f2acb6e388 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -773,11 +773,11 @@ EXPORT_SYMBOL(con_copy_unimap); int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list) { - int i, j, k, ret = 0; ushort ect; - u16 **p1, *p2; - struct uni_pagedict *p; + struct uni_pagedict *dict; struct unipair *unilist; + unsigned int d, r, g; + int ret = 0; unilist = kvmalloc_array(ct, sizeof(*unilist), GFP_KERNEL); if (!unilist) @@ -786,26 +786,26 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, console_lock(); ect = 0; - p = *vc->vc_uni_pagedir_loc; - if (!p) + dict = *vc->vc_uni_pagedir_loc; + if (!dict) goto unlock; - for (i = 0; i < UNI_DIRS; i++) { - p1 = p->uni_pgdir[i]; - if (!p1) + for (d = 0; d < UNI_DIRS; d++) { + u16 **dir = dict->uni_pgdir[d]; + if (!dir) continue; - for (j = 0; j < UNI_DIR_ROWS; j++, p1++) { - p2 = *p1; - if (!p2) + for (r = 0; r < UNI_DIR_ROWS; r++) { + u16 *row = dir[r]; + if (!row) continue; - for (k = 0; k < UNI_ROW_GLYPHS; k++, p2++) { - if (*p2 >= MAX_GLYPH) + for (g = 0; g < UNI_ROW_GLYPHS; g++, row++) { + if (*row >= MAX_GLYPH) continue; if (ect < ct) { - unilist[ect].unicode = UNI(i, j, k); - unilist[ect].fontpos = *p2; + unilist[ect].unicode = UNI(d, r, g); + unilist[ect].fontpos = *row; } ect++; } -- cgit v1.2.3 From ff4606acb4dcf05c49a6053c26f1bacb5753d200 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:39 +0200 Subject: tty/vt: consolemap: saner variable names in con_set_unimap() The function uses too vague variable names like i, j, k for iterators, p, q, p1, p2 for pointers etc. Rename all these, so that it is clear what is going on: - dict: for dictionaries. - d, r, g: for dir, row, glyph iterators -- these are unsigned now. - dir, row: for directory and row pointers. - glyph: for the glyph. - and so on... This is a lot of shuffling, but the result pays off, IMO. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-29-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index b8f2acb6e388..65c83f9228e9 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -627,7 +627,7 @@ static struct uni_pagedict *con_unshare_unimap(struct vc_data *vc, int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) { int err = 0, err1; - struct uni_pagedict *p; + struct uni_pagedict *dict; struct unipair *unilist, *plist; if (!ct) @@ -640,19 +640,19 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) console_lock(); /* Save original vc_unipagdir_loc in case we allocate a new one */ - p = *vc->vc_uni_pagedir_loc; - if (!p) { + dict = *vc->vc_uni_pagedir_loc; + if (!dict) { err = -EINVAL; goto out_unlock; } - if (p->refcount > 1) { - p = con_unshare_unimap(vc, p); - if (IS_ERR(p)) { - err = PTR_ERR(p); + if (dict->refcount > 1) { + dict = con_unshare_unimap(vc, dict); + if (IS_ERR(dict)) { + err = PTR_ERR(dict); goto out_unlock; } - } else if (p == dflt) { + } else if (dict == dflt) { dflt = NULL; } @@ -660,7 +660,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) * Insert user specified unicode pairs into new table. */ for (plist = unilist; ct; ct--, plist++) { - err1 = con_insert_unipair(p, plist->unicode, plist->fontpos); + err1 = con_insert_unipair(dict, plist->unicode, plist->fontpos); if (err1) err = err1; } @@ -668,12 +668,12 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) /* * Merge with fontmaps of any other virtual consoles. */ - if (con_unify_unimap(vc, p)) + if (con_unify_unimap(vc, dict)) goto out_unlock; for (enum translation_map m = FIRST_MAP; m <= LAST_MAP; m++) - set_inverse_transl(vc, p, m); /* Update inverse translations */ - set_inverse_trans_unicode(vc, p); + set_inverse_transl(vc, dict, m); + set_inverse_trans_unicode(vc, dict); out_unlock: console_unlock(); -- cgit v1.2.3 From 1a086f5d63ae3f9bfa85a6ddfc3c377315a56187 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:40 +0200 Subject: tty/vt: consolemap: saner variable names in con_set_default_unimap() The function uses too vague variable names like i, j, k for iterators, p, q, p1, p2 for pointers etc. Rename all these, so that it is clear what is going on: - dict: for dictionaries. - d, r, g: for dir, row, glyph iterators -- these are unsigned now. - dir, row: for directory and row pointers. - glyph: for the glyph. - and so on... This is a lot of shuffling, but the result pays off, IMO. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-30-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 65c83f9228e9..8abf114b6c68 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -694,49 +694,50 @@ out_unlock: */ int con_set_default_unimap(struct vc_data *vc) { - int i, j, err = 0, err1; - u16 *q; - struct uni_pagedict *p; + struct uni_pagedict *dict; + unsigned int fontpos, count; + int err = 0, err1; + u16 *dfont; if (dflt) { - p = *vc->vc_uni_pagedir_loc; - if (p == dflt) + dict = *vc->vc_uni_pagedir_loc; + if (dict == dflt) return 0; dflt->refcount++; *vc->vc_uni_pagedir_loc = dflt; - if (p && !--p->refcount) { - con_release_unimap(p); - kfree(p); + if (dict && !--dict->refcount) { + con_release_unimap(dict); + kfree(dict); } return 0; } - + /* The default font is always 256 characters */ err = con_do_clear_unimap(vc); if (err) return err; - - p = *vc->vc_uni_pagedir_loc; - q = dfont_unitable; - - for (i = 0; i < 256; i++) - for (j = dfont_unicount[i]; j; j--) { - err1 = con_insert_unipair(p, *(q++), i); + + dict = *vc->vc_uni_pagedir_loc; + dfont = dfont_unitable; + + for (fontpos = 0; fontpos < 256U; fontpos++) + for (count = dfont_unicount[fontpos]; count; count--) { + err1 = con_insert_unipair(dict, *(dfont++), fontpos); if (err1) err = err1; } - - if (con_unify_unimap(vc, p)) { + + if (con_unify_unimap(vc, dict)) { dflt = *vc->vc_uni_pagedir_loc; return err; } for (enum translation_map m = FIRST_MAP; m <= LAST_MAP; m++) - set_inverse_transl(vc, p, m); /* Update all inverse translations */ - set_inverse_trans_unicode(vc, p); - dflt = p; + set_inverse_transl(vc, dict, m); + set_inverse_trans_unicode(vc, dict); + dflt = dict; return err; } EXPORT_SYMBOL(con_set_default_unimap); -- cgit v1.2.3 From 9ec9b79a2b9b44c33510156906a6e7c0cef7047e Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:41 +0200 Subject: tty/vt: consolemap: make conv_uni_to_pc() more readable 1) Fetch *conp->vc_uni_pagedir_loc first and do the NULL check on the local variable. 2) Decouple the large "if" into few smaller "if"s. 3) Remove a \n from the definition line. This makes the code more readable. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-31-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 8abf114b6c68..a9b497ffb346 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -849,8 +849,7 @@ int conv_uni_to_8bit(u32 uni) return -1; } -int -conv_uni_to_pc(struct vc_data *conp, long ucs) +int conv_uni_to_pc(struct vc_data *conp, long ucs) { struct uni_pagedict *dict; u16 **dir, *row, glyph; @@ -869,17 +868,24 @@ conv_uni_to_pc(struct vc_data *conp, long ucs) */ else if ((ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE) return ucs & UNI_DIRECT_MASK; - - if (!*conp->vc_uni_pagedir_loc) - return -3; dict = *conp->vc_uni_pagedir_loc; - if ((dir = dict->uni_pgdir[UNI_DIR(ucs)]) && - (row = dir[UNI_ROW(ucs)]) && - (glyph = row[UNI_GLYPH(ucs)]) < MAX_GLYPH) - return glyph; + if (!dict) + return -3; + + dir = dict->uni_pgdir[UNI_DIR(ucs)]; + if (!dir) + return -4; + + row = dir[UNI_ROW(ucs)]; + if (!row) + return -4; + + glyph = row[UNI_GLYPH(ucs)]; + if (glyph >= MAX_GLYPH) + return -4; - return -4; /* not found */ + return glyph; } /* -- cgit v1.2.3 From d8d0d1758c7d5ef37066f1122eb236d47b2948a9 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:42 +0200 Subject: tty/vt: consolemap: remove superfluous whitespace There are still some remaining tabs/spaces at EOLs or spaces before tabs. Remove them all now. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-32-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index a9b497ffb346..01b7e49f1f91 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -220,7 +220,7 @@ static void set_inverse_transl(struct vc_data *conp, struct uni_pagedict *p, int j, glyph; unsigned short *t = translations[m]; unsigned char *q; - + if (!p) return; q = p->inverse_translations[m]; @@ -236,7 +236,7 @@ static void set_inverse_transl(struct vc_data *conp, struct uni_pagedict *p, glyph = conv_uni_to_pc(conp, t[j]); if (glyph >= 0 && glyph < MAX_GLYPH && q[glyph] < 32) { /* prefer '-' above SHY etc. */ - q[glyph] = j; + q[glyph] = j; } } } @@ -320,7 +320,7 @@ static void update_user_maps(void) { int i; struct uni_pagedict *p, *q = NULL; - + for (i = 0; i < MAX_NR_CONSOLES; i++) { if (!vc_cons_allocated(i)) continue; @@ -403,7 +403,7 @@ int con_get_trans_new(ushort __user * arg) } /* - * Unicode -> current font conversion + * Unicode -> current font conversion * * A font has at most 512 chars, usually 256. * But one font position may represent several Unicode chars. @@ -455,7 +455,7 @@ void con_free_unimap(struct vc_data *vc) con_release_unimap(p); kfree(p); } - + static int con_unify_unimap(struct vc_data *conp, struct uni_pagedict *dict1) { struct uni_pagedict *dict2; @@ -688,7 +688,7 @@ out_unlock: * Loads the unimap for the hardware font, as defined in uni_hash.tbl. * The representation used was the most compact I could come up * with. This routine is executed at video setup, and when the - * PIO_FONTRESET ioctl is called. + * PIO_FONTRESET ioctl is called. * * The caller must hold the console lock */ @@ -893,11 +893,11 @@ int conv_uni_to_pc(struct vc_data *conp, long ucs) * initialized. It must be possible to call kmalloc(..., GFP_KERNEL) * from this function, hence the call from sys_setup. */ -void __init +void __init console_map_init(void) { int i; - + for (i = 0; i < MAX_NR_CONSOLES; i++) if (vc_cons_allocated(i) && !*vc_cons[i].d->vc_uni_pagedir_loc) con_set_default_unimap(vc_cons[i].d); -- cgit v1.2.3 From a7e50de460d7d9230dc065c9d2f1a1b1669c675c Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:43 +0200 Subject: tty/vt: consolemap: change refcount only if needed in con_do_clear_unimap() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit con_do_clear_unimap() currently decreases and increases refcount of old dictionary in a back and forth fashion. This makes the code really hard to follow. Decrease the refcount only if everything went well and we really allocated a new one and decoupled from the old dictionary. I sincerelly hope I did not make a mistake in this (ill) logic. Reviewed-by: Ilpo Järvinen Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-33-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 01b7e49f1f91..4d8efe74315c 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -535,22 +535,23 @@ static int con_do_clear_unimap(struct vc_data *vc) { struct uni_pagedict *old = *vc->vc_uni_pagedir_loc; - if (!old || --old->refcount) { + if (!old || old->refcount > 1) { struct uni_pagedict *new = kzalloc(sizeof(*new), GFP_KERNEL); - if (!new) { - if (old) - old->refcount++; + if (!new) return -ENOMEM; - } + new->refcount = 1; *vc->vc_uni_pagedir_loc = new; + + if (old) + old->refcount--; } else { if (old == dflt) dflt = NULL; - old->refcount++; old->sum = 0; con_release_unimap(old); } + return 0; } -- cgit v1.2.3 From 63c4f92fcca3f077de1d9d1a99a690f5ea381e58 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:44 +0200 Subject: tty/vt: consolemap: extract con_allocate_new() from con_do_clear_unimap() The first part of con_do_clear_unimap() is needed on another place, so extract it to a separate function called con_allocate_new(). It will be used once more in the next patch. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-34-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 4d8efe74315c..14d3fbff015c 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -530,27 +530,35 @@ con_insert_unipair(struct uni_pagedict *p, u_short unicode, u_short fontpos) return 0; } +static int con_allocate_new(struct vc_data *vc) +{ + struct uni_pagedict *new, *old = *vc->vc_uni_pagedir_loc; + + new = kzalloc(sizeof(*new), GFP_KERNEL); + if (!new) + return -ENOMEM; + + new->refcount = 1; + *vc->vc_uni_pagedir_loc = new; + + if (old) + old->refcount--; + + return 0; +} + /* Caller must hold the lock */ static int con_do_clear_unimap(struct vc_data *vc) { struct uni_pagedict *old = *vc->vc_uni_pagedir_loc; - if (!old || old->refcount > 1) { - struct uni_pagedict *new = kzalloc(sizeof(*new), GFP_KERNEL); - if (!new) - return -ENOMEM; - - new->refcount = 1; - *vc->vc_uni_pagedir_loc = new; + if (!old || old->refcount > 1) + return con_allocate_new(vc); - if (old) - old->refcount--; - } else { - if (old == dflt) - dflt = NULL; - old->sum = 0; - con_release_unimap(old); - } + if (old == dflt) + dflt = NULL; + old->sum = 0; + con_release_unimap(old); return 0; } -- cgit v1.2.3 From fc440658346e1bff9b6661467f55856d1df1cdb2 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:45 +0200 Subject: tty/vt: consolemap: use con_allocate_new() in con_unshare_unimap() The old->refcount is guaranteed to be > 1, so we can directly call con_allocate_new() to make the code more obvious. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-35-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 14d3fbff015c..f97f7ee6268b 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -580,14 +580,10 @@ static struct uni_pagedict *con_unshare_unimap(struct vc_data *vc, int ret; u16 uni = 0; - ret = con_do_clear_unimap(vc); + ret = con_allocate_new(vc); if (ret) return ERR_PTR(ret); - /* - * Since refcount was > 1, con_clear_unimap() allocated a new - * uni_pagedict for this vc. Re: old != new - */ new = *vc->vc_uni_pagedir_loc; /* -- cgit v1.2.3 From 484923ad3ad1604efa666502ac507b1e3ee30e3b Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:46 +0200 Subject: tty/vt: consolemap: walk the buffer only once in con_set_trans_old() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fetch the user data one by one (by get_user()) and fill in the local buffer simultaneously. I.e. we no longer require to walk two buffers and save thus 256 B from stack (whole ubuf). Reviewed-by: Ilpo Järvinen Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-36-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index f97f7ee6268b..fff97ae87e00 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -343,15 +343,15 @@ static void update_user_maps(void) */ int con_set_trans_old(unsigned char __user * arg) { - int i; unsigned short inbuf[E_TABSZ]; - unsigned char ubuf[E_TABSZ]; - - if (copy_from_user(ubuf, arg, E_TABSZ)) - return -EFAULT; + unsigned int i; + unsigned char ch; - for (i = 0; i < E_TABSZ ; i++) - inbuf[i] = UNI_DIRECT_BASE | ubuf[i]; + for (i = 0; i < ARRAY_SIZE(inbuf); i++) { + if (get_user(ch, &arg[i])) + return -EFAULT; + inbuf[i] = UNI_DIRECT_BASE | ch; + } console_lock(); memcpy(translations[USER_MAP], inbuf, sizeof(inbuf)); -- cgit v1.2.3 From 285e76fc049c4d32c772eea9460a7ef28a193802 Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Sun, 5 Jun 2022 17:46:56 +0300 Subject: serial: max310x: use regmap methods for SPI batch operations The SPI batch read/write operations can be implemented as simple regmap raw read and write, which will also try to do a gather write just as it is done here. Use the regmap raw read and write methods. Reviewed-by: Andy Shevchenko Signed-off-by: Cosmin Tanislav Link: https://lore.kernel.org/r/20220605144659.4169853-2-demonsingur@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 36 ++++++++---------------------------- 1 file changed, 8 insertions(+), 28 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index a0b6ea52d133..46887a4ffea4 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -259,8 +259,6 @@ struct max310x_one { struct work_struct md_work; struct work_struct rs_work; - u8 wr_header; - u8 rd_header; u8 rx_buf[MAX310X_FIFO_SIZE]; }; #define to_max310x_port(_port) \ @@ -623,32 +621,18 @@ static u32 max310x_set_ref_clk(struct device *dev, struct max310x_port *s, static void max310x_batch_write(struct uart_port *port, u8 *txbuf, unsigned int len) { - struct max310x_one *one = to_max310x_port(port); - struct spi_transfer xfer[] = { - { - .tx_buf = &one->wr_header, - .len = sizeof(one->wr_header), - }, { - .tx_buf = txbuf, - .len = len, - } - }; - spi_sync_transfer(to_spi_device(port->dev), xfer, ARRAY_SIZE(xfer)); + struct max310x_port *s = dev_get_drvdata(port->dev); + u8 reg = port->iobase + MAX310X_THR_REG; + + regmap_raw_write(s->regmap, reg, txbuf, len); } static void max310x_batch_read(struct uart_port *port, u8 *rxbuf, unsigned int len) { - struct max310x_one *one = to_max310x_port(port); - struct spi_transfer xfer[] = { - { - .tx_buf = &one->rd_header, - .len = sizeof(one->rd_header), - }, { - .rx_buf = rxbuf, - .len = len, - } - }; - spi_sync_transfer(to_spi_device(port->dev), xfer, ARRAY_SIZE(xfer)); + struct max310x_port *s = dev_get_drvdata(port->dev); + u8 reg = port->iobase + MAX310X_RHR_REG; + + regmap_raw_read(s->regmap, reg, rxbuf, len); } static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen) @@ -1368,10 +1352,6 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty INIT_WORK(&s->p[i].md_work, max310x_md_proc); /* Initialize queue for changing RS485 mode */ INIT_WORK(&s->p[i].rs_work, max310x_rs_proc); - /* Initialize SPI-transfer buffers */ - s->p[i].wr_header = (s->p[i].port.iobase + MAX310X_THR_REG) | - MAX310X_WRITE_BIT; - s->p[i].rd_header = (s->p[i].port.iobase + MAX310X_RHR_REG); /* Register port */ ret = uart_add_one_port(&max310x_uart, &s->p[i].port); -- cgit v1.2.3 From 6ef281daf020592c219fa91780abc381c6c20db5 Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Sun, 5 Jun 2022 17:46:57 +0300 Subject: serial: max310x: use a separate regmap for each port The driver currently does manual register manipulation in multiple places to talk to a specific UART port. In order to talk to a specific UART port over SPI, the bits U1 and U0 of the register address can be set, as explained in the Command byte configuration section of the datasheet. Make this more elegant by creating regmaps for each UART port and setting the read_flag_mask and write_flag_mask accordingly. All communcations regarding global registers are done on UART port 0, so replace the global regmap entirely with the port 0 regmap. Also, remove the 0x1f masks from reg_writeable(), reg_volatile() and reg_precious() methods, since setting the U1 and U0 bits of the register address happens inside the regmap core now. Reviewed-by: Andy Shevchenko Signed-off-by: Cosmin Tanislav Link: https://lore.kernel.org/r/20220605144659.4169853-3-demonsingur@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 68 +++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 32 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 46887a4ffea4..6fd133c177a3 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -258,6 +258,7 @@ struct max310x_one { struct work_struct tx_work; struct work_struct md_work; struct work_struct rs_work; + struct regmap *regmap; u8 rx_buf[MAX310X_FIFO_SIZE]; }; @@ -287,26 +288,26 @@ static DECLARE_BITMAP(max310x_lines, MAX310X_UART_NRMAX); static u8 max310x_port_read(struct uart_port *port, u8 reg) { - struct max310x_port *s = dev_get_drvdata(port->dev); + struct max310x_one *one = to_max310x_port(port); unsigned int val = 0; - regmap_read(s->regmap, port->iobase + reg, &val); + regmap_read(one->regmap, reg, &val); return val; } static void max310x_port_write(struct uart_port *port, u8 reg, u8 val) { - struct max310x_port *s = dev_get_drvdata(port->dev); + struct max310x_one *one = to_max310x_port(port); - regmap_write(s->regmap, port->iobase + reg, val); + regmap_write(one->regmap, reg, val); } static void max310x_port_update(struct uart_port *port, u8 reg, u8 mask, u8 val) { - struct max310x_port *s = dev_get_drvdata(port->dev); + struct max310x_one *one = to_max310x_port(port); - regmap_update_bits(s->regmap, port->iobase + reg, mask, val); + regmap_update_bits(one->regmap, reg, mask, val); } static int max3107_detect(struct device *dev) @@ -445,7 +446,7 @@ static const struct max310x_devtype max14830_devtype = { static bool max310x_reg_writeable(struct device *dev, unsigned int reg) { - switch (reg & 0x1f) { + switch (reg) { case MAX310X_IRQSTS_REG: case MAX310X_LSR_IRQSTS_REG: case MAX310X_SPCHR_IRQSTS_REG: @@ -462,7 +463,7 @@ static bool max310x_reg_writeable(struct device *dev, unsigned int reg) static bool max310x_reg_volatile(struct device *dev, unsigned int reg) { - switch (reg & 0x1f) { + switch (reg) { case MAX310X_RHR_REG: case MAX310X_IRQSTS_REG: case MAX310X_LSR_IRQSTS_REG: @@ -484,7 +485,7 @@ static bool max310x_reg_volatile(struct device *dev, unsigned int reg) static bool max310x_reg_precious(struct device *dev, unsigned int reg) { - switch (reg & 0x1f) { + switch (reg) { case MAX310X_RHR_REG: case MAX310X_IRQSTS_REG: case MAX310X_SPCHR_IRQSTS_REG: @@ -621,18 +622,16 @@ static u32 max310x_set_ref_clk(struct device *dev, struct max310x_port *s, static void max310x_batch_write(struct uart_port *port, u8 *txbuf, unsigned int len) { - struct max310x_port *s = dev_get_drvdata(port->dev); - u8 reg = port->iobase + MAX310X_THR_REG; + struct max310x_one *one = to_max310x_port(port); - regmap_raw_write(s->regmap, reg, txbuf, len); + regmap_raw_write(one->regmap, MAX310X_THR_REG, txbuf, len); } static void max310x_batch_read(struct uart_port *port, u8 *rxbuf, unsigned int len) { - struct max310x_port *s = dev_get_drvdata(port->dev); - u8 reg = port->iobase + MAX310X_RHR_REG; + struct max310x_one *one = to_max310x_port(port); - regmap_raw_read(s->regmap, reg, rxbuf, len); + regmap_raw_read(one->regmap, MAX310X_RHR_REG, rxbuf, len); } static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen) @@ -1234,15 +1233,16 @@ static int max310x_gpio_set_config(struct gpio_chip *chip, unsigned int offset, #endif static int max310x_probe(struct device *dev, const struct max310x_devtype *devtype, - struct regmap *regmap, int irq) + struct regmap *regmaps[], int irq) { int i, ret, fmin, fmax, freq; struct max310x_port *s; u32 uartclk = 0; bool xtal; - if (IS_ERR(regmap)) - return PTR_ERR(regmap); + for (i = 0; i < devtype->nr; i++) + if (IS_ERR(regmaps[i])) + return PTR_ERR(regmaps[i]); /* Alloc port structure */ s = devm_kzalloc(dev, struct_size(s, p, devtype->nr), GFP_KERNEL); @@ -1289,7 +1289,7 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty goto out_clk; } - s->regmap = regmap; + s->regmap = regmaps[0]; s->devtype = devtype; dev_set_drvdata(dev, s); @@ -1299,22 +1299,18 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty goto out_clk; for (i = 0; i < devtype->nr; i++) { - unsigned int offs = i << 5; - /* Reset port */ - regmap_write(s->regmap, MAX310X_MODE2_REG + offs, + regmap_write(regmaps[i], MAX310X_MODE2_REG, MAX310X_MODE2_RST_BIT); /* Clear port reset */ - regmap_write(s->regmap, MAX310X_MODE2_REG + offs, 0); + regmap_write(regmaps[i], MAX310X_MODE2_REG, 0); /* Wait for port startup */ do { - regmap_read(s->regmap, - MAX310X_BRGDIVLSB_REG + offs, &ret); + regmap_read(regmaps[i], MAX310X_BRGDIVLSB_REG, &ret); } while (ret != 0x01); - regmap_write(s->regmap, MAX310X_MODE1_REG + offs, - devtype->mode1); + regmap_write(regmaps[i], MAX310X_MODE1_REG, devtype->mode1); } uartclk = max310x_set_ref_clk(dev, s, freq, xtal); @@ -1337,11 +1333,13 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty s->p[i].port.fifosize = MAX310X_FIFO_SIZE; s->p[i].port.flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY; s->p[i].port.iotype = UPIO_PORT; - s->p[i].port.iobase = i * 0x20; + s->p[i].port.iobase = i; s->p[i].port.membase = (void __iomem *)~0; s->p[i].port.uartclk = uartclk; s->p[i].port.rs485_config = max310x_rs485_config; s->p[i].port.ops = &max310x_ops; + s->p[i].regmap = regmaps[i]; + /* Disable all interrupts */ max310x_port_write(&s->p[i].port, MAX310X_IRQEN_REG, 0); /* Clear IRQ status register */ @@ -1436,6 +1434,7 @@ static struct regmap_config regcfg = { .val_bits = 8, .write_flag_mask = MAX310X_WRITE_BIT, .cache_type = REGCACHE_RBTREE, + .max_register = MAX310X_REG_1F, .writeable_reg = max310x_reg_writeable, .volatile_reg = max310x_reg_volatile, .precious_reg = max310x_reg_precious, @@ -1445,7 +1444,8 @@ static struct regmap_config regcfg = { static int max310x_spi_probe(struct spi_device *spi) { const struct max310x_devtype *devtype; - struct regmap *regmap; + struct regmap *regmaps[4]; + unsigned int i; int ret; /* Setup SPI bus */ @@ -1460,10 +1460,14 @@ static int max310x_spi_probe(struct spi_device *spi) if (!devtype) devtype = (struct max310x_devtype *)spi_get_device_id(spi)->driver_data; - regcfg.max_register = devtype->nr * 0x20 - 1; - regmap = devm_regmap_init_spi(spi, ®cfg); + for (i = 0; i < devtype->nr; i++) { + u8 port_mask = i * 0x20; + regcfg.read_flag_mask = port_mask; + regcfg.write_flag_mask = port_mask | MAX310X_WRITE_BIT; + regmaps[i] = devm_regmap_init_spi(spi, ®cfg); + } - return max310x_probe(&spi->dev, devtype, regmap, spi->irq); + return max310x_probe(&spi->dev, devtype, regmaps, spi->irq); } static void max310x_spi_remove(struct spi_device *spi) -- cgit v1.2.3 From b3883ab5e95713e479f774ea68be275413e8e5b2 Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Sun, 5 Jun 2022 17:46:58 +0300 Subject: serial: max310x: make accessing revision id interface-agnostic SPI can only use 5 address bits, since one bit is reserved for specifying R/W and 2 bits are used to specify the UART port. To access registers that have addresses past 0x1F, an extended register space can be enabled by writing to the GlobalCommand register (address 0x1F). I2C uses 8 address bits. The R/W bit is placed in the slave address, and so is the UART port. Because of this, registers that have addresses higher than 0x1F can be accessed normally. To access the RevID register, on SPI, 0xCE must be written to the 0x1F address to enable the extended register space, after which the RevID register is accessible at address 0x5. 0xCD must be written to the 0x1F address to disable the extended register space. On I2C, the RevID register is accessible at address 0x25. Create an interface config struct, and add a method for toggling the extended register space and a member for the RevId register address. Implement these for SPI. Reviewed-by: Andy Shevchenko Signed-off-by: Cosmin Tanislav Link: https://lore.kernel.org/r/20220605144659.4169853-4-demonsingur@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 6fd133c177a3..ef6b91242524 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -72,7 +72,7 @@ #define MAX310X_GLOBALCMD_REG MAX310X_REG_1F /* Global Command (WO) */ /* Extended registers */ -#define MAX310X_REVID_EXTREG MAX310X_REG_05 /* Revision ID */ +#define MAX310X_SPI_REVID_EXTREG MAX310X_REG_05 /* Revision ID */ /* IRQ register bits */ #define MAX310X_IRQ_LSR_BIT (1 << 0) /* LSR interrupt */ @@ -245,6 +245,12 @@ #define MAX14830_BRGCFG_CLKDIS_BIT (1 << 6) /* Clock Disable */ #define MAX14830_REV_ID (0xb0) +struct max310x_if_cfg { + int (*extended_reg_enable)(struct device *dev, bool enable); + + unsigned int rev_id_reg; +}; + struct max310x_devtype { char name[9]; int nr; @@ -267,6 +273,7 @@ struct max310x_one { struct max310x_port { const struct max310x_devtype *devtype; + const struct max310x_if_cfg *if_cfg; struct regmap *regmap; struct clk *clk; #ifdef CONFIG_GPIOLIB @@ -356,13 +363,12 @@ static int max3109_detect(struct device *dev) unsigned int val = 0; int ret; - ret = regmap_write(s->regmap, MAX310X_GLOBALCMD_REG, - MAX310X_EXTREG_ENBL); + ret = s->if_cfg->extended_reg_enable(dev, true); if (ret) return ret; - regmap_read(s->regmap, MAX310X_REVID_EXTREG, &val); - regmap_write(s->regmap, MAX310X_GLOBALCMD_REG, MAX310X_EXTREG_DSBL); + 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); @@ -387,13 +393,12 @@ static int max14830_detect(struct device *dev) unsigned int val = 0; int ret; - ret = regmap_write(s->regmap, MAX310X_GLOBALCMD_REG, - MAX310X_EXTREG_ENBL); + ret = s->if_cfg->extended_reg_enable(dev, true); if (ret) return ret; - regmap_read(s->regmap, MAX310X_REVID_EXTREG, &val); - regmap_write(s->regmap, MAX310X_GLOBALCMD_REG, MAX310X_EXTREG_DSBL); + 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); @@ -1233,6 +1238,7 @@ static int max310x_gpio_set_config(struct gpio_chip *chip, unsigned int offset, #endif static int max310x_probe(struct device *dev, const struct max310x_devtype *devtype, + const struct max310x_if_cfg *if_cfg, struct regmap *regmaps[], int irq) { int i, ret, fmin, fmax, freq; @@ -1291,6 +1297,7 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty s->regmap = regmaps[0]; s->devtype = devtype; + s->if_cfg = if_cfg; dev_set_drvdata(dev, s); /* Check device to ensure we are talking to what we expect */ @@ -1441,6 +1448,19 @@ static struct regmap_config regcfg = { }; #ifdef CONFIG_SPI_MASTER +static int max310x_spi_extended_reg_enable(struct device *dev, bool enable) +{ + struct max310x_port *s = dev_get_drvdata(dev); + + return regmap_write(s->regmap, MAX310X_GLOBALCMD_REG, + enable ? MAX310X_EXTREG_ENBL : MAX310X_EXTREG_DSBL); +} + +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, +}; + static int max310x_spi_probe(struct spi_device *spi) { const struct max310x_devtype *devtype; @@ -1467,7 +1487,7 @@ static int max310x_spi_probe(struct spi_device *spi) regmaps[i] = devm_regmap_init_spi(spi, ®cfg); } - return max310x_probe(&spi->dev, devtype, regmaps, spi->irq); + return max310x_probe(&spi->dev, devtype, &max310x_spi_if_cfg, regmaps, spi->irq); } static void max310x_spi_remove(struct spi_device *spi) -- cgit v1.2.3 From 2e1f2d9a9bdbe12ee475c82a45ac46a278e8049a Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Sun, 5 Jun 2022 17:46:59 +0300 Subject: serial: max310x: implement I2C support I2C implementation on this chip has a few key differences compared to SPI, as described in previous patches. * extended register space access needs no extra logic * slave address is used to select which UART to communicate with To accommodate these differences, add an I2C interface config, set the RevID register address and implement an empty method for setting the GlobalCommand register, since no special handling is needed for the extended register space. To handle the port-specific slave address, create an I2C dummy device for each port, except the base one (UART0), which is expected to be the one specified in firmware, and create a regmap for each I2C device. Add minimum and maximum slave addresses to each devtype for sanity checking. Also, use a separate regmap config with no write_flag_mask, since I2C has a R/W bit in its slave address, and set the max register to the address of the RevID register, since the extended register space needs no extra logic. Finally, add the I2C driver. Reviewed-by: Andy Shevchenko Signed-off-by: Cosmin Tanislav Link: https://lore.kernel.org/r/20220605144659.4169853-5-demonsingur@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 1 + drivers/tty/serial/max310x.c | 135 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 135 insertions(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index a452748c69b2..8a3ee1525d80 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -324,6 +324,7 @@ config SERIAL_MAX310X depends on SPI_MASTER select SERIAL_CORE select REGMAP_SPI if SPI_MASTER + select REGMAP_I2C if I2C help This selects support for an advanced UART from Maxim (Dallas). Supported ICs are MAX3107, MAX3108, MAX3109, MAX14830. diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index ef6b91242524..0f7c5908fee0 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -73,6 +74,7 @@ /* Extended registers */ #define MAX310X_SPI_REVID_EXTREG MAX310X_REG_05 /* Revision ID */ +#define MAX310X_I2C_REVID_EXTREG (0x25) /* Revision ID */ /* IRQ register bits */ #define MAX310X_IRQ_LSR_BIT (1 << 0) /* LSR interrupt */ @@ -252,6 +254,10 @@ struct max310x_if_cfg { }; struct max310x_devtype { + struct { + unsigned short min; + unsigned short max; + } slave_addr; char name[9]; int nr; u8 mode1; @@ -423,6 +429,10 @@ static const struct max310x_devtype max3107_devtype = { .mode1 = MAX310X_MODE1_AUTOSLEEP_BIT | MAX310X_MODE1_IRQSEL_BIT, .detect = max3107_detect, .power = max310x_power, + .slave_addr = { + .min = 0x2c, + .max = 0x2f, + }, }; static const struct max310x_devtype max3108_devtype = { @@ -431,6 +441,10 @@ static const struct max310x_devtype max3108_devtype = { .mode1 = MAX310X_MODE1_AUTOSLEEP_BIT, .detect = max3108_detect, .power = max310x_power, + .slave_addr = { + .min = 0x60, + .max = 0x6f, + }, }; static const struct max310x_devtype max3109_devtype = { @@ -439,6 +453,10 @@ static const struct max310x_devtype max3109_devtype = { .mode1 = MAX310X_MODE1_AUTOSLEEP_BIT, .detect = max3109_detect, .power = max310x_power, + .slave_addr = { + .min = 0x60, + .max = 0x6f, + }, }; static const struct max310x_devtype max14830_devtype = { @@ -447,6 +465,10 @@ static const struct max310x_devtype max14830_devtype = { .mode1 = MAX310X_MODE1_IRQSEL_BIT, .detect = max14830_detect, .power = max14830_power, + .slave_addr = { + .min = 0x60, + .max = 0x6f, + }, }; static bool max310x_reg_writeable(struct device *dev, unsigned int reg) @@ -1516,6 +1538,97 @@ static struct spi_driver max310x_spi_driver = { }; #endif +#ifdef CONFIG_I2C +static int max310x_i2c_extended_reg_enable(struct device *dev, bool enable) +{ + return 0; +} + +static struct regmap_config regcfg_i2c = { + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .writeable_reg = max310x_reg_writeable, + .volatile_reg = max310x_reg_volatile, + .precious_reg = max310x_reg_precious, + .max_register = MAX310X_I2C_REVID_EXTREG, +}; + +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, +}; + +static unsigned short max310x_i2c_slave_addr(unsigned short addr, + unsigned int nr) +{ + /* + * 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 + */ + + addr -= nr * 0x10; + + if (nr >= 2) + addr -= 0x20; + + return addr; +} + +static int max310x_i2c_probe(struct i2c_client *client) +{ + const struct max310x_devtype *devtype = + device_get_match_data(&client->dev); + struct i2c_client *port_client; + struct regmap *regmaps[4]; + unsigned int i; + u8 port_addr; + + if (client->addr < devtype->slave_addr.min || + 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, + devtype->slave_addr.max); + + regmaps[0] = devm_regmap_init_i2c(client, ®cfg_i2c); + + for (i = 1; i < devtype->nr; i++) { + port_addr = max310x_i2c_slave_addr(client->addr, i); + port_client = devm_i2c_new_dummy_device(&client->dev, + client->adapter, + port_addr); + + regmaps[i] = devm_regmap_init_i2c(port_client, ®cfg_i2c); + } + + return max310x_probe(&client->dev, devtype, &max310x_i2c_if_cfg, + regmaps, client->irq); +} + +static int max310x_i2c_remove(struct i2c_client *client) +{ + max310x_remove(&client->dev); + + return 0; +} + +static struct i2c_driver max310x_i2c_driver = { + .driver = { + .name = MAX310X_NAME, + .of_match_table = max310x_dt_ids, + .pm = &max310x_pm_ops, + }, + .probe_new = max310x_i2c_probe, + .remove = max310x_i2c_remove, +}; +#endif + static int __init max310x_uart_init(void) { int ret; @@ -1529,15 +1642,35 @@ static int __init max310x_uart_init(void) #ifdef CONFIG_SPI_MASTER ret = spi_register_driver(&max310x_spi_driver); if (ret) - uart_unregister_driver(&max310x_uart); + goto err_spi_register; +#endif + +#ifdef CONFIG_I2C + ret = i2c_add_driver(&max310x_i2c_driver); + if (ret) + goto err_i2c_register; #endif + return 0; + +#ifdef CONFIG_I2C +err_i2c_register: + spi_unregister_driver(&max310x_spi_driver); +#endif + +err_spi_register: + uart_unregister_driver(&max310x_uart); + return ret; } module_init(max310x_uart_init); static void __exit max310x_uart_exit(void) { +#ifdef CONFIG_I2C + i2c_del_driver(&max310x_i2c_driver); +#endif + #ifdef CONFIG_SPI_MASTER spi_unregister_driver(&max310x_spi_driver); #endif -- cgit v1.2.3 From ebaed53c00174abf2224c1ebbe0f315189dfd046 Mon Sep 17 00:00:00 2001 From: Xuezhi Zhang Date: Tue, 31 May 2022 07:28:14 +0000 Subject: tty: vt: convert sysfs snprintf to sysfs_emit Fix the following coccicheck warnings: drivers/tty/vt/vt.c:3942:8-16: WARNING: use scnprintf or sprintf drivers/tty/vt/vt.c:3950:8-16: WARNING: use scnprintf or sprintf Signed-off-by: Xuezhi Zhang Link: https://lore.kernel.org/r/20220531072814.34999-1-zhangxuezhi1@coolpad.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 1ea1c11c42fd..c718b0d01e3d 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -3939,7 +3939,7 @@ static ssize_t show_bind(struct device *dev, struct device_attribute *attr, bind = con_is_bound(con->con); console_unlock(); - return snprintf(buf, PAGE_SIZE, "%i\n", bind); + return sysfs_emit(buf, "%i\n", bind); } static ssize_t show_name(struct device *dev, struct device_attribute *attr, @@ -3947,7 +3947,7 @@ static ssize_t show_name(struct device *dev, struct device_attribute *attr, { struct con_driver *con = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%s %s\n", + return sysfs_emit(buf, "%s %s\n", (con->flag & CON_DRIVER_FLAG_MODULE) ? "(M)" : "(S)", con->desc); -- cgit v1.2.3 From 767cc6681b1b17f4cbba0b8b37bf6dbb1322c9ac Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Tue, 7 Jun 2022 11:41:53 +0300 Subject: serial: 8250: kill __do_stop_tx() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There seems to be little reason for __do_stop_tx() to exits on its own. It is rather simple and is only called from __stop_tx(). Thus, move its logic into __stop_tx(). Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220607084154.8172-1-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 78b6dedc43e6..448cfbb05f63 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1503,12 +1503,6 @@ static void __stop_tx_rs485(struct uart_8250_port *p, u64 stop_delay) } } -static inline void __do_stop_tx(struct uart_8250_port *p) -{ - if (serial8250_clear_THRI(p)) - serial8250_rpm_put_tx(p); -} - static inline void __stop_tx(struct uart_8250_port *p) { struct uart_8250_em485 *em485 = p->em485; @@ -1542,7 +1536,9 @@ static inline void __stop_tx(struct uart_8250_port *p) __stop_tx_rs485(p, stop_delay); } - __do_stop_tx(p); + + if (serial8250_clear_THRI(p)) + serial8250_rpm_put_tx(p); } static void serial8250_stop_tx(struct uart_port *port) -- cgit v1.2.3 From 90574a5b5a048af7c8c1de8977da498f1e2bdce9 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Tue, 7 Jun 2022 11:41:54 +0300 Subject: serial: 8250: handle __start_tx() call in start_tx() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As either start_tx_rs485() or start_tx() calls __start_tx() as the last line of their logic, it makes sense to just move that call into start_tx(). When start_tx_rs485() wants to defer tx using timer, return false so start_tx() can return based on it. Reorganize em485 code in serial8250_start_tx() so that the return can be shared for the cases where tx start is deferred. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220607084154.8172-2-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 448cfbb05f63..a3ffbdfe8fae 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1610,7 +1610,8 @@ void serial8250_em485_start_tx(struct uart_8250_port *up) } EXPORT_SYMBOL_GPL(serial8250_em485_start_tx); -static inline void start_tx_rs485(struct uart_port *port) +/* Returns false, if start_tx_timer was setup to defer TX start */ +static bool start_tx_rs485(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); struct uart_8250_em485 *em485 = up->em485; @@ -1638,11 +1639,11 @@ static inline void start_tx_rs485(struct uart_port *port) em485->active_timer = &em485->start_tx_timer; start_hrtimer_ms(&em485->start_tx_timer, up->port.rs485.delay_rts_before_send); - return; + return false; } } - __start_tx(port); + return true; } static enum hrtimer_restart serial8250_em485_handle_start_tx(struct hrtimer *t) @@ -1672,14 +1673,12 @@ static void serial8250_start_tx(struct uart_port *port) serial8250_rpm_get_tx(up); - if (em485 && - em485->active_timer == &em485->start_tx_timer) - return; - - if (em485) - start_tx_rs485(port); - else - __start_tx(port); + if (em485) { + if ((em485->active_timer == &em485->start_tx_timer) || + !start_tx_rs485(port)) + return; + } + __start_tx(port); } static void serial8250_throttle(struct uart_port *port) -- cgit v1.2.3 From ce338e4477cfdff0abeb27eff2d43fc379ee9ebb Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Wed, 8 Jun 2022 12:54:26 +0300 Subject: serial: 8250: Store to lsr_save_flags after lsr read MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not all LSR register flags are preserved across reads. Therefore, LSR readers must store the non-preserved bits into lsr_save_flags. This fix was initially mixed into feature commit f6f586102add ("serial: 8250: Handle UART without interrupt on TEMT using em485"). However, that feature change had a flaw and it was reverted to make room for simpler approach providing the same feature. The embedded fix got reverted with the feature change. Re-add the lsr_save_flags fix and properly mark it's a fix. Link: https://lore.kernel.org/all/1d6c31d-d194-9e6a-ddf9-5f29af829f3@linux.intel.com/T/#m1737eef986bd20cf19593e344cebd7b0244945fc Fixes: e490c9144cfa ("tty: Add software emulated RS485 support for 8250") Co-developed-by: Uwe Kleine-König Reviewed-by: Andy Shevchenko Signed-off-by: Uwe Kleine-König Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220608095431.18376-2-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index a3ffbdfe8fae..209ecb1f29ed 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1511,6 +1511,8 @@ static inline void __stop_tx(struct uart_8250_port *p) unsigned char lsr = serial_in(p, UART_LSR); u64 stop_delay = 0; + p->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; + if (!(lsr & UART_LSR_THRE)) return; /* -- cgit v1.2.3 From bdb70c424df1543bc02ee2639aecebd20318c599 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Wed, 8 Jun 2022 12:54:27 +0300 Subject: serial: 8250: Create serial_lsr_in() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LSR register readers need to be careful in order to not lose bits that are not preserved across reads. Create a helper that takes care of storing the non-preserved bits into lsr_save_flags. Reviewed-by: Andy Shevchenko Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220608095431.18376-3-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250.h | 20 ++++++++++++++++++++ drivers/tty/serial/8250/8250_core.c | 3 +-- drivers/tty/serial/8250/8250_port.c | 15 ++++----------- 3 files changed, 25 insertions(+), 13 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 696030cfcb09..c89cb881d9b0 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -123,6 +123,26 @@ static inline void serial_out(struct uart_8250_port *up, int offset, int value) up->port.serial_out(&up->port, offset, value); } +/** + * serial_lsr_in - Read LSR register and preserve flags across reads + * @up: uart 8250 port + * + * Read LSR register and handle saving non-preserved flags across reads. + * The flags that are not preserved across reads are stored into + * up->lsr_saved_flags. + * + * Returns LSR value or'ed with the preserved flags (if any). + */ +static inline unsigned int serial_lsr_in(struct uart_8250_port *up) +{ + unsigned int lsr = up->lsr_saved_flags; + + lsr |= serial_in(up, UART_LSR); + up->lsr_saved_flags = lsr & LSR_SAVE_FLAGS; + + return lsr; +} + /* * For the 16C950 */ diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index cfbd2de0ca6e..b0320de3379c 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -276,8 +276,7 @@ static void serial8250_backup_timeout(struct timer_list *t) * the "Diva" UART used on the management processor on many HP * ia64 and parisc boxes. */ - lsr = serial_in(up, UART_LSR); - up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; + lsr = serial_lsr_in(up); if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) && (!uart_circ_empty(&up->port.state->xmit) || up->port.x_char) && (lsr & UART_LSR_THRE)) { diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 209ecb1f29ed..5a5e81dd3b74 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1508,11 +1508,9 @@ static inline void __stop_tx(struct uart_8250_port *p) struct uart_8250_em485 *em485 = p->em485; if (em485) { - unsigned char lsr = serial_in(p, UART_LSR); + unsigned char lsr = serial_lsr_in(p); u64 stop_delay = 0; - p->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; - if (!(lsr & UART_LSR_THRE)) return; /* @@ -1569,10 +1567,8 @@ static inline void __start_tx(struct uart_port *port) if (serial8250_set_THRI(up)) { if (up->bugs & UART_BUG_TXEN) { - unsigned char lsr; + unsigned char lsr = serial_lsr_in(up); - lsr = serial_in(up, UART_LSR); - up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; if (lsr & UART_LSR_THRE) serial8250_tx_chars(up); } @@ -2002,8 +1998,7 @@ static unsigned int serial8250_tx_empty(struct uart_port *port) serial8250_rpm_get(up); spin_lock_irqsave(&port->lock, flags); - lsr = serial_port_in(port, UART_LSR); - up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; + lsr = serial_lsr_in(up); spin_unlock_irqrestore(&port->lock, flags); serial8250_rpm_put(up); @@ -2079,9 +2074,7 @@ static void wait_for_lsr(struct uart_8250_port *up, int bits) /* Wait up to 10ms for the character(s) to be sent. */ for (;;) { - status = serial_in(up, UART_LSR); - - up->lsr_saved_flags |= status & LSR_SAVE_FLAGS; + status = serial_lsr_in(up); if ((status & bits) == bits) break; -- cgit v1.2.3 From 6a4241e8f9b17aa17f55842d6478f280c22d2b44 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Wed, 8 Jun 2022 12:54:28 +0300 Subject: serial: 8250: Get preserved flags using serial_lsr_in() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit serial8250_handle_irq() assumes it's the first to read LSR register. However, there are 8250 drivers which perform LSR read in their own irq handler prior to calling serial8250_handle_irq(). As not all flags are preserved across LSR reads, use serial_lsr_in() helper to get all the preserved flags. This commit might fix other commits too besides the ones for DW UART mentioned below. It's just not clear to me which of the other devices clear some of the LSR flags on read. AFAIK, nobody has complained about this problem (either against DW or other devices) so it might not have that bad impact in the end. Fixes: 424d79183af0 ("serial: 8250_dw: Avoid "too much work" from bogus rx timeout interrupt") Fixes: aa63d786cea2 ("serial: 8250: dw: Add support for DMA flow controlling devices") Reviewed-by: Andy Shevchenko Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220608095431.18376-4-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 5a5e81dd3b74..92fb2e39134e 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1917,7 +1917,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) spin_lock_irqsave(&port->lock, flags); - status = serial_port_in(port, UART_LSR); + status = serial_lsr_in(up); /* * If port is stopped and there are no error conditions in the -- cgit v1.2.3 From 7a3525e48cf7c1d85c38cedb452912cb99b60c43 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Wed, 8 Jun 2022 12:54:29 +0300 Subject: serial: 8250: Adjust misleading LSR related comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit serial8250_rx_chars() has max_count based character limit. If it triggers, the function returns the old LSR value (and it has never returned only flags which were not handled). Adjust the comment to match behavior and warn about which flags can be depended on. I'd have moved LSR read before LSR read and used serial_lsr_in() also here but I came across an old discussion about the topic. That discussion generated commit d22f8f10683c ("serial: 8250: Fix lost rx state") so I left the code as it is (it works as long as the callers only use a subset of the LSR flags which holds true today) and changed the comment instead. Link: https://www.spinics.net/lists/linux-serial/msg16220.html Reviewed-by: Andy Shevchenko Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220608095431.18376-5-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 92fb2e39134e..30e0aaf52adc 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1783,9 +1783,11 @@ void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr) EXPORT_SYMBOL_GPL(serial8250_read_char); /* - * serial8250_rx_chars: processes according to the passed in LSR - * value, and returns the remaining LSR bits not handled - * by this Rx routine. + * serial8250_rx_chars - Read characters. The first LSR value must be passed in. + * + * Returns LSR bits. The caller should rely only on non-Rx related LSR bits + * (such as THRE) because the LSR value might come from an already consumed + * character. */ unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) { -- cgit v1.2.3 From 197eb5c416ff0e52d152e6ff59b4e759d2f3e10d Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Wed, 8 Jun 2022 12:54:30 +0300 Subject: serial: 8250_dw: Use serial_lsr_in() in dw8250_handle_irq() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dw8250_handle_irq() reads LSR under a few conditions, convert both to use serial_lsr_in() in order to preserve LSR flags properly across reads. Fixes: 424d79183af0 ("serial: 8250_dw: Avoid "too much work" from bogus rx timeout interrupt") Fixes: aa63d786cea2 ("serial: 8250: dw: Add support for DMA flow controlling devices") Cc: Douglas Anderson Cc: Phil Edworthy Cc: Miquel Raynal Reviewed-by: Andy Shevchenko Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220608095431.18376-6-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index f57bbd32ef11..1fae45991812 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -253,7 +253,7 @@ static int dw8250_handle_irq(struct uart_port *p) */ if (!up->dma && rx_timeout) { spin_lock_irqsave(&p->lock, flags); - status = p->serial_in(p, UART_LSR); + status = serial_lsr_in(up); if (!(status & (UART_LSR_DR | UART_LSR_BI))) (void) p->serial_in(p, UART_RX); @@ -263,7 +263,7 @@ static int dw8250_handle_irq(struct uart_port *p) /* Manually stop the Rx DMA transfer when acting as flow controller */ if (quirks & DW_UART_QUIRK_IS_DMA_FC && up->dma && up->dma->rx_running && rx_timeout) { - status = p->serial_in(p, UART_LSR); + status = serial_lsr_in(up); if (status & (UART_LSR_DR | UART_LSR_BI)) { dw8250_writel_ext(p, RZN1_UART_RDMACR, 0); dw8250_writel_ext(p, DW_UART_DMASA, 1); -- cgit v1.2.3 From af14f3007e2dca0d112f10f6717ba43093f74e81 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Wed, 8 Jun 2022 12:54:31 +0300 Subject: serial: 8250_dw: Store LSR into lsr_saved_flags in dw8250_tx_wait_empty() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make sure LSR flags are preserved in dw8250_tx_wait_empty(). This function is called from a low-level out function and therefore cannot call serial_lsr_in() as it would lead to infinite recursion. It is borderline if the flags need to be saved here at all since this code relates to writing LCR register which usually implies no important characters should be arriving. Fixes: 914eaf935ec7 ("serial: 8250_dw: Allow TX FIFO to drain before writing to UART_LCR") Reviewed-by: Andy Shevchenko Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220608095431.18376-7-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 1fae45991812..4cc69bb612ab 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -122,12 +122,15 @@ static void dw8250_check_lcr(struct uart_port *p, int value) /* Returns once the transmitter is empty or we run out of retries */ static void dw8250_tx_wait_empty(struct uart_port *p) { + struct uart_8250_port *up = up_to_u8250p(p); unsigned int tries = 20000; unsigned int delay_threshold = tries - 1000; unsigned int lsr; while (tries--) { lsr = readb (p->membase + (UART_LSR << p->regshift)); + up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; + if (lsr & UART_LSR_TEMT) break; -- cgit v1.2.3 From 8322b1f527159de578aab277629296575a11eb3c Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:03:58 +0300 Subject: serial: Add uart_rs485_config() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A few serial drivers make a call to rs485_config() themselves (all these seem to relate to init). Convert them all to use a common helper which makes it easy to make adjustments on tasks related to it as serial_rs485 struct sanitization is going to be added. In pci_fintek_setup() (in 8250_pci.c), the rs485_config() call was made with NULL, however, it can be changed to pass uart_port's rs485 struct. No other callers should pass NULL into rs485_config() so the NULL check can now be eliminated. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-2-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 6 ++---- drivers/tty/serial/8250/8250_port.c | 2 +- drivers/tty/serial/fsl_lpuart.c | 2 +- drivers/tty/serial/imx.c | 2 +- drivers/tty/serial/serial_core.c | 6 ++++++ include/linux/serial_core.h | 1 + 6 files changed, 12 insertions(+), 7 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index a17619db7939..fb0a49e39072 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1562,9 +1562,7 @@ static int pci_fintek_rs485_config(struct uart_port *port, pci_read_config_byte(pci_dev, 0x40 + 8 * *index + 7, &setting); - if (!rs485) - rs485 = &port->rs485; - else if (rs485->flags & SER_RS485_ENABLED) + if (rs485->flags & SER_RS485_ENABLED) memset(rs485->padding, 0, sizeof(rs485->padding)); else memset(rs485, 0, sizeof(*rs485)); @@ -1689,7 +1687,7 @@ static int pci_fintek_init(struct pci_dev *dev) * pciserial_resume_ports() */ port = serial8250_get_port(priv->line[i]); - pci_fintek_rs485_config(&port->port, NULL); + uart_rs485_config(&port->port); } else { /* First init without port data * force init to RS232 Mode diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 30e0aaf52adc..af550a4a27f8 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -3191,7 +3191,7 @@ static void serial8250_config_port(struct uart_port *port, int flags) autoconfig(up); if (port->rs485.flags & SER_RS485_ENABLED) - port->rs485_config(port, &port->rs485); + uart_rs485_config(port); /* if access method is AU, it is a 16550 with a quirk */ if (port->type == PORT_16550A && port->iotype == UPIO_AU) diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 0d6e62f6bb07..509a7912fa9d 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -2724,7 +2724,7 @@ static int lpuart_probe(struct platform_device *pdev) sport->port.rs485.delay_rts_after_send) dev_err(&pdev->dev, "driver doesn't support RTS delays\n"); - sport->port.rs485_config(&sport->port, &sport->port.rs485); + uart_rs485_config(&sport->port); ret = devm_request_irq(&pdev->dev, sport->port.irq, handler, 0, DRIVER_NAME, sport); diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 30edb35a6a15..17fb9a57078b 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -2338,7 +2338,7 @@ static int imx_uart_probe(struct platform_device *pdev) dev_err(&pdev->dev, "low-active RTS not possible when receiver is off, enabling receiver\n"); - imx_uart_rs485_config(&sport->port, &sport->port.rs485); + uart_rs485_config(&sport->port); /* Disable interrupts before requesting them */ ucr1 = imx_uart_readl(sport, UCR1); diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 9a85b41caa0a..8466181db4e9 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1276,6 +1276,12 @@ static int uart_get_icount(struct tty_struct *tty, return 0; } +int uart_rs485_config(struct uart_port *port) +{ + return port->rs485_config(port, &port->rs485); +} +EXPORT_SYMBOL_GPL(uart_rs485_config); + static int uart_get_rs485_config(struct uart_port *port, struct serial_rs485 __user *rs485) { diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index cbd5070bc87f..d3ebb4db2d80 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -592,4 +592,5 @@ static inline int uart_handle_break(struct uart_port *port) !((cflag) & CLOCAL)) int uart_get_rs485_mode(struct uart_port *port); +int uart_rs485_config(struct uart_port *port); #endif /* LINUX_SERIAL_CORE_H */ -- cgit v1.2.3 From 2dbd0c14ebe8836eaf890c7f50f3fc5d26d67d95 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:03:59 +0300 Subject: serial: Move serial_rs485 sanitization into separate function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add uart_sanitize_serial_rs485() function for sanitizing serial_rs485 structure fields. No functional changes. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-3-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 55 ++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 25 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 8466181db4e9..44a50158552d 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1276,6 +1276,35 @@ static int uart_get_icount(struct tty_struct *tty, return 0; } +static void uart_sanitize_serial_rs485(struct uart_port *port, struct serial_rs485 *rs485) +{ + /* pick sane settings if the user hasn't */ + if (!(rs485->flags & SER_RS485_RTS_ON_SEND) == + !(rs485->flags & SER_RS485_RTS_AFTER_SEND)) { + dev_warn_ratelimited(port->dev, + "%s (%d): invalid RTS setting, using RTS_ON_SEND instead\n", + port->name, port->line); + rs485->flags |= SER_RS485_RTS_ON_SEND; + rs485->flags &= ~SER_RS485_RTS_AFTER_SEND; + } + + if (rs485->delay_rts_before_send > RS485_MAX_RTS_DELAY) { + rs485->delay_rts_before_send = RS485_MAX_RTS_DELAY; + dev_warn_ratelimited(port->dev, + "%s (%d): RTS delay before sending clamped to %u ms\n", + port->name, port->line, rs485->delay_rts_before_send); + } + + if (rs485->delay_rts_after_send > RS485_MAX_RTS_DELAY) { + rs485->delay_rts_after_send = RS485_MAX_RTS_DELAY; + dev_warn_ratelimited(port->dev, + "%s (%d): RTS delay after sending clamped to %u ms\n", + port->name, port->line, rs485->delay_rts_after_send); + } + /* Return clean padding area to userspace */ + memset(rs485->padding, 0, sizeof(rs485->padding)); +} + int uart_rs485_config(struct uart_port *port) { return port->rs485_config(port, &port->rs485); @@ -1311,31 +1340,7 @@ static int uart_set_rs485_config(struct uart_port *port, if (copy_from_user(&rs485, rs485_user, sizeof(*rs485_user))) return -EFAULT; - /* pick sane settings if the user hasn't */ - if (!(rs485.flags & SER_RS485_RTS_ON_SEND) == - !(rs485.flags & SER_RS485_RTS_AFTER_SEND)) { - dev_warn_ratelimited(port->dev, - "%s (%d): invalid RTS setting, using RTS_ON_SEND instead\n", - port->name, port->line); - rs485.flags |= SER_RS485_RTS_ON_SEND; - rs485.flags &= ~SER_RS485_RTS_AFTER_SEND; - } - - if (rs485.delay_rts_before_send > RS485_MAX_RTS_DELAY) { - rs485.delay_rts_before_send = RS485_MAX_RTS_DELAY; - dev_warn_ratelimited(port->dev, - "%s (%d): RTS delay before sending clamped to %u ms\n", - port->name, port->line, rs485.delay_rts_before_send); - } - - if (rs485.delay_rts_after_send > RS485_MAX_RTS_DELAY) { - rs485.delay_rts_after_send = RS485_MAX_RTS_DELAY; - dev_warn_ratelimited(port->dev, - "%s (%d): RTS delay after sending clamped to %u ms\n", - port->name, port->line, rs485.delay_rts_after_send); - } - /* Return clean padding area to userspace */ - memset(rs485.padding, 0, sizeof(rs485.padding)); + uart_sanitize_serial_rs485(port, &rs485); spin_lock_irqsave(&port->lock, flags); ret = port->rs485_config(port, &rs485); -- cgit v1.2.3 From 8925c31c1ac2f1e05da988581f2a70a2a8c4d638 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:00 +0300 Subject: serial: Add rs485_supported to uart_port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Preparing to move serial_rs485 struct sanitization into serial core, each driver has to provide what fields/flags it supports. This information is pointed into by rs485_supported. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-4-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_core.c | 1 + include/linux/serial_core.h | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index b0320de3379c..90ddc8924811 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -1003,6 +1003,7 @@ int serial8250_register_8250_port(const struct uart_8250_port *up) uart->port.throttle = up->port.throttle; uart->port.unthrottle = up->port.unthrottle; uart->port.rs485_config = up->port.rs485_config; + uart->port.rs485_supported = up->port.rs485_supported; uart->port.rs485 = up->port.rs485; uart->rs485_start_tx = up->rs485_start_tx; uart->rs485_stop_tx = up->rs485_stop_tx; diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index d3ebb4db2d80..5518b70177b3 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -254,6 +254,7 @@ struct uart_port { struct attribute_group *attr_group; /* port specific attributes */ const struct attribute_group **tty_groups; /* all attributes (serial core use only) */ struct serial_rs485 rs485; + const struct serial_rs485 *rs485_supported; /* Supported mask for serial_rs485 */ struct gpio_desc *rs485_term_gpio; /* enable RS485 bus termination */ struct serial_iso7816 iso7816; void *private_data; /* generic platform data pointer */ -- cgit v1.2.3 From 43ee34131cedca95c413b5e6203f4545309d2450 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:01 +0300 Subject: serial: 8250: Create serial8250_em485_supported for em485 users MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create serial8250_em485_supported for the serial_rs485 features supported by the em485 framework. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-5-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250.h | 1 + drivers/tty/serial/8250/8250_port.c | 8 ++++++++ 2 files changed, 9 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index c89cb881d9b0..b120da57c61f 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -207,6 +207,7 @@ int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485); void serial8250_em485_start_tx(struct uart_8250_port *p); void serial8250_em485_stop_tx(struct uart_8250_port *p); void serial8250_em485_destroy(struct uart_8250_port *p); +extern struct serial_rs485 serial8250_em485_supported; /* MCR <-> TIOCM conversion */ static inline int serial8250_TIOCM_to_MCR(int tiocm) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index af550a4a27f8..65a60e4808ea 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -647,6 +647,14 @@ void serial8250_em485_destroy(struct uart_8250_port *p) } EXPORT_SYMBOL_GPL(serial8250_em485_destroy); +struct serial_rs485 serial8250_em485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND | + SER_RS485_TERMINATE_BUS | SER_RS485_RX_DURING_TX, + .delay_rts_before_send = 1, + .delay_rts_after_send = 1, +}; +EXPORT_SYMBOL_GPL(serial8250_em485_supported); + /** * serial8250_em485_config() - generic ->rs485_config() callback * @port: uart port -- cgit v1.2.3 From 499b1160bc026eb7774bcf5b82b9e0ec2f6ae0be Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:02 +0300 Subject: serial: 8250_bcm2835aux: Use serial8250_em485_supported MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bcm2835aux uses em485, fill in rs485_supported accordingly. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-6-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_bcm2835aux.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c index 2a1226a78a0c..d9f1e618cfbd 100644 --- a/drivers/tty/serial/8250/8250_bcm2835aux.c +++ b/drivers/tty/serial/8250/8250_bcm2835aux.c @@ -108,6 +108,7 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev) up.port.flags = UPF_SHARE_IRQ | 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; up.rs485_stop_tx = bcm2835aux_rs485_stop_tx; -- cgit v1.2.3 From 62a4b3d274192c845cde4e885bfa7c2bedf18330 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:03 +0300 Subject: serial: 8250_dwlib: Fill in rs485_supported MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add information on supported serial_rs485 features. When the driver is using em485, take advantage of serial8250_em485_supported. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-7-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dwlib.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_dwlib.c b/drivers/tty/serial/8250/8250_dwlib.c index fbabfdd8c7b8..120b29519d74 100644 --- a/drivers/tty/serial/8250/8250_dwlib.c +++ b/drivers/tty/serial/8250/8250_dwlib.c @@ -149,6 +149,11 @@ static bool dw8250_detect_rs485_hw(struct uart_port *p) return reg; } +static const struct serial_rs485 dw8250_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RX_DURING_TX | SER_RS485_RTS_ON_SEND | + SER_RS485_RTS_AFTER_SEND, +}; + void dw8250_setup_port(struct uart_port *p) { struct dw8250_port_data *pd = p->private_data; @@ -159,8 +164,10 @@ void dw8250_setup_port(struct uart_port *p) pd->hw_rs485_support = dw8250_detect_rs485_hw(p); if (pd->hw_rs485_support) { p->rs485_config = dw8250_rs485_config; + p->rs485_supported = &dw8250_rs485_supported; } else { p->rs485_config = serial8250_em485_config; + p->rs485_supported = &serial8250_em485_supported; up->rs485_start_tx = serial8250_em485_start_tx; up->rs485_stop_tx = serial8250_em485_stop_tx; } -- cgit v1.2.3 From 59c221f8e1269278161313048c71929c9950b2c4 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:04 +0300 Subject: serial: 8250_exar: Fill in rs485_supported MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add information on supported serial_rs485 features. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-8-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_exar.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index 7292917ac878..11916f603a3d 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -113,6 +113,7 @@ struct exar8250; struct exar8250_platform { int (*rs485_config)(struct uart_port *, struct serial_rs485 *); + const struct serial_rs485 *rs485_supported; int (*register_gpio)(struct pci_dev *, struct uart_8250_port *); void (*unregister_gpio)(struct uart_8250_port *); }; @@ -431,10 +432,15 @@ static int generic_rs485_config(struct uart_port *port, return 0; } +static const struct serial_rs485 generic_rs485_supported = { + .flags = SER_RS485_ENABLED, +}; + static const struct exar8250_platform exar8250_default_platform = { .register_gpio = xr17v35x_register_gpio, .unregister_gpio = xr17v35x_unregister_gpio, .rs485_config = generic_rs485_config, + .rs485_supported = &generic_rs485_supported, }; static int iot2040_rs485_config(struct uart_port *port, @@ -470,6 +476,10 @@ static int iot2040_rs485_config(struct uart_port *port, return generic_rs485_config(port, rs485); } +static const struct serial_rs485 iot2040_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RX_DURING_TX | SER_RS485_TERMINATE_BUS, +}; + static const struct property_entry iot2040_gpio_properties[] = { PROPERTY_ENTRY_U32("exar,first-pin", 10), PROPERTY_ENTRY_U32("ngpios", 1), @@ -498,6 +508,7 @@ static int iot2040_register_gpio(struct pci_dev *pcidev, static const struct exar8250_platform iot2040_platform = { .rs485_config = iot2040_rs485_config, + .rs485_supported = &iot2040_rs485_supported, .register_gpio = iot2040_register_gpio, .unregister_gpio = xr17v35x_unregister_gpio, }; @@ -540,6 +551,7 @@ pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev, port->port.uartclk = baud * 16; port->port.rs485_config = platform->rs485_config; + port->port.rs485_supported = platform->rs485_supported; /* * Setup the UART clock for the devices on expansion slot to -- cgit v1.2.3 From 70780464846f763c00aa4fa3fda67525d3bb7fe8 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:05 +0300 Subject: serial: 8250_fintek: Fill in rs485_supported MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add information on supported serial_rs485 features. Differentiate based on which port is in question. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-9-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_fintek.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c index dba5950b8d0e..6e98c376e082 100644 --- a/drivers/tty/serial/8250/8250_fintek.c +++ b/drivers/tty/serial/8250/8250_fintek.c @@ -424,6 +424,17 @@ static int probe_setup_port(struct fintek_8250 *pdata, return -ENODEV; } +/* Only the first port supports delays */ +static const struct serial_rs485 fintek_8250_rs485_supported_port0 = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND, + .delay_rts_before_send = 1, + .delay_rts_after_send = 1, +}; + +static const struct serial_rs485 fintek_8250_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND, +}; + static void fintek_8250_set_rs485_handler(struct uart_8250_port *uart) { struct fintek_8250 *pdata = uart->port.private_data; @@ -435,6 +446,10 @@ static void fintek_8250_set_rs485_handler(struct uart_8250_port *uart) case CHIP_ID_F81866: case CHIP_ID_F81865: uart->port.rs485_config = fintek_8250_rs485_config; + if (!pdata->index) + uart->port.rs485_supported = &fintek_8250_rs485_supported_port0; + else + uart->port.rs485_supported = &fintek_8250_rs485_supported; break; default: /* No RS485 Auto direction functional */ -- cgit v1.2.3 From 4f4c90bb2a5178124391d617c32c4261c53277e7 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:06 +0300 Subject: serial: 8250_lpc18cc: Fill in rs485_supported MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add information on supported serial_rs485 features. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-10-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_lpc18xx.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_lpc18xx.c b/drivers/tty/serial/8250/8250_lpc18xx.c index 570e25d6f37e..66ce5d05fe9c 100644 --- a/drivers/tty/serial/8250/8250_lpc18xx.c +++ b/drivers/tty/serial/8250/8250_lpc18xx.c @@ -98,6 +98,12 @@ static void lpc18xx_uart_serial_out(struct uart_port *p, int offset, int value) writel(value, p->membase + offset); } +static const struct serial_rs485 lpc18xx_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND, + .delay_rts_after_send = 1, + /* Delay RTS before send is not supported */ +}; + static int lpc18xx_serial_probe(struct platform_device *pdev) { struct lpc18xx_uart_data *data; @@ -168,6 +174,7 @@ static int lpc18xx_serial_probe(struct platform_device *pdev) uart.port.uartclk = clk_get_rate(data->clk_uart); uart.port.private_data = data; uart.port.rs485_config = lpc18xx_rs485_config; + uart.port.rs485_supported = &lpc18xx_rs485_supported; uart.port.serial_out = lpc18xx_uart_serial_out; uart.dma = &data->dma; -- cgit v1.2.3 From 6d345f7cf83ce035d6b25724e4c72156098186b3 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:07 +0300 Subject: serial: 8250_of: Use serial8250_em485_supported MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 8250_of uses em485, fill in rs485_supported accordingly. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-11-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_of.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c index 5a699a1aa79c..65cccd559db2 100644 --- a/drivers/tty/serial/8250/8250_of.c +++ b/drivers/tty/serial/8250/8250_of.c @@ -165,6 +165,7 @@ static int of_platform_serial_setup(struct platform_device *ofdev, port->dev = &ofdev->dev; port->rs485_config = serial8250_em485_config; + port->rs485_supported = &serial8250_em485_supported; up->rs485_start_tx = serial8250_em485_start_tx; up->rs485_stop_tx = serial8250_em485_stop_tx; -- cgit v1.2.3 From 456d523b1be3a0a0c3498fce55b32fc205fac7e1 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:08 +0300 Subject: serial: 8250_pci: Fill in rs485_supported for pci_fintek MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add information on supported serial_rs485 features. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-12-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index fb0a49e39072..a76254031bc2 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1597,6 +1597,11 @@ static int pci_fintek_rs485_config(struct uart_port *port, return 0; } +static const struct serial_rs485 pci_fintek_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND, + /* F81504/508/512 does not support RTS delay before or after send */ +}; + static int pci_fintek_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) @@ -1616,6 +1621,7 @@ static int pci_fintek_setup(struct serial_private *priv, port->port.iotype = UPIO_PORT; port->port.iobase = iobase; port->port.rs485_config = pci_fintek_rs485_config; + port->port.rs485_supported = &pci_fintek_rs485_supported; data = devm_kzalloc(&pdev->dev, sizeof(u8), GFP_KERNEL); if (!data) -- cgit v1.2.3 From ebe2cf736a0426b228b73f858cdd782c77c109c3 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:09 +0300 Subject: serial: pl011: Fill in rs485_supported MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add information on supported serial_rs485 features. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-13-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 97ef41cb2721..cdc466e89aa8 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -2751,6 +2751,13 @@ static int pl011_register_port(struct uart_amba_port *uap) return ret; } +static const struct serial_rs485 pl011_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND | + SER_RS485_RX_DURING_TX, + .delay_rts_before_send = 1, + .delay_rts_after_send = 1, +}; + static int pl011_probe(struct amba_device *dev, const struct amba_id *id) { struct uart_amba_port *uap; @@ -2777,6 +2784,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) uap->port.irq = dev->irq[0]; uap->port.ops = &amba_pl011_pops; uap->port.rs485_config = pl011_rs485_config; + uap->port.rs485_supported = &pl011_rs485_supported; snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev)); ret = pl011_setup_port(&dev->dev, uap, &dev->res, portnr); -- cgit v1.2.3 From e849145e1fdd2d6d7bde26a5b3dbfd11567ce071 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:10 +0300 Subject: serial: ar933x: Fill in rs485_supported MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add information on supported serial_rs485 features. In the case where RTS is lacking, RS485 cannot be enabled so provide zero rs485_supported for that case. Perhaps it would make sense to not provide rs485_config() at all in that case but such a change would have userspace visible impact/change in behavior so this patch does not attempt it. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-14-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/ar933x_uart.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c index 6269dbf93546..ab2c5b2a1ce8 100644 --- a/drivers/tty/serial/ar933x_uart.c +++ b/drivers/tty/serial/ar933x_uart.c @@ -702,6 +702,11 @@ static struct uart_driver ar933x_uart_driver = { .cons = NULL, /* filled in runtime */ }; +static const struct serial_rs485 ar933x_no_rs485 = {}; +static const struct serial_rs485 ar933x_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND, +}; + static int ar933x_uart_probe(struct platform_device *pdev) { struct ar933x_uart_port *up; @@ -773,6 +778,7 @@ static int ar933x_uart_probe(struct platform_device *pdev) port->fifosize = AR933X_UART_FIFO_SIZE; port->ops = &ar933x_uart_ops; port->rs485_config = ar933x_config_rs485; + port->rs485_supported = &ar933x_rs485_supported; baud = ar933x_uart_get_baud(port->uartclk, AR933X_UART_MAX_SCALE, 1); up->min_baud = max_t(unsigned int, baud, AR933X_UART_MIN_BAUD); @@ -796,6 +802,7 @@ static int ar933x_uart_probe(struct platform_device *pdev) !up->rts_gpiod) { dev_err(&pdev->dev, "lacking rts-gpio, disabling RS485\n"); port->rs485.flags &= ~SER_RS485_ENABLED; + port->rs485_supported = &ar933x_no_rs485; } #ifdef CONFIG_SERIAL_AR933X_CONSOLE -- cgit v1.2.3 From af47c491e3c78e051a5e4d1832dbb29a8ab97799 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:11 +0300 Subject: serial: atmel: Fill in rs485_supported MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add information on supported serial_rs485 features. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-15-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index dd1c7e4bd1c9..74dd1d3ac46f 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -2473,6 +2473,12 @@ static const struct uart_ops atmel_pops = { #endif }; +static const struct serial_rs485 atmel_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_AFTER_SEND | SER_RS485_RX_DURING_TX, + .delay_rts_before_send = 1, + .delay_rts_after_send = 1, +}; + /* * Configure the port from the platform device resource info. */ @@ -2494,6 +2500,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port, port->mapbase = mpdev->resource[0].start; port->irq = platform_get_irq(mpdev, 0); port->rs485_config = atmel_config_rs485; + port->rs485_supported = &atmel_rs485_supported; port->iso7816_config = atmel_config_iso7816; port->membase = NULL; -- cgit v1.2.3 From 07481f448b635d7cebb92d5940f5bea5c4395a26 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:12 +0300 Subject: serial: fsl_lpuart: Fill in rs485_supported MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add information on supported serial_rs485 features. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-16-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 509a7912fa9d..88692dc9eefa 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -2621,6 +2621,11 @@ static struct uart_driver lpuart_reg = { .cons = LPUART_CONSOLE, }; +static const struct serial_rs485 lpuart_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND, + /* delay_rts_* and RX_DURING_TX are not supported */ +}; + static int lpuart_probe(struct platform_device *pdev) { const struct lpuart_soc_data *sdata = of_device_get_match_data(&pdev->dev); @@ -2660,6 +2665,7 @@ static int lpuart_probe(struct platform_device *pdev) sport->port.rs485_config = lpuart32_config_rs485; else sport->port.rs485_config = lpuart_config_rs485; + sport->port.rs485_supported = &lpuart_rs485_supported; sport->ipg_clk = devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(sport->ipg_clk)) { -- cgit v1.2.3 From 00d7a00e2a6ff60140068cadb6739ee0a13f5297 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:13 +0300 Subject: serial: imx: Fill in rs485_supported MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add information on supported serial_rs485 features. In the case where RTS is lacking, RS485 cannot be enabled so provide zero rs485_supported for that case. Perhaps it would make sense to not provide rs485_config() at all in that case but such a change would have userspace visible impact/change in behavior so this patch does not attempt it. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-17-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 17fb9a57078b..9d5f505008f7 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -2200,6 +2200,14 @@ static enum hrtimer_restart imx_trigger_stop_tx(struct hrtimer *t) return HRTIMER_NORESTART; } +static const struct serial_rs485 imx_no_rs485 = {}; /* No RS485 if no RTS */ +static const struct serial_rs485 imx_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND | + SER_RS485_RX_DURING_TX, + .delay_rts_before_send = 1, + .delay_rts_after_send = 1, +}; + /* Default RX DMA buffer configuration */ #define RX_DMA_PERIODS 16 #define RX_DMA_PERIOD_LEN (PAGE_SIZE / 4) @@ -2279,6 +2287,11 @@ static int imx_uart_probe(struct platform_device *pdev) sport->port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_IMX_CONSOLE); sport->port.ops = &imx_uart_pops; sport->port.rs485_config = imx_uart_rs485_config; + /* RTS is required to control the RS485 transmitter */ + if (sport->have_rtscts || sport->have_rtsgpio) + sport->port.rs485_supported = &imx_rs485_supported; + else + sport->port.rs485_supported = &imx_no_rs485; sport->port.flags = UPF_BOOT_AUTOCONF; timer_setup(&sport->timer, imx_uart_timeout, 0); -- cgit v1.2.3 From 2b947cf9e335bb1152a3395e461b9c8e94738730 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:14 +0300 Subject: serial: max310x: Fill in rs485_supported MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add information on supported serial_rs485 features. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-18-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 0f7c5908fee0..7b0c1351d75e 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1259,6 +1259,12 @@ static int max310x_gpio_set_config(struct gpio_chip *chip, unsigned int offset, } #endif +static const struct serial_rs485 max310x_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RX_DURING_TX, + .delay_rts_before_send = 1, + .delay_rts_after_send = 1, +}; + static int max310x_probe(struct device *dev, const struct max310x_devtype *devtype, const struct max310x_if_cfg *if_cfg, struct regmap *regmaps[], int irq) @@ -1366,6 +1372,7 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty s->p[i].port.membase = (void __iomem *)~0; s->p[i].port.uartclk = uartclk; s->p[i].port.rs485_config = max310x_rs485_config; + s->p[i].port.rs485_supported = &max310x_rs485_supported; s->p[i].port.ops = &max310x_ops; s->p[i].regmap = regmaps[i]; -- cgit v1.2.3 From 949b4dbfb6b39ae0de5cfce0d74543b92c6df93d Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:15 +0300 Subject: serial: mcf: Fill in rs485_supported MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add information on supported serial_rs485 features. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-19-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/mcf.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c index 2aec62b5d6c4..655255e0c76a 100644 --- a/drivers/tty/serial/mcf.c +++ b/drivers/tty/serial/mcf.c @@ -453,6 +453,10 @@ static int mcf_config_rs485(struct uart_port *port, struct serial_rs485 *rs485) return 0; } +static const struct serial_rs485 mcf_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_AFTER_SEND, +}; + /****************************************************************************/ /* @@ -502,6 +506,7 @@ int __init early_mcf_setup(struct mcf_platform_uart *platp) 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; } @@ -629,6 +634,7 @@ static int mcf_probe(struct platform_device *pdev) port->ops = &mcf_uart_ops; port->flags = UPF_BOOT_AUTOCONF; port->rs485_config = mcf_config_rs485; + port->rs485_supported = &mcf_rs485_supported; port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_MCF_CONSOLE); uart_add_one_port(&mcf_driver, port); -- cgit v1.2.3 From d45e50d087765606cdb0728798697467fd5bcc9e Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:16 +0300 Subject: serial: omap: Fill in rs485_supported MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add information on supported serial_rs485 features. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-20-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/omap-serial.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 46f4d4cacb6e..98622c35d896 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -1559,6 +1559,13 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up, return 0; } +static const struct serial_rs485 serial_omap_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND | + SER_RS485_RX_DURING_TX, + .delay_rts_before_send = 1, + .delay_rts_after_send = 1, +}; + static int serial_omap_probe(struct platform_device *pdev) { struct omap_uart_port_info *omap_up_info = dev_get_platdata(&pdev->dev); @@ -1636,6 +1643,7 @@ static int serial_omap_probe(struct platform_device *pdev) up->port.flags = omap_up_info->flags; up->port.uartclk = omap_up_info->uartclk; up->port.rs485_config = serial_omap_config_rs485; + up->port.rs485_supported = &serial_omap_rs485_supported; if (!up->port.uartclk) { up->port.uartclk = DEFAULT_CLK_SPEED; dev_warn(&pdev->dev, -- cgit v1.2.3 From 267913ecf73745ca3e8fc8282671b0b4f24df5fe Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:17 +0300 Subject: serial: sc16is7xx: Fill in rs485_supported MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add information on supported serial_rs485 features. This driver does not support delay_rts_after_send but the pre-existing behavior is to return -EINVAL if delay_rts_after_send is non-zero. In contrast, other drivers that do not support delay_rts_after_send either zero delay_rts_after_send or do not care (leave the inaccurate value). As changing this would cause userspace visible impact, the change is not attempted here. But perhaps it should be still tried (maybe nobody finds that kind of API oddity significant)? Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-21-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sc16is7xx.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 8472bf70477c..b3162dfe97b1 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -1354,6 +1354,12 @@ static int sc16is7xx_gpio_direction_output(struct gpio_chip *chip, } #endif +static const struct serial_rs485 sc16is7xx_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_AFTER_SEND, + .delay_rts_before_send = 1, + .delay_rts_after_send = 1, /* Not supported but keep returning -EINVAL */ +}; + static int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype, struct regmap *regmap, int irq) @@ -1456,6 +1462,7 @@ static int sc16is7xx_probe(struct device *dev, s->p[i].port.iotype = UPIO_PORT; s->p[i].port.uartclk = freq; s->p[i].port.rs485_config = sc16is7xx_config_rs485; + s->p[i].port.rs485_supported = &sc16is7xx_rs485_supported; s->p[i].port.ops = &sc16is7xx_ops; s->p[i].old_mctrl = 0; s->p[i].port.line = sc16is7xx_alloc_line(); -- cgit v1.2.3 From aeae8f222fdd34bdddc1050dc073e56b2242c9b5 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:18 +0300 Subject: serial: stm32: Fill in rs485_supported MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add information on supported serial_rs485 features. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-22-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/stm32-usart.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index b7b44f4050d4..db3dd9731ee1 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -1375,6 +1375,13 @@ static void stm32_usart_deinit_port(struct stm32_port *stm32port) clk_disable_unprepare(stm32port->clk); } +static const struct serial_rs485 stm32_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND | + SER_RS485_RX_DURING_TX, + .delay_rts_before_send = 1, + .delay_rts_after_send = 1, +}; + static int stm32_usart_init_port(struct stm32_port *stm32port, struct platform_device *pdev) { @@ -1394,6 +1401,7 @@ static int stm32_usart_init_port(struct stm32_port *stm32port, port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_STM32_CONSOLE); port->irq = irq; port->rs485_config = stm32_usart_config_rs485; + port->rs485_supported = &stm32_rs485_supported; ret = stm32_usart_init_rs485(port, pdev); if (ret) -- cgit v1.2.3 From be2e2cb1d28195792539ac2539f8c40c39d3dd4c Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:19 +0300 Subject: serial: Sanitize rs485_struct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sanitize serial_rs485 struct before calling into rs485_setup. The drivers provide supported_rs485 to help sanitization of the fields. If neither of SER_RS485_RTS_ON_SEND or SER_RS485_RTS_AFTER_SEND supported, don't pretend they can be set to sane settings but clear them both instead. If only one of them is supported it may look tempting to use the one driver supports to set the other, however, the userspace does not have that information readily available so it wouldn't be helpful. While adjusting the documentation, remove also the claim that TIOCGRS485 would call driver specific code. In reality, it does nothing else than copies the stored serial_rs485 structure from uart_port to userspace. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-23-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/serial/serial-rs485.rst | 12 ++++++--- drivers/tty/serial/serial_core.c | 33 +++++++++++++++++++++--- 2 files changed, 37 insertions(+), 8 deletions(-) (limited to 'drivers/tty') diff --git a/Documentation/driver-api/serial/serial-rs485.rst b/Documentation/driver-api/serial/serial-rs485.rst index 6bc824f948f9..00b5d333acba 100644 --- a/Documentation/driver-api/serial/serial-rs485.rst +++ b/Documentation/driver-api/serial/serial-rs485.rst @@ -38,10 +38,14 @@ RS485 Serial Communications the values given by the device tree. Any driver for devices capable of working both as RS232 and RS485 should - implement the rs485_config callback in the uart_port structure. The - serial_core calls rs485_config to do the device specific part in response - to TIOCSRS485 and TIOCGRS485 ioctls (see below). The rs485_config callback - receives a pointer to struct serial_rs485. + implement the rs485_config callback and provide rs485_supported in the + uart_port structure. The serial core calls rs485_config to do the device + specific part in response to TIOCSRS485 ioctl (see below). The rs485_config + callback receives a pointer to a sanitizated serial_rs485 structure. The + serial_rs485 userspace provides is sanitized before calling rs485_config + using rs485_supported that indicates what RS485 features the driver supports + for the uart_port. TIOCGRS485 ioctl can be used to read back the + serial_rs485 structure matching to the current configuration. 4. Usage from user-level ======================== diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 44a50158552d..f0d7b3d20731 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1278,36 +1278,61 @@ static int uart_get_icount(struct tty_struct *tty, static void uart_sanitize_serial_rs485(struct uart_port *port, struct serial_rs485 *rs485) { + u32 supported_flags = port->rs485_supported->flags; + /* pick sane settings if the user hasn't */ - if (!(rs485->flags & SER_RS485_RTS_ON_SEND) == + if ((supported_flags & (SER_RS485_RTS_ON_SEND|SER_RS485_RTS_AFTER_SEND)) && + !(rs485->flags & SER_RS485_RTS_ON_SEND) == !(rs485->flags & SER_RS485_RTS_AFTER_SEND)) { dev_warn_ratelimited(port->dev, "%s (%d): invalid RTS setting, using RTS_ON_SEND instead\n", port->name, port->line); rs485->flags |= SER_RS485_RTS_ON_SEND; rs485->flags &= ~SER_RS485_RTS_AFTER_SEND; + supported_flags |= SER_RS485_RTS_ON_SEND|SER_RS485_RTS_AFTER_SEND; } - if (rs485->delay_rts_before_send > RS485_MAX_RTS_DELAY) { + if (!port->rs485_supported->delay_rts_before_send) { + if (rs485->delay_rts_before_send) { + dev_warn_ratelimited(port->dev, + "%s (%d): RTS delay before sending not supported\n", + port->name, port->line); + } + rs485->delay_rts_before_send = 0; + } else if (rs485->delay_rts_before_send > RS485_MAX_RTS_DELAY) { rs485->delay_rts_before_send = RS485_MAX_RTS_DELAY; dev_warn_ratelimited(port->dev, "%s (%d): RTS delay before sending clamped to %u ms\n", port->name, port->line, rs485->delay_rts_before_send); } - if (rs485->delay_rts_after_send > RS485_MAX_RTS_DELAY) { + if (!port->rs485_supported->delay_rts_after_send) { + if (rs485->delay_rts_after_send) { + dev_warn_ratelimited(port->dev, + "%s (%d): RTS delay after sending not supported\n", + port->name, port->line); + } + rs485->delay_rts_after_send = 0; + } else if (rs485->delay_rts_after_send > RS485_MAX_RTS_DELAY) { rs485->delay_rts_after_send = RS485_MAX_RTS_DELAY; dev_warn_ratelimited(port->dev, "%s (%d): RTS delay after sending clamped to %u ms\n", port->name, port->line, rs485->delay_rts_after_send); } + + rs485->flags &= supported_flags; + /* Return clean padding area to userspace */ memset(rs485->padding, 0, sizeof(rs485->padding)); } int uart_rs485_config(struct uart_port *port) { - return port->rs485_config(port, &port->rs485); + struct serial_rs485 *rs485 = &port->rs485; + + uart_sanitize_serial_rs485(port, rs485); + + return port->rs485_config(port, rs485); } EXPORT_SYMBOL_GPL(uart_rs485_config); -- cgit v1.2.3 From 596a9171472ba31edce566e938524dbbe3c54183 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:20 +0300 Subject: serial: Clear rs485 struct when non-RS485 mode is set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When SER_RS485_ENABLED is not set, having any other flag/field set in serial_rs485 struct does not have an effect different from not having them set. Thus, make the serial_rs485 struct also match the behavior for all flags, not just SER_RS485_ENABLED. Some drivers do similar clearing of rs485 struct in their rs485_config() already, but not all. This change makes the behavior consistent across drivers. Don't try to validate rs485 struct further when no RS485 is requested, this silences some bogus warnings. This change has (minor) userspace visible impact. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-24-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index f0d7b3d20731..6be538720564 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1280,6 +1280,11 @@ static void uart_sanitize_serial_rs485(struct uart_port *port, struct serial_rs4 { u32 supported_flags = port->rs485_supported->flags; + if (!(rs485->flags & SER_RS485_ENABLED)) { + memset(rs485, 0, sizeof(*rs485)); + return; + } + /* pick sane settings if the user hasn't */ if ((supported_flags & (SER_RS485_RTS_ON_SEND|SER_RS485_RTS_AFTER_SEND)) && !(rs485->flags & SER_RS485_RTS_ON_SEND) == @@ -1329,10 +1334,15 @@ static void uart_sanitize_serial_rs485(struct uart_port *port, struct serial_rs4 int uart_rs485_config(struct uart_port *port) { struct serial_rs485 *rs485 = &port->rs485; + int ret; uart_sanitize_serial_rs485(port, rs485); - return port->rs485_config(port, rs485); + ret = port->rs485_config(port, rs485); + if (ret) + memset(rs485, 0, sizeof(*rs485)); + + return ret; } EXPORT_SYMBOL_GPL(uart_rs485_config); -- cgit v1.2.3 From 51ad36baacb3b2fd1bd980138a937d30d6c84cdf Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:21 +0300 Subject: serial: return -EINVAL for non-legacy RS485 flags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to be add new flags more cleanly and safely, return -EINVAL from TIOCSRS485 ioctl for the flags bits which are not among the current legacy ones. This might cause a regression for userspace as those non-flag bits do not currently trigger -EINVAL. However, it would only occur if the userspace is sending garbage bits so perhaps we'll get away with this change. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-25-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 6be538720564..621fc15e2e54 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1276,6 +1276,27 @@ static int uart_get_icount(struct tty_struct *tty, return 0; } +#define SER_RS485_LEGACY_FLAGS (SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | \ + SER_RS485_RTS_AFTER_SEND | SER_RS485_RX_DURING_TX | \ + SER_RS485_TERMINATE_BUS) + +static int uart_check_rs485_flags(struct uart_port *port, struct serial_rs485 *rs485) +{ + u32 flags = rs485->flags; + + /* Don't return -EINVAL for unsupported legacy flags */ + flags &= ~SER_RS485_LEGACY_FLAGS; + + /* + * For any bit outside of the legacy ones that is not supported by + * the driver, return -EINVAL. + */ + if (flags & ~port->rs485_supported->flags) + return -EINVAL; + + return 0; +} + static void uart_sanitize_serial_rs485(struct uart_port *port, struct serial_rs485 *rs485) { u32 supported_flags = port->rs485_supported->flags; @@ -1375,6 +1396,9 @@ static int uart_set_rs485_config(struct uart_port *port, if (copy_from_user(&rs485, rs485_user, sizeof(*rs485_user))) return -EFAULT; + ret = uart_check_rs485_flags(port, &rs485); + if (ret) + return ret; uart_sanitize_serial_rs485(port, &rs485); spin_lock_irqsave(&port->lock, flags); -- cgit v1.2.3 From 9cdaf4fc2e6f8eeb137dbf6c5d6346cbf249ff49 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:22 +0300 Subject: serial: 8250_dwlib: Remove serial_rs485 sanitization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Serial core handles serial_rs485 sanitization and rs485 struct assignment. As serial_rs485 is already clear for the non-RS485 case by serial core, there no need to clear flags in the driver. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-26-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dwlib.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_dwlib.c b/drivers/tty/serial/8250/8250_dwlib.c index 120b29519d74..c83e7eaf3877 100644 --- a/drivers/tty/serial/8250/8250_dwlib.c +++ b/drivers/tty/serial/8250/8250_dwlib.c @@ -93,9 +93,6 @@ static int dw8250_rs485_config(struct uart_port *p, struct serial_rs485 *rs485) tcr &= ~DW_UART_TCR_XFER_MODE; if (rs485->flags & SER_RS485_ENABLED) { - /* Clear unsupported flags. */ - rs485->flags &= SER_RS485_ENABLED | SER_RS485_RX_DURING_TX | - SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND; tcr |= DW_UART_TCR_RS485_EN; if (rs485->flags & SER_RS485_RX_DURING_TX) { @@ -111,8 +108,6 @@ static int dw8250_rs485_config(struct uart_port *p, struct serial_rs485 *rs485) dw8250_writel_ext(p, DW_UART_DE_EN, 1); dw8250_writel_ext(p, DW_UART_RE_EN, 1); } else { - rs485->flags = 0; - tcr &= ~DW_UART_TCR_RS485_EN; } @@ -127,11 +122,6 @@ static int dw8250_rs485_config(struct uart_port *p, struct serial_rs485 *rs485) dw8250_writel_ext(p, DW_UART_TCR, tcr); - rs485->delay_rts_before_send = 0; - rs485->delay_rts_after_send = 0; - - p->rs485 = *rs485; - return 0; } -- cgit v1.2.3 From cf426544a4131c54c2e49b40547c43cfe2e56b76 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:23 +0300 Subject: serial: 8250_fintek: Remove serial_rs485 sanitization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Serial core handles serial_rs485 sanitization and copying rs485 struct. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-27-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_fintek.c | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c index 6e98c376e082..1fb86c73786c 100644 --- a/drivers/tty/serial/8250/8250_fintek.c +++ b/drivers/tty/serial/8250/8250_fintek.c @@ -206,19 +206,7 @@ static int fintek_8250_rs485_config(struct uart_port *port, if (!(rs485->flags & SER_RS485_RTS_ON_SEND) == !(rs485->flags & SER_RS485_RTS_AFTER_SEND)) return -EINVAL; - memset(rs485->padding, 0, sizeof(rs485->padding)); config |= RS485_URA; - } else { - memset(rs485, 0, sizeof(*rs485)); - } - - rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | - SER_RS485_RTS_AFTER_SEND; - - /* Only the first port supports delays */ - if (pdata->index) { - rs485->delay_rts_before_send = 0; - rs485->delay_rts_after_send = 0; } if (rs485->delay_rts_before_send) { @@ -241,8 +229,6 @@ static int fintek_8250_rs485_config(struct uart_port *port, sio_write_reg(pdata, RS485, config); fintek_8250_exit_key(pdata->base_port); - port->rs485 = *rs485; - return 0; } -- cgit v1.2.3 From ebc3c2a4cdba004de57f7d8316603ac61218d9d8 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:24 +0300 Subject: serial: 8250: lpc18xx: Remove serial_rs485 sanitization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Serial core handles serial_rs485 sanitization and copying rs485 struct. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-28-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_lpc18xx.c | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_lpc18xx.c b/drivers/tty/serial/8250/8250_lpc18xx.c index 66ce5d05fe9c..3a1cb51cbc91 100644 --- a/drivers/tty/serial/8250/8250_lpc18xx.c +++ b/drivers/tty/serial/8250/8250_lpc18xx.c @@ -40,14 +40,6 @@ static int lpc18xx_rs485_config(struct uart_port *port, u32 rs485_dly_reg = 0; unsigned baud_clk; - if (rs485->flags & SER_RS485_ENABLED) - memset(rs485->padding, 0, sizeof(rs485->padding)); - else - memset(rs485, 0, sizeof(*rs485)); - - rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | - SER_RS485_RTS_AFTER_SEND; - if (rs485->flags & SER_RS485_ENABLED) { rs485_ctrl_reg |= LPC18XX_UART_RS485CTRL_NMMEN | LPC18XX_UART_RS485CTRL_DCTRL; @@ -73,14 +65,9 @@ static int lpc18xx_rs485_config(struct uart_port *port, / baud_clk; } - /* Delay RTS before send not supported */ - rs485->delay_rts_before_send = 0; - serial_out(up, LPC18XX_UART_RS485CTRL, rs485_ctrl_reg); serial_out(up, LPC18XX_UART_RS485DLY, rs485_dly_reg); - port->rs485 = *rs485; - return 0; } -- cgit v1.2.3 From 61bca7da91c680ef140ecb35c27d887406bd4167 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:25 +0300 Subject: serial: 8250_pci: Remove serial_rs485 sanitization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Serial core handles serial_rs485 sanitization and copying rs485 struct. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-29-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index a76254031bc2..b6d71268aa7d 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1562,14 +1562,6 @@ static int pci_fintek_rs485_config(struct uart_port *port, pci_read_config_byte(pci_dev, 0x40 + 8 * *index + 7, &setting); - if (rs485->flags & SER_RS485_ENABLED) - memset(rs485->padding, 0, sizeof(rs485->padding)); - else - memset(rs485, 0, sizeof(*rs485)); - - /* F81504/508/512 not support RTS delay before or after send */ - rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND; - if (rs485->flags & SER_RS485_ENABLED) { /* Enable RTS H/W control mode */ setting |= FINTEK_RTS_CONTROL_BY_HW; @@ -1581,9 +1573,6 @@ static int pci_fintek_rs485_config(struct uart_port *port, /* RTS driving low on TX */ setting |= FINTEK_RTS_INVERT; } - - rs485->delay_rts_after_send = 0; - rs485->delay_rts_before_send = 0; } else { /* Disable RTS H/W control mode */ setting &= ~(FINTEK_RTS_CONTROL_BY_HW | FINTEK_RTS_INVERT); @@ -1591,9 +1580,6 @@ static int pci_fintek_rs485_config(struct uart_port *port, pci_write_config_byte(pci_dev, 0x40 + 8 * *index + 7, setting); - if (rs485 != &port->rs485) - port->rs485 = *rs485; - return 0; } -- cgit v1.2.3 From b9759cba3221767ac1910b0cff65ec588003b9a6 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:26 +0300 Subject: serial: pl011: Remove serial_rs485 sanitization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Serial core handles serial_rs485 sanitization. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-30-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index cdc466e89aa8..eccd66625d25 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -2681,17 +2681,12 @@ static int pl011_find_free_port(void) static int pl011_get_rs485_mode(struct uart_amba_port *uap) { struct uart_port *port = &uap->port; - struct serial_rs485 *rs485 = &port->rs485; int ret; ret = uart_get_rs485_mode(port); if (ret) return ret; - /* clamp the delays to [0, 100ms] */ - rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U); - rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U); - return 0; } -- cgit v1.2.3 From 7195eefb38d76d2353e658b10a8b1c2b1f8341e3 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:27 +0300 Subject: serial: fsl_lpuart: Call core's sanitization and remove custom one MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Serial core handles serial_rs485 sanitization. Remove custom sanitization from lpuart_config_rs485. This change loses dev_err when SER_RS485_RX_DURING_TX is set due to incorrect configuration. Other drivers do not do similar prinout for full-duplex case and it should be done in serial core if it is desirable to notify on this condition. Personally, I doesn't see it important because the kernel gracefully downgrades to half-duplex. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-31-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 17 ----------------- 1 file changed, 17 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 88692dc9eefa..d35414cb3e4e 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -1365,11 +1365,6 @@ static int lpuart_config_rs485(struct uart_port *port, ~(UARTMODEM_TXRTSPOL | UARTMODEM_TXRTSE); writeb(modem, sport->port.membase + UARTMODEM); - /* clear unsupported configurations */ - rs485->delay_rts_before_send = 0; - rs485->delay_rts_after_send = 0; - rs485->flags &= ~SER_RS485_RX_DURING_TX; - if (rs485->flags & SER_RS485_ENABLED) { /* Enable auto RS-485 RTS mode */ modem |= UARTMODEM_TXRTSE; @@ -1400,11 +1395,6 @@ static int lpuart32_config_rs485(struct uart_port *port, & ~(UARTMODEM_TXRTSPOL | UARTMODEM_TXRTSE); lpuart32_write(&sport->port, modem, UARTMODIR); - /* clear unsupported configurations */ - rs485->delay_rts_before_send = 0; - rs485->delay_rts_after_send = 0; - rs485->flags &= ~SER_RS485_RX_DURING_TX; - if (rs485->flags & SER_RS485_ENABLED) { /* Enable auto RS-485 RTS mode */ modem |= UARTMODEM_TXRTSE; @@ -2723,13 +2713,6 @@ static int lpuart_probe(struct platform_device *pdev) if (ret) goto failed_get_rs485; - if (sport->port.rs485.flags & SER_RS485_RX_DURING_TX) - dev_err(&pdev->dev, "driver doesn't support RX during TX\n"); - - if (sport->port.rs485.delay_rts_before_send || - sport->port.rs485.delay_rts_after_send) - dev_err(&pdev->dev, "driver doesn't support RTS delays\n"); - uart_rs485_config(&sport->port); ret = devm_request_irq(&pdev->dev, sport->port.irq, handler, 0, -- cgit v1.2.3 From 55e18c6b6d426818032d5e0f9d88d87fd2a8ae30 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:28 +0300 Subject: serial: imx: Remove serial_rs485 sanitization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver provides different rs485_supported for the case where RTS is not available making it unnecessary to handle it in imx_uart_rs485_config. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-32-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 9d5f505008f7..f4edde54175f 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -1913,10 +1913,6 @@ static int imx_uart_rs485_config(struct uart_port *port, struct imx_port *sport = (struct imx_port *)port; u32 ucr2; - /* RTS is required to control the transmitter */ - if (!sport->have_rtscts && !sport->have_rtsgpio) - rs485conf->flags &= ~SER_RS485_ENABLED; - if (rs485conf->flags & SER_RS485_ENABLED) { /* Enable receiver if low-active RTS signal is requested */ if (sport->have_rtscts && !sport->have_rtsgpio && -- cgit v1.2.3 From ad98c78bd011ca76d1667aa3cb53562dfb29725a Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:29 +0300 Subject: serial: max310x: Remove serial_rs485 sanitization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Serial core handles serial_rs485 sanitization. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-33-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 7b0c1351d75e..4915a786e315 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1045,8 +1045,6 @@ static int max310x_rs485_config(struct uart_port *port, (rs485->delay_rts_after_send > 0x0f)) return -ERANGE; - rs485->flags &= SER_RS485_RTS_ON_SEND | SER_RS485_RX_DURING_TX | - SER_RS485_ENABLED; port->rs485 = *rs485; schedule_work(&one->rs_work); -- cgit v1.2.3 From e25ed4a8857f8bf6d4f51bea0ff6c6a80adbb7fe Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:30 +0300 Subject: serial: 8250_exar: Remove serial_rs485 assignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Serial core handles serial_rs485 assignment. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-34-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_exar.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index 11916f603a3d..528779b40049 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -427,8 +427,6 @@ static int generic_rs485_config(struct uart_port *port, if (is_rs485) writeb(UART_EXAR_RS485_DLY(4), p + UART_MSR); - port->rs485 = *rs485; - return 0; } -- cgit v1.2.3 From fd93a3d851c54198a517c6209947cc0569e1059d Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:31 +0300 Subject: serial: mcf: Remove serial_rs485 assignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Serial core handles serial_rs485 assignment. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-35-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/mcf.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c index 655255e0c76a..036f178e3d66 100644 --- a/drivers/tty/serial/mcf.c +++ b/drivers/tty/serial/mcf.c @@ -448,7 +448,6 @@ static int mcf_config_rs485(struct uart_port *port, struct serial_rs485 *rs485) } writeb(mr1, port->membase + MCFUART_UMR); writeb(mr2, port->membase + MCFUART_UMR); - port->rs485 = *rs485; return 0; } -- cgit v1.2.3 From bbdcbc1301ce16d5cbabfbccaacb87f047a0a309 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:32 +0300 Subject: serial: sc16is7xx: Remove serial_rs485 assignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Serial core handles serial_rs485 assignment. It is safe to remove this assignment because sc16is7xx_reg_proc() takes port.lock at start (and sc16is7xx_reconf_rs485() would too). Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-36-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sc16is7xx.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index b3162dfe97b1..2ceecaa4a478 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -1143,7 +1143,6 @@ static int sc16is7xx_config_rs485(struct uart_port *port, return -EINVAL; } - port->rs485 = *rs485; one->config.flags |= SC16IS7XX_RECONF_RS485; kthread_queue_work(&s->kworker, &one->reg_work); -- cgit v1.2.3 From 84f2faa7852e1f55d89bb0c99b3a672b87b11f87 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:33 +0300 Subject: serial: 8250: Remove serial_rs485 sanitization from em485 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Serial core handles serial_rs485 sanitization. When em485 init fails, there are two possible paths of entry: 1) uart_rs485_config (init path) that fully clears port->rs485 on error. 2) ioctl path with a pre-existing, valid port->rs485 unto which the kernel falls back on error and port->rs485 should therefore be kept untouched. The temporary rs485 struct is not returned to userspace in case of error so its flag don't matter. ...Thus SER_RS485_ENABLED clearing on error can/should be dropped. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-37-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 65a60e4808ea..953b0fadfd4c 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -675,13 +675,6 @@ int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485) rs485->flags &= ~SER_RS485_RTS_AFTER_SEND; } - /* clamp the delays to [0, 100ms] */ - rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U); - rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U); - - memset(rs485->padding, 0, sizeof(rs485->padding)); - port->rs485 = *rs485; - gpiod_set_value(port->rs485_term_gpio, rs485->flags & SER_RS485_TERMINATE_BUS); @@ -689,15 +682,8 @@ int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485) * Both serial8250_em485_init() and serial8250_em485_destroy() * are idempotent. */ - if (rs485->flags & SER_RS485_ENABLED) { - int ret = serial8250_em485_init(up); - - if (ret) { - rs485->flags &= ~SER_RS485_ENABLED; - port->rs485.flags &= ~SER_RS485_ENABLED; - } - return ret; - } + if (rs485->flags & SER_RS485_ENABLED) + return serial8250_em485_init(up); serial8250_em485_destroy(up); return 0; -- cgit v1.2.3 From 6bb6fa6908ebd3cb4e14cd4f0ce272ec885d2eb0 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 18:36:51 +0300 Subject: tty: Implement lookahead to process XON/XOFF timely MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When tty is not read from, XON/XOFF may get stuck into an intermediate buffer. As those characters are there to do software flow-control, it is not very useful. In the case where neither end reads from ttys, the receiving ends might not be able receive the XOFF characters and just keep sending more data to the opposite direction. This problem is almost guaranteed to occur with DMA which sends data in large chunks. If TTY is slow to process characters, that is, eats less than given amount in receive_buf, invoke lookahead for the rest of the chars to process potential XON/XOFF characters. We need to keep track of how many characters have been processed by the lookahead to avoid processing the flow control char again on the normal path. Bookkeeping occurs parallel on two layers (tty_buffer and n_tty) to avoid passing the lookahead_count through the whole call chain. When a flow-control char is processed, two things must occur: a) it must not be treated as normal char b) if not yet processed, flow-control actions need to be taken The return value of n_tty_receive_char_flow_ctrl() tells caller a), and b) is kept internal to n_tty_receive_char_flow_ctrl(). If characters were previous looked ahead, __receive_buf() makes two calls to the appropriate n_tty_receive_buf_* function. First call is made with lookahead_done=true for the characters that were subject to lookahead earlier and then with lookahead=false for the new characters. Either of the calls might be skipped when it has no characters to handle. Reported-by: Gilles Buloz Reviewed-by: Andy Shevchenko Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606153652.63554-2-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_tty.c | 91 ++++++++++++++++++++++++++++++++++++++-------- drivers/tty/tty_buffer.c | 59 +++++++++++++++++++++++++----- drivers/tty/tty_port.c | 21 +++++++++++ include/linux/tty_buffer.h | 1 + include/linux/tty_ldisc.h | 14 +++++++ include/linux/tty_port.h | 2 + 6 files changed, 163 insertions(+), 25 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 640c9e871044..8d80384df874 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -118,6 +118,9 @@ struct n_tty_data { size_t read_tail; size_t line_start; + /* # of chars looked ahead (to find software flow control chars) */ + size_t lookahead_count; + /* protected by output lock */ unsigned int column; unsigned int canon_column; @@ -333,6 +336,8 @@ static void reset_buffer_flags(struct n_tty_data *ldata) ldata->erasing = 0; bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE); ldata->push = 0; + + ldata->lookahead_count = 0; } static void n_tty_packet_mode_flush(struct tty_struct *tty) @@ -1225,12 +1230,30 @@ static bool n_tty_is_char_flow_ctrl(struct tty_struct *tty, unsigned char c) return c == START_CHAR(tty) || c == STOP_CHAR(tty); } -/* Returns true if c is consumed as flow-control character */ -static bool n_tty_receive_char_flow_ctrl(struct tty_struct *tty, unsigned char c) +/** + * n_tty_receive_char_flow_ctrl - receive flow control chars + * @tty: terminal device + * @c: character + * @lookahead_done: lookahead has processed this character already + * + * Receive and process flow control character actions. + * + * In case lookahead for flow control chars already handled the character in + * advance to the normal receive, the actions are skipped during normal + * receive. + * + * Returns true if @c is consumed as flow-control character, the character + * must not be treated as normal character. + */ +static bool n_tty_receive_char_flow_ctrl(struct tty_struct *tty, unsigned char c, + bool lookahead_done) { if (!n_tty_is_char_flow_ctrl(tty, c)) return false; + if (lookahead_done) + return true; + if (c == START_CHAR(tty)) { start_tty(tty); process_echoes(tty); @@ -1242,11 +1265,12 @@ static bool n_tty_receive_char_flow_ctrl(struct tty_struct *tty, unsigned char c return true; } -static void n_tty_receive_char_special(struct tty_struct *tty, unsigned char c) +static void n_tty_receive_char_special(struct tty_struct *tty, unsigned char c, + bool lookahead_done) { struct n_tty_data *ldata = tty->disc_data; - if (I_IXON(tty) && n_tty_receive_char_flow_ctrl(tty, c)) + if (I_IXON(tty) && n_tty_receive_char_flow_ctrl(tty, c, lookahead_done)) return; if (L_ISIG(tty)) { @@ -1401,7 +1425,8 @@ static void n_tty_receive_char(struct tty_struct *tty, unsigned char c) put_tty_queue(c, ldata); } -static void n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c) +static void n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c, + bool lookahead_done) { if (I_ISTRIP(tty)) c &= 0x7f; @@ -1409,9 +1434,12 @@ static void n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c) c = tolower(c); if (I_IXON(tty)) { - if (c == STOP_CHAR(tty)) - stop_tty(tty); - else if (c == START_CHAR(tty) || + if (c == STOP_CHAR(tty)) { + if (!lookahead_done) + stop_tty(tty); + } else if (c == START_CHAR(tty) && lookahead_done) { + return; + } else if (c == START_CHAR(tty) || (tty->flow.stopped && !tty->flow.tco_stopped && I_IXANY(tty) && c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) && c != SUSP_CHAR(tty))) { @@ -1457,6 +1485,27 @@ n_tty_receive_char_lnext(struct tty_struct *tty, unsigned char c, char flag) n_tty_receive_char_flagged(tty, c, flag); } +/* Caller must ensure count > 0 */ +static void n_tty_lookahead_flow_ctrl(struct tty_struct *tty, const unsigned char *cp, + const unsigned char *fp, unsigned int count) +{ + struct n_tty_data *ldata = tty->disc_data; + unsigned char flag = TTY_NORMAL; + + ldata->lookahead_count += count; + + if (!I_IXON(tty)) + return; + + while (count--) { + if (fp) + flag = *fp++; + if (likely(flag == TTY_NORMAL)) + n_tty_receive_char_flow_ctrl(tty, *cp, false); + cp++; + } +} + static void n_tty_receive_buf_real_raw(struct tty_struct *tty, const unsigned char *cp, const char *fp, int count) @@ -1496,7 +1545,7 @@ n_tty_receive_buf_raw(struct tty_struct *tty, const unsigned char *cp, static void n_tty_receive_buf_closing(struct tty_struct *tty, const unsigned char *cp, - const char *fp, int count) + const char *fp, int count, bool lookahead_done) { char flag = TTY_NORMAL; @@ -1504,12 +1553,12 @@ n_tty_receive_buf_closing(struct tty_struct *tty, const unsigned char *cp, if (fp) flag = *fp++; if (likely(flag == TTY_NORMAL)) - n_tty_receive_char_closing(tty, *cp++); + n_tty_receive_char_closing(tty, *cp++, lookahead_done); } } static void n_tty_receive_buf_standard(struct tty_struct *tty, - const unsigned char *cp, const char *fp, int count) + const unsigned char *cp, const char *fp, int count, bool lookahead_done) { struct n_tty_data *ldata = tty->disc_data; char flag = TTY_NORMAL; @@ -1540,7 +1589,7 @@ static void n_tty_receive_buf_standard(struct tty_struct *tty, } if (test_bit(c, ldata->char_map)) - n_tty_receive_char_special(tty, c); + n_tty_receive_char_special(tty, c, lookahead_done); else n_tty_receive_char(tty, c); } @@ -1551,21 +1600,30 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp, { struct n_tty_data *ldata = tty->disc_data; bool preops = I_ISTRIP(tty) || (I_IUCLC(tty) && L_IEXTEN(tty)); + size_t la_count = min_t(size_t, ldata->lookahead_count, count); if (ldata->real_raw) n_tty_receive_buf_real_raw(tty, cp, fp, count); else if (ldata->raw || (L_EXTPROC(tty) && !preops)) n_tty_receive_buf_raw(tty, cp, fp, count); - else if (tty->closing && !L_EXTPROC(tty)) - n_tty_receive_buf_closing(tty, cp, fp, count); - else { - n_tty_receive_buf_standard(tty, cp, fp, count); + else if (tty->closing && !L_EXTPROC(tty)) { + if (la_count > 0) + n_tty_receive_buf_closing(tty, cp, fp, la_count, true); + if (count > la_count) + n_tty_receive_buf_closing(tty, cp, fp, count - la_count, false); + } else { + if (la_count > 0) + n_tty_receive_buf_standard(tty, cp, fp, la_count, true); + if (count > la_count) + n_tty_receive_buf_standard(tty, cp, fp, count - la_count, false); flush_echoes(tty); if (tty->ops->flush_chars) tty->ops->flush_chars(tty); } + ldata->lookahead_count -= la_count; + if (ldata->icanon && !L_EXTPROC(tty)) return; @@ -2446,6 +2504,7 @@ static struct tty_ldisc_ops n_tty_ops = { .receive_buf = n_tty_receive_buf, .write_wakeup = n_tty_write_wakeup, .receive_buf2 = n_tty_receive_buf2, + .lookahead_buf = n_tty_lookahead_flow_ctrl, }; /** diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index bfa431a8e690..754fa43670cc 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -104,6 +105,7 @@ static void tty_buffer_reset(struct tty_buffer *p, size_t size) p->size = size; p->next = NULL; p->commit = 0; + p->lookahead = 0; p->read = 0; p->flags = 0; } @@ -234,6 +236,7 @@ void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld) buf->head = next; } buf->head->read = buf->head->commit; + buf->head->lookahead = buf->head->read; if (ld && ld->ops->flush_buffer) ld->ops->flush_buffer(tty); @@ -276,13 +279,15 @@ static int __tty_buffer_request_room(struct tty_port *port, size_t size, if (n != NULL) { n->flags = flags; buf->tail = n; - /* paired w/ acquire in flush_to_ldisc(); ensures - * flush_to_ldisc() sees buffer data. + /* + * Paired w/ acquire in flush_to_ldisc() and lookahead_bufs() + * ensures they see all buffer data. */ smp_store_release(&b->commit, b->used); - /* paired w/ acquire in flush_to_ldisc(); ensures the - * latest commit value can be read before the head is - * advanced to the next buffer + /* + * Paired w/ acquire in flush_to_ldisc() and lookahead_bufs() + * ensures the latest commit value can be read before the head + * is advanced to the next buffer. */ smp_store_release(&b->next, n); } else if (change) @@ -459,6 +464,40 @@ int tty_ldisc_receive_buf(struct tty_ldisc *ld, const unsigned char *p, } EXPORT_SYMBOL_GPL(tty_ldisc_receive_buf); +static void lookahead_bufs(struct tty_port *port, struct tty_buffer *head) +{ + head->lookahead = max(head->lookahead, head->read); + + while (head) { + struct tty_buffer *next; + unsigned char *p, *f = NULL; + unsigned int count; + + /* + * Paired w/ release in __tty_buffer_request_room(); + * ensures commit value read is not stale if the head + * is advancing to the next buffer. + */ + next = smp_load_acquire(&head->next); + /* + * Paired w/ release in __tty_buffer_request_room() or in + * tty_buffer_flush(); ensures we see the committed buffer data. + */ + count = smp_load_acquire(&head->commit) - head->lookahead; + if (!count) { + head = next; + continue; + } + + p = char_buf_ptr(head, head->lookahead); + if (~head->flags & TTYB_NORMAL) + f = flag_buf_ptr(head, head->lookahead); + + port->client_ops->lookahead_buf(port, p, f, count); + head->lookahead += count; + } +} + static int receive_buf(struct tty_port *port, struct tty_buffer *head, int count) { @@ -496,7 +535,7 @@ static void flush_to_ldisc(struct work_struct *work) while (1) { struct tty_buffer *head = buf->head; struct tty_buffer *next; - int count; + int count, rcvd; /* Ldisc or user is trying to gain exclusive access */ if (atomic_read(&buf->priority)) @@ -519,10 +558,12 @@ static void flush_to_ldisc(struct work_struct *work) continue; } - count = receive_buf(port, head, count); - if (!count) + rcvd = receive_buf(port, head, count); + head->read += rcvd; + if (rcvd < count) + lookahead_bufs(port, head); + if (!rcvd) break; - head->read += count; if (need_resched()) cond_resched(); diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 880608a65773..dce08a6d7b5e 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -43,6 +43,26 @@ static int tty_port_default_receive_buf(struct tty_port *port, return ret; } +static void tty_port_default_lookahead_buf(struct tty_port *port, const unsigned char *p, + const unsigned char *f, unsigned int count) +{ + struct tty_struct *tty; + struct tty_ldisc *disc; + + tty = READ_ONCE(port->itty); + if (!tty) + return; + + disc = tty_ldisc_ref(tty); + if (!disc) + return; + + if (disc->ops->lookahead_buf) + disc->ops->lookahead_buf(disc->tty, p, f, count); + + tty_ldisc_deref(disc); +} + static void tty_port_default_wakeup(struct tty_port *port) { struct tty_struct *tty = tty_port_tty_get(port); @@ -55,6 +75,7 @@ static void tty_port_default_wakeup(struct tty_port *port) const struct tty_port_client_operations tty_port_default_client_ops = { .receive_buf = tty_port_default_receive_buf, + .lookahead_buf = tty_port_default_lookahead_buf, .write_wakeup = tty_port_default_wakeup, }; EXPORT_SYMBOL_GPL(tty_port_default_client_ops); diff --git a/include/linux/tty_buffer.h b/include/linux/tty_buffer.h index 3b9d77604291..1796648c2907 100644 --- a/include/linux/tty_buffer.h +++ b/include/linux/tty_buffer.h @@ -15,6 +15,7 @@ struct tty_buffer { int used; int size; int commit; + int lookahead; /* Lazy update on recv, can become less than "read" */ int read; int flags; /* Data points here */ diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h index e85002b56752..33678e1936f6 100644 --- a/include/linux/tty_ldisc.h +++ b/include/linux/tty_ldisc.h @@ -186,6 +186,18 @@ int ldsem_down_write_nested(struct ld_semaphore *sem, int subclass, * indicate all data received is %TTY_NORMAL. If assigned, prefer this * function for automatic flow control. * + * @lookahead_buf: [DRV] ``void ()(struct tty_struct *tty, + * const unsigned char *cp, const char *fp, int count) + * + * This function is called by the low-level tty driver for characters + * not eaten by ->receive_buf() or ->receive_buf2(). It is useful for + * processing high-priority characters such as software flow-control + * characters that could otherwise get stuck into the intermediate + * buffer until tty has room to receive them. Ldisc must be able to + * handle later a ->receive_buf() or ->receive_buf2() call for the + * same characters (e.g. by skipping the actions for high-priority + * characters already handled by ->lookahead_buf()). + * * @owner: module containting this ldisc (for reference counting) * * This structure defines the interface between the tty line discipline @@ -229,6 +241,8 @@ struct tty_ldisc_ops { void (*dcd_change)(struct tty_struct *tty, unsigned int status); int (*receive_buf2)(struct tty_struct *tty, const unsigned char *cp, const char *fp, int count); + void (*lookahead_buf)(struct tty_struct *tty, const unsigned char *cp, + const unsigned char *fp, unsigned int count); struct module *owner; }; diff --git a/include/linux/tty_port.h b/include/linux/tty_port.h index 58e9619116b7..fa3c3bdaa234 100644 --- a/include/linux/tty_port.h +++ b/include/linux/tty_port.h @@ -40,6 +40,8 @@ struct tty_port_operations { struct tty_port_client_operations { int (*receive_buf)(struct tty_port *port, const unsigned char *, const unsigned char *, size_t); + void (*lookahead_buf)(struct tty_port *port, const unsigned char *cp, + const unsigned char *fp, unsigned int count); void (*write_wakeup)(struct tty_port *port); }; -- cgit v1.2.3 From 65534736d9a5cab5340ae8819e1394b6325e8390 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 18:36:52 +0300 Subject: tty: Use flow-control char function on closing path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use n_tty_receive_char_flow_ctrl also on the closing path. This makes the code cleaner and consistent. However, there a small change of regression! The earlier closing path has a small difference compared with the normal receive path. If START_CHAR and STOP_CHAR are equal, their precedence is different depending on which path a character is processed. I don't know whether this difference was intentional or not, and if equal START_CHAR and STOP_CHAR is actually used anywhere. But it feels not so useful corner case. While this change would logically belong to those earlier changes, having a separate patch for this is useful. If this regresses, bisect can pinpoint this change rather than the large patch. Also, this change is not necessary to minimal fix for the issue addressed in the previous patch. Reviewed-by: Andy Shevchenko Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606153652.63554-3-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_tty.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 8d80384df874..3afdd9033a9c 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -1434,15 +1434,10 @@ static void n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c, c = tolower(c); if (I_IXON(tty)) { - if (c == STOP_CHAR(tty)) { - if (!lookahead_done) - stop_tty(tty); - } else if (c == START_CHAR(tty) && lookahead_done) { - return; - } else if (c == START_CHAR(tty) || - (tty->flow.stopped && !tty->flow.tco_stopped && I_IXANY(tty) && - c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) && - c != SUSP_CHAR(tty))) { + if (!n_tty_receive_char_flow_ctrl(tty, c, lookahead_done) && + tty->flow.stopped && !tty->flow.tco_stopped && I_IXANY(tty) && + c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) && + c != SUSP_CHAR(tty)) { start_tty(tty); process_echoes(tty); } -- cgit v1.2.3 From 139f39be42fcd5f88366d6f3e6f05002027d3514 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 14 Jun 2022 11:05:30 +0200 Subject: tty/vt: consolemap: use ARRAY_SIZE(), part II. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code still uses constants (macros) as bounds in loops after commit 17945d317a52 (tty/vt: consolemap: use ARRAY_SIZE()). The contants are at least macros used also in the definition of the arrays. But use ARRAY_SIZE() on two more places to ensure the loops never run out of bounds even if the array definition change. Reviewed-by: Ilpo Järvinen Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220614090537.15557-1-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index fff97ae87e00..2039237b5266 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -232,7 +232,7 @@ static void set_inverse_transl(struct vc_data *conp, struct uni_pagedict *p, } memset(q, 0, MAX_GLYPH); - for (j = 0; j < E_TABSZ; j++) { + for (j = 0; j < ARRAY_SIZE(translations[m]); j++) { glyph = conv_uni_to_pc(conp, t[j]); if (glyph >= 0 && glyph < MAX_GLYPH && q[glyph] < 32) { /* prefer '-' above SHY etc. */ @@ -367,7 +367,7 @@ int con_get_trans_old(unsigned char __user * arg) unsigned char outbuf[E_TABSZ]; console_lock(); - for (i = 0; i < E_TABSZ ; i++) + for (i = 0; i < ARRAY_SIZE(outbuf); i++) { ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]); outbuf[i] = (ch & ~0xff) ? 0 : ch; -- cgit v1.2.3 From 43e1d0776840b05c356c78a0c5c7d544af07a6a4 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 14 Jun 2022 11:05:31 +0200 Subject: tty/vt: consolemap: remove unused parameter from set_inverse_trans_unicode() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit conp is unused in set_inverse_trans_unicode(), remove it. Reviewed-by: Ilpo Järvinen Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220614090537.15557-2-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 2039237b5266..c5f5fa39d7b2 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -241,8 +241,7 @@ static void set_inverse_transl(struct vc_data *conp, struct uni_pagedict *p, } } -static void set_inverse_trans_unicode(struct vc_data *conp, - struct uni_pagedict *p) +static void set_inverse_trans_unicode(struct uni_pagedict *p) { unsigned int d, r, g; u16 *inv; @@ -327,7 +326,7 @@ static void update_user_maps(void) p = *vc_cons[i].d->vc_uni_pagedir_loc; if (p && p != q) { set_inverse_transl(vc_cons[i].d, p, USER_MAP); - set_inverse_trans_unicode(vc_cons[i].d, p); + set_inverse_trans_unicode(p); q = p; } } @@ -678,7 +677,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) for (enum translation_map m = FIRST_MAP; m <= LAST_MAP; m++) set_inverse_transl(vc, dict, m); - set_inverse_trans_unicode(vc, dict); + set_inverse_trans_unicode(dict); out_unlock: console_unlock(); @@ -741,7 +740,7 @@ int con_set_default_unimap(struct vc_data *vc) for (enum translation_map m = FIRST_MAP; m <= LAST_MAP; m++) set_inverse_transl(vc, dict, m); - set_inverse_trans_unicode(vc, dict); + set_inverse_trans_unicode(dict); dflt = dict; return err; } -- cgit v1.2.3 From a7311228ae9bbfe532844ac55e8cfb68a574f2e1 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 14 Jun 2022 11:05:32 +0200 Subject: tty/vt: consolemap: saner variable names in set_inverse_trans_unicode() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function still uses too vague parameter name after commit 50c92a1b2d50 (tty/vt: consolemap: saner variable names in set_inverse_trans_unicode()). So use "dict" instead of "p" for that parameter too. Reviewed-by: Ilpo Järvinen Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220614090537.15557-3-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index c5f5fa39d7b2..55fb466361c1 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -241,17 +241,17 @@ static void set_inverse_transl(struct vc_data *conp, struct uni_pagedict *p, } } -static void set_inverse_trans_unicode(struct uni_pagedict *p) +static void set_inverse_trans_unicode(struct uni_pagedict *dict) { unsigned int d, r, g; u16 *inv; - if (!p) + if (!dict) return; - inv = p->inverse_trans_unicode; + inv = dict->inverse_trans_unicode; if (!inv) { - inv = p->inverse_trans_unicode = kmalloc_array(MAX_GLYPH, + inv = dict->inverse_trans_unicode = kmalloc_array(MAX_GLYPH, sizeof(*inv), GFP_KERNEL); if (!inv) return; @@ -259,7 +259,7 @@ static void set_inverse_trans_unicode(struct uni_pagedict *p) memset(inv, 0, MAX_GLYPH * sizeof(*inv)); for (d = 0; d < UNI_DIRS; d++) { - u16 **dir = p->uni_pgdir[d]; + u16 **dir = dict->uni_pgdir[d]; if (!dir) continue; for (r = 0; r < UNI_DIR_ROWS; r++) { -- cgit v1.2.3 From d524e1c764a6befcaf384f40b45d05ba63fc172f Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 14 Jun 2022 11:05:33 +0200 Subject: tty/vt: consolemap: saner variable names in set_inverse_transl() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function uses too vague variable names like i, j, k for iterators, p, q, p1, p2 for pointers etc. Rename all these, so that it is clear what is going on: - dict: for dictionaries. - d, r, g: for dir, row, glyph iterators -- these are unsigned now. - dir, row: for directory and row pointers. - glyph: for the glyph. - and so on... This is a lot of shuffling, but the result pays off, IMO. Reviewed-by: Ilpo Järvinen Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220614090537.15557-4-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 55fb466361c1..3d0e10dac6d9 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -214,29 +214,29 @@ struct uni_pagedict { static struct uni_pagedict *dflt; -static void set_inverse_transl(struct vc_data *conp, struct uni_pagedict *p, +static void set_inverse_transl(struct vc_data *conp, struct uni_pagedict *dict, enum translation_map m) { - int j, glyph; unsigned short *t = translations[m]; - unsigned char *q; + unsigned char *inv; - if (!p) + if (!dict) return; - q = p->inverse_translations[m]; + inv = dict->inverse_translations[m]; - if (!q) { - q = p->inverse_translations[m] = kmalloc(MAX_GLYPH, GFP_KERNEL); - if (!q) + if (!inv) { + inv = dict->inverse_translations[m] = kmalloc(MAX_GLYPH, + GFP_KERNEL); + if (!inv) return; } - memset(q, 0, MAX_GLYPH); + memset(inv, 0, MAX_GLYPH); - for (j = 0; j < ARRAY_SIZE(translations[m]); j++) { - glyph = conv_uni_to_pc(conp, t[j]); - if (glyph >= 0 && glyph < MAX_GLYPH && q[glyph] < 32) { + for (unsigned int ch = 0; ch < ARRAY_SIZE(translations[m]); ch++) { + int glyph = conv_uni_to_pc(conp, t[ch]); + if (glyph >= 0 && glyph < MAX_GLYPH && inv[glyph] < 32) { /* prefer '-' above SHY etc. */ - q[glyph] = j; + inv[glyph] = ch; } } } -- cgit v1.2.3 From 8da443b1a4036b5863fd2ec7e0251164b704c726 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 14 Jun 2022 11:05:34 +0200 Subject: tty/vt: consolemap: rename struct vc_data::vc_uni_pagedir* MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As a follow-up to the commit 4173f018aae1 (tty/vt: consolemap: rename and document struct uni_pagedir), rename also the members of struct vc_data. I.e. pagedir -> pagedict. And while touching all the places, remove also the unnecessary vc_ prefix. Suggested-by: Ilpo Järvinen Reviewed-by: Ilpo Järvinen Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220614090537.15557-5-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 46 ++++++++++++++++----------------- drivers/tty/vt/vt.c | 8 +++--- drivers/usb/misc/sisusbvga/sisusb_con.c | 2 +- drivers/video/console/vgacon.c | 8 +++--- drivers/video/fbdev/core/fbcon.c | 8 +++--- include/linux/console_struct.h | 4 +-- 6 files changed, 38 insertions(+), 38 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 3d0e10dac6d9..16d0d8f04f0e 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -296,7 +296,7 @@ u16 inverse_translate(const struct vc_data *conp, u16 glyph, bool use_unicode) if (glyph >= MAX_GLYPH) return 0; - p = *conp->vc_uni_pagedir_loc; + p = *conp->uni_pagedict_loc; if (!p) return glyph; @@ -323,7 +323,7 @@ static void update_user_maps(void) for (i = 0; i < MAX_NR_CONSOLES; i++) { if (!vc_cons_allocated(i)) continue; - p = *vc_cons[i].d->vc_uni_pagedir_loc; + p = *vc_cons[i].d->uni_pagedict_loc; if (p && p != q) { set_inverse_transl(vc_cons[i].d, p, USER_MAP); set_inverse_trans_unicode(p); @@ -445,10 +445,10 @@ void con_free_unimap(struct vc_data *vc) { struct uni_pagedict *p; - p = *vc->vc_uni_pagedir_loc; + p = *vc->uni_pagedict_loc; if (!p) return; - *vc->vc_uni_pagedir_loc = NULL; + *vc->uni_pagedict_loc = NULL; if (--p->refcount) return; con_release_unimap(p); @@ -463,7 +463,7 @@ static int con_unify_unimap(struct vc_data *conp, struct uni_pagedict *dict1) for (cons = 0; cons < MAX_NR_CONSOLES; cons++) { if (!vc_cons_allocated(cons)) continue; - dict2 = *vc_cons[cons].d->vc_uni_pagedir_loc; + dict2 = *vc_cons[cons].d->uni_pagedict_loc; if (!dict2 || dict2 == dict1 || dict2->sum != dict1->sum) continue; for (d = 0; d < UNI_DIRS; d++) { @@ -487,7 +487,7 @@ static int con_unify_unimap(struct vc_data *conp, struct uni_pagedict *dict1) } if (d == UNI_DIRS) { dict2->refcount++; - *conp->vc_uni_pagedir_loc = dict2; + *conp->uni_pagedict_loc = dict2; con_release_unimap(dict1); kfree(dict1); return 1; @@ -531,14 +531,14 @@ con_insert_unipair(struct uni_pagedict *p, u_short unicode, u_short fontpos) static int con_allocate_new(struct vc_data *vc) { - struct uni_pagedict *new, *old = *vc->vc_uni_pagedir_loc; + struct uni_pagedict *new, *old = *vc->uni_pagedict_loc; new = kzalloc(sizeof(*new), GFP_KERNEL); if (!new) return -ENOMEM; new->refcount = 1; - *vc->vc_uni_pagedir_loc = new; + *vc->uni_pagedict_loc = new; if (old) old->refcount--; @@ -549,7 +549,7 @@ static int con_allocate_new(struct vc_data *vc) /* Caller must hold the lock */ static int con_do_clear_unimap(struct vc_data *vc) { - struct uni_pagedict *old = *vc->vc_uni_pagedir_loc; + struct uni_pagedict *old = *vc->uni_pagedict_loc; if (!old || old->refcount > 1) return con_allocate_new(vc); @@ -583,7 +583,7 @@ static struct uni_pagedict *con_unshare_unimap(struct vc_data *vc, if (ret) return ERR_PTR(ret); - new = *vc->vc_uni_pagedir_loc; + new = *vc->uni_pagedict_loc; /* * uni_pgdir is a 32*32*64 table with rows allocated when its first @@ -616,7 +616,7 @@ static struct uni_pagedict *con_unshare_unimap(struct vc_data *vc, ret = con_insert_unipair(new, uni, row[g]); if (ret) { old->refcount++; - *vc->vc_uni_pagedir_loc = old; + *vc->uni_pagedict_loc = old; con_release_unimap(new); kfree(new); return ERR_PTR(ret); @@ -644,7 +644,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) console_lock(); /* Save original vc_unipagdir_loc in case we allocate a new one */ - dict = *vc->vc_uni_pagedir_loc; + dict = *vc->uni_pagedict_loc; if (!dict) { err = -EINVAL; goto out_unlock; @@ -704,12 +704,12 @@ int con_set_default_unimap(struct vc_data *vc) u16 *dfont; if (dflt) { - dict = *vc->vc_uni_pagedir_loc; + dict = *vc->uni_pagedict_loc; if (dict == dflt) return 0; dflt->refcount++; - *vc->vc_uni_pagedir_loc = dflt; + *vc->uni_pagedict_loc = dflt; if (dict && !--dict->refcount) { con_release_unimap(dict); kfree(dict); @@ -723,7 +723,7 @@ int con_set_default_unimap(struct vc_data *vc) if (err) return err; - dict = *vc->vc_uni_pagedir_loc; + dict = *vc->uni_pagedict_loc; dfont = dfont_unitable; for (fontpos = 0; fontpos < 256U; fontpos++) @@ -734,7 +734,7 @@ int con_set_default_unimap(struct vc_data *vc) } if (con_unify_unimap(vc, dict)) { - dflt = *vc->vc_uni_pagedir_loc; + dflt = *vc->uni_pagedict_loc; return err; } @@ -757,14 +757,14 @@ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc) { struct uni_pagedict *src; - if (!*src_vc->vc_uni_pagedir_loc) + if (!*src_vc->uni_pagedict_loc) return -EINVAL; - if (*dst_vc->vc_uni_pagedir_loc == *src_vc->vc_uni_pagedir_loc) + if (*dst_vc->uni_pagedict_loc == *src_vc->uni_pagedict_loc) return 0; con_free_unimap(dst_vc); - src = *src_vc->vc_uni_pagedir_loc; + src = *src_vc->uni_pagedict_loc; src->refcount++; - *dst_vc->vc_uni_pagedir_loc = src; + *dst_vc->uni_pagedict_loc = src; return 0; } EXPORT_SYMBOL(con_copy_unimap); @@ -791,7 +791,7 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, console_lock(); ect = 0; - dict = *vc->vc_uni_pagedir_loc; + dict = *vc->uni_pagedict_loc; if (!dict) goto unlock; @@ -873,7 +873,7 @@ int conv_uni_to_pc(struct vc_data *conp, long ucs) else if ((ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE) return ucs & UNI_DIRECT_MASK; - dict = *conp->vc_uni_pagedir_loc; + dict = *conp->uni_pagedict_loc; if (!dict) return -3; @@ -903,7 +903,7 @@ console_map_init(void) int i; for (i = 0; i < MAX_NR_CONSOLES; i++) - if (vc_cons_allocated(i) && !*vc_cons[i].d->vc_uni_pagedir_loc) + if (vc_cons_allocated(i) && !*vc_cons[i].d->uni_pagedict_loc) con_set_default_unimap(vc_cons[i].d); } diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index c718b0d01e3d..1899b8a5d73e 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1063,10 +1063,10 @@ static void visual_init(struct vc_data *vc, int num, int init) __module_get(vc->vc_sw->owner); vc->vc_num = num; vc->vc_display_fg = &master_display_fg; - if (vc->vc_uni_pagedir_loc) + if (vc->uni_pagedict_loc) con_free_unimap(vc); - vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir; - vc->vc_uni_pagedir = NULL; + vc->uni_pagedict_loc = &vc->uni_pagedict; + vc->uni_pagedict = NULL; vc->vc_hi_font_mask = 0; vc->vc_complement_mask = 0; vc->vc_can_do_color = 0; @@ -1136,7 +1136,7 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */ visual_init(vc, currcons, 1); - if (!*vc->vc_uni_pagedir_loc) + if (!*vc->uni_pagedict_loc) con_set_default_unimap(vc); err = -EINVAL; diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index dfa0d5ce6012..fcb95fb639e0 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -248,7 +248,7 @@ sisusbcon_init(struct vc_data *c, int init) */ kref_get(&sisusb->kref); - if (!*c->vc_uni_pagedir_loc) + if (!*c->uni_pagedict_loc) con_set_default_unimap(c); mutex_unlock(&sisusb->lock); diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 058a78b8dbcf..fcdf017e2665 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -367,10 +367,10 @@ static void vgacon_init(struct vc_data *c, int init) c->vc_complement_mask = 0x7700; if (vga_512_chars) c->vc_hi_font_mask = 0x0800; - p = *c->vc_uni_pagedir_loc; - if (c->vc_uni_pagedir_loc != &vgacon_uni_pagedir) { + p = *c->uni_pagedict_loc; + if (c->uni_pagedict_loc != &vgacon_uni_pagedir) { con_free_unimap(c); - c->vc_uni_pagedir_loc = &vgacon_uni_pagedir; + c->uni_pagedict_loc = &vgacon_uni_pagedir; vgacon_refcount++; } if (!vgacon_uni_pagedir && p) @@ -392,7 +392,7 @@ static void vgacon_deinit(struct vc_data *c) if (!--vgacon_refcount) con_free_unimap(c); - c->vc_uni_pagedir_loc = &c->vc_uni_pagedir; + c->uni_pagedict_loc = &c->uni_pagedict; con_set_default_unimap(c); } diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index c4e91715ef00..b10236fe5886 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -1058,9 +1058,9 @@ static void fbcon_init(struct vc_data *vc, int init) vc->vc_complement_mask <<= 1; } - if (!*svc->vc_uni_pagedir_loc) + if (!*svc->uni_pagedict_loc) con_set_default_unimap(svc); - if (!*vc->vc_uni_pagedir_loc) + if (!*vc->uni_pagedict_loc) con_copy_unimap(vc, svc); ops = info->fbcon_par; @@ -1382,9 +1382,9 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, vc->vc_complement_mask <<= 1; } - if (!*svc->vc_uni_pagedir_loc) + if (!*svc->uni_pagedict_loc) con_set_default_unimap(svc); - if (!*vc->vc_uni_pagedir_loc) + if (!*vc->uni_pagedict_loc) con_copy_unimap(vc, svc); cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h index f75033f0277f..1518568aaf0f 100644 --- a/include/linux/console_struct.h +++ b/include/linux/console_struct.h @@ -157,8 +157,8 @@ struct vc_data { unsigned int vc_bell_duration; /* Console bell duration */ unsigned short vc_cur_blink_ms; /* Cursor blink duration */ struct vc_data **vc_display_fg; /* [!] Ptr to var holding fg console for this display */ - struct uni_pagedict *vc_uni_pagedir; - struct uni_pagedict **vc_uni_pagedir_loc; /* [!] Location of uni_pagedict variable for this console */ + struct uni_pagedict *uni_pagedict; + struct uni_pagedict **uni_pagedict_loc; /* [!] Location of uni_pagedict variable for this console */ struct uni_screen *vc_uni_screen; /* unicode screen content */ /* additional information is in vt_kern.h */ }; -- cgit v1.2.3 From 1c2f6294a3613b84fc20d6620da078dedbb2ac1e Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 14 Jun 2022 11:05:35 +0200 Subject: tty/vt: consolemap: improve UNI_*() macros definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use FIELD_GET() and GENMASK() helpers instead of direct shifts and ANDs. This makes the code even more obvious. I didn't know about the helpers at the time of writing the macros. Suggested-by: Ilpo Järvinen Reviewed-by: Ilpo Järvinen Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220614090537.15557-6-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 16d0d8f04f0e..9e94ec0e0f83 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -23,6 +23,8 @@ * stack overflow. */ +#include +#include #include #include #include @@ -190,10 +192,17 @@ static enum translation_map inv_translate[MAX_NR_CONSOLES]; #define UNI_DIR_ROWS 32U #define UNI_ROW_GLYPHS 64U -#define UNI_DIR(uni) ( (uni) >> 11) -#define UNI_ROW(uni) (((uni) & GENMASK(10, 6)) >> 6) -#define UNI_GLYPH(uni) ( (uni) & GENMASK( 5, 0)) -#define UNI(dir, row, glyph) (((dir) << 11) | ((row) << 6) | (glyph)) +#define UNI_DIR_BITS GENMASK(15, 11) +#define UNI_ROW_BITS GENMASK(10, 6) +#define UNI_GLYPH_BITS GENMASK( 5, 0) + +#define UNI_DIR(uni) FIELD_GET(UNI_DIR_BITS, (uni)) +#define UNI_ROW(uni) FIELD_GET(UNI_ROW_BITS, (uni)) +#define UNI_GLYPH(uni) FIELD_GET(UNI_GLYPH_BITS, (uni)) + +#define UNI(dir, row, glyph) (FIELD_PREP(UNI_DIR_BITS, (dir)) | \ + FIELD_PREP(UNI_ROW_BITS, (row)) | \ + FIELD_PREP(UNI_GLYPH_BITS, (glyph))) /** * struct uni_pagedict -- unicode directory -- cgit v1.2.3 From a666c70c0c2c63a60b5672a14b022da9376cffb9 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 14 Jun 2022 11:05:36 +0200 Subject: tty/vt: consolemap: remove dflt reset from con_do_clear_unimap() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit con_do_clear_unimap() sets dflt to NULL and then calls con_release_unimap() which does the very same as the first thing. So remove the former as it is apparently superfluous. Suggested-by: Ilpo Järvinen Reviewed-by: Ilpo Järvinen Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220614090537.15557-7-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 9e94ec0e0f83..5f3e58165b98 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -563,8 +563,6 @@ static int con_do_clear_unimap(struct vc_data *vc) if (!old || old->refcount > 1) return con_allocate_new(vc); - if (old == dflt) - dflt = NULL; old->sum = 0; con_release_unimap(old); -- cgit v1.2.3 From 2a9c56cceec04c50490befd5662423e3bb8c476f Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 14 Jun 2022 11:05:37 +0200 Subject: tty/vt: consolemap: use E_TABSZ for the translations size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code expects "translations" to have 256 (E_TABSZ) values. Use the macro instead of the constant to be explicit about this. Suggested-by: Ilpo Järvinen Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220614090537.15557-8-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 5f3e58165b98..f02d21e2a96e 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -38,7 +38,7 @@ #include #include -static unsigned short translations[][256] = { +static unsigned short translations[][E_TABSZ] = { /* 8-bit Latin-1 mapped to Unicode -- trivial mapping */ [LAT1_MAP] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, -- cgit v1.2.3 From 2069cb2e1f3ed2d97e8b6fe818982432de7f4e69 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 11 Jun 2022 10:42:06 +0200 Subject: serial: sifive: Remove useless license text when SPDX-License-Identifier is already used An SPDX-License-Identifier is already in place. There is no need to duplicate part of the corresponding license. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/dbc54eff6f4e077d9126054f395d5bc5b3405917.1654936915.git.christophe.jaillet@wanadoo.fr Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sifive.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c index c0869b080cc3..5c3a07546a58 100644 --- a/drivers/tty/serial/sifive.c +++ b/drivers/tty/serial/sifive.c @@ -4,16 +4,6 @@ * Copyright (C) 2018 Paul Walmsley * Copyright (C) 2018-2019 SiFive * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * * Based partially on: * - drivers/tty/serial/pxa.c * - drivers/tty/serial/amba-pl011.c -- cgit v1.2.3 From 5db6db08c6de4f95865c16a5f5b46726da295809 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 13 Jun 2022 10:57:35 +0300 Subject: serial: 8250: Use UART_LCR_WLEN8 instead of literal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use UART_LCR_WLEN8 instead of literal 0x03 in size_fifo(). Reviewed-by: Jiri Slaby Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220613075736.12283-1-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 3e3d784aa628..3a8747ec672b 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -843,7 +843,7 @@ static int size_fifo(struct uart_8250_port *up) serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); old_dl = serial_dl_read(up); serial_dl_write(up, 0x0001); - serial_out(up, UART_LCR, 0x03); + serial_out(up, UART_LCR, UART_LCR_WLEN8); for (count = 0; count < 256; count++) serial_out(up, UART_TX, count); mdelay(20);/* FIXME - schedule_timeout */ -- cgit v1.2.3 From d4b06172861bfcb390fc196bf616f60e95665e7d Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 13 Jun 2022 10:57:36 +0300 Subject: serial: 8250_pericom: Use UART_LCR_DLAB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use UART_LCR_DLAB instead of literal. Reviewed-by: Jiri Slaby Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220613075736.12283-2-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pericom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_pericom.c b/drivers/tty/serial/8250/8250_pericom.c index 95ff10f25d58..b8d5b7714a9d 100644 --- a/drivers/tty/serial/8250/8250_pericom.c +++ b/drivers/tty/serial/8250/8250_pericom.c @@ -73,7 +73,7 @@ static void pericom_do_set_divisor(struct uart_port *port, unsigned int baud, struct uart_8250_port *up = up_to_u8250p(port); int lcr = serial_port_in(port, UART_LCR); - serial_port_out(port, UART_LCR, lcr | 0x80); + serial_port_out(port, UART_LCR, lcr | UART_LCR_DLAB); serial_dl_write(up, divisor); serial_port_out(port, 2, 16 - scr); serial_port_out(port, UART_LCR, lcr); -- cgit v1.2.3 From f9008285bb69e4713918a665250ab2d356b731ba Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 13 Jun 2022 14:39:05 +0300 Subject: serial: Drop timeout from uart_port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 31f6bd7fad3b ("serial: Store character timing information to uart_port"), per frame timing information is available on uart_port. Uart port's timeout can be derived from frame_time by multiplying with fifosize. Most callers of uart_poll_timeout are not made under port's lock. To be on the safe side, make sure frame_time is only accessed once. As fifo_size is effectively a constant, it shouldn't cause any issues. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220613113905.22962-1-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/serial/driver.rst | 5 +++-- drivers/tty/serial/mux.c | 6 ------ drivers/tty/serial/serial_core.c | 25 ++++++++++--------------- include/linux/serial_core.h | 16 ++++++++++++++-- 4 files changed, 27 insertions(+), 25 deletions(-) (limited to 'drivers/tty') diff --git a/Documentation/driver-api/serial/driver.rst b/Documentation/driver-api/serial/driver.rst index 7ef83fd3917b..1e7ab4142d49 100644 --- a/Documentation/driver-api/serial/driver.rst +++ b/Documentation/driver-api/serial/driver.rst @@ -422,8 +422,9 @@ Other functions --------------- uart_update_timeout(port,cflag,baud) - Update the FIFO drain timeout, port->timeout, according to the - number of bits, parity, stop bits and baud rate. + Update the frame timing information according to the number of bits, + parity, stop bits and baud rate. The FIFO drain timeout is derived + from the frame timing information. Locking: caller is expected to take port->lock diff --git a/drivers/tty/serial/mux.c b/drivers/tty/serial/mux.c index 643dfbcc43f9..0ba0f4d9459d 100644 --- a/drivers/tty/serial/mux.c +++ b/drivers/tty/serial/mux.c @@ -481,12 +481,6 @@ static int __init mux_probe(struct parisc_device *dev) port->line = port_cnt; port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_MUX_CONSOLE); - /* The port->timeout needs to match what is present in - * uart_wait_until_sent in serial_core.c. Otherwise - * the time spent in msleep_interruptable will be very - * long, causing the appearance of a console hang. - */ - port->timeout = HZ / 50; spin_lock_init(&port->lock); status = uart_add_one_port(&mux_driver, port); diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 1368b0ef7d7f..75ece750bedc 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -327,13 +327,14 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) } /** - * uart_update_timeout - update per-port FIFO timeout. + * uart_update_timeout - update per-port frame timing information. * @port: uart_port structure describing the port * @cflag: termios cflag value * @baud: speed of the port * - * Set the port FIFO timeout value. The @cflag value should - * reflect the actual hardware settings. + * Set the port frame timing information from which the FIFO timeout + * value is derived. The @cflag value should reflect the actual hardware + * settings. */ void uart_update_timeout(struct uart_port *port, unsigned int cflag, @@ -343,13 +344,6 @@ uart_update_timeout(struct uart_port *port, unsigned int cflag, u64 frame_time; frame_time = (u64)size * NSEC_PER_SEC; - size *= port->fifosize; - - /* - * Figure the timeout to send the above number of bits. - * Add .02 seconds of slop - */ - port->timeout = (HZ * size) / baud + HZ/50; port->frame_time = DIV64_U64_ROUND_UP(frame_time, baud); } EXPORT_SYMBOL(uart_update_timeout); @@ -1698,7 +1692,7 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout) { struct uart_state *state = tty->driver_data; struct uart_port *port; - unsigned long char_time, expire; + unsigned long char_time, expire, fifo_timeout; port = uart_port_ref(state); if (!port) @@ -1728,12 +1722,13 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout) * amount of time to send the entire FIFO, it probably won't * ever clear. This assumes the UART isn't doing flow * control, which is currently the case. Hence, if it ever - * takes longer than port->timeout, this is probably due to a + * takes longer than FIFO timeout, this is probably due to a * UART bug of some kind. So, we clamp the timeout parameter at - * 2*port->timeout. + * 2 * FIFO timeout. */ - if (timeout == 0 || timeout > 2 * port->timeout) - timeout = 2 * port->timeout; + fifo_timeout = uart_fifo_timeout(port); + if (timeout == 0 || timeout > 2 * fifo_timeout) + timeout = 2 * fifo_timeout; } expire = jiffies + timeout; diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 8032ffa741ed..faaf2372c60d 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -232,7 +232,6 @@ struct uart_port { int hw_stopped; /* sw-assisted CTS flow state */ unsigned int mctrl; /* current modem ctrl settings */ - unsigned int timeout; /* character-based timeout */ unsigned int frame_time; /* frame timing in ns */ unsigned int type; /* port type */ const struct uart_ops *ops; @@ -335,10 +334,23 @@ unsigned int uart_get_baud_rate(struct uart_port *port, struct ktermios *termios unsigned int max); unsigned int uart_get_divisor(struct uart_port *port, unsigned int baud); +/* + * Calculates FIFO drain time. + */ +static inline unsigned long uart_fifo_timeout(struct uart_port *port) +{ + u64 fifo_timeout = (u64)READ_ONCE(port->frame_time) * port->fifosize; + + /* Add .02 seconds of slop */ + fifo_timeout += 20 * NSEC_PER_MSEC; + + return max(nsecs_to_jiffies(fifo_timeout), 1UL); +} + /* Base timer interval for polling */ static inline int uart_poll_timeout(struct uart_port *port) { - int timeout = port->timeout; + int timeout = uart_fifo_timeout(port); return timeout > 6 ? (timeout / 2 - 2) : 1; } -- cgit v1.2.3 From eb01611056cf835cf2c1cc1a800bfff9386c82ea Mon Sep 17 00:00:00 2001 From: Liang He Date: Wed, 15 Jun 2022 19:17:47 +0800 Subject: drivers: tty: serial: Add missing of_node_put() in serial-tegra.c In tegra_uart_init(), of_find_matching_node() will return a node pointer with refcount incremented. We should use of_node_put() when it is not used anymore. Signed-off-by: Liang He Link: https://lore.kernel.org/r/20220615111747.3963930-1-windhl@126.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial-tegra.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c index 101fb585e6f9..ad4f3567ff90 100644 --- a/drivers/tty/serial/serial-tegra.c +++ b/drivers/tty/serial/serial-tegra.c @@ -1667,6 +1667,7 @@ static int __init tegra_uart_init(void) node = of_find_matching_node(NULL, tegra_uart_of_match); if (node) match = of_match_node(tegra_uart_of_match, node); + of_node_put(node); if (match) cdata = match->data; if (cdata) -- cgit v1.2.3 From d24d7bb2cd947676f9b71fb944d045e09b8b282f Mon Sep 17 00:00:00 2001 From: Liang He Date: Sat, 18 Jun 2022 14:08:50 +0800 Subject: tty: serial: Fix refcount leak bug in ucc_uart.c In soc_info(), of_find_node_by_type() will return a node pointer with refcount incremented. We should use of_node_put() when it is not used anymore. Acked-by: Timur Tabi Signed-off-by: Liang He Link: https://lore.kernel.org/r/20220618060850.4058525-1-windhl@126.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/ucc_uart.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c index 6000853973c1..3cc9ef08455c 100644 --- a/drivers/tty/serial/ucc_uart.c +++ b/drivers/tty/serial/ucc_uart.c @@ -1137,6 +1137,8 @@ static unsigned int soc_info(unsigned int *rev_h, unsigned int *rev_l) /* No compatible property, so try the name. */ soc_string = np->name; + of_node_put(np); + /* Extract the SOC number from the "PowerPC," string */ if ((sscanf(soc_string, "PowerPC,%u", &soc) != 1) || !soc) return 0; -- cgit v1.2.3 From ab8ba6c59d5ab4f894cd731c0b05825576d15ed1 Mon Sep 17 00:00:00 2001 From: Xiang wangx Date: Mon, 20 Jun 2022 18:46:53 +0800 Subject: serial: kgdboc: Fix typo in comment Delete the redundant word 'the'. Signed-off-by: Xiang wangx Link: https://lore.kernel.org/r/20220620104653.5451-1-wangxiang@cdjrlc.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/kgdboc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c index 79b7db8580e0..7aa37be3216a 100644 --- a/drivers/tty/serial/kgdboc.c +++ b/drivers/tty/serial/kgdboc.c @@ -342,7 +342,7 @@ static int param_set_kgdboc_var(const char *kmessage, /* * Configure with the new params as long as init already ran. * Note that we can get called before init if someone loads us - * with "modprobe kgdboc kgdboc=..." or if they happen to use the + * with "modprobe kgdboc kgdboc=..." or if they happen to use * the odd syntax of "kgdboc.kgdboc=..." on the kernel command. */ if (configured >= 0) -- cgit v1.2.3 From b50058b82e0a0ea2cb11889c261cb7d587b62e1c Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 16 Jun 2022 17:00:21 +0300 Subject: tty: serial: atmel: stop using legacy pm ops Stop using legacy PM ops and switch using dev_pm_ops. Along with it #ifdef CONFIG_PM are removed and __maybe_unused and pm_ptr() used instead. Coding style recommends (at chapter Conditional Compilation) to avoid using preprocessor conditional and use __maybe_unused instead. Acked-by: Richard Genoud Signed-off-by: Claudiu Beznea Link: https://lore.kernel.org/r/20220616140024.2081238-2-claudiu.beznea@microchip.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 74dd1d3ac46f..c618d7e93058 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -166,7 +166,6 @@ struct atmel_uart_port { unsigned int fidi_min; unsigned int fidi_max; -#ifdef CONFIG_PM struct { u32 cr; u32 mr; @@ -177,7 +176,6 @@ struct atmel_uart_port { u32 fmr; u32 fimr; } cache; -#endif int (*prepare_rx)(struct uart_port *port); int (*prepare_tx)(struct uart_port *port); @@ -2718,7 +2716,6 @@ static struct uart_driver atmel_uart = { .cons = ATMEL_CONSOLE_DEVICE, }; -#ifdef CONFIG_PM static bool atmel_serial_clk_will_stop(void) { #ifdef CONFIG_ARCH_AT91 @@ -2728,10 +2725,9 @@ static bool atmel_serial_clk_will_stop(void) #endif } -static int atmel_serial_suspend(struct platform_device *pdev, - pm_message_t state) +static int __maybe_unused atmel_serial_suspend(struct device *dev) { - struct uart_port *port = platform_get_drvdata(pdev); + struct uart_port *port = dev_get_drvdata(dev); struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); if (uart_console(port) && console_suspend_enabled) { @@ -2756,14 +2752,14 @@ static int atmel_serial_suspend(struct platform_device *pdev, } /* we can not wake up if we're running on slow clock */ - atmel_port->may_wakeup = device_may_wakeup(&pdev->dev); + atmel_port->may_wakeup = device_may_wakeup(dev); if (atmel_serial_clk_will_stop()) { unsigned long flags; spin_lock_irqsave(&atmel_port->lock_suspended, flags); atmel_port->suspended = true; spin_unlock_irqrestore(&atmel_port->lock_suspended, flags); - device_set_wakeup_enable(&pdev->dev, 0); + device_set_wakeup_enable(dev, 0); } uart_suspend_port(&atmel_uart, port); @@ -2771,9 +2767,9 @@ static int atmel_serial_suspend(struct platform_device *pdev, return 0; } -static int atmel_serial_resume(struct platform_device *pdev) +static int __maybe_unused atmel_serial_resume(struct device *dev) { - struct uart_port *port = platform_get_drvdata(pdev); + struct uart_port *port = dev_get_drvdata(dev); struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); unsigned long flags; @@ -2808,14 +2804,10 @@ static int atmel_serial_resume(struct platform_device *pdev) spin_unlock_irqrestore(&atmel_port->lock_suspended, flags); uart_resume_port(&atmel_uart, port); - device_set_wakeup_enable(&pdev->dev, atmel_port->may_wakeup); + device_set_wakeup_enable(dev, atmel_port->may_wakeup); return 0; } -#else -#define atmel_serial_suspend NULL -#define atmel_serial_resume NULL -#endif static void atmel_serial_probe_fifos(struct atmel_uart_port *atmel_port, struct platform_device *pdev) @@ -3019,14 +3011,16 @@ static int atmel_serial_remove(struct platform_device *pdev) return ret; } +static SIMPLE_DEV_PM_OPS(atmel_serial_pm_ops, atmel_serial_suspend, + atmel_serial_resume); + static struct platform_driver atmel_serial_driver = { .probe = atmel_serial_probe, .remove = atmel_serial_remove, - .suspend = atmel_serial_suspend, - .resume = atmel_serial_resume, .driver = { .name = "atmel_usart_serial", .of_match_table = of_match_ptr(atmel_serial_dt_ids), + .pm = pm_ptr(&atmel_serial_pm_ops), }, }; -- cgit v1.2.3 From 84b476b124d4581d0c18e2e39e14fca52feedffd Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 16 Jun 2022 17:00:22 +0300 Subject: tty: serial: atmel: use devm_clk_get() Use devm_clk_get() for serial clock instead of clk_get()/clk_put(). With this move the clk_get in driver's probe function. Acked-by: Richard Genoud Signed-off-by: Claudiu Beznea Link: https://lore.kernel.org/r/20220616140024.2081238-3-claudiu.beznea@microchip.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 50 ++++++++++++--------------------------- 1 file changed, 15 insertions(+), 35 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index c618d7e93058..4cec97fd7241 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -2508,24 +2508,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port, if (ret) return ret; - /* for console, the clock could already be configured */ - if (!atmel_port->clk) { - atmel_port->clk = clk_get(&mpdev->dev, "usart"); - if (IS_ERR(atmel_port->clk)) { - ret = PTR_ERR(atmel_port->clk); - atmel_port->clk = NULL; - return ret; - } - ret = clk_prepare_enable(atmel_port->clk); - if (ret) { - clk_put(atmel_port->clk); - atmel_port->clk = NULL; - return ret; - } - port->uartclk = clk_get_rate(atmel_port->clk); - clk_disable_unprepare(atmel_port->clk); - /* only enable clock when USART is in use */ - } + port->uartclk = clk_get_rate(atmel_port->clk); /* * Use TXEMPTY for interrupt when rs485 or ISO7816 else TXRDY or @@ -2896,14 +2879,23 @@ static int atmel_serial_probe(struct platform_device *pdev) atomic_set(&atmel_port->tasklet_shutdown, 0); spin_lock_init(&atmel_port->lock_suspended); + atmel_port->clk = devm_clk_get(&pdev->dev, "usart"); + if (IS_ERR(atmel_port->clk)) { + ret = PTR_ERR(atmel_port->clk); + goto err; + } + ret = clk_prepare_enable(atmel_port->clk); + if (ret) + goto err; + ret = atmel_init_port(atmel_port, pdev); if (ret) - goto err_clear_bit; + goto err_clk_disable_unprepare; atmel_port->gpios = mctrl_gpio_init(&atmel_port->uart, 0); if (IS_ERR(atmel_port->gpios)) { ret = PTR_ERR(atmel_port->gpios); - goto err_clear_bit; + goto err_clk_disable_unprepare; } if (!atmel_use_pdc_rx(&atmel_port->uart)) { @@ -2912,7 +2904,7 @@ static int atmel_serial_probe(struct platform_device *pdev) sizeof(struct atmel_uart_char), GFP_KERNEL); if (!data) - goto err_alloc_ring; + goto err_clk_disable_unprepare; atmel_port->rx_ring.buf = data; } @@ -2936,12 +2928,6 @@ static int atmel_serial_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 1); platform_set_drvdata(pdev, atmel_port); - /* - * The peripheral clock has been disabled by atmel_init_port(): - * enable it before accessing I/O registers - */ - clk_prepare_enable(atmel_port->clk); - if (rs485_enabled) { atmel_uart_writel(&atmel_port->uart, ATMEL_US_MR, ATMEL_US_USMODE_NORMAL); @@ -2965,12 +2951,8 @@ static int atmel_serial_probe(struct platform_device *pdev) err_add_port: kfree(atmel_port->rx_ring.buf); atmel_port->rx_ring.buf = NULL; -err_alloc_ring: - if (!uart_console(&atmel_port->uart)) { - clk_put(atmel_port->clk); - atmel_port->clk = NULL; - } -err_clear_bit: +err_clk_disable_unprepare: + clk_disable_unprepare(atmel_port->clk); clear_bit(atmel_port->uart.line, atmel_ports_in_use); err: return ret; @@ -3004,8 +2986,6 @@ static int atmel_serial_remove(struct platform_device *pdev) clear_bit(port->line, atmel_ports_in_use); - clk_put(atmel_port->clk); - atmel_port->clk = NULL; pdev->dev.of_node = NULL; return ret; -- cgit v1.2.3 From 61dbc75ce00f4e27da61683d23cb4f9f3ef3f944 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 16 Jun 2022 17:00:23 +0300 Subject: tty: serial: atmel: remove enable/disable clock due to atmel_console_setup() There is no need for clk_prepare_enable() at the beginning of atmel_console_setup() and clk_disable_unprepare() at the end of atmel_console_setup() as the clock is already enabled when calling atmel_console_setup() and its disablement is done at the end of probe. Acked-by: Richard Genoud Signed-off-by: Claudiu Beznea Link: https://lore.kernel.org/r/20220616140024.2081238-4-claudiu.beznea@microchip.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 16 ---------------- 1 file changed, 16 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 4cec97fd7241..3a94c2bdda72 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -2617,7 +2617,6 @@ static void __init atmel_console_get_options(struct uart_port *port, int *baud, static int __init atmel_console_setup(struct console *co, char *options) { - int ret; struct uart_port *port = &atmel_ports[co->index].uart; struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); int baud = 115200; @@ -2630,10 +2629,6 @@ static int __init atmel_console_setup(struct console *co, char *options) return -ENODEV; } - ret = clk_prepare_enable(atmel_ports[co->index].clk); - if (ret) - return ret; - atmel_uart_writel(port, ATMEL_US_IDR, -1); atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN); @@ -2914,17 +2909,6 @@ static int atmel_serial_probe(struct platform_device *pdev) if (ret) goto err_add_port; -#ifdef CONFIG_SERIAL_ATMEL_CONSOLE - if (uart_console(&atmel_port->uart) - && ATMEL_CONSOLE_DEVICE->flags & CON_ENABLED) { - /* - * The serial core enabled the clock for us, so undo - * the clk_prepare_enable() in atmel_console_setup() - */ - clk_disable_unprepare(atmel_port->clk); - } -#endif - device_init_wakeup(&pdev->dev, 1); platform_set_drvdata(pdev, atmel_port); -- cgit v1.2.3 From df5dac860111aa9cfab61521494d25825446cfcc Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 16 Jun 2022 17:00:24 +0300 Subject: serial: st-asc: remove include of pm_runtime.h st-asc driver doesn't use helpers from pm_runtime.h thus remove its include. Reviewed-by: Patrice Chotard Signed-off-by: Claudiu Beznea Link: https://lore.kernel.org/r/20220616140024.2081238-5-claudiu.beznea@microchip.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/st-asc.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c index 1b0da603ab54..cce42f4c9bc2 100644 --- a/drivers/tty/serial/st-asc.c +++ b/drivers/tty/serial/st-asc.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From 24b5596a858d1b27e63b4f7f894403f0f3dc31c3 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Fri, 24 Jun 2022 23:54:19 +0300 Subject: serial: msm: Convert container_of UART_TO_MSM to static inline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create static inline instead of define as it provides type safety and is safer wrt. macros expansion. Reviewed-by: Jiri Slaby Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220624205424.12686-2-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/msm_serial.c | 49 ++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 23 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index e676ec761f18..15cab9c4b295 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -181,7 +181,10 @@ struct msm_port { struct msm_dma rx_dma; }; -#define UART_TO_MSM(uart_port) container_of(uart_port, struct msm_port, uart) +static inline struct msm_port *to_msm_port(struct uart_port *up) +{ + return container_of(up, struct msm_port, uart); +} static void msm_write(struct uart_port *port, unsigned int val, unsigned int off) @@ -221,7 +224,7 @@ static void msm_serial_set_mnd_regs_tcxoby4(struct uart_port *port) static void msm_serial_set_mnd_regs(struct uart_port *port) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); /* * These registers don't exist so we change the clk input rate @@ -404,7 +407,7 @@ static inline void msm_wait_for_xmitr(struct uart_port *port) static void msm_stop_tx(struct uart_port *port) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); msm_port->imr &= ~UART_IMR_TXLEV; msm_write(port, msm_port->imr, UART_IMR); @@ -412,7 +415,7 @@ static void msm_stop_tx(struct uart_port *port) static void msm_start_tx(struct uart_port *port) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); struct msm_dma *dma = &msm_port->tx_dma; /* Already started in DMA mode */ @@ -690,7 +693,7 @@ sw_mode: static void msm_stop_rx(struct uart_port *port) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); struct msm_dma *dma = &msm_port->rx_dma; msm_port->imr &= ~(UART_IMR_RXLEV | UART_IMR_RXSTALE); @@ -702,7 +705,7 @@ static void msm_stop_rx(struct uart_port *port) static void msm_enable_ms(struct uart_port *port) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); msm_port->imr |= UART_IMR_DELTA_CTS; msm_write(port, msm_port->imr, UART_IMR); @@ -714,7 +717,7 @@ static void msm_handle_rx_dm(struct uart_port *port, unsigned int misr) struct tty_port *tport = &port->state->port; unsigned int sr; int count = 0; - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) { port->icount.overrun++; @@ -837,7 +840,7 @@ static void msm_handle_rx(struct uart_port *port) static void msm_handle_tx_pio(struct uart_port *port, unsigned int tx_count) { struct circ_buf *xmit = &port->state->xmit; - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); unsigned int num_chars; unsigned int tf_pointer = 0; void __iomem *tf; @@ -883,7 +886,7 @@ static void msm_handle_tx_pio(struct uart_port *port, unsigned int tx_count) static void msm_handle_tx(struct uart_port *port) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); struct circ_buf *xmit = &msm_port->uart.state->xmit; struct msm_dma *dma = &msm_port->tx_dma; unsigned int pio_count, dma_count, dma_min; @@ -947,7 +950,7 @@ static void msm_handle_delta_cts(struct uart_port *port) static irqreturn_t msm_uart_irq(int irq, void *dev_id) { struct uart_port *port = dev_id; - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); struct msm_dma *dma = &msm_port->rx_dma; unsigned long flags; unsigned int misr; @@ -1002,7 +1005,7 @@ static unsigned int msm_get_mctrl(struct uart_port *port) static void msm_reset(struct uart_port *port) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); unsigned int mr; /* reset everything */ @@ -1055,7 +1058,7 @@ static const struct msm_baud_map * msm_find_best_baud(struct uart_port *port, unsigned int baud, unsigned long *rate) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); unsigned int divisor, result; unsigned long target, old, best_rate = 0, diff, best_diff = ULONG_MAX; const struct msm_baud_map *entry, *end, *best; @@ -1124,7 +1127,7 @@ static int msm_set_baud_rate(struct uart_port *port, unsigned int baud, unsigned long *saved_flags) { unsigned int rxstale, watermark, mask; - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); const struct msm_baud_map *entry; unsigned long flags, rate; @@ -1185,7 +1188,7 @@ static int msm_set_baud_rate(struct uart_port *port, unsigned int baud, static void msm_init_clock(struct uart_port *port) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); clk_prepare_enable(msm_port->clk); clk_prepare_enable(msm_port->pclk); @@ -1194,7 +1197,7 @@ static void msm_init_clock(struct uart_port *port) static int msm_startup(struct uart_port *port) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); unsigned int data, rfr_level, mask; int ret; @@ -1246,7 +1249,7 @@ err_irq: static void msm_shutdown(struct uart_port *port) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); msm_port->imr = 0; msm_write(port, 0, UART_IMR); /* disable interrupts */ @@ -1262,7 +1265,7 @@ static void msm_shutdown(struct uart_port *port) static void msm_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); struct msm_dma *dma = &msm_port->rx_dma; unsigned long flags; unsigned int baud, mr; @@ -1416,7 +1419,7 @@ static int msm_verify_port(struct uart_port *port, struct serial_struct *ser) static void msm_power(struct uart_port *port, unsigned int state, unsigned int oldstate) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); switch (state) { case 0: @@ -1435,7 +1438,7 @@ static void msm_power(struct uart_port *port, unsigned int state, #ifdef CONFIG_CONSOLE_POLL static int msm_poll_get_char_single(struct uart_port *port) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); unsigned int rf_reg = msm_port->is_uartdm ? UARTDM_RF : UART_RF; if (!(msm_read(port, UART_SR) & UART_SR_RX_READY)) @@ -1489,7 +1492,7 @@ static int msm_poll_get_char(struct uart_port *port) { u32 imr; int c; - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); /* Disable all interrupts */ imr = msm_read(port, UART_IMR); @@ -1509,7 +1512,7 @@ static int msm_poll_get_char(struct uart_port *port) static void msm_poll_put_char(struct uart_port *port, unsigned char c) { u32 imr; - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); /* Disable all interrupts */ imr = msm_read(port, UART_IMR); @@ -1677,7 +1680,7 @@ static void msm_console_write(struct console *co, const char *s, BUG_ON(co->index < 0 || co->index >= UART_NR); port = msm_get_port_from_line(co->index); - msm_port = UART_TO_MSM(port); + msm_port = to_msm_port(port); __msm_console_write(port, s, count, msm_port->is_uartdm); } @@ -1808,7 +1811,7 @@ static int msm_serial_probe(struct platform_device *pdev) port = msm_get_port_from_line(line); port->dev = &pdev->dev; - msm_port = UART_TO_MSM(port); + msm_port = to_msm_port(port); id = of_match_device(msm_uartdm_table, &pdev->dev); if (id) -- cgit v1.2.3 From fddbab7b40b34d204c4dfa7c6a62e5f7c1920e98 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Fri, 24 Jun 2022 23:54:20 +0300 Subject: serial: msm: Rename UART_* defines to MSM_UART_* MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using UART_* to name defines is a bit problematic. When trying to do unrelated cleanup which also involved tweaking header inclusion logic, caused UART_CSR from serial_reg.h to leak into msm's namespace which is also among msm defines. Thus, rename all UART_* ones to MSM_UART_* to eliminate possibility of collisions. Reviewed-by: Jiri Slaby Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220624205424.12686-3-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/msm_serial.c | 501 ++++++++++++++++++++-------------------- 1 file changed, 250 insertions(+), 251 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 15cab9c4b295..3159889ddae1 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -29,103 +29,103 @@ #include #include -#define UART_MR1 0x0000 - -#define UART_MR1_AUTO_RFR_LEVEL0 0x3F -#define UART_MR1_AUTO_RFR_LEVEL1 0x3FF00 -#define UART_DM_MR1_AUTO_RFR_LEVEL1 0xFFFFFF00 -#define UART_MR1_RX_RDY_CTL BIT(7) -#define UART_MR1_CTS_CTL BIT(6) - -#define UART_MR2 0x0004 -#define UART_MR2_ERROR_MODE BIT(6) -#define UART_MR2_BITS_PER_CHAR 0x30 -#define UART_MR2_BITS_PER_CHAR_5 (0x0 << 4) -#define UART_MR2_BITS_PER_CHAR_6 (0x1 << 4) -#define UART_MR2_BITS_PER_CHAR_7 (0x2 << 4) -#define UART_MR2_BITS_PER_CHAR_8 (0x3 << 4) -#define UART_MR2_STOP_BIT_LEN_ONE (0x1 << 2) -#define UART_MR2_STOP_BIT_LEN_TWO (0x3 << 2) -#define UART_MR2_PARITY_MODE_NONE 0x0 -#define UART_MR2_PARITY_MODE_ODD 0x1 -#define UART_MR2_PARITY_MODE_EVEN 0x2 -#define UART_MR2_PARITY_MODE_SPACE 0x3 -#define UART_MR2_PARITY_MODE 0x3 - -#define UART_CSR 0x0008 - -#define UART_TF 0x000C +#define MSM_UART_MR1 0x0000 + +#define MSM_UART_MR1_AUTO_RFR_LEVEL0 0x3F +#define MSM_UART_MR1_AUTO_RFR_LEVEL1 0x3FF00 +#define MSM_UART_DM_MR1_AUTO_RFR_LEVEL1 0xFFFFFF00 +#define MSM_UART_MR1_RX_RDY_CTL BIT(7) +#define MSM_UART_MR1_CTS_CTL BIT(6) + +#define MSM_UART_MR2 0x0004 +#define MSM_UART_MR2_ERROR_MODE BIT(6) +#define MSM_UART_MR2_BITS_PER_CHAR 0x30 +#define MSM_UART_MR2_BITS_PER_CHAR_5 (0x0 << 4) +#define MSM_UART_MR2_BITS_PER_CHAR_6 (0x1 << 4) +#define MSM_UART_MR2_BITS_PER_CHAR_7 (0x2 << 4) +#define MSM_UART_MR2_BITS_PER_CHAR_8 (0x3 << 4) +#define MSM_UART_MR2_STOP_BIT_LEN_ONE (0x1 << 2) +#define MSM_UART_MR2_STOP_BIT_LEN_TWO (0x3 << 2) +#define MSM_UART_MR2_PARITY_MODE_NONE 0x0 +#define MSM_UART_MR2_PARITY_MODE_ODD 0x1 +#define MSM_UART_MR2_PARITY_MODE_EVEN 0x2 +#define MSM_UART_MR2_PARITY_MODE_SPACE 0x3 +#define MSM_UART_MR2_PARITY_MODE 0x3 + +#define MSM_UART_CSR 0x0008 + +#define MSM_UART_TF 0x000C #define UARTDM_TF 0x0070 -#define UART_CR 0x0010 -#define UART_CR_CMD_NULL (0 << 4) -#define UART_CR_CMD_RESET_RX (1 << 4) -#define UART_CR_CMD_RESET_TX (2 << 4) -#define UART_CR_CMD_RESET_ERR (3 << 4) -#define UART_CR_CMD_RESET_BREAK_INT (4 << 4) -#define UART_CR_CMD_START_BREAK (5 << 4) -#define UART_CR_CMD_STOP_BREAK (6 << 4) -#define UART_CR_CMD_RESET_CTS (7 << 4) -#define UART_CR_CMD_RESET_STALE_INT (8 << 4) -#define UART_CR_CMD_PACKET_MODE (9 << 4) -#define UART_CR_CMD_MODE_RESET (12 << 4) -#define UART_CR_CMD_SET_RFR (13 << 4) -#define UART_CR_CMD_RESET_RFR (14 << 4) -#define UART_CR_CMD_PROTECTION_EN (16 << 4) -#define UART_CR_CMD_STALE_EVENT_DISABLE (6 << 8) -#define UART_CR_CMD_STALE_EVENT_ENABLE (80 << 4) -#define UART_CR_CMD_FORCE_STALE (4 << 8) -#define UART_CR_CMD_RESET_TX_READY (3 << 8) -#define UART_CR_TX_DISABLE BIT(3) -#define UART_CR_TX_ENABLE BIT(2) -#define UART_CR_RX_DISABLE BIT(1) -#define UART_CR_RX_ENABLE BIT(0) -#define UART_CR_CMD_RESET_RXBREAK_START ((1 << 11) | (2 << 4)) - -#define UART_IMR 0x0014 -#define UART_IMR_TXLEV BIT(0) -#define UART_IMR_RXSTALE BIT(3) -#define UART_IMR_RXLEV BIT(4) -#define UART_IMR_DELTA_CTS BIT(5) -#define UART_IMR_CURRENT_CTS BIT(6) -#define UART_IMR_RXBREAK_START BIT(10) - -#define UART_IPR_RXSTALE_LAST 0x20 -#define UART_IPR_STALE_LSB 0x1F -#define UART_IPR_STALE_TIMEOUT_MSB 0x3FF80 -#define UART_DM_IPR_STALE_TIMEOUT_MSB 0xFFFFFF80 - -#define UART_IPR 0x0018 -#define UART_TFWR 0x001C -#define UART_RFWR 0x0020 -#define UART_HCR 0x0024 - -#define UART_MREG 0x0028 -#define UART_NREG 0x002C -#define UART_DREG 0x0030 -#define UART_MNDREG 0x0034 -#define UART_IRDA 0x0038 -#define UART_MISR_MODE 0x0040 -#define UART_MISR_RESET 0x0044 -#define UART_MISR_EXPORT 0x0048 -#define UART_MISR_VAL 0x004C -#define UART_TEST_CTRL 0x0050 - -#define UART_SR 0x0008 -#define UART_SR_HUNT_CHAR BIT(7) -#define UART_SR_RX_BREAK BIT(6) -#define UART_SR_PAR_FRAME_ERR BIT(5) -#define UART_SR_OVERRUN BIT(4) -#define UART_SR_TX_EMPTY BIT(3) -#define UART_SR_TX_READY BIT(2) -#define UART_SR_RX_FULL BIT(1) -#define UART_SR_RX_READY BIT(0) - -#define UART_RF 0x000C +#define MSM_UART_CR 0x0010 +#define MSM_UART_CR_CMD_NULL (0 << 4) +#define MSM_UART_CR_CMD_RESET_RX (1 << 4) +#define MSM_UART_CR_CMD_RESET_TX (2 << 4) +#define MSM_UART_CR_CMD_RESET_ERR (3 << 4) +#define MSM_UART_CR_CMD_RESET_BREAK_INT (4 << 4) +#define MSM_UART_CR_CMD_START_BREAK (5 << 4) +#define MSM_UART_CR_CMD_STOP_BREAK (6 << 4) +#define MSM_UART_CR_CMD_RESET_CTS (7 << 4) +#define MSM_UART_CR_CMD_RESET_STALE_INT (8 << 4) +#define MSM_UART_CR_CMD_PACKET_MODE (9 << 4) +#define MSM_UART_CR_CMD_MODE_RESET (12 << 4) +#define MSM_UART_CR_CMD_SET_RFR (13 << 4) +#define MSM_UART_CR_CMD_RESET_RFR (14 << 4) +#define MSM_UART_CR_CMD_PROTECTION_EN (16 << 4) +#define MSM_UART_CR_CMD_STALE_EVENT_DISABLE (6 << 8) +#define MSM_UART_CR_CMD_STALE_EVENT_ENABLE (80 << 4) +#define MSM_UART_CR_CMD_FORCE_STALE (4 << 8) +#define MSM_UART_CR_CMD_RESET_TX_READY (3 << 8) +#define MSM_UART_CR_TX_DISABLE BIT(3) +#define MSM_UART_CR_TX_ENABLE BIT(2) +#define MSM_UART_CR_RX_DISABLE BIT(1) +#define MSM_UART_CR_RX_ENABLE BIT(0) +#define MSM_UART_CR_CMD_RESET_RXBREAK_START ((1 << 11) | (2 << 4)) + +#define MSM_UART_IMR 0x0014 +#define MSM_UART_IMR_TXLEV BIT(0) +#define MSM_UART_IMR_RXSTALE BIT(3) +#define MSM_UART_IMR_RXLEV BIT(4) +#define MSM_UART_IMR_DELTA_CTS BIT(5) +#define MSM_UART_IMR_CURRENT_CTS BIT(6) +#define MSM_UART_IMR_RXBREAK_START BIT(10) + +#define MSM_UART_IPR_RXSTALE_LAST 0x20 +#define MSM_UART_IPR_STALE_LSB 0x1F +#define MSM_UART_IPR_STALE_TIMEOUT_MSB 0x3FF80 +#define MSM_UART_DM_IPR_STALE_TIMEOUT_MSB 0xFFFFFF80 + +#define MSM_UART_IPR 0x0018 +#define MSM_UART_TFWR 0x001C +#define MSM_UART_RFWR 0x0020 +#define MSM_UART_HCR 0x0024 + +#define MSM_UART_MREG 0x0028 +#define MSM_UART_NREG 0x002C +#define MSM_UART_DREG 0x0030 +#define MSM_UART_MNDREG 0x0034 +#define MSM_UART_IRDA 0x0038 +#define MSM_UART_MISR_MODE 0x0040 +#define MSM_UART_MISR_RESET 0x0044 +#define MSM_UART_MISR_EXPORT 0x0048 +#define MSM_UART_MISR_VAL 0x004C +#define MSM_UART_TEST_CTRL 0x0050 + +#define MSM_UART_SR 0x0008 +#define MSM_UART_SR_HUNT_CHAR BIT(7) +#define MSM_UART_SR_RX_BREAK BIT(6) +#define MSM_UART_SR_PAR_FRAME_ERR BIT(5) +#define MSM_UART_SR_OVERRUN BIT(4) +#define MSM_UART_SR_TX_EMPTY BIT(3) +#define MSM_UART_SR_TX_READY BIT(2) +#define MSM_UART_SR_RX_FULL BIT(1) +#define MSM_UART_SR_RX_READY BIT(0) + +#define MSM_UART_RF 0x000C #define UARTDM_RF 0x0070 -#define UART_MISR 0x0010 -#define UART_ISR 0x0014 -#define UART_ISR_TX_READY BIT(7) +#define MSM_UART_MISR 0x0010 +#define MSM_UART_ISR 0x0014 +#define MSM_UART_ISR_TX_READY BIT(7) #define UARTDM_RXFS 0x50 #define UARTDM_RXFS_BUF_SHIFT 0x7 @@ -203,10 +203,10 @@ unsigned int msm_read(struct uart_port *port, unsigned int off) */ static void msm_serial_set_mnd_regs_tcxo(struct uart_port *port) { - msm_write(port, 0x06, UART_MREG); - msm_write(port, 0xF1, UART_NREG); - msm_write(port, 0x0F, UART_DREG); - msm_write(port, 0x1A, UART_MNDREG); + msm_write(port, 0x06, MSM_UART_MREG); + msm_write(port, 0xF1, MSM_UART_NREG); + msm_write(port, 0x0F, MSM_UART_DREG); + msm_write(port, 0x1A, MSM_UART_MNDREG); port->uartclk = 1843200; } @@ -215,10 +215,10 @@ static void msm_serial_set_mnd_regs_tcxo(struct uart_port *port) */ static void msm_serial_set_mnd_regs_tcxoby4(struct uart_port *port) { - msm_write(port, 0x18, UART_MREG); - msm_write(port, 0xF6, UART_NREG); - msm_write(port, 0x0F, UART_DREG); - msm_write(port, 0x0A, UART_MNDREG); + msm_write(port, 0x18, MSM_UART_MREG); + msm_write(port, 0xF6, MSM_UART_NREG); + msm_write(port, 0x0F, MSM_UART_DREG); + msm_write(port, 0x0A, MSM_UART_MNDREG); port->uartclk = 1843200; } @@ -395,22 +395,22 @@ static inline void msm_wait_for_xmitr(struct uart_port *port) { unsigned int timeout = 500000; - while (!(msm_read(port, UART_SR) & UART_SR_TX_EMPTY)) { - if (msm_read(port, UART_ISR) & UART_ISR_TX_READY) + while (!(msm_read(port, MSM_UART_SR) & MSM_UART_SR_TX_EMPTY)) { + if (msm_read(port, MSM_UART_ISR) & MSM_UART_ISR_TX_READY) break; udelay(1); if (!timeout--) break; } - msm_write(port, UART_CR_CMD_RESET_TX_READY, UART_CR); + msm_write(port, MSM_UART_CR_CMD_RESET_TX_READY, MSM_UART_CR); } static void msm_stop_tx(struct uart_port *port) { struct msm_port *msm_port = to_msm_port(port); - msm_port->imr &= ~UART_IMR_TXLEV; - msm_write(port, msm_port->imr, UART_IMR); + msm_port->imr &= ~MSM_UART_IMR_TXLEV; + msm_write(port, msm_port->imr, MSM_UART_IMR); } static void msm_start_tx(struct uart_port *port) @@ -422,8 +422,8 @@ static void msm_start_tx(struct uart_port *port) if (dma->count) return; - msm_port->imr |= UART_IMR_TXLEV; - msm_write(port, msm_port->imr, UART_IMR); + msm_port->imr |= MSM_UART_IMR_TXLEV; + msm_write(port, msm_port->imr, MSM_UART_IMR); } static void msm_reset_dm_count(struct uart_port *port, int count) @@ -459,8 +459,8 @@ static void msm_complete_tx_dma(void *args) msm_write(port, val, UARTDM_DMEN); if (msm_port->is_uartdm > UARTDM_1P3) { - msm_write(port, UART_CR_CMD_RESET_TX, UART_CR); - msm_write(port, UART_CR_TX_ENABLE, UART_CR); + msm_write(port, MSM_UART_CR_CMD_RESET_TX, MSM_UART_CR); + msm_write(port, MSM_UART_CR_TX_ENABLE, MSM_UART_CR); } count = dma->count - state.residue; @@ -471,8 +471,8 @@ static void msm_complete_tx_dma(void *args) xmit->tail &= UART_XMIT_SIZE - 1; /* Restore "Tx FIFO below watermark" interrupt */ - msm_port->imr |= UART_IMR_TXLEV; - msm_write(port, msm_port->imr, UART_IMR); + msm_port->imr |= MSM_UART_IMR_TXLEV; + msm_write(port, msm_port->imr, MSM_UART_IMR); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); @@ -519,8 +519,8 @@ static int msm_handle_tx_dma(struct msm_port *msm_port, unsigned int count) * Using DMA complete for Tx FIFO reload, no need for * "Tx FIFO below watermark" one, disable it */ - msm_port->imr &= ~UART_IMR_TXLEV; - msm_write(port, msm_port->imr, UART_IMR); + msm_port->imr &= ~MSM_UART_IMR_TXLEV; + msm_write(port, msm_port->imr, MSM_UART_IMR); dma->count = count; @@ -562,10 +562,10 @@ static void msm_complete_rx_dma(void *args) val &= ~dma->enable_bit; msm_write(port, val, UARTDM_DMEN); - if (msm_read(port, UART_SR) & UART_SR_OVERRUN) { + if (msm_read(port, MSM_UART_SR) & MSM_UART_SR_OVERRUN) { port->icount.overrun++; tty_insert_flip_char(tport, 0, TTY_OVERRUN); - msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR); + msm_write(port, MSM_UART_CR_CMD_RESET_ERR, MSM_UART_CR); } count = msm_read(port, UARTDM_RX_TOTAL_SNAP); @@ -587,7 +587,7 @@ static void msm_complete_rx_dma(void *args) continue; } - if (!(port->read_status_mask & UART_SR_RX_BREAK)) + if (!(port->read_status_mask & MSM_UART_SR_RX_BREAK)) flag = TTY_NORMAL; spin_unlock_irqrestore(&port->lock, flags); @@ -641,23 +641,23 @@ static void msm_start_rx_dma(struct msm_port *msm_port) * Using DMA for FIFO off-load, no need for "Rx FIFO over * watermark" or "stale" interrupts, disable them */ - msm_port->imr &= ~(UART_IMR_RXLEV | UART_IMR_RXSTALE); + msm_port->imr &= ~(MSM_UART_IMR_RXLEV | MSM_UART_IMR_RXSTALE); /* * Well, when DMA is ADM3 engine(implied by <= UARTDM v1.3), * we need RXSTALE to flush input DMA fifo to memory */ if (msm_port->is_uartdm < UARTDM_1P4) - msm_port->imr |= UART_IMR_RXSTALE; + msm_port->imr |= MSM_UART_IMR_RXSTALE; - msm_write(uart, msm_port->imr, UART_IMR); + msm_write(uart, msm_port->imr, MSM_UART_IMR); dma->count = UARTDM_RX_SIZE; dma_async_issue_pending(dma->chan); - msm_write(uart, UART_CR_CMD_RESET_STALE_INT, UART_CR); - msm_write(uart, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR); + msm_write(uart, MSM_UART_CR_CMD_RESET_STALE_INT, MSM_UART_CR); + msm_write(uart, MSM_UART_CR_CMD_STALE_EVENT_ENABLE, MSM_UART_CR); val = msm_read(uart, UARTDM_DMEN); val |= dma->enable_bit; @@ -679,16 +679,16 @@ sw_mode: * Switch from DMA to SW/FIFO mode. After clearing Rx BAM (UARTDM_DMEN), * receiver must be reset. */ - msm_write(uart, UART_CR_CMD_RESET_RX, UART_CR); - msm_write(uart, UART_CR_RX_ENABLE, UART_CR); + msm_write(uart, MSM_UART_CR_CMD_RESET_RX, MSM_UART_CR); + msm_write(uart, MSM_UART_CR_RX_ENABLE, MSM_UART_CR); - msm_write(uart, UART_CR_CMD_RESET_STALE_INT, UART_CR); + msm_write(uart, MSM_UART_CR_CMD_RESET_STALE_INT, MSM_UART_CR); msm_write(uart, 0xFFFFFF, UARTDM_DMRX); - msm_write(uart, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR); + msm_write(uart, MSM_UART_CR_CMD_STALE_EVENT_ENABLE, MSM_UART_CR); /* Re-enable RX interrupts */ - msm_port->imr |= (UART_IMR_RXLEV | UART_IMR_RXSTALE); - msm_write(uart, msm_port->imr, UART_IMR); + msm_port->imr |= MSM_UART_IMR_RXLEV | MSM_UART_IMR_RXSTALE; + msm_write(uart, msm_port->imr, MSM_UART_IMR); } static void msm_stop_rx(struct uart_port *port) @@ -696,8 +696,8 @@ static void msm_stop_rx(struct uart_port *port) struct msm_port *msm_port = to_msm_port(port); struct msm_dma *dma = &msm_port->rx_dma; - msm_port->imr &= ~(UART_IMR_RXLEV | UART_IMR_RXSTALE); - msm_write(port, msm_port->imr, UART_IMR); + msm_port->imr &= ~(MSM_UART_IMR_RXLEV | MSM_UART_IMR_RXSTALE); + msm_write(port, msm_port->imr, MSM_UART_IMR); if (dma->chan) msm_stop_dma(port, dma); @@ -707,8 +707,8 @@ static void msm_enable_ms(struct uart_port *port) { struct msm_port *msm_port = to_msm_port(port); - msm_port->imr |= UART_IMR_DELTA_CTS; - msm_write(port, msm_port->imr, UART_IMR); + msm_port->imr |= MSM_UART_IMR_DELTA_CTS; + msm_write(port, msm_port->imr, MSM_UART_IMR); } static void msm_handle_rx_dm(struct uart_port *port, unsigned int misr) @@ -719,18 +719,18 @@ static void msm_handle_rx_dm(struct uart_port *port, unsigned int misr) int count = 0; struct msm_port *msm_port = to_msm_port(port); - if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) { + if ((msm_read(port, MSM_UART_SR) & MSM_UART_SR_OVERRUN)) { port->icount.overrun++; tty_insert_flip_char(tport, 0, TTY_OVERRUN); - msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR); + msm_write(port, MSM_UART_CR_CMD_RESET_ERR, MSM_UART_CR); } - if (misr & UART_IMR_RXSTALE) { + if (misr & MSM_UART_IMR_RXSTALE) { count = msm_read(port, UARTDM_RX_TOTAL_SNAP) - msm_port->old_snap_state; msm_port->old_snap_state = 0; } else { - count = 4 * (msm_read(port, UART_RFWR)); + count = 4 * (msm_read(port, MSM_UART_RFWR)); msm_port->old_snap_state += count; } @@ -742,8 +742,8 @@ static void msm_handle_rx_dm(struct uart_port *port, unsigned int misr) unsigned char buf[4]; int sysrq, r_count, i; - sr = msm_read(port, UART_SR); - if ((sr & UART_SR_RX_READY) == 0) { + sr = msm_read(port, MSM_UART_SR); + if ((sr & MSM_UART_SR_RX_READY) == 0) { msm_port->old_snap_state -= count; break; } @@ -762,7 +762,7 @@ static void msm_handle_rx_dm(struct uart_port *port, unsigned int misr) continue; } - if (!(port->read_status_mask & UART_SR_RX_BREAK)) + if (!(port->read_status_mask & MSM_UART_SR_RX_BREAK)) flag = TTY_NORMAL; spin_unlock(&port->lock); @@ -776,10 +776,10 @@ static void msm_handle_rx_dm(struct uart_port *port, unsigned int misr) tty_flip_buffer_push(tport); - if (misr & (UART_IMR_RXSTALE)) - msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR); + if (misr & (MSM_UART_IMR_RXSTALE)) + msm_write(port, MSM_UART_CR_CMD_RESET_STALE_INT, MSM_UART_CR); msm_write(port, 0xFFFFFF, UARTDM_DMRX); - msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR); + msm_write(port, MSM_UART_CR_CMD_STALE_EVENT_ENABLE, MSM_UART_CR); /* Try to use DMA */ msm_start_rx_dma(msm_port); @@ -795,25 +795,25 @@ static void msm_handle_rx(struct uart_port *port) * Handle overrun. My understanding of the hardware is that overrun * is not tied to the RX buffer, so we handle the case out of band. */ - if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) { + if ((msm_read(port, MSM_UART_SR) & MSM_UART_SR_OVERRUN)) { port->icount.overrun++; tty_insert_flip_char(tport, 0, TTY_OVERRUN); - msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR); + msm_write(port, MSM_UART_CR_CMD_RESET_ERR, MSM_UART_CR); } /* and now the main RX loop */ - while ((sr = msm_read(port, UART_SR)) & UART_SR_RX_READY) { + while ((sr = msm_read(port, MSM_UART_SR)) & MSM_UART_SR_RX_READY) { unsigned int c; char flag = TTY_NORMAL; int sysrq; - c = msm_read(port, UART_RF); + c = msm_read(port, MSM_UART_RF); - if (sr & UART_SR_RX_BREAK) { + if (sr & MSM_UART_SR_RX_BREAK) { port->icount.brk++; if (uart_handle_break(port)) continue; - } else if (sr & UART_SR_PAR_FRAME_ERR) { + } else if (sr & MSM_UART_SR_PAR_FRAME_ERR) { port->icount.frame++; } else { port->icount.rx++; @@ -822,9 +822,9 @@ static void msm_handle_rx(struct uart_port *port) /* Mask conditions we're ignorning. */ sr &= port->read_status_mask; - if (sr & UART_SR_RX_BREAK) + if (sr & MSM_UART_SR_RX_BREAK) flag = TTY_BREAK; - else if (sr & UART_SR_PAR_FRAME_ERR) + else if (sr & MSM_UART_SR_PAR_FRAME_ERR) flag = TTY_FRAME; spin_unlock(&port->lock); @@ -848,7 +848,7 @@ static void msm_handle_tx_pio(struct uart_port *port, unsigned int tx_count) if (msm_port->is_uartdm) tf = port->membase + UARTDM_TF; else - tf = port->membase + UART_TF; + tf = port->membase + MSM_UART_TF; if (tx_count && msm_port->is_uartdm) msm_reset_dm_count(port, tx_count); @@ -857,7 +857,7 @@ static void msm_handle_tx_pio(struct uart_port *port, unsigned int tx_count) int i; char buf[4] = { 0 }; - if (!(msm_read(port, UART_SR) & UART_SR_TX_READY)) + if (!(msm_read(port, MSM_UART_SR) & MSM_UART_SR_TX_READY)) break; if (msm_port->is_uartdm) @@ -898,7 +898,7 @@ static void msm_handle_tx(struct uart_port *port) if (msm_port->is_uartdm) tf = port->membase + UARTDM_TF; else - tf = port->membase + UART_TF; + tf = port->membase + MSM_UART_TF; buf[0] = port->x_char; @@ -942,7 +942,7 @@ static void msm_handle_tx(struct uart_port *port) static void msm_handle_delta_cts(struct uart_port *port) { - msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR); + msm_write(port, MSM_UART_CR_CMD_RESET_CTS, MSM_UART_CR); port->icount.cts++; wake_up_interruptible(&port->state->port.delta_msr_wait); } @@ -957,20 +957,20 @@ static irqreturn_t msm_uart_irq(int irq, void *dev_id) u32 val; spin_lock_irqsave(&port->lock, flags); - misr = msm_read(port, UART_MISR); - msm_write(port, 0, UART_IMR); /* disable interrupt */ + misr = msm_read(port, MSM_UART_MISR); + msm_write(port, 0, MSM_UART_IMR); /* disable interrupt */ - if (misr & UART_IMR_RXBREAK_START) { + if (misr & MSM_UART_IMR_RXBREAK_START) { msm_port->break_detected = true; - msm_write(port, UART_CR_CMD_RESET_RXBREAK_START, UART_CR); + msm_write(port, MSM_UART_CR_CMD_RESET_RXBREAK_START, MSM_UART_CR); } - if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE)) { + if (misr & (MSM_UART_IMR_RXLEV | MSM_UART_IMR_RXSTALE)) { if (dma->count) { - val = UART_CR_CMD_STALE_EVENT_DISABLE; - msm_write(port, val, UART_CR); - val = UART_CR_CMD_RESET_STALE_INT; - msm_write(port, val, UART_CR); + val = MSM_UART_CR_CMD_STALE_EVENT_DISABLE; + msm_write(port, val, MSM_UART_CR); + val = MSM_UART_CR_CMD_RESET_STALE_INT; + msm_write(port, val, MSM_UART_CR); /* * Flush DMA input fifo to memory, this will also * trigger DMA RX completion @@ -982,12 +982,12 @@ static irqreturn_t msm_uart_irq(int irq, void *dev_id) msm_handle_rx(port); } } - if (misr & UART_IMR_TXLEV) + if (misr & MSM_UART_IMR_TXLEV) msm_handle_tx(port); - if (misr & UART_IMR_DELTA_CTS) + if (misr & MSM_UART_IMR_DELTA_CTS) msm_handle_delta_cts(port); - msm_write(port, msm_port->imr, UART_IMR); /* restore interrupt */ + msm_write(port, msm_port->imr, MSM_UART_IMR); /* restore interrupt */ spin_unlock_irqrestore(&port->lock, flags); return IRQ_HANDLED; @@ -995,7 +995,7 @@ static irqreturn_t msm_uart_irq(int irq, void *dev_id) static unsigned int msm_tx_empty(struct uart_port *port) { - return (msm_read(port, UART_SR) & UART_SR_TX_EMPTY) ? TIOCSER_TEMT : 0; + return (msm_read(port, MSM_UART_SR) & MSM_UART_SR_TX_EMPTY) ? TIOCSER_TEMT : 0; } static unsigned int msm_get_mctrl(struct uart_port *port) @@ -1009,15 +1009,15 @@ static void msm_reset(struct uart_port *port) unsigned int mr; /* reset everything */ - msm_write(port, UART_CR_CMD_RESET_RX, UART_CR); - msm_write(port, UART_CR_CMD_RESET_TX, UART_CR); - msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR); - msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR); - msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR); - msm_write(port, UART_CR_CMD_RESET_RFR, UART_CR); - mr = msm_read(port, UART_MR1); - mr &= ~UART_MR1_RX_RDY_CTL; - msm_write(port, mr, UART_MR1); + msm_write(port, MSM_UART_CR_CMD_RESET_RX, MSM_UART_CR); + msm_write(port, MSM_UART_CR_CMD_RESET_TX, MSM_UART_CR); + msm_write(port, MSM_UART_CR_CMD_RESET_ERR, MSM_UART_CR); + msm_write(port, MSM_UART_CR_CMD_RESET_BREAK_INT, MSM_UART_CR); + msm_write(port, MSM_UART_CR_CMD_RESET_CTS, MSM_UART_CR); + msm_write(port, MSM_UART_CR_CMD_RESET_RFR, MSM_UART_CR); + mr = msm_read(port, MSM_UART_MR1); + mr &= ~MSM_UART_MR1_RX_RDY_CTL; + msm_write(port, mr, MSM_UART_MR1); /* Disable DM modes */ if (msm_port->is_uartdm) @@ -1028,24 +1028,24 @@ static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl) { unsigned int mr; - mr = msm_read(port, UART_MR1); + mr = msm_read(port, MSM_UART_MR1); if (!(mctrl & TIOCM_RTS)) { - mr &= ~UART_MR1_RX_RDY_CTL; - msm_write(port, mr, UART_MR1); - msm_write(port, UART_CR_CMD_RESET_RFR, UART_CR); + mr &= ~MSM_UART_MR1_RX_RDY_CTL; + msm_write(port, mr, MSM_UART_MR1); + msm_write(port, MSM_UART_CR_CMD_RESET_RFR, MSM_UART_CR); } else { - mr |= UART_MR1_RX_RDY_CTL; - msm_write(port, mr, UART_MR1); + mr |= MSM_UART_MR1_RX_RDY_CTL; + msm_write(port, mr, MSM_UART_MR1); } } static void msm_break_ctl(struct uart_port *port, int break_ctl) { if (break_ctl) - msm_write(port, UART_CR_CMD_START_BREAK, UART_CR); + msm_write(port, MSM_UART_CR_CMD_START_BREAK, MSM_UART_CR); else - msm_write(port, UART_CR_CMD_STOP_BREAK, UART_CR); + msm_write(port, MSM_UART_CR_CMD_STOP_BREAK, MSM_UART_CR); } struct msm_baud_map { @@ -1142,45 +1142,45 @@ static int msm_set_baud_rate(struct uart_port *port, unsigned int baud, *saved_flags = flags; port->uartclk = rate; - msm_write(port, entry->code, UART_CSR); + msm_write(port, entry->code, MSM_UART_CSR); /* RX stale watermark */ rxstale = entry->rxstale; - watermark = UART_IPR_STALE_LSB & rxstale; + watermark = MSM_UART_IPR_STALE_LSB & rxstale; if (msm_port->is_uartdm) { - mask = UART_DM_IPR_STALE_TIMEOUT_MSB; + mask = MSM_UART_DM_IPR_STALE_TIMEOUT_MSB; } else { - watermark |= UART_IPR_RXSTALE_LAST; - mask = UART_IPR_STALE_TIMEOUT_MSB; + watermark |= MSM_UART_IPR_RXSTALE_LAST; + mask = MSM_UART_IPR_STALE_TIMEOUT_MSB; } watermark |= mask & (rxstale << 2); - msm_write(port, watermark, UART_IPR); + msm_write(port, watermark, MSM_UART_IPR); /* set RX watermark */ watermark = (port->fifosize * 3) / 4; - msm_write(port, watermark, UART_RFWR); + msm_write(port, watermark, MSM_UART_RFWR); /* set TX watermark */ - msm_write(port, 10, UART_TFWR); + msm_write(port, 10, MSM_UART_TFWR); - msm_write(port, UART_CR_CMD_PROTECTION_EN, UART_CR); + msm_write(port, MSM_UART_CR_CMD_PROTECTION_EN, MSM_UART_CR); msm_reset(port); /* Enable RX and TX */ - msm_write(port, UART_CR_TX_ENABLE | UART_CR_RX_ENABLE, UART_CR); + msm_write(port, MSM_UART_CR_TX_ENABLE | MSM_UART_CR_RX_ENABLE, MSM_UART_CR); /* turn on RX and CTS interrupts */ - msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE | - UART_IMR_CURRENT_CTS | UART_IMR_RXBREAK_START; + msm_port->imr = MSM_UART_IMR_RXLEV | MSM_UART_IMR_RXSTALE | + MSM_UART_IMR_CURRENT_CTS | MSM_UART_IMR_RXBREAK_START; - msm_write(port, msm_port->imr, UART_IMR); + msm_write(port, msm_port->imr, MSM_UART_IMR); if (msm_port->is_uartdm) { - msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR); + msm_write(port, MSM_UART_CR_CMD_RESET_STALE_INT, MSM_UART_CR); msm_write(port, 0xFFFFFF, UARTDM_DMRX); - msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR); + msm_write(port, MSM_UART_CR_CMD_STALE_EVENT_ENABLE, MSM_UART_CR); } return baud; @@ -1212,18 +1212,18 @@ static int msm_startup(struct uart_port *port) rfr_level = port->fifosize; /* set automatic RFR level */ - data = msm_read(port, UART_MR1); + data = msm_read(port, MSM_UART_MR1); if (msm_port->is_uartdm) - mask = UART_DM_MR1_AUTO_RFR_LEVEL1; + mask = MSM_UART_DM_MR1_AUTO_RFR_LEVEL1; else - mask = UART_MR1_AUTO_RFR_LEVEL1; + mask = MSM_UART_MR1_AUTO_RFR_LEVEL1; data &= ~mask; - data &= ~UART_MR1_AUTO_RFR_LEVEL0; + data &= ~MSM_UART_MR1_AUTO_RFR_LEVEL0; data |= mask & (rfr_level << 2); - data |= UART_MR1_AUTO_RFR_LEVEL0 & rfr_level; - msm_write(port, data, UART_MR1); + data |= MSM_UART_MR1_AUTO_RFR_LEVEL0 & rfr_level; + msm_write(port, data, MSM_UART_MR1); if (msm_port->is_uartdm) { msm_request_tx_dma(msm_port, msm_port->uart.mapbase); @@ -1252,7 +1252,7 @@ static void msm_shutdown(struct uart_port *port) struct msm_port *msm_port = to_msm_port(port); msm_port->imr = 0; - msm_write(port, 0, UART_IMR); /* disable interrupts */ + msm_write(port, 0, MSM_UART_IMR); /* disable interrupts */ if (msm_port->is_uartdm) msm_release_dma(msm_port); @@ -1282,60 +1282,60 @@ static void msm_set_termios(struct uart_port *port, struct ktermios *termios, tty_termios_encode_baud_rate(termios, baud, baud); /* calculate parity */ - mr = msm_read(port, UART_MR2); - mr &= ~UART_MR2_PARITY_MODE; + mr = msm_read(port, MSM_UART_MR2); + mr &= ~MSM_UART_MR2_PARITY_MODE; if (termios->c_cflag & PARENB) { if (termios->c_cflag & PARODD) - mr |= UART_MR2_PARITY_MODE_ODD; + mr |= MSM_UART_MR2_PARITY_MODE_ODD; else if (termios->c_cflag & CMSPAR) - mr |= UART_MR2_PARITY_MODE_SPACE; + mr |= MSM_UART_MR2_PARITY_MODE_SPACE; else - mr |= UART_MR2_PARITY_MODE_EVEN; + mr |= MSM_UART_MR2_PARITY_MODE_EVEN; } /* calculate bits per char */ - mr &= ~UART_MR2_BITS_PER_CHAR; + mr &= ~MSM_UART_MR2_BITS_PER_CHAR; switch (termios->c_cflag & CSIZE) { case CS5: - mr |= UART_MR2_BITS_PER_CHAR_5; + mr |= MSM_UART_MR2_BITS_PER_CHAR_5; break; case CS6: - mr |= UART_MR2_BITS_PER_CHAR_6; + mr |= MSM_UART_MR2_BITS_PER_CHAR_6; break; case CS7: - mr |= UART_MR2_BITS_PER_CHAR_7; + mr |= MSM_UART_MR2_BITS_PER_CHAR_7; break; case CS8: default: - mr |= UART_MR2_BITS_PER_CHAR_8; + mr |= MSM_UART_MR2_BITS_PER_CHAR_8; break; } /* calculate stop bits */ - mr &= ~(UART_MR2_STOP_BIT_LEN_ONE | UART_MR2_STOP_BIT_LEN_TWO); + mr &= ~(MSM_UART_MR2_STOP_BIT_LEN_ONE | MSM_UART_MR2_STOP_BIT_LEN_TWO); if (termios->c_cflag & CSTOPB) - mr |= UART_MR2_STOP_BIT_LEN_TWO; + mr |= MSM_UART_MR2_STOP_BIT_LEN_TWO; else - mr |= UART_MR2_STOP_BIT_LEN_ONE; + mr |= MSM_UART_MR2_STOP_BIT_LEN_ONE; /* set parity, bits per char, and stop bit */ - msm_write(port, mr, UART_MR2); + msm_write(port, mr, MSM_UART_MR2); /* calculate and set hardware flow control */ - mr = msm_read(port, UART_MR1); - mr &= ~(UART_MR1_CTS_CTL | UART_MR1_RX_RDY_CTL); + mr = msm_read(port, MSM_UART_MR1); + mr &= ~(MSM_UART_MR1_CTS_CTL | MSM_UART_MR1_RX_RDY_CTL); if (termios->c_cflag & CRTSCTS) { - mr |= UART_MR1_CTS_CTL; - mr |= UART_MR1_RX_RDY_CTL; + mr |= MSM_UART_MR1_CTS_CTL; + mr |= MSM_UART_MR1_RX_RDY_CTL; } - msm_write(port, mr, UART_MR1); + msm_write(port, mr, MSM_UART_MR1); /* Configure status bits to ignore based on termio flags. */ port->read_status_mask = 0; if (termios->c_iflag & INPCK) - port->read_status_mask |= UART_SR_PAR_FRAME_ERR; + port->read_status_mask |= MSM_UART_SR_PAR_FRAME_ERR; if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) - port->read_status_mask |= UART_SR_RX_BREAK; + port->read_status_mask |= MSM_UART_SR_RX_BREAK; uart_update_timeout(port, termios->c_cflag, baud); @@ -1439,9 +1439,9 @@ static void msm_power(struct uart_port *port, unsigned int state, static int msm_poll_get_char_single(struct uart_port *port) { struct msm_port *msm_port = to_msm_port(port); - unsigned int rf_reg = msm_port->is_uartdm ? UARTDM_RF : UART_RF; + unsigned int rf_reg = msm_port->is_uartdm ? UARTDM_RF : MSM_UART_RF; - if (!(msm_read(port, UART_SR) & UART_SR_RX_READY)) + if (!(msm_read(port, MSM_UART_SR) & MSM_UART_SR_RX_READY)) return NO_POLL_CHAR; return msm_read(port, rf_reg) & 0xff; @@ -1459,7 +1459,7 @@ static int msm_poll_get_char_dm(struct uart_port *port) c = sp[sizeof(slop) - count]; count--; /* Or if FIFO is empty */ - } else if (!(msm_read(port, UART_SR) & UART_SR_RX_READY)) { + } else if (!(msm_read(port, MSM_UART_SR) & MSM_UART_SR_RX_READY)) { /* * If RX packing buffer has less than a word, force stale to * push contents into RX FIFO @@ -1467,14 +1467,13 @@ static int msm_poll_get_char_dm(struct uart_port *port) count = msm_read(port, UARTDM_RXFS); count = (count >> UARTDM_RXFS_BUF_SHIFT) & UARTDM_RXFS_BUF_MASK; if (count) { - msm_write(port, UART_CR_CMD_FORCE_STALE, UART_CR); + msm_write(port, MSM_UART_CR_CMD_FORCE_STALE, MSM_UART_CR); slop = msm_read(port, UARTDM_RF); c = sp[0]; count--; - msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR); + msm_write(port, MSM_UART_CR_CMD_RESET_STALE_INT, MSM_UART_CR); msm_write(port, 0xFFFFFF, UARTDM_DMRX); - msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, - UART_CR); + msm_write(port, MSM_UART_CR_CMD_STALE_EVENT_ENABLE, MSM_UART_CR); } else { c = NO_POLL_CHAR; } @@ -1495,8 +1494,8 @@ static int msm_poll_get_char(struct uart_port *port) struct msm_port *msm_port = to_msm_port(port); /* Disable all interrupts */ - imr = msm_read(port, UART_IMR); - msm_write(port, 0, UART_IMR); + imr = msm_read(port, MSM_UART_IMR); + msm_write(port, 0, MSM_UART_IMR); if (msm_port->is_uartdm) c = msm_poll_get_char_dm(port); @@ -1504,7 +1503,7 @@ static int msm_poll_get_char(struct uart_port *port) c = msm_poll_get_char_single(port); /* Enable interrupts */ - msm_write(port, imr, UART_IMR); + msm_write(port, imr, MSM_UART_IMR); return c; } @@ -1515,25 +1514,25 @@ static void msm_poll_put_char(struct uart_port *port, unsigned char c) struct msm_port *msm_port = to_msm_port(port); /* Disable all interrupts */ - imr = msm_read(port, UART_IMR); - msm_write(port, 0, UART_IMR); + imr = msm_read(port, MSM_UART_IMR); + msm_write(port, 0, MSM_UART_IMR); if (msm_port->is_uartdm) msm_reset_dm_count(port, 1); /* Wait until FIFO is empty */ - while (!(msm_read(port, UART_SR) & UART_SR_TX_READY)) + while (!(msm_read(port, MSM_UART_SR) & MSM_UART_SR_TX_READY)) cpu_relax(); /* Write a character */ - msm_write(port, c, msm_port->is_uartdm ? UARTDM_TF : UART_TF); + msm_write(port, c, msm_port->is_uartdm ? UARTDM_TF : MSM_UART_TF); /* Wait until FIFO is empty */ - while (!(msm_read(port, UART_SR) & UART_SR_TX_READY)) + while (!(msm_read(port, MSM_UART_SR) & MSM_UART_SR_TX_READY)) cpu_relax(); /* Enable interrupts */ - msm_write(port, imr, UART_IMR); + msm_write(port, imr, MSM_UART_IMR); } #endif @@ -1591,7 +1590,7 @@ static struct msm_port msm_uart_ports[] = { }, }; -#define UART_NR ARRAY_SIZE(msm_uart_ports) +#define MSM_UART_NR ARRAY_SIZE(msm_uart_ports) static inline struct uart_port *msm_get_port_from_line(unsigned int line) { @@ -1612,7 +1611,7 @@ static void __msm_console_write(struct uart_port *port, const char *s, if (is_uartdm) tf = port->membase + UARTDM_TF; else - tf = port->membase + UART_TF; + tf = port->membase + MSM_UART_TF; /* Account for newlines that will get a carriage return added */ for (i = 0; i < count; i++) @@ -1658,7 +1657,7 @@ static void __msm_console_write(struct uart_port *port, const char *s, } } - while (!(msm_read(port, UART_SR) & UART_SR_TX_READY)) + while (!(msm_read(port, MSM_UART_SR) & MSM_UART_SR_TX_READY)) cpu_relax(); iowrite32_rep(tf, buf, 1); @@ -1677,7 +1676,7 @@ static void msm_console_write(struct console *co, const char *s, struct uart_port *port; struct msm_port *msm_port; - BUG_ON(co->index < 0 || co->index >= UART_NR); + BUG_ON(co->index < 0 || co->index >= MSM_UART_NR); port = msm_get_port_from_line(co->index); msm_port = to_msm_port(port); @@ -1693,7 +1692,7 @@ static int msm_console_setup(struct console *co, char *options) int parity = 'n'; int flow = 'n'; - if (unlikely(co->index >= UART_NR || co->index < 0)) + if (unlikely(co->index >= MSM_UART_NR || co->index < 0)) return -ENXIO; port = msm_get_port_from_line(co->index); @@ -1774,7 +1773,7 @@ static struct uart_driver msm_uart_driver = { .owner = THIS_MODULE, .driver_name = "msm_serial", .dev_name = "ttyMSM", - .nr = UART_NR, + .nr = MSM_UART_NR, .cons = MSM_CONSOLE, }; @@ -1804,7 +1803,7 @@ static int msm_serial_probe(struct platform_device *pdev) if (line < 0) line = atomic_inc_return(&msm_uart_next_id) - 1; - if (unlikely(line < 0 || line >= UART_NR)) + if (unlikely(line < 0 || line >= MSM_UART_NR)) return -ENXIO; dev_info(&pdev->dev, "msm_serial: detected port #%d\n", line); -- cgit v1.2.3 From 27a1c39215a2f4f4ca6bae0dba1bebc8e16a01a0 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Fri, 24 Jun 2022 23:54:22 +0300 Subject: serial: 8250: Use C99 array initializer & define UART_REG_UNMAPPED MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use C99 array initializer insteads of comments and make unmapped checks more obvious. Reviewed-by: Jiri Slaby Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220624205424.12686-5-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 38 +++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 3a8747ec672b..1311b00f8194 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -336,27 +336,29 @@ static void default_serial_dl_write(struct uart_8250_port *up, int value) #ifdef CONFIG_SERIAL_8250_RT288X +#define UART_REG_UNMAPPED -1 + /* Au1x00/RT288x UART hardware has a weird register layout */ static const s8 au_io_in_map[8] = { - 0, /* UART_RX */ - 2, /* UART_IER */ - 3, /* UART_IIR */ - 5, /* UART_LCR */ - 6, /* UART_MCR */ - 7, /* UART_LSR */ - 8, /* UART_MSR */ - -1, /* UART_SCR (unmapped) */ + [UART_RX] = 0, + [UART_IER] = 2, + [UART_IIR] = 3, + [UART_LCR] = 5, + [UART_MCR] = 6, + [UART_LSR] = 7, + [UART_MSR] = 8, + [UART_SCR] = UART_REG_UNMAPPED, }; static const s8 au_io_out_map[8] = { - 1, /* UART_TX */ - 2, /* UART_IER */ - 4, /* UART_FCR */ - 5, /* UART_LCR */ - 6, /* UART_MCR */ - -1, /* UART_LSR (unmapped) */ - -1, /* UART_MSR (unmapped) */ - -1, /* UART_SCR (unmapped) */ + [UART_TX] = 1, + [UART_IER] = 2, + [UART_FCR] = 4, + [UART_LCR] = 5, + [UART_MCR] = 6, + [UART_LSR] = UART_REG_UNMAPPED, + [UART_MSR] = UART_REG_UNMAPPED, + [UART_SCR] = UART_REG_UNMAPPED, }; unsigned int au_serial_in(struct uart_port *p, int offset) @@ -364,7 +366,7 @@ unsigned int au_serial_in(struct uart_port *p, int offset) if (offset >= ARRAY_SIZE(au_io_in_map)) return UINT_MAX; offset = au_io_in_map[offset]; - if (offset < 0) + if (offset == UART_REG_UNMAPPED) return UINT_MAX; return __raw_readl(p->membase + (offset << p->regshift)); } @@ -374,7 +376,7 @@ void au_serial_out(struct uart_port *p, int offset, int value) if (offset >= ARRAY_SIZE(au_io_out_map)) return; offset = au_io_out_map[offset]; - if (offset < 0) + if (offset == UART_REG_UNMAPPED) return; __raw_writel(value, p->membase + (offset << p->regshift)); } -- cgit v1.2.3 From eb47b59afb7e46c952d7b03884245364990d4910 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Fri, 24 Jun 2022 23:54:23 +0300 Subject: serial: Convert SERIAL_XMIT_SIZE to UART_XMIT_SIZE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both UART_XMIT_SIZE and SERIAL_XMIT_SIZE are defined. Make them all UART_XMIT_SIZE. Reviewed-by: Jiri Slaby Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220624205424.12686-6-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/amiserial.c | 18 +++++++++--------- drivers/tty/mips_ejtag_fdc.c | 2 +- drivers/tty/serial/meson_uart.c | 2 +- drivers/tty/serial/owl-uart.c | 2 +- drivers/tty/serial/rda-uart.c | 2 +- include/linux/serial.h | 6 ------ 6 files changed, 13 insertions(+), 19 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index afb2d373dd47..5458e2b1c125 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -283,12 +284,12 @@ static void transmit_chars(struct serial_state *info) amiga_custom.serdat = info->xmit.buf[info->xmit.tail++] | 0x100; mb(); - info->xmit.tail = info->xmit.tail & (SERIAL_XMIT_SIZE-1); + info->xmit.tail = info->xmit.tail & (UART_XMIT_SIZE - 1); info->icount.tx++; if (CIRC_CNT(info->xmit.head, info->xmit.tail, - SERIAL_XMIT_SIZE) < WAKEUP_CHARS) + UART_XMIT_SIZE) < WAKEUP_CHARS) tty_wakeup(info->tport.tty); #ifdef SERIAL_DEBUG_INTR @@ -708,13 +709,13 @@ static int rs_put_char(struct tty_struct *tty, unsigned char ch) local_irq_save(flags); if (CIRC_SPACE(info->xmit.head, info->xmit.tail, - SERIAL_XMIT_SIZE) == 0) { + UART_XMIT_SIZE) == 0) { local_irq_restore(flags); return 0; } info->xmit.buf[info->xmit.head++] = ch; - info->xmit.head &= SERIAL_XMIT_SIZE-1; + info->xmit.head &= UART_XMIT_SIZE - 1; local_irq_restore(flags); return 1; } @@ -753,15 +754,14 @@ static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count while (1) { c = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, - SERIAL_XMIT_SIZE); + UART_XMIT_SIZE); if (count < c) c = count; if (c <= 0) { break; } memcpy(info->xmit.buf + info->xmit.head, buf, c); - info->xmit.head = ((info->xmit.head + c) & - (SERIAL_XMIT_SIZE-1)); + info->xmit.head = (info->xmit.head + c) & (UART_XMIT_SIZE - 1); buf += c; count -= c; ret += c; @@ -788,14 +788,14 @@ static unsigned int rs_write_room(struct tty_struct *tty) { struct serial_state *info = tty->driver_data; - return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); + return CIRC_SPACE(info->xmit.head, info->xmit.tail, UART_XMIT_SIZE); } static unsigned int rs_chars_in_buffer(struct tty_struct *tty) { struct serial_state *info = tty->driver_data; - return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); + return CIRC_CNT(info->xmit.head, info->xmit.tail, UART_XMIT_SIZE); } static void rs_flush_buffer(struct tty_struct *tty) diff --git a/drivers/tty/mips_ejtag_fdc.c b/drivers/tty/mips_ejtag_fdc.c index 49907427a165..e81701a66429 100644 --- a/drivers/tty/mips_ejtag_fdc.c +++ b/drivers/tty/mips_ejtag_fdc.c @@ -916,7 +916,7 @@ static int mips_ejtag_fdc_tty_probe(struct mips_cdmm_device *dev) mips_ejtag_fdc_write(priv, REG_FDCFG, cfg); /* Make each port's xmit FIFO big enough to fill FDC TX FIFO */ - priv->xmit_size = min(tx_fifo * 4, (unsigned int)SERIAL_XMIT_SIZE); + priv->xmit_size = min(tx_fifo * 4, (unsigned int)UART_XMIT_SIZE); driver = tty_alloc_driver(NUM_TTY_CHANNELS, TTY_DRIVER_REAL_RAW); if (IS_ERR(driver)) diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c index 4869c0059c98..6c8db19fd572 100644 --- a/drivers/tty/serial/meson_uart.c +++ b/drivers/tty/serial/meson_uart.c @@ -162,7 +162,7 @@ static void meson_uart_start_tx(struct uart_port *port) ch = xmit->buf[xmit->tail]; writel(ch, port->membase + AML_UART_WFIFO); - xmit->tail = (xmit->tail+1) & (SERIAL_XMIT_SIZE - 1); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; } diff --git a/drivers/tty/serial/owl-uart.c b/drivers/tty/serial/owl-uart.c index 44d20e5a7dd3..888e17e3f25f 100644 --- a/drivers/tty/serial/owl-uart.c +++ b/drivers/tty/serial/owl-uart.c @@ -201,7 +201,7 @@ static void owl_uart_send_chars(struct uart_port *port) ch = xmit->buf[xmit->tail]; owl_uart_write(port, ch, OWL_UART_TXDAT); - xmit->tail = (xmit->tail + 1) & (SERIAL_XMIT_SIZE - 1); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; } diff --git a/drivers/tty/serial/rda-uart.c b/drivers/tty/serial/rda-uart.c index f556b4955f59..feb2054aba37 100644 --- a/drivers/tty/serial/rda-uart.c +++ b/drivers/tty/serial/rda-uart.c @@ -353,7 +353,7 @@ static void rda_uart_send_chars(struct uart_port *port) ch = xmit->buf[xmit->tail]; rda_uart_write(port, ch, RDA_UART_RXTX_BUFFER); - xmit->tail = (xmit->tail + 1) & (SERIAL_XMIT_SIZE - 1); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; } diff --git a/include/linux/serial.h b/include/linux/serial.h index 0b8b7d7c8f33..70a9866e4abb 100644 --- a/include/linux/serial.h +++ b/include/linux/serial.h @@ -9,7 +9,6 @@ #ifndef _LINUX_SERIAL_H #define _LINUX_SERIAL_H -#include #include /* Helper for dealing with UART_LCR_WLEN* defines */ @@ -25,11 +24,6 @@ struct async_icount { __u32 buf_overrun; }; -/* - * The size of the serial xmit buffer is 1 page, or 4096 bytes - */ -#define SERIAL_XMIT_SIZE PAGE_SIZE - #include #endif /* _LINUX_SERIAL_H */ -- cgit v1.2.3 From 34619de1b8cb52afa90bbeb3b4fbad34c28f19cf Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Fri, 24 Jun 2022 23:54:24 +0300 Subject: serial: Consolidate BOTH_EMPTY use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per file BOTH_EMPTY defines are littering our source code here and there. Define once in serial.h and create helper for the check too. Reviewed-by: Jiri Slaby Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220624205424.12686-7-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- arch/mips/ath79/early_printk.c | 9 +++++---- drivers/accessibility/speakup/serialio.h | 3 +-- drivers/tty/serial/8250/8250_early.c | 4 +--- drivers/tty/serial/8250/8250_port.c | 12 +++++------- drivers/tty/serial/omap-serial.c | 7 +++---- drivers/tty/serial/pch_uart.c | 7 +++---- drivers/tty/serial/pxa.c | 5 ++--- drivers/tty/serial/sunsu.c | 4 +--- drivers/tty/serial/vr41xx_siu.c | 4 +--- include/linux/serial.h | 9 +++++++++ 10 files changed, 31 insertions(+), 33 deletions(-) (limited to 'drivers/tty') diff --git a/arch/mips/ath79/early_printk.c b/arch/mips/ath79/early_printk.c index 8751d067f98f..f6d02b425a10 100644 --- a/arch/mips/ath79/early_printk.c +++ b/arch/mips/ath79/early_printk.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -29,15 +30,15 @@ static inline void prom_putchar_wait(void __iomem *reg, u32 mask, u32 val) } while (1); } -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - static void prom_putchar_ar71xx(char ch) { void __iomem *base = (void __iomem *)(KSEG1ADDR(AR71XX_UART_BASE)); - prom_putchar_wait(base + UART_LSR * 4, BOTH_EMPTY, BOTH_EMPTY); + prom_putchar_wait(base + UART_LSR * 4, UART_LSR_BOTH_EMPTY, + UART_LSR_BOTH_EMPTY); __raw_writel((unsigned char)ch, base + UART_TX * 4); - prom_putchar_wait(base + UART_LSR * 4, BOTH_EMPTY, BOTH_EMPTY); + prom_putchar_wait(base + UART_LSR * 4, UART_LSR_BOTH_EMPTY, + UART_LSR_BOTH_EMPTY); } static void prom_putchar_ar933x(char ch) diff --git a/drivers/accessibility/speakup/serialio.h b/drivers/accessibility/speakup/serialio.h index 6f8f86f161bb..b4f9a1925b81 100644 --- a/drivers/accessibility/speakup/serialio.h +++ b/drivers/accessibility/speakup/serialio.h @@ -33,9 +33,8 @@ struct old_serial_port { #define NUM_DISABLE_TIMEOUTS 3 /* buffer timeout in ms */ #define SPK_TIMEOUT 100 -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) #define spk_serial_tx_busy() \ - ((inb(speakup_info.port_tts + UART_LSR) & BOTH_EMPTY) != BOTH_EMPTY) + (!uart_lsr_tx_empty(inb(speakup_info.port_tts + UART_LSR))) #endif diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c index e52585064565..f271becfc46c 100644 --- a/drivers/tty/serial/8250/8250_early.c +++ b/drivers/tty/serial/8250/8250_early.c @@ -84,8 +84,6 @@ static void serial8250_early_out(struct uart_port *port, int offset, int value) } } -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - static void serial_putc(struct uart_port *port, unsigned char c) { unsigned int status; @@ -94,7 +92,7 @@ static void serial_putc(struct uart_port *port, unsigned char c) for (;;) { status = serial8250_early_in(port, UART_LSR); - if ((status & BOTH_EMPTY) == BOTH_EMPTY) + if (uart_lsr_tx_empty(status)) break; cpu_relax(); } diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 1311b00f8194..55b252954a92 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -50,8 +50,6 @@ #define DEBUG_AUTOCONF(fmt...) do { } while (0) #endif -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - /* * Here we define the default xmit fifo size used for each type of UART. */ @@ -1843,7 +1841,7 @@ void serial8250_tx_chars(struct uart_8250_port *up) if (uart_circ_empty(xmit)) break; if ((up->capabilities & UART_CAP_HFIFO) && - (serial_in(up, UART_LSR) & BOTH_EMPTY) != BOTH_EMPTY) + !uart_lsr_tx_empty(serial_in(up, UART_LSR))) break; /* The BCM2835 MINI UART THRE bit is really a not-full bit. */ if ((up->capabilities & UART_CAP_MINI) && @@ -2003,7 +2001,7 @@ static unsigned int serial8250_tx_empty(struct uart_port *port) serial8250_rpm_put(up); - return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0; + return uart_lsr_tx_empty(lsr) ? TIOCSER_TEMT : 0; } unsigned int serial8250_do_get_mctrl(struct uart_port *port) @@ -2151,7 +2149,7 @@ static void serial8250_put_poll_char(struct uart_port *port, else serial_port_out(port, UART_IER, 0); - wait_for_xmitr(up, BOTH_EMPTY); + wait_for_xmitr(up, UART_LSR_BOTH_EMPTY); /* * Send the character out. */ @@ -2161,7 +2159,7 @@ static void serial8250_put_poll_char(struct uart_port *port, * Finally, wait for transmitter to become empty * and restore the IER */ - wait_for_xmitr(up, BOTH_EMPTY); + wait_for_xmitr(up, UART_LSR_BOTH_EMPTY); serial_port_out(port, UART_IER, ier); serial8250_rpm_put(up); } @@ -3431,7 +3429,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, * Finally, wait for transmitter to become empty * and restore the IER */ - wait_for_xmitr(up, BOTH_EMPTY); + wait_for_xmitr(up, UART_LSR_BOTH_EMPTY); if (em485) { mdelay(port->rs485.delay_rts_after_send); diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 98622c35d896..52cb1a68b053 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -1102,8 +1103,6 @@ serial_omap_type(struct uart_port *port) return up->name; } -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - static void __maybe_unused wait_for_xmitr(struct uart_omap_port *up) { unsigned int status, tmout = 10000; @@ -1118,7 +1117,7 @@ static void __maybe_unused wait_for_xmitr(struct uart_omap_port *up) if (--tmout == 0) break; udelay(1); - } while ((status & BOTH_EMPTY) != BOTH_EMPTY); + } while (!uart_lsr_tx_empty(status)); /* Wait up to 1s for flow control if necessary */ if (up->port.flags & UPF_CONS_FLOW) { @@ -1186,7 +1185,7 @@ static void omap_serial_early_putc(struct uart_port *port, unsigned char c) for (;;) { status = omap_serial_early_in(port, UART_LSR); - if ((status & BOTH_EMPTY) == BOTH_EMPTY) + if (uart_lsr_tx_empty(status)) break; cpu_relax(); } diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 3b26524d48e3..8a9065e4a903 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -3,6 +3,7 @@ *Copyright (C) 2011 LAPIS Semiconductor Co., Ltd. */ #include +#include #include #include #include @@ -189,8 +190,6 @@ enum { #define PCH_UART_HAL_LOOP (PCH_UART_MCR_LOOP) #define PCH_UART_HAL_AFE (PCH_UART_MCR_AFE) -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - #define DEFAULT_UARTCLK 1843200 /* 1.8432 MHz */ #define CMITC_UARTCLK 192000000 /* 192.0000 MHz */ #define FRI2_64_UARTCLK 64000000 /* 64.0000 MHz */ @@ -1516,7 +1515,7 @@ static void pch_uart_put_poll_char(struct uart_port *port, * Finally, wait for transmitter to become empty * and restore the IER */ - wait_for_xmitr(priv, BOTH_EMPTY); + wait_for_xmitr(priv, UART_LSR_BOTH_EMPTY); iowrite8(ier, priv->membase + UART_IER); } #endif /* CONFIG_CONSOLE_POLL */ @@ -1602,7 +1601,7 @@ pch_console_write(struct console *co, const char *s, unsigned int count) * Finally, wait for transmitter to become empty * and restore the IER */ - wait_for_xmitr(priv, BOTH_EMPTY); + wait_for_xmitr(priv, UART_LSR_BOTH_EMPTY); iowrite8(ier, priv->membase + UART_IER); if (port_locked) diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c index e80ba8e10407..9309ffd87c8e 100644 --- a/drivers/tty/serial/pxa.c +++ b/drivers/tty/serial/pxa.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -575,8 +576,6 @@ static struct uart_driver serial_pxa_reg; #ifdef CONFIG_SERIAL_PXA_CONSOLE -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - /* * Wait for transmitter & holding register to empty */ @@ -594,7 +593,7 @@ static void wait_for_xmitr(struct uart_pxa_port *up) if (--tmout == 0) break; udelay(1); - } while ((status & BOTH_EMPTY) != BOTH_EMPTY); + } while (!uart_lsr_tx_empty(status)); /* Wait up to 1s for flow control if necessary */ if (up->port.flags & UPF_CONS_FLOW) { diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c index fff50b5b82eb..84d545e5a8c7 100644 --- a/drivers/tty/serial/sunsu.c +++ b/drivers/tty/serial/sunsu.c @@ -1249,8 +1249,6 @@ static int sunsu_kbd_ms_init(struct uart_sunsu_port *up) #ifdef CONFIG_SERIAL_SUNSU_CONSOLE -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - /* * Wait for transmitter & holding register to empty */ @@ -1268,7 +1266,7 @@ static void wait_for_xmitr(struct uart_sunsu_port *up) if (--tmout == 0) break; udelay(1); - } while ((status & BOTH_EMPTY) != BOTH_EMPTY); + } while (!uart_lsr_tx_empty(status)); /* Wait up to 1s for flow control if necessary */ if (up->port.flags & UPF_CONS_FLOW) { diff --git a/drivers/tty/serial/vr41xx_siu.c b/drivers/tty/serial/vr41xx_siu.c index e0bf003ca3a1..1ba689a81abd 100644 --- a/drivers/tty/serial/vr41xx_siu.c +++ b/drivers/tty/serial/vr41xx_siu.c @@ -703,8 +703,6 @@ static int siu_init_ports(struct platform_device *pdev) #ifdef CONFIG_SERIAL_VR41XX_CONSOLE -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - static void wait_for_xmitr(struct uart_port *port) { int timeout = 10000; @@ -715,7 +713,7 @@ static void wait_for_xmitr(struct uart_port *port) if (lsr & UART_LSR_BI) lsr_break_flag[port->line] = UART_LSR_BI; - if ((lsr & BOTH_EMPTY) == BOTH_EMPTY) + if (uart_lsr_tx_empty(lsr)) break; } while (timeout-- > 0); diff --git a/include/linux/serial.h b/include/linux/serial.h index 70a9866e4abb..3d6fe3ef92cf 100644 --- a/include/linux/serial.h +++ b/include/linux/serial.h @@ -10,10 +10,19 @@ #define _LINUX_SERIAL_H #include +#include /* Helper for dealing with UART_LCR_WLEN* defines */ #define UART_LCR_WLEN(x) ((x) - 5) +/* FIFO and shifting register empty */ +#define UART_LSR_BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) + +static inline bool uart_lsr_tx_empty(u16 lsr) +{ + return (lsr & UART_LSR_BOTH_EMPTY) == UART_LSR_BOTH_EMPTY; +} + /* * Counters of the input lines (CTS, DSR, RI, CD) interrupts */ -- cgit v1.2.3 From f8ba5680a56be696b3f4343ed0a591abab807da4 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Fri, 24 Jun 2022 23:42:05 +0300 Subject: serial: 8250: make saved LSR larger MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DW flags address received as BIT(8) in LSR. In order to not lose that on read, enlarge lsr_saved_flags to u16. Adjust lsr/status variables and related call chains to use u16. Technically, some of these type conversion would not be needed but it doesn't hurt to be consistent. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220624204210.11112-2-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250.h | 4 ++-- drivers/tty/serial/8250/8250_exar.c | 2 +- drivers/tty/serial/8250/8250_fsl.c | 2 +- drivers/tty/serial/8250/8250_ingenic.c | 2 +- drivers/tty/serial/8250/8250_omap.c | 7 +++---- drivers/tty/serial/8250/8250_port.c | 17 +++++++++-------- include/linux/serial_8250.h | 6 +++--- 7 files changed, 20 insertions(+), 20 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index b120da57c61f..0ff5688ba90c 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -133,9 +133,9 @@ static inline void serial_out(struct uart_8250_port *up, int offset, int value) * * Returns LSR value or'ed with the preserved flags (if any). */ -static inline unsigned int serial_lsr_in(struct uart_8250_port *up) +static inline u16 serial_lsr_in(struct uart_8250_port *up) { - unsigned int lsr = up->lsr_saved_flags; + u16 lsr = up->lsr_saved_flags; lsr |= serial_in(up, UART_LSR); up->lsr_saved_flags = lsr & LSR_SAVE_FLAGS; diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index 528779b40049..3d999eec4087 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -195,11 +195,11 @@ static int xr17v35x_startup(struct uart_port *port) static void exar_shutdown(struct uart_port *port) { - unsigned char lsr; bool tx_complete = false; struct uart_8250_port *up = up_to_u8250p(port); struct circ_buf *xmit = &port->state->xmit; int i = 0; + u16 lsr; do { lsr = serial_in(up, UART_LSR); diff --git a/drivers/tty/serial/8250/8250_fsl.c b/drivers/tty/serial/8250/8250_fsl.c index 9c01c531349d..fd4005fcd0d6 100644 --- a/drivers/tty/serial/8250/8250_fsl.c +++ b/drivers/tty/serial/8250/8250_fsl.c @@ -25,8 +25,8 @@ int fsl8250_handle_irq(struct uart_port *port) { - unsigned char lsr, orig_lsr; unsigned long flags; + u16 lsr, orig_lsr; unsigned int iir; struct uart_8250_port *up = up_to_u8250p(port); diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c index cff91aa03f29..2b2f5d8d24b9 100644 --- a/drivers/tty/serial/8250/8250_ingenic.c +++ b/drivers/tty/serial/8250/8250_ingenic.c @@ -54,7 +54,7 @@ static void early_out(struct uart_port *port, int offset, uint8_t value) static void ingenic_early_console_putc(struct uart_port *port, unsigned char c) { - uint8_t lsr; + u16 lsr; do { lsr = early_in(port, UART_LSR); diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index ac8bfa042391..0dcecbbc3967 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -1115,8 +1115,7 @@ static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir) return omap_8250_rx_dma(up); } -static unsigned char omap_8250_handle_rx_dma(struct uart_8250_port *up, - u8 iir, unsigned char status) +static u16 omap_8250_handle_rx_dma(struct uart_8250_port *up, u8 iir, u16 status) { if ((status & (UART_LSR_DR | UART_LSR_BI)) && (iir & UART_IIR_RDI)) { @@ -1130,7 +1129,7 @@ static unsigned char omap_8250_handle_rx_dma(struct uart_8250_port *up, } static void am654_8250_handle_rx_dma(struct uart_8250_port *up, u8 iir, - unsigned char status) + u16 status) { /* * Queue a new transfer if FIFO has data. @@ -1164,7 +1163,7 @@ static int omap_8250_dma_handle_irq(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); struct omap8250_priv *priv = up->port.private_data; - unsigned char status; + u16 status; u8 iir; serial8250_rpm_get(up); diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 55b252954a92..c8ae0e8376d4 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1502,7 +1502,7 @@ static inline void __stop_tx(struct uart_8250_port *p) struct uart_8250_em485 *em485 = p->em485; if (em485) { - unsigned char lsr = serial_lsr_in(p); + u16 lsr = serial_lsr_in(p); u64 stop_delay = 0; p->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; @@ -1563,7 +1563,7 @@ static inline void __start_tx(struct uart_port *port) if (serial8250_set_THRI(up)) { if (up->bugs & UART_BUG_TXEN) { - unsigned char lsr = serial_lsr_in(up); + u16 lsr = serial_lsr_in(up); if (lsr & UART_LSR_THRE) serial8250_tx_chars(up); @@ -1716,7 +1716,7 @@ static void serial8250_enable_ms(struct uart_port *port) serial8250_rpm_put(up); } -void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr) +void serial8250_read_char(struct uart_8250_port *up, u16 lsr) { struct uart_port *port = &up->port; unsigned char ch; @@ -1785,7 +1785,7 @@ EXPORT_SYMBOL_GPL(serial8250_read_char); * (such as THRE) because the LSR value might come from an already consumed * character. */ -unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) +u16 serial8250_rx_chars(struct uart_8250_port *up, u16 lsr) { struct uart_port *port = &up->port; int max_count = 256; @@ -1905,10 +1905,10 @@ static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir) */ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) { - unsigned char status; struct uart_8250_port *up = up_to_u8250p(port); bool skip_rx = false; unsigned long flags; + u16 status; if (iir & UART_IIR_NO_INT) return 0; @@ -1991,7 +1991,7 @@ static unsigned int serial8250_tx_empty(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); unsigned long flags; - unsigned int lsr; + u16 lsr; serial8250_rpm_get(up); @@ -2114,8 +2114,8 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits) static int serial8250_get_poll_char(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); - unsigned char lsr; int status; + u16 lsr; serial8250_rpm_get(up); @@ -2170,8 +2170,9 @@ int serial8250_do_startup(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); unsigned long flags; - unsigned char lsr, iir; + unsigned char iir; int retval; + u16 lsr; if (!port->fifosize) port->fifosize = uart_config[port->type].fifo_size; diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index ff84a3ed10ea..4565f25ba9a2 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -119,7 +119,7 @@ struct uart_8250_port { * be immediately processed. */ #define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS - unsigned char lsr_saved_flags; + u16 lsr_saved_flags; #define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA unsigned char msr_saved_flags; @@ -170,8 +170,8 @@ extern void serial8250_do_set_divisor(struct uart_port *port, unsigned int baud, unsigned int quot_frac); extern int fsl8250_handle_irq(struct uart_port *port); int serial8250_handle_irq(struct uart_port *port, unsigned int iir); -unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr); -void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr); +u16 serial8250_rx_chars(struct uart_8250_port *up, u16 lsr); +void serial8250_read_char(struct uart_8250_port *up, u16 lsr); void serial8250_tx_chars(struct uart_8250_port *up); unsigned int serial8250_modem_status(struct uart_8250_port *up); void serial8250_init_port(struct uart_8250_port *up); -- cgit v1.2.3 From 507bd6fbaaefcb8dd89bd00baddf00b439d30c51 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Fri, 24 Jun 2022 23:42:06 +0300 Subject: serial: 8250: create lsr_save_mask MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow drivers to alter LSR save mask. Reviewed-by: Andy Shevchenko Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220624204210.11112-3-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250.h | 2 +- drivers/tty/serial/8250/8250_core.c | 4 ++++ drivers/tty/serial/8250/8250_dw.c | 2 +- include/linux/serial_8250.h | 1 + 4 files changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 0ff5688ba90c..5cc967fe3b59 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -138,7 +138,7 @@ static inline u16 serial_lsr_in(struct uart_8250_port *up) u16 lsr = up->lsr_saved_flags; lsr |= serial_in(up, UART_LSR); - up->lsr_saved_flags = lsr & LSR_SAVE_FLAGS; + up->lsr_saved_flags = lsr & up->lsr_save_mask; return lsr; } diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 90ddc8924811..57e86133af4f 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -1007,6 +1007,7 @@ int serial8250_register_8250_port(const struct uart_8250_port *up) uart->port.rs485 = up->port.rs485; uart->rs485_start_tx = up->rs485_start_tx; uart->rs485_stop_tx = up->rs485_stop_tx; + uart->lsr_save_mask = up->lsr_save_mask; uart->dma = up->dma; /* Take tx_loadsz from fifosize if it wasn't set separately */ @@ -1094,6 +1095,9 @@ int serial8250_register_8250_port(const struct uart_8250_port *up) ret = 0; } + if (!uart->lsr_save_mask) + uart->lsr_save_mask = LSR_SAVE_FLAGS; /* Use default LSR mask */ + /* Initialise interrupt backoff work if required */ if (up->overrun_backoff_time_ms > 0) { uart->overrun_backoff_time_ms = diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 4cc69bb612ab..167a691c7b19 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -129,7 +129,7 @@ static void dw8250_tx_wait_empty(struct uart_port *p) while (tries--) { lsr = readb (p->membase + (UART_LSR << p->regshift)); - up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; + up->lsr_saved_flags |= lsr & up->lsr_save_mask; if (lsr & UART_LSR_TEMT) break; diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index 4565f25ba9a2..8c7b793aa4d7 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -120,6 +120,7 @@ struct uart_8250_port { */ #define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS u16 lsr_saved_flags; + u16 lsr_save_mask; #define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA unsigned char msr_saved_flags; -- cgit v1.2.3 From 79b3e69fa4a1c796d1002faf70da3280430eab61 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Fri, 24 Jun 2022 23:42:07 +0300 Subject: serial: 8250_lpss: Use 32-bit reads MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use 32-bit reads in order to not lose higher bits of DW UART regs. This change does not fix any known issue as the high bits are not used for anything related to 8250 driver (dw8250_readl_ext and dw8250_writel_ext used within the dwlib are already doing readl/writel/ioread32be/iowrite32be anyway). This change is necessary to enables 9th bit address mode. DW UART reports address frames with BIT(8) of LSR. Reviewed-by: Andy Shevchenko Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220624204210.11112-4-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_lpss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_lpss.c b/drivers/tty/serial/8250/8250_lpss.c index 0f5af061e0b4..4ba43bef9933 100644 --- a/drivers/tty/serial/8250/8250_lpss.c +++ b/drivers/tty/serial/8250/8250_lpss.c @@ -330,7 +330,7 @@ static int lpss8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) uart.port.irq = pci_irq_vector(pdev, 0); uart.port.private_data = &lpss->data; uart.port.type = PORT_16550A; - uart.port.iotype = UPIO_MEM; + uart.port.iotype = UPIO_MEM32; uart.port.regshift = 2; uart.port.uartclk = lpss->board->base_baud * 16; uart.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE; -- cgit v1.2.3 From ae50bb2752836277ae15aa4e9d99074d6d947946 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Fri, 24 Jun 2022 23:42:08 +0300 Subject: serial: take termios_rwsem for ->rs485_config() & pass termios as param MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To be able to alter ADDRB within ->rs485_config(), take termios_rwsem before calling ->rs485_config() and pass termios. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220624204210.11112-5-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250.h | 3 ++- drivers/tty/serial/8250/8250_dwlib.c | 3 ++- drivers/tty/serial/8250/8250_exar.c | 9 +++++---- drivers/tty/serial/8250/8250_fintek.c | 2 +- drivers/tty/serial/8250/8250_lpc18xx.c | 2 +- drivers/tty/serial/8250/8250_pci.c | 2 +- drivers/tty/serial/8250/8250_port.c | 3 ++- drivers/tty/serial/amba-pl011.c | 2 +- drivers/tty/serial/ar933x_uart.c | 2 +- drivers/tty/serial/atmel_serial.c | 2 +- drivers/tty/serial/fsl_lpuart.c | 4 ++-- drivers/tty/serial/imx.c | 2 +- drivers/tty/serial/max310x.c | 2 +- drivers/tty/serial/mcf.c | 3 ++- drivers/tty/serial/omap-serial.c | 3 ++- drivers/tty/serial/sc16is7xx.c | 2 +- drivers/tty/serial/serial_core.c | 14 ++++++++++---- drivers/tty/serial/stm32-usart.c | 2 +- include/linux/serial_core.h | 1 + 19 files changed, 38 insertions(+), 25 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 5cc967fe3b59..287153d32536 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -203,7 +203,8 @@ void serial8250_rpm_put(struct uart_8250_port *p); void serial8250_rpm_get_tx(struct uart_8250_port *p); void serial8250_rpm_put_tx(struct uart_8250_port *p); -int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485); +int serial8250_em485_config(struct uart_port *port, struct ktermios *termios, + struct serial_rs485 *rs485); void serial8250_em485_start_tx(struct uart_8250_port *p); void serial8250_em485_stop_tx(struct uart_8250_port *p); void serial8250_em485_destroy(struct uart_8250_port *p); diff --git a/drivers/tty/serial/8250/8250_dwlib.c b/drivers/tty/serial/8250/8250_dwlib.c index c83e7eaf3877..d1ff3daeb0ba 100644 --- a/drivers/tty/serial/8250/8250_dwlib.c +++ b/drivers/tty/serial/8250/8250_dwlib.c @@ -85,7 +85,8 @@ void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios, struct } EXPORT_SYMBOL_GPL(dw8250_do_set_termios); -static int dw8250_rs485_config(struct uart_port *p, struct serial_rs485 *rs485) +static int dw8250_rs485_config(struct uart_port *p, struct ktermios *termios, + struct serial_rs485 *rs485) { u32 tcr; diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index 3d999eec4087..f5344cfe303c 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -112,7 +112,8 @@ struct exar8250; struct exar8250_platform { - int (*rs485_config)(struct uart_port *, struct serial_rs485 *); + int (*rs485_config)(struct uart_port *port, struct ktermios *termios, + struct serial_rs485 *rs485); const struct serial_rs485 *rs485_supported; int (*register_gpio)(struct pci_dev *, struct uart_8250_port *); void (*unregister_gpio)(struct uart_8250_port *); @@ -409,7 +410,7 @@ static void xr17v35x_unregister_gpio(struct uart_8250_port *port) port->port.private_data = NULL; } -static int generic_rs485_config(struct uart_port *port, +static int generic_rs485_config(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485) { bool is_rs485 = !!(rs485->flags & SER_RS485_ENABLED); @@ -441,7 +442,7 @@ static const struct exar8250_platform exar8250_default_platform = { .rs485_supported = &generic_rs485_supported, }; -static int iot2040_rs485_config(struct uart_port *port, +static int iot2040_rs485_config(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485) { bool is_rs485 = !!(rs485->flags & SER_RS485_ENABLED); @@ -471,7 +472,7 @@ static int iot2040_rs485_config(struct uart_port *port, value |= mode; writeb(value, p + UART_EXAR_MPIOLVL_7_0); - return generic_rs485_config(port, rs485); + return generic_rs485_config(port, termios, rs485); } static const struct serial_rs485 iot2040_rs485_supported = { diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c index 1fb86c73786c..eea693f5b577 100644 --- a/drivers/tty/serial/8250/8250_fintek.c +++ b/drivers/tty/serial/8250/8250_fintek.c @@ -191,7 +191,7 @@ static int fintek_8250_get_ldn_range(struct fintek_8250 *pdata, int *min, return -ENODEV; } -static int fintek_8250_rs485_config(struct uart_port *port, +static int fintek_8250_rs485_config(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485) { uint8_t config = 0; diff --git a/drivers/tty/serial/8250/8250_lpc18xx.c b/drivers/tty/serial/8250/8250_lpc18xx.c index 3a1cb51cbc91..d7cb3bb52069 100644 --- a/drivers/tty/serial/8250/8250_lpc18xx.c +++ b/drivers/tty/serial/8250/8250_lpc18xx.c @@ -32,7 +32,7 @@ struct lpc18xx_uart_data { int line; }; -static int lpc18xx_rs485_config(struct uart_port *port, +static int lpc18xx_rs485_config(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485) { struct uart_8250_port *up = up_to_u8250p(port); diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index b6d71268aa7d..d31d2350a9db 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1553,7 +1553,7 @@ pci_brcm_trumanage_setup(struct serial_private *priv, #define FINTEK_RTS_INVERT BIT(5) /* We should do proper H/W transceiver setting before change to RS485 mode */ -static int pci_fintek_rs485_config(struct uart_port *port, +static int pci_fintek_rs485_config(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485) { struct pci_dev *pci_dev = to_pci_dev(port->dev); diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index c8ae0e8376d4..d4337d8346c8 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -664,7 +664,8 @@ EXPORT_SYMBOL_GPL(serial8250_em485_supported); * if the uart is incapable of driving RTS as a Transmit Enable signal in * hardware, relying on software emulation instead. */ -int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485) +int serial8250_em485_config(struct uart_port *port, struct ktermios *termios, + struct serial_rs485 *rs485) { struct uart_8250_port *up = up_to_u8250p(port); diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index eccd66625d25..c8f52945a4aa 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -2197,7 +2197,7 @@ static int pl011_verify_port(struct uart_port *port, struct serial_struct *ser) return ret; } -static int pl011_rs485_config(struct uart_port *port, +static int pl011_rs485_config(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485) { struct uart_amba_port *uap = diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c index ab2c5b2a1ce8..b73ce13683db 100644 --- a/drivers/tty/serial/ar933x_uart.c +++ b/drivers/tty/serial/ar933x_uart.c @@ -580,7 +580,7 @@ static const struct uart_ops ar933x_uart_ops = { .verify_port = ar933x_uart_verify_port, }; -static int ar933x_config_rs485(struct uart_port *port, +static int ar933x_config_rs485(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485conf) { struct ar933x_uart_port *up = diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 3a94c2bdda72..bc6004679585 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -283,7 +283,7 @@ static void atmel_tasklet_schedule(struct atmel_uart_port *atmel_port, } /* Enable or disable the rs485 support */ -static int atmel_config_rs485(struct uart_port *port, +static int atmel_config_rs485(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485conf) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index d35414cb3e4e..8fe0494d4057 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -1355,7 +1355,7 @@ static void lpuart_dma_rx_free(struct uart_port *port) sport->dma_rx_cookie = -EINVAL; } -static int lpuart_config_rs485(struct uart_port *port, +static int lpuart_config_rs485(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485) { struct lpuart_port *sport = container_of(port, @@ -1385,7 +1385,7 @@ static int lpuart_config_rs485(struct uart_port *port, return 0; } -static int lpuart32_config_rs485(struct uart_port *port, +static int lpuart32_config_rs485(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485) { struct lpuart_port *sport = container_of(port, diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index f4edde54175f..3457006cea3f 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -1907,7 +1907,7 @@ static void imx_uart_poll_put_char(struct uart_port *port, unsigned char c) #endif /* called with port.lock taken and irqs off or from .probe without locking */ -static int imx_uart_rs485_config(struct uart_port *port, +static int imx_uart_rs485_config(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485conf) { struct imx_port *sport = (struct imx_port *)port; diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 4915a786e315..e162bfb44080 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1036,7 +1036,7 @@ static void max310x_rs_proc(struct work_struct *ws) MAX310X_MODE2_ECHOSUPR_BIT, mode2); } -static int max310x_rs485_config(struct uart_port *port, +static int max310x_rs485_config(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485) { struct max310x_one *one = to_max310x_port(port); diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c index 036f178e3d66..73c5287b8e5e 100644 --- a/drivers/tty/serial/mcf.c +++ b/drivers/tty/serial/mcf.c @@ -431,7 +431,8 @@ static int mcf_verify_port(struct uart_port *port, struct serial_struct *ser) /****************************************************************************/ /* Enable or disable the RS485 support */ -static int mcf_config_rs485(struct uart_port *port, struct serial_rs485 *rs485) +static int mcf_config_rs485(struct uart_port *port, struct ktermios *termios, + struct serial_rs485 *rs485) { unsigned char mr1, mr2; diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 52cb1a68b053..196bae704f85 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -1324,7 +1324,8 @@ static inline void serial_omap_add_console_port(struct uart_omap_port *up) /* Enable or disable the rs485 support */ static int -serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485) +serial_omap_config_rs485(struct uart_port *port, struct ktermios *termios, + struct serial_rs485 *rs485) { struct uart_omap_port *up = to_uart_omap_port(port); unsigned int mode; diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 2ceecaa4a478..8cb92a3b3fb8 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -1127,7 +1127,7 @@ static void sc16is7xx_set_termios(struct uart_port *port, spin_unlock_irqrestore(&port->lock, flags); } -static int sc16is7xx_config_rs485(struct uart_port *port, +static int sc16is7xx_config_rs485(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485) { struct sc16is7xx_port *s = dev_get_drvdata(port->dev); diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 75ece750bedc..2529153c8979 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1353,7 +1353,7 @@ int uart_rs485_config(struct uart_port *port) uart_sanitize_serial_rs485(port, rs485); - ret = port->rs485_config(port, rs485); + ret = port->rs485_config(port, NULL, rs485); if (ret) memset(rs485, 0, sizeof(*rs485)); @@ -1377,7 +1377,7 @@ static int uart_get_rs485_config(struct uart_port *port, return 0; } -static int uart_set_rs485_config(struct uart_port *port, +static int uart_set_rs485_config(struct tty_struct *tty, struct uart_port *port, struct serial_rs485 __user *rs485_user) { struct serial_rs485 rs485; @@ -1396,7 +1396,7 @@ static int uart_set_rs485_config(struct uart_port *port, uart_sanitize_serial_rs485(port, &rs485); spin_lock_irqsave(&port->lock, flags); - ret = port->rs485_config(port, &rs485); + ret = port->rs485_config(port, &tty->termios, &rs485); if (!ret) port->rs485 = rs485; spin_unlock_irqrestore(&port->lock, flags); @@ -1505,6 +1505,10 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) if (ret != -ENOIOCTLCMD) goto out; + /* rs485_config requires more locking than others */ + if (cmd == TIOCGRS485) + down_write(&tty->termios_rwsem); + mutex_lock(&port->mutex); uport = uart_port_check(state); @@ -1528,7 +1532,7 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) break; case TIOCSRS485: - ret = uart_set_rs485_config(uport, uarg); + ret = uart_set_rs485_config(tty, uport, uarg); break; case TIOCSISO7816: @@ -1545,6 +1549,8 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) } out_up: mutex_unlock(&port->mutex); + if (cmd == TIOCGRS485) + up_write(&tty->termios_rwsem); out: return ret; } diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index db3dd9731ee1..13992e64a7df 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -97,7 +97,7 @@ static void stm32_usart_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE, *cr1 |= rs485_deat_dedt; } -static int stm32_usart_config_rs485(struct uart_port *port, +static int stm32_usart_config_rs485(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485conf) { struct stm32_port *stm32_port = to_stm32_port(port); diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index faaf2372c60d..b7b86ee3cb12 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -133,6 +133,7 @@ struct uart_port { unsigned int old); void (*handle_break)(struct uart_port *); int (*rs485_config)(struct uart_port *, + struct ktermios *termios, struct serial_rs485 *rs485); int (*iso7816_config)(struct uart_port *, struct serial_iso7816 *iso7816); -- cgit v1.2.3 From 4f768e94774c58c9f7f54ebd38dadf172970046a Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Fri, 24 Jun 2022 23:42:09 +0300 Subject: serial: Support for RS-485 multipoint addresses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for RS-485 multipoint addressing using 9th bit [*]. The addressing mode is configured through ->rs485_config(). ADDRB in termios indicates 9th bit addressing mode is enabled. In this mode, 9th bit is used to indicate an address (byte) within the communication line. ADDRB can only be enabled/disabled through ->rs485_config() that is also responsible for setting the destination and receiver (filter) addresses. Add traps to detect unwanted changes to struct serial_rs485 layout using static_assert(). [*] Technically, RS485 is just an electronic spec and does not itself specify the 9th bit addressing mode but 9th bit seems at least "semi-standard" way to do addressing with RS485. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220624204210.11112-6-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/serial/driver.rst | 2 ++ Documentation/driver-api/serial/serial-rs485.rst | 26 +++++++++++++++++++++++- drivers/tty/serial/serial_core.c | 22 +++++++++++++++++++- drivers/tty/tty_ioctl.c | 4 ++++ include/uapi/asm-generic/termbits-common.h | 1 + include/uapi/linux/serial.h | 20 ++++++++++++++++-- 6 files changed, 71 insertions(+), 4 deletions(-) (limited to 'drivers/tty') diff --git a/Documentation/driver-api/serial/driver.rst b/Documentation/driver-api/serial/driver.rst index 1e7ab4142d49..ee1679858aa2 100644 --- a/Documentation/driver-api/serial/driver.rst +++ b/Documentation/driver-api/serial/driver.rst @@ -261,6 +261,8 @@ hardware. - parity enable PARODD - odd parity (when PARENB is in force) + ADDRB + - address bit (changed through .rs485_config()). CREAD - enable reception of characters (if not set, still receive characters from the port, but diff --git a/Documentation/driver-api/serial/serial-rs485.rst b/Documentation/driver-api/serial/serial-rs485.rst index 00b5d333acba..6ebad75c74ed 100644 --- a/Documentation/driver-api/serial/serial-rs485.rst +++ b/Documentation/driver-api/serial/serial-rs485.rst @@ -99,7 +99,31 @@ RS485 Serial Communications /* Error handling. See errno. */ } -5. References +5. Multipoint Addressing +======================== + + The Linux kernel provides addressing mode for multipoint RS-485 serial + communications line. The addressing mode is enabled with SER_RS485_ADDRB + flag in serial_rs485. Struct serial_rs485 has two additional flags and + fields for enabling receive and destination addresses. + + Address mode flags: + - SER_RS485_ADDRB: Enabled addressing mode (sets also ADDRB in termios). + - SER_RS485_ADDR_RECV: Receive (filter) address enabled. + - SER_RS485_ADDR_DEST: Set destination address. + + Address fields (enabled with corresponding SER_RS485_ADDR_* flag): + - addr_recv: Receive address. + - addr_dest: Destination address. + + Once a receive address is set, the communication can occur only with the + particular device and other peers are filtered out. It is left up to the + receiver side to enforce the filtering. Receive address will be cleared + if SER_RS485_ADDR_RECV is not set. + + Note: not all devices supporting RS485 support multipoint addressing. + +6. References ============= [1] include/uapi/linux/serial.h diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 2529153c8979..85ef7ef00b82 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1288,6 +1288,17 @@ static int uart_check_rs485_flags(struct uart_port *port, struct serial_rs485 *r if (flags & ~port->rs485_supported->flags) return -EINVAL; + /* Asking for address w/o addressing mode? */ + if (!(rs485->flags & SER_RS485_ADDRB) && + (rs485->flags & (SER_RS485_ADDR_RECV|SER_RS485_ADDR_DEST))) + return -EINVAL; + + /* Address given but not enabled? */ + if (!(rs485->flags & SER_RS485_ADDR_RECV) && rs485->addr_recv) + return -EINVAL; + if (!(rs485->flags & SER_RS485_ADDR_DEST) && rs485->addr_dest) + return -EINVAL; + return 0; } @@ -1343,7 +1354,8 @@ static void uart_sanitize_serial_rs485(struct uart_port *port, struct serial_rs4 rs485->flags &= supported_flags; /* Return clean padding area to userspace */ - memset(rs485->padding, 0, sizeof(rs485->padding)); + memset(rs485->padding0, 0, sizeof(rs485->padding0)); + memset(rs485->padding1, 0, sizeof(rs485->padding1)); } int uart_rs485_config(struct uart_port *port) @@ -3402,5 +3414,13 @@ int uart_get_rs485_mode(struct uart_port *port) } EXPORT_SYMBOL_GPL(uart_get_rs485_mode); +/* Compile-time assertions for serial_rs485 layout */ +static_assert(offsetof(struct serial_rs485, padding) == + (offsetof(struct serial_rs485, delay_rts_after_send) + sizeof(__u32))); +static_assert(offsetof(struct serial_rs485, padding1) == + offsetof(struct serial_rs485, padding[1])); +static_assert((offsetof(struct serial_rs485, padding[4]) + sizeof(__u32)) == + sizeof(struct serial_rs485)); + MODULE_DESCRIPTION("Serial driver core"); MODULE_LICENSE("GPL"); diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index adae687f654b..2a76b330e108 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -319,6 +319,8 @@ unsigned char tty_get_frame_size(unsigned int cflag) bits++; if (cflag & PARENB) bits++; + if (cflag & ADDRB) + bits++; return bits; } @@ -353,6 +355,8 @@ int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios) old_termios = tty->termios; tty->termios = *new_termios; unset_locked_termios(tty, &old_termios); + /* Reset any ADDRB changes, ADDRB is changed through ->rs485_config() */ + tty->termios.c_cflag ^= (tty->termios.c_cflag ^ old_termios.c_cflag) & ADDRB; if (tty->ops->set_termios) tty->ops->set_termios(tty, &old_termios); diff --git a/include/uapi/asm-generic/termbits-common.h b/include/uapi/asm-generic/termbits-common.h index 4d084fe8def5..4a6a79f28b21 100644 --- a/include/uapi/asm-generic/termbits-common.h +++ b/include/uapi/asm-generic/termbits-common.h @@ -46,6 +46,7 @@ typedef unsigned int speed_t; #define EXTA B19200 #define EXTB B38400 +#define ADDRB 0x20000000 /* address bit */ #define CMSPAR 0x40000000 /* mark or space (stick) parity */ #define CRTSCTS 0x80000000 /* flow control */ diff --git a/include/uapi/linux/serial.h b/include/uapi/linux/serial.h index fa6b16e5fdd8..cea06924b295 100644 --- a/include/uapi/linux/serial.h +++ b/include/uapi/linux/serial.h @@ -126,10 +126,26 @@ struct serial_rs485 { #define SER_RS485_TERMINATE_BUS (1 << 5) /* Enable bus termination (if supported) */ + +/* RS-485 addressing mode */ +#define SER_RS485_ADDRB (1 << 6) /* Enable addressing mode */ +#define SER_RS485_ADDR_RECV (1 << 7) /* Receive address filter */ +#define SER_RS485_ADDR_DEST (1 << 8) /* Destination address */ + __u32 delay_rts_before_send; /* Delay before send (milliseconds) */ __u32 delay_rts_after_send; /* Delay after send (milliseconds) */ - __u32 padding[5]; /* Memory is cheap, new structs - are a royal PITA .. */ + + /* The fields below are defined by flags */ + union { + __u32 padding[5]; /* Memory is cheap, new structs are a pain */ + + struct { + __u8 addr_recv; + __u8 addr_dest; + __u8 padding0[2]; + __u32 padding1[4]; + }; + }; }; /* -- cgit v1.2.3 From f287f971e2569827fe9fb3a8d55a37703a13cf29 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Fri, 24 Jun 2022 23:42:10 +0300 Subject: serial: 8250_dwlib: Support for 9th bit multipoint addressing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add 9th bit multipoint addressing mode for DW UART. 9th bit addressing can be used only when HW RS485 is available. Updating RAR (receive address register) is bit tricky because busy indication is not be available when DW UART is strictly 16550 compatible, which is the case with the hardware I was testing with. RAR should not be updated while receive is in progress which is now achieved by deasserting RE and waiting for one frame (in case rx would be in progress, the driver seems to have no way of knowing it w/o busy indication). Because of this complexity, it's better to avoid doing it unless really needed. Co-developed-by: Heikki Krogerus Co-developed-by: Andy Shevchenko Co-developed-by: Raymond Tan Co-developed-by: Lakshmi Sowjanya Signed-off-by: Heikki Krogerus Signed-off-by: Andy Shevchenko Signed-off-by: Raymond Tan Signed-off-by: Lakshmi Sowjanya Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220624204210.11112-7-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dwlib.c | 102 ++++++++++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_dwlib.c b/drivers/tty/serial/8250/8250_dwlib.c index d1ff3daeb0ba..da330ef46446 100644 --- a/drivers/tty/serial/8250/8250_dwlib.c +++ b/drivers/tty/serial/8250/8250_dwlib.c @@ -3,8 +3,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -16,9 +18,18 @@ #define DW_UART_DE_EN 0xb0 /* Driver Output Enable Register */ #define DW_UART_RE_EN 0xb4 /* Receiver Output Enable Register */ #define DW_UART_DLF 0xc0 /* Divisor Latch Fraction Register */ +#define DW_UART_RAR 0xc4 /* Receive Address Register */ +#define DW_UART_TAR 0xc8 /* Transmit Address Register */ +#define DW_UART_LCR_EXT 0xcc /* Line Extended Control Register */ #define DW_UART_CPR 0xf4 /* Component Parameter Register */ #define DW_UART_UCV 0xf8 /* UART Component Version */ +/* Receive / Transmit Address Register bits */ +#define DW_UART_ADDR_MASK GENMASK(7, 0) + +/* Line Status Register bits */ +#define DW_UART_LSR_ADDR_RCVD BIT(8) + /* Transceiver Control Register bits */ #define DW_UART_TCR_RS485_EN BIT(0) #define DW_UART_TCR_RE_POL BIT(1) @@ -28,6 +39,12 @@ #define DW_UART_TCR_XFER_MODE_SW_DE_OR_RE FIELD_PREP(DW_UART_TCR_XFER_MODE, 1) #define DW_UART_TCR_XFER_MODE_DE_OR_RE FIELD_PREP(DW_UART_TCR_XFER_MODE, 2) +/* Line Extended Control Register bits */ +#define DW_UART_LCR_EXT_DLS_E BIT(0) +#define DW_UART_LCR_EXT_ADDR_MATCH BIT(1) +#define DW_UART_LCR_EXT_SEND_ADDR BIT(2) +#define DW_UART_LCR_EXT_TRANSMIT_MODE BIT(3) + /* Component Parameter Register bits */ #define DW_UART_CPR_ABP_DATA_WIDTH (3 << 0) #define DW_UART_CPR_AFCE_MODE (1 << 4) @@ -82,9 +99,83 @@ void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios, struct p->status |= UPSTAT_AUTOCTS; serial8250_do_set_termios(p, termios, old); + + /* Filter addresses which have 9th bit set */ + p->ignore_status_mask |= DW_UART_LSR_ADDR_RCVD; + p->read_status_mask |= DW_UART_LSR_ADDR_RCVD; } EXPORT_SYMBOL_GPL(dw8250_do_set_termios); +/* + * Wait until re is de-asserted for sure. An ongoing receive will keep + * re asserted until end of frame. Without BUSY indication available, + * only available course of action is to wait for the time it takes to + * receive one frame (there might nothing to receive but w/o BUSY the + * driver cannot know). + */ +static void dw8250_wait_re_deassert(struct uart_port *p) +{ + ndelay(p->frame_time); +} + +static void dw8250_update_rar(struct uart_port *p, u32 addr) +{ + u32 re_en = dw8250_readl_ext(p, DW_UART_RE_EN); + + /* + * RAR shouldn't be changed while receiving. Thus, de-assert RE_EN + * if asserted and wait. + */ + if (re_en) + dw8250_writel_ext(p, DW_UART_RE_EN, 0); + dw8250_wait_re_deassert(p); + dw8250_writel_ext(p, DW_UART_RAR, addr); + if (re_en) + dw8250_writel_ext(p, DW_UART_RE_EN, re_en); +} + +static void dw8250_rs485_set_addr(struct uart_port *p, struct serial_rs485 *rs485, + struct ktermios *termios) +{ + u32 lcr = dw8250_readl_ext(p, DW_UART_LCR_EXT); + + if (rs485->flags & SER_RS485_ADDRB) { + lcr |= DW_UART_LCR_EXT_DLS_E; + if (termios) + termios->c_cflag |= ADDRB; + + if (rs485->flags & SER_RS485_ADDR_RECV) { + u32 delta = p->rs485.flags ^ rs485->flags; + + /* + * rs485 (param) is equal to uart_port's rs485 only during init + * (during init, delta is not yet applicable). + */ + if (unlikely(&p->rs485 == rs485)) + delta = rs485->flags; + + if ((delta & SER_RS485_ADDR_RECV) || + (p->rs485.addr_recv != rs485->addr_recv)) + dw8250_update_rar(p, rs485->addr_recv); + lcr |= DW_UART_LCR_EXT_ADDR_MATCH; + } else { + lcr &= ~DW_UART_LCR_EXT_ADDR_MATCH; + } + if (rs485->flags & SER_RS485_ADDR_DEST) { + /* + * Don't skip writes here as another endpoint could + * have changed communication line's destination + * address in between. + */ + dw8250_writel_ext(p, DW_UART_TAR, rs485->addr_dest); + lcr |= DW_UART_LCR_EXT_SEND_ADDR; + } + } else { + lcr = 0; + } + dw8250_writel_ext(p, DW_UART_LCR_EXT, lcr); +} + static int dw8250_rs485_config(struct uart_port *p, struct ktermios *termios, struct serial_rs485 *rs485) { @@ -109,6 +200,9 @@ static int dw8250_rs485_config(struct uart_port *p, struct ktermios *termios, dw8250_writel_ext(p, DW_UART_DE_EN, 1); dw8250_writel_ext(p, DW_UART_RE_EN, 1); } else { + if (termios) + termios->c_cflag &= ~ADDRB; + tcr &= ~DW_UART_TCR_RS485_EN; } @@ -123,6 +217,10 @@ static int dw8250_rs485_config(struct uart_port *p, struct ktermios *termios, dw8250_writel_ext(p, DW_UART_TCR, tcr); + /* Addressing mode can only be set up after TCR */ + if (rs485->flags & SER_RS485_ENABLED) + dw8250_rs485_set_addr(p, rs485, termios); + return 0; } @@ -142,7 +240,8 @@ static bool dw8250_detect_rs485_hw(struct uart_port *p) static const struct serial_rs485 dw8250_rs485_supported = { .flags = SER_RS485_ENABLED | SER_RS485_RX_DURING_TX | SER_RS485_RTS_ON_SEND | - SER_RS485_RTS_AFTER_SEND, + SER_RS485_RTS_AFTER_SEND | SER_RS485_ADDRB | SER_RS485_ADDR_RECV | + SER_RS485_ADDR_DEST, }; void dw8250_setup_port(struct uart_port *p) @@ -155,6 +254,7 @@ void dw8250_setup_port(struct uart_port *p) pd->hw_rs485_support = dw8250_detect_rs485_hw(p); if (pd->hw_rs485_support) { p->rs485_config = dw8250_rs485_config; + up->lsr_save_mask = LSR_SAVE_FLAGS | DW_UART_LSR_ADDR_RCVD; p->rs485_supported = &dw8250_rs485_supported; } else { p->rs485_config = serial8250_em485_config; -- cgit v1.2.3 From 9636047ffafcf5988946c05f0ebd7e0b2114aa74 Mon Sep 17 00:00:00 2001 From: Chanho Park Date: Wed, 29 Jun 2022 09:55:38 +0900 Subject: tty: serial: samsung_tty: support more than 4 uart ports Regarding Exynos Auto v9 SoC, it supports uarts up to 12. However, the maximum number of the ports has been derived from CONFIG_SERIAL_SAMSUNG_UARTS and tightly coupled with the config for previous Samsung SoCs such as s3c24xx and s3c64xx. To overcome this limitation, this changes the usage of the definition to UART_NR which is widely used from other serial drivers. This also defines the value to 12 only for ARM64 SoCs to not affect the change to previous arm32 SoCs. Instead of enumerating all the ports as predefined arrays, this introduces s3c24xx_serial_init_port_default that is initializing the structure as the default value. Reviewed-by: Hector Martin Reviewed-by: Krzysztof Kozlowski Signed-off-by: Chanho Park Link: https://lore.kernel.org/r/20220629005538.60132-1-chanho61.park@samsung.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 82 ++++++++++++---------------------------- 1 file changed, 25 insertions(+), 57 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index d5ca904def34..3e0aa2923605 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -48,6 +48,12 @@ #define S3C24XX_SERIAL_MAJOR 204 #define S3C24XX_SERIAL_MINOR 64 +#ifdef CONFIG_ARM64 +#define UART_NR 12 +#else +#define UART_NR CONFIG_SERIAL_SAMSUNG_UARTS +#endif + #define S3C24XX_TX_PIO 1 #define S3C24XX_TX_DMA 2 #define S3C24XX_RX_PIO 1 @@ -87,7 +93,7 @@ struct s3c24xx_uart_info { struct s3c24xx_serial_drv_data { const struct s3c24xx_uart_info info; const struct s3c2410_uartcfg def_cfg; - const unsigned int fifosize[CONFIG_SERIAL_SAMSUNG_UARTS]; + const unsigned int fifosize[UART_NR]; }; struct s3c24xx_uart_dma { @@ -1802,67 +1808,27 @@ static const struct uart_ops apple_s5l_serial_ops = { static struct uart_driver s3c24xx_uart_drv = { .owner = THIS_MODULE, .driver_name = "s3c2410_serial", - .nr = CONFIG_SERIAL_SAMSUNG_UARTS, + .nr = UART_NR, .cons = S3C24XX_SERIAL_CONSOLE, .dev_name = S3C24XX_SERIAL_NAME, .major = S3C24XX_SERIAL_MAJOR, .minor = S3C24XX_SERIAL_MINOR, }; -#define __PORT_LOCK_UNLOCKED(i) \ - __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[i].port.lock) -static struct s3c24xx_uart_port -s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = { - [0] = { - .port = { - .lock = __PORT_LOCK_UNLOCKED(0), - .iotype = UPIO_MEM, - .uartclk = 0, - .fifosize = 16, - .ops = &s3c24xx_serial_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - } - }, - [1] = { - .port = { - .lock = __PORT_LOCK_UNLOCKED(1), - .iotype = UPIO_MEM, - .uartclk = 0, - .fifosize = 16, - .ops = &s3c24xx_serial_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 1, - } - }, -#if CONFIG_SERIAL_SAMSUNG_UARTS > 2 - [2] = { - .port = { - .lock = __PORT_LOCK_UNLOCKED(2), - .iotype = UPIO_MEM, - .uartclk = 0, - .fifosize = 16, - .ops = &s3c24xx_serial_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 2, - } - }, -#endif -#if CONFIG_SERIAL_SAMSUNG_UARTS > 3 - [3] = { - .port = { - .lock = __PORT_LOCK_UNLOCKED(3), - .iotype = UPIO_MEM, - .uartclk = 0, - .fifosize = 16, - .ops = &s3c24xx_serial_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 3, - } - } -#endif -}; -#undef __PORT_LOCK_UNLOCKED +static struct s3c24xx_uart_port s3c24xx_serial_ports[UART_NR]; + +static void s3c24xx_serial_init_port_default(int index) { + struct uart_port *port = &s3c24xx_serial_ports[index].port; + + spin_lock_init(&port->lock); + + port->iotype = UPIO_MEM; + port->uartclk = 0; + port->fifosize = 16; + port->ops = &s3c24xx_serial_ops; + port->flags = UPF_BOOT_AUTOCONF; + port->line = index; +} /* s3c24xx_serial_resetport * @@ -2178,6 +2144,8 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) } ourport = &s3c24xx_serial_ports[index]; + s3c24xx_serial_init_port_default(index); + ourport->drv_data = s3c24xx_get_driver_data(pdev); if (!ourport->drv_data) { dev_err(&pdev->dev, "could not find driver data\n"); @@ -2576,7 +2544,7 @@ s3c24xx_serial_console_setup(struct console *co, char *options) /* is this a valid port */ - if (co->index == -1 || co->index >= CONFIG_SERIAL_SAMSUNG_UARTS) + if (co->index == -1 || co->index >= UART_NR) co->index = 0; port = &s3c24xx_serial_ports[co->index].port; -- cgit v1.2.3 From 72a43046b61a3fe7164a622224bcdfc3cf6b795d Mon Sep 17 00:00:00 2001 From: Chanho Park Date: Wed, 29 Jun 2022 09:41:41 +0900 Subject: tty: serial: samsung_tty: loopback mode support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Internal loopback mode can be supported by setting UCON register's Loopback Mode bit. The mode & bit can be supported since s3c2410 and later SoCs. The prefix of LOOPBACK / BIT(5) naming should be also changed to S3C2410_ in order to avoid confusion. Reviewed-by: Krzysztof Kozlowski Reviewed-by: Ilpo Järvinen Signed-off-by: Chanho Park Link: https://lore.kernel.org/r/20220629004141.51484-1-chanho61.park@samsung.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 8 ++++++++ include/linux/serial_s3c.h | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 3e0aa2923605..8971fbb49fa3 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -1018,6 +1018,7 @@ 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_reg(port, S3C2410_UCON); if (mctrl & TIOCM_RTS) umcon |= S3C2410_UMCOM_RTS_LOW; @@ -1025,6 +1026,13 @@ static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl) umcon &= ~S3C2410_UMCOM_RTS_LOW; wr_regl(port, S3C2410_UMCON, umcon); + + if (mctrl & TIOCM_LOOP) + ucon |= S3C2410_UCON_LOOPBACK; + else + ucon &= ~S3C2410_UCON_LOOPBACK; + + wr_regl(port, S3C2410_UCON, ucon); } static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state) diff --git a/include/linux/serial_s3c.h b/include/linux/serial_s3c.h index dec15f5b3dec..1672cf0810ef 100644 --- a/include/linux/serial_s3c.h +++ b/include/linux/serial_s3c.h @@ -83,7 +83,7 @@ #define S3C2410_UCON_RXIRQMODE (1<<0) #define S3C2410_UCON_RXFIFO_TOI (1<<7) #define S3C2443_UCON_RXERR_IRQEN (1<<6) -#define S3C2443_UCON_LOOPBACK (1<<5) +#define S3C2410_UCON_LOOPBACK (1<<5) #define S3C2410_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \ S3C2410_UCON_RXILEVEL | \ -- cgit v1.2.3 From 137b2d985928890557f8e73cf7e53677637b7af8 Mon Sep 17 00:00:00 2001 From: Zhang Jiaming Date: Wed, 29 Jun 2022 17:44:11 +0800 Subject: serial: 8250_port: Fix spelling mistake MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change 'timeing' to 'timing'. Change 'Characteres' to 'Characters'. Reviewed-by: Ilpo Järvinen Signed-off-by: Zhang Jiaming Link: https://lore.kernel.org/r/20220629094411.39066-1-jiaming@nfschina.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index d4337d8346c8..ed2a606f2da7 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1511,7 +1511,7 @@ static inline void __stop_tx(struct uart_8250_port *p) if (!(lsr & UART_LSR_THRE)) return; /* - * To provide required timeing and allow FIFO transfer, + * To provide required timing and allow FIFO transfer, * __stop_tx_rs485() must be called only when both FIFO and * shift register are empty. The device driver should either * enable interrupt on TEMT or set UART_CAP_NOTEMT that will @@ -2798,7 +2798,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, port->read_status_mask |= UART_LSR_BI; /* - * Characteres to ignore + * Characters to ignore */ port->ignore_status_mask = 0; if (termios->c_iflag & IGNPAR) -- cgit v1.2.3 From b9491b2e45d71eb64245560e208897af95ffbf95 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Tue, 28 Jun 2022 12:01:28 +0300 Subject: serial: 8250_dw: Take port lock while accessing LSR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Accessing LSR requires port lock because it mutates lsr_saved_flags in serial_lsr_in(). Fixes: 197eb5c416ff ("serial: 8250_dw: Use serial_lsr_in() in dw8250_handle_irq()") Reviewed-by: Andy Shevchenko Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/c5879db7-bee9-93f-526e-872a292442@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 167a691c7b19..f78b13db1b1e 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -266,7 +266,10 @@ static int dw8250_handle_irq(struct uart_port *p) /* Manually stop the Rx DMA transfer when acting as flow controller */ if (quirks & DW_UART_QUIRK_IS_DMA_FC && up->dma && up->dma->rx_running && rx_timeout) { + spin_lock_irqsave(&p->lock, flags); status = serial_lsr_in(up); + spin_unlock_irqrestore(&p->lock, flags); + if (status & (UART_LSR_DR | UART_LSR_BI)) { dw8250_writel_ext(p, RZN1_UART_RDMACR, 0); dw8250_writel_ext(p, DW_UART_DMASA, 1); -- cgit v1.2.3 From 65e20e8cbbccaf0968474d27420c3a5170a5a5b8 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Tue, 28 Jun 2022 14:07:05 +0200 Subject: earlycon: prevent multiple register_console() If the earlycon parameter is given twice, the kernel will spit out a WARN() in register_console() because it was already registered. The non-dt variant setup_earlycon() already handles that gracefully. The dt variant of_setup_earlycon() doesn't. Add the check there and add the -EALREADY handling in early_init_dt_scan_chosen_stdout(). FWIW, this doesn't happen if CONFIG_ACPI_SPCR_TABLE is set. In that case the registration is delayed until after earlycon parameter(s) are parsed. Reviewed-by: Rob Herring Signed-off-by: Michael Walle Link: https://lore.kernel.org/r/20220628120705.200617-1-michael@walle.cc Signed-off-by: Greg Kroah-Hartman --- drivers/of/fdt.c | 4 +++- drivers/tty/serial/earlycon.c | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index a8f5b6532165..043b12be22d6 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -1025,6 +1025,7 @@ int __init early_init_dt_scan_chosen_stdout(void) int l; const struct earlycon_id *match; const void *fdt = initial_boot_params; + int ret; offset = fdt_path_offset(fdt, "/chosen"); if (offset < 0) @@ -1057,7 +1058,8 @@ int __init early_init_dt_scan_chosen_stdout(void) if (fdt_node_check_compatible(fdt, offset, match->compatible)) continue; - if (of_setup_earlycon(match, offset, options) == 0) + ret = of_setup_earlycon(match, offset, options); + if (!ret || ret == -EALREADY) return 0; } return -ENODEV; diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c index 57c70851f22a..88d08ba1ca83 100644 --- a/drivers/tty/serial/earlycon.c +++ b/drivers/tty/serial/earlycon.c @@ -253,6 +253,9 @@ int __init of_setup_earlycon(const struct earlycon_id *match, bool big_endian; u64 addr; + if (early_con.flags & CON_ENABLED) + return -EALREADY; + spin_lock_init(&port->lock); port->iotype = UPIO_MEM; addr = of_flat_dt_translate_address(node); -- cgit v1.2.3 From 6343ecd76c828951fbe55e7d5b29e1923655aed9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 30 Jun 2022 12:38:16 +0300 Subject: serial: 8250_dw: Sort headers alphabetically MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For the sake of better maintenance, sort included headers alphabetically. While at it, split the serial group of headers which makes clear the subsystem the driver belongs to. Reviewed-by: Ilpo Järvinen Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220630093816.28271-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index f78b13db1b1e..e4211c5b3b00 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -9,26 +9,27 @@ * 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 #include #include #include -#include -#include +#include #include #include +#include #include -#include -#include -#include -#include -#include #include -#include +#include +#include #include +#include +#include + #include "8250_dwlib.h" /* Offsets for the DesignWare specific registers */ -- cgit v1.2.3 From 808313bc2182ab60761eed82d2c345883fbc65a7 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 30 Jun 2022 13:05:07 +0300 Subject: serial: 8250_dw: Drop PM ifdeffery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop CONFIG_PM and CONFIG_PM_SLEEP ifdeffery while converting dw8250_pm_ops to use new PM macros. Since we are using runtime PM, wrap dw8250_pm_ops into pm_ptr(). Reviewed-by: Ilpo Järvinen Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220630100507.31113-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index e4211c5b3b00..b5b783f01221 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -695,7 +695,6 @@ static int dw8250_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP static int dw8250_suspend(struct device *dev) { struct dw8250_data *data = dev_get_drvdata(dev); @@ -713,9 +712,7 @@ static int dw8250_resume(struct device *dev) return 0; } -#endif /* CONFIG_PM_SLEEP */ -#ifdef CONFIG_PM static int dw8250_runtime_suspend(struct device *dev) { struct dw8250_data *data = dev_get_drvdata(dev); @@ -737,11 +734,10 @@ static int dw8250_runtime_resume(struct device *dev) return 0; } -#endif static const struct dev_pm_ops dw8250_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(dw8250_suspend, dw8250_resume) - SET_RUNTIME_PM_OPS(dw8250_runtime_suspend, dw8250_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(dw8250_suspend, dw8250_resume) + RUNTIME_PM_OPS(dw8250_runtime_suspend, dw8250_runtime_resume, NULL) }; static const struct dw8250_platform_data dw8250_dw_apb = { @@ -799,7 +795,7 @@ MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match); static struct platform_driver dw8250_platform_driver = { .driver = { .name = "dw-apb-uart", - .pm = &dw8250_pm_ops, + .pm = pm_ptr(&dw8250_pm_ops), .of_match_table = dw8250_of_match, .acpi_match_table = dw8250_acpi_match, }, -- cgit v1.2.3 From e9f9736679566cfa4158a40820cd50a46e601349 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Thu, 30 Jun 2022 13:05:36 +0300 Subject: 8250_dwlib: Convert bitops to newer form MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of open-coding, use BIT(), GENMASK(), and FIELD_GET() helpers. Reviewed-by: Andy Shevchenko Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220630100536.41329-1-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dwlib.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_dwlib.c b/drivers/tty/serial/8250/8250_dwlib.c index da330ef46446..a8bbed74ea70 100644 --- a/drivers/tty/serial/8250/8250_dwlib.c +++ b/drivers/tty/serial/8250/8250_dwlib.c @@ -46,21 +46,21 @@ #define DW_UART_LCR_EXT_TRANSMIT_MODE BIT(3) /* Component Parameter Register bits */ -#define DW_UART_CPR_ABP_DATA_WIDTH (3 << 0) -#define DW_UART_CPR_AFCE_MODE (1 << 4) -#define DW_UART_CPR_THRE_MODE (1 << 5) -#define DW_UART_CPR_SIR_MODE (1 << 6) -#define DW_UART_CPR_SIR_LP_MODE (1 << 7) -#define DW_UART_CPR_ADDITIONAL_FEATURES (1 << 8) -#define DW_UART_CPR_FIFO_ACCESS (1 << 9) -#define DW_UART_CPR_FIFO_STAT (1 << 10) -#define DW_UART_CPR_SHADOW (1 << 11) -#define DW_UART_CPR_ENCODED_PARMS (1 << 12) -#define DW_UART_CPR_DMA_EXTRA (1 << 13) -#define DW_UART_CPR_FIFO_MODE (0xff << 16) +#define DW_UART_CPR_ABP_DATA_WIDTH GENMASK(1, 0) +#define DW_UART_CPR_AFCE_MODE BIT(4) +#define DW_UART_CPR_THRE_MODE BIT(5) +#define DW_UART_CPR_SIR_MODE BIT(6) +#define DW_UART_CPR_SIR_LP_MODE BIT(7) +#define DW_UART_CPR_ADDITIONAL_FEATURES BIT(8) +#define DW_UART_CPR_FIFO_ACCESS BIT(9) +#define DW_UART_CPR_FIFO_STAT BIT(10) +#define DW_UART_CPR_SHADOW BIT(11) +#define DW_UART_CPR_ENCODED_PARMS BIT(12) +#define DW_UART_CPR_DMA_EXTRA BIT(13) +#define DW_UART_CPR_FIFO_MODE GENMASK(23, 16) /* Helper for FIFO size calculation */ -#define DW_UART_CPR_FIFO_SIZE(a) (((a >> 16) & 0xff) * 16) +#define DW_UART_CPR_FIFO_SIZE(a) (FIELD_GET(DW_UART_CPR_FIFO_MODE, (a)) * 16) /* * divisor = div(I) + div(F) -- cgit v1.2.3 From 309f7beddf053bd0560b07f3251ac64a5872ecf9 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Tue, 28 Jun 2022 16:42:31 +0300 Subject: serial: 8250_dw: Use dw8250_serial_out() in dw8250_serial_out38x() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Place dw8250_serial_out() before dw8250_serial_out38x() so that it can be called from dw8250_serial_out38x() to do the actual write. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220628134234.53771-2-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index b5b783f01221..e419e032895c 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -144,29 +144,23 @@ static void dw8250_tx_wait_empty(struct uart_port *p) } } -static void dw8250_serial_out38x(struct uart_port *p, int offset, int value) +static void dw8250_serial_out(struct uart_port *p, int offset, int value) { struct dw8250_data *d = to_dw8250_data(p->private_data); - /* Allow the TX to drain before we reconfigure */ - if (offset == UART_LCR) - dw8250_tx_wait_empty(p); - writeb(value, p->membase + (offset << p->regshift)); if (offset == UART_LCR && !d->uart_16550_compatible) dw8250_check_lcr(p, value); } - -static void dw8250_serial_out(struct uart_port *p, int offset, int value) +static void dw8250_serial_out38x(struct uart_port *p, int offset, int value) { - struct dw8250_data *d = to_dw8250_data(p->private_data); - - writeb(value, p->membase + (offset << p->regshift)); + /* Allow the TX to drain before we reconfigure */ + if (offset == UART_LCR) + dw8250_tx_wait_empty(p); - if (offset == UART_LCR && !d->uart_16550_compatible) - dw8250_check_lcr(p, value); + dw8250_serial_out(p, offset, value); } static unsigned int dw8250_serial_in(struct uart_port *p, int offset) -- cgit v1.2.3 From ac77f0077c3265197d378158c85a55eee6d21508 Mon Sep 17 00:00:00 2001 From: Daniel Starke Date: Fri, 1 Jul 2022 08:16:44 +0200 Subject: tty: n_gsm: fix user open not possible at responder until initiator open After setting up the control channel on both sides the responder side may want to open a virtual tty to listen on until the initiator starts an application on a user channel. The current implementation allows the open() but no other operation, like termios. These fail with EINVAL. The responder sided application has no means to detect an open by the initiator sided application this way. And the initiator sided applications usually expect the responder sided application to listen on the user channel upon open. Set the user channel into half-open state on responder side once a user application opens the virtual tty to allow IO operations on it. Furthermore, keep the user channel constipated until the initiator side opens it to give the responder sided application the chance to detect the new connection and to avoid data loss if the responder sided application starts sending before the user channel is open. Fixes: e1eaea46bb40 ("tty: n_gsm line discipline") Signed-off-by: Daniel Starke Link: https://lore.kernel.org/r/20220701061652.39604-1-daniel.starke@siemens.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index fd4d24f61c46..5a0fd35ce1f9 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -1510,6 +1510,8 @@ static void gsm_dlci_close(struct gsm_dlci *dlci) if (debug & 8) pr_debug("DLCI %d goes closed.\n", dlci->addr); dlci->state = DLCI_CLOSED; + /* Prevent us from sending data before the link is up again */ + dlci->constipated = true; if (dlci->addr != 0) { tty_port_tty_hangup(&dlci->port, false); spin_lock_irqsave(&dlci->lock, flags); @@ -1539,6 +1541,7 @@ static void gsm_dlci_open(struct gsm_dlci *dlci) del_timer(&dlci->t1); /* This will let a tty open continue */ dlci->state = DLCI_OPEN; + dlci->constipated = false; if (debug & 8) pr_debug("DLCI %d goes open.\n", dlci->addr); /* Send current modem state */ @@ -1619,6 +1622,25 @@ static void gsm_dlci_begin_open(struct gsm_dlci *dlci) mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100); } +/** + * gsm_dlci_set_opening - change state to opening + * @dlci: DLCI to open + * + * Change internal state to wait for DLCI open from initiator side. + * We set off timers and responses upon reception of an SABM. + */ +static void gsm_dlci_set_opening(struct gsm_dlci *dlci) +{ + switch (dlci->state) { + case DLCI_CLOSED: + case DLCI_CLOSING: + dlci->state = DLCI_OPENING; + break; + default: + break; + } +} + /** * gsm_dlci_begin_close - start channel open procedure * @dlci: DLCI to open @@ -1762,10 +1784,13 @@ static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr) dlci->addr = addr; dlci->adaption = gsm->adaption; dlci->state = DLCI_CLOSED; - if (addr) + if (addr) { dlci->data = gsm_dlci_data; - else + /* Prevent us from sending data before the link is up */ + dlci->constipated = true; + } else { dlci->data = gsm_dlci_command; + } gsm->dlci[addr] = dlci; return dlci; } @@ -3174,6 +3199,8 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp) /* Start sending off SABM messages */ if (gsm->initiator) gsm_dlci_begin_open(dlci); + else + gsm_dlci_set_opening(dlci); /* And wait for virtual carrier */ return tty_port_block_til_ready(port, tty, filp); } -- cgit v1.2.3 From 01aecd917114577c423f07cec0d186ad007d76fc Mon Sep 17 00:00:00 2001 From: Daniel Starke Date: Fri, 1 Jul 2022 08:16:45 +0200 Subject: tty: n_gsm: fix tty registration before control channel open The current implementation registers/deregisters the user ttys at mux attach/detach. That means that the user devices are available before any control channel is open. However, user channel initialization requires an open control channel. Furthermore, the user is not informed if the mux restarts due to configuration changes. Put the registration/deregistration procedure into separate function to improve readability. Move registration to mux activation and deregistration to mux cleanup to keep the user devices only open as long as a control channel exists. The user will be informed via the device driver if the mux was reconfigured in a way that required a mux re-activation. This makes it necessary to add T2 initialization to gsmld_open() for the ldisc open code path (not the reconfiguration code path) to avoid deletion of an uninitialized T2 at mux cleanup. Fixes: d50f6dcaf22a ("tty: n_gsm: expose gsmtty device nodes at ldisc open time") Signed-off-by: Daniel Starke Link: https://lore.kernel.org/r/20220701061652.39604-2-daniel.starke@siemens.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 117 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 79 insertions(+), 38 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 5a0fd35ce1f9..e8c0ce114c07 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -235,6 +235,7 @@ struct gsm_mux { struct gsm_dlci *dlci[NUM_DLCI]; int old_c_iflag; /* termios c_iflag value before attach */ bool constipated; /* Asked by remote to shut up */ + bool has_devices; /* Devices were registered */ spinlock_t tx_lock; unsigned int tx_bytes; /* TX data outstanding */ @@ -463,6 +464,68 @@ static void gsm_hex_dump_bytes(const char *fname, const u8 *data, kfree(prefix); } +/** + * gsm_register_devices - register all tty devices for a given mux index + * + * @driver: the tty driver that describes the tty devices + * @index: the mux number is used to calculate the minor numbers of the + * ttys for this mux and may differ from the position in the + * mux array. + */ +static int gsm_register_devices(struct tty_driver *driver, unsigned int index) +{ + struct device *dev; + int i; + unsigned int base; + + if (!driver || index >= MAX_MUX) + return -EINVAL; + + base = index * NUM_DLCI; /* first minor for this index */ + for (i = 1; i < NUM_DLCI; i++) { + /* Don't register device 0 - this is the control channel + * and not a usable tty interface + */ + dev = tty_register_device(gsm_tty_driver, base + i, NULL); + if (IS_ERR(dev)) { + if (debug & 8) + pr_info("%s failed to register device minor %u", + __func__, base + i); + for (i--; i >= 1; i--) + tty_unregister_device(gsm_tty_driver, base + i); + return PTR_ERR(dev); + } + } + + return 0; +} + +/** + * gsm_unregister_devices - unregister all tty devices for a given mux index + * + * @driver: the tty driver that describes the tty devices + * @index: the mux number is used to calculate the minor numbers of the + * ttys for this mux and may differ from the position in the + * mux array. + */ +static void gsm_unregister_devices(struct tty_driver *driver, + unsigned int index) +{ + int i; + unsigned int base; + + if (!driver || index >= MAX_MUX) + return; + + base = index * NUM_DLCI; /* first minor for this index */ + for (i = 1; i < NUM_DLCI; i++) { + /* Don't unregister device 0 - this is the control + * channel and not a usable tty interface + */ + tty_unregister_device(gsm_tty_driver, base + i); + } +} + /** * gsm_print_packet - display a frame for debug * @hdr: header to print before decode @@ -2204,6 +2267,10 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm, bool disc) del_timer_sync(&gsm->t2_timer); /* Free up any link layer users and finally the control channel */ + if (gsm->has_devices) { + gsm_unregister_devices(gsm_tty_driver, gsm->num); + gsm->has_devices = false; + } for (i = NUM_DLCI - 1; i >= 0; i--) if (gsm->dlci[i]) gsm_dlci_release(gsm->dlci[i]); @@ -2227,6 +2294,7 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm, bool disc) static int gsm_activate_mux(struct gsm_mux *gsm) { struct gsm_dlci *dlci; + int ret; timer_setup(&gsm->t2_timer, gsm_control_retransmit, 0); init_waitqueue_head(&gsm->event); @@ -2238,9 +2306,14 @@ static int gsm_activate_mux(struct gsm_mux *gsm) else gsm->receive = gsm1_receive; + ret = gsm_register_devices(gsm_tty_driver, gsm->num); + if (ret) + return ret; + dlci = gsm_dlci_alloc(gsm, 0); if (dlci == NULL) return -ENOMEM; + gsm->has_devices = true; gsm->dead = false; /* Tty opens are now permissible */ return 0; } @@ -2500,39 +2573,14 @@ static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len) * will need moving to an ioctl path. */ -static int gsmld_attach_gsm(struct tty_struct *tty, struct gsm_mux *gsm) +static void gsmld_attach_gsm(struct tty_struct *tty, struct gsm_mux *gsm) { - unsigned int base; - int ret, i; - gsm->tty = tty_kref_get(tty); /* Turn off tty XON/XOFF handling to handle it explicitly. */ gsm->old_c_iflag = tty->termios.c_iflag; tty->termios.c_iflag &= (IXON | IXOFF); - ret = gsm_activate_mux(gsm); - if (ret != 0) - tty_kref_put(gsm->tty); - else { - /* Don't register device 0 - this is the control channel and not - a usable tty interface */ - base = mux_num_to_base(gsm); /* Base for this MUX */ - for (i = 1; i < NUM_DLCI; i++) { - struct device *dev; - - dev = tty_register_device(gsm_tty_driver, - base + i, NULL); - if (IS_ERR(dev)) { - for (i--; i >= 1; i--) - tty_unregister_device(gsm_tty_driver, - base + i); - return PTR_ERR(dev); - } - } - } - return ret; } - /** * gsmld_detach_gsm - stop doing 0710 mux * @tty: tty attached to the mux @@ -2543,12 +2591,7 @@ static int gsmld_attach_gsm(struct tty_struct *tty, struct gsm_mux *gsm) static void gsmld_detach_gsm(struct tty_struct *tty, struct gsm_mux *gsm) { - unsigned int base = mux_num_to_base(gsm); /* Base for this MUX */ - int i; - WARN_ON(tty != gsm->tty); - for (i = 1; i < NUM_DLCI; i++) - tty_unregister_device(gsm_tty_driver, base + i); /* Restore tty XON/XOFF handling. */ gsm->tty->termios.c_iflag = gsm->old_c_iflag; tty_kref_put(gsm->tty); @@ -2640,7 +2683,6 @@ static void gsmld_close(struct tty_struct *tty) static int gsmld_open(struct tty_struct *tty) { struct gsm_mux *gsm; - int ret; if (tty->ops->write == NULL) return -EINVAL; @@ -2656,12 +2698,11 @@ static int gsmld_open(struct tty_struct *tty) /* Attach the initial passive connection */ gsm->encoding = 1; - ret = gsmld_attach_gsm(tty, gsm); - if (ret != 0) { - gsm_cleanup_mux(gsm, false); - mux_put(gsm); - } - return ret; + gsmld_attach_gsm(tty, gsm); + + timer_setup(&gsm->t2_timer, gsm_control_retransmit, 0); + + return 0; } /** -- cgit v1.2.3 From 556fc8ac06513cced381588d6d58c184d95cc4fe Mon Sep 17 00:00:00 2001 From: Daniel Starke Date: Fri, 1 Jul 2022 08:16:46 +0200 Subject: tty: n_gsm: fix wrong queuing behavior in gsm_dlci_data_output() 1) The function drains the fifo for the given user tty/DLCI without considering 'TX_THRESH_HI' and different to gsm_dlci_data_output_framed(), which moves only one packet from the user side to the internal transmission queue. We can only handle one packet at a time here if we want to allow DLCI priority handling in gsm_dlci_data_sweep() to avoid link starvation. 2) Furthermore, the additional header octet from convergence layer type 2 is not counted against MTU. It is part of the UI/UIH frame message which needs to be limited to MTU. Hence, it is wrong not to consider this octet. 3) Finally, the waiting user tty is not informed about freed space in its send queue. Take at most one packet worth of data out of the DLCI fifo to fix 1). Limit the max user data size per packet to MTU - 1 in case of convergence layer type 2 to leave space for the control signal octet which is added in the later part of the function. This fixes 2). Add tty_port_tty_wakeup() to wake up the user tty if new write space has been made available to fix 3). Fixes: 268e526b935e ("tty/n_gsm: avoid fifo overflow in gsm_dlci_data_output") Signed-off-by: Daniel Starke Link: https://lore.kernel.org/r/20220701061652.39604-3-daniel.starke@siemens.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 74 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 42 insertions(+), 32 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index e8c0ce114c07..d056b15b4d61 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -886,41 +886,51 @@ static int gsm_dlci_data_output(struct gsm_mux *gsm, struct gsm_dlci *dlci) { struct gsm_msg *msg; u8 *dp; - int len, total_size, size; - int h = dlci->adaption - 1; + int h, len, size; - total_size = 0; - while (1) { - len = kfifo_len(&dlci->fifo); - if (len == 0) - return total_size; - - /* MTU/MRU count only the data bits */ - if (len > gsm->mtu) - len = gsm->mtu; - - size = len + h; - - msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype); - /* FIXME: need a timer or something to kick this so it can't - get stuck with no work outstanding and no buffer free */ - if (msg == NULL) - return -ENOMEM; - dp = msg->data; - switch (dlci->adaption) { - case 1: /* Unstructured */ - break; - case 2: /* Unstructed with modem bits. - Always one byte as we never send inline break data */ - *dp++ = (gsm_encode_modem(dlci) << 1) | EA; - break; - } - WARN_ON(kfifo_out_locked(&dlci->fifo, dp , len, &dlci->lock) != len); - __gsm_data_queue(dlci, msg); - total_size += size; + /* for modem bits without break data */ + h = ((dlci->adaption == 1) ? 0 : 1); + + len = kfifo_len(&dlci->fifo); + if (len == 0) + return 0; + + /* MTU/MRU count only the data bits but watch adaption mode */ + if ((len + h) > gsm->mtu) + len = gsm->mtu - h; + + size = len + h; + + msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype); + /* FIXME: need a timer or something to kick this so it can't + * get stuck with no work outstanding and no buffer free + */ + if (!msg) + return -ENOMEM; + dp = msg->data; + switch (dlci->adaption) { + case 1: /* Unstructured */ + break; + case 2: /* Unstructured with modem bits. + * Always one byte as we never send inline break data + */ + *dp++ = (gsm_encode_modem(dlci) << 1) | EA; + break; + default: + pr_err("%s: unsupported adaption %d\n", __func__, + dlci->adaption); + break; } + + WARN_ON(len != kfifo_out_locked(&dlci->fifo, dp, len, + &dlci->lock)); + + /* Notify upper layer about available send space. */ + tty_port_tty_wakeup(&dlci->port); + + __gsm_data_queue(dlci, msg); /* Bytes of data we used up */ - return total_size; + return size; } /** -- cgit v1.2.3 From c568f7086c6e771c77aad13d727c70ef70e07243 Mon Sep 17 00:00:00 2001 From: Daniel Starke Date: Fri, 1 Jul 2022 08:16:47 +0200 Subject: tty: n_gsm: fix missing timer to handle stalled links The current implementation does not handle the situation that no data is in the internal queue and needs to be sent out while the user tty fifo is full. Add a timer that moves more data from user tty down to the internal queue which is then serialized on the ldisc. This timer is triggered if no data was moved from a user tty to the internal queue within 10 * T1. Fixes: e1eaea46bb40 ("tty: n_gsm line discipline") Signed-off-by: Daniel Starke Link: https://lore.kernel.org/r/20220701061652.39604-4-daniel.starke@siemens.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 43 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index d056b15b4d61..a01225819b92 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -244,6 +244,7 @@ struct gsm_mux { struct list_head tx_list; /* Pending data packets */ /* Control messages */ + struct timer_list kick_timer; /* Kick TX queuing on timeout */ struct timer_list t2_timer; /* Retransmit timer for commands */ int cretries; /* Command retry counter */ struct gsm_control *pending_cmd;/* Our current pending command */ @@ -850,6 +851,7 @@ static void __gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg) list_add_tail(&msg->list, &gsm->tx_list); gsm->tx_bytes += msg->len; gsm_data_kick(gsm, dlci); + mod_timer(&gsm->kick_timer, jiffies + 10 * gsm->t1 * HZ / 100); } /** @@ -902,9 +904,6 @@ static int gsm_dlci_data_output(struct gsm_mux *gsm, struct gsm_dlci *dlci) size = len + h; msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype); - /* FIXME: need a timer or something to kick this so it can't - * get stuck with no work outstanding and no buffer free - */ if (!msg) return -ENOMEM; dp = msg->data; @@ -981,9 +980,6 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm, size = len + overhead; msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype); - - /* FIXME: need a timer or something to kick this so it can't - get stuck with no work outstanding and no buffer free */ if (msg == NULL) { skb_queue_tail(&dlci->skb_list, dlci->skb); dlci->skb = NULL; @@ -1079,9 +1075,9 @@ static int gsm_dlci_modem_output(struct gsm_mux *gsm, struct gsm_dlci *dlci, * renegotiate DLCI priorities with optional stuff. Needs optimising. */ -static void gsm_dlci_data_sweep(struct gsm_mux *gsm) +static int gsm_dlci_data_sweep(struct gsm_mux *gsm) { - int len; + int len, ret = 0; /* Priority ordering: We should do priority with RR of the groups */ int i = 1; @@ -1104,7 +1100,11 @@ static void gsm_dlci_data_sweep(struct gsm_mux *gsm) /* DLCI empty - try the next */ if (len == 0) i++; + else + ret++; } + + return ret; } /** @@ -1823,6 +1823,30 @@ static void gsm_dlci_command(struct gsm_dlci *dlci, const u8 *data, int len) } } +/** + * gsm_kick_timer - transmit if possible + * @t: timer contained in our gsm object + * + * Transmit data from DLCIs if the queue is empty. We can't rely on + * a tty wakeup except when we filled the pipe so we need to fire off + * new data ourselves in other cases. + */ +static void gsm_kick_timer(struct timer_list *t) +{ + struct gsm_mux *gsm = from_timer(gsm, t, kick_timer); + unsigned long flags; + int sent = 0; + + spin_lock_irqsave(&gsm->tx_lock, flags); + /* If we have nothing running then we need to fire up */ + if (gsm->tx_bytes < TX_THRESH_LO) + sent = gsm_dlci_data_sweep(gsm); + spin_unlock_irqrestore(&gsm->tx_lock, flags); + + if (sent && debug & 4) + pr_info("%s TX queue stalled\n", __func__); +} + /* * Allocate/Free DLCI channels */ @@ -2274,6 +2298,7 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm, bool disc) } /* Finish outstanding timers, making sure they are done */ + del_timer_sync(&gsm->kick_timer); del_timer_sync(&gsm->t2_timer); /* Free up any link layer users and finally the control channel */ @@ -2306,6 +2331,7 @@ static int gsm_activate_mux(struct gsm_mux *gsm) struct gsm_dlci *dlci; int ret; + timer_setup(&gsm->kick_timer, gsm_kick_timer, 0); timer_setup(&gsm->t2_timer, gsm_control_retransmit, 0); init_waitqueue_head(&gsm->event); spin_lock_init(&gsm->control_lock); @@ -2710,6 +2736,7 @@ static int gsmld_open(struct tty_struct *tty) gsmld_attach_gsm(tty, gsm); + timer_setup(&gsm->kick_timer, gsm_kick_timer, 0); timer_setup(&gsm->t2_timer, gsm_control_retransmit, 0); return 0; -- cgit v1.2.3 From bec0224816d19abe4fe503586d16d51890540615 Mon Sep 17 00:00:00 2001 From: Daniel Starke Date: Fri, 1 Jul 2022 08:16:48 +0200 Subject: tty: n_gsm: fix non flow control frames during mux flow off n_gsm is based on the 3GPP 07.010 and its newer version is the 3GPP 27.010. See https://portal.3gpp.org/desktopmodules/Specifications/SpecificationDetails.aspx?specificationId=1516 The changes from 07.010 to 27.010 are non-functional. Therefore, I refer to the newer 27.010 here. Chapter 5.4.6.3.6 states that FCoff stops the transmission on all channels except the control channel. This is already implemented in gsm_data_kick(). However, chapter 5.4.8.1 explains that this shall result in the same behavior as software flow control on the ldisc in advanced option mode. That means only flow control frames shall be sent during flow off. The current implementation does not consider this case. Change gsm_data_kick() to send only flow control frames if constipated to abide the standard. gsm_read_ea_val() and gsm_is_flow_ctrl_msg() are introduced as helper functions for this. It is planned to use gsm_read_ea_val() in later code cleanups for other functions, too. Fixes: c01af4fec2c8 ("n_gsm : Flow control handling in Mux driver") Signed-off-by: Daniel Starke Link: https://lore.kernel.org/r/20220701061652.39604-5-daniel.starke@siemens.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index a01225819b92..3f415b2fa199 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -421,6 +421,27 @@ static int gsm_read_ea(unsigned int *val, u8 c) return c & EA; } +/** + * gsm_read_ea_val - read a value until EA + * @val: variable holding value + * @data: buffer of data + * @dlen: length of data + * + * Processes an EA value. Updates the passed variable and + * returns the processed data length. + */ +static unsigned int gsm_read_ea_val(unsigned int *val, const u8 *data, int dlen) +{ + unsigned int len = 0; + + for (; dlen > 0; dlen--) { + len++; + if (gsm_read_ea(val, *data++)) + break; + } + return len; +} + /** * gsm_encode_modem - encode modem data bits * @dlci: DLCI to encode from @@ -746,6 +767,37 @@ static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len, return m; } +/** + * gsm_is_flow_ctrl_msg - checks if flow control message + * @msg: message to check + * + * Returns true if the given message is a flow control command of the + * control channel. False is returned in any other case. + */ +static bool gsm_is_flow_ctrl_msg(struct gsm_msg *msg) +{ + unsigned int cmd; + + if (msg->addr > 0) + return false; + + switch (msg->ctrl & ~PF) { + case UI: + case UIH: + cmd = 0; + if (gsm_read_ea_val(&cmd, msg->data + 2, msg->len - 2) < 1) + break; + switch (cmd & ~PF) { + case CMD_FCOFF: + case CMD_FCON: + return true; + } + break; + } + + return false; +} + /** * gsm_data_kick - poke the queue * @gsm: GSM Mux @@ -765,7 +817,7 @@ static void gsm_data_kick(struct gsm_mux *gsm, struct gsm_dlci *dlci) int len; list_for_each_entry_safe(msg, nmsg, &gsm->tx_list, list) { - if (gsm->constipated && msg->addr) + if (gsm->constipated && !gsm_is_flow_ctrl_msg(msg)) continue; if (gsm->encoding != 0) { gsm->txframe[0] = GSM1_SOF; -- cgit v1.2.3 From 4fae831b3a71fc5a44cc5c7d0b8c1267ee7659f5 Mon Sep 17 00:00:00 2001 From: Daniel Starke Date: Fri, 1 Jul 2022 08:16:50 +0200 Subject: tty: n_gsm: fix packet re-transmission without open control channel In the current implementation control packets are re-transmitted even if the control channel closed down during T2. This is wrong. Check whether the control channel is open before re-transmitting any packets. Note that control channel open/close is handled by T1 and not T2 and remains unaffected by this. Fixes: e1eaea46bb40 ("tty: n_gsm line discipline") Signed-off-by: Daniel Starke Link: https://lore.kernel.org/r/20220701061652.39604-7-daniel.starke@siemens.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 3f415b2fa199..39359274096d 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -1532,7 +1532,7 @@ static void gsm_control_retransmit(struct timer_list *t) spin_lock_irqsave(&gsm->control_lock, flags); ctrl = gsm->pending_cmd; if (ctrl) { - if (gsm->cretries == 0) { + if (gsm->cretries == 0 || !gsm->dlci[0] || gsm->dlci[0]->dead) { gsm->pending_cmd = NULL; ctrl->error = -ETIMEDOUT; ctrl->done = 1; -- cgit v1.2.3 From 32dd59f96924f45e33bc79854f7a00679c0fa28e Mon Sep 17 00:00:00 2001 From: Daniel Starke Date: Fri, 1 Jul 2022 08:16:52 +0200 Subject: tty: n_gsm: fix race condition in gsmld_write() The function may be used by the user directly and also by the n_gsm internal functions. They can lead into a race condition which results in interleaved frames if both are writing at the same time. The receiving side is not able to decode those interleaved frames correctly. Add a lock around the low side tty write to avoid race conditions and frame interleaving between user originated writes and n_gsm writes. Fixes: e1eaea46bb40 ("tty: n_gsm line discipline") Signed-off-by: Daniel Starke Link: https://lore.kernel.org/r/20220701061652.39604-9-daniel.starke@siemens.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 39359274096d..9a3d7db33394 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2859,11 +2859,24 @@ static ssize_t gsmld_read(struct tty_struct *tty, struct file *file, static ssize_t gsmld_write(struct tty_struct *tty, struct file *file, const unsigned char *buf, size_t nr) { - int space = tty_write_room(tty); + struct gsm_mux *gsm = tty->disc_data; + unsigned long flags; + int space; + int ret; + + if (!gsm) + return -ENODEV; + + ret = -ENOBUFS; + spin_lock_irqsave(&gsm->tx_lock, flags); + space = tty_write_room(tty); if (space >= nr) - return tty->ops->write(tty, buf, nr); - set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - return -ENOBUFS; + ret = tty->ops->write(tty, buf, nr); + else + set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); + spin_unlock_irqrestore(&gsm->tx_lock, flags); + + return ret; } /** -- cgit v1.2.3 From 0af021678d5d30c31f5a6b631f404ead3575212a Mon Sep 17 00:00:00 2001 From: Daniel Starke Date: Fri, 1 Jul 2022 14:23:31 +0200 Subject: tty: n_gsm: fix deadlock and link starvation in outgoing data path The current implementation queues up new control and user packets as needed and processes this queue down to the ldisc in the same code path. That means that the upper and the lower layer are hard coupled in the code. Due to this deadlocks can happen as seen below while transmitting data, especially during ldisc congestion. Furthermore, the data channels starve the control channel on high transmission load on the ldisc. Introduce an additional control channel data queue to prevent timeouts and link hangups during ldisc congestion. This is being processed before the user channel data queue in gsm_data_kick(), i.e. with the highest priority. Put the queue to ldisc data path into a workqueue and trigger it whenever new data has been put into the transmission queue. Change gsm_dlci_data_sweep() accordingly to fill up the transmission queue until TX_THRESH_HI. This solves the locking issue, keeps latency low and provides good performance on high data load. Note that now all packets from a DLCI are removed from the internal queue if the associated DLCI was closed. This ensures that no data is sent by the introduced write task to an already closed DLCI. BUG: spinlock recursion on CPU#0, test_v24_loop/124 lock: serial8250_ports+0x3a8/0x7500, .magic: dead4ead, .owner: test_v24_loop/124, .owner_cpu: 0 CPU: 0 PID: 124 Comm: test_v24_loop Tainted: G O 5.18.0-rc2 #3 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 Call Trace: dump_stack_lvl+0x34/0x44 do_raw_spin_lock+0x76/0xa0 _raw_spin_lock_irqsave+0x72/0x80 uart_write_room+0x3b/0xc0 gsm_data_kick+0x14b/0x240 [n_gsm] gsmld_write_wakeup+0x35/0x70 [n_gsm] tty_wakeup+0x53/0x60 tty_port_default_wakeup+0x1b/0x30 serial8250_tx_chars+0x12f/0x220 serial8250_handle_irq.part.0+0xfe/0x150 serial8250_default_handle_irq+0x48/0x80 serial8250_interrupt+0x56/0xa0 __handle_irq_event_percpu+0x78/0x1f0 handle_irq_event+0x34/0x70 handle_fasteoi_irq+0x90/0x1e0 __common_interrupt+0x69/0x100 common_interrupt+0x48/0xc0 asm_common_interrupt+0x1e/0x40 RIP: 0010:__do_softirq+0x83/0x34e Code: 2a 0a ff 0f b7 ed c7 44 24 10 0a 00 00 00 48 c7 c7 51 2a 64 82 e8 2d e2 d5 ff 65 66 c7 05 83 af 1e 7e 00 00 fb b8 ff ff ff ff <49> c7 c2 40 61 80 82 0f bc c5 41 89 c4 41 83 c4 01 0f 84 e6 00 00 RSP: 0018:ffffc90000003f98 EFLAGS: 00000286 RAX: 00000000ffffffff RBX: 0000000000000000 RCX: 0000000000000000 RDX: 0000000000000000 RSI: ffffffff82642a51 RDI: ffffffff825bb5e7 RBP: 0000000000000200 R08: 00000008de3271a8 R09: 0000000000000000 R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000000 R13: 0000000000000030 R14: 0000000000000000 R15: 0000000000000000 ? __do_softirq+0x73/0x34e irq_exit_rcu+0xb5/0x100 common_interrupt+0xa4/0xc0 asm_common_interrupt+0x1e/0x40 RIP: 0010:_raw_spin_unlock_irqrestore+0x2e/0x50 Code: 00 55 48 89 fd 48 83 c7 18 53 48 89 f3 48 8b 74 24 10 e8 85 28 36 ff 48 89 ef e8 cd 58 36 ff 80 e7 02 74 01 fb bf 01 00 00 00 3d 97 33 ff 65 8b 05 96 23 2b 7e 85 c0 74 03 5b 5d c3 0f 1f 44 RSP: 0018:ffffc9000020fd08 EFLAGS: 00000202 RAX: 0000000000000000 RBX: 0000000000000246 RCX: 0000000000000000 RDX: 0000000000000004 RSI: ffffffff8257fd74 RDI: 0000000000000001 RBP: ffff8880057de3a0 R08: 00000008de233000 R09: 0000000000000000 R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000000 R13: 0000000000000100 R14: 0000000000000202 R15: ffff8880057df0b8 ? _raw_spin_unlock_irqrestore+0x23/0x50 gsmtty_write+0x65/0x80 [n_gsm] n_tty_write+0x33f/0x530 ? swake_up_all+0xe0/0xe0 file_tty_write.constprop.0+0x1b1/0x320 ? n_tty_flush_buffer+0xb0/0xb0 new_sync_write+0x10c/0x190 vfs_write+0x282/0x310 ksys_write+0x68/0xe0 do_syscall_64+0x3b/0x90 entry_SYSCALL_64_after_hwframe+0x44/0xae RIP: 0033:0x7f3e5e35c15c Code: 8b 7c 24 08 89 c5 e8 c5 ff ff ff 89 ef 89 44 24 08 e8 58 bc 02 00 8b 44 24 08 48 83 c4 10 5d c3 48 63 ff b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 76 10 48 8b 15 fd fc 05 00 f7 d8 64 89 02 48 83 RSP: 002b:00007ffcee77cd18 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 RAX: ffffffffffffffda RBX: 00007ffcee77cd70 RCX: 00007f3e5e35c15c RDX: 0000000000000100 RSI: 00007ffcee77cd90 RDI: 0000000000000003 RBP: 0000000000000100 R08: 0000000000000000 R09: 7efefefefefefeff R10: 00007f3e5e3bddeb R11: 0000000000000246 R12: 00007ffcee77ce8f R13: 0000000000000001 R14: 000056214404e010 R15: 00007ffcee77cd90 Fixes: e1eaea46bb40 ("tty: n_gsm line discipline") Signed-off-by: Daniel Starke Link: https://lore.kernel.org/r/20220701122332.2039-1-daniel.starke@siemens.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 407 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 279 insertions(+), 128 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 9a3d7db33394..79869f2b570c 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -5,6 +5,14 @@ * * * THIS IS A DEVELOPMENT SNAPSHOT IT IS NOT A FINAL RELEASE * * + * Outgoing path: + * tty -> DLCI fifo -> scheduler -> GSM MUX data queue ---o-> ldisc + * control message -> GSM MUX control queue --´ + * + * Incoming path: + * ldisc -> gsm_queue() -o--> tty + * `-> gsm_control_response() + * * TO DO: * Mostly done: ioctls for setting modes/timing * Partly done: hooks so you can pull off frames to non tty devs @@ -210,6 +218,9 @@ struct gsm_mux { /* Events on the GSM channel */ wait_queue_head_t event; + /* ldisc send work */ + struct work_struct tx_work; + /* Bits for GSM mode decoding */ /* Framing Layer */ @@ -241,7 +252,8 @@ struct gsm_mux { unsigned int tx_bytes; /* TX data outstanding */ #define TX_THRESH_HI 8192 #define TX_THRESH_LO 2048 - struct list_head tx_list; /* Pending data packets */ + struct list_head tx_ctrl_list; /* Pending control packets */ + struct list_head tx_data_list; /* Pending data packets */ /* Control messages */ struct timer_list kick_timer; /* Kick TX queuing on timeout */ @@ -371,6 +383,11 @@ static const u8 gsm_fcs8[256] = { static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len); static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk); +static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len, + u8 ctrl); +static int gsm_send_packet(struct gsm_mux *gsm, struct gsm_msg *msg); +static void gsmld_write_trigger(struct gsm_mux *gsm); +static void gsmld_write_task(struct work_struct *work); /** * gsm_fcs_add - update FCS @@ -655,57 +672,73 @@ static int gsm_stuff_frame(const u8 *input, u8 *output, int len) * @cr: command/response bit seen as initiator * @control: control byte including PF bit * - * Format up and transmit a control frame. These do not go via the - * queueing logic as they should be transmitted ahead of data when - * they are needed. - * - * FIXME: Lock versus data TX path + * Format up and transmit a control frame. These should be transmitted + * ahead of data when they are needed. */ - -static void gsm_send(struct gsm_mux *gsm, int addr, int cr, int control) +static int gsm_send(struct gsm_mux *gsm, int addr, int cr, int control) { - int len; - u8 cbuf[10]; - u8 ibuf[3]; + struct gsm_msg *msg; + u8 *dp; int ocr; + unsigned long flags; + + msg = gsm_data_alloc(gsm, addr, 0, control); + if (!msg) + return -ENOMEM; /* toggle C/R coding if not initiator */ ocr = cr ^ (gsm->initiator ? 0 : 1); - switch (gsm->encoding) { - case 0: - cbuf[0] = GSM0_SOF; - cbuf[1] = (addr << 2) | (ocr << 1) | EA; - cbuf[2] = control; - cbuf[3] = EA; /* Length of data = 0 */ - cbuf[4] = 0xFF - gsm_fcs_add_block(INIT_FCS, cbuf + 1, 3); - cbuf[5] = GSM0_SOF; - len = 6; - break; - case 1: - case 2: - /* Control frame + packing (but not frame stuffing) in mode 1 */ - ibuf[0] = (addr << 2) | (ocr << 1) | EA; - ibuf[1] = control; - ibuf[2] = 0xFF - gsm_fcs_add_block(INIT_FCS, ibuf, 2); - /* Stuffing may double the size worst case */ - len = gsm_stuff_frame(ibuf, cbuf + 1, 3); - /* Now add the SOF markers */ - cbuf[0] = GSM1_SOF; - cbuf[len + 1] = GSM1_SOF; - /* FIXME: we can omit the lead one in many cases */ - len += 2; - break; - default: - WARN_ON(1); - return; - } - gsmld_output(gsm, cbuf, len); - if (!gsm->initiator) { - cr = cr & gsm->initiator; - control = control & ~PF; + msg->data -= 3; + dp = msg->data; + *dp++ = (addr << 2) | (ocr << 1) | EA; + *dp++ = control; + + if (gsm->encoding == 0) + *dp++ = EA; /* Length of data = 0 */ + + *dp = 0xFF - gsm_fcs_add_block(INIT_FCS, msg->data, dp - msg->data); + msg->len = (dp - msg->data) + 1; + + gsm_print_packet("Q->", addr, cr, control, NULL, 0); + + spin_lock_irqsave(&gsm->tx_lock, flags); + list_add_tail(&msg->list, &gsm->tx_ctrl_list); + gsm->tx_bytes += msg->len; + spin_unlock_irqrestore(&gsm->tx_lock, flags); + gsmld_write_trigger(gsm); + + return 0; +} + +/** + * gsm_dlci_clear_queues - remove outstanding data for a DLCI + * @gsm: mux + * @dlci: clear for this DLCI + * + * Clears the data queues for a given DLCI. + */ +static void gsm_dlci_clear_queues(struct gsm_mux *gsm, struct gsm_dlci *dlci) +{ + struct gsm_msg *msg, *nmsg; + int addr = dlci->addr; + unsigned long flags; + + /* Clear DLCI write fifo first */ + spin_lock_irqsave(&dlci->lock, flags); + kfifo_reset(&dlci->fifo); + spin_unlock_irqrestore(&dlci->lock, flags); + + /* Clear data packets in MUX write queue */ + spin_lock_irqsave(&gsm->tx_lock, flags); + list_for_each_entry_safe(msg, nmsg, &gsm->tx_data_list, list) { + if (msg->addr != addr) + continue; + gsm->tx_bytes -= msg->len; + list_del(&msg->list); + kfree(msg); } - gsm_print_packet("-->", addr, cr, control, NULL, 0); + spin_unlock_irqrestore(&gsm->tx_lock, flags); } /** @@ -767,6 +800,45 @@ static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len, return m; } +/** + * gsm_send_packet - sends a single packet + * @gsm: GSM Mux + * @msg: packet to send + * + * The given packet is encoded and sent out. No memory is freed. + * The caller must hold the gsm tx lock. + */ +static int gsm_send_packet(struct gsm_mux *gsm, struct gsm_msg *msg) +{ + int len, ret; + + + if (gsm->encoding == 0) { + gsm->txframe[0] = GSM0_SOF; + memcpy(gsm->txframe + 1, msg->data, msg->len); + gsm->txframe[msg->len + 1] = GSM0_SOF; + len = msg->len + 2; + } else { + gsm->txframe[0] = GSM1_SOF; + len = gsm_stuff_frame(msg->data, gsm->txframe + 1, msg->len); + gsm->txframe[len + 1] = GSM1_SOF; + len += 2; + } + + if (debug & 4) + gsm_hex_dump_bytes(__func__, gsm->txframe, len); + gsm_print_packet("-->", msg->addr, gsm->initiator, msg->ctrl, msg->data, + msg->len); + + ret = gsmld_output(gsm, gsm->txframe, len); + if (ret <= 0) + return ret; + /* FIXME: Can eliminate one SOF in many more cases */ + gsm->tx_bytes -= msg->len; + + return 0; +} + /** * gsm_is_flow_ctrl_msg - checks if flow control message * @msg: message to check @@ -799,59 +871,81 @@ static bool gsm_is_flow_ctrl_msg(struct gsm_msg *msg) } /** - * gsm_data_kick - poke the queue + * gsm_data_kick - poke the queue * @gsm: GSM Mux - * @dlci: DLCI sending the data * * The tty device has called us to indicate that room has appeared in - * the transmit queue. Ram more data into the pipe if we have any + * the transmit queue. Ram more data into the pipe if we have any. * If we have been flow-stopped by a CMD_FCOFF, then we can only - * send messages on DLCI0 until CMD_FCON - * - * FIXME: lock against link layer control transmissions + * send messages on DLCI0 until CMD_FCON. The caller must hold + * the gsm tx lock. */ - -static void gsm_data_kick(struct gsm_mux *gsm, struct gsm_dlci *dlci) +static int gsm_data_kick(struct gsm_mux *gsm) { struct gsm_msg *msg, *nmsg; - int len; + struct gsm_dlci *dlci; + int ret; - list_for_each_entry_safe(msg, nmsg, &gsm->tx_list, list) { + clear_bit(TTY_DO_WRITE_WAKEUP, &gsm->tty->flags); + + /* Serialize control messages and control channel messages first */ + list_for_each_entry_safe(msg, nmsg, &gsm->tx_ctrl_list, list) { if (gsm->constipated && !gsm_is_flow_ctrl_msg(msg)) + return -EAGAIN; + ret = gsm_send_packet(gsm, msg); + switch (ret) { + case -ENOSPC: + return -ENOSPC; + case -ENODEV: + /* ldisc not open */ + gsm->tx_bytes -= msg->len; + list_del(&msg->list); + kfree(msg); continue; - if (gsm->encoding != 0) { - gsm->txframe[0] = GSM1_SOF; - len = gsm_stuff_frame(msg->data, - gsm->txframe + 1, msg->len); - gsm->txframe[len + 1] = GSM1_SOF; - len += 2; - } else { - gsm->txframe[0] = GSM0_SOF; - memcpy(gsm->txframe + 1 , msg->data, msg->len); - gsm->txframe[msg->len + 1] = GSM0_SOF; - len = msg->len + 2; - } - - if (debug & 4) - gsm_hex_dump_bytes(__func__, gsm->txframe, len); - if (gsmld_output(gsm, gsm->txframe, len) <= 0) + default: + if (ret >= 0) { + list_del(&msg->list); + kfree(msg); + } break; - /* FIXME: Can eliminate one SOF in many more cases */ - gsm->tx_bytes -= msg->len; - - list_del(&msg->list); - kfree(msg); + } + } - if (dlci) { - tty_port_tty_wakeup(&dlci->port); - } else { - int i = 0; + if (gsm->constipated) + return -EAGAIN; - for (i = 0; i < NUM_DLCI; i++) - if (gsm->dlci[i]) - tty_port_tty_wakeup(&gsm->dlci[i]->port); + /* Serialize other channels */ + if (list_empty(&gsm->tx_data_list)) + return 0; + list_for_each_entry_safe(msg, nmsg, &gsm->tx_data_list, list) { + dlci = gsm->dlci[msg->addr]; + /* Send only messages for DLCIs with valid state */ + if (dlci->state != DLCI_OPEN) { + gsm->tx_bytes -= msg->len; + list_del(&msg->list); + kfree(msg); + continue; + } + ret = gsm_send_packet(gsm, msg); + switch (ret) { + case -ENOSPC: + return -ENOSPC; + case -ENODEV: + /* ldisc not open */ + gsm->tx_bytes -= msg->len; + list_del(&msg->list); + kfree(msg); + continue; + default: + if (ret >= 0) { + list_del(&msg->list); + kfree(msg); + } + break; } } + + return 1; } /** @@ -900,9 +994,21 @@ static void __gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg) msg->data = dp; /* Add to the actual output queue */ - list_add_tail(&msg->list, &gsm->tx_list); + switch (msg->ctrl & ~PF) { + case UI: + case UIH: + if (msg->addr > 0) { + list_add_tail(&msg->list, &gsm->tx_data_list); + break; + } + fallthrough; + default: + list_add_tail(&msg->list, &gsm->tx_ctrl_list); + break; + } gsm->tx_bytes += msg->len; - gsm_data_kick(gsm, dlci); + + gsmld_write_trigger(gsm); mod_timer(&gsm->kick_timer, jiffies + 10 * gsm->t1 * HZ / 100); } @@ -1129,32 +1235,39 @@ static int gsm_dlci_modem_output(struct gsm_mux *gsm, struct gsm_dlci *dlci, static int gsm_dlci_data_sweep(struct gsm_mux *gsm) { - int len, ret = 0; /* Priority ordering: We should do priority with RR of the groups */ - int i = 1; - - while (i < NUM_DLCI) { - struct gsm_dlci *dlci; + int i, len, ret = 0; + bool sent; + struct gsm_dlci *dlci; - if (gsm->tx_bytes > TX_THRESH_HI) - break; - dlci = gsm->dlci[i]; - if (dlci == NULL || dlci->constipated) { - i++; - continue; + while (gsm->tx_bytes < TX_THRESH_HI) { + for (sent = false, i = 1; i < NUM_DLCI; i++) { + dlci = gsm->dlci[i]; + /* skip unused or blocked channel */ + if (!dlci || dlci->constipated) + continue; + /* skip channels with invalid state */ + if (dlci->state != DLCI_OPEN) + continue; + /* count the sent data per adaption */ + if (dlci->adaption < 3 && !dlci->net) + len = gsm_dlci_data_output(gsm, dlci); + else + len = gsm_dlci_data_output_framed(gsm, dlci); + /* on error exit */ + if (len < 0) + return ret; + if (len > 0) { + ret++; + sent = true; + /* The lower DLCs can starve the higher DLCs! */ + break; + } + /* try next */ } - if (dlci->adaption < 3 && !dlci->net) - len = gsm_dlci_data_output(gsm, dlci); - else - len = gsm_dlci_data_output_framed(gsm, dlci); - if (len < 0) + if (!sent) break; - /* DLCI empty - try the next */ - if (len == 0) - i++; - else - ret++; - } + }; return ret; } @@ -1402,7 +1515,6 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command, const u8 *data, int clen) { u8 buf[1]; - unsigned long flags; switch (command) { case CMD_CLD: { @@ -1424,9 +1536,7 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command, gsm->constipated = false; gsm_control_reply(gsm, CMD_FCON, NULL, 0); /* Kick the link in case it is idling */ - spin_lock_irqsave(&gsm->tx_lock, flags); - gsm_data_kick(gsm, NULL); - spin_unlock_irqrestore(&gsm->tx_lock, flags); + gsmld_write_trigger(gsm); break; case CMD_FCOFF: /* Modem wants us to STFU */ @@ -1629,8 +1739,6 @@ static int gsm_control_wait(struct gsm_mux *gsm, struct gsm_control *control) static void gsm_dlci_close(struct gsm_dlci *dlci) { - unsigned long flags; - del_timer(&dlci->t1); if (debug & 8) pr_debug("DLCI %d goes closed.\n", dlci->addr); @@ -1639,17 +1747,16 @@ static void gsm_dlci_close(struct gsm_dlci *dlci) dlci->constipated = true; if (dlci->addr != 0) { tty_port_tty_hangup(&dlci->port, false); - spin_lock_irqsave(&dlci->lock, flags); - kfifo_reset(&dlci->fifo); - spin_unlock_irqrestore(&dlci->lock, flags); + gsm_dlci_clear_queues(dlci->gsm, dlci); /* Ensure that gsmtty_open() can return. */ tty_port_set_initialized(&dlci->port, 0); wake_up_interruptible(&dlci->port.open_wait); } else dlci->gsm->dead = true; - wake_up(&dlci->gsm->event); /* A DLCI 0 close is a MUX termination so we need to kick that back to userspace somehow */ + gsm_dlci_data_kick(dlci); + wake_up(&dlci->gsm->event); } /** @@ -1672,6 +1779,7 @@ static void gsm_dlci_open(struct gsm_dlci *dlci) /* Send current modem state */ if (dlci->addr) gsm_modem_update(dlci, 0); + gsm_dlci_data_kick(dlci); wake_up(&dlci->gsm->event); } @@ -2222,7 +2330,7 @@ static void gsm1_receive(struct gsm_mux *gsm, unsigned char c) } else if ((c & ISO_IEC_646_MASK) == XOFF) { gsm->constipated = false; /* Kick the link in case it is idling */ - gsm_data_kick(gsm, NULL); + gsmld_write_trigger(gsm); return; } if (c == GSM1_SOF) { @@ -2353,6 +2461,9 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm, bool disc) del_timer_sync(&gsm->kick_timer); del_timer_sync(&gsm->t2_timer); + /* Finish writing to ldisc */ + flush_work(&gsm->tx_work); + /* Free up any link layer users and finally the control channel */ if (gsm->has_devices) { gsm_unregister_devices(gsm_tty_driver, gsm->num); @@ -2364,9 +2475,12 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm, bool disc) mutex_unlock(&gsm->mutex); /* Now wipe the queues */ tty_ldisc_flush(gsm->tty); - list_for_each_entry_safe(txq, ntxq, &gsm->tx_list, list) + list_for_each_entry_safe(txq, ntxq, &gsm->tx_ctrl_list, list) + kfree(txq); + INIT_LIST_HEAD(&gsm->tx_ctrl_list); + list_for_each_entry_safe(txq, ntxq, &gsm->tx_data_list, list) kfree(txq); - INIT_LIST_HEAD(&gsm->tx_list); + INIT_LIST_HEAD(&gsm->tx_data_list); } /** @@ -2385,6 +2499,7 @@ static int gsm_activate_mux(struct gsm_mux *gsm) timer_setup(&gsm->kick_timer, gsm_kick_timer, 0); timer_setup(&gsm->t2_timer, gsm_control_retransmit, 0); + INIT_WORK(&gsm->tx_work, gsmld_write_task); init_waitqueue_head(&gsm->event); spin_lock_init(&gsm->control_lock); spin_lock_init(&gsm->tx_lock); @@ -2494,7 +2609,8 @@ static struct gsm_mux *gsm_alloc_mux(void) spin_lock_init(&gsm->lock); mutex_init(&gsm->mutex); kref_init(&gsm->ref); - INIT_LIST_HEAD(&gsm->tx_list); + INIT_LIST_HEAD(&gsm->tx_ctrl_list); + INIT_LIST_HEAD(&gsm->tx_data_list); gsm->t1 = T1; gsm->t2 = T2; @@ -2651,6 +2767,47 @@ static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len) return gsm->tty->ops->write(gsm->tty, data, len); } + +/** + * gsmld_write_trigger - schedule ldisc write task + * @gsm: our mux + */ +static void gsmld_write_trigger(struct gsm_mux *gsm) +{ + if (!gsm || !gsm->dlci[0] || gsm->dlci[0]->dead) + return; + schedule_work(&gsm->tx_work); +} + + +/** + * gsmld_write_task - ldisc write task + * @work: our tx write work + * + * Writes out data to the ldisc if possible. We are doing this here to + * avoid dead-locking. This returns if no space or data is left for output. + */ +static void gsmld_write_task(struct work_struct *work) +{ + struct gsm_mux *gsm = container_of(work, struct gsm_mux, tx_work); + unsigned long flags; + int i, ret; + + /* All outstanding control channel and control messages and one data + * frame is sent. + */ + ret = -ENODEV; + spin_lock_irqsave(&gsm->tx_lock, flags); + if (gsm->tty) + ret = gsm_data_kick(gsm); + spin_unlock_irqrestore(&gsm->tx_lock, flags); + + if (ret >= 0) + for (i = 0; i < NUM_DLCI; i++) + if (gsm->dlci[i]) + tty_port_tty_wakeup(&gsm->dlci[i]->port); +} + /** * gsmld_attach_gsm - mode set up * @tty: our tty structure @@ -2790,6 +2947,7 @@ static int gsmld_open(struct tty_struct *tty) timer_setup(&gsm->kick_timer, gsm_kick_timer, 0); timer_setup(&gsm->t2_timer, gsm_control_retransmit, 0); + INIT_WORK(&gsm->tx_work, gsmld_write_task); return 0; } @@ -2806,16 +2964,9 @@ static int gsmld_open(struct tty_struct *tty) static void gsmld_write_wakeup(struct tty_struct *tty) { struct gsm_mux *gsm = tty->disc_data; - unsigned long flags; /* Queue poll */ - clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - spin_lock_irqsave(&gsm->tx_lock, flags); - gsm_data_kick(gsm, NULL); - if (gsm->tx_bytes < TX_THRESH_LO) { - gsm_dlci_data_sweep(gsm); - } - spin_unlock_irqrestore(&gsm->tx_lock, flags); + gsmld_write_trigger(gsm); } /** -- cgit v1.2.3 From 7349660438603ed19282e75949561406531785a5 Mon Sep 17 00:00:00 2001 From: Daniel Starke Date: Fri, 1 Jul 2022 14:23:32 +0200 Subject: tty: n_gsm: fix resource allocation order in gsm_activate_mux() Within gsm_activate_mux() all timers and locks are initiated before the actual resource for the control channel is allocated. This can lead to race conditions. Allocate the control channel DLCI object first to avoid race conditions. Fixes: e1eaea46bb40 ("tty: n_gsm line discipline") Signed-off-by: Daniel Starke Link: https://lore.kernel.org/r/20220701122332.2039-2-daniel.starke@siemens.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 79869f2b570c..ba399a660573 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2497,6 +2497,10 @@ static int gsm_activate_mux(struct gsm_mux *gsm) struct gsm_dlci *dlci; int ret; + dlci = gsm_dlci_alloc(gsm, 0); + if (dlci == NULL) + return -ENOMEM; + timer_setup(&gsm->kick_timer, gsm_kick_timer, 0); timer_setup(&gsm->t2_timer, gsm_control_retransmit, 0); INIT_WORK(&gsm->tx_work, gsmld_write_task); @@ -2513,9 +2517,6 @@ static int gsm_activate_mux(struct gsm_mux *gsm) if (ret) return ret; - dlci = gsm_dlci_alloc(gsm, 0); - if (dlci == NULL) - return -ENOMEM; gsm->has_devices = true; gsm->dead = false; /* Tty opens are now permissible */ return 0; -- cgit v1.2.3 From 9d3aaceb73acadf134596a2f8db9c451c1332d3d Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 4 Jul 2022 10:51:19 +0200 Subject: serial: 8250_fsl: Don't report FE, PE and OE twice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some Freescale 8250 implementations have the problem that a single long break results in one irq per character frame time. The code in fsl8250_handle_irq() that is supposed to handle that uses the BI bit in lsr_saved_flags to detect such a situation and then skip the second received character. However it also stores other error bits and so after a single frame error the character received in the next irq handling is passed to the upper layer with a frame error, too. So after a spike on the data line (which is correctly recognized as a frame error) the following valid character is thrown away, because the driver reports a frame error for that one, too. To weaken this problem restrict saving LSR to only the BI bit. Note however that the handling is still broken: - lsr_saved_flags is updated using orig_lsr which is the LSR content for the first received char, but there might be more in the FIFO, so a character is thrown away that is received later and not necessarily the one following the break. - The doubled break might be the 2nd and 3rd char in the FIFO, so the workaround doesn't catch these, because serial8250_rx_chars() doesn't handle the workaround. - lsr_saved_flags might have set UART_LSR_BI at the entry of fsl8250_handle_irq() which doesn't originate from fsl8250_handle_irq()'s "up->lsr_saved_flags |= orig_lsr & UART_LSR_BI;" but from e.g. from serial8250_tx_empty(). - For a long or a short break this isn't about two characters, but more or only a single one. Fixes: 9deaa53ac7fa ("serial: add irq handler for Freescale 16550 errata.") Acked-by: Ilpo Järvinen Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20220704085119.55900-1-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_fsl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_fsl.c b/drivers/tty/serial/8250/8250_fsl.c index fd4005fcd0d6..8aad15622a2e 100644 --- a/drivers/tty/serial/8250/8250_fsl.c +++ b/drivers/tty/serial/8250/8250_fsl.c @@ -77,7 +77,7 @@ int fsl8250_handle_irq(struct uart_port *port) if ((lsr & UART_LSR_THRE) && (up->ier & UART_IER_THRI)) serial8250_tx_chars(up); - up->lsr_saved_flags = orig_lsr; + up->lsr_saved_flags |= orig_lsr & UART_LSR_BI; uart_unlock_and_check_sysrq_irqrestore(&up->port, flags); -- cgit v1.2.3 From 0139da50dc53f0ce2804e83566d290c7e626fd17 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 4 Jul 2022 12:45:14 +0300 Subject: serial: Embed rs485_supported to uart_port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Embed rs485_supported to uart_port to allow serial core to tweak it as needed. Reviewed-by: Lino Sanfilippo Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220704094515.6831-2-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_bcm2835aux.c | 2 +- drivers/tty/serial/8250/8250_dwlib.c | 4 ++-- drivers/tty/serial/8250/8250_exar.c | 2 +- drivers/tty/serial/8250/8250_fintek.c | 4 ++-- drivers/tty/serial/8250/8250_lpc18xx.c | 2 +- drivers/tty/serial/8250/8250_of.c | 2 +- drivers/tty/serial/8250/8250_pci.c | 2 +- drivers/tty/serial/amba-pl011.c | 2 +- drivers/tty/serial/ar933x_uart.c | 4 ++-- drivers/tty/serial/atmel_serial.c | 2 +- drivers/tty/serial/fsl_lpuart.c | 2 +- drivers/tty/serial/imx.c | 4 ++-- drivers/tty/serial/max310x.c | 2 +- drivers/tty/serial/mcf.c | 4 ++-- drivers/tty/serial/omap-serial.c | 2 +- drivers/tty/serial/sc16is7xx.c | 2 +- drivers/tty/serial/serial_core.c | 8 ++++---- drivers/tty/serial/stm32-usart.c | 2 +- include/linux/serial_core.h | 2 +- 19 files changed, 27 insertions(+), 27 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c index d9f1e618cfbd..047e14ccb165 100644 --- a/drivers/tty/serial/8250/8250_bcm2835aux.c +++ b/drivers/tty/serial/8250/8250_bcm2835aux.c @@ -108,7 +108,7 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev) up.port.flags = UPF_SHARE_IRQ | 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.port.rs485_supported = serial8250_em485_supported; up.rs485_start_tx = bcm2835aux_rs485_start_tx; up.rs485_stop_tx = bcm2835aux_rs485_stop_tx; diff --git a/drivers/tty/serial/8250/8250_dwlib.c b/drivers/tty/serial/8250/8250_dwlib.c index a8bbed74ea70..2c3b1468bd88 100644 --- a/drivers/tty/serial/8250/8250_dwlib.c +++ b/drivers/tty/serial/8250/8250_dwlib.c @@ -255,10 +255,10 @@ void dw8250_setup_port(struct uart_port *p) if (pd->hw_rs485_support) { p->rs485_config = dw8250_rs485_config; up->lsr_save_mask = LSR_SAVE_FLAGS | DW_UART_LSR_ADDR_RCVD; - p->rs485_supported = &dw8250_rs485_supported; + p->rs485_supported = dw8250_rs485_supported; } else { p->rs485_config = serial8250_em485_config; - p->rs485_supported = &serial8250_em485_supported; + p->rs485_supported = serial8250_em485_supported; up->rs485_start_tx = serial8250_em485_start_tx; up->rs485_stop_tx = serial8250_em485_stop_tx; } diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index f5344cfe303c..314a05e009df 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -550,7 +550,7 @@ pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev, port->port.uartclk = baud * 16; port->port.rs485_config = platform->rs485_config; - port->port.rs485_supported = platform->rs485_supported; + port->port.rs485_supported = *(platform->rs485_supported); /* * Setup the UART clock for the devices on expansion slot to diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c index eea693f5b577..65b6b3cbaff6 100644 --- a/drivers/tty/serial/8250/8250_fintek.c +++ b/drivers/tty/serial/8250/8250_fintek.c @@ -433,9 +433,9 @@ static void fintek_8250_set_rs485_handler(struct uart_8250_port *uart) case CHIP_ID_F81865: uart->port.rs485_config = fintek_8250_rs485_config; if (!pdata->index) - uart->port.rs485_supported = &fintek_8250_rs485_supported_port0; + uart->port.rs485_supported = fintek_8250_rs485_supported_port0; else - uart->port.rs485_supported = &fintek_8250_rs485_supported; + uart->port.rs485_supported = fintek_8250_rs485_supported; break; default: /* No RS485 Auto direction functional */ diff --git a/drivers/tty/serial/8250/8250_lpc18xx.c b/drivers/tty/serial/8250/8250_lpc18xx.c index d7cb3bb52069..d6ca0d47e9d5 100644 --- a/drivers/tty/serial/8250/8250_lpc18xx.c +++ b/drivers/tty/serial/8250/8250_lpc18xx.c @@ -161,7 +161,7 @@ static int lpc18xx_serial_probe(struct platform_device *pdev) uart.port.uartclk = clk_get_rate(data->clk_uart); uart.port.private_data = data; uart.port.rs485_config = lpc18xx_rs485_config; - uart.port.rs485_supported = &lpc18xx_rs485_supported; + uart.port.rs485_supported = lpc18xx_rs485_supported; uart.port.serial_out = lpc18xx_uart_serial_out; uart.dma = &data->dma; diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c index 65cccd559db2..1b461fba15a3 100644 --- a/drivers/tty/serial/8250/8250_of.c +++ b/drivers/tty/serial/8250/8250_of.c @@ -165,7 +165,7 @@ static int of_platform_serial_setup(struct platform_device *ofdev, port->dev = &ofdev->dev; port->rs485_config = serial8250_em485_config; - port->rs485_supported = &serial8250_em485_supported; + port->rs485_supported = serial8250_em485_supported; up->rs485_start_tx = serial8250_em485_start_tx; up->rs485_stop_tx = serial8250_em485_stop_tx; diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index d31d2350a9db..8a39ae072c65 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1607,7 +1607,7 @@ static int pci_fintek_setup(struct serial_private *priv, port->port.iotype = UPIO_PORT; port->port.iobase = iobase; port->port.rs485_config = pci_fintek_rs485_config; - port->port.rs485_supported = &pci_fintek_rs485_supported; + port->port.rs485_supported = pci_fintek_rs485_supported; data = devm_kzalloc(&pdev->dev, sizeof(u8), GFP_KERNEL); if (!data) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index c8f52945a4aa..abeceeefdece 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -2779,7 +2779,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) uap->port.irq = dev->irq[0]; uap->port.ops = &amba_pl011_pops; uap->port.rs485_config = pl011_rs485_config; - uap->port.rs485_supported = &pl011_rs485_supported; + uap->port.rs485_supported = pl011_rs485_supported; snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev)); ret = pl011_setup_port(&dev->dev, uap, &dev->res, portnr); diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c index b73ce13683db..f931ecbc0bc0 100644 --- a/drivers/tty/serial/ar933x_uart.c +++ b/drivers/tty/serial/ar933x_uart.c @@ -778,7 +778,7 @@ static int ar933x_uart_probe(struct platform_device *pdev) port->fifosize = AR933X_UART_FIFO_SIZE; port->ops = &ar933x_uart_ops; port->rs485_config = ar933x_config_rs485; - port->rs485_supported = &ar933x_rs485_supported; + port->rs485_supported = ar933x_rs485_supported; baud = ar933x_uart_get_baud(port->uartclk, AR933X_UART_MAX_SCALE, 1); up->min_baud = max_t(unsigned int, baud, AR933X_UART_MIN_BAUD); @@ -802,7 +802,7 @@ static int ar933x_uart_probe(struct platform_device *pdev) !up->rts_gpiod) { dev_err(&pdev->dev, "lacking rts-gpio, disabling RS485\n"); port->rs485.flags &= ~SER_RS485_ENABLED; - port->rs485_supported = &ar933x_no_rs485; + port->rs485_supported = ar933x_no_rs485; } #ifdef CONFIG_SERIAL_AR933X_CONSOLE diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index bc6004679585..30ba9eef7b39 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -2498,7 +2498,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port, port->mapbase = mpdev->resource[0].start; port->irq = platform_get_irq(mpdev, 0); port->rs485_config = atmel_config_rs485; - port->rs485_supported = &atmel_rs485_supported; + port->rs485_supported = atmel_rs485_supported; port->iso7816_config = atmel_config_iso7816; port->membase = NULL; diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 8fe0494d4057..fc7d235a1e27 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -2655,7 +2655,7 @@ static int lpuart_probe(struct platform_device *pdev) sport->port.rs485_config = lpuart32_config_rs485; else sport->port.rs485_config = lpuart_config_rs485; - sport->port.rs485_supported = &lpuart_rs485_supported; + sport->port.rs485_supported = lpuart_rs485_supported; sport->ipg_clk = devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(sport->ipg_clk)) { diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 3457006cea3f..522445a8f666 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -2285,9 +2285,9 @@ static int imx_uart_probe(struct platform_device *pdev) sport->port.rs485_config = imx_uart_rs485_config; /* RTS is required to control the RS485 transmitter */ if (sport->have_rtscts || sport->have_rtsgpio) - sport->port.rs485_supported = &imx_rs485_supported; + sport->port.rs485_supported = imx_rs485_supported; else - sport->port.rs485_supported = &imx_no_rs485; + sport->port.rs485_supported = imx_no_rs485; sport->port.flags = UPF_BOOT_AUTOCONF; timer_setup(&sport->timer, imx_uart_timeout, 0); diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index e162bfb44080..ab10ca4a45b5 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1370,7 +1370,7 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty s->p[i].port.membase = (void __iomem *)~0; s->p[i].port.uartclk = uartclk; s->p[i].port.rs485_config = max310x_rs485_config; - s->p[i].port.rs485_supported = &max310x_rs485_supported; + s->p[i].port.rs485_supported = max310x_rs485_supported; s->p[i].port.ops = &max310x_ops; s->p[i].regmap = regmaps[i]; diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c index 73c5287b8e5e..f4aaaadd0742 100644 --- a/drivers/tty/serial/mcf.c +++ b/drivers/tty/serial/mcf.c @@ -506,7 +506,7 @@ int __init early_mcf_setup(struct mcf_platform_uart *platp) port->uartclk = MCF_BUSCLK; port->flags = UPF_BOOT_AUTOCONF; port->rs485_config = mcf_config_rs485; - port->rs485_supported = &mcf_rs485_supported; + port->rs485_supported = mcf_rs485_supported; port->ops = &mcf_uart_ops; } @@ -634,7 +634,7 @@ static int mcf_probe(struct platform_device *pdev) port->ops = &mcf_uart_ops; port->flags = UPF_BOOT_AUTOCONF; port->rs485_config = mcf_config_rs485; - port->rs485_supported = &mcf_rs485_supported; + port->rs485_supported = mcf_rs485_supported; port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_MCF_CONSOLE); uart_add_one_port(&mcf_driver, port); diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 196bae704f85..0aa666e247d5 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -1643,7 +1643,7 @@ static int serial_omap_probe(struct platform_device *pdev) up->port.flags = omap_up_info->flags; up->port.uartclk = omap_up_info->uartclk; up->port.rs485_config = serial_omap_config_rs485; - up->port.rs485_supported = &serial_omap_rs485_supported; + up->port.rs485_supported = serial_omap_rs485_supported; if (!up->port.uartclk) { up->port.uartclk = DEFAULT_CLK_SPEED; dev_warn(&pdev->dev, diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 8cb92a3b3fb8..259e08cc347c 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -1461,7 +1461,7 @@ static int sc16is7xx_probe(struct device *dev, s->p[i].port.iotype = UPIO_PORT; s->p[i].port.uartclk = freq; s->p[i].port.rs485_config = sc16is7xx_config_rs485; - s->p[i].port.rs485_supported = &sc16is7xx_rs485_supported; + s->p[i].port.rs485_supported = sc16is7xx_rs485_supported; s->p[i].port.ops = &sc16is7xx_ops; s->p[i].old_mctrl = 0; s->p[i].port.line = sc16is7xx_alloc_line(); diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 85ef7ef00b82..a9cf1044a9fa 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1285,7 +1285,7 @@ static int uart_check_rs485_flags(struct uart_port *port, struct serial_rs485 *r * For any bit outside of the legacy ones that is not supported by * the driver, return -EINVAL. */ - if (flags & ~port->rs485_supported->flags) + if (flags & ~port->rs485_supported.flags) return -EINVAL; /* Asking for address w/o addressing mode? */ @@ -1304,7 +1304,7 @@ static int uart_check_rs485_flags(struct uart_port *port, struct serial_rs485 *r static void uart_sanitize_serial_rs485(struct uart_port *port, struct serial_rs485 *rs485) { - u32 supported_flags = port->rs485_supported->flags; + u32 supported_flags = port->rs485_supported.flags; if (!(rs485->flags & SER_RS485_ENABLED)) { memset(rs485, 0, sizeof(*rs485)); @@ -1323,7 +1323,7 @@ static void uart_sanitize_serial_rs485(struct uart_port *port, struct serial_rs4 supported_flags |= SER_RS485_RTS_ON_SEND|SER_RS485_RTS_AFTER_SEND; } - if (!port->rs485_supported->delay_rts_before_send) { + if (!port->rs485_supported.delay_rts_before_send) { if (rs485->delay_rts_before_send) { dev_warn_ratelimited(port->dev, "%s (%d): RTS delay before sending not supported\n", @@ -1337,7 +1337,7 @@ static void uart_sanitize_serial_rs485(struct uart_port *port, struct serial_rs4 port->name, port->line, rs485->delay_rts_before_send); } - if (!port->rs485_supported->delay_rts_after_send) { + if (!port->rs485_supported.delay_rts_after_send) { if (rs485->delay_rts_after_send) { dev_warn_ratelimited(port->dev, "%s (%d): RTS delay after sending not supported\n", diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 13992e64a7df..ff5c7e0ebc4c 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -1401,7 +1401,7 @@ static int stm32_usart_init_port(struct stm32_port *stm32port, port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_STM32_CONSOLE); port->irq = irq; port->rs485_config = stm32_usart_config_rs485; - port->rs485_supported = &stm32_rs485_supported; + port->rs485_supported = stm32_rs485_supported; ret = stm32_usart_init_rs485(port, pdev); if (ret) diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index b7b86ee3cb12..a6fa7c40c330 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -255,7 +255,7 @@ struct uart_port { struct attribute_group *attr_group; /* port specific attributes */ const struct attribute_group **tty_groups; /* all attributes (serial core use only) */ struct serial_rs485 rs485; - const struct serial_rs485 *rs485_supported; /* Supported mask for serial_rs485 */ + struct serial_rs485 rs485_supported; /* Supported mask for serial_rs485 */ struct gpio_desc *rs485_term_gpio; /* enable RS485 bus termination */ struct serial_iso7816 iso7816; void *private_data; /* generic platform data pointer */ -- cgit v1.2.3 From 8bec874f84d826288a6cfa6acc683d15c218d78c Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 4 Jul 2022 12:45:15 +0300 Subject: serial: RS485 termination is supported if DT provides one MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When DT provides rs485-term, set termination flag as supported. Reviewed-by: Lino Sanfilippo Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220704094515.6831-3-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index a9cf1044a9fa..1db44cde76f6 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -3409,6 +3409,8 @@ int uart_get_rs485_mode(struct uart_port *port) port->rs485_term_gpio = NULL; return dev_err_probe(dev, ret, "Cannot get rs485-term-gpios\n"); } + if (port->rs485_term_gpio) + port->rs485_supported.flags |= SER_RS485_TERMINATE_BUS; return 0; } -- cgit v1.2.3 From f30e10caa80aa1f35508bc17fc302dbbde9a833c Mon Sep 17 00:00:00 2001 From: Daniel Starke Date: Thu, 7 Jul 2022 13:32:20 +0200 Subject: tty: n_gsm: fix wrong T1 retry count handling n_gsm is based on the 3GPP 07.010 and its newer version is the 3GPP 27.010. See https://portal.3gpp.org/desktopmodules/Specifications/SpecificationDetails.aspx?specificationId=1516 The changes from 07.010 to 27.010 are non-functional. Therefore, I refer to the newer 27.010 here. Chapter 5.7.3 states that the valid range for the maximum number of retransmissions (N2) is from 0 to 255 (both including). gsm_dlci_t1() handles this number incorrectly by performing N2 - 1 retransmission attempts. Setting N2 to zero results in more than 255 retransmission attempts. Fix gsm_dlci_t1() to comply with 3GPP 27.010. Fixes: e1eaea46bb40 ("tty: n_gsm line discipline") Signed-off-by: Daniel Starke Link: https://lore.kernel.org/r/20220707113223.3685-1-daniel.starke@siemens.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index ba399a660573..1a70e7ae90cc 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -1805,8 +1805,8 @@ static void gsm_dlci_t1(struct timer_list *t) switch (dlci->state) { case DLCI_OPENING: - dlci->retries--; if (dlci->retries) { + dlci->retries--; gsm_command(dlci->gsm, dlci->addr, SABM|PF); mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100); } else if (!dlci->addr && gsm->control == (DM | PF)) { @@ -1821,8 +1821,8 @@ static void gsm_dlci_t1(struct timer_list *t) break; case DLCI_CLOSING: - dlci->retries--; if (dlci->retries) { + dlci->retries--; gsm_command(dlci->gsm, dlci->addr, DISC|PF); mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100); } else -- cgit v1.2.3 From 18a948c7d90995d127785e308fa7b701df4c499f Mon Sep 17 00:00:00 2001 From: Daniel Starke Date: Thu, 7 Jul 2022 13:32:21 +0200 Subject: tty: n_gsm: fix DM command n_gsm is based on the 3GPP 07.010 and its newer version is the 3GPP 27.010. See https://portal.3gpp.org/desktopmodules/Specifications/SpecificationDetails.aspx?specificationId=1516 The changes from 07.010 to 27.010 are non-functional. Therefore, I refer to the newer 27.010 here. Chapter 5.3.3 defines the DM response. There exists no DM command. However, the current implementation incorrectly sends DM as command in case of unexpected UIH frames in gsm_queue(). Correct this behavior by always sending DM as response. Fixes: e1eaea46bb40 ("tty: n_gsm line discipline") Signed-off-by: Daniel Starke Link: https://lore.kernel.org/r/20220707113223.3685-2-daniel.starke@siemens.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 1a70e7ae90cc..90060018928f 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2207,7 +2207,7 @@ static void gsm_queue(struct gsm_mux *gsm) case UIH: case UIH|PF: if (dlci == NULL || dlci->state != DLCI_OPEN) { - gsm_command(gsm, address, DM|PF); + gsm_response(gsm, address, DM|PF); return; } dlci->data(dlci, gsm->buf, gsm->len); -- cgit v1.2.3 From 59ff0680ecbfec742b1e0381e7cc46b41eb06647 Mon Sep 17 00:00:00 2001 From: Daniel Starke Date: Thu, 7 Jul 2022 13:32:22 +0200 Subject: tty: n_gsm: fix flow control handling in tx path The current implementation constipates all transmission paths during flow control except for flow control frames. However, these may not be located at the beginning of the transmission queue of the control channel. Ensure that flow control frames in the transmission queue for the control channel are always handled even if constipated by skipping through other messages. Fixes: 0af021678d5d ("tty: n_gsm: fix deadlock and link starvation in outgoing data path") Signed-off-by: Daniel Starke Link: https://lore.kernel.org/r/20220707113223.3685-3-daniel.starke@siemens.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 90060018928f..51447ccccbab 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -891,7 +891,7 @@ static int gsm_data_kick(struct gsm_mux *gsm) /* Serialize control messages and control channel messages first */ list_for_each_entry_safe(msg, nmsg, &gsm->tx_ctrl_list, list) { if (gsm->constipated && !gsm_is_flow_ctrl_msg(msg)) - return -EAGAIN; + continue; ret = gsm_send_packet(gsm, msg); switch (ret) { case -ENOSPC: -- cgit v1.2.3 From 7e5b4322cde067e1d0f1bf8f490e93f664a7c843 Mon Sep 17 00:00:00 2001 From: Daniel Starke Date: Thu, 7 Jul 2022 13:32:23 +0200 Subject: tty: n_gsm: fix missing corner cases in gsmld_poll() gsmld_poll() currently fails to handle the following corner cases correctly: - remote party closed the associated tty Add the missing checks and map those to EPOLLHUP. Reorder the checks to group them by their reaction. Fixes: e1eaea46bb40 ("tty: n_gsm line discipline") Signed-off-by: Daniel Starke Link: https://lore.kernel.org/r/20220707113223.3685-4-daniel.starke@siemens.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 51447ccccbab..caa5c14ed57f 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -3053,12 +3053,15 @@ static __poll_t gsmld_poll(struct tty_struct *tty, struct file *file, poll_wait(file, &tty->read_wait, wait); poll_wait(file, &tty->write_wait, wait); + + if (gsm->dead) + mask |= EPOLLHUP; if (tty_hung_up_p(file)) mask |= EPOLLHUP; + if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) + mask |= EPOLLHUP; if (!tty_is_writelocked(tty) && tty_write_room(tty) > 0) mask |= EPOLLOUT | EPOLLWRNORM; - if (gsm->dead) - mask |= EPOLLHUP; return mask; } -- cgit v1.2.3 From ef5a03a26c87a760bc3d86b5af7b773e82f8b1b7 Mon Sep 17 00:00:00 2001 From: Cameron Williams Date: Mon, 11 Jul 2022 16:35:10 +0100 Subject: tty: 8250: Add support for Brainboxes PX cards. Add support for some of the Brainboxes PCIe (PX) range of serial cards, including the PX-101, PX-235/PX-246, PX-203/PX-257, PX-260/PX-701, PX-310, PX-313, PX-320/PX-324/PX-376/PX-387, PX-335/PX-346, PX-368, PX-420, PX-803 and PX-846. Signed-off-by: Cameron Williams Cc: stable Link: https://lore.kernel.org/r/AM5PR0202MB2564669252BDC59BF55A6E87C4879@AM5PR0202MB2564.eurprd02.prod.outlook.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 109 +++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 8a39ae072c65..6f66dc2ebacc 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -5066,6 +5066,115 @@ static const struct pci_device_id serial_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b2_4_115200 }, + /* + * Brainboxes PX-101 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x4005, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b0_2_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x4019, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_2_15625000 }, + /* + * Brainboxes PX-235/246 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x4004, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b0_1_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x4016, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_1_15625000 }, + /* + * Brainboxes PX-203/PX-257 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x4006, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b0_2_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x4015, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_4_15625000 }, + /* + * Brainboxes PX-260/PX-701 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x400A, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_4_15625000 }, + /* + * Brainboxes PX-310 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x400E, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_2_15625000 }, + /* + * Brainboxes PX-313 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x400C, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_2_15625000 }, + /* + * Brainboxes PX-320/324/PX-376/PX-387 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x400B, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_1_15625000 }, + /* + * Brainboxes PX-335/346 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x400F, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_4_15625000 }, + /* + * Brainboxes PX-368 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x4010, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_4_15625000 }, + /* + * Brainboxes PX-420 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x4000, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b0_4_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x4011, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_4_15625000 }, + /* + * Brainboxes PX-803 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x4009, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b0_1_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x401E, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_1_15625000 }, + /* + * Brainboxes PX-846 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x4008, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b0_1_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x4017, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_1_15625000 }, + /* * Perle PCI-RAS cards */ -- cgit v1.2.3 From 806a449725cbd679a7f52c394d3c87b451d66bd5 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 11 Jul 2022 10:42:52 +0200 Subject: serial: 8250: SERIAL_8250_ASPEED_VUART should depend on ARCH_ASPEED The Aspeed Virtual UART is only present on Aspeed BMC platforms. Hence add a dependency on ARCH_ASPEED, to prevent asking the user about this driver when configuring a kernel without Aspeed BMC support. Reviewed-by: Jeremy Kerr Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/259138c372d433005b4871789ef9ee8d15320307.1657528861.git.geert+renesas@glider.be Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index fdb6c4188695..d0b49e15fbf5 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -254,6 +254,7 @@ config SERIAL_8250_ASPEED_VUART depends on SERIAL_8250 depends on OF depends on REGMAP && MFD_SYSCON + depends on ARCH_ASPEED || COMPILE_TEST help If you want to use the virtual UART (VUART) device on Aspeed BMC platforms, enable this option. This enables the 16550A- -- cgit v1.2.3 From 1d46c08d246e2e0a2d81985727392a5a8348d06a Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Tue, 12 Jul 2022 16:07:45 +0200 Subject: tty: serial: samsung_tty: fix s3c24xx_serial_set_mctrl() S3C2410_UCON is a 32bit register, so it must be read with rd_regl() instead of rd_reg(), otherwise the upper bits will be zeroed. Fix this. Fixes: 72a43046b61a ("tty: serial: samsung_tty: loopback mode support") Tested-by: Chanho Park Reviewed-by: Krzysztof Kozlowski Reviewed-by: Chanho Park Signed-off-by: Marek Szyprowski Link: https://lore.kernel.org/r/20220712140745.30362-1-m.szyprowski@samsung.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 8971fbb49fa3..0fd4ac58c6ce 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -1018,7 +1018,7 @@ 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_reg(port, S3C2410_UCON); + unsigned int ucon = rd_regl(port, S3C2410_UCON); if (mctrl & TIOCM_RTS) umcon |= S3C2410_UMCOM_RTS_LOW; -- cgit v1.2.3 From 4f4e670342b14f302e17c93bd22fc943bbaaf1de Mon Sep 17 00:00:00 2001 From: VAMSHI GAJJELA Date: Wed, 13 Jul 2022 18:47:22 +0530 Subject: serial: 8250_dw: Avoid pslverr on reading empty receiver fifo With PSLVERR_RESP_EN parameter set to 1, the device generates an error response when an attempt to read an empty RBR with FIFO enabled. This happens when LCR writes are ignored when UART is busy. dw8250_check_lcr() in retries to update LCR, invokes dw8250_force_idle() to clear and reset FIFO and eventually reads UART_RX causing the error. Avoid this by not reading RBR/UART_RX when no data is available. Reviewed-by: Andy Shevchenko Signed-off-by: VAMSHI GAJJELA Link: https://lore.kernel.org/r/20220713131722.2316829-1-vamshigajjela@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index e419e032895c..f9e85ed0c50b 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -83,8 +83,21 @@ static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value) static void dw8250_force_idle(struct uart_port *p) { struct uart_8250_port *up = up_to_u8250p(p); + unsigned int lsr; serial8250_clear_and_reinit_fifos(up); + + /* + * With PSLVERR_RESP_EN parameter set to 1, the device generates an + * error response when an attempt to read an empty RBR with FIFO + * enabled. + */ + if (up->fcr & UART_FCR_ENABLE_FIFO) { + lsr = p->serial_in(p, UART_LSR); + if (!(lsr & UART_LSR_DR)) + return; + } + (void)p->serial_in(p, UART_RX); } -- cgit v1.2.3 From 3182efd036c1b955403d131258234896cbd9fbeb Mon Sep 17 00:00:00 2001 From: Doug Berger Date: Wed, 13 Jul 2022 20:13:15 -0700 Subject: serial: 8250_bcm7271: Save/restore RTS in suspend/resume Commit 9cabe26e65a8 ("serial: 8250_bcm7271: UART errors after resuming from S2") prevented an early enabling of RTS during resume, but it did not actively restore the RTS state after resume. Fixes: 9cabe26e65a8 ("serial: 8250_bcm7271: UART errors after resuming from S2") Signed-off-by: Doug Berger Signed-off-by: Florian Fainelli Link: https://lore.kernel.org/r/20220714031316.404918-1-f.fainelli@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_bcm7271.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_bcm7271.c b/drivers/tty/serial/8250/8250_bcm7271.c index 9b878d023dac..8efdc271eb75 100644 --- a/drivers/tty/serial/8250/8250_bcm7271.c +++ b/drivers/tty/serial/8250/8250_bcm7271.c @@ -1139,16 +1139,19 @@ static int __maybe_unused brcmuart_suspend(struct device *dev) struct brcmuart_priv *priv = dev_get_drvdata(dev); struct uart_8250_port *up = serial8250_get_port(priv->line); struct uart_port *port = &up->port; - - serial8250_suspend_port(priv->line); - clk_disable_unprepare(priv->baud_mux_clk); + unsigned long flags; /* * This will prevent resume from enabling RTS before the - * baud rate has been resored. + * baud rate has been restored. */ + spin_lock_irqsave(&port->lock, flags); priv->saved_mctrl = port->mctrl; - port->mctrl = 0; + port->mctrl &= ~TIOCM_RTS; + spin_unlock_irqrestore(&port->lock, flags); + + serial8250_suspend_port(priv->line); + clk_disable_unprepare(priv->baud_mux_clk); return 0; } @@ -1158,6 +1161,7 @@ static int __maybe_unused brcmuart_resume(struct device *dev) struct brcmuart_priv *priv = dev_get_drvdata(dev); struct uart_8250_port *up = serial8250_get_port(priv->line); struct uart_port *port = &up->port; + unsigned long flags; int ret; ret = clk_prepare_enable(priv->baud_mux_clk); @@ -1180,7 +1184,15 @@ static int __maybe_unused brcmuart_resume(struct device *dev) start_rx_dma(serial8250_get_port(priv->line)); } serial8250_resume_port(priv->line); - port->mctrl = priv->saved_mctrl; + + if (priv->saved_mctrl & TIOCM_RTS) { + /* Restore RTS */ + spin_lock_irqsave(&port->lock, flags); + port->mctrl |= TIOCM_RTS; + port->ops->set_mctrl(port, port->mctrl); + spin_unlock_irqrestore(&port->lock, flags); + } + return 0; } -- cgit v1.2.3 From 996fd3cf9c0f37d17867ccc26f8b746169463fcd Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Sun, 10 Jul 2022 18:44:35 +0200 Subject: serial: ar933x: Fix check for RS485 support RS485 is not possible without an RTS GPIO regardless of whether RS485 is enabled at boot time or not. So correct the concerning check in the probe() function. Fixes: e849145e1fdd ("serial: ar933x: Fill in rs485_supported") Signed-off-by: Lino Sanfilippo Link: https://lore.kernel.org/r/20220710164442.2958979-2-LinoSanfilippo@gmx.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/ar933x_uart.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c index f931ecbc0bc0..f7b4638d69e5 100644 --- a/drivers/tty/serial/ar933x_uart.c +++ b/drivers/tty/serial/ar933x_uart.c @@ -798,11 +798,12 @@ static int ar933x_uart_probe(struct platform_device *pdev) up->rts_gpiod = mctrl_gpio_to_gpiod(up->gpios, UART_GPIO_RTS); - if ((port->rs485.flags & SER_RS485_ENABLED) && - !up->rts_gpiod) { - dev_err(&pdev->dev, "lacking rts-gpio, disabling RS485\n"); - port->rs485.flags &= ~SER_RS485_ENABLED; + if (!up->rts_gpiod) { port->rs485_supported = ar933x_no_rs485; + if (port->rs485.flags & SER_RS485_ENABLED) { + dev_err(&pdev->dev, "lacking rts-gpio, disabling RS485\n"); + port->rs485.flags &= ~SER_RS485_ENABLED; + } } #ifdef CONFIG_SERIAL_AR933X_CONSOLE -- cgit v1.2.3 From 184842622c97da2f88f365a981af05432baa5385 Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Sun, 10 Jul 2022 18:44:36 +0200 Subject: serial: ar933x: Remove superfluous code in ar933x_config_rs485() In ar933x_config_rs485() the check for the RTS GPIO is not needed since in case the GPIO is not available at driver init ar933x_no_rs485 is assigned to port->rs485_supported and this function is never called. So remove the check. Also in uart_set_rs485_config() the serial core already assigns the passed serial_rs485 struct to the uart port. So remove the assignment in the drivers rs485_config() function to avoid redundancy. Signed-off-by: Lino Sanfilippo Link: https://lore.kernel.org/r/20220710164442.2958979-3-LinoSanfilippo@gmx.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/ar933x_uart.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c index f7b4638d69e5..32caeac12985 100644 --- a/drivers/tty/serial/ar933x_uart.c +++ b/drivers/tty/serial/ar933x_uart.c @@ -583,15 +583,6 @@ static const struct uart_ops ar933x_uart_ops = { static int ar933x_config_rs485(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485conf) { - struct ar933x_uart_port *up = - container_of(port, struct ar933x_uart_port, port); - - if ((rs485conf->flags & SER_RS485_ENABLED) && - !up->rts_gpiod) { - dev_err(port->dev, "RS485 needs rts-gpio\n"); - return 1; - } - port->rs485 = *rs485conf; return 0; } -- cgit v1.2.3 From 44b27aec9d9680875a1a250bc8bcefc234a37c9f Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Sun, 10 Jul 2022 18:44:37 +0200 Subject: serial: core, 8250: set RS485 termination GPIO in serial core In serial8250_em485_config() the termination GPIO is set with the uart_port spinlock held. This is an issue if setting the GPIO line can sleep (e.g. since the concerning GPIO expander is connected via SPI or I2C). Fix this by setting the termination line outside of the uart_port spinlock in the serial core and using gpiod_set_value_cansleep() which instead of gpiod_set_value() allows it to sleep. Beside fixing the termination GPIO line setting for the 8250 driver this change also makes setting the termination GPIO generic for all UART drivers. Signed-off-by: Lino Sanfilippo Link: https://lore.kernel.org/r/20220710164442.2958979-4-LinoSanfilippo@gmx.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 3 --- drivers/tty/serial/serial_core.c | 12 ++++++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index ed2a606f2da7..72252d956f17 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -676,9 +676,6 @@ int serial8250_em485_config(struct uart_port *port, struct ktermios *termios, rs485->flags &= ~SER_RS485_RTS_AFTER_SEND; } - gpiod_set_value(port->rs485_term_gpio, - rs485->flags & SER_RS485_TERMINATE_BUS); - /* * Both serial8250_em485_init() and serial8250_em485_destroy() * are idempotent. diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 1db44cde76f6..047ec51dbd41 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1358,12 +1358,23 @@ static void uart_sanitize_serial_rs485(struct uart_port *port, struct serial_rs4 memset(rs485->padding1, 0, sizeof(rs485->padding1)); } +static void uart_set_rs485_termination(struct uart_port *port, + const struct serial_rs485 *rs485) +{ + if (!(rs485->flags & SER_RS485_ENABLED)) + return; + + gpiod_set_value_cansleep(port->rs485_term_gpio, + !!(rs485->flags & SER_RS485_TERMINATE_BUS)); +} + int uart_rs485_config(struct uart_port *port) { struct serial_rs485 *rs485 = &port->rs485; int ret; uart_sanitize_serial_rs485(port, rs485); + uart_set_rs485_termination(port, rs485); ret = port->rs485_config(port, NULL, rs485); if (ret) @@ -1406,6 +1417,7 @@ static int uart_set_rs485_config(struct tty_struct *tty, struct uart_port *port, if (ret) return ret; uart_sanitize_serial_rs485(port, &rs485); + uart_set_rs485_termination(port, &rs485); spin_lock_irqsave(&port->lock, flags); ret = port->rs485_config(port, &tty->termios, &rs485); -- cgit v1.2.3 From d8fcd9cfbde5acd42a407d8b48fa80ad9d513bde Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Sun, 10 Jul 2022 18:44:38 +0200 Subject: serial: core: move sanitizing of RS485 delays into own function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the sanitizing of RS485 delays out of uart_sanitize_serial_rs485() into the new function uart_sanitize_serial_rs485_delays(). Reviewed-by: Ilpo Järvinen Signed-off-by: Lino Sanfilippo Link: https://lore.kernel.org/r/20220710164442.2958979-5-LinoSanfilippo@gmx.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 46 +++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 20 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 047ec51dbd41..3158f05a328c 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1302,27 +1302,9 @@ static int uart_check_rs485_flags(struct uart_port *port, struct serial_rs485 *r return 0; } -static void uart_sanitize_serial_rs485(struct uart_port *port, struct serial_rs485 *rs485) +static void uart_sanitize_serial_rs485_delays(struct uart_port *port, + struct serial_rs485 *rs485) { - u32 supported_flags = port->rs485_supported.flags; - - if (!(rs485->flags & SER_RS485_ENABLED)) { - memset(rs485, 0, sizeof(*rs485)); - return; - } - - /* pick sane settings if the user hasn't */ - if ((supported_flags & (SER_RS485_RTS_ON_SEND|SER_RS485_RTS_AFTER_SEND)) && - !(rs485->flags & SER_RS485_RTS_ON_SEND) == - !(rs485->flags & SER_RS485_RTS_AFTER_SEND)) { - dev_warn_ratelimited(port->dev, - "%s (%d): invalid RTS setting, using RTS_ON_SEND instead\n", - port->name, port->line); - rs485->flags |= SER_RS485_RTS_ON_SEND; - rs485->flags &= ~SER_RS485_RTS_AFTER_SEND; - supported_flags |= SER_RS485_RTS_ON_SEND|SER_RS485_RTS_AFTER_SEND; - } - if (!port->rs485_supported.delay_rts_before_send) { if (rs485->delay_rts_before_send) { dev_warn_ratelimited(port->dev, @@ -1350,9 +1332,33 @@ static void uart_sanitize_serial_rs485(struct uart_port *port, struct serial_rs4 "%s (%d): RTS delay after sending clamped to %u ms\n", port->name, port->line, rs485->delay_rts_after_send); } +} + +static void uart_sanitize_serial_rs485(struct uart_port *port, struct serial_rs485 *rs485) +{ + u32 supported_flags = port->rs485_supported.flags; + + if (!(rs485->flags & SER_RS485_ENABLED)) { + memset(rs485, 0, sizeof(*rs485)); + return; + } + + /* Pick sane settings if the user hasn't */ + if ((supported_flags & (SER_RS485_RTS_ON_SEND|SER_RS485_RTS_AFTER_SEND)) && + !(rs485->flags & SER_RS485_RTS_ON_SEND) == + !(rs485->flags & SER_RS485_RTS_AFTER_SEND)) { + dev_warn_ratelimited(port->dev, + "%s (%d): invalid RTS setting, using RTS_ON_SEND instead\n", + port->name, port->line); + rs485->flags |= SER_RS485_RTS_ON_SEND; + rs485->flags &= ~SER_RS485_RTS_AFTER_SEND; + supported_flags |= SER_RS485_RTS_ON_SEND|SER_RS485_RTS_AFTER_SEND; + } rs485->flags &= supported_flags; + uart_sanitize_serial_rs485_delays(port, rs485); + /* Return clean padding area to userspace */ memset(rs485->padding0, 0, sizeof(rs485->padding0)); memset(rs485->padding1, 0, sizeof(rs485->padding1)); -- cgit v1.2.3 From 4dfd10351e49a767f145fb0f6bf7f408f54ab94b Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Sun, 10 Jul 2022 18:44:39 +0200 Subject: serial: core: sanitize RS485 delays read from device tree Currently the RTS delays set via device tree are not clamped to a maximum value although the device tree bindings documentation for RS485 claims that only a maximum of 1000 msecs is allowed. So clamp the values to avoid arbitrary high delay settings. However clamp the values to 100 instead of 1000 msecs to be consistent which the maximum that is allowed when setting the delays from userspace via the UART ioctl TIOCSRS485. Signed-off-by: Lino Sanfilippo Link: https://lore.kernel.org/r/20220710164442.2958979-6-LinoSanfilippo@gmx.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 3158f05a328c..ac198d0d4c80 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -3395,6 +3395,8 @@ int uart_get_rs485_mode(struct uart_port *port) rs485conf->delay_rts_after_send = 0; } + uart_sanitize_serial_rs485_delays(port, rs485conf); + /* * Clear full-duplex and enabled flags, set RTS polarity to active high * to get to a defined state with the following properties: -- cgit v1.2.3 From c64e17584ba78552b51a27374b54686259826360 Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Sun, 10 Jul 2022 18:44:41 +0200 Subject: serial: 8250_dwlib: remove redundant sanity check for RS485 flags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before the drivers rs485_config() function is called the serial core already ensures that only one of both options RTS on send or RTS after send is set. So remove the concerning sanity check in the driver function to avoid redundancy. Reviewed-by: Ilpo Järvinen Signed-off-by: Lino Sanfilippo Link: https://lore.kernel.org/r/20220710164442.2958979-8-LinoSanfilippo@gmx.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dwlib.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_dwlib.c b/drivers/tty/serial/8250/8250_dwlib.c index 2c3b1468bd88..dbe4d44f60d4 100644 --- a/drivers/tty/serial/8250/8250_dwlib.c +++ b/drivers/tty/serial/8250/8250_dwlib.c @@ -187,16 +187,10 @@ static int dw8250_rs485_config(struct uart_port *p, struct ktermios *termios, if (rs485->flags & SER_RS485_ENABLED) { tcr |= DW_UART_TCR_RS485_EN; - if (rs485->flags & SER_RS485_RX_DURING_TX) { + if (rs485->flags & SER_RS485_RX_DURING_TX) tcr |= DW_UART_TCR_XFER_MODE_DE_DURING_RE; - } else { - /* HW does not support same DE level for tx and rx */ - if (!(rs485->flags & SER_RS485_RTS_ON_SEND) == - !(rs485->flags & SER_RS485_RTS_AFTER_SEND)) - return -EINVAL; - + else tcr |= DW_UART_TCR_XFER_MODE_DE_OR_RE; - } dw8250_writel_ext(p, DW_UART_DE_EN, 1); dw8250_writel_ext(p, DW_UART_RE_EN, 1); } else { -- cgit v1.2.3 From 5095ca634f8b134cc202a5f5e4985d2b81f0ef0a Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Sun, 10 Jul 2022 18:44:42 +0200 Subject: serial: 8250: lpc18xx: Remove redundant sanity check for RS485 flags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before the drivers rs485_config() function is called the serial core already ensures that only one of both options RTS on send or RTS after send is set. So remove the concerning sanity check in the driver function to avoid redundancy. Reviewed-by: Ilpo Järvinen Signed-off-by: Lino Sanfilippo Link: https://lore.kernel.org/r/20220710164442.2958979-9-LinoSanfilippo@gmx.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_lpc18xx.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_lpc18xx.c b/drivers/tty/serial/8250/8250_lpc18xx.c index d6ca0d47e9d5..6dc85aaba5d0 100644 --- a/drivers/tty/serial/8250/8250_lpc18xx.c +++ b/drivers/tty/serial/8250/8250_lpc18xx.c @@ -44,12 +44,8 @@ static int lpc18xx_rs485_config(struct uart_port *port, struct ktermios *termios rs485_ctrl_reg |= LPC18XX_UART_RS485CTRL_NMMEN | LPC18XX_UART_RS485CTRL_DCTRL; - if (rs485->flags & SER_RS485_RTS_ON_SEND) { + if (rs485->flags & SER_RS485_RTS_ON_SEND) rs485_ctrl_reg |= LPC18XX_UART_RS485CTRL_OINV; - rs485->flags &= ~SER_RS485_RTS_AFTER_SEND; - } else { - rs485->flags |= SER_RS485_RTS_AFTER_SEND; - } } if (rs485->delay_rts_after_send) { -- cgit v1.2.3 From ceefa81e6e69b020997205e5c30a42d43aa5ae63 Mon Sep 17 00:00:00 2001 From: Thomas Bogendoerfer Date: Fri, 15 Jul 2022 16:03:22 +0200 Subject: serial: remove VR41XX serial driver Commit d3164e2f3b0a ("MIPS: Remove VR41xx support") removed support for MIPS VR41xx platform, so remove exclusive drivers for this platform, too. Signed-off-by: Thomas Bogendoerfer Link: https://lore.kernel.org/r/20220715140322.135825-1-tsbogend@alpha.franken.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 17 - drivers/tty/serial/Makefile | 1 - drivers/tty/serial/vr41xx_siu.c | 932 --------------------------------------- include/uapi/linux/serial_core.h | 4 - 4 files changed, 954 deletions(-) delete mode 100644 drivers/tty/serial/vr41xx_siu.c (limited to 'drivers/tty') diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 8a3ee1525d80..f92963a2226b 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -890,23 +890,6 @@ config SERIAL_TXX9_STDSERIAL bool "TX39XX/49XX SIO act as standard serial" depends on !SERIAL_8250 && SERIAL_TXX9 -config SERIAL_VR41XX - tristate "NEC VR4100 series Serial Interface Unit support" - depends on CPU_VR41XX - select SERIAL_CORE - help - If you have a NEC VR4100 series processor and you want to use - Serial Interface Unit(SIU) or Debug Serial Interface Unit(DSIU) - (not include VR4111/VR4121 DSIU), say Y. Otherwise, say N. - -config SERIAL_VR41XX_CONSOLE - bool "Enable NEC VR4100 series Serial Interface Unit console" - depends on SERIAL_VR41XX=y - select SERIAL_CORE_CONSOLE - help - If you have a NEC VR4100 series processor and you want to use - a console on a serial port, say Y. Otherwise, say N. - config SERIAL_JSM tristate "Digi International NEO and Classic PCI Support" depends on PCI diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 61cc8de95571..238a9557b487 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -51,7 +51,6 @@ obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o obj-$(CONFIG_SERIAL_SC16IS7XX_CORE) += sc16is7xx.o obj-$(CONFIG_SERIAL_JSM) += jsm/ obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o -obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o obj-$(CONFIG_SERIAL_MSM) += msm_serial.o diff --git a/drivers/tty/serial/vr41xx_siu.c b/drivers/tty/serial/vr41xx_siu.c deleted file mode 100644 index 1ba689a81abd..000000000000 --- a/drivers/tty/serial/vr41xx_siu.c +++ /dev/null @@ -1,932 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Driver for NEC VR4100 series Serial Interface Unit. - * - * Copyright (C) 2004-2008 Yoichi Yuasa - * - * Based on drivers/serial/8250.c, by Russell King. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define SIU_BAUD_BASE 1152000 -#define SIU_MAJOR 204 -#define SIU_MINOR_BASE 82 - -#define RX_MAX_COUNT 256 -#define TX_MAX_COUNT 15 - -#define SIUIRSEL 0x08 - #define TMICMODE 0x20 - #define TMICTX 0x10 - #define IRMSEL 0x0c - #define IRMSEL_HP 0x08 - #define IRMSEL_TEMIC 0x04 - #define IRMSEL_SHARP 0x00 - #define IRUSESEL 0x02 - #define SIRSEL 0x01 - -static struct uart_port siu_uart_ports[SIU_PORTS_MAX] = { - [0 ... SIU_PORTS_MAX-1] = { - .lock = __SPIN_LOCK_UNLOCKED(siu_uart_ports->lock), - .irq = 0, - }, -}; - -#ifdef CONFIG_SERIAL_VR41XX_CONSOLE -static uint8_t lsr_break_flag[SIU_PORTS_MAX]; -#endif - -#define siu_read(port, offset) readb((port)->membase + (offset)) -#define siu_write(port, offset, value) writeb((value), (port)->membase + (offset)) - -void vr41xx_select_siu_interface(siu_interface_t interface) -{ - struct uart_port *port; - unsigned long flags; - uint8_t irsel; - - port = &siu_uart_ports[0]; - - spin_lock_irqsave(&port->lock, flags); - - irsel = siu_read(port, SIUIRSEL); - if (interface == SIU_INTERFACE_IRDA) - irsel |= SIRSEL; - else - irsel &= ~SIRSEL; - siu_write(port, SIUIRSEL, irsel); - - spin_unlock_irqrestore(&port->lock, flags); -} -EXPORT_SYMBOL_GPL(vr41xx_select_siu_interface); - -void vr41xx_use_irda(irda_use_t use) -{ - struct uart_port *port; - unsigned long flags; - uint8_t irsel; - - port = &siu_uart_ports[0]; - - spin_lock_irqsave(&port->lock, flags); - - irsel = siu_read(port, SIUIRSEL); - if (use == FIR_USE_IRDA) - irsel |= IRUSESEL; - else - irsel &= ~IRUSESEL; - siu_write(port, SIUIRSEL, irsel); - - spin_unlock_irqrestore(&port->lock, flags); -} -EXPORT_SYMBOL_GPL(vr41xx_use_irda); - -void vr41xx_select_irda_module(irda_module_t module, irda_speed_t speed) -{ - struct uart_port *port; - unsigned long flags; - uint8_t irsel; - - port = &siu_uart_ports[0]; - - spin_lock_irqsave(&port->lock, flags); - - irsel = siu_read(port, SIUIRSEL); - irsel &= ~(IRMSEL | TMICTX | TMICMODE); - switch (module) { - case SHARP_IRDA: - irsel |= IRMSEL_SHARP; - break; - case TEMIC_IRDA: - irsel |= IRMSEL_TEMIC | TMICMODE; - if (speed == IRDA_TX_4MBPS) - irsel |= TMICTX; - break; - case HP_IRDA: - irsel |= IRMSEL_HP; - break; - default: - break; - } - siu_write(port, SIUIRSEL, irsel); - - spin_unlock_irqrestore(&port->lock, flags); -} -EXPORT_SYMBOL_GPL(vr41xx_select_irda_module); - -static inline void siu_clear_fifo(struct uart_port *port) -{ - siu_write(port, UART_FCR, UART_FCR_ENABLE_FIFO); - siu_write(port, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | - UART_FCR_CLEAR_XMIT); - siu_write(port, UART_FCR, 0); -} - -static inline unsigned long siu_port_size(struct uart_port *port) -{ - switch (port->type) { - case PORT_VR41XX_SIU: - return 11UL; - case PORT_VR41XX_DSIU: - return 8UL; - } - - return 0; -} - -static inline unsigned int siu_check_type(struct uart_port *port) -{ - if (port->line == 0) - return PORT_VR41XX_SIU; - if (port->line == 1 && port->irq) - return PORT_VR41XX_DSIU; - - return PORT_UNKNOWN; -} - -static inline const char *siu_type_name(struct uart_port *port) -{ - switch (port->type) { - case PORT_VR41XX_SIU: - return "SIU"; - case PORT_VR41XX_DSIU: - return "DSIU"; - } - - return NULL; -} - -static unsigned int siu_tx_empty(struct uart_port *port) -{ - uint8_t lsr; - - lsr = siu_read(port, UART_LSR); - if (lsr & UART_LSR_TEMT) - return TIOCSER_TEMT; - - return 0; -} - -static void siu_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - uint8_t mcr = 0; - - if (mctrl & TIOCM_DTR) - mcr |= UART_MCR_DTR; - if (mctrl & TIOCM_RTS) - mcr |= UART_MCR_RTS; - if (mctrl & TIOCM_OUT1) - mcr |= UART_MCR_OUT1; - if (mctrl & TIOCM_OUT2) - mcr |= UART_MCR_OUT2; - if (mctrl & TIOCM_LOOP) - mcr |= UART_MCR_LOOP; - - siu_write(port, UART_MCR, mcr); -} - -static unsigned int siu_get_mctrl(struct uart_port *port) -{ - uint8_t msr; - unsigned int mctrl = 0; - - msr = siu_read(port, UART_MSR); - if (msr & UART_MSR_DCD) - mctrl |= TIOCM_CAR; - if (msr & UART_MSR_RI) - mctrl |= TIOCM_RNG; - if (msr & UART_MSR_DSR) - mctrl |= TIOCM_DSR; - if (msr & UART_MSR_CTS) - mctrl |= TIOCM_CTS; - - return mctrl; -} - -static void siu_stop_tx(struct uart_port *port) -{ - unsigned long flags; - uint8_t ier; - - spin_lock_irqsave(&port->lock, flags); - - ier = siu_read(port, UART_IER); - ier &= ~UART_IER_THRI; - siu_write(port, UART_IER, ier); - - spin_unlock_irqrestore(&port->lock, flags); -} - -static void siu_start_tx(struct uart_port *port) -{ - unsigned long flags; - uint8_t ier; - - spin_lock_irqsave(&port->lock, flags); - - ier = siu_read(port, UART_IER); - ier |= UART_IER_THRI; - siu_write(port, UART_IER, ier); - - spin_unlock_irqrestore(&port->lock, flags); -} - -static void siu_stop_rx(struct uart_port *port) -{ - unsigned long flags; - uint8_t ier; - - spin_lock_irqsave(&port->lock, flags); - - ier = siu_read(port, UART_IER); - ier &= ~UART_IER_RLSI; - siu_write(port, UART_IER, ier); - - port->read_status_mask &= ~UART_LSR_DR; - - spin_unlock_irqrestore(&port->lock, flags); -} - -static void siu_enable_ms(struct uart_port *port) -{ - unsigned long flags; - uint8_t ier; - - spin_lock_irqsave(&port->lock, flags); - - ier = siu_read(port, UART_IER); - ier |= UART_IER_MSI; - siu_write(port, UART_IER, ier); - - spin_unlock_irqrestore(&port->lock, flags); -} - -static void siu_break_ctl(struct uart_port *port, int ctl) -{ - unsigned long flags; - uint8_t lcr; - - spin_lock_irqsave(&port->lock, flags); - - lcr = siu_read(port, UART_LCR); - if (ctl == -1) - lcr |= UART_LCR_SBC; - else - lcr &= ~UART_LCR_SBC; - siu_write(port, UART_LCR, lcr); - - spin_unlock_irqrestore(&port->lock, flags); -} - -static inline void receive_chars(struct uart_port *port, uint8_t *status) -{ - uint8_t lsr, ch; - char flag; - int max_count = RX_MAX_COUNT; - - lsr = *status; - - do { - ch = siu_read(port, UART_RX); - port->icount.rx++; - flag = TTY_NORMAL; - -#ifdef CONFIG_SERIAL_VR41XX_CONSOLE - lsr |= lsr_break_flag[port->line]; - lsr_break_flag[port->line] = 0; -#endif - if (unlikely(lsr & (UART_LSR_BI | UART_LSR_FE | - UART_LSR_PE | UART_LSR_OE))) { - if (lsr & UART_LSR_BI) { - lsr &= ~(UART_LSR_FE | UART_LSR_PE); - port->icount.brk++; - - if (uart_handle_break(port)) - goto ignore_char; - } - - if (lsr & UART_LSR_FE) - port->icount.frame++; - if (lsr & UART_LSR_PE) - port->icount.parity++; - if (lsr & UART_LSR_OE) - port->icount.overrun++; - - lsr &= port->read_status_mask; - if (lsr & UART_LSR_BI) - flag = TTY_BREAK; - if (lsr & UART_LSR_FE) - flag = TTY_FRAME; - if (lsr & UART_LSR_PE) - flag = TTY_PARITY; - } - - if (uart_handle_sysrq_char(port, ch)) - goto ignore_char; - - uart_insert_char(port, lsr, UART_LSR_OE, ch, flag); - - ignore_char: - lsr = siu_read(port, UART_LSR); - } while ((lsr & UART_LSR_DR) && (max_count-- > 0)); - - tty_flip_buffer_push(&port->state->port); - - *status = lsr; -} - -static inline void check_modem_status(struct uart_port *port) -{ - uint8_t msr; - - msr = siu_read(port, UART_MSR); - if ((msr & UART_MSR_ANY_DELTA) == 0) - return; - if (msr & UART_MSR_DDCD) - uart_handle_dcd_change(port, msr & UART_MSR_DCD); - if (msr & UART_MSR_TERI) - port->icount.rng++; - if (msr & UART_MSR_DDSR) - port->icount.dsr++; - if (msr & UART_MSR_DCTS) - uart_handle_cts_change(port, msr & UART_MSR_CTS); - - wake_up_interruptible(&port->state->port.delta_msr_wait); -} - -static inline void transmit_chars(struct uart_port *port) -{ - struct circ_buf *xmit; - int max_count = TX_MAX_COUNT; - - xmit = &port->state->xmit; - - if (port->x_char) { - siu_write(port, UART_TX, port->x_char); - port->icount.tx++; - port->x_char = 0; - return; - } - - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - siu_stop_tx(port); - return; - } - - do { - siu_write(port, UART_TX, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (max_count-- > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (uart_circ_empty(xmit)) - siu_stop_tx(port); -} - -static irqreturn_t siu_interrupt(int irq, void *dev_id) -{ - struct uart_port *port; - uint8_t iir, lsr; - - port = (struct uart_port *)dev_id; - - iir = siu_read(port, UART_IIR); - if (iir & UART_IIR_NO_INT) - return IRQ_NONE; - - lsr = siu_read(port, UART_LSR); - if (lsr & UART_LSR_DR) - receive_chars(port, &lsr); - - check_modem_status(port); - - if (lsr & UART_LSR_THRE) - transmit_chars(port); - - return IRQ_HANDLED; -} - -static int siu_startup(struct uart_port *port) -{ - int retval; - - if (port->membase == NULL) - return -ENODEV; - - siu_clear_fifo(port); - - (void)siu_read(port, UART_LSR); - (void)siu_read(port, UART_RX); - (void)siu_read(port, UART_IIR); - (void)siu_read(port, UART_MSR); - - if (siu_read(port, UART_LSR) == 0xff) - return -ENODEV; - - retval = request_irq(port->irq, siu_interrupt, 0, siu_type_name(port), port); - if (retval) - return retval; - - if (port->type == PORT_VR41XX_DSIU) - vr41xx_enable_dsiuint(DSIUINT_ALL); - - siu_write(port, UART_LCR, UART_LCR_WLEN8); - - spin_lock_irq(&port->lock); - siu_set_mctrl(port, port->mctrl); - spin_unlock_irq(&port->lock); - - siu_write(port, UART_IER, UART_IER_RLSI | UART_IER_RDI); - - (void)siu_read(port, UART_LSR); - (void)siu_read(port, UART_RX); - (void)siu_read(port, UART_IIR); - (void)siu_read(port, UART_MSR); - - return 0; -} - -static void siu_shutdown(struct uart_port *port) -{ - unsigned long flags; - uint8_t lcr; - - siu_write(port, UART_IER, 0); - - spin_lock_irqsave(&port->lock, flags); - - port->mctrl &= ~TIOCM_OUT2; - siu_set_mctrl(port, port->mctrl); - - spin_unlock_irqrestore(&port->lock, flags); - - lcr = siu_read(port, UART_LCR); - lcr &= ~UART_LCR_SBC; - siu_write(port, UART_LCR, lcr); - - siu_clear_fifo(port); - - (void)siu_read(port, UART_RX); - - if (port->type == PORT_VR41XX_DSIU) - vr41xx_disable_dsiuint(DSIUINT_ALL); - - free_irq(port->irq, port); -} - -static void siu_set_termios(struct uart_port *port, struct ktermios *new, - struct ktermios *old) -{ - tcflag_t c_cflag, c_iflag; - uint8_t lcr, fcr, ier; - unsigned int baud, quot; - unsigned long flags; - - c_cflag = new->c_cflag; - lcr = UART_LCR_WLEN(tty_get_char_size(c_cflag)); - - if (c_cflag & CSTOPB) - lcr |= UART_LCR_STOP; - if (c_cflag & PARENB) - lcr |= UART_LCR_PARITY; - if ((c_cflag & PARODD) != PARODD) - lcr |= UART_LCR_EPAR; - if (c_cflag & CMSPAR) - lcr |= UART_LCR_SPAR; - - baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16); - quot = uart_get_divisor(port, baud); - - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10; - - spin_lock_irqsave(&port->lock, flags); - - uart_update_timeout(port, c_cflag, baud); - - c_iflag = new->c_iflag; - - port->read_status_mask = UART_LSR_THRE | UART_LSR_OE | UART_LSR_DR; - if (c_iflag & INPCK) - port->read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (c_iflag & (IGNBRK | BRKINT | PARMRK)) - port->read_status_mask |= UART_LSR_BI; - - port->ignore_status_mask = 0; - if (c_iflag & IGNPAR) - port->ignore_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (c_iflag & IGNBRK) { - port->ignore_status_mask |= UART_LSR_BI; - if (c_iflag & IGNPAR) - port->ignore_status_mask |= UART_LSR_OE; - } - - if ((c_cflag & CREAD) == 0) - port->ignore_status_mask |= UART_LSR_DR; - - ier = siu_read(port, UART_IER); - ier &= ~UART_IER_MSI; - if (UART_ENABLE_MS(port, c_cflag)) - ier |= UART_IER_MSI; - siu_write(port, UART_IER, ier); - - siu_write(port, UART_LCR, lcr | UART_LCR_DLAB); - - siu_write(port, UART_DLL, (uint8_t)quot); - siu_write(port, UART_DLM, (uint8_t)(quot >> 8)); - - siu_write(port, UART_LCR, lcr); - - siu_write(port, UART_FCR, fcr); - - siu_set_mctrl(port, port->mctrl); - - spin_unlock_irqrestore(&port->lock, flags); -} - -static void siu_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) -{ - switch (state) { - case 0: - switch (port->type) { - case PORT_VR41XX_SIU: - vr41xx_supply_clock(SIU_CLOCK); - break; - case PORT_VR41XX_DSIU: - vr41xx_supply_clock(DSIU_CLOCK); - break; - } - break; - case 3: - switch (port->type) { - case PORT_VR41XX_SIU: - vr41xx_mask_clock(SIU_CLOCK); - break; - case PORT_VR41XX_DSIU: - vr41xx_mask_clock(DSIU_CLOCK); - break; - } - break; - } -} - -static const char *siu_type(struct uart_port *port) -{ - return siu_type_name(port); -} - -static void siu_release_port(struct uart_port *port) -{ - unsigned long size; - - if (port->flags & UPF_IOREMAP) { - iounmap(port->membase); - port->membase = NULL; - } - - size = siu_port_size(port); - release_mem_region(port->mapbase, size); -} - -static int siu_request_port(struct uart_port *port) -{ - unsigned long size; - struct resource *res; - - size = siu_port_size(port); - res = request_mem_region(port->mapbase, size, siu_type_name(port)); - if (res == NULL) - return -EBUSY; - - if (port->flags & UPF_IOREMAP) { - port->membase = ioremap(port->mapbase, size); - if (port->membase == NULL) { - release_resource(res); - return -ENOMEM; - } - } - - return 0; -} - -static void siu_config_port(struct uart_port *port, int flags) -{ - if (flags & UART_CONFIG_TYPE) { - port->type = siu_check_type(port); - (void)siu_request_port(port); - } -} - -static int siu_verify_port(struct uart_port *port, struct serial_struct *serial) -{ - if (port->type != PORT_VR41XX_SIU && port->type != PORT_VR41XX_DSIU) - return -EINVAL; - if (port->irq != serial->irq) - return -EINVAL; - if (port->iotype != serial->io_type) - return -EINVAL; - if (port->mapbase != (unsigned long)serial->iomem_base) - return -EINVAL; - - return 0; -} - -static const struct uart_ops siu_uart_ops = { - .tx_empty = siu_tx_empty, - .set_mctrl = siu_set_mctrl, - .get_mctrl = siu_get_mctrl, - .stop_tx = siu_stop_tx, - .start_tx = siu_start_tx, - .stop_rx = siu_stop_rx, - .enable_ms = siu_enable_ms, - .break_ctl = siu_break_ctl, - .startup = siu_startup, - .shutdown = siu_shutdown, - .set_termios = siu_set_termios, - .pm = siu_pm, - .type = siu_type, - .release_port = siu_release_port, - .request_port = siu_request_port, - .config_port = siu_config_port, - .verify_port = siu_verify_port, -}; - -static int siu_init_ports(struct platform_device *pdev) -{ - struct uart_port *port; - struct resource *res; - int *type = dev_get_platdata(&pdev->dev); - int i; - - if (!type) - return 0; - - port = siu_uart_ports; - for (i = 0; i < SIU_PORTS_MAX; i++) { - port->type = type[i]; - if (port->type == PORT_UNKNOWN) - continue; - port->irq = platform_get_irq(pdev, i); - port->uartclk = SIU_BAUD_BASE * 16; - port->fifosize = 16; - port->regshift = 0; - port->iotype = UPIO_MEM; - port->flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF; - port->line = i; - res = platform_get_resource(pdev, IORESOURCE_MEM, i); - port->mapbase = res->start; - port++; - } - - return i; -} - -#ifdef CONFIG_SERIAL_VR41XX_CONSOLE - -static void wait_for_xmitr(struct uart_port *port) -{ - int timeout = 10000; - uint8_t lsr, msr; - - do { - lsr = siu_read(port, UART_LSR); - if (lsr & UART_LSR_BI) - lsr_break_flag[port->line] = UART_LSR_BI; - - if (uart_lsr_tx_empty(lsr)) - break; - } while (timeout-- > 0); - - if (port->flags & UPF_CONS_FLOW) { - timeout = 1000000; - - do { - msr = siu_read(port, UART_MSR); - if ((msr & UART_MSR_CTS) != 0) - break; - } while (timeout-- > 0); - } -} - -static void siu_console_putchar(struct uart_port *port, unsigned char ch) -{ - wait_for_xmitr(port); - siu_write(port, UART_TX, ch); -} - -static void siu_console_write(struct console *con, const char *s, unsigned count) -{ - struct uart_port *port; - uint8_t ier; - - port = &siu_uart_ports[con->index]; - - ier = siu_read(port, UART_IER); - siu_write(port, UART_IER, 0); - - uart_console_write(port, s, count, siu_console_putchar); - - wait_for_xmitr(port); - siu_write(port, UART_IER, ier); -} - -static int __init siu_console_setup(struct console *con, char *options) -{ - struct uart_port *port; - int baud = 9600; - int parity = 'n'; - int bits = 8; - int flow = 'n'; - - if (con->index >= SIU_PORTS_MAX) - con->index = 0; - - port = &siu_uart_ports[con->index]; - if (port->membase == NULL) { - if (port->mapbase == 0) - return -ENODEV; - port->membase = ioremap(port->mapbase, siu_port_size(port)); - } - - if (port->type == PORT_VR41XX_SIU) - vr41xx_select_siu_interface(SIU_INTERFACE_RS232C); - - if (options != NULL) - uart_parse_options(options, &baud, &parity, &bits, &flow); - - return uart_set_options(port, con, baud, parity, bits, flow); -} - -static struct uart_driver siu_uart_driver; - -static struct console siu_console = { - .name = "ttyVR", - .write = siu_console_write, - .device = uart_console_device, - .setup = siu_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &siu_uart_driver, -}; - -static int siu_console_init(void) -{ - struct uart_port *port; - int i; - - for (i = 0; i < SIU_PORTS_MAX; i++) { - port = &siu_uart_ports[i]; - port->ops = &siu_uart_ops; - } - - register_console(&siu_console); - - return 0; -} - -console_initcall(siu_console_init); - -void __init vr41xx_siu_early_setup(struct uart_port *port) -{ - if (port->type == PORT_UNKNOWN) - return; - - siu_uart_ports[port->line].line = port->line; - siu_uart_ports[port->line].type = port->type; - siu_uart_ports[port->line].uartclk = SIU_BAUD_BASE * 16; - siu_uart_ports[port->line].mapbase = port->mapbase; - siu_uart_ports[port->line].ops = &siu_uart_ops; -} - -#define SERIAL_VR41XX_CONSOLE &siu_console -#else -#define SERIAL_VR41XX_CONSOLE NULL -#endif - -static struct uart_driver siu_uart_driver = { - .owner = THIS_MODULE, - .driver_name = "SIU", - .dev_name = "ttyVR", - .major = SIU_MAJOR, - .minor = SIU_MINOR_BASE, - .cons = SERIAL_VR41XX_CONSOLE, -}; - -static int siu_probe(struct platform_device *dev) -{ - struct uart_port *port; - int num, i, retval; - - num = siu_init_ports(dev); - if (num <= 0) - return -ENODEV; - - siu_uart_driver.nr = num; - retval = uart_register_driver(&siu_uart_driver); - if (retval) - return retval; - - for (i = 0; i < num; i++) { - port = &siu_uart_ports[i]; - port->ops = &siu_uart_ops; - port->dev = &dev->dev; - port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_VR41XX_CONSOLE); - - retval = uart_add_one_port(&siu_uart_driver, port); - if (retval < 0) { - port->dev = NULL; - break; - } - } - - if (i == 0 && retval < 0) { - uart_unregister_driver(&siu_uart_driver); - return retval; - } - - return 0; -} - -static int siu_remove(struct platform_device *dev) -{ - struct uart_port *port; - int i; - - for (i = 0; i < siu_uart_driver.nr; i++) { - port = &siu_uart_ports[i]; - if (port->dev == &dev->dev) { - uart_remove_one_port(&siu_uart_driver, port); - port->dev = NULL; - } - } - - uart_unregister_driver(&siu_uart_driver); - - return 0; -} - -static int siu_suspend(struct platform_device *dev, pm_message_t state) -{ - struct uart_port *port; - int i; - - for (i = 0; i < siu_uart_driver.nr; i++) { - port = &siu_uart_ports[i]; - if ((port->type == PORT_VR41XX_SIU || - port->type == PORT_VR41XX_DSIU) && port->dev == &dev->dev) - uart_suspend_port(&siu_uart_driver, port); - - } - - return 0; -} - -static int siu_resume(struct platform_device *dev) -{ - struct uart_port *port; - int i; - - for (i = 0; i < siu_uart_driver.nr; i++) { - port = &siu_uart_ports[i]; - if ((port->type == PORT_VR41XX_SIU || - port->type == PORT_VR41XX_DSIU) && port->dev == &dev->dev) - uart_resume_port(&siu_uart_driver, port); - } - - return 0; -} - -static struct platform_driver siu_device_driver = { - .probe = siu_probe, - .remove = siu_remove, - .suspend = siu_suspend, - .resume = siu_resume, - .driver = { - .name = "SIU", - }, -}; - -module_platform_driver(siu_device_driver); - -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:SIU"); diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h index 6faf502b7860..3ba34d8378bd 100644 --- a/include/uapi/linux/serial_core.h +++ b/include/uapi/linux/serial_core.h @@ -124,10 +124,6 @@ /* TXX9 type number */ #define PORT_TXX9 64 -/* NEC VR4100 series SIU/DSIU */ -#define PORT_VR41XX_SIU 65 -#define PORT_VR41XX_DSIU 66 - /* Samsung S3C2400 SoC */ #define PORT_S3C2400 67 -- cgit v1.2.3 From af77c56aa35325daa2bc2bed5c2ebf169be61b86 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Tue, 19 Jul 2022 14:49:39 +0900 Subject: tty: vt: initialize unicode screen buffer syzbot reports kernel infoleak at vcs_read() [1], for buffer can be read immediately after resize operation. Initialize buffer using kzalloc(). ---------- #include #include #include #include int main(int argc, char *argv[]) { struct fb_var_screeninfo var = { }; const int fb_fd = open("/dev/fb0", 3); ioctl(fb_fd, FBIOGET_VSCREENINFO, &var); var.yres = 0x21; ioctl(fb_fd, FBIOPUT_VSCREENINFO, &var); return read(open("/dev/vcsu", O_RDONLY), &var, sizeof(var)) == -1; } ---------- Link: https://syzkaller.appspot.com/bug?extid=31a641689d43387f05d3 [1] Cc: stable Reported-by: syzbot Reviewed-by: Jiri Slaby Signed-off-by: Tetsuo Handa Link: https://lore.kernel.org/r/4ef053cf-e796-fb5e-58b7-3ae58242a4ad@I-love.SAKURA.ne.jp Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 1899b8a5d73e..cc8b9a3e58f1 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -344,7 +344,7 @@ static struct uni_screen *vc_uniscr_alloc(unsigned int cols, unsigned int rows) /* allocate everything in one go */ memsize = cols * rows * sizeof(char32_t); memsize += rows * sizeof(char32_t *); - p = vmalloc(memsize); + p = vzalloc(memsize); if (!p) return NULL; -- cgit v1.2.3 From b9f1736e475dba0d6da48fdcb831248ab1597886 Mon Sep 17 00:00:00 2001 From: Guo Mengqi Date: Fri, 15 Jul 2022 10:33:12 +0800 Subject: serial: 8250_bcm2835aux: Add missing clk_disable_unprepare() The error path when get clock frequency fails in bcm2835aux_serial driver does not correctly disable the clock. This flaw was found using a static analysis tool "Hulk Robot", which reported the following warning when analyzing linux-next/master: drivers/tty/serial/8250/8250_bcm2835aux.c: warning: clk_disable_unprepare_missing.cocci The cocci script checks for the existence of clk_disable_unprepare() paired with clk_prepare_enable(). Add the missing clk_disable_unprepare() to the error path. Fixes: fcc446c8aa63 ("serial: 8250_bcm2835aux: Add ACPI support") Reported-by: Hulk Robot Reviewed-by: Florian Fainelli Signed-off-by: Guo Mengqi Link: https://lore.kernel.org/r/20220715023312.37808-1-guomengqi3@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_bcm2835aux.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c index 047e14ccb165..15a2387a5b25 100644 --- a/drivers/tty/serial/8250/8250_bcm2835aux.c +++ b/drivers/tty/serial/8250/8250_bcm2835aux.c @@ -167,8 +167,10 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev) uartclk = clk_get_rate(data->clk); if (!uartclk) { ret = device_property_read_u32(&pdev->dev, "clock-frequency", &uartclk); - if (ret) - return dev_err_probe(&pdev->dev, ret, "could not get clk rate\n"); + if (ret) { + dev_err_probe(&pdev->dev, ret, "could not get clk rate\n"); + goto dis_clk; + } } /* the HW-clock divider for bcm2835aux is 8, -- cgit v1.2.3 From c474c775716edd46a51bf8161142bbd1545f8733 Mon Sep 17 00:00:00 2001 From: Vijaya Krishna Nivarthi Date: Sat, 16 Jul 2022 00:25:43 +0530 Subject: tty: serial: qcom-geni-serial: Fix get_clk_div_rate() which otherwise could return a sub-optimal clock rate. In the logic around call to clk_round_rate(), for some corner conditions, get_clk_div_rate() could return an sub-optimal clock rate. Also, if an exact clock rate was not found lowest clock was being returned. Search for suitable clock rate in 2 steps a) exact match or within 2% tolerance b) within 5% tolerance This also takes care of corner conditions. Fixes: c2194bc999d4 ("tty: serial: qcom-geni-serial: Remove uart frequency table. Instead, find suitable frequency with call to clk_round_rate") Reviewed-by: Douglas Anderson Signed-off-by: Vijaya Krishna Nivarthi Link: https://lore.kernel.org/r/1657911343-1909-1-git-send-email-quic_vnivarth@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/qcom_geni_serial.c | 88 +++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 35 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index f8f950641ad9..f754619451dc 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -940,52 +940,63 @@ static int qcom_geni_serial_startup(struct uart_port *uport) return 0; } -static unsigned long get_clk_div_rate(struct clk *clk, unsigned int baud, - unsigned int sampling_rate, unsigned int *clk_div) +static unsigned long find_clk_rate_in_tol(struct clk *clk, unsigned int desired_clk, + unsigned int *clk_div, unsigned int percent_tol) { - unsigned long ser_clk; - unsigned long desired_clk; - unsigned long freq, prev; + unsigned long freq; unsigned long div, maxdiv; - int64_t mult; - - desired_clk = baud * sampling_rate; - if (!desired_clk) { - pr_err("%s: Invalid frequency\n", __func__); - return 0; - } + u64 mult; + unsigned long offset, abs_tol, achieved; + abs_tol = div_u64((u64)desired_clk * percent_tol, 100); maxdiv = CLK_DIV_MSK >> CLK_DIV_SHFT; - prev = 0; - - for (div = 1; div <= maxdiv; div++) { - mult = div * desired_clk; - if (mult > ULONG_MAX) + div = 1; + while (div <= maxdiv) { + mult = (u64)div * desired_clk; + if (mult != (unsigned long)mult) break; - freq = clk_round_rate(clk, (unsigned long)mult); - if (!(freq % desired_clk)) { - ser_clk = freq; - break; - } + offset = div * abs_tol; + freq = clk_round_rate(clk, mult - offset); - if (!prev) - ser_clk = freq; - else if (prev == freq) + /* Can only get lower if we're done */ + if (freq < mult - offset) break; - prev = freq; - } + /* + * Re-calculate div in case rounding skipped rates but we + * ended up at a good one, then check for a match. + */ + div = DIV_ROUND_CLOSEST(freq, desired_clk); + achieved = DIV_ROUND_CLOSEST(freq, div); + if (achieved <= desired_clk + abs_tol && + achieved >= desired_clk - abs_tol) { + *clk_div = div; + return freq; + } - if (!ser_clk) { - pr_err("%s: Can't find matching DFS entry for baud %d\n", - __func__, baud); - return ser_clk; + div = DIV_ROUND_UP(freq, desired_clk); } - *clk_div = ser_clk / desired_clk; - if (!(*clk_div)) - *clk_div = 1; + return 0; +} + +static unsigned long get_clk_div_rate(struct clk *clk, unsigned int baud, + unsigned int sampling_rate, unsigned int *clk_div) +{ + unsigned long ser_clk; + unsigned long desired_clk; + + desired_clk = baud * sampling_rate; + if (!desired_clk) + return 0; + + /* + * try to find a clock rate within 2% tolerance, then within 5% + */ + ser_clk = find_clk_rate_in_tol(clk, desired_clk, clk_div, 2); + if (!ser_clk) + ser_clk = find_clk_rate_in_tol(clk, desired_clk, clk_div, 5); return ser_clk; } @@ -1020,8 +1031,15 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport, clk_rate = get_clk_div_rate(port->se.clk, baud, sampling_rate, &clk_div); - if (!clk_rate) + if (!clk_rate) { + dev_err(port->se.dev, + "Couldn't find suitable clock rate for %lu\n", + baud * sampling_rate); goto out_restart_rx; + } + + dev_dbg(port->se.dev, "desired_rate-%lu, clk_rate-%lu, clk_div-%u\n", + baud * sampling_rate, clk_rate, clk_div); uport->uartclk = clk_rate; dev_pm_opp_set_rate(uport->dev, clk_rate); -- cgit v1.2.3 From 070298c84e5b924c688a4d08c3a9193175cdffd8 Mon Sep 17 00:00:00 2001 From: Shenwei Wang Date: Thu, 14 Jul 2022 13:58:58 -0500 Subject: serial: fsl_lpuart: zero out parity bit in CS7 mode The LPUART hardware doesn't zero out the parity bit on the received characters. This behavior won't impact the use cases of CS8 because the parity bit is the 9th bit which is not currently used by software. But the parity bit for CS7 must be zeroed out by software in order to get the correct raw data. Signed-off-by: Shenwei Wang Link: https://lore.kernel.org/r/20220714185858.615373-1-shenwei.wang@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index fc7d235a1e27..afa0f941c862 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -274,6 +274,8 @@ struct lpuart_port { int rx_dma_rng_buf_len; unsigned int dma_tx_nents; wait_queue_head_t dma_wait; + bool is_cs7; /* Set to true when character size is 7 */ + /* and the parity is enabled */ }; struct lpuart_soc_data { @@ -1022,6 +1024,9 @@ static void lpuart32_rxint(struct lpuart_port *sport) flg = TTY_OVERRUN; } + if (sport->is_cs7) + rx &= 0x7F; + if (tty_insert_flip_char(port, rx, flg) == 0) sport->port.icount.buf_overrun++; } @@ -1107,6 +1112,17 @@ static void lpuart_handle_sysrq(struct lpuart_port *sport) } } +static int lpuart_tty_insert_flip_string(struct tty_port *port, + unsigned char *chars, size_t size, bool is_cs7) +{ + int i; + + if (is_cs7) + for (i = 0; i < size; i++) + chars[i] &= 0x7F; + return tty_insert_flip_string(port, chars, size); +} + static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) { struct tty_port *port = &sport->port.state->port; @@ -1217,7 +1233,8 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) if (ring->head < ring->tail) { count = sport->rx_sgl.length - ring->tail; - copied = tty_insert_flip_string(port, ring->buf + ring->tail, count); + copied = lpuart_tty_insert_flip_string(port, ring->buf + ring->tail, + count, sport->is_cs7); if (copied != count) sport->port.icount.buf_overrun++; ring->tail = 0; @@ -1227,7 +1244,8 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) /* Finally we read data from tail to head */ if (ring->tail < ring->head) { count = ring->head - ring->tail; - copied = tty_insert_flip_string(port, ring->buf + ring->tail, count); + copied = lpuart_tty_insert_flip_string(port, ring->buf + ring->tail, + count, sport->is_cs7); if (copied != count) sport->port.icount.buf_overrun++; /* Wrap ring->head if needed */ @@ -2066,6 +2084,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, ctrl = old_ctrl = lpuart32_read(&sport->port, UARTCTRL); bd = lpuart32_read(&sport->port, UARTBAUD); modem = lpuart32_read(&sport->port, UARTMODIR); + sport->is_cs7 = false; /* * only support CS8 and CS7, and for CS7 must enable PE. * supported mode: @@ -2184,6 +2203,9 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, lpuart32_write(&sport->port, ctrl, UARTCTRL); /* restore control register */ + if ((ctrl & (UARTCTRL_PE | UARTCTRL_M)) == UARTCTRL_PE) + sport->is_cs7 = true; + if (old && sport->lpuart_dma_rx_use) { if (!lpuart_start_rx_dma(sport)) rx_dma_timer_init(sport); -- cgit v1.2.3 From c7039ce904c0f80253a1171d10353e7832c3e4b3 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 21 Jul 2022 22:24:30 +0100 Subject: serial: stm32: make info structs static to avoid sparse warnings The info structs are local only to the stm32-usart.c driver and are triggering sparse warnings about being undecalred. Move these into the main driver code and make them static to avoid the following warnings: drivers/tty/serial/stm32-usart.h:42:25: warning: symbol 'stm32f4_info' was not declared. Should it be static? drivers/tty/serial/stm32-usart.h:63:25: warning: symbol 'stm32f7_info' was not declared. Should it be static? drivers/tty/serial/stm32-usart.h:85:25: warning: symbol 'stm32h7_info' was not declared. Should it be static? Signed-off-by: Ben Dooks Link: https://lore.kernel.org/r/20220721212430.453192-1-ben-linux@fluff.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/stm32-usart.c | 69 ++++++++++++++++++++++++++++++++++++++++ drivers/tty/serial/stm32-usart.h | 68 --------------------------------------- 2 files changed, 69 insertions(+), 68 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index ff5c7e0ebc4c..f8ea95d14309 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -35,6 +35,75 @@ #include "serial_mctrl_gpio.h" #include "stm32-usart.h" + +/* Register offsets */ +static struct stm32_usart_info 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, + }, + .cfg = { + .uart_enable_bit = 13, + .has_7bits_data = false, + .fifosize = 1, + } +}; + +static struct stm32_usart_info 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, + }, + .cfg = { + .uart_enable_bit = 0, + .has_7bits_data = true, + .has_swap = true, + .fifosize = 1, + } +}; + +static struct stm32_usart_info 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, + }, + .cfg = { + .uart_enable_bit = 0, + .has_7bits_data = true, + .has_swap = true, + .has_wakeup = true, + .has_fifo = true, + .fifosize = 16, + } +}; + static void stm32_usart_stop_tx(struct uart_port *port); static void stm32_usart_transmit_chars(struct uart_port *port); static void __maybe_unused stm32_usart_console_putchar(struct uart_port *port, unsigned char ch); diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h index ee69c203b926..0ec41a732c88 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -38,74 +38,6 @@ struct stm32_usart_info { #define UNDEF_REG 0xff -/* Register offsets */ -struct stm32_usart_info 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, - }, - .cfg = { - .uart_enable_bit = 13, - .has_7bits_data = false, - .fifosize = 1, - } -}; - -struct stm32_usart_info 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, - }, - .cfg = { - .uart_enable_bit = 0, - .has_7bits_data = true, - .has_swap = true, - .fifosize = 1, - } -}; - -struct stm32_usart_info 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, - }, - .cfg = { - .uart_enable_bit = 0, - .has_7bits_data = true, - .has_swap = true, - .has_wakeup = true, - .has_fifo = true, - .fifosize = 16, - } -}; - /* USART_SR (F4) / USART_ISR (F7) */ #define USART_SR_PE BIT(0) #define USART_SR_FE BIT(1) -- cgit v1.2.3 From 707f816f25590c20e056b3bd4a17ce69b03fe856 Mon Sep 17 00:00:00 2001 From: Sherry Sun Date: Mon, 25 Jul 2022 13:01:15 +0800 Subject: tty: serial: fsl_lpuart: correct the count of break characters The LPUART can't distinguish between a break signal and a framing error, so need to count the break characters if there is a framing error and received data is zero instead of the parity error. Fixes: 5541a9bacfe5 ("serial: fsl_lpuart: handle break and make sysrq work") Reviewed-by: Michael Walle Signed-off-by: Sherry Sun Link: https://lore.kernel.org/r/20220725050115.12396-1-sherry.sun@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index afa0f941c862..f6c33cd228c8 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -992,12 +992,12 @@ static void lpuart32_rxint(struct lpuart_port *sport) if (sr & (UARTSTAT_PE | UARTSTAT_OR | UARTSTAT_FE)) { if (sr & UARTSTAT_PE) { + sport->port.icount.parity++; + } else if (sr & UARTSTAT_FE) { if (is_break) sport->port.icount.brk++; else - sport->port.icount.parity++; - } else if (sr & UARTSTAT_FE) { - sport->port.icount.frame++; + sport->port.icount.frame++; } if (sr & UARTSTAT_OR) @@ -1012,12 +1012,12 @@ static void lpuart32_rxint(struct lpuart_port *sport) sr &= sport->port.read_status_mask; if (sr & UARTSTAT_PE) { + flg = TTY_PARITY; + } else if (sr & UARTSTAT_FE) { if (is_break) flg = TTY_BREAK; else - flg = TTY_PARITY; - } else if (sr & UARTSTAT_FE) { - flg = TTY_FRAME; + flg = TTY_FRAME; } if (sr & UARTSTAT_OR) -- cgit v1.2.3 From a7209541239e5dd44d981289e5f9059222d40fd1 Mon Sep 17 00:00:00 2001 From: Narendra Hadke Date: Tue, 26 Jul 2022 11:12:21 +0200 Subject: serial: mvebu-uart: uart2 error bits clearing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For mvebu uart2, error bits are not cleared on buffer read. This causes interrupt loop and system hang. Cc: stable@vger.kernel.org Reviewed-by: Yi Guo Reviewed-by: Nadav Haklai Signed-off-by: Narendra Hadke Signed-off-by: Pali Rohár Link: https://lore.kernel.org/r/20220726091221.12358-1-pali@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/mvebu-uart.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c index 0429c2a54290..ff61a8d00014 100644 --- a/drivers/tty/serial/mvebu-uart.c +++ b/drivers/tty/serial/mvebu-uart.c @@ -265,6 +265,7 @@ static void mvebu_uart_rx_chars(struct uart_port *port, unsigned int status) struct tty_port *tport = &port->state->port; unsigned char ch = 0; char flag = 0; + int ret; do { if (status & STAT_RX_RDY(port)) { @@ -277,6 +278,16 @@ static void mvebu_uart_rx_chars(struct uart_port *port, unsigned int status) port->icount.parity++; } + /* + * For UART2, error bits are not cleared on buffer read. + * This causes interrupt loop and system hang. + */ + if (IS_EXTENDED(port) && (status & STAT_BRK_ERR)) { + ret = readl(port->membase + UART_STAT); + ret |= STAT_BRK_ERR; + writel(ret, port->membase + UART_STAT); + } + if (status & STAT_BRK_DET) { port->icount.brk++; status &= ~(STAT_FRM_ERR | STAT_PAR_ERR); -- cgit v1.2.3 From c4bd17a6ddf3b92bf9d7939ae251570ace14bb52 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 28 Jul 2022 08:10:52 +0200 Subject: Documentation: serial: dedup kernel-doc for uart functions Some of the serial (uart_*) functions are documented twice. Once as kernel-doc along their sources and once in Documentation. So deduplicate these texts, merge them into kernel-doc in the sources, and link them using kernel-doc: from the Documentation. To be properly linked and rendered, tabulators had to be removed from the comments. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220728061056.20799-2-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/serial/driver.rst | 84 +---------------- drivers/tty/serial/serial_core.c | 141 +++++++++++++++++------------ 2 files changed, 87 insertions(+), 138 deletions(-) (limited to 'drivers/tty') diff --git a/Documentation/driver-api/serial/driver.rst b/Documentation/driver-api/serial/driver.rst index cb0ec6db4f1e..ac9620e97f4b 100644 --- a/Documentation/driver-api/serial/driver.rst +++ b/Documentation/driver-api/serial/driver.rst @@ -69,85 +69,11 @@ uart_ops Other functions --------------- -uart_update_timeout(port,cflag,baud) - Update the frame timing information according to the number of bits, - parity, stop bits and baud rate. The FIFO drain timeout is derived - from the frame timing information. - - Locking: caller is expected to take port->lock - - Interrupts: n/a - -uart_get_baud_rate(port,termios,old,min,max) - Return the numeric baud rate for the specified termios, taking - account of the special 38400 baud "kludge". The B0 baud rate - is mapped to 9600 baud. - - If the baud rate is not within min..max, then if old is non-NULL, - the original baud rate will be tried. If that exceeds the - min..max constraint, 9600 baud will be returned. termios will - be updated to the baud rate in use. - - Note: min..max must always allow 9600 baud to be selected. - - Locking: caller dependent. - - Interrupts: n/a - -uart_get_divisor(port,baud) - Return the divisor (baud_base / baud) for the specified baud - rate, appropriately rounded. - - If 38400 baud and custom divisor is selected, return the - custom divisor instead. - - Locking: caller dependent. - - Interrupts: n/a - -uart_match_port(port1,port2) - This utility function can be used to determine whether two - uart_port structures describe the same port. - - Locking: n/a - - Interrupts: n/a - -uart_write_wakeup(port) - A driver is expected to call this function when the number of - characters in the transmit buffer have dropped below a threshold. - - Locking: port->lock should be held. - - Interrupts: n/a - -uart_register_driver(drv) - Register a uart driver with the core driver. We in turn register - with the tty layer, and initialise the core driver per-port state. - - drv->port should be NULL, and the per-port structures should be - registered using uart_add_one_port after this call has succeeded. - - Locking: none - - Interrupts: enabled - -uart_unregister_driver() - Remove all references to a driver from the core driver. The low - level driver must have removed all its ports via the - uart_remove_one_port() if it registered them with uart_add_one_port(). - - Locking: none - - Interrupts: enabled - -**uart_suspend_port()** - -**uart_resume_port()** - -**uart_add_one_port()** - -**uart_remove_one_port()** +.. kernel-doc:: drivers/tty/serial/serial_core.c + :identifiers: uart_update_timeout uart_get_baud_rate uart_get_divisor + uart_match_port uart_write_wakeup uart_register_driver + uart_unregister_driver uart_suspend_port uart_resume_port + uart_add_one_port uart_remove_one_port Other notes ----------- diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index ac198d0d4c80..c302aa34668d 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -97,9 +97,16 @@ static inline struct uart_port *uart_port_check(struct uart_state *state) return state->uart_port; } -/* - * This routine is used by the interrupt handler to schedule processing in - * the software interrupt portion of the driver. +/** + * uart_write_wakeup - schedule write processing + * @port: port to be processed + * + * This routine is used by the interrupt handler to schedule processing in the + * software interrupt portion of the driver. A driver is expected to call this + * function when the number of characters in the transmit buffer have dropped + * below a threshold. + * + * Locking: @port->lock should be held */ void uart_write_wakeup(struct uart_port *port) { @@ -327,14 +334,16 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) } /** - * uart_update_timeout - update per-port frame timing information. - * @port: uart_port structure describing the port - * @cflag: termios cflag value - * @baud: speed of the port + * uart_update_timeout - update per-port frame timing information + * @port: uart_port structure describing the port + * @cflag: termios cflag value + * @baud: speed of the port * - * Set the port frame timing information from which the FIFO timeout - * value is derived. The @cflag value should reflect the actual hardware - * settings. + * Set the @port frame timing information from which the FIFO timeout value is + * derived. The @cflag value should reflect the actual hardware settings as + * number of bits, parity, stop bits and baud rate is taken into account here. + * + * Locking: caller is expected to take @port->lock */ void uart_update_timeout(struct uart_port *port, unsigned int cflag, @@ -349,23 +358,25 @@ uart_update_timeout(struct uart_port *port, unsigned int cflag, EXPORT_SYMBOL(uart_update_timeout); /** - * uart_get_baud_rate - return baud rate for a particular port - * @port: uart_port structure describing the port in question. - * @termios: desired termios settings. - * @old: old termios (or NULL) - * @min: minimum acceptable baud rate - * @max: maximum acceptable baud rate + * uart_get_baud_rate - return baud rate for a particular port + * @port: uart_port structure describing the port in question. + * @termios: desired termios settings + * @old: old termios (or %NULL) + * @min: minimum acceptable baud rate + * @max: maximum acceptable baud rate + * + * Decode the termios structure into a numeric baud rate, taking account of the + * magic 38400 baud rate (with spd_* flags), and mapping the %B0 rate to 9600 + * baud. * - * Decode the termios structure into a numeric baud rate, - * taking account of the magic 38400 baud rate (with spd_* - * flags), and mapping the %B0 rate to 9600 baud. + * If the new baud rate is invalid, try the @old termios setting. If it's still + * invalid, we try 9600 baud. * - * If the new baud rate is invalid, try the old termios setting. - * If it's still invalid, we try 9600 baud. + * The @termios structure is updated to reflect the baud rate we're actually + * going to be using. Don't do this for the case where B0 is requested ("hang + * up"). * - * Update the @termios structure to reflect the baud rate - * we're actually going to be using. Don't do this for the case - * where B0 is requested ("hang up"). + * Locking: caller dependent */ unsigned int uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, @@ -450,11 +461,17 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, EXPORT_SYMBOL(uart_get_baud_rate); /** - * uart_get_divisor - return uart clock divisor - * @port: uart_port structure describing the port. - * @baud: desired baud rate + * uart_get_divisor - return uart clock divisor + * @port: uart_port structure describing the port + * @baud: desired baud rate + * + * Calculate the divisor (baud_base / baud) for the specified @baud, + * appropriately rounded. * - * Calculate the uart clock divisor for the port. + * If 38400 baud and custom divisor is selected, return the custom divisor + * instead. + * + * Locking: caller dependent */ unsigned int uart_get_divisor(struct uart_port *port, unsigned int baud) @@ -2683,17 +2700,19 @@ static const struct tty_port_operations uart_port_ops = { }; /** - * uart_register_driver - register a driver with the uart core layer - * @drv: low level driver structure + * uart_register_driver - register a driver with the uart core layer + * @drv: low level driver structure + * + * Register a uart driver with the core driver. We in turn register with the + * tty layer, and initialise the core driver per-port state. * - * Register a uart driver with the core driver. We in turn register - * with the tty layer, and initialise the core driver per-port state. + * We have a proc file in /proc/tty/driver which is named after the normal + * driver. * - * We have a proc file in /proc/tty/driver which is named after the - * normal driver. + * @drv->port should be %NULL, and the per-port structures should be registered + * using uart_add_one_port() after this call has succeeded. * - * drv->port should be NULL, and the per-port structures should be - * registered using uart_add_one_port after this call has succeeded. + * Locking: none, Interrupts: enabled */ int uart_register_driver(struct uart_driver *drv) { @@ -2757,13 +2776,14 @@ out: EXPORT_SYMBOL(uart_register_driver); /** - * uart_unregister_driver - remove a driver from the uart core layer - * @drv: low level driver structure + * uart_unregister_driver - remove a driver from the uart core layer + * @drv: low level driver structure + * + * Remove all references to a driver from the core driver. The low level + * driver must have removed all its ports via the uart_remove_one_port() if it + * registered them with uart_add_one_port(). (I.e. @drv->port is %NULL.) * - * Remove all references to a driver from the core driver. The low - * level driver must have removed all its ports via the - * uart_remove_one_port() if it registered them with uart_add_one_port(). - * (ie, drv->port == NULL) + * Locking: none, Interrupts: enabled */ void uart_unregister_driver(struct uart_driver *drv) { @@ -3012,16 +3032,15 @@ static const struct attribute_group tty_dev_attr_group = { }; /** - * uart_add_one_port - attach a driver-defined port structure - * @drv: pointer to the uart low level driver structure for this port - * @uport: uart port structure to use for this port. + * uart_add_one_port - attach a driver-defined port structure + * @drv: pointer to the uart low level driver structure for this port + * @uport: uart port structure to use for this port. * - * Context: task context, might sleep + * Context: task context, might sleep * - * This allows the driver to register its own uart_port structure - * with the core driver. The main purpose is to allow the low - * level uart drivers to expand uart_port, rather than having yet - * more levels of structures. + * This allows the driver @drv to register its own uart_port structure with the + * core driver. The main purpose is to allow the low level uart drivers to + * expand uart_port, rather than having yet more levels of structures. */ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) { @@ -3116,15 +3135,14 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) EXPORT_SYMBOL(uart_add_one_port); /** - * uart_remove_one_port - detach a driver defined port structure - * @drv: pointer to the uart low level driver structure for this port - * @uport: uart port structure for this port + * uart_remove_one_port - detach a driver defined port structure + * @drv: pointer to the uart low level driver structure for this port + * @uport: uart port structure for this port * - * Context: task context, might sleep + * Context: task context, might sleep * - * This unhooks (and hangs up) the specified port structure from the - * core driver. No further calls will be made to the low-level code - * for this port. + * This unhooks (and hangs up) the specified port structure from the core + * driver. No further calls will be made to the low-level code for this port. */ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport) { @@ -3196,8 +3214,13 @@ out: } EXPORT_SYMBOL(uart_remove_one_port); -/* - * Are the two ports equivalent? +/** + * uart_match_port - are the two ports equivalent? + * @port1: first port + * @port2: second port + * + * This utility function can be used to determine whether two uart_port + * structures describe the same port. */ bool uart_match_port(const struct uart_port *port1, const struct uart_port *port2) -- cgit v1.2.3 From 27940abd555228fdda39a40081ae02450c500f35 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 28 Jul 2022 08:10:53 +0200 Subject: Documentation: serial: move GPIO kernel-doc to the functions The GPIO uart functions are documented in Documentation. Move and transform this documentation into kernel-doc directly in the code and reference it in Documentation using kernel-doc:. This makes it easier to update, maintain and check by the build. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220728061056.20799-3-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/serial/driver.rst | 32 +++----------------- drivers/tty/serial/serial_mctrl_gpio.c | 48 ++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 28 deletions(-) (limited to 'drivers/tty') diff --git a/Documentation/driver-api/serial/driver.rst b/Documentation/driver-api/serial/driver.rst index ac9620e97f4b..cae280f39189 100644 --- a/Documentation/driver-api/serial/driver.rst +++ b/Documentation/driver-api/serial/driver.rst @@ -94,31 +94,7 @@ Modem control lines via GPIO Some helpers are provided in order to set/get modem control lines via GPIO. -mctrl_gpio_init(port, idx): - This will get the {cts,rts,...}-gpios from device tree if they are - present and request them, set direction etc, and return an - allocated structure. `devm_*` functions are used, so there's no need - to call mctrl_gpio_free(). - As this sets up the irq handling make sure to not handle changes to the - gpio input lines in your driver, too. - -mctrl_gpio_free(dev, gpios): - This will free the requested gpios in mctrl_gpio_init(). - As `devm_*` functions are used, there's generally no need to call - this function. - -mctrl_gpio_to_gpiod(gpios, gidx) - This returns the gpio_desc structure associated to the modem line - index. - -mctrl_gpio_set(gpios, mctrl): - This will sets the gpios according to the mctrl state. - -mctrl_gpio_get(gpios, mctrl): - This will update mctrl with the gpios values. - -mctrl_gpio_enable_ms(gpios): - Enables irqs and handling of changes to the ms lines. - -mctrl_gpio_disable_ms(gpios): - Disables irqs and handling of changes to the ms lines. +.. kernel-doc:: drivers/tty/serial/serial_mctrl_gpio.c + :identifiers: mctrl_gpio_init mctrl_gpio_free mctrl_gpio_to_gpiod + mctrl_gpio_set mctrl_gpio_get mctrl_gpio_enable_ms + mctrl_gpio_disable_ms diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c index 1663b3afc3a0..7d5aaa8d422b 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.c +++ b/drivers/tty/serial/serial_mctrl_gpio.c @@ -42,6 +42,13 @@ static bool mctrl_gpio_flags_is_dir_out(unsigned int idx) return mctrl_gpios_desc[idx].flags & GPIOD_FLAGS_BIT_DIR_OUT; } +/** + * mctrl_gpio_set - set gpios according to mctrl state + * @gpios: gpios to set + * @mctrl: state to set + * + * Set the gpios according to the mctrl state. + */ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl) { enum mctrl_gpio_idx i; @@ -63,6 +70,12 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl) } EXPORT_SYMBOL_GPL(mctrl_gpio_set); +/** + * mctrl_gpio_to_gpiod - obtain gpio_desc of modem line index + * @gpios: gpios to look into + * @gidx: index of the modem line + * Returns: the gpio_desc structure associated to the modem line index + */ struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios, enum mctrl_gpio_idx gidx) { @@ -73,6 +86,14 @@ struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios, } EXPORT_SYMBOL_GPL(mctrl_gpio_to_gpiod); +/** + * mctrl_gpio_get - update mctrl with the gpios values. + * @gpios: gpios to get the info from + * @mctrl: mctrl to set + * Returns: modified mctrl (the same value as in @mctrl) + * + * Update mctrl with the gpios values. + */ unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl) { enum mctrl_gpio_idx i; @@ -189,6 +210,17 @@ static irqreturn_t mctrl_gpio_irq_handle(int irq, void *context) return IRQ_HANDLED; } +/** + * mctrl_gpio_init - initialize uart gpios + * @port: port to initialize gpios for + * @idx: index of the gpio in the @port's device + * + * This will get the {cts,rts,...}-gpios from device tree if they are present + * and request them, set direction etc, and return an allocated structure. + * `devm_*` functions are used, so there's no need to call mctrl_gpio_free(). + * As this sets up the irq handling, make sure to not handle changes to the + * gpio input lines in your driver, too. + */ struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx) { struct mctrl_gpios *gpios; @@ -235,6 +267,14 @@ struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx) } EXPORT_SYMBOL_GPL(mctrl_gpio_init); +/** + * mctrl_gpio_free - explicitly free uart gpios + * @dev: uart port's device + * @gpios: gpios structure to be freed + * + * This will free the requested gpios in mctrl_gpio_init(). As `devm_*` + * functions are used, there's generally no need to call this function. + */ void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios) { enum mctrl_gpio_idx i; @@ -253,6 +293,10 @@ void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios) } EXPORT_SYMBOL_GPL(mctrl_gpio_free); +/** + * mctrl_gpio_enable_ms - enable irqs and handling of changes to the ms lines + * @gpios: gpios to enable + */ void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios) { enum mctrl_gpio_idx i; @@ -278,6 +322,10 @@ void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios) } EXPORT_SYMBOL_GPL(mctrl_gpio_enable_ms); +/** + * mctrl_gpio_disable_ms - disable irqs and handling of changes to the ms lines + * @gpios: gpios to disable + */ void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios) { enum mctrl_gpio_idx i; -- cgit v1.2.3 From 987233b342b950653d21c5e3e5b78689c995c869 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 28 Jul 2022 08:10:55 +0200 Subject: tty: serial: serial_core, reformat kernel-doc for functions There are many annotated functions in serial_core.c, but they do not completely conform to the kernel-doc style. So reformat them and link them from the Documentation. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220728061056.20799-5-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/serial/driver.rst | 11 +-- drivers/tty/serial/serial_core.c | 107 ++++++++++++++--------------- 2 files changed, 60 insertions(+), 58 deletions(-) (limited to 'drivers/tty') diff --git a/Documentation/driver-api/serial/driver.rst b/Documentation/driver-api/serial/driver.rst index 13b580e887b4..e1b440f2c02b 100644 --- a/Documentation/driver-api/serial/driver.rst +++ b/Documentation/driver-api/serial/driver.rst @@ -25,10 +25,10 @@ Console Support --------------- The serial core provides a few helper functions. This includes identifing -the correct port structure (via uart_get_console) and decoding command line -arguments (uart_parse_options). +the correct port structure (via uart_get_console()) and decoding command line +arguments (uart_parse_options()). -There is also a helper function (uart_console_write) which performs a +There is also a helper function (uart_console_write()) which performs a character by character write, translating newlines to CRLF sequences. Driver writers are recommended to use this function rather than implementing their own version. @@ -73,7 +73,10 @@ Other functions :identifiers: uart_update_timeout uart_get_baud_rate uart_get_divisor uart_match_port uart_write_wakeup uart_register_driver uart_unregister_driver uart_suspend_port uart_resume_port - uart_add_one_port uart_remove_one_port + uart_add_one_port uart_remove_one_port uart_console_write + uart_parse_earlycon uart_parse_options uart_set_options + uart_get_lsr_info uart_handle_dcd_change uart_handle_cts_change + uart_try_toggle_sysrq Other notes ----------- diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index c302aa34668d..b2943da2d32c 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1034,10 +1034,10 @@ static int uart_set_info_user(struct tty_struct *tty, struct serial_struct *ss) } /** - * uart_get_lsr_info - get line status register info - * @tty: tty associated with the UART - * @state: UART being queried - * @value: returned modem value + * uart_get_lsr_info - get line status register info + * @tty: tty associated with the UART + * @state: UART being queried + * @value: returned modem value */ static int uart_get_lsr_info(struct tty_struct *tty, struct uart_state *state, unsigned int __user *value) @@ -2072,11 +2072,11 @@ static void uart_port_spin_lock_init(struct uart_port *port) #if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL) /** - * uart_console_write - write a console message to a serial port - * @port: the port to write the message - * @s: array of characters - * @count: number of characters in string to write - * @putchar: function to write character to port + * uart_console_write - write a console message to a serial port + * @port: the port to write the message + * @s: array of characters + * @count: number of characters in string to write + * @putchar: function to write character to port */ void uart_console_write(struct uart_port *port, const char *s, unsigned int count, @@ -2115,24 +2115,23 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co) } /** - * uart_parse_earlycon - Parse earlycon options - * @p: ptr to 2nd field (ie., just beyond ',') - * @iotype: ptr for decoded iotype (out) - * @addr: ptr for decoded mapbase/iobase (out) - * @options: ptr for field; NULL if not present (out) + * uart_parse_earlycon - Parse earlycon options + * @p: ptr to 2nd field (ie., just beyond ',') + * @iotype: ptr for decoded iotype (out) + * @addr: ptr for decoded mapbase/iobase (out) + * @options: ptr for field; %NULL if not present (out) * - * Decodes earlycon kernel command line parameters of the form - * earlycon=,io|mmio|mmio16|mmio32|mmio32be|mmio32native,, - * console=,io|mmio|mmio16|mmio32|mmio32be|mmio32native,, + * Decodes earlycon kernel command line parameters of the form: + * * earlycon=,io|mmio|mmio16|mmio32|mmio32be|mmio32native,, + * * console=,io|mmio|mmio16|mmio32|mmio32be|mmio32native,, * - * The optional form + * The optional form: + * * earlycon=,0x, + * * console=,0x, * - * earlycon=,0x, - * console=,0x, + * is also accepted; the returned @iotype will be %UPIO_MEM. * - * is also accepted; the returned @iotype will be UPIO_MEM. - * - * Returns 0 on success or -EINVAL on failure + * Returns: 0 on success or -%EINVAL on failure */ int uart_parse_earlycon(char *p, unsigned char *iotype, resource_size_t *addr, char **options) @@ -2177,16 +2176,16 @@ int uart_parse_earlycon(char *p, unsigned char *iotype, resource_size_t *addr, EXPORT_SYMBOL_GPL(uart_parse_earlycon); /** - * uart_parse_options - Parse serial port baud/parity/bits/flow control. - * @options: pointer to option string - * @baud: pointer to an 'int' variable for the baud rate. - * @parity: pointer to an 'int' variable for the parity. - * @bits: pointer to an 'int' variable for the number of data bits. - * @flow: pointer to an 'int' variable for the flow control character. + * uart_parse_options - Parse serial port baud/parity/bits/flow control. + * @options: pointer to option string + * @baud: pointer to an 'int' variable for the baud rate. + * @parity: pointer to an 'int' variable for the parity. + * @bits: pointer to an 'int' variable for the number of data bits. + * @flow: pointer to an 'int' variable for the flow control character. * - * uart_parse_options decodes a string containing the serial console - * options. The format of the string is , - * eg: 115200n8r + * uart_parse_options() decodes a string containing the serial console + * options. The format of the string is , + * eg: 115200n8r */ void uart_parse_options(const char *options, int *baud, int *parity, @@ -2207,13 +2206,13 @@ uart_parse_options(const char *options, int *baud, int *parity, EXPORT_SYMBOL_GPL(uart_parse_options); /** - * uart_set_options - setup the serial console parameters - * @port: pointer to the serial ports uart_port structure - * @co: console pointer - * @baud: baud rate - * @parity: parity character - 'n' (none), 'o' (odd), 'e' (even) - * @bits: number of data bits - * @flow: flow control character - 'r' (rts) + * uart_set_options - setup the serial console parameters + * @port: pointer to the serial ports uart_port structure + * @co: console pointer + * @baud: baud rate + * @parity: parity character - 'n' (none), 'o' (odd), 'e' (even) + * @bits: number of data bits + * @flow: flow control character - 'r' (rts) */ int uart_set_options(struct uart_port *port, struct console *co, @@ -3248,11 +3247,11 @@ bool uart_match_port(const struct uart_port *port1, EXPORT_SYMBOL(uart_match_port); /** - * uart_handle_dcd_change - handle a change of carrier detect state - * @uport: uart_port structure for the open port - * @status: new carrier detect status, nonzero if active + * uart_handle_dcd_change - handle a change of carrier detect state + * @uport: uart_port structure for the open port + * @status: new carrier detect status, nonzero if active * - * Caller must hold uport->lock + * Caller must hold uport->lock. */ void uart_handle_dcd_change(struct uart_port *uport, unsigned int status) { @@ -3283,11 +3282,11 @@ void uart_handle_dcd_change(struct uart_port *uport, unsigned int status) EXPORT_SYMBOL_GPL(uart_handle_dcd_change); /** - * uart_handle_cts_change - handle a change of clear-to-send state - * @uport: uart_port structure for the open port - * @status: new clear to send status, nonzero if active + * uart_handle_cts_change - handle a change of clear-to-send state + * @uport: uart_port structure for the open port + * @status: new clear to send status, nonzero if active * - * Caller must hold uport->lock + * Caller must hold uport->lock. */ void uart_handle_cts_change(struct uart_port *uport, unsigned int status) { @@ -3358,15 +3357,15 @@ static void uart_sysrq_on(struct work_struct *w) static DECLARE_WORK(sysrq_enable_work, uart_sysrq_on); /** - * uart_try_toggle_sysrq - Enables SysRq from serial line - * @port: uart_port structure where char(s) after BREAK met - * @ch: new character in the sequence after received BREAK + * uart_try_toggle_sysrq - Enables SysRq from serial line + * @port: uart_port structure where char(s) after BREAK met + * @ch: new character in the sequence after received BREAK * - * Enables magic SysRq when the required sequence is met on port - * (see CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE). + * Enables magic SysRq when the required sequence is met on port + * (see CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE). * - * Returns false if @ch is out of enabling sequence and should be - * handled some other way, true if @ch was consumed. + * Returns: %false if @ch is out of enabling sequence and should be + * handled some other way, %true if @ch was consumed. */ bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch) { -- cgit v1.2.3 From 9e5f399f5c9f62e537735f2f8e42bd2f7c255c1f Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 28 Jul 2022 08:10:56 +0200 Subject: tty: serial: document uart_get_console() This was the only function mentioned in the text, but was neither linked nor documented. So document and link it, so that hyperlinking works in the text. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220728061056.20799-6-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/serial/driver.rst | 2 +- drivers/tty/serial/serial_core.c | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers/tty') diff --git a/Documentation/driver-api/serial/driver.rst b/Documentation/driver-api/serial/driver.rst index e1b440f2c02b..23c6b956cd90 100644 --- a/Documentation/driver-api/serial/driver.rst +++ b/Documentation/driver-api/serial/driver.rst @@ -76,7 +76,7 @@ Other functions uart_add_one_port uart_remove_one_port uart_console_write uart_parse_earlycon uart_parse_options uart_set_options uart_get_lsr_info uart_handle_dcd_change uart_handle_cts_change - uart_try_toggle_sysrq + uart_try_toggle_sysrq uart_get_console Other notes ----------- diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index b2943da2d32c..339f4c421503 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2092,10 +2092,15 @@ void uart_console_write(struct uart_port *port, const char *s, } EXPORT_SYMBOL_GPL(uart_console_write); -/* - * Check whether an invalid uart number has been specified, and - * if so, search for the first available port that does have - * console support. +/** + * uart_get_console - get uart port for console + * @ports: ports to search in + * @nr: number of @ports + * @co: console to search for + * Returns: uart_port for the console @co + * + * Check whether an invalid uart number has been specified (as @co->index), and + * if so, search for the first available port that does have console support. */ struct uart_port * __init uart_get_console(struct uart_port *ports, int nr, struct console *co) -- cgit v1.2.3 From 014482b667d3550d7a610c5f11b6351fe47eb39a Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Fri, 15 Jul 2022 13:44:01 +0800 Subject: tty: amiserial: Fix comment typo The double `should' is duplicated in line 15, remove one. Signed-off-by: Jason Wang Link: https://lore.kernel.org/r/20220715054401.9870-1-wangborong@cdjrlc.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/amiserial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 5458e2b1c125..81e7f64c1739 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -12,7 +12,7 @@ * (non hardware specific) changes to serial.c. * * The port is registered with the tty driver as minor device 64, and - * therefore other ports should should only use 65 upwards. + * therefore other ports should only use 65 upwards. * * Richard Lucock 28/12/99 * -- cgit v1.2.3 From 0fec518018cc5ceffa706370b6e3acbbb1e3c798 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Tue, 2 Aug 2022 13:23:09 -0700 Subject: tty: serial: qcom-geni-serial: Fix %lu -> %u in print statements When we multiply an unsigned int by a u32 we still end up with an unsigned int. That means we should specify "%u" not "%lu" in the format code. NOTE: this fix was chosen instead of somehow promoting the value to "unsigned long" since the max baud rate from the earlier call to uart_get_baud_rate() is 4000000 and the max sampling rate is 32. 4000000 * 32 = 0x07a12000, not even close to overflowing 32-bits. Fixes: c474c775716e ("tty: serial: qcom-geni-serial: Fix get_clk_div_rate() which otherwise could return a sub-optimal clock rate.") Reported-by: Mark Brown Signed-off-by: Douglas Anderson Link: https://lore.kernel.org/r/20220802132250.1.Iea061e14157a17e114dbe2eca764568a02d6b889@changeid Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/qcom_geni_serial.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index f754619451dc..f7c1f1807040 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -1033,12 +1033,12 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport, sampling_rate, &clk_div); if (!clk_rate) { dev_err(port->se.dev, - "Couldn't find suitable clock rate for %lu\n", + "Couldn't find suitable clock rate for %u\n", baud * sampling_rate); goto out_restart_rx; } - dev_dbg(port->se.dev, "desired_rate-%lu, clk_rate-%lu, clk_div-%u\n", + dev_dbg(port->se.dev, "desired_rate-%u, clk_rate-%lu, clk_div-%u\n", baud * sampling_rate, clk_rate, clk_div); uport->uartclk = clk_rate; -- cgit v1.2.3