aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/serial/fsl-lpuart.yaml10
-rw-r--r--Documentation/devicetree/bindings/serial/mtk-uart.txt1
-rw-r--r--Documentation/devicetree/bindings/serial/renesas,sci.yaml2
-rw-r--r--Documentation/devicetree/bindings/serial/renesas,scif.yaml5
-rw-r--r--Documentation/devicetree/bindings/serial/samsung_uart.yaml2
-rw-r--r--drivers/tty/amiserial.c6
-rw-r--r--drivers/tty/mxser.c109
-rw-r--r--drivers/tty/serdev/core.c7
-rw-r--r--drivers/tty/serial/8250/8250_bcm2835aux.c52
-rw-r--r--drivers/tty/serial/8250/8250_exar.c37
-rw-r--r--drivers/tty/serial/atmel_serial.c1
-rw-r--r--drivers/tty/serial/fsl_linflexuart.c46
-rw-r--r--drivers/tty/serial/fsl_lpuart.c20
-rw-r--r--drivers/tty/serial/imx.c20
-rw-r--r--drivers/tty/serial/max3100.c1
-rw-r--r--drivers/tty/serial/mcf.c7
-rw-r--r--drivers/tty/serial/serial_core.c24
-rw-r--r--drivers/tty/serial/serial_mctrl_gpio.c38
-rw-r--r--drivers/tty/serial/serial_mctrl_gpio.h18
-rw-r--r--drivers/tty/serial/stm32-usart.c3
-rw-r--r--drivers/tty/tty_port.c18
-rw-r--r--include/linux/serial_core.h2
-rw-r--r--include/linux/tty_port.h3
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;