diff options
63 files changed, 1799 insertions, 1565 deletions
diff --git a/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml b/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml index 75b8521eb7cb..06d5f251ec88 100644 --- a/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml +++ b/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml @@ -35,9 +35,11 @@ properties: description: label associated with this uart st,hw-flow-ctrl: - description: enable hardware flow control + description: enable hardware flow control (deprecated) $ref: /schemas/types.yaml#/definitions/flag + uart-has-rtscts: true + dmas: minItems: 1 maxItems: 2 diff --git a/Documentation/driver-api/serial/n_gsm.rst b/Documentation/driver-api/serial/n_gsm.rst index 286e7ff4d2d9..87dfcd54a96b 100644 --- a/Documentation/driver-api/serial/n_gsm.rst +++ b/Documentation/driver-api/serial/n_gsm.rst @@ -5,7 +5,7 @@ GSM 0710 tty multiplexor HOWTO This line discipline implements the GSM 07.10 multiplexing protocol detailed in the following 3GPP document: - http://www.3gpp.org/ftp/Specs/archive/07_series/07.10/0710-720.zip + https://www.3gpp.org/ftp/Specs/archive/07_series/07.10/0710-720.zip This document give some hints on how to use this driver with GPRS and 3G modems connected to a physical serial port. diff --git a/MAINTAINERS b/MAINTAINERS index 8b87d8a7c6d7..4e497d1e2ab5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4386,6 +4386,12 @@ L: netdev@vger.kernel.org S: Maintained F: drivers/connector/ +CONSOLE SUBSYSTEM +M: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +S: Supported +F: drivers/video/console/ +F: include/linux/console* + CONTROL GROUP (CGROUP) M: Tejun Heo <tj@kernel.org> M: Li Zefan <lizefan@huawei.com> diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 4f2a4ac8a82b..14ad9f495fe6 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -184,11 +184,6 @@ void line_flush_chars(struct tty_struct *tty) line_flush_buffer(tty); } -int line_put_char(struct tty_struct *tty, unsigned char ch) -{ - return line_write(tty, &ch, sizeof(ch)); -} - int line_write(struct tty_struct *tty, const unsigned char *buf, int len) { struct line *line = tty->driver_data; diff --git a/arch/um/drivers/line.h b/arch/um/drivers/line.h index a151ff5155ef..01d21e76144f 100644 --- a/arch/um/drivers/line.h +++ b/arch/um/drivers/line.h @@ -66,7 +66,6 @@ extern int line_setup(char **conf, unsigned nlines, char **def, char *init, char *name); extern int line_write(struct tty_struct *tty, const unsigned char *buf, int len); -extern int line_put_char(struct tty_struct *tty, unsigned char ch); extern void line_set_termios(struct tty_struct *tty, struct ktermios * old); extern int line_chars_in_buffer(struct tty_struct *tty); extern void line_flush_buffer(struct tty_struct *tty); diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c index 26c5716fac0f..6476b28d7c5e 100644 --- a/arch/um/drivers/ssl.c +++ b/arch/um/drivers/ssl.c @@ -95,7 +95,6 @@ static const struct tty_operations ssl_ops = { .open = line_open, .close = line_close, .write = line_write, - .put_char = line_put_char, .write_room = line_write_room, .chars_in_buffer = line_chars_in_buffer, .flush_buffer = line_flush_buffer, diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c index 0021d7ffb528..37b127941e6f 100644 --- a/arch/um/drivers/stdio_console.c +++ b/arch/um/drivers/stdio_console.c @@ -102,7 +102,6 @@ static const struct tty_operations console_ops = { .install = con_install, .close = line_close, .write = line_write, - .put_char = line_put_char, .write_room = line_write_room, .chars_in_buffer = line_chars_in_buffer, .flush_buffer = line_flush_buffer, diff --git a/drivers/accessibility/braille/braille_console.c b/drivers/accessibility/braille/braille_console.c index a8f7c278b691..c2b452af6806 100644 --- a/drivers/accessibility/braille/braille_console.c +++ b/drivers/accessibility/braille/braille_console.c @@ -109,16 +109,16 @@ static void braille_write(u16 *buf) /* Follow the VC cursor*/ static void vc_follow_cursor(struct vc_data *vc) { - vc_x = vc->vc_x - (vc->vc_x % WIDTH); - vc_y = vc->vc_y; - lastvc_x = vc->vc_x; - lastvc_y = vc->vc_y; + vc_x = vc->state.x - (vc->state.x % WIDTH); + vc_y = vc->state.y; + lastvc_x = vc->state.x; + lastvc_y = vc->state.y; } /* Maybe the VC cursor moved, if so follow it */ static void vc_maybe_cursor_moved(struct vc_data *vc) { - if (vc->vc_x != lastvc_x || vc->vc_y != lastvc_y) + if (vc->state.x != lastvc_x || vc->state.y != lastvc_y) vc_follow_cursor(vc); } diff --git a/drivers/accessibility/speakup/main.c b/drivers/accessibility/speakup/main.c index 02471d932d71..ddfd12afe3b9 100644 --- a/drivers/accessibility/speakup/main.c +++ b/drivers/accessibility/speakup/main.c @@ -263,8 +263,8 @@ static unsigned char get_attributes(struct vc_data *vc, u16 *pos) static void speakup_date(struct vc_data *vc) { - spk_x = spk_cx = vc->vc_x; - spk_y = spk_cy = vc->vc_y; + spk_x = spk_cx = vc->state.x; + spk_y = spk_cy = vc->state.y; spk_pos = spk_cp = vc->vc_pos; spk_old_attr = spk_attr; spk_attr = get_attributes(vc, (u_short *)spk_pos); @@ -1551,9 +1551,9 @@ static void do_handle_cursor(struct vc_data *vc, u_char value, char up_flag) */ is_cursor = value + 1; old_cursor_pos = vc->vc_pos; - old_cursor_x = vc->vc_x; - old_cursor_y = vc->vc_y; - speakup_console[vc->vc_num]->ht.cy = vc->vc_y; + old_cursor_x = vc->state.x; + old_cursor_y = vc->state.y; + speakup_console[vc->vc_num]->ht.cy = vc->state.y; cursor_con = vc->vc_num; if (cursor_track == CT_Highlight) reset_highlight_buffers(vc); @@ -1574,8 +1574,8 @@ static void update_color_buffer(struct vc_data *vc, const u16 *ic, int len) i = 0; if (speakup_console[vc_num]->ht.highsize[bi] == 0) { speakup_console[vc_num]->ht.rpos[bi] = vc->vc_pos; - speakup_console[vc_num]->ht.rx[bi] = vc->vc_x; - speakup_console[vc_num]->ht.ry[bi] = vc->vc_y; + speakup_console[vc_num]->ht.rx[bi] = vc->state.x; + speakup_console[vc_num]->ht.ry[bi] = vc->state.y; } while ((hi < COLOR_BUFFER_SIZE) && (i < len)) { if (ic[i] > 32) { @@ -1664,9 +1664,9 @@ static int speak_highlight(struct vc_data *vc) return 0; hc = get_highlight_color(vc); if (hc != -1) { - d = vc->vc_y - speakup_console[vc_num]->ht.cy; + d = vc->state.y - speakup_console[vc_num]->ht.cy; if ((d == 1) || (d == -1)) - if (speakup_console[vc_num]->ht.ry[hc] != vc->vc_y) + if (speakup_console[vc_num]->ht.ry[hc] != vc->state.y) return 0; spk_parked |= 0x01; spk_do_flush(); @@ -1693,8 +1693,8 @@ static void cursor_done(struct timer_list *unused) } speakup_date(vc); if (win_enabled) { - if (vc->vc_x >= win_left && vc->vc_x <= win_right && - vc->vc_y >= win_top && vc->vc_y <= win_bottom) { + if (vc->state.x >= win_left && vc->state.x <= win_right && + vc->state.y >= win_top && vc->state.y <= win_bottom) { spk_keydown = 0; is_cursor = 0; goto out; @@ -1757,7 +1757,7 @@ static void speakup_con_write(struct vc_data *vc, u16 *str, int len) if (!spin_trylock_irqsave(&speakup_info.spinlock, flags)) /* Speakup output, discard */ return; - if (spk_bell_pos && spk_keydown && (vc->vc_x == spk_bell_pos - 1)) + if (spk_bell_pos && spk_keydown && (vc->state.x == spk_bell_pos - 1)) bleep(3); if ((is_cursor) || (cursor_track == read_all_mode)) { if (cursor_track == CT_Highlight) @@ -1766,8 +1766,8 @@ static void speakup_con_write(struct vc_data *vc, u16 *str, int len) return; } if (win_enabled) { - if (vc->vc_x >= win_left && vc->vc_x <= win_right && - vc->vc_y >= win_top && vc->vc_y <= win_bottom) { + if (vc->state.x >= win_left && vc->state.x <= win_right && + vc->state.y >= win_top && vc->state.y <= win_bottom) { spin_unlock_irqrestore(&speakup_info.spinlock, flags); return; } diff --git a/drivers/tty/moxa.h b/drivers/tty/moxa.h index 563d2dce80b3..f0a4381b6861 100644 --- a/drivers/tty/moxa.h +++ b/drivers/tty/moxa.h @@ -138,7 +138,7 @@ #define IntrQuit 0x40 /* received QUIT code */ #define IntrEOF 0x80 /* received EOF code */ -#define IntrRxTrigger 0x100 /* rx data count reach tigger value */ +#define IntrRxTrigger 0x100 /* rx data count reach trigger value */ #define IntrTxTrigger 0x200 /* tx data count below trigger value */ #define Magic_no (Config_base + 0) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index aab3cccc6789..87f450b7c177 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -19,6 +19,8 @@ #include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/platform_device.h> +#include <linux/workqueue.h> +#include <linux/notifier.h> #include <linux/slab.h> #include <linux/acpi.h> #include <linux/clk.h> @@ -43,6 +45,8 @@ struct dw8250_data { int msr_mask_off; struct clk *clk; struct clk *pclk; + struct notifier_block clk_notifier; + struct work_struct clk_work; struct reset_control *rst; unsigned int skip_autocfg:1; @@ -54,6 +58,16 @@ static inline struct dw8250_data *to_dw8250_data(struct dw8250_port_data *data) return container_of(data, struct dw8250_data, data); } +static inline struct dw8250_data *clk_to_dw8250_data(struct notifier_block *nb) +{ + return container_of(nb, struct dw8250_data, clk_notifier); +} + +static inline struct dw8250_data *work_to_dw8250_data(struct work_struct *work) +{ + return container_of(work, struct dw8250_data, clk_work); +} + static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value) { struct dw8250_data *d = to_dw8250_data(p->private_data); @@ -260,6 +274,46 @@ static int dw8250_handle_irq(struct uart_port *p) return 0; } +static void dw8250_clk_work_cb(struct work_struct *work) +{ + struct dw8250_data *d = work_to_dw8250_data(work); + struct uart_8250_port *up; + unsigned long rate; + + rate = clk_get_rate(d->clk); + if (rate <= 0) + return; + + up = serial8250_get_port(d->data.line); + + serial8250_update_uartclk(&up->port, rate); +} + +static int dw8250_clk_notifier_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct dw8250_data *d = clk_to_dw8250_data(nb); + + /* + * We have no choice but to defer the uartclk update due to two + * deadlocks. First one is caused by a recursive mutex lock which + * happens when clk_set_rate() is called from dw8250_set_termios(). + * Second deadlock is more tricky and is caused by an inverted order of + * the clk and tty-port mutexes lock. It happens if clock rate change + * is requested asynchronously while set_termios() is executed between + * tty-port mutex lock and clk_set_rate() function invocation and + * vise-versa. Anyway if we didn't have the reference clock alteration + * in the dw8250_set_termios() method we wouldn't have needed this + * deferred event handling complication. + */ + if (event == POST_RATE_CHANGE) { + queue_work(system_unbound_wq, &d->clk_work); + return NOTIFY_OK; + } + + return NOTIFY_DONE; +} + static void dw8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old) { @@ -275,27 +329,27 @@ dw8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old) static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios, struct ktermios *old) { - unsigned int baud = tty_termios_baud_rate(termios); + unsigned long newrate = tty_termios_baud_rate(termios) * 16; struct dw8250_data *d = to_dw8250_data(p->private_data); long rate; int ret; clk_disable_unprepare(d->clk); - rate = clk_round_rate(d->clk, baud * 16); - if (rate < 0) - ret = rate; - else if (rate == 0) - ret = -ENOENT; - else - ret = clk_set_rate(d->clk, rate); + rate = clk_round_rate(d->clk, newrate); + if (rate > 0) { + /* + * Premilinary set the uartclk to the new clock rate so the + * clock update event handler caused by the clk_set_rate() + * calling wouldn't actually update the UART divisor since + * we about to do this anyway. + */ + swap(p->uartclk, rate); + ret = clk_set_rate(d->clk, newrate); + if (ret) + swap(p->uartclk, rate); + } clk_prepare_enable(d->clk); - if (ret) - goto out; - - p->uartclk = rate; - -out: p->status &= ~UPSTAT_AUTOCTS; if (termios->c_cflag & CRTSCTS) p->status |= UPSTAT_AUTOCTS; @@ -319,6 +373,39 @@ static void dw8250_set_ldisc(struct uart_port *p, struct ktermios *termios) serial8250_do_set_ldisc(p, termios); } +static int dw8250_startup(struct uart_port *p) +{ + struct dw8250_data *d = to_dw8250_data(p->private_data); + int ret; + + /* + * Some platforms may provide a reference clock shared between several + * devices. In this case before using the serial port first we have to + * make sure that any clock state change is known to the UART port at + * least post factum. + */ + if (d->clk) { + ret = clk_notifier_register(d->clk, &d->clk_notifier); + if (ret) + dev_warn(p->dev, "Failed to set the clock notifier\n"); + } + + return serial8250_do_startup(p); +} + +static void dw8250_shutdown(struct uart_port *p) +{ + struct dw8250_data *d = to_dw8250_data(p->private_data); + + serial8250_do_shutdown(p); + + if (d->clk) { + clk_notifier_unregister(d->clk, &d->clk_notifier); + + flush_work(&d->clk_work); + } +} + /* * dw8250_fallback_dma_filter will prevent the UART from getting just any free * channel on platforms that have DMA engines, but don't have any channels @@ -414,6 +501,8 @@ static int dw8250_probe(struct platform_device *pdev) p->serial_out = dw8250_serial_out; p->set_ldisc = dw8250_set_ldisc; p->set_termios = dw8250_set_termios; + p->startup = dw8250_startup; + p->shutdown = dw8250_shutdown; p->membase = devm_ioremap(dev, regs->start, resource_size(regs)); if (!p->membase) @@ -475,6 +564,9 @@ static int dw8250_probe(struct platform_device *pdev) if (IS_ERR(data->clk)) return PTR_ERR(data->clk); + INIT_WORK(&data->clk_work, dw8250_clk_work_cb); + data->clk_notifier.notifier_call = dw8250_clk_notifier_cb; + err = clk_prepare_enable(data->clk); if (err) dev_warn(dev, "could not enable optional baudclk: %d\n", err); diff --git a/drivers/tty/serial/8250/8250_em.c b/drivers/tty/serial/8250/8250_em.c index 2a76e22d2ec0..db88dee3a399 100644 --- a/drivers/tty/serial/8250/8250_em.c +++ b/drivers/tty/serial/8250/8250_em.c @@ -78,14 +78,18 @@ static void serial8250_em_serial_dl_write(struct uart_8250_port *up, int value) static int serial8250_em_probe(struct platform_device *pdev) { - struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); struct serial8250_em_priv *priv; struct uart_8250_port up; - int ret; + struct resource *regs; + int irq, ret; - if (!regs || !irq) { - dev_err(&pdev->dev, "missing registers or irq\n"); + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) { + dev_err(&pdev->dev, "missing registers\n"); return -EINVAL; } @@ -101,7 +105,7 @@ static int serial8250_em_probe(struct platform_device *pdev) memset(&up, 0, sizeof(up)); up.port.mapbase = regs->start; - up.port.irq = irq->start; + up.port.irq = irq; up.port.type = PORT_UNKNOWN; up.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_IOREMAP; up.port.dev = &pdev->dev; diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c index 424c07c5f629..dde766fa465f 100644 --- a/drivers/tty/serial/8250/8250_ingenic.c +++ b/drivers/tty/serial/8250/8250_ingenic.c @@ -207,12 +207,11 @@ static unsigned int ingenic_uart_serial_in(struct uart_port *p, int offset) static int ingenic_uart_probe(struct platform_device *pdev) { struct uart_8250_port uart = {}; - struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); struct ingenic_uart_data *data; const struct ingenic_uart_config *cdata; const struct of_device_id *match; - int err, line; + struct resource *regs; + int irq, err, line; match = of_match_device(of_match, &pdev->dev); if (!match) { @@ -221,8 +220,13 @@ static int ingenic_uart_probe(struct platform_device *pdev) } cdata = match->data; - if (!regs || !irq) { - dev_err(&pdev->dev, "no registers/irq defined\n"); + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) { + dev_err(&pdev->dev, "no registers defined\n"); return -EINVAL; } @@ -238,7 +242,7 @@ static int ingenic_uart_probe(struct platform_device *pdev) uart.port.regshift = 2; uart.port.serial_out = ingenic_uart_serial_out; uart.port.serial_in = ingenic_uart_serial_in; - uart.port.irq = irq->start; + uart.port.irq = irq; uart.port.dev = &pdev->dev; uart.port.fifosize = cdata->fifosize; uart.tx_loadsz = cdata->tx_loadsz; diff --git a/drivers/tty/serial/8250/8250_men_mcb.c b/drivers/tty/serial/8250/8250_men_mcb.c index e985f344b2dd..737c4c31e8a0 100644 --- a/drivers/tty/serial/8250/8250_men_mcb.c +++ b/drivers/tty/serial/8250/8250_men_mcb.c @@ -51,7 +51,7 @@ static u32 men_lookup_uartclk(struct mcb_device *mdev) return clkval; } -static unsigned int get_num_ports(struct mcb_device *mdev, +static int get_num_ports(struct mcb_device *mdev, void __iomem *membase) { switch (mdev->id) { @@ -140,7 +140,7 @@ static void serial_8250_men_mcb_remove(struct mcb_device *mdev) return; num_ports = get_num_ports(mdev, data[0].uart.port.membase); - if (num_ports < 0 || num_ports > 4) { + if (num_ports <= 0 || num_ports > 4) { dev_err(&mdev->dev, "error retrieving number of ports!\n"); return; } diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c index 98b8a3e30733..7b0dec14c8b8 100644 --- a/drivers/tty/serial/8250/8250_mtk.c +++ b/drivers/tty/serial/8250/8250_mtk.c @@ -512,13 +512,17 @@ static int mtk8250_probe_of(struct platform_device *pdev, struct uart_port *p, static int mtk8250_probe(struct platform_device *pdev) { struct uart_8250_port uart = {}; - struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); struct mtk8250_data *data; - int err; + struct resource *regs; + int irq, err; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; - if (!regs || !irq) { - dev_err(&pdev->dev, "no registers/irq defined\n"); + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) { + dev_err(&pdev->dev, "no registers defined\n"); return -EINVAL; } @@ -542,7 +546,7 @@ static int mtk8250_probe(struct platform_device *pdev) spin_lock_init(&uart.port.lock); uart.port.mapbase = regs->start; - uart.port.irq = irq->start; + uart.port.irq = irq; uart.port.pm = mtk8250_do_pm; uart.port.type = PORT_16550; uart.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT; diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 16cfb887c5a3..562087df7d33 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -1209,17 +1209,21 @@ MODULE_DEVICE_TABLE(of, omap8250_dt_ids); static int omap8250_probe(struct platform_device *pdev) |