diff options
23 files changed, 251 insertions, 181 deletions
diff --git a/Documentation/devicetree/bindings/serial/fsl-lpuart.yaml b/Documentation/devicetree/bindings/serial/fsl-lpuart.yaml index 6e04e3848261..ff364bd0fbac 100644 --- a/Documentation/devicetree/bindings/serial/fsl-lpuart.yaml +++ b/Documentation/devicetree/bindings/serial/fsl-lpuart.yaml @@ -20,15 +20,15 @@ properties: - fsl,ls1021a-lpuart - fsl,ls1028a-lpuart - fsl,imx7ulp-lpuart - - fsl,imx8qm-lpuart + - fsl,imx8qxp-lpuart - fsl,imxrt1050-lpuart - items: - - enum: - - fsl,imx8qxp-lpuart - - fsl,imx8ulp-lpuart + - const: fsl,imx8ulp-lpuart - const: fsl,imx7ulp-lpuart - items: - - const: fsl,imx8qm-lpuart + - enum: + - fsl,imx8qm-lpuart + - fsl,imx8dxl-lpuart - const: fsl,imx8qxp-lpuart reg: diff --git a/Documentation/devicetree/bindings/serial/mtk-uart.txt b/Documentation/devicetree/bindings/serial/mtk-uart.txt index b3a0bfef0d54..113b5d6a2245 100644 --- a/Documentation/devicetree/bindings/serial/mtk-uart.txt +++ b/Documentation/devicetree/bindings/serial/mtk-uart.txt @@ -20,6 +20,7 @@ Required properties: * "mediatek,mt8135-uart" for MT8135 compatible UARTS * "mediatek,mt8173-uart" for MT8173 compatible UARTS * "mediatek,mt8183-uart", "mediatek,mt6577-uart" for MT8183 compatible UARTS + * "mediatek,mt8186-uart", "mediatek,mt6577-uart" for MT8183 compatible UARTS * "mediatek,mt8192-uart", "mediatek,mt6577-uart" for MT8192 compatible UARTS * "mediatek,mt8195-uart", "mediatek,mt6577-uart" for MT8195 compatible UARTS * "mediatek,mt8516-uart" for MT8516 compatible UARTS diff --git a/Documentation/devicetree/bindings/serial/renesas,sci.yaml b/Documentation/devicetree/bindings/serial/renesas,sci.yaml index 8dda4e10e09d..bf7708a7a2c0 100644 --- a/Documentation/devicetree/bindings/serial/renesas,sci.yaml +++ b/Documentation/devicetree/bindings/serial/renesas,sci.yaml @@ -17,6 +17,7 @@ properties: oneOf: - items: - enum: + - renesas,r9a07g043-sci # RZ/G2UL - renesas,r9a07g044-sci # RZ/G2{L,LC} - renesas,r9a07g054-sci # RZ/V2L - const: renesas,sci # generic SCI compatible UART @@ -67,6 +68,7 @@ if: compatible: contains: enum: + - renesas,r9a07g043-sci - renesas,r9a07g044-sci - renesas,r9a07g054-sci then: diff --git a/Documentation/devicetree/bindings/serial/renesas,scif.yaml b/Documentation/devicetree/bindings/serial/renesas,scif.yaml index ba5d3e0acc63..5d37f8f189fb 100644 --- a/Documentation/devicetree/bindings/serial/renesas,scif.yaml +++ b/Documentation/devicetree/bindings/serial/renesas,scif.yaml @@ -73,12 +73,12 @@ properties: - items: - enum: - renesas,scif-r9a07g044 # RZ/G2{L,LC} - - renesas,scif-r9a07g054 # RZ/V2L - items: - enum: + - renesas,scif-r9a07g043 # RZ/G2UL - renesas,scif-r9a07g054 # RZ/V2L - - const: renesas,scif-r9a07g044 # RZ/G2{L,LC} fallback for RZ/V2L + - const: renesas,scif-r9a07g044 # RZ/G2{L,LC} fallback reg: maxItems: 1 @@ -167,7 +167,6 @@ if: - renesas,rcar-gen3-scif - renesas,rcar-gen4-scif - renesas,scif-r9a07g044 - - renesas,scif-r9a07g054 then: required: - resets diff --git a/Documentation/devicetree/bindings/serial/samsung_uart.yaml b/Documentation/devicetree/bindings/serial/samsung_uart.yaml index 2940afb874b3..6aceba4a5f79 100644 --- a/Documentation/devicetree/bindings/serial/samsung_uart.yaml +++ b/Documentation/devicetree/bindings/serial/samsung_uart.yaml @@ -26,6 +26,7 @@ properties: - samsung,s3c6400-uart - samsung,s5pv210-uart - samsung,exynos4210-uart + - samsung,exynos5433-uart - samsung,exynos850-uart reg: @@ -111,6 +112,7 @@ allOf: enum: - apple,s5l-uart - samsung,exynos4210-uart + - samsung,exynos5433-uart then: properties: clocks: diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 1e60dbef676c..533d02b38e02 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -538,10 +538,8 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info) */ free_irq(IRQ_AMIGA_VERTB, info); - if (info->xmit.buf) { - free_page((unsigned long) info->xmit.buf); - info->xmit.buf = NULL; - } + free_page((unsigned long)info->xmit.buf); + info->xmit.buf = NULL; info->IER = 0; amiga_custom.intena = IF_RBF | IF_TBE; diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index c858aff721c4..836c9eca2946 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -275,9 +275,6 @@ struct mxser_port { u8 read_status_mask; u8 ignore_status_mask; u8 xmit_fifo_size; - unsigned int xmit_head; - unsigned int xmit_tail; - unsigned int xmit_cnt; spinlock_t slock; }; @@ -742,22 +739,21 @@ static void mxser_disable_and_clear_FIFO(struct mxser_port *info) static int mxser_activate(struct tty_port *port, struct tty_struct *tty) { struct mxser_port *info = container_of(port, struct mxser_port, port); - unsigned long page; unsigned long flags; + int ret; - page = __get_free_page(GFP_KERNEL); - if (!page) - return -ENOMEM; + ret = tty_port_alloc_xmit_buf(port); + if (ret < 0) + return ret; spin_lock_irqsave(&info->slock, flags); if (!info->type) { set_bit(TTY_IO_ERROR, &tty->flags); - free_page(page); spin_unlock_irqrestore(&info->slock, flags); - return 0; + ret = 0; + goto err_free_xmit; } - info->port.xmit_buf = (unsigned char *) page; /* * Clear the FIFO buffers and disable them @@ -775,8 +771,10 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty) if (capable(CAP_SYS_ADMIN)) { set_bit(TTY_IO_ERROR, &tty->flags); return 0; - } else - return -ENODEV; + } + + ret = -ENODEV; + goto err_free_xmit; } /* @@ -812,7 +810,7 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty) (void) inb(info->ioaddr + UART_MSR); clear_bit(TTY_IO_ERROR, &tty->flags); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + kfifo_reset(&port->xmit_fifo); /* * and set the speed of the serial port @@ -821,6 +819,9 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty) spin_unlock_irqrestore(&info->slock, flags); return 0; +err_free_xmit: + tty_port_free_xmit_buf(port); + return ret; } /* @@ -855,14 +856,6 @@ static void mxser_shutdown_port(struct tty_port *port) */ wake_up_interruptible(&info->port.delta_msr_wait); - /* - * Free the xmit buffer, if necessary - */ - if (info->port.xmit_buf) { - free_page((unsigned long) info->port.xmit_buf); - info->port.xmit_buf = NULL; - } - info->IER = 0; outb(0x00, info->ioaddr + UART_IER); @@ -877,6 +870,11 @@ static void mxser_shutdown_port(struct tty_port *port) mxser_must_no_sw_flow_control(info->ioaddr); spin_unlock_irqrestore(&info->slock, flags); + + /* make sure ISR is not running while we free the buffer */ + synchronize_irq(info->board->irq); + + tty_port_free_xmit_buf(port); } /* @@ -900,9 +898,8 @@ static void mxser_flush_buffer(struct tty_struct *tty) struct mxser_port *info = tty->driver_data; unsigned long flags; - spin_lock_irqsave(&info->slock, flags); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + kfifo_reset(&info->port.xmit_fifo); outb(info->FCR | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, info->ioaddr + UART_FCR); @@ -919,50 +916,34 @@ static void mxser_close(struct tty_struct *tty, struct file *filp) static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int count) { - int c, total = 0; struct mxser_port *info = tty->driver_data; unsigned long flags; + int written; + bool is_empty; - while (1) { - c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); - if (c <= 0) - break; - - memcpy(info->port.xmit_buf + info->xmit_head, buf, c); - spin_lock_irqsave(&info->slock, flags); - info->xmit_head = (info->xmit_head + c) & - (SERIAL_XMIT_SIZE - 1); - info->xmit_cnt += c; - spin_unlock_irqrestore(&info->slock, flags); - - buf += c; - count -= c; - total += c; - } + spin_lock_irqsave(&info->slock, flags); + written = kfifo_in(&info->port.xmit_fifo, buf, count); + is_empty = kfifo_is_empty(&info->port.xmit_fifo); + spin_unlock_irqrestore(&info->slock, flags); - if (info->xmit_cnt && !tty->flow.stopped) + if (!is_empty && !tty->flow.stopped) if (!tty->hw_stopped || mxser_16550A_or_MUST(info)) mxser_start_tx(info); - return total; + return written; } static int mxser_put_char(struct tty_struct *tty, unsigned char ch) { struct mxser_port *info = tty->driver_data; unsigned long flags; - - if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) - return 0; + int ret; spin_lock_irqsave(&info->slock, flags); - info->port.xmit_buf[info->xmit_head++] = ch; - info->xmit_head &= SERIAL_XMIT_SIZE - 1; - info->xmit_cnt++; + ret = kfifo_put(&info->port.xmit_fifo, ch); spin_unlock_irqrestore(&info->slock, flags); - return 1; + return ret; } @@ -970,7 +951,7 @@ static void mxser_flush_chars(struct tty_struct *tty) { struct mxser_port *info = tty->driver_data; - if (!info->xmit_cnt || tty->flow.stopped || + if (kfifo_is_empty(&info->port.xmit_fifo) || tty->flow.stopped || (tty->hw_stopped && !mxser_16550A_or_MUST(info))) return; @@ -980,16 +961,15 @@ static void mxser_flush_chars(struct tty_struct *tty) static unsigned int mxser_write_room(struct tty_struct *tty) { struct mxser_port *info = tty->driver_data; - int ret; - ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; - return ret < 0 ? 0 : ret; + return kfifo_avail(&info->port.xmit_fifo); } static unsigned int mxser_chars_in_buffer(struct tty_struct *tty) { struct mxser_port *info = tty->driver_data; - return info->xmit_cnt; + + return kfifo_len(&info->port.xmit_fifo); } /* @@ -1378,7 +1358,7 @@ static void mxser_start(struct tty_struct *tty) unsigned long flags; spin_lock_irqsave(&info->slock, flags); - if (info->xmit_cnt) + if (!kfifo_is_empty(&info->port.xmit_fifo)) __mxser_start_tx(info); spin_unlock_irqrestore(&info->slock, flags); } @@ -1609,7 +1589,7 @@ static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port return; } - if (!port->xmit_cnt || tty->flow.stopped || + if (kfifo_is_empty(&port->port.xmit_fifo) || tty->flow.stopped || (tty->hw_stopped && !mxser_16550A_or_MUST(port))) { __mxser_stop_tx(port); return; @@ -1617,18 +1597,19 @@ static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port count = port->xmit_fifo_size; do { - outb(port->port.xmit_buf[port->xmit_tail++], - port->ioaddr + UART_TX); - port->xmit_tail &= SERIAL_XMIT_SIZE - 1; - port->icount.tx++; - if (!--port->xmit_cnt) + unsigned char c; + + if (!kfifo_get(&port->port.xmit_fifo, &c)) break; + + outb(c, port->ioaddr + UART_TX); + port->icount.tx++; } while (--count > 0); - if (port->xmit_cnt < WAKEUP_CHARS) + if (kfifo_len(&port->port.xmit_fifo) < WAKEUP_CHARS) tty_wakeup(tty); - if (!port->xmit_cnt) + if (kfifo_is_empty(&port->port.xmit_fifo)) __mxser_stop_tx(port); } diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index 92e3433276f8..0180e1e4e75d 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -704,13 +704,10 @@ static const struct acpi_device_id serdev_acpi_devices_blacklist[] = { static acpi_status acpi_serdev_add_device(acpi_handle handle, u32 level, void *data, void **return_value) { + struct acpi_device *adev = acpi_fetch_acpi_dev(handle); struct serdev_controller *ctrl = data; - struct acpi_device *adev; - if (acpi_bus_get_device(handle, &adev)) - return AE_OK; - - if (acpi_device_enumerated(adev)) + if (!adev || acpi_device_enumerated(adev)) return AE_OK; /* Skip if black listed */ diff --git a/drivers/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c index fd95860cd661..2a1226a78a0c 100644 --- a/drivers/tty/serial/8250/8250_bcm2835aux.c +++ b/drivers/tty/serial/8250/8250_bcm2835aux.c @@ -17,6 +17,7 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> +#include <linux/property.h> #include "8250.h" @@ -44,6 +45,10 @@ struct bcm2835aux_data { u32 cntl; }; +struct bcm2835_aux_serial_driver_data { + resource_size_t offset; +}; + static void bcm2835aux_rs485_start_tx(struct uart_8250_port *up) { if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) { @@ -80,9 +85,12 @@ static void bcm2835aux_rs485_stop_tx(struct uart_8250_port *up) static int bcm2835aux_serial_probe(struct platform_device *pdev) { + const struct bcm2835_aux_serial_driver_data *bcm_data; struct uart_8250_port up = { }; struct bcm2835aux_data *data; + resource_size_t offset = 0; struct resource *res; + unsigned int uartclk; int ret; /* allocate the custom structure */ @@ -109,9 +117,7 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev) platform_set_drvdata(pdev, data); /* get the clock - this also enables the HW */ - data->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(data->clk)) - return dev_err_probe(&pdev->dev, PTR_ERR(data->clk), "could not get clk\n"); + data->clk = devm_clk_get_optional(&pdev->dev, NULL); /* get the interrupt */ ret = platform_get_irq(pdev, 0); @@ -125,8 +131,24 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev) dev_err(&pdev->dev, "memory resource not found"); return -EINVAL; } - up.port.mapbase = res->start; - up.port.mapsize = resource_size(res); + + bcm_data = device_get_match_data(&pdev->dev); + + /* Some UEFI implementations (e.g. tianocore/edk2 for the Raspberry Pi) + * describe the miniuart with a base address that encompasses the auxiliary + * registers shared between the miniuart and spi. + * + * This is due to historical reasons, see discussion here : + * https://edk2.groups.io/g/devel/topic/87501357#84349 + * + * We need to add the offset between the miniuart and auxiliary + * registers to get the real miniuart base address. + */ + if (bcm_data) + offset = bcm_data->offset; + + up.port.mapbase = res->start + offset; + up.port.mapsize = resource_size(res) - offset; /* Check for a fixed line number */ ret = of_alias_get_id(pdev->dev.of_node, "serial"); @@ -141,12 +163,19 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev) return ret; } + 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"); + } + /* the HW-clock divider for bcm2835aux is 8, * but 8250 expects a divider of 16, * so we have to multiply the actual clock by 2 * to get identical baudrates. */ - up.port.uartclk = clk_get_rate(data->clk) * 2; + up.port.uartclk = uartclk * 2; /* register the port */ ret = serial8250_register_8250_port(&up); @@ -173,16 +202,27 @@ static int bcm2835aux_serial_remove(struct platform_device *pdev) return 0; } +static const struct bcm2835_aux_serial_driver_data bcm2835_acpi_data = { + .offset = 0x40, +}; + static const struct of_device_id bcm2835aux_serial_match[] = { { .compatible = "brcm,bcm2835-aux-uart" }, { }, }; MODULE_DEVICE_TABLE(of, bcm2835aux_serial_match); +static const struct acpi_device_id bcm2835aux_serial_acpi_match[] = { + { "BCM2836", (kernel_ulong_t)&bcm2835_acpi_data }, + { } +}; +MODULE_DEVICE_TABLE(acpi, bcm2835aux_serial_acpi_match); + static struct platform_driver bcm2835aux_serial_driver = { .driver = { .name = "bcm2835-aux-uart", .of_match_table = bcm2835aux_serial_match, + .acpi_match_table = bcm2835aux_serial_acpi_match, }, .probe = bcm2835aux_serial_probe, .remove = bcm2835aux_serial_remove, diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index d502240bbcf2..7292917ac878 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -623,7 +623,12 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) maxnr = pci_resource_len(pcidev, bar) >> (board->reg_shift + 3); - nr_ports = board->num_ports ? board->num_ports : pcidev->device & 0x0f; + if (pcidev->vendor == PCI_VENDOR_ID_ACCESSIO) + nr_ports = BIT(((pcidev->device & 0x38) >> 3) - 1); + else if (board->num_ports) + nr_ports = board->num_ports; + else + nr_ports = pcidev->device & 0x0f; priv = devm_kzalloc(&pcidev->dev, struct_size(priv, line, nr_ports), GFP_KERNEL); if (!priv) @@ -722,22 +727,6 @@ static int __maybe_unused exar_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(exar_pci_pm, exar_suspend, exar_resume); -static const struct exar8250_board acces_com_2x = { - .num_ports = 2, - .setup = pci_xr17c154_setup, -}; - -static const struct exar8250_board acces_com_4x = { - .num_ports = 4, - .setup = pci_xr17c154_setup, -}; - -static const struct exar8250_board acces_com_8x = { - .num_ports = 8, - .setup = pci_xr17c154_setup, -}; - - static const struct exar8250_board pbn_fastcom335_2 = { .num_ports = 2, .setup = pci_fastcom335_setup, @@ -822,13 +811,13 @@ static const struct exar8250_board pbn_exar_XR17V8358 = { } static const struct pci_device_id exar_pci_tbl[] = { - EXAR_DEVICE(ACCESSIO, COM_2S, acces_com_2x), - EXAR_DEVICE(ACCESSIO, COM_4S, acces_com_4x), - EXAR_DEVICE(ACCESSIO, COM_8S, acces_com_8x), - EXAR_DEVICE(ACCESSIO, COM232_8, acces_com_8x), - EXAR_DEVICE(ACCESSIO, COM_2SM, acces_com_2x), - EXAR_DEVICE(ACCESSIO, COM_4SM, acces_com_4x), - EXAR_DEVICE(ACCESSIO, COM_8SM, acces_com_8x), + EXAR_DEVICE(ACCESSIO, COM_2S, pbn_exar_XR17C15x), + EXAR_DEVICE(ACCESSIO, COM_4S, pbn_exar_XR17C15x), + EXAR_DEVICE(ACCESSIO, COM_8S, pbn_exar_XR17C15x), + EXAR_DEVICE(ACCESSIO, COM232_8, pbn_exar_XR17C15x), + EXAR_DEVICE(ACCESSIO, COM_2SM, pbn_exar_XR17C15x), + EXAR_DEVICE(ACCESSIO, COM_4SM, pbn_exar_XR17C15x), + EXAR_DEVICE(ACCESSIO, COM_8SM, pbn_exar_XR17C15x), CONNECT_DEVICE(XR17C152, UART_2_232, pbn_connect), CONNECT_DEVICE(XR17C154, UART_4_232, pbn_connect), diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index c370eddc651b..2d09a89974a2 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -8,6 +8,7 @@ * * DMA support added by Chip Coldwell. */ +#include <linux/circ_buf.h> #include <linux/tty.h> #include <linux/ioport.h> #include <linux/slab.h> diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c index 283757264608..e72cba085743 100644 --- a/drivers/tty/serial/fsl_linflexuart.c +++ b/drivers/tty/serial/fsl_linflexuart.c @@ -157,27 +157,29 @@ static void linflex_stop_rx(struct uart_port *port) writel(ier & ~LINFLEXD_LINIER_DRIE, port->membase + LINIER); } -static inline void linflex_transmit_buffer(struct uart_port *sport) +static void linflex_put_char(struct uart_port *sport, unsigned char c) { - struct circ_buf *xmit = &sport->state->xmit; - unsigned char c; unsigned long status; - while (!uart_circ_empty(xmit)) { - c = xmit->buf[xmit->tail]; - writeb(c, sport->membase + BDRL); + writeb(c, sport->membase + BDRL); - /* Waiting for data transmission completed. */ - while (((status = readl(sport->membase + UARTSR)) & - LINFLEXD_UARTSR_DTFTFF) != - LINFLEXD_UARTSR_DTFTFF) - ; + /* Waiting for data transmission completed. */ + while (((status = readl(sport->membase + UARTSR)) & + LINFLEXD_UARTSR_DTFTFF) != + LINFLEXD_UARTSR_DTFTFF) + ; + + writel(status | LINFLEXD_UARTSR_DTFTFF, sport->membase + UARTSR); +} + +static inline void linflex_transmit_buffer(struct uart_port *sport) +{ + struct circ_buf *xmit = &sport->state->xmit; + while (!uart_circ_empty(xmit)) { + linflex_put_char(sport, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); sport->icount.tx++; - - writel(status | LINFLEXD_UARTSR_DTFTFF, - sport->membase + UARTSR); } if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) @@ -201,21 +203,11 @@ static irqreturn_t linflex_txint(int irq, void *dev_id) struct uart_port *sport = dev_id; struct circ_buf *xmit = &sport->state->xmit; unsigned long flags; - unsigned long status; spin_lock_irqsave(&sport->lock, flags); if (sport->x_char) { - writeb(sport->x_char, sport->membase + BDRL); - - /* waiting for data transmission completed */ - while (((status = readl(sport->membase + UARTSR)) & - LINFLEXD_UARTSR_DTFTFF) != LINFLEXD_UARTSR_DTFTFF) - ; - - writel(status | LINFLEXD_UARTSR_DTFTFF, - sport->membase + UARTSR); - + linflex_put_char(sport, sport->x_char); goto out; } @@ -225,10 +217,6 @@ static irqreturn_t linflex_txint(int irq, void *dev_id) } linflex_transmit_buffer(sport); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(sport); - out: spin_unlock_irqrestore(&sport->lock, flags); return IRQ_HANDLED; diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index ce3e26144689..7d90c5a530ee 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -931,7 +931,8 @@ static void lpuart_rxint(struct lpuart_port *sport) sport->port.sysrq = 0; } - tty_insert_flip_char(port, rx, flg); + if (tty_insert_flip_char(port, rx, flg) == 0) + sport->port.icount.buf_overrun++; } out: @@ -1024,7 +1025,8 @@ static void lpuart32_rxint(struct lpuart_port *sport) flg = TTY_OVERRUN; } - tty_insert_flip_char(port, rx, flg); + if (tty_insert_flip_char(port, rx, flg) == 0) + sport->port.icount.buf_overrun++; } out: @@ -1116,7 +1118,7 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) struct dma_chan *chan = sport->dma_rx_chan; struct circ_buf *ring = &sport->rx_ring; unsigned long flags; - int count = 0; + int count = 0, copied; if (lpuart_is_32(sport)) { unsigned long sr = lpuart32_read(&sport->port, UARTSTAT); @@ -1218,20 +1220,24 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) if (ring->head < ring->tail) { count = sport->rx_sgl.length - ring->tail; - tty_insert_flip_string(port, ring->buf + ring->tail, count); + copied = tty_insert_flip_string(port, ring->buf + ring->tail, count); + if (copied != count) + sport->port.icount.buf_overrun++; ring->tail = 0; - sport->port.icount.rx += count; + sport->port.icount.rx += copied; } /* Finally we read data from tail to head */ if (ring->tail < ring->head) { count = ring->head - ring->tail; - tty_insert_flip_string(port, ring->buf + ring->tail, count); + copied = tty_insert_flip_string(port, ring->buf + ring->tail, count); + if (copied != count) + sport->port.icount.buf_overrun++; /* Wrap ring->head if needed */ if (ring->head >= sport->rx_sgl.length) ring->head = 0; ring->tail = ring->head; - sport->port.icount.rx += count; + sport->port.icount.rx += copied; } exit: diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index df8a0c8b8b29..0b467ce8d737 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -455,9 +455,14 @@ static void imx_uart_stop_tx(struct uart_port *port) if (port->rs485.flags & SER_RS485_ENABLED) { if (sport->tx_state == SEND) { sport->tx_state = WAIT_AFTER_SEND; - start_hrtimer_ms(&sport->trigger_stop_tx, + + if (port->rs485.delay_rts_after_send > 0) { + start_hrtimer_ms(&sport->trigger_stop_tx, port->rs485.delay_rts_after_send); - return; + return; + } + + /* continue without any delay */ } if (sport->tx_state == WAIT_AFTER_RTS || @@ -698,9 +703,14 @@ static void imx_uart_start_tx(struct uart_port *port) imx_uart_stop_rx(port); sport->tx_state = WAIT_AFTER_RTS; - start_hrtimer_ms(&sport->trigger_start_tx, + + if (port->rs485.delay_rts_before_send > 0) { + start_hrtimer_ms(&sport->trigger_start_tx, port->rs485.delay_rts_before_send); - return; + return; + } + + /* continue without any delay */ } if (sport->tx_state == WAIT_AFTER_SEND @@ -1258,7 +1268,7 @@ static void imx_uart_clear_rx_errors(struct imx_port *sport) } #define TXTL_DEFAULT 2 /* reset default */ -#define RXTL_DEFAULT 1 /* reset default */ +#define RXTL_DEFAULT 8 /* 8 characters or aging timer */ #define TXTL_DMA 8 /* DMA burst setting */ #define RXTL_DMA 9 /* DMA burst setting */ diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index 3c92d4e01488..9494690dcfe2 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -554,7 +554,6 @@ static void max3100_shutdown(struct uart_port *port) del_timer_sync(&s->timer); if (s->workqueue) { - flush_workqueue(s->workqueue); destroy_workqueue(s->workqueue); s->workqueue = NULL; } diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c index c7cec7d03620..2aec62b5d6c4 100644 --- a/drivers/tty/serial/mcf.c +++ b/drivers/tty/serial/mcf.c @@ -338,7 +338,7 @@ static void mcf_tx_chars(struct mcf_uart *pp) } while (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY) { - if (xmit->head == xmit->tail) + if (uart_circ_empty(xmit)) break; writeb(xmit->buf[xmit->tail], port->membase + MCFUART_UTB); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1); @@ -348,9 +348,8 @@ static void mcf_tx_chars(struct mcf_uart *pp) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); - if (xmit->head == xmit->tail) { - pp->imr &= ~MCFUART_UIR_TXREADY; - writeb(pp->imr, port->membase + MCFUART_UIMR); + if (uart_circ_empty(xmit)) { + mcf_stop_tx(port); /* Disable TX to negate RTS automatically */ if (port->rs485.flags & SER_RS485_ENABLED) writeb(MCFUART_UCR_TXDISABLE, diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 0db90be4c3bc..846192a7b4bf 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -105,6 +105,7 @@ void uart_write_wakeup(struct uart_port *port) BUG_ON(!state); tty_port_tty_wakeup(&state->port); } +EXPORT_SYMBOL(uart_write_wakeup); static void uart_stop(struct tty_struct *tty) { @@ -316,8 +317,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) state->xmit.buf = NULL; uart_port_unlock(uport, flags); - if (xmit_buf) - free_page((unsigned long)xmit_buf); + free_page((unsigned long)xmit_buf); } /** @@ -343,7 +343,6 @@ uart_update_timeout(struct uart_port *port, unsigned int cflag, */ port->timeout = (HZ * size) / baud + HZ/50; } - EXPORT_SYMBOL(uart_update_timeout); /** @@ -445,7 +444,6 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, WARN_ON(1); return 0; } - EXPORT_SYMBOL(uart_get_baud_rate); /** @@ -470,7 +468,6 @@ uart_get_divisor(struct uart_port *port, unsigned int baud) return quot; } - EXPORT_SYMBOL(uart_get_divisor); /* Caller holds port mutex */ @@ -1571,8 +1568,7 @@ static void uart_tty_port_shutdown(struct tty_port *port) state->xmit.buf = NULL; spin_unlock_irq(&uport->lock); - if (buf) - free_page((unsigned long)buf); + free_page((unsigned long)buf); uart_change_pm(state, UART_PM_STATE_OFF); } @@ -2207,6 +2203,7 @@ unlock: return 0; } +EXPORT_SYMBOL(uart_suspend_port); int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) { @@ -2292,6 +2289,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) return 0; } +EXPORT_SYMBOL(uart_resume_port); static inline void uart_report_port(struct uart_driver *drv, struct uart_port *port) @@ -2589,6 +2587,7 @@ out_kfree: out: return retval; } +EXPORT_SYMBOL(uart_register_driver); /** * uart_unregister_driver - remove a driver from the uart core layer @@ -2612,6 +2611,7 @@ void uart_unregister_driver(struct uart_driver *drv) drv->state = NULL; drv->tty_driver = NULL; } +EXPORT_SYMBOL(uart_unregister_driver); struct tty_driver *uart_console_device(struct console *co, int *index) { @@ -2946,6 +2946,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) return ret; } +EXPORT_SYMBOL(uart_add_one_port); /** * uart_remove_one_port - detach a driver defined port structure @@ -3026,6 +3027,7 @@ out: return ret; } +EXPORT_SYMBOL(uart_remove_one_port); /* * Are the two ports equivalent? @@ -3202,14 +3204,6 @@ bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch) EXPORT_SYMBOL_GPL(uart_try_toggle_sysrq); #endif -EXPORT_SYMBOL(uart_write_wakeup); -EXPORT_SYMBOL(uart_register_driver); -EXPORT_SYMBOL(uart_unregister_driver); -EXPORT_SYMBOL(uart_suspend_port); -EXPORT_SYMBOL(uart_resume_port); -EXPORT_SYMBOL(uart_add_one_port); -EXPORT_SYMBOL(uart_remove_one_port); - /** * uart_get_rs485_mode() - retrieve rs485 properties for given uart * @port: uart device's target port diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c index c41d8911ce95..1663b3afc3a0 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.c +++ b/drivers/tty/serial/serial_mctrl_gpio.c @@ -299,4 +299,42 @@ void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios) } EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms); +void mctrl_gpio_enable_irq_wake(struct mctrl_gpios *gpios) +{ + enum mctrl_gpio_idx i; + + if (!gpios) + return; + + if (!gpios->mctrl_on) + return; + + for (i = 0; i < UART_GPIO_MAX; ++i) { + if (!gpios->irq[i]) + continue; + + enable_irq_wake(gpios->irq[i]); + } +} +EXPORT_SYMBOL_GPL(mctrl_gpio_enable_irq_wake); + +void mctrl_gpio_disable_irq_wake(struct mctrl_gpios *gpios) +{ + enum mctrl_gpio_idx i; + + if (!gpios) + return; + + if (!gpios->mctrl_on) + return; + + for (i = 0; i < UART_GPIO_MAX; ++i) { + if (!gpios->irq[i]) + continue; + + disable_irq_wake(gpios->irq[i]); + } +} +EXPORT_SYMBOL_GPL(mctrl_gpio_disable_irq_wake); + MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/serial_mctrl_gpio.h b/drivers/tty/serial/serial_mctrl_gpio.h index b134a0ffc894..fc76910fb105 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.h +++ b/drivers/tty/serial/serial_mctrl_gpio.h @@ -91,6 +91,16 @@ void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios); */ void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios); +/* + * Enable gpio wakeup interrupts to enable wake up source. + */ +void mctrl_gpio_enable_irq_wake(struct mctrl_gpios *gpios); + +/* + * Disable gpio wakeup interrupts to enable wake up source. + */ +void mctrl_gpio_disable_irq_wake(struct mctrl_gpios *gpios); + #else /* GPIOLIB */ static inline @@ -142,6 +152,14 @@ static inline void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios) { } +static inline void mctrl_gpio_enable_irq_wake(struct mctrl_gpios *gpios) +{ +} + +static inline void mctrl_gpio_disable_irq_wake(struct mctrl_gpios *gpios) +{ +} + #endif /* GPIOLIB */ #endif diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 9570002d07e7..1b3a611ac39e 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -1756,6 +1756,7 @@ static int __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port, if (enable) { stm32_usart_set_bits(port, ofs->cr1, USART_CR1_UESM); stm32_usart_set_bits(port, ofs->cr3, USART_CR3_WUFIE); + mctrl_gpio_enable_irq_wake(stm32_port->gpios); /* * When DMA is used for reception, it must be disabled before @@ -1782,7 +1783,7 @@ static int __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port, if (ret) return ret; } - + mctrl_gpio_disable_irq_wake(stm32_port->gpios); stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_UESM); stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_WUFIE); } diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 7709ce655f44..880608a65773 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -225,8 +225,11 @@ int tty_port_alloc_xmit_buf(struct tty_port *port) { /* We may sleep in get_zeroed_page() */ mutex_lock(&port->buf_mutex); - if (port->xmit_buf == NULL) + if (port->xmit_buf == NULL) { port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL); + if (port->xmit_buf) + kfifo_init(&port->xmit_fifo, port->xmit_buf, PAGE_SIZE); + } mutex_unlock(&port->buf_mutex); if (port->xmit_buf == NULL) return -ENOMEM; @@ -237,10 +240,9 @@ EXPORT_SYMBOL(tty_port_alloc_xmit_buf); void tty_port_free_xmit_buf(struct tty_port *port) { mutex_lock(&port->buf_mutex); - if (port->xmit_buf != NULL) { - free_page((unsigned long)port->xmit_buf); - port->xmit_buf = NULL; - } + free_page((unsigned long)port->xmit_buf); + port->xmit_buf = NULL; + INIT_KFIFO(port->xmit_fifo); mutex_unlock(&port->buf_mutex); } EXPORT_SYMBOL(tty_port_free_xmit_buf); @@ -267,8 +269,7 @@ static void tty_port_destructor(struct kref *kref) /* check if last port ref was dropped before tty release */ if (WARN_ON(port->itty)) return; - if (port->xmit_buf) - free_page((unsigned long)port->xmit_buf); + free_page((unsigned long)port->xmit_buf); tty_port_destroy(port); if (port->ops && port->ops->destruct) port->ops->destruct(port); @@ -732,6 +733,9 @@ EXPORT_SYMBOL_GPL(tty_port_install); * the device to be ready using tty_port_block_til_ready() (e.g. raises * DTR/CTS and waits for carrier). * + * Note that @port->ops->shutdown is not called when @port->ops->activate + * returns an error (on the contrary, @tty->ops->close is). + * * Locking: Caller holds tty lock. * * Note: may drop and reacquire tty lock (in tty_port_block_til_ready()) so diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index c58cc142d23f..31f7fe527395 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -171,7 +171,7 @@ struct uart_port { * assigned from the serial_struct flags in uart_set_info() * [for bit definitions in the UPF_CHANGE_MASK] * - * Bits [0..UPF_LAST_USER] are userspace defined/visible/changeable + * Bits [0..ASYNCB_LAST_USER] are userspace defined/visible/changeable * The remaining bits are serial-core specific and not modifiable by * userspace. */ diff --git a/include/linux/tty_port.h b/include/linux/tty_port.h index d3ea9ed0b98e..58e9619116b7 100644 --- a/include/linux/tty_port.h +++ b/include/linux/tty_port.h @@ -2,6 +2,7 @@ #ifndef _LINUX_TTY_PORT_H #define _LINUX_TTY_PORT_H +#include <linux/kfifo.h> #include <linux/kref.h> #include <linux/mutex.h> #include <linux/tty_buffer.h> @@ -67,6 +68,7 @@ extern const struct tty_port_client_operations tty_port_default_client_ops; * @mutex: locking, for open, shutdown and other port operations * @buf_mutex: @xmit_buf alloc lock * @xmit_buf: optional xmit buffer used by some drivers + * @xmit_fifo: optional xmit buffer used by some drivers * @close_delay: delay in jiffies to wait when closing the port * @closing_wait: delay in jiffies for output to be sent before closing * @drain_delay: set to zero if no pure time based drain is needed else set to @@ -110,6 +112,7 @@ struct tty_port { struct mutex mutex; struct mutex buf_mutex; unsigned char *xmit_buf; + DECLARE_KFIFO_PTR(xmit_fifo, unsigned char); unsigned int close_delay; unsigned int closing_wait; int drain_delay; |