mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
Merge tag 'tty-4.21-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull tty/serial driver updates from Greg KH:
"Here is the large TTY/Serial driver set of patches for 4.21-rc1.
A number of small serial driver changes along with some good tty core
fixes for long-reported issues with locking. There is also a new
console font added to the tree, for high-res screens, so that should
be helpful for many.
The last patch in the series is a revert of an older one in the tree,
it came late but it resolves a reported issue that linux-next was
having for some people.
Full details are in the shortlog, and all of these, with the exception
of the revert, have been in linux-next for a while with no reported
issues"
* tag 'tty-4.21-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (85 commits)
Revert "serial: 8250: Default SERIAL_OF_PLATFORM to SERIAL_8250"
serial: sccnxp: Allow to use non-standard baud rates
serial: sccnxp: Adds a delay between sequential read/write cycles
tty: serial: qcom_geni_serial: Fix UART hang
tty: serial: qcom_geni_serial: Fix wrap around of TX buffer
serial: max310x: Fix tx_empty() callback
dt-bindings: serial: sh-sci: Document r8a774c0 bindings
dt-bindings: serial: sh-sci: Document r8a774a1 bindings
Fonts: New Terminus large console font
dt-bindings: serial: lpuart: add imx8qxp compatible string
serial: uartps: Fix interrupt mask issue to handle the RX interrupts properly
serial: uartps: Fix error path when alloc failed
serial: uartps: Check if the device is a console
serial: uartps: Add the device_init_wakeup
tty: serial: samsung: Increase maximum baudrate
tty: serial: samsung: Properly set flags in autoCTS mode
tty: Use of_node_name_{eq,prefix} for node name comparisons
tty/serial: do not free trasnmit buffer page under port lock
serial: 8250: Rate limit serial port rx interrupts during input overruns
dt-bindings: serial: 8250: Add rate limit for serial port input overruns
...
This commit is contained in:
33
Documentation/devicetree/bindings/dma/8250_mtk_dma.txt
Normal file
33
Documentation/devicetree/bindings/dma/8250_mtk_dma.txt
Normal file
@@ -0,0 +1,33 @@
|
||||
* Mediatek UART APDMA Controller
|
||||
|
||||
Required properties:
|
||||
- compatible should contain:
|
||||
* "mediatek,mt2712-uart-dma" for MT2712 compatible APDMA
|
||||
* "mediatek,mt6577-uart-dma" for MT6577 and all of the above
|
||||
|
||||
- reg: The base address of the APDMA register bank.
|
||||
|
||||
- interrupts: A single interrupt specifier.
|
||||
|
||||
- clocks : Must contain an entry for each entry in clock-names.
|
||||
See ../clocks/clock-bindings.txt for details.
|
||||
- clock-names: The APDMA clock for register accesses
|
||||
|
||||
Examples:
|
||||
|
||||
apdma: dma-controller@11000380 {
|
||||
compatible = "mediatek,mt2712-uart-dma";
|
||||
reg = <0 0x11000380 0 0x400>;
|
||||
interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_LOW>,
|
||||
<GIC_SPI 64 IRQ_TYPE_LEVEL_LOW>,
|
||||
<GIC_SPI 65 IRQ_TYPE_LEVEL_LOW>,
|
||||
<GIC_SPI 66 IRQ_TYPE_LEVEL_LOW>,
|
||||
<GIC_SPI 67 IRQ_TYPE_LEVEL_LOW>,
|
||||
<GIC_SPI 68 IRQ_TYPE_LEVEL_LOW>,
|
||||
<GIC_SPI 69 IRQ_TYPE_LEVEL_LOW>,
|
||||
<GIC_SPI 70 IRQ_TYPE_LEVEL_LOW>;
|
||||
clocks = <&pericfg CLK_PERI_AP_DMA>;
|
||||
clock-names = "apdma";
|
||||
#dma-cells = <1>;
|
||||
};
|
||||
|
||||
@@ -51,6 +51,7 @@ Optional properties:
|
||||
- tx-threshold: Specify the TX FIFO low water indication for parts with
|
||||
programmable TX FIFO thresholds.
|
||||
- resets : phandle + reset specifier pairs
|
||||
- overrun-throttle-ms : how long to pause uart rx when input overrun is encountered.
|
||||
|
||||
Note:
|
||||
* fsl,ns16550:
|
||||
|
||||
@@ -8,6 +8,8 @@ Required properties:
|
||||
on LS1021A SoC with 32-bit big-endian register organization
|
||||
- "fsl,imx7ulp-lpuart" for lpuart compatible with the one integrated
|
||||
on i.MX7ULP SoC with 32-bit little-endian register organization
|
||||
- "fsl,imx8qxp-lpuart" for lpuart compatible with the one integrated
|
||||
on i.MX8QXP SoC with 32-bit little-endian register organization
|
||||
- reg : Address and length of the register set for the device
|
||||
- interrupts : Should contain uart interrupt
|
||||
- clocks : phandle + clock specifier pairs, one for each entry in clock-names
|
||||
|
||||
@@ -6,8 +6,23 @@ Required properties:
|
||||
- interrupts: the 3 (tx rx err) interrupt numbers. The interrupt specifier
|
||||
depends on the interrupt-parent interrupt controller.
|
||||
|
||||
Optional properties:
|
||||
- clocks: Should contain frequency clock and gate clock
|
||||
- clock-names: Should be "freq" and "asc"
|
||||
|
||||
Example:
|
||||
|
||||
asc0: serial@16600000 {
|
||||
compatible = "lantiq,asc";
|
||||
reg = <0x16600000 0x100000>;
|
||||
interrupt-parent = <&gic>;
|
||||
interrupts = <GIC_SHARED 103 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SHARED 105 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SHARED 106 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cgu CLK_SSX4>, <&cgu GCLK_UART>;
|
||||
clock-names = "freq", "asc";
|
||||
};
|
||||
|
||||
asc1: serial@e100c00 {
|
||||
compatible = "lantiq,asc";
|
||||
reg = <0xE100C00 0x400>;
|
||||
|
||||
@@ -24,6 +24,10 @@ Required properties:
|
||||
- "renesas,hscif-r8a7745" for R8A7745 (RZ/G1E) HSCIF compatible UART.
|
||||
- "renesas,scif-r8a77470" for R8A77470 (RZ/G1C) SCIF compatible UART.
|
||||
- "renesas,hscif-r8a77470" for R8A77470 (RZ/G1C) HSCIF compatible UART.
|
||||
- "renesas,scif-r8a774a1" for R8A774A1 (RZ/G2M) SCIF compatible UART.
|
||||
- "renesas,hscif-r8a774a1" for R8A774A1 (RZ/G2M) HSCIF compatible UART.
|
||||
- "renesas,scif-r8a774c0" for R8A774C0 (RZ/G2E) SCIF compatible UART.
|
||||
- "renesas,hscif-r8a774c0" for R8A774C0 (RZ/G2E) HSCIF compatible UART.
|
||||
- "renesas,scif-r8a7778" for R8A7778 (R-Car M1) SCIF compatible UART.
|
||||
- "renesas,scif-r8a7779" for R8A7779 (R-Car H1) SCIF compatible UART.
|
||||
- "renesas,scif-r8a7790" for R8A7790 (R-Car H2) SCIF compatible UART.
|
||||
@@ -61,13 +65,13 @@ Required properties:
|
||||
- "renesas,scifa-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFA compatible UART.
|
||||
- "renesas,scifb-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFB compatible UART.
|
||||
- "renesas,rcar-gen1-scif" for R-Car Gen1 SCIF compatible UART,
|
||||
- "renesas,rcar-gen2-scif" for R-Car Gen2 SCIF compatible UART,
|
||||
- "renesas,rcar-gen3-scif" for R-Car Gen3 SCIF compatible UART,
|
||||
- "renesas,rcar-gen2-scifa" for R-Car Gen2 SCIFA compatible UART,
|
||||
- "renesas,rcar-gen2-scifb" for R-Car Gen2 SCIFB compatible UART,
|
||||
- "renesas,rcar-gen2-scif" for R-Car Gen2 and RZ/G1 SCIF compatible UART,
|
||||
- "renesas,rcar-gen3-scif" for R-Car Gen3 and RZ/G2 SCIF compatible UART,
|
||||
- "renesas,rcar-gen2-scifa" for R-Car Gen2 and RZ/G1 SCIFA compatible UART,
|
||||
- "renesas,rcar-gen2-scifb" for R-Car Gen2 and RZ/G1 SCIFB compatible UART,
|
||||
- "renesas,rcar-gen1-hscif" for R-Car Gen1 HSCIF compatible UART,
|
||||
- "renesas,rcar-gen2-hscif" for R-Car Gen2 HSCIF compatible UART,
|
||||
- "renesas,rcar-gen3-hscif" for R-Car Gen3 HSCIF compatible UART,
|
||||
- "renesas,rcar-gen2-hscif" for R-Car Gen2 and RZ/G1 HSCIF compatible UART,
|
||||
- "renesas,rcar-gen3-hscif" for R-Car Gen3 and RZ/G2 HSCIF compatible UART,
|
||||
- "renesas,scif" for generic SCIF compatible UART.
|
||||
- "renesas,scifa" for generic SCIFA compatible UART.
|
||||
- "renesas,scifb" for generic SCIFB compatible UART.
|
||||
|
||||
@@ -66,6 +66,14 @@ config TTY_PRINTK
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config TTY_PRINTK_LEVEL
|
||||
depends on TTY_PRINTK
|
||||
int "ttyprintk log level (1-7)"
|
||||
range 1 7
|
||||
default "6"
|
||||
help
|
||||
Printk log level to use for ttyprintk messages.
|
||||
|
||||
config PRINTER
|
||||
tristate "Parallel printer support"
|
||||
depends on PARPORT
|
||||
|
||||
@@ -37,6 +37,8 @@ static struct ttyprintk_port tpk_port;
|
||||
*/
|
||||
#define TPK_STR_SIZE 508 /* should be bigger then max expected line length */
|
||||
#define TPK_MAX_ROOM 4096 /* we could assume 4K for instance */
|
||||
#define TPK_PREFIX KERN_SOH __stringify(CONFIG_TTY_PRINTK_LEVEL)
|
||||
|
||||
static int tpk_curr;
|
||||
|
||||
static char tpk_buffer[TPK_STR_SIZE + 4];
|
||||
@@ -45,7 +47,7 @@ static void tpk_flush(void)
|
||||
{
|
||||
if (tpk_curr > 0) {
|
||||
tpk_buffer[tpk_curr] = '\0';
|
||||
pr_info("[U] %s\n", tpk_buffer);
|
||||
printk(TPK_PREFIX "[U] %s\n", tpk_buffer);
|
||||
tpk_curr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ static int gnss_serial_write_raw(struct gnss_device *gdev,
|
||||
|
||||
/* write is only buffered synchronously */
|
||||
ret = serdev_device_write(serdev, buf, count, MAX_SCHEDULE_TIMEOUT);
|
||||
if (ret < 0)
|
||||
if (ret < 0 || ret < count)
|
||||
return ret;
|
||||
|
||||
/* FIXME: determine if interrupted? */
|
||||
|
||||
@@ -85,7 +85,7 @@ static int sirf_write_raw(struct gnss_device *gdev, const unsigned char *buf,
|
||||
|
||||
/* write is only buffered synchronously */
|
||||
ret = serdev_device_write(serdev, buf, count, MAX_SCHEDULE_TIMEOUT);
|
||||
if (ret < 0)
|
||||
if (ret < 0 || ret < count)
|
||||
return ret;
|
||||
|
||||
/* FIXME: determine if interrupted? */
|
||||
|
||||
@@ -353,7 +353,7 @@ void __init hvc_opal_init_early(void)
|
||||
if (!opal)
|
||||
return;
|
||||
for_each_child_of_node(opal, np) {
|
||||
if (!strcmp(np->name, "serial")) {
|
||||
if (of_node_name_eq(np, "serial")) {
|
||||
stdout_node = np;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -371,20 +371,11 @@ device_initcall(hvc_vio_init); /* after drivers/tty/hvc/hvc_console.c */
|
||||
void __init hvc_vio_init_early(void)
|
||||
{
|
||||
const __be32 *termno;
|
||||
const char *name;
|
||||
const struct hv_ops *ops;
|
||||
|
||||
/* find the boot console from /chosen/stdout */
|
||||
if (!of_stdout)
|
||||
return;
|
||||
name = of_get_property(of_stdout, "name", NULL);
|
||||
if (!name) {
|
||||
printk(KERN_WARNING "stdout node missing 'name' property!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if it's a virtual terminal */
|
||||
if (strncmp(name, "vty", 3) != 0)
|
||||
if (!of_node_name_prefix(of_stdout, "vty"))
|
||||
return;
|
||||
termno = of_get_property(of_stdout, "reg", NULL);
|
||||
if (termno == NULL)
|
||||
|
||||
@@ -612,7 +612,7 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
|
||||
}
|
||||
|
||||
/* no data */
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
if (tty_io_nonblock(tty, file)) {
|
||||
ret = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
@@ -679,7 +679,7 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
|
||||
if (tbuf)
|
||||
break;
|
||||
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
if (tty_io_nonblock(tty, file)) {
|
||||
error = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1085,7 +1085,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
|
||||
pMsg = remove_msg(pInfo, pClient);
|
||||
if (pMsg == NULL) {
|
||||
/* no messages available. */
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
if (tty_io_nonblock(tty, file)) {
|
||||
ret = -EAGAIN;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
@@ -1702,7 +1702,7 @@ n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp,
|
||||
|
||||
down_read(&tty->termios_rwsem);
|
||||
|
||||
while (1) {
|
||||
do {
|
||||
/*
|
||||
* When PARMRK is set, each input char may take up to 3 chars
|
||||
* in the read buf; reduce the buffer space avail by 3x
|
||||
@@ -1744,7 +1744,7 @@ n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp,
|
||||
fp += n;
|
||||
count -= n;
|
||||
rcvd += n;
|
||||
}
|
||||
} while (!test_bit(TTY_LDISC_CHANGING, &tty->flags));
|
||||
|
||||
tty->receive_room = room;
|
||||
|
||||
@@ -2211,7 +2211,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
|
||||
break;
|
||||
if (!timeout)
|
||||
break;
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
if (tty_io_nonblock(tty, file)) {
|
||||
retval = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
@@ -2365,7 +2365,7 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
|
||||
}
|
||||
if (!nr)
|
||||
break;
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
if (tty_io_nonblock(tty, file)) {
|
||||
retval = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/serdev.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
@@ -216,6 +217,21 @@ void serdev_device_write_wakeup(struct serdev_device *serdev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serdev_device_write_wakeup);
|
||||
|
||||
/**
|
||||
* serdev_device_write_buf() - write data asynchronously
|
||||
* @serdev: serdev device
|
||||
* @buf: data to be written
|
||||
* @count: number of bytes to write
|
||||
*
|
||||
* Write data to the device asynchronously.
|
||||
*
|
||||
* Note that any accepted data has only been buffered by the controller; use
|
||||
* serdev_device_wait_until_sent() to make sure the controller write buffer
|
||||
* has actually been emptied.
|
||||
*
|
||||
* Return: The number of bytes written (less than count if not enough room in
|
||||
* the write buffer), or a negative errno on errors.
|
||||
*/
|
||||
int serdev_device_write_buf(struct serdev_device *serdev,
|
||||
const unsigned char *buf, size_t count)
|
||||
{
|
||||
@@ -228,17 +244,42 @@ int serdev_device_write_buf(struct serdev_device *serdev,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serdev_device_write_buf);
|
||||
|
||||
/**
|
||||
* serdev_device_write() - write data synchronously
|
||||
* @serdev: serdev device
|
||||
* @buf: data to be written
|
||||
* @count: number of bytes to write
|
||||
* @timeout: timeout in jiffies, or 0 to wait indefinitely
|
||||
*
|
||||
* Write data to the device synchronously by repeatedly calling
|
||||
* serdev_device_write() until the controller has accepted all data (unless
|
||||
* interrupted by a timeout or a signal).
|
||||
*
|
||||
* Note that any accepted data has only been buffered by the controller; use
|
||||
* serdev_device_wait_until_sent() to make sure the controller write buffer
|
||||
* has actually been emptied.
|
||||
*
|
||||
* Note that this function depends on serdev_device_write_wakeup() being
|
||||
* called in the serdev driver write_wakeup() callback.
|
||||
*
|
||||
* Return: The number of bytes written (less than count if interrupted),
|
||||
* -ETIMEDOUT or -ERESTARTSYS if interrupted before any bytes were written, or
|
||||
* a negative errno on errors.
|
||||
*/
|
||||
int serdev_device_write(struct serdev_device *serdev,
|
||||
const unsigned char *buf, size_t count,
|
||||
unsigned long timeout)
|
||||
long timeout)
|
||||
{
|
||||
struct serdev_controller *ctrl = serdev->ctrl;
|
||||
int written = 0;
|
||||
int ret;
|
||||
|
||||
if (!ctrl || !ctrl->ops->write_buf ||
|
||||
(timeout && !serdev->ops->write_wakeup))
|
||||
if (!ctrl || !ctrl->ops->write_buf || !serdev->ops->write_wakeup)
|
||||
return -EINVAL;
|
||||
|
||||
if (timeout == 0)
|
||||
timeout = MAX_SCHEDULE_TIMEOUT;
|
||||
|
||||
mutex_lock(&serdev->write_lock);
|
||||
do {
|
||||
reinit_completion(&serdev->write_comp);
|
||||
@@ -247,14 +288,29 @@ int serdev_device_write(struct serdev_device *serdev,
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
written += ret;
|
||||
buf += ret;
|
||||
count -= ret;
|
||||
|
||||
} while (count &&
|
||||
(timeout = wait_for_completion_timeout(&serdev->write_comp,
|
||||
timeout)));
|
||||
if (count == 0)
|
||||
break;
|
||||
|
||||
timeout = wait_for_completion_interruptible_timeout(&serdev->write_comp,
|
||||
timeout);
|
||||
} while (timeout > 0);
|
||||
mutex_unlock(&serdev->write_lock);
|
||||
return ret < 0 ? ret : (count ? -ETIMEDOUT : 0);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (timeout <= 0 && written == 0) {
|
||||
if (timeout == -ERESTARTSYS)
|
||||
return -ERESTARTSYS;
|
||||
else
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return written;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serdev_device_write);
|
||||
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
* Copyright (C) 2016 Jeremy Kerr <jk@ozlabs.org>, IBM Corp.
|
||||
* Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>, IBM Corp.
|
||||
*/
|
||||
#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
|
||||
#define SUPPORT_SYSRQ
|
||||
#endif
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
@@ -293,7 +297,7 @@ static int aspeed_vuart_handle_irq(struct uart_port *port)
|
||||
if (lsr & UART_LSR_THRE)
|
||||
serial8250_tx_chars(up);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
uart_unlock_and_check_sysrq(port, flags);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -942,6 +942,21 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void serial_8250_overrun_backoff_work(struct work_struct *work)
|
||||
{
|
||||
struct uart_8250_port *up =
|
||||
container_of(to_delayed_work(work), struct uart_8250_port,
|
||||
overrun_backoff);
|
||||
struct uart_port *port = &up->port;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
up->ier |= UART_IER_RLSI | UART_IER_RDI;
|
||||
up->port.read_status_mask |= UART_LSR_DR;
|
||||
serial_out(up, UART_IER, up->ier);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* serial8250_register_8250_port - register a serial port
|
||||
* @up: serial port template
|
||||
@@ -1056,6 +1071,16 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialise interrupt backoff work if required */
|
||||
if (up->overrun_backoff_time_ms > 0) {
|
||||
uart->overrun_backoff_time_ms = up->overrun_backoff_time_ms;
|
||||
INIT_DELAYED_WORK(&uart->overrun_backoff,
|
||||
serial_8250_overrun_backoff_work);
|
||||
} else {
|
||||
uart->overrun_backoff_time_ms = 0;
|
||||
}
|
||||
|
||||
mutex_unlock(&serial_mutex);
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
|
||||
#define SUPPORT_SYSRQ
|
||||
#endif
|
||||
|
||||
#include <linux/serial_reg.h>
|
||||
#include <linux/serial_8250.h>
|
||||
|
||||
@@ -45,8 +49,29 @@ int fsl8250_handle_irq(struct uart_port *port)
|
||||
|
||||
lsr = orig_lsr = up->port.serial_in(&up->port, UART_LSR);
|
||||
|
||||
if (lsr & (UART_LSR_DR | UART_LSR_BI))
|
||||
/* Process incoming characters first */
|
||||
if ((lsr & (UART_LSR_DR | UART_LSR_BI)) &&
|
||||
(up->ier & (UART_IER_RLSI | UART_IER_RDI))) {
|
||||
lsr = serial8250_rx_chars(up, lsr);
|
||||
}
|
||||
|
||||
/* Stop processing interrupts on input overrun */
|
||||
if ((orig_lsr & UART_LSR_OE) && (up->overrun_backoff_time_ms > 0)) {
|
||||
unsigned long delay;
|
||||
|
||||
up->ier = port->serial_in(port, UART_IER);
|
||||
if (up->ier & (UART_IER_RLSI | UART_IER_RDI)) {
|
||||
port->ops->stop_rx(port);
|
||||
} else {
|
||||
/* Keep restarting the timer until
|
||||
* the input overrun subsides.
|
||||
*/
|
||||
cancel_delayed_work(&up->overrun_backoff);
|
||||
}
|
||||
|
||||
delay = msecs_to_jiffies(up->overrun_backoff_time_ms);
|
||||
schedule_delayed_work(&up->overrun_backoff, delay);
|
||||
}
|
||||
|
||||
serial8250_modem_status(up);
|
||||
|
||||
@@ -54,7 +79,7 @@ int fsl8250_handle_irq(struct uart_port *port)
|
||||
serial8250_tx_chars(up);
|
||||
|
||||
up->lsr_saved_flags = orig_lsr;
|
||||
spin_unlock_irqrestore(&up->port.lock, flags);
|
||||
uart_unlock_and_check_sysrq(&up->port, flags);
|
||||
return 1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fsl8250_handle_irq);
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/serial_reg.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_flip.h>
|
||||
|
||||
#include "8250.h"
|
||||
|
||||
@@ -22,12 +26,172 @@
|
||||
#define UART_MTK_SAMPLE_POINT 0x0b /* Sample point register */
|
||||
#define MTK_UART_RATE_FIX 0x0d /* UART Rate Fix Register */
|
||||
|
||||
#define MTK_UART_DMA_EN 0x13 /* DMA Enable register */
|
||||
#define MTK_UART_DMA_EN_TX 0x2
|
||||
#define MTK_UART_DMA_EN_RX 0x5
|
||||
|
||||
#define MTK_UART_TX_SIZE UART_XMIT_SIZE
|
||||
#define MTK_UART_RX_SIZE 0x8000
|
||||
#define MTK_UART_TX_TRIGGER 1
|
||||
#define MTK_UART_RX_TRIGGER MTK_UART_RX_SIZE
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
enum dma_rx_status {
|
||||
DMA_RX_START = 0,
|
||||
DMA_RX_RUNNING = 1,
|
||||
DMA_RX_SHUTDOWN = 2,
|
||||
};
|
||||
#endif
|
||||
|
||||
struct mtk8250_data {
|
||||
int line;
|
||||
unsigned int rx_pos;
|
||||
struct clk *uart_clk;
|
||||
struct clk *bus_clk;
|
||||
struct uart_8250_dma *dma;
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
enum dma_rx_status rx_status;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
static void mtk8250_rx_dma(struct uart_8250_port *up);
|
||||
|
||||
static void mtk8250_dma_rx_complete(void *param)
|
||||
{
|
||||
struct uart_8250_port *up = param;
|
||||
struct uart_8250_dma *dma = up->dma;
|
||||
struct mtk8250_data *data = up->port.private_data;
|
||||
struct tty_port *tty_port = &up->port.state->port;
|
||||
struct dma_tx_state state;
|
||||
unsigned char *ptr;
|
||||
int copied;
|
||||
|
||||
dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr,
|
||||
dma->rx_size, DMA_FROM_DEVICE);
|
||||
|
||||
dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
|
||||
|
||||
if (data->rx_status == DMA_RX_SHUTDOWN)
|
||||
return;
|
||||
|
||||
if ((data->rx_pos + state.residue) <= dma->rx_size) {
|
||||
ptr = (unsigned char *)(data->rx_pos + dma->rx_buf);
|
||||
copied = tty_insert_flip_string(tty_port, ptr, state.residue);
|
||||
} else {
|
||||
ptr = (unsigned char *)(data->rx_pos + dma->rx_buf);
|
||||
copied = tty_insert_flip_string(tty_port, ptr,
|
||||
dma->rx_size - data->rx_pos);
|
||||
ptr = (unsigned char *)(dma->rx_buf);
|
||||
copied += tty_insert_flip_string(tty_port, ptr,
|
||||
data->rx_pos + state.residue - dma->rx_size);
|
||||
}
|
||||
up->port.icount.rx += copied;
|
||||
|
||||
tty_flip_buffer_push(tty_port);
|
||||
|
||||
mtk8250_rx_dma(up);
|
||||
}
|
||||
|
||||
static void mtk8250_rx_dma(struct uart_8250_port *up)
|
||||
{
|
||||
struct uart_8250_dma *dma = up->dma;
|
||||
struct mtk8250_data *data = up->port.private_data;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
struct dma_tx_state state;
|
||||
|
||||
desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr,
|
||||
dma->rx_size, DMA_DEV_TO_MEM,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (!desc) {
|
||||
pr_err("failed to prepare rx slave single\n");
|
||||
return;
|
||||
}
|
||||
|
||||
desc->callback = mtk8250_dma_rx_complete;
|
||||
desc->callback_param = up;
|
||||
|
||||
dma->rx_cookie = dmaengine_submit(desc);
|
||||
|
||||
dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
|
||||
data->rx_pos = state.residue;
|
||||
|
||||
dma_sync_single_for_device(dma->rxchan->device->dev, dma->rx_addr,
|
||||
dma->rx_size, DMA_FROM_DEVICE);
|
||||
|
||||
dma_async_issue_pending(dma->rxchan);
|
||||
}
|
||||
|
||||
static void mtk8250_dma_enable(struct uart_8250_port *up)
|
||||
{
|
||||
struct uart_8250_dma *dma = up->dma;
|
||||
struct mtk8250_data *data = up->port.private_data;
|
||||
int lcr = serial_in(up, UART_LCR);
|
||||
|
||||
if (data->rx_status != DMA_RX_START)
|
||||
return;
|
||||
|
||||
dma->rxconf.direction = DMA_DEV_TO_MEM;
|
||||
dma->rxconf.src_addr_width = dma->rx_size / 1024;
|
||||
dma->rxconf.src_addr = dma->rx_addr;
|
||||
|
||||
dma->txconf.direction = DMA_MEM_TO_DEV;
|
||||
dma->txconf.dst_addr_width = MTK_UART_TX_SIZE / 1024;
|
||||
dma->txconf.dst_addr = dma->tx_addr;
|
||||
|
||||
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR |
|
||||
UART_FCR_CLEAR_XMIT);
|
||||
serial_out(up, MTK_UART_DMA_EN,
|
||||
MTK_UART_DMA_EN_RX | MTK_UART_DMA_EN_TX);
|
||||
|
||||
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
|
||||
serial_out(up, UART_EFR, UART_EFR_ECB);
|
||||
serial_out(up, UART_LCR, lcr);
|
||||
|
||||
if (dmaengine_slave_config(dma->rxchan, &dma->rxconf) != 0)
|
||||
pr_err("failed to configure rx dma channel\n");
|
||||
if (dmaengine_slave_config(dma->txchan, &dma->txconf) != 0)
|
||||
pr_err("failed to configure tx dma channel\n");
|
||||
|
||||
data->rx_status = DMA_RX_RUNNING;
|
||||
data->rx_pos = 0;
|
||||
mtk8250_rx_dma(up);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int mtk8250_startup(struct uart_port *port)
|
||||
{
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
struct mtk8250_data *data = port->private_data;
|
||||
|
||||
/* disable DMA for console */
|
||||
if (uart_console(port))
|
||||
up->dma = NULL;
|
||||
|
||||
if (up->dma) {
|
||||
data->rx_status = DMA_RX_START;
|
||||
uart_circ_clear(&port->state->xmit);
|
||||
}
|
||||
#endif
|
||||
memset(&port->icount, 0, sizeof(port->icount));
|
||||
|
||||
return serial8250_do_startup(port);
|
||||
}
|
||||
|
||||
static void mtk8250_shutdown(struct uart_port *port)
|
||||
{
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
struct mtk8250_data *data = port->private_data;
|
||||
|
||||
if (up->dma)
|
||||
data->rx_status = DMA_RX_SHUTDOWN;
|
||||
#endif
|
||||
|
||||
return serial8250_do_shutdown(port);
|
||||
}
|
||||
|
||||
static void
|
||||
mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
@@ -36,6 +200,17 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
unsigned long flags;
|
||||
unsigned int baud, quot;
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
if (up->dma) {
|
||||
if (uart_console(port)) {
|
||||
devm_kfree(up->port.dev, up->dma);
|
||||
up->dma = NULL;
|
||||
} else {
|
||||
mtk8250_dma_enable(up);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
serial8250_do_set_termios(port, termios, old);
|
||||
|
||||
/*
|
||||
@@ -143,9 +318,20 @@ mtk8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old)
|
||||
pm_runtime_put_sync_suspend(port->dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
static bool mtk8250_dma_filter(struct dma_chan *chan, void *param)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int mtk8250_probe_of(struct platform_device *pdev, struct uart_port *p,
|
||||
struct mtk8250_data *data)
|
||||
{
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
int dmacnt;
|
||||
#endif
|
||||
|
||||
data->uart_clk = devm_clk_get(&pdev->dev, "baud");
|
||||
if (IS_ERR(data->uart_clk)) {
|
||||
/*
|
||||
@@ -162,7 +348,23 @@ static int mtk8250_probe_of(struct platform_device *pdev, struct uart_port *p,
|
||||
}
|
||||
|
||||
data->bus_clk = devm_clk_get(&pdev->dev, "bus");
|
||||
return PTR_ERR_OR_ZERO(data->bus_clk);
|
||||
if (IS_ERR(data->bus_clk))
|
||||
return PTR_ERR(data->bus_clk);
|
||||
|
||||
data->dma = NULL;
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
dmacnt = of_property_count_strings(pdev->dev.of_node, "dma-names");
|
||||
if (dmacnt == 2) {
|
||||
data->dma = devm_kzalloc(&pdev->dev, sizeof(*data->dma),
|
||||
GFP_KERNEL);
|
||||
data->dma->fn = mtk8250_dma_filter;
|
||||
data->dma->rx_size = MTK_UART_RX_SIZE;
|
||||
data->dma->rxconf.src_maxburst = MTK_UART_RX_TRIGGER;
|
||||
data->dma->txconf.dst_maxburst = MTK_UART_TX_TRIGGER;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk8250_probe(struct platform_device *pdev)
|
||||
@@ -204,8 +406,14 @@ static int mtk8250_probe(struct platform_device *pdev)
|
||||
uart.port.iotype = UPIO_MEM32;
|
||||
uart.port.regshift = 2;
|
||||
uart.port.private_data = data;
|
||||
uart.port.shutdown = mtk8250_shutdown;
|
||||
uart.port.startup = mtk8250_startup;
|
||||
uart.port.set_termios = mtk8250_set_termios;
|
||||
uart.port.uartclk = clk_get_rate(data->uart_clk);
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
if (data->dma)
|
||||
uart.dma = data->dma;
|
||||
#endif
|
||||
|
||||
/* Disable Rate Fix function */
|
||||
writel(0x0, uart.port.membase +
|
||||
|
||||
@@ -240,6 +240,11 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
|
||||
if (of_property_read_bool(ofdev->dev.of_node, "auto-flow-control"))
|
||||
port8250.capabilities |= UART_CAP_AFE;
|
||||
|
||||
if (of_property_read_u32(ofdev->dev.of_node,
|
||||
"overrun-throttle-ms",
|
||||
&port8250.overrun_backoff_time_ms) != 0)
|
||||
port8250.overrun_backoff_time_ms = 0;
|
||||
|
||||
ret = serial8250_register_8250_port(&port8250);
|
||||
if (ret < 0)
|
||||
goto err_dispose;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user