1
0
Fork 0

TTY/Serial driver patches for 4.21-rc1

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.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iGwEABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCXCY+1w8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+yl9PgCXckFuSe66uNMzdq2jsVgLKtMR+ACbBzrLQeMZ
 LU8UpaVqDJrrPxVURGY=
 =a/Xk
 -----END PGP SIGNATURE-----

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
  ...
hifive-unleashed-5.1
Linus Torvalds 2018-12-28 20:33:54 -08:00
commit 117eda8f71
55 changed files with 3040 additions and 314 deletions

View 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>;
};

View File

@ -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:

View File

@ -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

View File

@ -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>;

View File

@ -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.

View File

@ -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

View File

@ -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;
}
}

View File

@ -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? */

View File

@ -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? */

View File

@ -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;
}

View File

@ -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)

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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 +

View File

@ -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;

View File

@ -8,6 +8,10 @@
*
*/
#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
#include <linux/device.h>
#include <linux/io.h>
#include <linux/module.h>
@ -1085,7 +1089,7 @@ static int omap_8250_dma_handle_irq(struct uart_port *port)
}
}
spin_unlock_irqrestore(&port->lock, flags);
uart_unlock_and_check_sysrq(port, flags);
serial8250_rpm_put(up);
return 1;
}

View File

@ -1736,7 +1736,7 @@ void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr)
else if (lsr & UART_LSR_FE)
flag = TTY_FRAME;
}
if (uart_handle_sysrq_char(port, ch))
if (uart_prepare_sysrq_char(port, ch))
return;
uart_insert_char(port, lsr, UART_LSR_OE, ch, flag);
@ -1878,7 +1878,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
if ((!up->dma || up->dma->tx_err) && (status & UART_LSR_THRE))
serial8250_tx_chars(up);
spin_unlock_irqrestore(&port->lock, flags);
uart_unlock_and_check_sysrq(port, flags);
return 1;
}
EXPORT_SYMBOL_GPL(serial8250_handle_irq);
@ -3239,9 +3239,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
serial8250_rpm_get(up);
if (port->sysrq)
locked = 0;
else if (oops_in_progress)
if (oops_in_progress)
locked = spin_trylock_irqsave(&port->lock, flags);
else
spin_lock_irqsave(&port->lock, flags);

View File

@ -2780,6 +2780,7 @@ static struct platform_driver arm_sbsa_uart_platform_driver = {
.name = "sbsa-uart",
.of_match_table = of_match_ptr(sbsa_uart_of_match),
.acpi_match_table = ACPI_PTR(sbsa_uart_acpi_match),
.suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_AMBA_PL011),
},
};
@ -2808,6 +2809,7 @@ static struct amba_driver pl011_driver = {
.drv = {
.name = "uart-pl011",
.pm = &pl011_dev_pm_ops,
.suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_AMBA_PL011),
},
.id_table = pl011_ids,
.probe = pl011_probe,

View File

@ -1479,6 +1479,8 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
else
cr1 &= ~UARTCR1_PT;
}
} else {
cr1 &= ~UARTCR1_PE;
}
/* ask the core to calculate the divisor */
@ -1682,7 +1684,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
ctrl &= ~UARTCTRL_PE;
ctrl |= UARTCTRL_M;
} else {
ctrl |= UARTCR1_PE;
ctrl |= UARTCTRL_PE;
if ((termios->c_cflag & CSIZE) == CS8)
ctrl |= UARTCTRL_M;
if (termios->c_cflag & PARODD)
@ -1690,6 +1692,8 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
else
ctrl &= ~UARTCTRL_PT;
}
} else {
ctrl &= ~UARTCTRL_PE;
}
/* ask the core to calculate the divisor */

View File

@ -2064,7 +2064,7 @@ imx_uart_console_setup(struct console *co, char *options)
retval = clk_prepare(sport->clk_per);
if (retval)
clk_disable_unprepare(sport->clk_ipg);
clk_unprepare(sport->clk_ipg);
error_console:
return retval;

View File

@ -8,24 +8,23 @@
* Copyright (C) 2010 Thomas Langer, <thomas.langer@lantiq.com>
*/
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/clk.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <linux/of_platform.h>
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/lantiq.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/gpio.h>
#include <lantiq_soc.h>
#include <linux/of_platform.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/slab.h>
#include <linux/sysrq.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#define PORT_LTQ_ASC 111
#define MAXPORTS 2
@ -105,7 +104,7 @@ static DEFINE_SPINLOCK(ltq_asc_lock);
struct ltq_uart_port {
struct uart_port port;
/* clock used to derive divider */
struct clk *fpiclk;
struct clk *freqclk;
/* clock gating of the ASC core */
struct clk *clk;
unsigned int tx_irq;
@ -113,6 +112,13 @@ struct ltq_uart_port {
unsigned int err_irq;
};
static inline void asc_update_bits(u32 clear, u32 set, void __iomem *reg)
{
u32 tmp = readl(reg);
writel((tmp & ~clear) | set, reg);
}
static inline struct
ltq_uart_port *to_ltq_uart_port(struct uart_port *port)
{
@ -138,7 +144,7 @@ lqasc_start_tx(struct uart_port *port)
static void
lqasc_stop_rx(struct uart_port *port)
{
ltq_w32(ASCWHBSTATE_CLRREN, port->membase + LTQ_ASC_WHBSTATE);
writel(ASCWHBSTATE_CLRREN, port->membase + LTQ_ASC_WHBSTATE);
}
static int
@ -147,11 +153,11 @@ lqasc_rx_chars(struct uart_port *port)
struct tty_port *tport = &port->state->port;
unsigned int ch = 0, rsr = 0, fifocnt;
fifocnt = ltq_r32(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_RXFFLMASK;
fifocnt = readl(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_RXFFLMASK;
while (fifocnt--) {
u8 flag = TTY_NORMAL;
ch = ltq_r8(port->membase + LTQ_ASC_RBUF);
rsr = (ltq_r32(port->membase + LTQ_ASC_STATE)
ch = readb(port->membase + LTQ_ASC_RBUF);
rsr = (readl(port->membase + LTQ_ASC_STATE)
& ASCSTATE_ANY) | UART_DUMMY_UER_RX;
tty_flip_buffer_push(tport);
port->icount.rx++;
@ -163,16 +169,16 @@ lqasc_rx_chars(struct uart_port *port)
if (rsr & ASCSTATE_ANY) {
if (rsr & ASCSTATE_PE) {
port->icount.parity++;
ltq_w32_mask(0, ASCWHBSTATE_CLRPE,
asc_update_bits(0, ASCWHBSTATE_CLRPE,
port->membase + LTQ_ASC_WHBSTATE);
} else if (rsr & ASCSTATE_FE) {
port->icount.frame++;
ltq_w32_mask(0, ASCWHBSTATE_CLRFE,
asc_update_bits(0, ASCWHBSTATE_CLRFE,
port->membase + LTQ_ASC_WHBSTATE);
}
if (rsr & ASCSTATE_ROE) {
port->icount.overrun++;
ltq_w32_mask(0, ASCWHBSTATE_CLRROE,
asc_update_bits(0, ASCWHBSTATE_CLRROE,
port->membase + LTQ_ASC_WHBSTATE);
}
@ -211,10 +217,10 @@ lqasc_tx_chars(struct uart_port *port)
return;
}
while (((ltq_r32(port->membase + LTQ_ASC_FSTAT) &
while (((readl(port->membase + LTQ_ASC_FSTAT) &
ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF) != 0) {
if (port->x_char) {
ltq_w8(port->x_char, port->membase + LTQ_ASC_TBUF);
writeb(port->x_char, port->membase + LTQ_ASC_TBUF);
port->icount.tx++;
port->x_char = 0;
continue;
@ -223,7 +229,7 @@ lqasc_tx_chars(struct uart_port *port)
if (uart_circ_empty(xmit))
break;
ltq_w8(port->state->xmit.buf[port->state->xmit.tail],
writeb(port->state->xmit.buf[port->state->xmit.tail],
port->membase + LTQ_ASC_TBUF);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
@ -239,7 +245,7 @@ lqasc_tx_int(int irq, void *_port)
unsigned long flags;
struct uart_port *port = (struct uart_port *)_port;
spin_lock_irqsave(&ltq_asc_lock, flags);
ltq_w32(ASC_IRNCR_TIR, port->membase + LTQ_ASC_IRNCR);
writel(ASC_IRNCR_TIR, port->membase + LTQ_ASC_IRNCR);
spin_unlock_irqrestore(&ltq_asc_lock, flags);
lqasc_start_tx(port);
return IRQ_HANDLED;
@ -252,7 +258,7 @@ lqasc_err_int(int irq, void *_port)
struct uart_port *port = (struct uart_port *)_port;
spin_lock_irqsave(&ltq_asc_lock, flags);
/* clear any pending interrupts */
ltq_w32_mask(0, ASCWHBSTATE_CLRPE | ASCWHBSTATE_CLRFE |
asc_update_bits(0, ASCWHBSTATE_CLRPE | ASCWHBSTATE_CLRFE |
ASCWHBSTATE_CLRROE, port->membase + LTQ_ASC_WHBSTATE);
spin_unlock_irqrestore(&ltq_asc_lock, flags);
return IRQ_HANDLED;
@ -264,7 +270,7 @@ lqasc_rx_int(int irq, void *_port)
unsigned long flags;
struct uart_port *port = (struct uart_port *)_port;
spin_lock_irqsave(&ltq_asc_lock, flags);
ltq_w32(ASC_IRNCR_RIR, port->membase + LTQ_ASC_IRNCR);
writel(ASC_IRNCR_RIR, port->membase + LTQ_ASC_IRNCR);
lqasc_rx_chars(port);
spin_unlock_irqrestore(&ltq_asc_lock, flags);
return IRQ_HANDLED;
@ -274,7 +280,7 @@ static unsigned int
lqasc_tx_empty(struct uart_port *port)
{
int status;
status = ltq_r32(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_TXFFLMASK;
status = readl(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_TXFFLMASK;
return status ? 0 : TIOCSER_TEMT;
}
@ -301,18 +307,18 @@ lqasc_startup(struct uart_port *port)
int retval;
if (!IS_ERR(ltq_port->clk))
clk_enable(ltq_port->clk);
port->uartclk = clk_get_rate(ltq_port->fpiclk);
clk_prepare_enable(ltq_port->clk);
port->uartclk = clk_get_rate(ltq_port->freqclk);
ltq_w32_mask(ASCCLC_DISS | ASCCLC_RMCMASK, (1 << ASCCLC_RMCOFFSET),
asc_update_bits(ASCCLC_DISS | ASCCLC_RMCMASK, (1 << ASCCLC_RMCOFFSET),
port->membase + LTQ_ASC_CLC);
ltq_w32(0, port->membase + LTQ_ASC_PISEL);
ltq_w32(
writel(0, port->membase + LTQ_ASC_PISEL);
writel(
((TXFIFO_FL << ASCTXFCON_TXFITLOFF) & ASCTXFCON_TXFITLMASK) |
ASCTXFCON_TXFEN | ASCTXFCON_TXFFLU,
port->membase + LTQ_ASC_TXFCON);
ltq_w32(
writel(
((RXFIFO_FL << ASCRXFCON_RXFITLOFF) & ASCRXFCON_RXFITLMASK)
| ASCRXFCON_RXFEN | ASCRXFCON_RXFFLU,
port->membase + LTQ_ASC_RXFCON);
@ -320,7 +326,7 @@ lqasc_startup(struct uart_port *port)
* setting enable bits
*/
wmb();
ltq_w32_mask(0, ASCCON_M_8ASYNC | ASCCON_FEN | ASCCON_TOEN |
asc_update_bits(0, ASCCON_M_8ASYNC | ASCCON_FEN | ASCCON_TOEN |
ASCCON_ROEN, port->membase + LTQ_ASC_CON);
retval = request_irq(ltq_port->tx_irq, lqasc_tx_int,
@ -344,7 +350,7 @@ lqasc_startup(struct uart_port *port)
goto err2;
}
ltq_w32(ASC_IRNREN_RX | ASC_IRNREN_ERR | ASC_IRNREN_TX,
writel(ASC_IRNREN_RX | ASC_IRNREN_ERR | ASC_IRNREN_TX,
port->membase + LTQ_ASC_IRNREN);
return 0;
@ -363,13 +369,13 @@ lqasc_shutdown(struct uart_port *port)
free_irq(ltq_port->rx_irq, port);
free_irq(ltq_port->err_irq, port);
ltq_w32(0, port->membase + LTQ_ASC_CON);
ltq_w32_mask(ASCRXFCON_RXFEN, ASCRXFCON_RXFFLU,
writel(0, port->membase + LTQ_ASC_CON);
asc_update_bits(ASCRXFCON_RXFEN, ASCRXFCON_RXFFLU,
port->membase + LTQ_ASC_RXFCON);
ltq_w32_mask(ASCTXFCON_TXFEN, ASCTXFCON_TXFFLU,
asc_update_bits(ASCTXFCON_TXFEN, ASCTXFCON_TXFFLU,
port->membase + LTQ_ASC_TXFCON);
if (!IS_ERR(ltq_port->clk))
clk_disable(ltq_port->clk);
clk_disable_unprepare(ltq_port->clk);
}
static void
@ -438,7 +444,7 @@ lqasc_set_termios(struct uart_port *port,
spin_lock_irqsave(&ltq_asc_lock, flags);
/* set up CON */
ltq_w32_mask(0, con, port->membase + LTQ_ASC_CON);
asc_update_bits(0, con, port->membase + LTQ_ASC_CON);
/* Set baud rate - take a divider of 2 into account */
baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16);
@ -446,22 +452,22 @@ lqasc_set_termios(struct uart_port *port,
divisor = divisor / 2 - 1;
/* disable the baudrate generator */
ltq_w32_mask(ASCCON_R, 0, port->membase + LTQ_ASC_CON);
asc_update_bits(ASCCON_R, 0, port->membase + LTQ_ASC_CON);
/* make sure the fractional divider is off */
ltq_w32_mask(ASCCON_FDE, 0, port->membase + LTQ_ASC_CON);
asc_update_bits(ASCCON_FDE, 0, port->membase + LTQ_ASC_CON);
/* set up to use divisor of 2 */
ltq_w32_mask(ASCCON_BRS, 0, port->membase + LTQ_ASC_CON);
asc_update_bits(ASCCON_BRS, 0, port->membase + LTQ_ASC_CON);
/* now we can write the new baudrate into the register */
ltq_w32(divisor, port->membase + LTQ_ASC_BG);
writel(divisor, port->membase + LTQ_ASC_BG);
/* turn the baudrate generator back on */
ltq_w32_mask(0, ASCCON_R, port->membase + LTQ_ASC_CON);
asc_update_bits(0, ASCCON_R, port->membase + LTQ_ASC_CON);
/* enable rx */
ltq_w32(ASCWHBSTATE_SETREN, port->membase + LTQ_ASC_WHBSTATE);
writel(ASCWHBSTATE_SETREN, port->membase + LTQ_ASC_WHBSTATE);
spin_unlock_irqrestore(&ltq_asc_lock, flags);
@ -572,10 +578,10 @@ lqasc_console_putchar(struct uart_port *port, int ch)
return;
do {
fifofree = (ltq_r32(port->membase + LTQ_ASC_FSTAT)
fifofree = (readl(port->membase + LTQ_ASC_FSTAT)
& ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF;
} while (fifofree == 0);
ltq_w8(ch, port->membase + LTQ_ASC_TBUF);
writeb(ch, port->membase + LTQ_ASC_TBUF);
}
static void lqasc_serial_port_write(struct uart_port *port, const char *s,
@ -623,9 +629,9 @@ lqasc_console_setup(struct console *co, char *options)
port = &ltq_port->port;
if (!IS_ERR(ltq_port->clk))
clk_enable(ltq_port->clk);
clk_prepare_enable(ltq_port->clk);
port->uartclk = clk_get_rate(ltq_port->fpiclk);
port->uartclk = clk_get_rate(ltq_port->freqclk);
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
@ -688,7 +694,7 @@ lqasc_probe(struct platform_device *pdev)
struct ltq_uart_port *ltq_port;
struct uart_port *port;
struct resource *mmres, irqres[3];
int line = 0;
int line;
int ret;
mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@ -699,9 +705,20 @@ lqasc_probe(struct platform_device *pdev)
return -ENODEV;
}
/* check if this is the console port */
if (mmres->start != CPHYSADDR(LTQ_EARLY_ASC))
line = 1;
/* get serial id */
line = of_alias_get_id(node, "serial");
if (line < 0) {
if (IS_ENABLED(CONFIG_LANTIQ)) {
if (mmres->start == CPHYSADDR(LTQ_EARLY_ASC))
line = 0;
else
line = 1;
} else {
dev_err(&pdev->dev, "failed to get alias id, errno %d\n",
line);
return line;
}
}
if (lqasc_port[line]) {
dev_err(&pdev->dev, "port %d already allocated\n", line);
@ -726,14 +743,22 @@ lqasc_probe(struct platform_device *pdev)
port->irq = irqres[0].start;
port->mapbase = mmres->start;
ltq_port->fpiclk = clk_get_fpi();
if (IS_ERR(ltq_port->fpiclk)) {
if (IS_ENABLED(CONFIG_LANTIQ) && !IS_ENABLED(CONFIG_COMMON_CLK))
ltq_port->freqclk = clk_get_fpi();
else
ltq_port->freqclk = devm_clk_get(&pdev->dev, "freq");
if (IS_ERR(ltq_port->freqclk)) {
pr_err("failed to get fpi clk\n");
return -ENOENT;
}
/* not all asc ports have clock gates, lets ignore the return code */
ltq_port->clk = clk_get(&pdev->dev, NULL);
if (IS_ENABLED(CONFIG_LANTIQ) && !IS_ENABLED(CONFIG_COMMON_CLK))
ltq_port->clk = clk_get(&pdev->dev, NULL);
else
ltq_port->clk = devm_clk_get(&pdev->dev, "asc");
ltq_port->tx_irq = irqres[0].start;
ltq_port->rx_irq = irqres[1].start;
@ -759,7 +784,7 @@ static struct platform_driver lqasc_driver = {
},
};
int __init
static int __init
init_lqasc(void)
{
int ret;

View File

@ -833,12 +833,9 @@ static void max310x_wq_proc(struct work_struct *ws)
static unsigned int max310x_tx_empty(struct uart_port *port)
{
unsigned int lvl, sts;
u8 lvl = max310x_port_read(port, MAX310X_TXFIFOLVL_REG);
lvl = max310x_port_read(port, MAX310X_TXFIFOLVL_REG);
sts = max310x_port_read(port, MAX310X_IRQSTS_REG);
return ((sts & MAX310X_IRQ_TXEMPTY_BIT) && !lvl) ? TIOCSER_TEMT : 0;
return lvl ? 0 : TIOCSER_TEMT;
}
static unsigned int max310x_get_mctrl(struct uart_port *port)

View File

@ -72,6 +72,8 @@
#define BRDV_BAUD_MASK 0x3FF
#define UART_OSAMP 0x14
#define OSAMP_DEFAULT_DIVISOR 16
#define OSAMP_DIVISORS_MASK 0x3F3F3F3F
#define MVEBU_NR_UARTS 2
@ -444,25 +446,34 @@ static void mvebu_uart_shutdown(struct uart_port *port)
static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
{
struct mvebu_uart *mvuart = to_mvuart(port);
unsigned int baud_rate_div;
u32 brdv;
unsigned int d_divisor, m_divisor;
u32 brdv, osamp;
if (IS_ERR(mvuart->clk))
return -PTR_ERR(mvuart->clk);
/*
* The UART clock is divided by the value of the divisor to generate
* UCLK_OUT clock, which is 16 times faster than the baudrate.
* This prescaler can achieve all standard baudrates until 230400.
* Higher baudrates could be achieved for the extended UART by using the
* programmable oversampling stack (also called fractional divisor).
* The baudrate is derived from the UART clock thanks to two divisors:
* > D ("baud generator"): can divide the clock from 2 to 2^10 - 1.
* > M ("fractional divisor"): allows a better accuracy for
* baudrates higher than 230400.
*
* As the derivation of M is rather complicated, the code sticks to its
* default value (x16) when all the prescalers are zeroed, and only
* makes use of D to configure the desired baudrate.
*/
baud_rate_div = DIV_ROUND_UP(port->uartclk, baud * 16);
m_divisor = OSAMP_DEFAULT_DIVISOR;
d_divisor = DIV_ROUND_UP(port->uartclk, baud * m_divisor);
brdv = readl(port->membase + UART_BRDV);
brdv &= ~BRDV_BAUD_MASK;
brdv |= baud_rate_div;
brdv |= d_divisor;
writel(brdv, port->membase + UART_BRDV);
osamp = readl(port->membase + UART_OSAMP);
osamp &= ~OSAMP_DIVISORS_MASK;
writel(osamp, port->membase + UART_OSAMP);
return 0;
}

View File

@ -933,7 +933,6 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
struct scatterlist *sg;
int nent;
int fifo_size;
int tx_empty;
struct dma_async_tx_descriptor *desc;
int num;
int i;
@ -958,11 +957,9 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
}
fifo_size = max(priv->fifo_size, 1);
tx_empty = 1;
if (pop_tx_x(priv, xmit->buf)) {
pch_uart_hal_write(priv, xmit->buf, 1);
port->icount.tx++;
tx_empty = 0;
fifo_size--;
}

View File

@ -919,6 +919,7 @@ static struct platform_driver pic32_uart_platform_driver = {
.driver = {
.name = PIC32_DEV_NAME,
.of_match_table = of_match_ptr(pic32_serial_dt_ids),
.suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_PIC32),
},
};

View File

@ -1648,9 +1648,9 @@ static int __init pmz_probe(void)
*/
node_a = node_b = NULL;
for (np = NULL; (np = of_get_next_child(node_p, np)) != NULL;) {
if (strncmp(np->name, "ch-a", 4) == 0)
if (of_node_name_prefix(np, "ch-a"))
node_a = of_node_get(np);
else if (strncmp(np->name, "ch-b", 4) == 0)
else if (of_node_name_prefix(np, "ch-b"))
node_b = of_node_get(np);
}
if (!node_a && !node_b) {

View File

@ -1,6 +1,10 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2017-2018, The Linux foundation. All rights reserved.
#if defined(CONFIG_SERIAL_QCOM_GENI_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
# define SUPPORT_SYSRQ
#endif
#include <linux/clk.h>
#include <linux/console.h>
#include <linux/io.h>
@ -89,9 +93,9 @@
#define MAX_LOOPBACK_CFG 3
#ifdef CONFIG_CONSOLE_POLL
#define RX_BYTES_PW 1
#define CONSOLE_RX_BYTES_PW 1
#else
#define RX_BYTES_PW 4
#define CONSOLE_RX_BYTES_PW 4
#endif
struct qcom_geni_serial_port {
@ -113,6 +117,8 @@ struct qcom_geni_serial_port {
u32 *rx_fifo;
u32 loopback;
bool brk;
unsigned int tx_remaining;
};
static const struct uart_ops qcom_geni_console_pops;
@ -162,8 +168,7 @@ static struct qcom_geni_serial_port qcom_geni_uart_ports[GENI_UART_PORTS] = {
static ssize_t loopback_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct platform_device *pdev = to_platform_device(dev);
struct qcom_geni_serial_port *port = platform_get_drvdata(pdev);
struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
return snprintf(buf, sizeof(u32), "%d\n", port->loopback);
}
@ -172,8 +177,7 @@ static ssize_t loopback_store(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t size)
{
struct platform_device *pdev = to_platform_device(dev);
struct qcom_geni_serial_port *port = platform_get_drvdata(pdev);
struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
u32 loopback;
if (kstrtoint(buf, 0, &loopback) || loopback > MAX_LOOPBACK_CFG) {
@ -435,6 +439,8 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s,
struct qcom_geni_serial_port *port;
bool locked = true;
unsigned long flags;
u32 geni_status;
u32 irq_en;
WARN_ON(co->index < 0 || co->index >= GENI_UART_CONS_PORTS);
@ -448,6 +454,8 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s,
else
spin_lock_irqsave(&uport->lock, flags);
geni_status = readl_relaxed(uport->membase + SE_GENI_STATUS);
/* Cancel the current write to log the fault */
if (!locked) {
geni_se_cancel_m_cmd(&port->se);
@ -461,9 +469,26 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s,
}
writel_relaxed(M_CMD_CANCEL_EN, uport->membase +
SE_GENI_M_IRQ_CLEAR);
} else if ((geni_status & M_GENI_CMD_ACTIVE) && !port->tx_remaining) {
/*
* It seems we can't interrupt existing transfers if all data
* has been sent, in which case we need to look for done first.
*/
qcom_geni_serial_poll_tx_done(uport);
if (uart_circ_chars_pending(&uport->state->xmit)) {
irq_en = readl_relaxed(uport->membase +
SE_GENI_M_IRQ_EN);
writel_relaxed(irq_en | M_TX_FIFO_WATERMARK_EN,
uport->membase + SE_GENI_M_IRQ_EN);
}
}
__qcom_geni_serial_console_write(uport, s, count);
if (port->tx_remaining)
qcom_geni_serial_setup_tx(uport, port->tx_remaining);
if (locked)
spin_unlock_irqrestore(&uport->lock, flags);
}
@ -495,7 +520,8 @@ static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop)
continue;
}
sysrq = uart_handle_sysrq_char(uport, buf[c]);
sysrq = uart_prepare_sysrq_char(uport, buf[c]);
if (!sysrq)
tty_insert_flip_char(tport, buf[c], TTY_NORMAL);
}
@ -694,40 +720,51 @@ static void qcom_geni_serial_handle_rx(struct uart_port *uport, bool drop)
port->handle_rx(uport, total_bytes, drop);
}
static void qcom_geni_serial_handle_tx(struct uart_port *uport)
static void qcom_geni_serial_handle_tx(struct uart_port *uport, bool done,
bool active)
{
struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
struct circ_buf *xmit = &uport->state->xmit;
size_t avail;
size_t remaining;
size_t pending;
int i;
u32 status;
u32 irq_en;
unsigned int chunk;
int tail;
u32 irq_en;
chunk = uart_circ_chars_pending(xmit);
status = readl_relaxed(uport->membase + SE_GENI_TX_FIFO_STATUS);
/* Both FIFO and framework buffer are drained */
if (!chunk && !status) {
/* Complete the current tx command before taking newly added data */
if (active)
pending = port->tx_remaining;
else
pending = uart_circ_chars_pending(xmit);
/* All data has been transmitted and acknowledged as received */
if (!pending && !status && done) {
qcom_geni_serial_stop_tx(uport);
goto out_write_wakeup;
}
if (!uart_console(uport)) {
irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN);
irq_en &= ~(M_TX_FIFO_WATERMARK_EN);
writel_relaxed(0, uport->membase + SE_GENI_TX_WATERMARK_REG);
writel_relaxed(irq_en, uport->membase + SE_GENI_M_IRQ_EN);
}
avail = port->tx_fifo_depth - (status & TX_FIFO_WC);
avail *= port->tx_bytes_pw;
avail = (port->tx_fifo_depth - port->tx_wm) * port->tx_bytes_pw;
tail = xmit->tail;
chunk = min3((size_t)chunk, (size_t)(UART_XMIT_SIZE - tail), avail);
chunk = min(avail, pending);
if (!chunk)
goto out_write_wakeup;
qcom_geni_serial_setup_tx(uport, chunk);
if (!port->tx_remaining) {
qcom_geni_serial_setup_tx(uport, pending);
port->tx_remaining = pending;
irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN);
if (!(irq_en & M_TX_FIFO_WATERMARK_EN))
writel_relaxed(irq_en | M_TX_FIFO_WATERMARK_EN,
uport->membase + SE_GENI_M_IRQ_EN);
}
remaining = chunk;
for (i = 0; i < chunk; ) {
@ -737,21 +774,38 @@ static void qcom_geni_serial_handle_tx(struct uart_port *uport)
memset(buf, 0, ARRAY_SIZE(buf));
tx_bytes = min_t(size_t, remaining, port->tx_bytes_pw);
for (c = 0; c < tx_bytes ; c++)
buf[c] = xmit->buf[tail + c];
for (c = 0; c < tx_bytes ; c++) {
buf[c] = xmit->buf[tail++];
tail &= UART_XMIT_SIZE - 1;
}
iowrite32_rep(uport->membase + SE_GENI_TX_FIFOn, buf, 1);
i += tx_bytes;
tail += tx_bytes;
uport->icount.tx += tx_bytes;
remaining -= tx_bytes;
port->tx_remaining -= tx_bytes;
}
xmit->tail = tail & (UART_XMIT_SIZE - 1);
if (uart_console(uport))
qcom_geni_serial_poll_tx_done(uport);
xmit->tail = tail;
/*
* The tx fifo watermark is level triggered and latched. Though we had
* cleared it in qcom_geni_serial_isr it will have already reasserted
* so we must clear it again here after our writes.
*/
writel_relaxed(M_TX_FIFO_WATERMARK_EN,
uport->membase + SE_GENI_M_IRQ_CLEAR);
out_write_wakeup:
if (!port->tx_remaining) {
irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN);
if (irq_en & M_TX_FIFO_WATERMARK_EN)
writel_relaxed(irq_en & ~M_TX_FIFO_WATERMARK_EN,
uport->membase + SE_GENI_M_IRQ_EN);
}
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(uport);
}
@ -760,6 +814,7 @@ static irqreturn_t qcom_geni_serial_isr(int isr, void *dev)
{
unsigned int m_irq_status;
unsigned int s_irq_status;
unsigned int geni_status;
struct uart_port *uport = dev;
unsigned long flags;
unsigned int m_irq_en;
@ -773,6 +828,7 @@ static irqreturn_t qcom_geni_serial_isr(int isr, void *dev)
spin_lock_irqsave(&uport->lock, flags);
m_irq_status = readl_relaxed(uport->membase + SE_GENI_M_IRQ_STATUS);
s_irq_status = readl_relaxed(uport->membase + SE_GENI_S_IRQ_STATUS);
geni_status = readl_relaxed(uport->membase + SE_GENI_STATUS);
m_irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN);
writel_relaxed(m_irq_status, uport->membase + SE_GENI_M_IRQ_CLEAR);
writel_relaxed(s_irq_status, uport->membase + SE_GENI_S_IRQ_CLEAR);
@ -785,9 +841,9 @@ static irqreturn_t qcom_geni_serial_isr(int isr, void *dev)
tty_insert_flip_char(tport, 0, TTY_OVERRUN);
}
if (m_irq_status & (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN) &&
m_irq_en & (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN))
qcom_geni_serial_handle_tx(uport);
if (m_irq_status & m_irq_en & (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN))
qcom_geni_serial_handle_tx(uport, m_irq_status & M_CMD_DONE_EN,
geni_status & M_GENI_CMD_ACTIVE);
if (s_irq_status & S_GP_IRQ_0_EN || s_irq_status & S_GP_IRQ_1_EN) {
if (s_irq_status & S_GP_IRQ_0_EN)
@ -804,7 +860,8 @@ static irqreturn_t qcom_geni_serial_isr(int isr, void *dev)
qcom_geni_serial_handle_rx(uport, drop_rx);
out_unlock:
spin_unlock_irqrestore(&uport->lock, flags);
uart_unlock_and_check_sysrq(uport, flags);
return IRQ_HANDLED;
}
@ -853,11 +910,13 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport)
unsigned int rxstale = DEFAULT_BITS_PER_CHAR * STALE_TIMEOUT;
u32 proto;
if (uart_console(uport))
if (uart_console(uport)) {
port->tx_bytes_pw = 1;
else
port->rx_bytes_pw = CONSOLE_RX_BYTES_PW;
} else {
port->tx_bytes_pw = 4;
port->rx_bytes_pw = RX_BYTES_PW;
port->rx_bytes_pw = 4;
}
proto = geni_se_read_proto(&port->se);
if (proto != GENI_SE_UART) {
@ -1322,49 +1381,25 @@ static int qcom_geni_serial_remove(struct platform_device *pdev)
return 0;
}
static int __maybe_unused qcom_geni_serial_sys_suspend_noirq(struct device *dev)
static int __maybe_unused qcom_geni_serial_sys_suspend(struct device *dev)
{
struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
struct uart_port *uport = &port->uport;
if (uart_console(uport)) {
uart_suspend_port(uport->private_data, uport);
} else {
struct uart_state *state = uport->state;
/*
* If the port is open, deny system suspend.
*/
if (state->pm_state == UART_PM_STATE_ON)
return -EBUSY;
}
return 0;
return uart_suspend_port(uport->private_data, uport);
}
static int __maybe_unused qcom_geni_serial_sys_resume_noirq(struct device *dev)
static int __maybe_unused qcom_geni_serial_sys_resume(struct device *dev)
{
struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
struct uart_port *uport = &port->uport;
if (uart_console(uport) &&
console_suspend_enabled && uport->suspended) {
uart_resume_port(uport->private_data, uport);
/*
* uart_suspend_port() invokes port shutdown which in turn
* frees the irq. uart_resume_port invokes port startup which
* performs request_irq. The request_irq auto-enables the IRQ.
* In addition, resume_noirq implicitly enables the IRQ and
* leads to an unbalanced IRQ enable warning. Disable the IRQ
* before returning so that the warning is suppressed.
*/
disable_irq(uport->irq);
}
return 0;
return uart_resume_port(uport->private_data, uport);
}
static const struct dev_pm_ops qcom_geni_serial_pm_ops = {
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(qcom_geni_serial_sys_suspend_noirq,
qcom_geni_serial_sys_resume_noirq)
SET_SYSTEM_SLEEP_PM_OPS(qcom_geni_serial_sys_suspend,
qcom_geni_serial_sys_resume)
};
static const struct of_device_id qcom_geni_serial_match_table[] = {

View File

@ -1287,7 +1287,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
* Ask the core to calculate the divisor for us.
*/
baud = uart_get_baud_rate(port, termios, old, 0, 115200*8);
baud = uart_get_baud_rate(port, termios, old, 0, 3000000);
quot = s3c24xx_serial_getclk(ourport, baud, &clk, &clk_sel);
if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
quot = port->custom_divisor;
@ -1365,11 +1365,14 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
wr_regl(port, S3C2410_ULCON, ulcon);
wr_regl(port, S3C2410_UBRDIV, quot);
port->status &= ~UPSTAT_AUTOCTS;
umcon = rd_regl(port, S3C2410_UMCON);
if (termios->c_cflag & CRTSCTS) {
umcon |= S3C2410_UMCOM_AFC;
/* Disable RTS when RX FIFO contains 63 bytes */
umcon &= ~S3C2412_UMCON_AFC_8;
port->status = UPSTAT_AUTOCTS;
} else {
umcon &= ~S3C2410_UMCOM_AFC;
}

View File

@ -12,6 +12,7 @@
#endif
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
@ -47,7 +48,6 @@
# define MR2_STOP1 (7 << 0)
# define MR2_STOP2 (0xf << 0)
#define SCCNXP_SR_REG (0x01)
#define SCCNXP_CSR_REG SCCNXP_SR_REG
# define SR_RXRDY (1 << 0)
# define SR_FULL (1 << 1)
# define SR_TXRDY (1 << 2)
@ -56,6 +56,8 @@
# define SR_PE (1 << 5)
# define SR_FE (1 << 6)
# define SR_BRK (1 << 7)
#define SCCNXP_CSR_REG (SCCNXP_SR_REG)
# define CSR_TIMER_MODE (0x0d)
#define SCCNXP_CR_REG (0x02)
# define CR_RX_ENABLE (1 << 0)
# define CR_RX_DISABLE (1 << 1)
@ -82,9 +84,12 @@
# define IMR_RXRDY (1 << 1)
# define ISR_TXRDY(x) (1 << ((x * 4) + 0))
# define ISR_RXRDY(x) (1 << ((x * 4) + 1))
#define SCCNXP_CTPU_REG (0x06)
#define SCCNXP_CTPL_REG (0x07)
#define SCCNXP_IPR_REG (0x0d)
#define SCCNXP_OPCR_REG SCCNXP_IPR_REG
#define SCCNXP_SOP_REG (0x0e)
#define SCCNXP_START_COUNTER_REG SCCNXP_SOP_REG
#define SCCNXP_ROP_REG (0x0f)
/* Route helpers */
@ -103,6 +108,8 @@ struct sccnxp_chip {
unsigned long freq_max;
unsigned int flags;
unsigned int fifosize;
/* Time between read/write cycles */
unsigned int trwd;
};
struct sccnxp_port {
@ -137,6 +144,7 @@ static const struct sccnxp_chip sc2681 = {
.freq_max = 4000000,
.flags = SCCNXP_HAVE_IO,
.fifosize = 3,
.trwd = 200,
};
static const struct sccnxp_chip sc2691 = {
@ -147,6 +155,7 @@ static const struct sccnxp_chip sc2691 = {
.freq_max = 4000000,
.flags = 0,
.fifosize = 3,
.trwd = 150,
};
static const struct sccnxp_chip sc2692 = {
@ -157,6 +166,7 @@ static const struct sccnxp_chip sc2692 = {
.freq_max = 4000000,
.flags = SCCNXP_HAVE_IO,
.fifosize = 3,
.trwd = 30,
};
static const struct sccnxp_chip sc2891 = {
@ -167,6 +177,7 @@ static const struct sccnxp_chip sc2891 = {
.freq_max = 8000000,
.flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0,
.fifosize = 16,
.trwd = 27,
};
static const struct sccnxp_chip sc2892 = {
@ -177,6 +188,7 @@ static const struct sccnxp_chip sc2892 = {
.freq_max = 8000000,
.flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0,
.fifosize = 16,
.trwd = 17,
};
static const struct sccnxp_chip sc28202 = {
@ -187,6 +199,7 @@ static const struct sccnxp_chip sc28202 = {
.freq_max = 50000000,
.flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0,
.fifosize = 256,
.trwd = 10,
};
static const struct sccnxp_chip sc68681 = {
@ -197,6 +210,7 @@ static const struct sccnxp_chip sc68681 = {
.freq_max = 4000000,
.flags = SCCNXP_HAVE_IO,
.fifosize = 3,
.trwd = 200,
};
static const struct sccnxp_chip sc68692 = {
@ -207,24 +221,36 @@ static const struct sccnxp_chip sc68692 = {
.freq_max = 4000000,
.flags = SCCNXP_HAVE_IO,
.fifosize = 3,
.trwd = 200,
};
static inline u8 sccnxp_read(struct uart_port *port, u8 reg)
static u8 sccnxp_read(struct uart_port *port, u8 reg)
{
return readb(port->membase + (reg << port->regshift));
struct sccnxp_port *s = dev_get_drvdata(port->dev);
u8 ret;
ret = readb(port->membase + (reg << port->regshift));
ndelay(s->chip->trwd);
return ret;
}
static inline void sccnxp_write(struct uart_port *port, u8 reg, u8 v)
static void sccnxp_write(struct uart_port *port, u8 reg, u8 v)
{
struct sccnxp_port *s = dev_get_drvdata(port->dev);
writeb(v, port->membase + (reg << port->regshift));
ndelay(s->chip->trwd);
}
static inline u8 sccnxp_port_read(struct uart_port *port, u8 reg)
static u8 sccnxp_port_read(struct uart_port *port, u8 reg)
{
return sccnxp_read(port, (port->line << 3) + reg);
}
static inline void sccnxp_port_write(struct uart_port *port, u8 reg, u8 v)
static void sccnxp_port_write(struct uart_port *port, u8 reg, u8 v)
{
sccnxp_write(port, (port->line << 3) + reg, v);
}
@ -233,7 +259,7 @@ static int sccnxp_update_best_err(int a, int b, int *besterr)
{
int err = abs(a - b);
if ((*besterr < 0) || (*besterr > err)) {
if (*besterr > err) {
*besterr = err;
return 0;
}
@ -281,10 +307,22 @@ static const struct {
static int sccnxp_set_baud(struct uart_port *port, int baud)
{
struct sccnxp_port *s = dev_get_drvdata(port->dev);
int div_std, tmp_baud, bestbaud = baud, besterr = -1;
int div_std, tmp_baud, bestbaud = INT_MAX, besterr = INT_MAX;
struct sccnxp_chip *chip = s->chip;
u8 i, acr = 0, csr = 0, mr0 = 0;
/* Find divisor to load to the timer preset registers */
div_std = DIV_ROUND_CLOSEST(port->uartclk, 2 * 16 * baud);
if ((div_std >= 2) && (div_std <= 0xffff)) {
bestbaud = DIV_ROUND_CLOSEST(port->uartclk, 2 * 16 * div_std);
sccnxp_update_best_err(baud, bestbaud, &besterr);
csr = CSR_TIMER_MODE;
sccnxp_port_write(port, SCCNXP_CTPU_REG, div_std >> 8);
sccnxp_port_write(port, SCCNXP_CTPL_REG, div_std);
/* Issue start timer/counter command */
sccnxp_port_read(port, SCCNXP_START_COUNTER_REG);
}
/* Find best baud from table */
for (i = 0; baud_std[i].baud && besterr; i++) {
if (baud_std[i].mr0 && !(chip->flags & SCCNXP_HAVE_MR0))

View File

@ -746,7 +746,7 @@ static void tegra_uart_stop_rx(struct uart_port *u)
if (!tup->rx_in_progress)
return;
tegra_uart_wait_sym_time(tup, 1); /* wait a character interval */
tegra_uart_wait_sym_time(tup, 1); /* wait one character interval */
ier = tup->ier_shadow;
ier &= ~(UART_IER_RDI | UART_IER_RLSI | UART_IER_RTOIE |
@ -887,7 +887,7 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup)
*
* EORD is different interrupt than RX_TIMEOUT - RX_TIMEOUT occurs when
* the DATA is sitting in the FIFO and couldn't be transferred to the
* DMA as the DMA size alignment(4 bytes) is not met. EORD will be
* DMA as the DMA size alignment (4 bytes) is not met. EORD will be
* triggered when there is a pause of the incomming data stream for 4
* characters long.
*
@ -1079,7 +1079,7 @@ static void tegra_uart_set_termios(struct uart_port *u,
if (tup->rts_active)
set_rts(tup, false);
/* Clear all interrupts as configuration is going to be change */
/* Clear all interrupts as configuration is going to be changed */
tegra_uart_write(tup, tup->ier_shadow | UART_IER_RDI, UART_IER);
tegra_uart_read(tup, UART_IER);
tegra_uart_write(tup, 0, UART_IER);
@ -1165,10 +1165,10 @@ static void tegra_uart_set_termios(struct uart_port *u,
/* update the port timeout based on new settings */
uart_update_timeout(u, termios->c_cflag, baud);
/* Make sure all write has completed */
/* Make sure all writes have completed */
tegra_uart_read(tup, UART_IER);
/* Reenable interrupt */
/* Re-enable interrupt */
tegra_uart_write(tup, tup->ier_shadow, UART_IER);
tegra_uart_read(tup, UART_IER);

View File

@ -205,10 +205,15 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
if (!state->xmit.buf) {
state->xmit.buf = (unsigned char *) page;
uart_circ_clear(&state->xmit);
uart_port_unlock(uport, flags);
} else {
uart_port_unlock(uport, flags);
/*
* Do not free() the page under the port lock, see
* uart_shutdown().
*/
free_page(page);
}
uart_port_unlock(uport, flags);
retval = uport->ops->startup(uport);
if (retval == 0) {
@ -268,6 +273,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
struct uart_port *uport = uart_port_check(state);
struct tty_port *port = &state->port;
unsigned long flags = 0;
char *xmit_buf = NULL;
/*
* Set the TTY IO error marker
@ -298,14 +304,18 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
tty_port_set_suspended(port, 0);
/*
* Free the transmit buffer page.
* Do not free() the transmit buffer page under the port lock since
* this can create various circular locking scenarios. For instance,
* console driver may need to allocate/free a debug object, which
* can endup in printk() recursion.
*/
uart_port_lock(state, flags);
if (state->xmit.buf) {
free_page((unsigned long)state->xmit.buf);
state->xmit.buf = NULL;
}
xmit_buf = state->xmit.buf;
state->xmit.buf = NULL;
uart_port_unlock(uport, flags);
if (xmit_buf)
free_page((unsigned long)xmit_buf);
}
/**

View File

@ -1331,7 +1331,7 @@ static void sci_tx_dma_release(struct sci_port *s)
dma_release_channel(chan);
}
static void sci_submit_rx(struct sci_port *s)
static int sci_submit_rx(struct sci_port *s, bool port_lock_held)
{
struct dma_chan *chan = s->chan_rx;
struct uart_port *port = &s->port;
@ -1359,19 +1359,22 @@ static void sci_submit_rx(struct sci_port *s)
s->active_rx = s->cookie_rx[0];
dma_async_issue_pending(chan);
return;
return 0;
fail:
/* Switch to PIO */
if (!port_lock_held)
spin_lock_irqsave(&port->lock, flags);
if (i)
dmaengine_terminate_async(chan);
for (i = 0; i < 2; i++)
s->cookie_rx[i] = -EINVAL;
s->active_rx = -EINVAL;
/* Switch to PIO */
spin_lock_irqsave(&port->lock, flags);
s->active_rx = 0;
s->chan_rx = NULL;
sci_start_rx(port);
spin_unlock_irqrestore(&port->lock, flags);
if (!port_lock_held)
spin_unlock_irqrestore(&port->lock, flags);
return -EAGAIN;
}
static void work_fn_tx(struct work_struct *work)
@ -1491,7 +1494,7 @@ static enum hrtimer_restart rx_timer_fn(struct hrtimer *t)
}
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
sci_submit_rx(s);
sci_submit_rx(s, true);
/* Direct new serial port interrupts back to CPU */
scr = serial_port_in(port, SCSCR);
@ -1617,7 +1620,7 @@ static void sci_request_dma(struct uart_port *port)
s->chan_rx_saved = s->chan_rx = chan;
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
sci_submit_rx(s);
sci_submit_rx(s, false);
}
}
@ -1666,8 +1669,10 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
disable_irq_nosync(irq);
scr |= SCSCR_RDRQE;
} else {
if (sci_submit_rx(s, false) < 0)
goto handle_pio;
scr &= ~SCSCR_RIE;
sci_submit_rx(s);
}
serial_port_out(port, SCSCR, scr);
/* Clear current interrupt */
@ -1679,6 +1684,8 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
return IRQ_HANDLED;
}
handle_pio:
#endif
if (s->rx_trigger > 1 && s->rx_fifo_timeout > 0) {
@ -1693,7 +1700,7 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
* of whether the I_IXOFF is set, otherwise, how is the interrupt
* to be disabled?
*/
sci_receive_chars(ptr);
sci_receive_chars(port);
return IRQ_HANDLED;
}
@ -1749,7 +1756,7 @@ static irqreturn_t sci_er_interrupt(int irq, void *ptr)
} else {
sci_handle_fifo_overrun(port);
if (!s->chan_rx)
sci_receive_chars(ptr);
sci_receive_chars(port);
}
sci_clear_SCxSR(port, SCxSR_ERROR_CLEAR(port));

View File

@ -89,14 +89,14 @@ void sunserial_console_termios(struct console *con, struct device_node *uart_dp)
int baud, bits, stop, cflag;
char parity;
if (!strcmp(uart_dp->name, "rsc") ||
!strcmp(uart_dp->name, "rsc-console") ||
!strcmp(uart_dp->name, "rsc-control")) {
if (of_node_name_eq(uart_dp, "rsc") ||
of_node_name_eq(uart_dp, "rsc-console") ||
of_node_name_eq(uart_dp, "rsc-control")) {
mode = of_get_property(uart_dp,
"ssp-console-modes", NULL);
if (!mode)
mode = "115200,8,n,1,-";
} else if (!strcmp(uart_dp->name, "lom-console")) {
} else if (of_node_name_eq(uart_dp, "lom-console")) {
mode = "9600,8,n,1,-";
} else {
struct device_node *dp;

View File

@ -1503,8 +1503,8 @@ static int su_probe(struct platform_device *op)
up->port.ops = &sunsu_pops;
ignore_line = false;
if (!strcmp(dp->name, "rsc-console") ||
!strcmp(dp->name, "lom-console"))
if (of_node_name_eq(dp, "rsc-console") ||
of_node_name_eq(dp, "lom-console"))
ignore_line = true;
sunserial_console_match(SUNSU_CONSOLE(), dp,

View File

@ -22,6 +22,7 @@
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/clk.h>
#include <linux/pm_runtime.h>
#define ULITE_NAME "ttyUL"
#define ULITE_MAJOR 204
@ -54,6 +55,7 @@
#define ULITE_CONTROL_RST_TX 0x01
#define ULITE_CONTROL_RST_RX 0x02
#define ULITE_CONTROL_IE 0x10
#define UART_AUTOSUSPEND_TIMEOUT 3000
/* Static pointer to console port */
#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
@ -63,6 +65,7 @@ static struct uart_port *console_port;
struct uartlite_data {
const struct uartlite_reg_ops *reg_ops;
struct clk *clk;
struct uart_driver *ulite_uart_driver;
};
struct uartlite_reg_ops {
@ -390,12 +393,12 @@ static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser)
static void ulite_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate)
{
struct uartlite_data *pdata = port->private_data;
if (!state)
clk_enable(pdata->clk);
else
clk_disable(pdata->clk);
if (!state) {
pm_runtime_get_sync(port->dev);
} else {
pm_runtime_mark_last_busy(port->dev);
pm_runtime_put_autosuspend(port->dev);
}
}
#ifdef CONFIG_CONSOLE_POLL
@ -694,7 +697,9 @@ static int ulite_release(struct device *dev)
int rc = 0;
if (port) {
rc = uart_remove_one_port(&ulite_uart_driver, port);
struct uartlite_data *pdata = port->private_data;
rc = uart_remove_one_port(pdata->ulite_uart_driver, port);
dev_set_drvdata(dev, NULL);
port->mapbase = 0;
}
@ -712,8 +717,11 @@ static int __maybe_unused ulite_suspend(struct device *dev)
{
struct uart_port *port = dev_get_drvdata(dev);
if (port)
uart_suspend_port(&ulite_uart_driver, port);
if (port) {
struct uartlite_data *pdata = port->private_data;
uart_suspend_port(pdata->ulite_uart_driver, port);
}
return 0;
}
@ -728,17 +736,41 @@ static int __maybe_unused ulite_resume(struct device *dev)
{
struct uart_port *port = dev_get_drvdata(dev);
if (port)
uart_resume_port(&ulite_uart_driver, port);
if (port) {
struct uartlite_data *pdata = port->private_data;
uart_resume_port(pdata->ulite_uart_driver, port);
}
return 0;
}
static int __maybe_unused ulite_runtime_suspend(struct device *dev)
{
struct uart_port *port = dev_get_drvdata(dev);
struct uartlite_data *pdata = port->private_data;
clk_disable(pdata->clk);
return 0;
};
static int __maybe_unused ulite_runtime_resume(struct device *dev)
{
struct uart_port *port = dev_get_drvdata(dev);
struct uartlite_data *pdata = port->private_data;
clk_enable(pdata->clk);
return 0;
}
/* ---------------------------------------------------------------------
* Platform bus binding
*/
static SIMPLE_DEV_PM_OPS(ulite_pm_ops, ulite_suspend, ulite_resume);
static const struct dev_pm_ops ulite_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(ulite_suspend, ulite_resume)
SET_RUNTIME_PM_OPS(ulite_runtime_suspend,
ulite_runtime_resume, NULL)
};
#if defined(CONFIG_OF)
/* Match table for of_platform binding */
@ -763,6 +795,22 @@ static int ulite_probe(struct platform_device *pdev)
if (prop)
id = be32_to_cpup(prop);
#endif
if (id < 0) {
/* Look for a serialN alias */
id = of_alias_get_id(pdev->dev.of_node, "serial");
if (id < 0)
id = 0;
}
if (!ulite_uart_driver.state) {
dev_dbg(&pdev->dev, "uartlite: calling uart_register_driver()\n");
ret = uart_register_driver(&ulite_uart_driver);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register driver\n");
return ret;
}
}
pdata = devm_kzalloc(&pdev->dev, sizeof(struct uartlite_data),
GFP_KERNEL);
if (!pdata)
@ -788,24 +836,22 @@ static int ulite_probe(struct platform_device *pdev)
pdata->clk = NULL;
}
pdata->ulite_uart_driver = &ulite_uart_driver;
ret = clk_prepare_enable(pdata->clk);
if (ret) {
dev_err(&pdev->dev, "Failed to prepare clock\n");
return ret;
}
if (!ulite_uart_driver.state) {
dev_dbg(&pdev->dev, "uartlite: calling uart_register_driver()\n");
ret = uart_register_driver(&ulite_uart_driver);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register driver\n");
return ret;
}
}
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT);
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
ret = ulite_assign(&pdev->dev, id, res->start, irq, pdata);
clk_disable(pdata->clk);
pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
return ret;
}
@ -814,9 +860,14 @@ static int ulite_remove(struct platform_device *pdev)
{
struct uart_port *port = dev_get_drvdata(&pdev->dev);
struct uartlite_data *pdata = port->private_data;
int rc;
clk_disable_unprepare(pdata->clk);
return ulite_release(&pdev->dev);
clk_unprepare(pdata->clk);
rc = ulite_release(&pdev->dev);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
return rc;
}
/* work with hotplug and coldplug */

View File

@ -123,7 +123,7 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
#define CDNS_UART_IXR_RXTRIG 0x00000001 /* RX FIFO trigger interrupt */
#define CDNS_UART_IXR_RXFULL 0x00000004 /* RX FIFO full interrupt. */
#define CDNS_UART_IXR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt. */
#define CDNS_UART_IXR_MASK 0x00001FFF /* Valid bit mask */
#define CDNS_UART_IXR_RXMASK 0x000021e7 /* Valid RX bit mask */
/*
* Do not enable parity error interrupt for the following
@ -364,7 +364,7 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id)
cdns_uart_handle_tx(dev_id);
isrstatus &= ~CDNS_UART_IXR_TXEMPTY;
}
if (isrstatus & CDNS_UART_IXR_MASK)
if (isrstatus & CDNS_UART_IXR_RXMASK)
cdns_uart_handle_rx(dev_id, isrstatus);
spin_unlock(&port->lock);
@ -1255,7 +1255,7 @@ static int cdns_uart_suspend(struct device *device)
may_wake = device_may_wakeup(device);
if (console_suspend_enabled && may_wake) {
if (console_suspend_enabled && uart_console(port) && may_wake) {
unsigned long flags = 0;
spin_lock_irqsave(&port->lock, flags);
@ -1293,7 +1293,7 @@ static int cdns_uart_resume(struct device *device)
may_wake = device_may_wakeup(device);
if (console_suspend_enabled && !may_wake) {
if (console_suspend_enabled && uart_console(port) && !may_wake) {
clk_enable(cdns_uart->pclk);
clk_enable(cdns_uart->uartclk);
@ -1508,8 +1508,10 @@ static int cdns_uart_probe(struct platform_device *pdev)
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
cdns_uart_console = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_console),
GFP_KERNEL);
if (!cdns_uart_console)
return -ENOMEM;
if (!cdns_uart_console) {
rc = -ENOMEM;
goto err_out_id;
}
strncpy(cdns_uart_console->name, CDNS_UART_TTY_NAME,
sizeof(cdns_uart_console->name));
@ -1624,6 +1626,7 @@ static int cdns_uart_probe(struct platform_device *pdev)
pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT);
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
device_init_wakeup(port->dev, true);
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
/*
@ -1702,6 +1705,7 @@ static int cdns_uart_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
device_init_wakeup(&pdev->dev, false);
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
if (console_port == port)
@ -1719,6 +1723,7 @@ static struct platform_driver cdns_uart_platform_driver = {
.name = CDNS_UART_NAME,
.of_match_table = cdns_uart_of_match,
.pm = &cdns_uart_dev_pm_ops,
.suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_XILINX_PS_UART),
},
};

View File

@ -134,17 +134,10 @@ static struct sysrq_key_op sysrq_unraw_op = {
static void sysrq_handle_crash(int key)
{
char *killer = NULL;
/* we need to release the RCU read lock here,
* otherwise we get an annoying
* 'BUG: sleeping function called from invalid context'
* complaint from the kernel before the panic.
*/
/* release the RCU read lock before crashing */
rcu_read_unlock();
panic_on_oops = 1; /* force panic */
wmb();
*killer = 1;
panic("sysrq triggered crash\n");
}
static struct sysrq_key_op sysrq_crash_op = {
.handler = sysrq_handle_crash,
@ -660,8 +653,7 @@ static void sysrq_do_reset(struct timer_list *t)
state->reset_requested = true;
ksys_sync();
kernel_restart(NULL);
orderly_reboot();
}
static void sysrq_handle_reset_request(struct sysrq_state *state)
@ -736,6 +728,8 @@ static void sysrq_of_get_keyreset_config(void)
/* Get reset timeout if any. */
of_property_read_u32(np, "timeout-ms", &sysrq_reset_downtime_ms);
of_node_put(np);
}
#else
static void sysrq_of_get_keyreset_config(void)

View File

@ -1268,14 +1268,16 @@ static int tty_reopen(struct tty_struct *tty)
if (test_bit(TTY_EXCLUSIVE, &tty->flags) && !capable(CAP_SYS_ADMIN))
return -EBUSY;
tty->count++;
if (tty->ldisc)
return 0;
retval = tty_ldisc_reinit(tty, tty->termios.c_line);
retval = tty_ldisc_lock(tty, 5 * HZ);
if (retval)
tty->count--;
return retval;
if (!tty->ldisc)
retval = tty_ldisc_reinit(tty, tty->termios.c_line);
tty_ldisc_unlock(tty);
if (retval == 0)
tty->count++;
return retval;
}

View File

@ -327,6 +327,11 @@ int tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout)
{
int ret;
/* Kindly asking blocked readers to release the read side */
set_bit(TTY_LDISC_CHANGING, &tty->flags);
wake_up_interruptible_all(&tty->read_wait);
wake_up_interruptible_all(&tty->write_wait);
ret = __tty_ldisc_lock(tty, timeout);
if (!ret)
return -EBUSY;
@ -337,6 +342,8 @@ int tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout)
void tty_ldisc_unlock(struct tty_struct *tty)
{
clear_bit(TTY_LDISC_HALTED, &tty->flags);
/* Can be cleared here - ldisc_unlock will wake up writers firstly */
clear_bit(TTY_LDISC_CHANGING, &tty->flags);
__tty_ldisc_unlock(tty);
}
@ -471,6 +478,7 @@ static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld)
static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld)
{
lockdep_assert_held_exclusive(&tty->ldisc_sem);
WARN_ON(!test_bit(TTY_LDISC_OPEN, &tty->flags));
clear_bit(TTY_LDISC_OPEN, &tty->flags);
if (ld->ops->close)
@ -492,6 +500,7 @@ static int tty_ldisc_failto(struct tty_struct *tty, int ld)
struct tty_ldisc *disc = tty_ldisc_get(tty, ld);
int r;
lockdep_assert_held_exclusive(&tty->ldisc_sem);
if (IS_ERR(disc))
return PTR_ERR(disc);
tty->ldisc = disc;
@ -615,6 +624,7 @@ EXPORT_SYMBOL_GPL(tty_set_ldisc);
*/
static void tty_ldisc_kill(struct tty_struct *tty)
{
lockdep_assert_held_exclusive(&tty->ldisc_sem);
if (!tty->ldisc)
return;
/*
@ -662,6 +672,7 @@ int tty_ldisc_reinit(struct tty_struct *tty, int disc)
struct tty_ldisc *ld;
int retval;
lockdep_assert_held_exclusive(&tty->ldisc_sem);
ld = tty_ldisc_get(tty, disc);
if (IS_ERR(ld)) {
BUG_ON(disc == N_TTY);
@ -760,6 +771,10 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
return retval;
if (o_tty) {
/*
* Called without o_tty->ldisc_sem held, as o_tty has been
* just allocated and no one has a reference to it.
*/
retval = tty_ldisc_open(o_tty, o_tty->ldisc);
if (retval) {
tty_ldisc_close(tty, tty->ldisc);
@ -825,6 +840,7 @@ int tty_ldisc_init(struct tty_struct *tty)
*/
void tty_ldisc_deinit(struct tty_struct *tty)
{
/* no ldisc_sem, tty is being destroyed */
if (tty->ldisc)
tty_ldisc_put(tty->ldisc);
tty->ldisc = NULL;

View File

@ -34,29 +34,6 @@
#include <linux/sched/task.h>
#ifdef CONFIG_DEBUG_LOCK_ALLOC
# define __acq(l, s, t, r, c, n, i) \
lock_acquire(&(l)->dep_map, s, t, r, c, n, i)
# define __rel(l, n, i) \
lock_release(&(l)->dep_map, n, i)
#define lockdep_acquire(l, s, t, i) __acq(l, s, t, 0, 1, NULL, i)
#define lockdep_acquire_nest(l, s, t, n, i) __acq(l, s, t, 0, 1, n, i)
#define lockdep_acquire_read(l, s, t, i) __acq(l, s, t, 1, 1, NULL, i)
#define lockdep_release(l, n, i) __rel(l, n, i)
#else
# define lockdep_acquire(l, s, t, i) do { } while (0)
# define lockdep_acquire_nest(l, s, t, n, i) do { } while (0)
# define lockdep_acquire_read(l, s, t, i) do { } while (0)
# define lockdep_release(l, n, i) do { } while (0)
#endif
#ifdef CONFIG_LOCK_STAT
# define lock_stat(_lock, stat) lock_##stat(&(_lock)->dep_map, _RET_IP_)
#else
# define lock_stat(_lock, stat) do { } while (0)
#endif
#if BITS_PER_LONG == 64
# define LDSEM_ACTIVE_MASK 0xffffffffL
#else
@ -235,6 +212,7 @@ down_read_failed(struct ld_semaphore *sem, long count, long timeout)
raw_spin_lock_irq(&sem->wait_lock);
if (waiter.task) {
atomic_long_add_return(-LDSEM_WAIT_BIAS, &sem->count);
sem->wait_readers--;
list_del(&waiter.list);
raw_spin_unlock_irq(&sem->wait_lock);
put_task_struct(waiter.task);
@ -293,6 +271,16 @@ down_write_failed(struct ld_semaphore *sem, long count, long timeout)
if (!locked)
atomic_long_add_return(-LDSEM_WAIT_BIAS, &sem->count);
list_del(&waiter.list);
/*
* In case of timeout, wake up every reader who gave the right of way
* to writer. Prevent separation readers into two groups:
* one that helds semaphore and another that sleeps.
* (in case of no contention with a writer)
*/
if (!locked && list_empty(&sem->write_wait))
__ldsem_wake_readers(sem);
raw_spin_unlock_irq(&sem->wait_lock);
__set_current_state(TASK_RUNNING);
@ -310,17 +298,17 @@ static int __ldsem_down_read_nested(struct ld_semaphore *sem,
{
long count;
lockdep_acquire_read(sem, subclass, 0, _RET_IP_);
rwsem_acquire_read(&sem->dep_map, subclass, 0, _RET_IP_);
count = atomic_long_add_return(LDSEM_READ_BIAS, &sem->count);
if (count <= 0) {
lock_stat(sem, contended);
lock_contended(&sem->dep_map, _RET_IP_);
if (!down_read_failed(sem, count, timeout)) {
lockdep_release(sem, 1, _RET_IP_);
rwsem_release(&sem->dep_map, 1, _RET_IP_);
return 0;
}
}
lock_stat(sem, acquired);
lock_acquired(&sem->dep_map, _RET_IP_);
return 1;
}
@ -329,17 +317,17 @@ static int __ldsem_down_write_nested(struct ld_semaphore *sem,
{
long count;
lockdep_acquire(sem, subclass, 0, _RET_IP_);
rwsem_acquire(&sem->dep_map, subclass, 0, _RET_IP_);
count = atomic_long_add_return(LDSEM_WRITE_BIAS, &sem->count);
if ((count & LDSEM_ACTIVE_MASK) != LDSEM_ACTIVE_BIAS) {
lock_stat(sem, contended);
lock_contended(&sem->dep_map, _RET_IP_);
if (!down_write_failed(sem, count, timeout)) {
lockdep_release(sem, 1, _RET_IP_);
rwsem_release(&sem->dep_map, 1, _RET_IP_);
return 0;
}
}
lock_stat(sem, acquired);
lock_acquired(&sem->dep_map, _RET_IP_);
return 1;
}
@ -362,8 +350,8 @@ int ldsem_down_read_trylock(struct ld_semaphore *sem)
while (count >= 0) {
if (atomic_long_try_cmpxchg(&sem->count, &count, count + LDSEM_READ_BIAS)) {
lockdep_acquire_read(sem, 0, 1, _RET_IP_);
lock_stat(sem, acquired);
rwsem_acquire_read(&sem->dep_map, 0, 1, _RET_IP_);
lock_acquired(&sem->dep_map, _RET_IP_);
return 1;
}
}
@ -388,8 +376,8 @@ int ldsem_down_write_trylock(struct ld_semaphore *sem)
while ((count & LDSEM_ACTIVE_MASK) == 0) {
if (atomic_long_try_cmpxchg(&sem->count, &count, count + LDSEM_WRITE_BIAS)) {
lockdep_acquire(sem, 0, 1, _RET_IP_);
lock_stat(sem, acquired);
rwsem_acquire(&sem->dep_map, 0, 1, _RET_IP_);
lock_acquired(&sem->dep_map, _RET_IP_);
return 1;
}
}
@ -403,7 +391,7 @@ void ldsem_up_read(struct ld_semaphore *sem)
{
long count;
lockdep_release(sem, 1, _RET_IP_);
rwsem_release(&sem->dep_map, 1, _RET_IP_);
count = atomic_long_add_return(-LDSEM_READ_BIAS, &sem->count);
if (count < 0 && (count & LDSEM_ACTIVE_MASK) == 0)
@ -417,7 +405,7 @@ void ldsem_up_write(struct ld_semaphore *sem)
{
long count;
lockdep_release(sem, 1, _RET_IP_);
rwsem_release(&sem->dep_map, 1, _RET_IP_);
count = atomic_long_add_return(-LDSEM_WRITE_BIAS, &sem->count);
if (count < 0)

View File

@ -32,6 +32,7 @@ struct font_desc {
#define ACORN8x8_IDX 8
#define MINI4x6_IDX 9
#define FONT6x10_IDX 10
#define TER16x32_IDX 11
extern const struct font_desc font_vga_8x8,
font_vga_8x16,
@ -43,7 +44,8 @@ extern const struct font_desc font_vga_8x8,
font_sun_12x22,
font_acorn_8x8,
font_mini_4x6,
font_6x10;
font_6x10,
font_ter_16x32;
/* Find a font with a specific name */

View File

@ -0,0 +1,23 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __LINUX_LANTIQ_H
#define __LINUX_LANTIQ_H
#ifdef CONFIG_LANTIQ
#include <lantiq_soc.h>
#else
#ifndef LTQ_EARLY_ASC
#define LTQ_EARLY_ASC 0
#endif
#ifndef CPHYSADDR
#define CPHYSADDR(a) 0
#endif
static inline struct clk *clk_get_fpi(void)
{
return NULL;
}
#endif /* CONFIG_LANTIQ */
#endif /* __LINUX_LANTIQ_H */

View File

@ -210,7 +210,7 @@ void serdev_device_wait_until_sent(struct serdev_device *, long);
int serdev_device_get_tiocm(struct serdev_device *);
int serdev_device_set_tiocm(struct serdev_device *, int, int);
void serdev_device_write_wakeup(struct serdev_device *);
int serdev_device_write(struct serdev_device *, const unsigned char *, size_t, unsigned long);
int serdev_device_write(struct serdev_device *, const unsigned char *, size_t, long);
void serdev_device_write_flush(struct serdev_device *);
int serdev_device_write_room(struct serdev_device *);

View File

@ -134,6 +134,10 @@ struct uart_8250_port {
void (*dl_write)(struct uart_8250_port *, int);
struct uart_8250_em485 *em485;
/* Serial port overrun backoff */
struct delayed_work overrun_backoff;
u32 overrun_backoff_time_ms;
};
static inline struct uart_8250_port *up_to_u8250p(struct uart_port *up)

View File

@ -22,6 +22,7 @@
#include <linux/bitops.h>
#include <linux/compiler.h>
#include <linux/console.h>
#include <linux/interrupt.h>
#include <linux/circ_buf.h>
#include <linux/spinlock.h>
@ -175,6 +176,7 @@ struct uart_port {
struct console *cons; /* struct console, if any */
#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(SUPPORT_SYSRQ)
unsigned long sysrq; /* sysrq timeout */
unsigned int sysrq_ch; /* char for sysrq */
#endif
/* flags must be updated while holding port mutex */
@ -485,8 +487,42 @@ uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
}
return 0;
}
static inline int
uart_prepare_sysrq_char(struct uart_port *port, unsigned int ch)
{
if (port->sysrq) {
if (ch && time_before(jiffies, port->sysrq)) {
port->sysrq_ch = ch;
port->sysrq = 0;
return 1;
}
port->sysrq = 0;
}
return 0;
}
static inline void
uart_unlock_and_check_sysrq(struct uart_port *port, unsigned long irqflags)
{
int sysrq_ch;
sysrq_ch = port->sysrq_ch;
port->sysrq_ch = 0;
spin_unlock_irqrestore(&port->lock, irqflags);
if (sysrq_ch)
handle_sysrq(sysrq_ch);
}
#else
#define uart_handle_sysrq_char(port,ch) ({ (void)port; 0; })
static inline int
uart_handle_sysrq_char(struct uart_port *port, unsigned int ch) { return 0; }
static inline int
uart_prepare_sysrq_char(struct uart_port *port, unsigned int ch) { return 0; }
static inline void
uart_unlock_and_check_sysrq(struct uart_port *port, unsigned long irqflags)
{
spin_unlock_irqrestore(&port->lock, irqflags);
}
#endif
/*

View File

@ -366,6 +366,7 @@ struct tty_file_private {
#define TTY_NO_WRITE_SPLIT 17 /* Preserve write boundaries to driver */
#define TTY_HUPPED 18 /* Post driver->hangup() */
#define TTY_HUPPING 19 /* Hangup in progress */
#define TTY_LDISC_CHANGING 20 /* Change pending - non-block IO */
#define TTY_LDISC_HALTED 22 /* Line discipline is halted */
/* Values for tty->flow_change */
@ -383,6 +384,12 @@ static inline void tty_set_flow_change(struct tty_struct *tty, int val)
smp_mb();
}
static inline bool tty_io_nonblock(struct tty_struct *tty, struct file *file)
{
return file->f_flags & O_NONBLOCK ||
test_bit(TTY_LDISC_CHANGING, &tty->flags);
}
static inline bool tty_io_error(struct tty_struct *tty)
{
return test_bit(TTY_IO_ERROR, &tty->flags);

View File

@ -109,6 +109,15 @@ config FONT_SUN12x22
big letters (like the letters used in the SPARC PROM). If the
standard font is unreadable for you, say Y, otherwise say N.
config FONT_TER16x32
bool "Terminus 16x32 font (not supported by all drivers)"
depends on FRAMEBUFFER_CONSOLE && (!SPARC && FONTS || SPARC)
help
Terminus Font is a clean, fixed width bitmap font, designed
for long (8 and more hours per day) work with computers.
This is the high resolution, large version for use with HiDPI screens.
If the standard font is unreadable for you, say Y, otherwise say N.
config FONT_AUTOSELECT
def_bool y
depends on !FONT_8x8
@ -121,6 +130,7 @@ config FONT_AUTOSELECT
depends on !FONT_SUN8x16
depends on !FONT_SUN12x22
depends on !FONT_10x18
depends on !FONT_TER16x32
select FONT_8x16
endif # FONT_SUPPORT

View File

@ -14,6 +14,7 @@ font-objs-$(CONFIG_FONT_PEARL_8x8) += font_pearl_8x8.o
font-objs-$(CONFIG_FONT_ACORN_8x8) += font_acorn_8x8.o
font-objs-$(CONFIG_FONT_MINI_4x6) += font_mini_4x6.o
font-objs-$(CONFIG_FONT_6x10) += font_6x10.o
font-objs-$(CONFIG_FONT_TER16x32) += font_ter16x32.o
font-objs += $(font-objs-y)

File diff suppressed because it is too large Load Diff

View File

@ -67,6 +67,10 @@ static const struct font_desc *fonts[] = {
#undef NO_FONTS
&font_6x10,
#endif
#ifdef CONFIG_FONT_TER16x32
#undef NO_FONTS
&font_ter_16x32,
#endif
};
#define num_fonts ARRAY_SIZE(fonts)