mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-23 04:04:26 +08:00
TTY/Serial changes for 6.10-rc1
Here is the big set of tty/serial driver changes for 6.10-rc1. Included in here are: - Usual good set of api cleanups and evolution by Jiri Slaby to make the serial interfaces move out of the 1990's by using kfifos instead of hand-rolling their own logic. - 8250_exar driver updates - max3100 driver updates - sc16is7xx driver updates - exar driver updates - sh-sci driver updates - tty ldisc api addition to help refuse bindings - other smaller serial driver updates All of these have been in linux-next for a while with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCZk4Cvg8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ymqpwCgnHU1NeBBUsvoSDOLk5oApIQ4jVgAn102jWlw 3dNDhA4i3Ay/mZdv8/Kj =TI+P -----END PGP SIGNATURE----- Merge tag 'tty-6.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty Pull tty / serial updates from Greg KH: "Here is the big set of tty/serial driver changes for 6.10-rc1. Included in here are: - Usual good set of api cleanups and evolution by Jiri Slaby to make the serial interfaces move out of the 1990's by using kfifos instead of hand-rolling their own logic. - 8250_exar driver updates - max3100 driver updates - sc16is7xx driver updates - exar driver updates - sh-sci driver updates - tty ldisc api addition to help refuse bindings - other smaller serial driver updates All of these have been in linux-next for a while with no reported issues" * tag 'tty-6.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (113 commits) serial: Clear UPF_DEAD before calling tty_port_register_device_attr_serdev() serial: imx: Raise TX trigger level to 8 serial: 8250_pnp: Simplify "line" related code serial: sh-sci: simplify locking when re-issuing RXDMA fails serial: sh-sci: let timeout timer only run when DMA is scheduled serial: sh-sci: describe locking requirements for invalidating RXDMA serial: sh-sci: protect invalidating RXDMA on shutdown tty: add the option to have a tty reject a new ldisc serial: core: Call device_set_awake_path() for console port dt-bindings: serial: brcm,bcm2835-aux-uart: convert to dtschema tty: serial: uartps: Add support for uartps controller reset arm64: zynqmp: Add resets property for UART nodes dt-bindings: serial: cdns,uart: Add optional reset property serial: 8250_pnp: Switch to DEFINE_SIMPLE_DEV_PM_OPS() serial: 8250_exar: Keep the includes sorted serial: 8250_exar: Make type of bit the same in exar_ee_*_bit() serial: 8250_exar: Use BIT() in exar_ee_read() serial: 8250_exar: Switch to use dev_err_probe() serial: 8250_exar: Return directly from switch-cases serial: 8250_exar: Decrease indentation level ...
This commit is contained in:
commit
f6b8e86b7a
@ -788,6 +788,25 @@
|
||||
Documentation/networking/netconsole.rst for an
|
||||
alternative.
|
||||
|
||||
<DEVNAME>:<n>.<n>[,options]
|
||||
Use the specified serial port on the serial core bus.
|
||||
The addressing uses DEVNAME of the physical serial port
|
||||
device, followed by the serial core controller instance,
|
||||
and the serial port instance. The options are the same
|
||||
as documented for the ttyS addressing above.
|
||||
|
||||
The mapping of the serial ports to the tty instances
|
||||
can be viewed with:
|
||||
|
||||
$ ls -d /sys/bus/serial-base/devices/*:*.*/tty/*
|
||||
/sys/bus/serial-base/devices/00:04:0.0/tty/ttyS0
|
||||
|
||||
In the above example, the console can be addressed with
|
||||
console=00:04:0.0. Note that a console addressed this
|
||||
way will only get added when the related device driver
|
||||
is ready. The use of an earlycon parameter in addition to
|
||||
the console may be desired for console output early on.
|
||||
|
||||
uart[8250],io,<addr>[,options]
|
||||
uart[8250],mmio,<addr>[,options]
|
||||
uart[8250],mmio16,<addr>[,options]
|
||||
|
@ -161,6 +161,8 @@ Command Function
|
||||
will be printed to your console. (``0``, for example would make
|
||||
it so that only emergency messages like PANICs or OOPSes would
|
||||
make it to your console.)
|
||||
|
||||
``R`` Replay the kernel log messages on consoles.
|
||||
=========== ===================================================================
|
||||
|
||||
Okay, so what can I use them for?
|
||||
@ -211,6 +213,13 @@ processes.
|
||||
"just thaw ``it(j)``" is useful if your system becomes unresponsive due to a
|
||||
frozen (probably root) filesystem via the FIFREEZE ioctl.
|
||||
|
||||
``Replay logs(R)`` is useful to view the kernel log messages when system is hung
|
||||
or you are not able to use dmesg command to view the messages in printk buffer.
|
||||
User may have to press the key combination multiple times if console system is
|
||||
busy. If it is completely locked up, then messages won't be printed. Output
|
||||
messages depend on current console loglevel, which can be modified using
|
||||
sysrq[0-9] (see above).
|
||||
|
||||
Sometimes SysRq seems to get 'stuck' after using it, what can I do?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -1,16 +0,0 @@
|
||||
Actions Semi Owl UART
|
||||
|
||||
Required properties:
|
||||
- compatible : "actions,s500-uart", "actions,owl-uart" for S500
|
||||
"actions,s900-uart", "actions,owl-uart" for S900
|
||||
- reg : Offset and length of the register set for the device.
|
||||
- interrupts : Should contain UART interrupt.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
uart3: serial@b0126000 {
|
||||
compatible = "actions,s500-uart", "actions,owl-uart";
|
||||
reg = <0xb0126000 0x1000>;
|
||||
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
@ -0,0 +1,48 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/serial/actions,owl-uart.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Actions Semi Owl UART
|
||||
|
||||
maintainers:
|
||||
- Kanak Shilledar <kanakshilledar111@protonmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: serial.yaml
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- actions,s500-uart
|
||||
- actions,s900-uart
|
||||
- const: actions,owl-uart
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/actions,s500-cmu.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
uart0: serial@b0126000 {
|
||||
compatible = "actions,s500-uart", "actions,owl-uart";
|
||||
reg = <0xb0126000 0x1000>;
|
||||
clocks = <&cmu CLK_UART0>;
|
||||
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
@ -1,18 +0,0 @@
|
||||
* BCM2835 AUXILIAR UART
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: "brcm,bcm2835-aux-uart"
|
||||
- reg: The base address of the UART register bank.
|
||||
- interrupts: A single interrupt specifier.
|
||||
- clocks: Clock driving the hardware; used to figure out the baud rate
|
||||
divisor.
|
||||
|
||||
Example:
|
||||
|
||||
uart1: serial@7e215040 {
|
||||
compatible = "brcm,bcm2835-aux-uart";
|
||||
reg = <0x7e215040 0x40>;
|
||||
interrupts = <1 29>;
|
||||
clocks = <&aux BCM2835_AUX_CLOCK_UART>;
|
||||
};
|
@ -0,0 +1,46 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/serial/brcm,bcm2835-aux-uart.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: BCM2835 AUXILIARY UART
|
||||
|
||||
maintainers:
|
||||
- Pratik Farkase <pratikfarkase94@gmail.com>
|
||||
- Florian Fainelli <florian.fainelli@broadcom.com>
|
||||
- Stefan Wahren <wahrenst@gmx.net>
|
||||
|
||||
allOf:
|
||||
- $ref: serial.yaml
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: brcm,bcm2835-aux-uart
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/bcm2835-aux.h>
|
||||
serial@7e215040 {
|
||||
compatible = "brcm,bcm2835-aux-uart";
|
||||
reg = <0x7e215040 0x40>;
|
||||
interrupts = <1 29>;
|
||||
clocks = <&aux BCM2835_AUX_CLOCK_UART>;
|
||||
};
|
@ -46,6 +46,9 @@ properties:
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
@ -68,6 +68,7 @@ properties:
|
||||
- renesas,scif-r8a779a0 # R-Car V3U
|
||||
- renesas,scif-r8a779f0 # R-Car S4-8
|
||||
- renesas,scif-r8a779g0 # R-Car V4H
|
||||
- renesas,scif-r8a779h0 # R-Car V4M
|
||||
- const: renesas,rcar-gen4-scif # R-Car Gen4
|
||||
- const: renesas,scif # generic SCIF compatible UART
|
||||
|
||||
|
@ -906,6 +906,7 @@
|
||||
reg = <0x0 0xff000000 0x0 0x1000>;
|
||||
clock-names = "uart_clk", "pclk";
|
||||
power-domains = <&zynqmp_firmware PD_UART_0>;
|
||||
resets = <&zynqmp_reset ZYNQMP_RESET_UART0>;
|
||||
};
|
||||
|
||||
uart1: serial@ff010000 {
|
||||
@ -917,6 +918,7 @@
|
||||
reg = <0x0 0xff010000 0x0 0x1000>;
|
||||
clock-names = "uart_clk", "pclk";
|
||||
power-domains = <&zynqmp_firmware PD_UART_1>;
|
||||
resets = <&zynqmp_reset ZYNQMP_RESET_UART1>;
|
||||
};
|
||||
|
||||
usb0: usb@ff9d0000 {
|
||||
|
@ -1578,7 +1578,13 @@ static void __exit amiga_serial_remove(struct platform_device *pdev)
|
||||
free_irq(IRQ_AMIGA_RBF, state);
|
||||
}
|
||||
|
||||
static struct platform_driver amiga_serial_driver = {
|
||||
/*
|
||||
* amiga_serial_remove() lives in .exit.text. For drivers registered via
|
||||
* module_platform_driver_probe() this is ok because they cannot get unbound at
|
||||
* runtime. So mark the driver struct with __refdata to prevent modpost
|
||||
* triggering a section mismatch warning.
|
||||
*/
|
||||
static struct platform_driver amiga_serial_driver __refdata = {
|
||||
.remove_new = __exit_p(amiga_serial_remove),
|
||||
.driver = {
|
||||
.name = "amiga-serial",
|
||||
|
@ -558,7 +558,7 @@ static void xencons_backend_changed(struct xenbus_device *dev,
|
||||
break;
|
||||
fallthrough; /* Missed the backend's CLOSING state */
|
||||
case XenbusStateClosing: {
|
||||
struct xencons_info *info = dev_get_drvdata(&dev->dev);;
|
||||
struct xencons_info *info = dev_get_drvdata(&dev->dev);
|
||||
|
||||
/*
|
||||
* Don't tear down the evtchn and grant ref before the other
|
||||
|
@ -4010,7 +4010,7 @@ static int gsm_create_network(struct gsm_dlci *dlci, struct gsm_netconfig *nc)
|
||||
mux_net = netdev_priv(net);
|
||||
mux_net->dlci = dlci;
|
||||
kref_init(&mux_net->ref);
|
||||
strncpy(nc->if_name, net->name, IFNAMSIZ); /* return net name */
|
||||
strscpy(nc->if_name, net->name); /* return net name */
|
||||
|
||||
/* reconfigure dlci for network */
|
||||
dlci->prev_adaption = dlci->adaption;
|
||||
|
@ -413,20 +413,18 @@ static int stop_tx_dma(struct uart_8250_port *p)
|
||||
static int brcmuart_tx_dma(struct uart_8250_port *p)
|
||||
{
|
||||
struct brcmuart_priv *priv = p->port.private_data;
|
||||
struct circ_buf *xmit = &p->port.state->xmit;
|
||||
struct tty_port *tport = &p->port.state->port;
|
||||
u32 tx_size;
|
||||
|
||||
if (uart_tx_stopped(&p->port) || priv->tx_running ||
|
||||
uart_circ_empty(xmit)) {
|
||||
kfifo_is_empty(&tport->xmit_fifo)) {
|
||||
return 0;
|
||||
}
|
||||
tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
|
||||
|
||||
priv->dma.tx_err = 0;
|
||||
memcpy(priv->tx_buf, &xmit->buf[xmit->tail], tx_size);
|
||||
uart_xmit_advance(&p->port, tx_size);
|
||||
tx_size = uart_fifo_out(&p->port, priv->tx_buf, UART_XMIT_SIZE);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&p->port);
|
||||
|
||||
udma_writel(priv, REGS_DMA_TX, UDMA_TX_TRANSFER_LEN, tx_size);
|
||||
@ -540,7 +538,7 @@ static void brcmuart_tx_isr(struct uart_port *up, u32 isr)
|
||||
struct brcmuart_priv *priv = up->private_data;
|
||||
struct device *dev = up->dev;
|
||||
struct uart_8250_port *port_8250 = up_to_u8250p(up);
|
||||
struct circ_buf *xmit = &port_8250->port.state->xmit;
|
||||
struct tty_port *tport = &port_8250->port.state->port;
|
||||
|
||||
if (isr & UDMA_INTR_TX_ABORT) {
|
||||
if (priv->tx_running)
|
||||
@ -548,7 +546,7 @@ static void brcmuart_tx_isr(struct uart_port *up, u32 isr)
|
||||
return;
|
||||
}
|
||||
priv->tx_running = false;
|
||||
if (!uart_circ_empty(xmit) && !uart_tx_stopped(up))
|
||||
if (!kfifo_is_empty(&tport->xmit_fifo) && !uart_tx_stopped(up))
|
||||
brcmuart_tx_dma(port_8250);
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/ioport.h>
|
||||
@ -41,6 +42,8 @@
|
||||
|
||||
#include <asm/irq.h>
|
||||
|
||||
#include "../serial_base.h" /* For serial_base_add_isa_preferred_console() */
|
||||
|
||||
#include "8250.h"
|
||||
|
||||
/*
|
||||
@ -280,7 +283,8 @@ static void serial8250_backup_timeout(struct timer_list *t)
|
||||
*/
|
||||
lsr = serial_lsr_in(up);
|
||||
if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) &&
|
||||
(!uart_circ_empty(&up->port.state->xmit) || up->port.x_char) &&
|
||||
(!kfifo_is_empty(&up->port.state->port.xmit_fifo) ||
|
||||
up->port.x_char) &&
|
||||
(lsr & UART_LSR_THRE)) {
|
||||
iir &= ~(UART_IIR_ID | UART_IIR_NO_INT);
|
||||
iir |= UART_IIR_THRI;
|
||||
@ -559,6 +563,8 @@ static void __init serial8250_isa_init_ports(void)
|
||||
port->irqflags |= irqflag;
|
||||
if (serial8250_isa_config != NULL)
|
||||
serial8250_isa_config(i, &up->port, &up->capabilities);
|
||||
|
||||
serial_base_add_isa_preferred_console(serial8250_reg.dev_name, i);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ static void __dma_tx_complete(void *param)
|
||||
{
|
||||
struct uart_8250_port *p = param;
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
struct circ_buf *xmit = &p->port.state->xmit;
|
||||
struct tty_port *tport = &p->port.state->port;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
@ -28,7 +28,7 @@ static void __dma_tx_complete(void *param)
|
||||
|
||||
uart_xmit_advance(&p->port, dma->tx_size);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&p->port);
|
||||
|
||||
ret = serial8250_tx_dma(p);
|
||||
@ -86,9 +86,10 @@ static void dma_rx_complete(void *param)
|
||||
int serial8250_tx_dma(struct uart_8250_port *p)
|
||||
{
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
struct circ_buf *xmit = &p->port.state->xmit;
|
||||
struct tty_port *tport = &p->port.state->port;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
struct uart_port *up = &p->port;
|
||||
struct scatterlist sg;
|
||||
int ret;
|
||||
|
||||
if (dma->tx_running) {
|
||||
@ -102,19 +103,27 @@ int serial8250_tx_dma(struct uart_8250_port *p)
|
||||
uart_xchar_out(up, UART_TX);
|
||||
}
|
||||
|
||||
if (uart_tx_stopped(&p->port) || uart_circ_empty(xmit)) {
|
||||
if (uart_tx_stopped(&p->port) || kfifo_is_empty(&tport->xmit_fifo)) {
|
||||
/* We have been called from __dma_tx_complete() */
|
||||
return 0;
|
||||
}
|
||||
|
||||
dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
|
||||
|
||||
serial8250_do_prepare_tx_dma(p);
|
||||
|
||||
desc = dmaengine_prep_slave_single(dma->txchan,
|
||||
dma->tx_addr + xmit->tail,
|
||||
dma->tx_size, DMA_MEM_TO_DEV,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
sg_init_table(&sg, 1);
|
||||
/* kfifo can do more than one sg, we don't (quite yet) */
|
||||
ret = kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, &sg, 1,
|
||||
UART_XMIT_SIZE, dma->tx_addr);
|
||||
|
||||
/* we already checked empty fifo above, so there should be something */
|
||||
if (WARN_ON_ONCE(ret != 1))
|
||||
return 0;
|
||||
|
||||
dma->tx_size = sg_dma_len(&sg);
|
||||
|
||||
desc = dmaengine_prep_slave_sg(dma->txchan, &sg, 1,
|
||||
DMA_MEM_TO_DEV,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (!desc) {
|
||||
ret = -EBUSY;
|
||||
goto err;
|
||||
@ -253,7 +262,7 @@ int serial8250_request_dma(struct uart_8250_port *p)
|
||||
|
||||
/* TX buffer */
|
||||
dma->tx_addr = dma_map_single(dma->txchan->device->dev,
|
||||
p->port.state->xmit.buf,
|
||||
p->port.state->port.xmit_buf,
|
||||
UART_XMIT_SIZE,
|
||||
DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(dma->txchan->device->dev, dma->tx_addr)) {
|
||||
|
@ -100,14 +100,18 @@ static void dw8250_force_idle(struct uart_port *p)
|
||||
(void)p->serial_in(p, UART_RX);
|
||||
}
|
||||
|
||||
static void dw8250_check_lcr(struct uart_port *p, int value)
|
||||
static void dw8250_check_lcr(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
void __iomem *offset = p->membase + (UART_LCR << p->regshift);
|
||||
struct dw8250_data *d = to_dw8250_data(p->private_data);
|
||||
void __iomem *addr = p->membase + (offset << p->regshift);
|
||||
int tries = 1000;
|
||||
|
||||
if (offset != UART_LCR || d->uart_16550_compatible)
|
||||
return;
|
||||
|
||||
/* Make sure LCR write wasn't ignored */
|
||||
while (tries--) {
|
||||
unsigned int lcr = p->serial_in(p, UART_LCR);
|
||||
unsigned int lcr = p->serial_in(p, offset);
|
||||
|
||||
if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
|
||||
return;
|
||||
@ -116,15 +120,15 @@ static void dw8250_check_lcr(struct uart_port *p, int value)
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
if (p->type == PORT_OCTEON)
|
||||
__raw_writeq(value & 0xff, offset);
|
||||
__raw_writeq(value & 0xff, addr);
|
||||
else
|
||||
#endif
|
||||
if (p->iotype == UPIO_MEM32)
|
||||
writel(value, offset);
|
||||
writel(value, addr);
|
||||
else if (p->iotype == UPIO_MEM32BE)
|
||||
iowrite32be(value, offset);
|
||||
iowrite32be(value, addr);
|
||||
else
|
||||
writeb(value, offset);
|
||||
writeb(value, addr);
|
||||
}
|
||||
/*
|
||||
* FIXME: this deadlocks if port->lock is already held
|
||||
@ -158,12 +162,8 @@ static void dw8250_tx_wait_empty(struct uart_port *p)
|
||||
|
||||
static void dw8250_serial_out(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
struct dw8250_data *d = to_dw8250_data(p->private_data);
|
||||
|
||||
writeb(value, p->membase + (offset << p->regshift));
|
||||
|
||||
if (offset == UART_LCR && !d->uart_16550_compatible)
|
||||
dw8250_check_lcr(p, value);
|
||||
dw8250_check_lcr(p, offset, value);
|
||||
}
|
||||
|
||||
static void dw8250_serial_out38x(struct uart_port *p, int offset, int value)
|
||||
@ -185,35 +185,26 @@ static unsigned int dw8250_serial_in(struct uart_port *p, int offset)
|
||||
#ifdef CONFIG_64BIT
|
||||
static unsigned int dw8250_serial_inq(struct uart_port *p, int offset)
|
||||
{
|
||||
unsigned int value;
|
||||
|
||||
value = (u8)__raw_readq(p->membase + (offset << p->regshift));
|
||||
u8 value = __raw_readq(p->membase + (offset << p->regshift));
|
||||
|
||||
return dw8250_modify_msr(p, offset, value);
|
||||
}
|
||||
|
||||
static void dw8250_serial_outq(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
struct dw8250_data *d = to_dw8250_data(p->private_data);
|
||||
|
||||
value &= 0xff;
|
||||
__raw_writeq(value, p->membase + (offset << p->regshift));
|
||||
/* Read back to ensure register write ordering. */
|
||||
__raw_readq(p->membase + (UART_LCR << p->regshift));
|
||||
|
||||
if (offset == UART_LCR && !d->uart_16550_compatible)
|
||||
dw8250_check_lcr(p, value);
|
||||
dw8250_check_lcr(p, offset, value);
|
||||
}
|
||||
#endif /* CONFIG_64BIT */
|
||||
|
||||
static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
struct dw8250_data *d = to_dw8250_data(p->private_data);
|
||||
|
||||
writel(value, p->membase + (offset << p->regshift));
|
||||
|
||||
if (offset == UART_LCR && !d->uart_16550_compatible)
|
||||
dw8250_check_lcr(p, value);
|
||||
dw8250_check_lcr(p, offset, value);
|
||||
}
|
||||
|
||||
static unsigned int dw8250_serial_in32(struct uart_port *p, int offset)
|
||||
@ -225,12 +216,8 @@ static unsigned int dw8250_serial_in32(struct uart_port *p, int offset)
|
||||
|
||||
static void dw8250_serial_out32be(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
struct dw8250_data *d = to_dw8250_data(p->private_data);
|
||||
|
||||
iowrite32be(value, p->membase + (offset << p->regshift));
|
||||
|
||||
if (offset == UART_LCR && !d->uart_16550_compatible)
|
||||
dw8250_check_lcr(p, value);
|
||||
dw8250_check_lcr(p, offset, value);
|
||||
}
|
||||
|
||||
static unsigned int dw8250_serial_in32be(struct uart_port *p, int offset)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -199,7 +199,7 @@ static int mtk8250_startup(struct uart_port *port)
|
||||
|
||||
if (up->dma) {
|
||||
data->rx_status = DMA_RX_START;
|
||||
uart_circ_clear(&port->state->xmit);
|
||||
kfifo_reset(&port->state->port.xmit_fifo);
|
||||
}
|
||||
#endif
|
||||
memset(&port->icount, 0, sizeof(port->icount));
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/notifier.h>
|
||||
|
||||
#include "8250.h"
|
||||
|
||||
@ -26,6 +27,7 @@ struct of_serial_info {
|
||||
struct reset_control *rst;
|
||||
int type;
|
||||
int line;
|
||||
struct notifier_block clk_notifier;
|
||||
};
|
||||
|
||||
/* Nuvoton NPCM timeout register */
|
||||
@ -58,6 +60,26 @@ static int npcm_setup(struct uart_port *port)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct of_serial_info *clk_nb_to_info(struct notifier_block *nb)
|
||||
{
|
||||
return container_of(nb, struct of_serial_info, clk_notifier);
|
||||
}
|
||||
|
||||
static int of_platform_serial_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
|
||||
void *data)
|
||||
{
|
||||
struct of_serial_info *info = clk_nb_to_info(nb);
|
||||
struct uart_8250_port *port8250 = serial8250_get_port(info->line);
|
||||
struct clk_notifier_data *ndata = data;
|
||||
|
||||
if (event == POST_RATE_CHANGE) {
|
||||
serial8250_update_uartclk(&port8250->port, ndata->new_rate);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill a struct uart_port for a given device node
|
||||
*/
|
||||
@ -218,7 +240,19 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
|
||||
info->type = port_type;
|
||||
info->line = ret;
|
||||
platform_set_drvdata(ofdev, info);
|
||||
|
||||
if (info->clk) {
|
||||
info->clk_notifier.notifier_call = of_platform_serial_clk_notifier_cb;
|
||||
ret = clk_notifier_register(info->clk, &info->clk_notifier);
|
||||
if (ret) {
|
||||
dev_err_probe(port8250.port.dev, ret, "Failed to set the clock notifier\n");
|
||||
goto err_unregister;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
err_unregister:
|
||||
serial8250_unregister_port(info->line);
|
||||
err_dispose:
|
||||
pm_runtime_put_sync(&ofdev->dev);
|
||||
pm_runtime_disable(&ofdev->dev);
|
||||
@ -234,6 +268,9 @@ static void of_platform_serial_remove(struct platform_device *ofdev)
|
||||
{
|
||||
struct of_serial_info *info = platform_get_drvdata(ofdev);
|
||||
|
||||
if (info->clk)
|
||||
clk_notifier_unregister(info->clk, &info->clk_notifier);
|
||||
|
||||
serial8250_unregister_port(info->line);
|
||||
|
||||
reset_control_assert(info->rst);
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
@ -1094,7 +1093,7 @@ static void omap_8250_dma_tx_complete(void *param)
|
||||
{
|
||||
struct uart_8250_port *p = param;
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
struct circ_buf *xmit = &p->port.state->xmit;
|
||||
struct tty_port *tport = &p->port.state->port;
|
||||
unsigned long flags;
|
||||
bool en_thri = false;
|
||||
struct omap8250_priv *priv = p->port.private_data;
|
||||
@ -1113,10 +1112,10 @@ static void omap_8250_dma_tx_complete(void *param)
|
||||
omap8250_restore_regs(p);
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&p->port);
|
||||
|
||||
if (!uart_circ_empty(xmit) && !uart_tx_stopped(&p->port)) {
|
||||
if (!kfifo_is_empty(&tport->xmit_fifo) && !uart_tx_stopped(&p->port)) {
|
||||
int ret;
|
||||
|
||||
ret = omap_8250_tx_dma(p);
|
||||
@ -1138,14 +1137,15 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
|
||||
{
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
struct omap8250_priv *priv = p->port.private_data;
|
||||
struct circ_buf *xmit = &p->port.state->xmit;
|
||||
struct tty_port *tport = &p->port.state->port;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
unsigned int skip_byte = 0;
|
||||
struct scatterlist sg;
|
||||
int skip_byte = -1;
|
||||
int ret;
|
||||
|
||||
if (dma->tx_running)
|
||||
return 0;
|
||||
if (uart_tx_stopped(&p->port) || uart_circ_empty(xmit)) {
|
||||
if (uart_tx_stopped(&p->port) || kfifo_is_empty(&tport->xmit_fifo)) {
|
||||
|
||||
/*
|
||||
* Even if no data, we need to return an error for the two cases
|
||||
@ -1160,8 +1160,18 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
|
||||
return 0;
|
||||
}
|
||||
|
||||
dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
|
||||
sg_init_table(&sg, 1);
|
||||
ret = kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, &sg, 1,
|
||||
UART_XMIT_SIZE, dma->tx_addr);
|
||||
if (ret != 1) {
|
||||
serial8250_clear_THRI(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dma->tx_size = sg_dma_len(&sg);
|
||||
|
||||
if (priv->habit & OMAP_DMA_TX_KICK) {
|
||||
unsigned char c;
|
||||
u8 tx_lvl;
|
||||
|
||||
/*
|
||||
@ -1188,12 +1198,17 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
skip_byte = 1;
|
||||
if (!kfifo_get(&tport->xmit_fifo, &c)) {
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
skip_byte = c;
|
||||
/* now we need to recompute due to kfifo_get */
|
||||
kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, &sg, 1,
|
||||
UART_XMIT_SIZE, dma->tx_addr);
|
||||
}
|
||||
|
||||
desc = dmaengine_prep_slave_single(dma->txchan,
|
||||
dma->tx_addr + xmit->tail + skip_byte,
|
||||
dma->tx_size - skip_byte, DMA_MEM_TO_DEV,
|
||||
desc = dmaengine_prep_slave_sg(dma->txchan, &sg, 1, DMA_MEM_TO_DEV,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (!desc) {
|
||||
ret = -EBUSY;
|
||||
@ -1215,11 +1230,13 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
|
||||
dma->tx_err = 0;
|
||||
|
||||
serial8250_clear_THRI(p);
|
||||
if (skip_byte)
|
||||
serial_out(p, UART_TX, xmit->buf[xmit->tail]);
|
||||
return 0;
|
||||
ret = 0;
|
||||
goto out_skip;
|
||||
err:
|
||||
dma->tx_err = 1;
|
||||
out_skip:
|
||||
if (skip_byte >= 0)
|
||||
serial_out(p, UART_TX, skip_byte);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1308,7 +1325,7 @@ static int omap_8250_dma_handle_irq(struct uart_port *port)
|
||||
serial8250_modem_status(up);
|
||||
if (status & UART_LSR_THRE && up->dma->tx_err) {
|
||||
if (uart_tx_stopped(&up->port) ||
|
||||
uart_circ_empty(&up->port.state->xmit)) {
|
||||
kfifo_is_empty(&up->port.state->port.xmit_fifo)) {
|
||||
up->dma->tx_err = 0;
|
||||
serial8250_tx_chars(up);
|
||||
} else {
|
||||
|
@ -382,10 +382,10 @@ static void pci1xxxx_rx_burst(struct uart_port *port, u32 uart_status)
|
||||
}
|
||||
|
||||
static void pci1xxxx_process_write_data(struct uart_port *port,
|
||||
struct circ_buf *xmit,
|
||||
int *data_empty_count,
|
||||
u32 *valid_byte_count)
|
||||
{
|
||||
struct tty_port *tport = &port->state->port;
|
||||
u32 valid_burst_count = *valid_byte_count / UART_BURST_SIZE;
|
||||
|
||||
/*
|
||||
@ -395,41 +395,36 @@ static void pci1xxxx_process_write_data(struct uart_port *port,
|
||||
* one byte at a time.
|
||||
*/
|
||||
while (valid_burst_count) {
|
||||
u32 c;
|
||||
|
||||
if (*data_empty_count - UART_BURST_SIZE < 0)
|
||||
break;
|
||||
if (xmit->tail > (UART_XMIT_SIZE - UART_BURST_SIZE))
|
||||
if (kfifo_len(&tport->xmit_fifo) < UART_BURST_SIZE)
|
||||
break;
|
||||
writel(*(unsigned int *)&xmit->buf[xmit->tail],
|
||||
port->membase + UART_TX_BURST_FIFO);
|
||||
if (WARN_ON(kfifo_out(&tport->xmit_fifo, (u8 *)&c, sizeof(c)) !=
|
||||
sizeof(c)))
|
||||
break;
|
||||
writel(c, port->membase + UART_TX_BURST_FIFO);
|
||||
*valid_byte_count -= UART_BURST_SIZE;
|
||||
*data_empty_count -= UART_BURST_SIZE;
|
||||
valid_burst_count -= UART_BYTE_SIZE;
|
||||
|
||||
xmit->tail = (xmit->tail + UART_BURST_SIZE) &
|
||||
(UART_XMIT_SIZE - 1);
|
||||
}
|
||||
|
||||
while (*valid_byte_count) {
|
||||
if (*data_empty_count - UART_BYTE_SIZE < 0)
|
||||
u8 c;
|
||||
|
||||
if (!kfifo_get(&tport->xmit_fifo, &c))
|
||||
break;
|
||||
writeb(xmit->buf[xmit->tail], port->membase +
|
||||
UART_TX_BYTE_FIFO);
|
||||
writeb(c, port->membase + UART_TX_BYTE_FIFO);
|
||||
*data_empty_count -= UART_BYTE_SIZE;
|
||||
*valid_byte_count -= UART_BYTE_SIZE;
|
||||
|
||||
/*
|
||||
* When the tail of the circular buffer is reached, the next
|
||||
* byte is transferred to the beginning of the buffer.
|
||||
*/
|
||||
xmit->tail = (xmit->tail + UART_BYTE_SIZE) &
|
||||
(UART_XMIT_SIZE - 1);
|
||||
|
||||
/*
|
||||
* If there are any pending burst count, data is handled by
|
||||
* transmitting DWORDs at a time.
|
||||
*/
|
||||
if (valid_burst_count && (xmit->tail <
|
||||
(UART_XMIT_SIZE - UART_BURST_SIZE)))
|
||||
if (valid_burst_count &&
|
||||
kfifo_len(&tport->xmit_fifo) >= UART_BURST_SIZE)
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -437,11 +432,9 @@ static void pci1xxxx_process_write_data(struct uart_port *port,
|
||||
static void pci1xxxx_tx_burst(struct uart_port *port, u32 uart_status)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
struct tty_port *tport = &port->state->port;
|
||||
u32 valid_byte_count;
|
||||
int data_empty_count;
|
||||
struct circ_buf *xmit;
|
||||
|
||||
xmit = &port->state->xmit;
|
||||
|
||||
if (port->x_char) {
|
||||
writeb(port->x_char, port->membase + UART_TX);
|
||||
@ -450,25 +443,25 @@ static void pci1xxxx_tx_burst(struct uart_port *port, u32 uart_status)
|
||||
return;
|
||||
}
|
||||
|
||||
if ((uart_tx_stopped(port)) || (uart_circ_empty(xmit))) {
|
||||
if ((uart_tx_stopped(port)) || kfifo_is_empty(&tport->xmit_fifo)) {
|
||||
port->ops->stop_tx(port);
|
||||
} else {
|
||||
data_empty_count = (pci1xxxx_read_burst_status(port) &
|
||||
UART_BST_STAT_TX_COUNT_MASK) >> 8;
|
||||
do {
|
||||
valid_byte_count = uart_circ_chars_pending(xmit);
|
||||
valid_byte_count = kfifo_len(&tport->xmit_fifo);
|
||||
|
||||
pci1xxxx_process_write_data(port, xmit,
|
||||
pci1xxxx_process_write_data(port,
|
||||
&data_empty_count,
|
||||
&valid_byte_count);
|
||||
|
||||
port->icount.tx++;
|
||||
if (uart_circ_empty(xmit))
|
||||
if (kfifo_is_empty(&tport->xmit_fifo))
|
||||
break;
|
||||
} while (data_empty_count && valid_byte_count);
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
/*
|
||||
@ -476,7 +469,8 @@ static void pci1xxxx_tx_burst(struct uart_port *port, u32 uart_status)
|
||||
* the HW can go idle. So we get here once again with empty FIFO and
|
||||
* disable the interrupt and RPM in __stop_tx()
|
||||
*/
|
||||
if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM))
|
||||
if (kfifo_is_empty(&tport->xmit_fifo) &&
|
||||
!(up->capabilities & UART_CAP_RPM))
|
||||
port->ops->stop_tx(port);
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pnp.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kernel.h>
|
||||
@ -434,7 +435,9 @@ static int
|
||||
serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
|
||||
{
|
||||
struct uart_8250_port uart, *port;
|
||||
int ret, line, flags = dev_id->driver_data;
|
||||
int ret, flags = dev_id->driver_data;
|
||||
unsigned char iotype;
|
||||
long line;
|
||||
|
||||
if (flags & UNKNOWN_DEV) {
|
||||
ret = serial_pnp_guess_board(dev);
|
||||
@ -443,37 +446,46 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
|
||||
}
|
||||
|
||||
memset(&uart, 0, sizeof(uart));
|
||||
if (pnp_irq_valid(dev, 0))
|
||||
uart.port.irq = pnp_irq(dev, 0);
|
||||
if ((flags & CIR_PORT) && pnp_port_valid(dev, 2)) {
|
||||
uart.port.iobase = pnp_port_start(dev, 2);
|
||||
uart.port.iotype = UPIO_PORT;
|
||||
iotype = UPIO_PORT;
|
||||
} else if (pnp_port_valid(dev, 0)) {
|
||||
uart.port.iobase = pnp_port_start(dev, 0);
|
||||
uart.port.iotype = UPIO_PORT;
|
||||
iotype = UPIO_PORT;
|
||||
} else if (pnp_mem_valid(dev, 0)) {
|
||||
uart.port.mapbase = pnp_mem_start(dev, 0);
|
||||
uart.port.iotype = UPIO_MEM;
|
||||
uart.port.mapsize = pnp_mem_len(dev, 0);
|
||||
iotype = UPIO_MEM;
|
||||
uart.port.flags = UPF_IOREMAP;
|
||||
} else
|
||||
return -ENODEV;
|
||||
|
||||
dev_dbg(&dev->dev,
|
||||
"Setup PNP port: port %#lx, mem %#llx, irq %u, type %u\n",
|
||||
uart.port.iobase, (unsigned long long)uart.port.mapbase,
|
||||
uart.port.irq, uart.port.iotype);
|
||||
uart.port.uartclk = 1843200;
|
||||
uart.port.dev = &dev->dev;
|
||||
uart.port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
|
||||
|
||||
ret = uart_read_port_properties(&uart.port);
|
||||
/* no interrupt -> fall back to polling */
|
||||
if (ret == -ENXIO)
|
||||
ret = 0;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* The previous call may not set iotype correctly when reg-io-width
|
||||
* property is absent and it doesn't support IO port resource.
|
||||
*/
|
||||
uart.port.iotype = iotype;
|
||||
|
||||
if (flags & CIR_PORT) {
|
||||
uart.port.flags |= UPF_FIXED_PORT | UPF_FIXED_TYPE;
|
||||
uart.port.type = PORT_8250_CIR;
|
||||
}
|
||||
|
||||
uart.port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
|
||||
if (pnp_irq_flags(dev, 0) & IORESOURCE_IRQ_SHAREABLE)
|
||||
uart.port.flags |= UPF_SHARE_IRQ;
|
||||
uart.port.uartclk = 1843200;
|
||||
device_property_read_u32(&dev->dev, "clock-frequency", &uart.port.uartclk);
|
||||
uart.port.dev = &dev->dev;
|
||||
dev_dbg(&dev->dev,
|
||||
"Setup PNP port: port %#lx, mem %#llx, size %#llx, irq %u, type %u\n",
|
||||
uart.port.iobase, (unsigned long long)uart.port.mapbase,
|
||||
(unsigned long long)uart.port.mapsize, uart.port.irq, uart.port.iotype);
|
||||
|
||||
line = serial8250_register_8250_port(&uart);
|
||||
if (line < 0 || (flags & CIR_PORT))
|
||||
@ -483,7 +495,7 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
|
||||
if (uart_console(&port->port))
|
||||
dev->capabilities |= PNP_CONSOLE;
|
||||
|
||||
pnp_set_drvdata(dev, (void *)((long)line + 1));
|
||||
pnp_set_drvdata(dev, (void *)line);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -492,38 +504,33 @@ static void serial_pnp_remove(struct pnp_dev *dev)
|
||||
long line = (long)pnp_get_drvdata(dev);
|
||||
|
||||
dev->capabilities &= ~PNP_CONSOLE;
|
||||
if (line)
|
||||
serial8250_unregister_port(line - 1);
|
||||
serial8250_unregister_port(line);
|
||||
}
|
||||
|
||||
static int __maybe_unused serial_pnp_suspend(struct device *dev)
|
||||
static int serial_pnp_suspend(struct device *dev)
|
||||
{
|
||||
long line = (long)dev_get_drvdata(dev);
|
||||
|
||||
if (!line)
|
||||
return -ENODEV;
|
||||
serial8250_suspend_port(line - 1);
|
||||
serial8250_suspend_port(line);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused serial_pnp_resume(struct device *dev)
|
||||
static int serial_pnp_resume(struct device *dev)
|
||||
{
|
||||
long line = (long)dev_get_drvdata(dev);
|
||||
|
||||
if (!line)
|
||||
return -ENODEV;
|
||||
serial8250_resume_port(line - 1);
|
||||
serial8250_resume_port(line);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(serial_pnp_pm_ops, serial_pnp_suspend, serial_pnp_resume);
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(serial_pnp_pm_ops, serial_pnp_suspend, serial_pnp_resume);
|
||||
|
||||
static struct pnp_driver serial_pnp_driver = {
|
||||
.name = "serial",
|
||||
.probe = serial_pnp_probe,
|
||||
.remove = serial_pnp_remove,
|
||||
.driver = {
|
||||
.pm = &serial_pnp_pm_ops,
|
||||
.pm = pm_sleep_ptr(&serial_pnp_pm_ops),
|
||||
},
|
||||
.id_table = pnp_dev_table,
|
||||
};
|
||||
|
@ -612,13 +612,6 @@ int serial8250_em485_config(struct uart_port *port, struct ktermios *termios,
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
|
||||
/* pick sane settings if the user hasn't */
|
||||
if (!!(rs485->flags & SER_RS485_RTS_ON_SEND) ==
|
||||
!!(rs485->flags & SER_RS485_RTS_AFTER_SEND)) {
|
||||
rs485->flags |= SER_RS485_RTS_ON_SEND;
|
||||
rs485->flags &= ~SER_RS485_RTS_AFTER_SEND;
|
||||
}
|
||||
|
||||
/*
|
||||
* Both serial8250_em485_init() and serial8250_em485_destroy()
|
||||
* are idempotent.
|
||||
@ -1630,7 +1623,7 @@ static void serial8250_start_tx(struct uart_port *port)
|
||||
/* Port locked to synchronize UART_IER access against the console. */
|
||||
lockdep_assert_held_once(&port->lock);
|
||||
|
||||
if (!port->x_char && uart_circ_empty(&port->state->xmit))
|
||||
if (!port->x_char && kfifo_is_empty(&port->state->port.xmit_fifo))
|
||||
return;
|
||||
|
||||
serial8250_rpm_get_tx(up);
|
||||
@ -1778,7 +1771,7 @@ EXPORT_SYMBOL_GPL(serial8250_rx_chars);
|
||||
void serial8250_tx_chars(struct uart_8250_port *up)
|
||||
{
|
||||
struct uart_port *port = &up->port;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
int count;
|
||||
|
||||
if (port->x_char) {
|
||||
@ -1789,14 +1782,19 @@ void serial8250_tx_chars(struct uart_8250_port *up)
|
||||
serial8250_stop_tx(port);
|
||||
return;
|
||||
}
|
||||
if (uart_circ_empty(xmit)) {
|
||||
if (kfifo_is_empty(&tport->xmit_fifo)) {
|
||||
__stop_tx(up);
|
||||
return;
|
||||
}
|
||||
|
||||
count = up->tx_loadsz;
|
||||
do {
|
||||
serial_out(up, UART_TX, xmit->buf[xmit->tail]);
|
||||
unsigned char c;
|
||||
|
||||
if (!uart_fifo_get(port, &c))
|
||||
break;
|
||||
|
||||
serial_out(up, UART_TX, c);
|
||||
if (up->bugs & UART_BUG_TXRACE) {
|
||||
/*
|
||||
* The Aspeed BMC virtual UARTs have a bug where data
|
||||
@ -1809,9 +1807,7 @@ void serial8250_tx_chars(struct uart_8250_port *up)
|
||||
*/
|
||||
serial_in(up, UART_SCR);
|
||||
}
|
||||
uart_xmit_advance(port, 1);
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
|
||||
if ((up->capabilities & UART_CAP_HFIFO) &&
|
||||
!uart_lsr_tx_empty(serial_in(up, UART_LSR)))
|
||||
break;
|
||||
@ -1821,7 +1817,7 @@ void serial8250_tx_chars(struct uart_8250_port *up)
|
||||
break;
|
||||
} while (--count > 0);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
/*
|
||||
@ -1829,7 +1825,8 @@ void serial8250_tx_chars(struct uart_8250_port *up)
|
||||
* HW can go idle. So we get here once again with empty FIFO and disable
|
||||
* the interrupt and RPM in __stop_tx()
|
||||
*/
|
||||
if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM))
|
||||
if (kfifo_is_empty(&tport->xmit_fifo) &&
|
||||
!(up->capabilities & UART_CAP_RPM))
|
||||
__stop_tx(up);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_tx_chars);
|
||||
|
@ -307,11 +307,14 @@ config SERIAL_TEGRA_TCU_CONSOLE
|
||||
If unsure, say Y.
|
||||
|
||||
config SERIAL_MAX3100
|
||||
tristate "MAX3100 support"
|
||||
tristate "MAX3100/3110/3111/3222 support"
|
||||
depends on SPI
|
||||
select SERIAL_CORE
|
||||
help
|
||||
MAX3100 chip support
|
||||
This selects support for an advanced UART from Maxim.
|
||||
Supported ICs are MAX3100, MAX3110, MAX3111, MAX3222.
|
||||
|
||||
Say Y here if you want to support these ICs.
|
||||
|
||||
config SERIAL_MAX310X
|
||||
tristate "MAX310X support"
|
||||
@ -1021,41 +1024,30 @@ config SERIAL_SCCNXP_CONSOLE
|
||||
Support for console on SCCNXP serial ports.
|
||||
|
||||
config SERIAL_SC16IS7XX_CORE
|
||||
tristate
|
||||
|
||||
config SERIAL_SC16IS7XX
|
||||
tristate "SC16IS7xx serial support"
|
||||
tristate "NXP SC16IS7xx UART support"
|
||||
select SERIAL_CORE
|
||||
depends on (SPI_MASTER && !I2C) || I2C
|
||||
select SERIAL_SC16IS7XX_SPI if SPI_MASTER
|
||||
select SERIAL_SC16IS7XX_I2C if I2C
|
||||
help
|
||||
This selects support for SC16IS7xx serial ports.
|
||||
Supported ICs are SC16IS740, SC16IS741, SC16IS750, SC16IS752,
|
||||
SC16IS760 and SC16IS762. Select supported buses using options below.
|
||||
Core driver for NXP SC16IS7xx UARTs.
|
||||
Supported ICs are:
|
||||
|
||||
SC16IS740
|
||||
SC16IS741
|
||||
SC16IS750
|
||||
SC16IS752
|
||||
SC16IS760
|
||||
SC16IS762
|
||||
|
||||
The driver supports both I2C and SPI interfaces.
|
||||
|
||||
config SERIAL_SC16IS7XX_I2C
|
||||
bool "SC16IS7xx for I2C interface"
|
||||
depends on SERIAL_SC16IS7XX
|
||||
depends on I2C
|
||||
select SERIAL_SC16IS7XX_CORE if SERIAL_SC16IS7XX
|
||||
select REGMAP_I2C if I2C
|
||||
default y
|
||||
help
|
||||
Enable SC16IS7xx driver on I2C bus,
|
||||
If required say y, and say n to i2c if not required,
|
||||
Enabled by default to support oldconfig.
|
||||
You must select at least one bus for the driver to be built.
|
||||
tristate
|
||||
select REGMAP_I2C
|
||||
|
||||
config SERIAL_SC16IS7XX_SPI
|
||||
bool "SC16IS7xx for spi interface"
|
||||
depends on SERIAL_SC16IS7XX
|
||||
depends on SPI_MASTER
|
||||
select SERIAL_SC16IS7XX_CORE if SERIAL_SC16IS7XX
|
||||
select REGMAP_SPI if SPI_MASTER
|
||||
help
|
||||
Enable SC16IS7xx driver on SPI bus,
|
||||
If required say y, and say n to spi if not required,
|
||||
This is additional support to existing driver.
|
||||
You must select at least one bus for the driver to be built.
|
||||
tristate
|
||||
select REGMAP_SPI
|
||||
|
||||
config SERIAL_TIMBERDALE
|
||||
tristate "Support for timberdale UART"
|
||||
|
@ -76,6 +76,8 @@ obj-$(CONFIG_SERIAL_SAMSUNG) += samsung_tty.o
|
||||
obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
|
||||
obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o
|
||||
obj-$(CONFIG_SERIAL_SC16IS7XX_CORE) += sc16is7xx.o
|
||||
obj-$(CONFIG_SERIAL_SC16IS7XX_SPI) += sc16is7xx_spi.o
|
||||
obj-$(CONFIG_SERIAL_SC16IS7XX_I2C) += sc16is7xx_i2c.o
|
||||
obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
|
||||
obj-$(CONFIG_SERIAL_SIFIVE) += sifive.o
|
||||
obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
|
||||
|
@ -256,7 +256,6 @@ struct uart_amba_port {
|
||||
const u16 *reg_offset;
|
||||
struct clk *clk;
|
||||
const struct vendor_data *vendor;
|
||||
unsigned int dmacr; /* dma control reg */
|
||||
unsigned int im; /* interrupt mask */
|
||||
unsigned int old_status;
|
||||
unsigned int fifosize; /* vendor-specific */
|
||||
@ -266,6 +265,7 @@ struct uart_amba_port {
|
||||
unsigned int rs485_tx_drain_interval; /* usecs */
|
||||
#ifdef CONFIG_DMA_ENGINE
|
||||
/* DMA stuff */
|
||||
unsigned int dmacr; /* dma control reg */
|
||||
bool using_tx_dma;
|
||||
bool using_rx_dma;
|
||||
struct pl011_dmarx_data dmarx;
|
||||
@ -535,6 +535,7 @@ static void pl011_start_tx_pio(struct uart_amba_port *uap);
|
||||
static void pl011_dma_tx_callback(void *data)
|
||||
{
|
||||
struct uart_amba_port *uap = data;
|
||||
struct tty_port *tport = &uap->port.state->port;
|
||||
struct pl011_dmatx_data *dmatx = &uap->dmatx;
|
||||
unsigned long flags;
|
||||
u16 dmacr;
|
||||
@ -558,7 +559,7 @@ static void pl011_dma_tx_callback(void *data)
|
||||
* get further refills (hence we check dmacr).
|
||||
*/
|
||||
if (!(dmacr & UART011_TXDMAE) || uart_tx_stopped(&uap->port) ||
|
||||
uart_circ_empty(&uap->port.state->xmit)) {
|
||||
kfifo_is_empty(&tport->xmit_fifo)) {
|
||||
uap->dmatx.queued = false;
|
||||
uart_port_unlock_irqrestore(&uap->port, flags);
|
||||
return;
|
||||
@ -588,7 +589,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap)
|
||||
struct dma_chan *chan = dmatx->chan;
|
||||
struct dma_device *dma_dev = chan->device;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
struct circ_buf *xmit = &uap->port.state->xmit;
|
||||
struct tty_port *tport = &uap->port.state->port;
|
||||
unsigned int count;
|
||||
|
||||
/*
|
||||
@ -597,7 +598,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap)
|
||||
* the standard interrupt handling. This ensures that we
|
||||
* issue a uart_write_wakeup() at the appropriate time.
|
||||
*/
|
||||
count = uart_circ_chars_pending(xmit);
|
||||
count = kfifo_len(&tport->xmit_fifo);
|
||||
if (count < (uap->fifosize >> 1)) {
|
||||
uap->dmatx.queued = false;
|
||||
return 0;
|
||||
@ -613,21 +614,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap)
|
||||
if (count > PL011_DMA_BUFFER_SIZE)
|
||||
count = PL011_DMA_BUFFER_SIZE;
|
||||
|
||||
if (xmit->tail < xmit->head) {
|
||||
memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], count);
|
||||
} else {
|
||||
size_t first = UART_XMIT_SIZE - xmit->tail;
|
||||
size_t second;
|
||||
|
||||
if (first > count)
|
||||
first = count;
|
||||
second = count - first;
|
||||
|
||||
memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], first);
|
||||
if (second)
|
||||
memcpy(&dmatx->buf[first], &xmit->buf[0], second);
|
||||
}
|
||||
|
||||
count = kfifo_out_peek(&tport->xmit_fifo, dmatx->buf, count);
|
||||
dmatx->len = count;
|
||||
dmatx->dma = dma_map_single(dma_dev->dev, dmatx->buf, count,
|
||||
DMA_TO_DEVICE);
|
||||
@ -670,7 +657,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap)
|
||||
*/
|
||||
uart_xmit_advance(&uap->port, count);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&uap->port);
|
||||
|
||||
return 1;
|
||||
@ -1454,7 +1441,7 @@ static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c,
|
||||
/* Returns true if tx interrupts have to be (kept) enabled */
|
||||
static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq)
|
||||
{
|
||||
struct circ_buf *xmit = &uap->port.state->xmit;
|
||||
struct tty_port *tport = &uap->port.state->port;
|
||||
int count = uap->fifosize >> 1;
|
||||
|
||||
if (uap->port.x_char) {
|
||||
@ -1463,7 +1450,7 @@ static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq)
|
||||
uap->port.x_char = 0;
|
||||
--count;
|
||||
}
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) {
|
||||
if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(&uap->port)) {
|
||||
pl011_stop_tx(&uap->port);
|
||||
return false;
|
||||
}
|
||||
@ -1472,20 +1459,25 @@ static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq)
|
||||
if (pl011_dma_tx_irq(uap))
|
||||
return true;
|
||||
|
||||
do {
|
||||
while (1) {
|
||||
unsigned char c;
|
||||
|
||||
if (likely(from_irq) && count-- == 0)
|
||||
break;
|
||||
|
||||
if (!pl011_tx_char(uap, xmit->buf[xmit->tail], from_irq))
|
||||
if (!kfifo_peek(&tport->xmit_fifo, &c))
|
||||
break;
|
||||
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
} while (!uart_circ_empty(xmit));
|
||||
if (!pl011_tx_char(uap, c, from_irq))
|
||||
break;
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
kfifo_skip(&tport->xmit_fifo);
|
||||
}
|
||||
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&uap->port);
|
||||
|
||||
if (uart_circ_empty(xmit)) {
|
||||
if (kfifo_is_empty(&tport->xmit_fifo)) {
|
||||
pl011_stop_tx(&uap->port);
|
||||
return false;
|
||||
}
|
||||
@ -2700,18 +2692,6 @@ static int pl011_find_free_port(void)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
static int pl011_get_rs485_mode(struct uart_amba_port *uap)
|
||||
{
|
||||
struct uart_port *port = &uap->port;
|
||||
int ret;
|
||||
|
||||
ret = uart_get_rs485_mode(port);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap,
|
||||
struct resource *mmiobase, int index)
|
||||
{
|
||||
@ -2732,7 +2712,7 @@ static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap,
|
||||
uap->port.flags = UPF_BOOT_AUTOCONF;
|
||||
uap->port.line = index;
|
||||
|
||||
ret = pl011_get_rs485_mode(uap);
|
||||
ret = uart_get_rs485_mode(&uap->port);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -390,7 +390,7 @@ static void ar933x_uart_rx_chars(struct ar933x_uart_port *up)
|
||||
|
||||
static void ar933x_uart_tx_chars(struct ar933x_uart_port *up)
|
||||
{
|
||||
struct circ_buf *xmit = &up->port.state->xmit;
|
||||
struct tty_port *tport = &up->port.state->port;
|
||||
struct serial_rs485 *rs485conf = &up->port.rs485;
|
||||
int count;
|
||||
bool half_duplex_send = false;
|
||||
@ -399,7 +399,7 @@ static void ar933x_uart_tx_chars(struct ar933x_uart_port *up)
|
||||
return;
|
||||
|
||||
if ((rs485conf->flags & SER_RS485_ENABLED) &&
|
||||
(up->port.x_char || !uart_circ_empty(xmit))) {
|
||||
(up->port.x_char || !kfifo_is_empty(&tport->xmit_fifo))) {
|
||||
ar933x_uart_stop_rx_interrupt(up);
|
||||
gpiod_set_value(up->rts_gpiod, !!(rs485conf->flags & SER_RS485_RTS_ON_SEND));
|
||||
half_duplex_send = true;
|
||||
@ -408,6 +408,7 @@ static void ar933x_uart_tx_chars(struct ar933x_uart_port *up)
|
||||
count = up->port.fifosize;
|
||||
do {
|
||||
unsigned int rdata;
|
||||
unsigned char c;
|
||||
|
||||
rdata = ar933x_uart_read(up, AR933X_UART_DATA_REG);
|
||||
if ((rdata & AR933X_UART_DATA_TX_CSR) == 0)
|
||||
@ -420,18 +421,16 @@ static void ar933x_uart_tx_chars(struct ar933x_uart_port *up)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
if (!uart_fifo_get(&up->port, &c))
|
||||
break;
|
||||
|
||||
ar933x_uart_putc(up, xmit->buf[xmit->tail]);
|
||||
|
||||
uart_xmit_advance(&up->port, 1);
|
||||
ar933x_uart_putc(up, c);
|
||||
} while (--count > 0);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&up->port);
|
||||
|
||||
if (!uart_circ_empty(xmit)) {
|
||||
if (!kfifo_is_empty(&tport->xmit_fifo)) {
|
||||
ar933x_uart_start_tx_interrupt(up);
|
||||
} else if (half_duplex_send) {
|
||||
ar933x_uart_wait_tx_complete(up);
|
||||
@ -693,7 +692,6 @@ static struct uart_driver ar933x_uart_driver = {
|
||||
.cons = NULL, /* filled in runtime */
|
||||
};
|
||||
|
||||
static const struct serial_rs485 ar933x_no_rs485 = {};
|
||||
static const struct serial_rs485 ar933x_rs485_supported = {
|
||||
.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND,
|
||||
};
|
||||
@ -789,7 +787,7 @@ static int ar933x_uart_probe(struct platform_device *pdev)
|
||||
up->rts_gpiod = mctrl_gpio_to_gpiod(up->gpios, UART_GPIO_RTS);
|
||||
|
||||
if (!up->rts_gpiod) {
|
||||
port->rs485_supported = ar933x_no_rs485;
|
||||
port->rs485_supported.flags &= ~SER_RS485_ENABLED;
|
||||
if (port->rs485.flags & SER_RS485_ENABLED) {
|
||||
dev_err(&pdev->dev, "lacking rts-gpio, disabling RS485\n");
|
||||
port->rs485.flags &= ~SER_RS485_ENABLED;
|
||||
|
@ -155,7 +155,7 @@ static unsigned int arc_serial_tx_empty(struct uart_port *port)
|
||||
*/
|
||||
static void arc_serial_tx_chars(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
int sent = 0;
|
||||
unsigned char ch;
|
||||
|
||||
@ -164,9 +164,7 @@ static void arc_serial_tx_chars(struct uart_port *port)
|
||||
port->icount.tx++;
|
||||
port->x_char = 0;
|
||||
sent = 1;
|
||||
} else if (!uart_circ_empty(xmit)) {
|
||||
ch = xmit->buf[xmit->tail];
|
||||
uart_xmit_advance(port, 1);
|
||||
} else if (uart_fifo_get(port, &ch)) {
|
||||
while (!(UART_GET_STATUS(port) & TXEMPTY))
|
||||
cpu_relax();
|
||||
UART_SET_DATA(port, ch);
|
||||
@ -177,7 +175,7 @@ static void arc_serial_tx_chars(struct uart_port *port)
|
||||
* If num chars in xmit buffer are too few, ask tty layer for more.
|
||||
* By Hard ISR to schedule processing in software interrupt part
|
||||
*/
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (sent)
|
||||
|
@ -96,7 +96,9 @@ struct atmel_uart_char {
|
||||
* can contain up to 1024 characters in PIO mode and up to 4096 characters in
|
||||
* DMA mode.
|
||||
*/
|
||||
#define ATMEL_SERIAL_RINGSIZE 1024
|
||||
#define ATMEL_SERIAL_RINGSIZE 1024
|
||||
#define ATMEL_SERIAL_RX_SIZE array_size(sizeof(struct atmel_uart_char), \
|
||||
ATMEL_SERIAL_RINGSIZE)
|
||||
|
||||
/*
|
||||
* at91: 6 USARTs and one DBGU port (SAM9260)
|
||||
@ -132,8 +134,8 @@ struct atmel_uart_port {
|
||||
struct dma_async_tx_descriptor *desc_rx;
|
||||
dma_cookie_t cookie_tx;
|
||||
dma_cookie_t cookie_rx;
|
||||
struct scatterlist sg_tx;
|
||||
struct scatterlist sg_rx;
|
||||
dma_addr_t tx_phys;
|
||||
dma_addr_t rx_phys;
|
||||
struct tasklet_struct tasklet_rx;
|
||||
struct tasklet_struct tasklet_tx;
|
||||
atomic_t tasklet_shutdown;
|
||||
@ -857,7 +859,7 @@ static void atmel_complete_tx_dma(void *arg)
|
||||
{
|
||||
struct atmel_uart_port *atmel_port = arg;
|
||||
struct uart_port *port = &atmel_port->uart;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
struct dma_chan *chan = atmel_port->chan_tx;
|
||||
unsigned long flags;
|
||||
|
||||
@ -873,15 +875,15 @@ static void atmel_complete_tx_dma(void *arg)
|
||||
atmel_port->desc_tx = NULL;
|
||||
spin_unlock(&atmel_port->lock_tx);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
/*
|
||||
* xmit is a circular buffer so, if we have just send data from
|
||||
* xmit->tail to the end of xmit->buf, now we have to transmit the
|
||||
* remaining data from the beginning of xmit->buf to xmit->head.
|
||||
* xmit is a circular buffer so, if we have just send data from the
|
||||
* tail to the end, now we have to transmit the remaining data from the
|
||||
* beginning to the head.
|
||||
*/
|
||||
if (!uart_circ_empty(xmit))
|
||||
if (!kfifo_is_empty(&tport->xmit_fifo))
|
||||
atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx);
|
||||
else if (atmel_uart_is_half_duplex(port)) {
|
||||
/*
|
||||
@ -904,8 +906,8 @@ static void atmel_release_tx_dma(struct uart_port *port)
|
||||
if (chan) {
|
||||
dmaengine_terminate_all(chan);
|
||||
dma_release_channel(chan);
|
||||
dma_unmap_sg(port->dev, &atmel_port->sg_tx, 1,
|
||||
DMA_TO_DEVICE);
|
||||
dma_unmap_single(port->dev, atmel_port->tx_phys,
|
||||
UART_XMIT_SIZE, DMA_TO_DEVICE);
|
||||
}
|
||||
|
||||
atmel_port->desc_tx = NULL;
|
||||
@ -919,18 +921,18 @@ static void atmel_release_tx_dma(struct uart_port *port)
|
||||
static void atmel_tx_dma(struct uart_port *port)
|
||||
{
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
struct dma_chan *chan = atmel_port->chan_tx;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
struct scatterlist sgl[2], *sg, *sg_tx = &atmel_port->sg_tx;
|
||||
unsigned int tx_len, part1_len, part2_len, sg_len;
|
||||
struct scatterlist sgl[2], *sg;
|
||||
unsigned int tx_len, tail, part1_len, part2_len, sg_len;
|
||||
dma_addr_t phys_addr;
|
||||
|
||||
/* Make sure we have an idle channel */
|
||||
if (atmel_port->desc_tx != NULL)
|
||||
return;
|
||||
|
||||
if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) {
|
||||
if (!kfifo_is_empty(&tport->xmit_fifo) && !uart_tx_stopped(port)) {
|
||||
/*
|
||||
* DMA is idle now.
|
||||
* Port xmit buffer is already mapped,
|
||||
@ -940,9 +942,8 @@ static void atmel_tx_dma(struct uart_port *port)
|
||||
* Take the port lock to get a
|
||||
* consistent xmit buffer state.
|
||||
*/
|
||||
tx_len = CIRC_CNT_TO_END(xmit->head,
|
||||
xmit->tail,
|
||||
UART_XMIT_SIZE);
|
||||
tx_len = kfifo_out_linear(&tport->xmit_fifo, &tail,
|
||||
UART_XMIT_SIZE);
|
||||
|
||||
if (atmel_port->fifo_size) {
|
||||
/* multi data mode */
|
||||
@ -956,7 +957,7 @@ static void atmel_tx_dma(struct uart_port *port)
|
||||
|
||||
sg_init_table(sgl, 2);
|
||||
sg_len = 0;
|
||||
phys_addr = sg_dma_address(sg_tx) + xmit->tail;
|
||||
phys_addr = atmel_port->tx_phys + tail;
|
||||
if (part1_len) {
|
||||
sg = &sgl[sg_len++];
|
||||
sg_dma_address(sg) = phys_addr;
|
||||
@ -973,7 +974,7 @@ static void atmel_tx_dma(struct uart_port *port)
|
||||
|
||||
/*
|
||||
* save tx_len so atmel_complete_tx_dma() will increase
|
||||
* xmit->tail correctly
|
||||
* tail correctly
|
||||
*/
|
||||
atmel_port->tx_len = tx_len;
|
||||
|
||||
@ -988,7 +989,8 @@ static void atmel_tx_dma(struct uart_port *port)
|
||||
return;
|
||||
}
|
||||
|
||||
dma_sync_sg_for_device(port->dev, sg_tx, 1, DMA_TO_DEVICE);
|
||||
dma_sync_single_for_device(port->dev, atmel_port->tx_phys,
|
||||
UART_XMIT_SIZE, DMA_TO_DEVICE);
|
||||
|
||||
atmel_port->desc_tx = desc;
|
||||
desc->callback = atmel_complete_tx_dma;
|
||||
@ -1003,18 +1005,19 @@ static void atmel_tx_dma(struct uart_port *port)
|
||||
dma_async_issue_pending(chan);
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
}
|
||||
|
||||
static int atmel_prepare_tx_dma(struct uart_port *port)
|
||||
{
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
struct tty_port *tport = &port->state->port;
|
||||
struct device *mfd_dev = port->dev->parent;
|
||||
dma_cap_mask_t mask;
|
||||
struct dma_slave_config config;
|
||||
struct dma_chan *chan;
|
||||
int ret, nent;
|
||||
int ret;
|
||||
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
@ -1029,26 +1032,18 @@ static int atmel_prepare_tx_dma(struct uart_port *port)
|
||||
dma_chan_name(atmel_port->chan_tx));
|
||||
|
||||
spin_lock_init(&atmel_port->lock_tx);
|
||||
sg_init_table(&atmel_port->sg_tx, 1);
|
||||
/* UART circular tx buffer is an aligned page. */
|
||||
BUG_ON(!PAGE_ALIGNED(port->state->xmit.buf));
|
||||
sg_set_page(&atmel_port->sg_tx,
|
||||
virt_to_page(port->state->xmit.buf),
|
||||
UART_XMIT_SIZE,
|
||||
offset_in_page(port->state->xmit.buf));
|
||||
nent = dma_map_sg(port->dev,
|
||||
&atmel_port->sg_tx,
|
||||
1,
|
||||
DMA_TO_DEVICE);
|
||||
BUG_ON(!PAGE_ALIGNED(tport->xmit_buf));
|
||||
atmel_port->tx_phys = dma_map_single(port->dev, tport->xmit_buf,
|
||||
UART_XMIT_SIZE, DMA_TO_DEVICE);
|
||||
|
||||
if (!nent) {
|
||||
if (dma_mapping_error(port->dev, atmel_port->tx_phys)) {
|
||||
dev_dbg(port->dev, "need to release resource of dma\n");
|
||||
goto chan_err;
|
||||
} else {
|
||||
dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n", __func__,
|
||||
sg_dma_len(&atmel_port->sg_tx),
|
||||
port->state->xmit.buf,
|
||||
&sg_dma_address(&atmel_port->sg_tx));
|
||||
dev_dbg(port->dev, "%s: mapped %lu@%p to %pad\n", __func__,
|
||||
UART_XMIT_SIZE, tport->xmit_buf,
|
||||
&atmel_port->tx_phys);
|
||||
}
|
||||
|
||||
/* Configure the slave DMA */
|
||||
@ -1093,8 +1088,8 @@ static void atmel_release_rx_dma(struct uart_port *port)
|
||||
if (chan) {
|
||||
dmaengine_terminate_all(chan);
|
||||
dma_release_channel(chan);
|
||||
dma_unmap_sg(port->dev, &atmel_port->sg_rx, 1,
|
||||
DMA_FROM_DEVICE);
|
||||
dma_unmap_single(port->dev, atmel_port->rx_phys,
|
||||
ATMEL_SERIAL_RX_SIZE, DMA_FROM_DEVICE);
|
||||
}
|
||||
|
||||
atmel_port->desc_rx = NULL;
|
||||
@ -1127,10 +1122,8 @@ static void atmel_rx_from_dma(struct uart_port *port)
|
||||
}
|
||||
|
||||
/* CPU claims ownership of RX DMA buffer */
|
||||
dma_sync_sg_for_cpu(port->dev,
|
||||
&atmel_port->sg_rx,
|
||||
1,
|
||||
DMA_FROM_DEVICE);
|
||||
dma_sync_single_for_cpu(port->dev, atmel_port->rx_phys,
|
||||
ATMEL_SERIAL_RX_SIZE, DMA_FROM_DEVICE);
|
||||
|
||||
/*
|
||||
* ring->head points to the end of data already written by the DMA.
|
||||
@ -1139,8 +1132,8 @@ static void atmel_rx_from_dma(struct uart_port *port)
|
||||
* The current transfer size should not be larger than the dma buffer
|
||||
* length.
|
||||
*/
|
||||
ring->head = sg_dma_len(&atmel_port->sg_rx) - state.residue;
|
||||
BUG_ON(ring->head > sg_dma_len(&atmel_port->sg_rx));
|
||||
ring->head = ATMEL_SERIAL_RX_SIZE - state.residue;
|
||||
BUG_ON(ring->head > ATMEL_SERIAL_RX_SIZE);
|
||||
/*
|
||||
* At this point ring->head may point to the first byte right after the
|
||||
* last byte of the dma buffer:
|
||||
@ -1154,7 +1147,7 @@ static void atmel_rx_from_dma(struct uart_port *port)
|
||||
* tail to the end of the buffer then reset tail.
|
||||
*/
|
||||
if (ring->head < ring->tail) {
|
||||
count = sg_dma_len(&atmel_port->sg_rx) - ring->tail;
|
||||
count = ATMEL_SERIAL_RX_SIZE - ring->tail;
|
||||
|
||||
tty_insert_flip_string(tport, ring->buf + ring->tail, count);
|
||||
ring->tail = 0;
|
||||
@ -1167,17 +1160,15 @@ static void atmel_rx_from_dma(struct uart_port *port)
|
||||
|
||||
tty_insert_flip_string(tport, ring->buf + ring->tail, count);
|
||||
/* Wrap ring->head if needed */
|
||||
if (ring->head >= sg_dma_len(&atmel_port->sg_rx))
|
||||
if (ring->head >= ATMEL_SERIAL_RX_SIZE)
|
||||
ring->head = 0;
|
||||
ring->tail = ring->head;
|
||||
port->icount.rx += count;
|
||||
}
|
||||
|
||||
/* USART retreives ownership of RX DMA buffer */
|
||||
dma_sync_sg_for_device(port->dev,
|
||||
&atmel_port->sg_rx,
|
||||
1,
|
||||
DMA_FROM_DEVICE);
|
||||
dma_sync_single_for_device(port->dev, atmel_port->rx_phys,
|
||||
ATMEL_SERIAL_RX_SIZE, DMA_FROM_DEVICE);
|
||||
|
||||
tty_flip_buffer_push(tport);
|
||||
|
||||
@ -1193,7 +1184,7 @@ static int atmel_prepare_rx_dma(struct uart_port *port)
|
||||
struct dma_slave_config config;
|
||||
struct circ_buf *ring;
|
||||
struct dma_chan *chan;
|
||||
int ret, nent;
|
||||
int ret;
|
||||
|
||||
ring = &atmel_port->rx_ring;
|
||||
|
||||
@ -1210,26 +1201,18 @@ static int atmel_prepare_rx_dma(struct uart_port *port)
|
||||
dma_chan_name(atmel_port->chan_rx));
|
||||
|
||||
spin_lock_init(&atmel_port->lock_rx);
|
||||
sg_init_table(&atmel_port->sg_rx, 1);
|
||||
/* UART circular rx buffer is an aligned page. */
|
||||
BUG_ON(!PAGE_ALIGNED(ring->buf));
|
||||
sg_set_page(&atmel_port->sg_rx,
|
||||
virt_to_page(ring->buf),
|
||||
sizeof(struct atmel_uart_char) * ATMEL_SERIAL_RINGSIZE,
|
||||
offset_in_page(ring->buf));
|
||||
nent = dma_map_sg(port->dev,
|
||||
&atmel_port->sg_rx,
|
||||
1,
|
||||
DMA_FROM_DEVICE);
|
||||
atmel_port->rx_phys = dma_map_single(port->dev, ring->buf,
|
||||
ATMEL_SERIAL_RX_SIZE,
|
||||
DMA_FROM_DEVICE);
|
||||
|
||||
if (!nent) {
|
||||
if (dma_mapping_error(port->dev, atmel_port->rx_phys)) {
|
||||
dev_dbg(port->dev, "need to release resource of dma\n");
|
||||
goto chan_err;
|
||||
} else {
|
||||
dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n", __func__,
|
||||
sg_dma_len(&atmel_port->sg_rx),
|
||||
ring->buf,
|
||||
&sg_dma_address(&atmel_port->sg_rx));
|
||||
dev_dbg(port->dev, "%s: mapped %zu@%p to %pad\n", __func__,
|
||||
ATMEL_SERIAL_RX_SIZE, ring->buf, &atmel_port->rx_phys);
|
||||
}
|
||||
|
||||
/* Configure the slave DMA */
|
||||
@ -1250,9 +1233,9 @@ static int atmel_prepare_rx_dma(struct uart_port *port)
|
||||
* each one is half ring buffer size
|
||||
*/
|
||||
desc = dmaengine_prep_dma_cyclic(atmel_port->chan_rx,
|
||||
sg_dma_address(&atmel_port->sg_rx),
|
||||
sg_dma_len(&atmel_port->sg_rx),
|
||||
sg_dma_len(&atmel_port->sg_rx)/2,
|
||||
atmel_port->rx_phys,
|
||||
ATMEL_SERIAL_RX_SIZE,
|
||||
ATMEL_SERIAL_RX_SIZE / 2,
|
||||
DMA_DEV_TO_MEM,
|
||||
DMA_PREP_INTERRUPT);
|
||||
if (!desc) {
|
||||
@ -1459,9 +1442,8 @@ static void atmel_release_tx_pdc(struct uart_port *port)
|
||||
static void atmel_tx_pdc(struct uart_port *port)
|
||||
{
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
|
||||
int count;
|
||||
|
||||
/* nothing left to transmit? */
|
||||
if (atmel_uart_readl(port, ATMEL_PDC_TCR))
|
||||
@ -1474,17 +1456,19 @@ static void atmel_tx_pdc(struct uart_port *port)
|
||||
/* disable PDC transmit */
|
||||
atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS);
|
||||
|
||||
if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) {
|
||||
if (!kfifo_is_empty(&tport->xmit_fifo) && !uart_tx_stopped(port)) {
|
||||
unsigned int count, tail;
|
||||
|
||||
dma_sync_single_for_device(port->dev,
|
||||
pdc->dma_addr,
|
||||
pdc->dma_size,
|
||||
DMA_TO_DEVICE);
|
||||
|
||||
count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
|
||||
count = kfifo_out_linear(&tport->xmit_fifo, &tail,
|
||||
UART_XMIT_SIZE);
|
||||
pdc->ofs = count;
|
||||
|
||||
atmel_uart_writel(port, ATMEL_PDC_TPR,
|
||||
pdc->dma_addr + xmit->tail);
|
||||
atmel_uart_writel(port, ATMEL_PDC_TPR, pdc->dma_addr + tail);
|
||||
atmel_uart_writel(port, ATMEL_PDC_TCR, count);
|
||||
/* re-enable PDC transmit */
|
||||
atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN);
|
||||
@ -1498,7 +1482,7 @@ static void atmel_tx_pdc(struct uart_port *port)
|
||||
}
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
}
|
||||
|
||||
@ -1506,9 +1490,9 @@ static int atmel_prepare_tx_pdc(struct uart_port *port)
|
||||
{
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
|
||||
pdc->buf = xmit->buf;
|
||||
pdc->buf = tport->xmit_buf;
|
||||
pdc->dma_addr = dma_map_single(port->dev,
|
||||
pdc->buf,
|
||||
UART_XMIT_SIZE,
|
||||
@ -2953,9 +2937,7 @@ static int atmel_serial_probe(struct platform_device *pdev)
|
||||
|
||||
if (!atmel_use_pdc_rx(&atmel_port->uart)) {
|
||||
ret = -ENOMEM;
|
||||
data = kmalloc_array(ATMEL_SERIAL_RINGSIZE,
|
||||
sizeof(struct atmel_uart_char),
|
||||
GFP_KERNEL);
|
||||
data = kmalloc(ATMEL_SERIAL_RX_SIZE, GFP_KERNEL);
|
||||
if (!data)
|
||||
goto err_clk_disable_unprepare;
|
||||
atmel_port->rx_ring.buf = data;
|
||||
|
@ -146,7 +146,8 @@ static irqreturn_t uart_clps711x_int_tx(int irq, void *dev_id)
|
||||
{
|
||||
struct uart_port *port = dev_id;
|
||||
struct clps711x_port *s = dev_get_drvdata(port->dev);
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned char c;
|
||||
|
||||
if (port->x_char) {
|
||||
writew(port->x_char, port->membase + UARTDR_OFFSET);
|
||||
@ -155,7 +156,7 @@ static irqreturn_t uart_clps711x_int_tx(int irq, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
|
||||
if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
|
||||
if (s->tx_enabled) {
|
||||
disable_irq_nosync(port->irq);
|
||||
s->tx_enabled = 0;
|
||||
@ -163,18 +164,17 @@ static irqreturn_t uart_clps711x_int_tx(int irq, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
while (!uart_circ_empty(xmit)) {
|
||||
while (uart_fifo_get(port, &c)) {
|
||||
u32 sysflg = 0;
|
||||
|
||||
writew(xmit->buf[xmit->tail], port->membase + UARTDR_OFFSET);
|
||||
uart_xmit_advance(port, 1);
|
||||
writew(c, port->membase + UARTDR_OFFSET);
|
||||
|
||||
regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg);
|
||||
if (sysflg & SYSFLG_UTXFF)
|
||||
break;
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
@ -648,7 +648,7 @@ static int cpm_uart_tx_pump(struct uart_port *port)
|
||||
int count;
|
||||
struct uart_cpm_port *pinfo =
|
||||
container_of(port, struct uart_cpm_port, port);
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
|
||||
/* Handle xon/xoff */
|
||||
if (port->x_char) {
|
||||
@ -673,7 +673,7 @@ static int cpm_uart_tx_pump(struct uart_port *port)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
|
||||
if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
|
||||
cpm_uart_stop_tx(port);
|
||||
return 0;
|
||||
}
|
||||
@ -681,16 +681,10 @@ static int cpm_uart_tx_pump(struct uart_port *port)
|
||||
/* Pick next descriptor and fill from buffer */
|
||||
bdp = pinfo->tx_cur;
|
||||
|
||||
while (!(in_be16(&bdp->cbd_sc) & BD_SC_READY) && !uart_circ_empty(xmit)) {
|
||||
count = 0;
|
||||
while (!(in_be16(&bdp->cbd_sc) & BD_SC_READY) &&
|
||||
!kfifo_is_empty(&tport->xmit_fifo)) {
|
||||
p = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo);
|
||||
while (count < pinfo->tx_fifosize) {
|
||||
*p++ = xmit->buf[xmit->tail];
|
||||
uart_xmit_advance(port, 1);
|
||||
count++;
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
}
|
||||
count = uart_fifo_out(port, p, pinfo->tx_fifosize);
|
||||
out_be16(&bdp->cbd_datlen, count);
|
||||
setbits16(&bdp->cbd_sc, BD_SC_READY);
|
||||
/* Get next BD. */
|
||||
@ -701,10 +695,10 @@ static int cpm_uart_tx_pump(struct uart_port *port)
|
||||
}
|
||||
pinfo->tx_cur = bdp;
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (uart_circ_empty(xmit)) {
|
||||
if (kfifo_is_empty(&tport->xmit_fifo)) {
|
||||
cpm_uart_stop_tx(port);
|
||||
return 0;
|
||||
}
|
||||
|
@ -179,8 +179,9 @@ static void digicolor_uart_rx(struct uart_port *port)
|
||||
|
||||
static void digicolor_uart_tx(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned long flags;
|
||||
unsigned char c;
|
||||
|
||||
if (digicolor_uart_tx_full(port))
|
||||
return;
|
||||
@ -194,20 +195,19 @@ static void digicolor_uart_tx(struct uart_port *port)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
|
||||
if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
|
||||
digicolor_uart_stop_tx(port);
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (!uart_circ_empty(xmit)) {
|
||||
writeb(xmit->buf[xmit->tail], port->membase + UA_EMI_REC);
|
||||
uart_xmit_advance(port, 1);
|
||||
while (uart_fifo_get(port, &c)) {
|
||||
writeb(c, port->membase + UA_EMI_REC);
|
||||
|
||||
if (digicolor_uart_tx_full(port))
|
||||
break;
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
out:
|
||||
|
@ -252,13 +252,13 @@ static inline void dz_receive_chars(struct dz_mux *mux)
|
||||
static inline void dz_transmit_chars(struct dz_mux *mux)
|
||||
{
|
||||
struct dz_port *dport = &mux->dport[0];
|
||||
struct circ_buf *xmit;
|
||||
struct tty_port *tport;
|
||||
unsigned char tmp;
|
||||
u16 status;
|
||||
|
||||
status = dz_in(dport, DZ_CSR);
|
||||
dport = &mux->dport[LINE(status)];
|
||||
xmit = &dport->port.state->xmit;
|
||||
tport = &dport->port.state->port;
|
||||
|
||||
if (dport->port.x_char) { /* XON/XOFF chars */
|
||||
dz_out(dport, DZ_TDR, dport->port.x_char);
|
||||
@ -267,7 +267,8 @@ static inline void dz_transmit_chars(struct dz_mux *mux)
|
||||
return;
|
||||
}
|
||||
/* If nothing to do or stopped or hardware stopped. */
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(&dport->port)) {
|
||||
if (uart_tx_stopped(&dport->port) ||
|
||||
!uart_fifo_get(&dport->port, &tmp)) {
|
||||
uart_port_lock(&dport->port);
|
||||
dz_stop_tx(&dport->port);
|
||||
uart_port_unlock(&dport->port);
|
||||
@ -278,15 +279,13 @@ static inline void dz_transmit_chars(struct dz_mux *mux)
|
||||
* If something to do... (remember the dz has no output fifo,
|
||||
* so we go one char at a time) :-<
|
||||
*/
|
||||
tmp = xmit->buf[xmit->tail];
|
||||
dz_out(dport, DZ_TDR, tmp);
|
||||
uart_xmit_advance(&dport->port, 1);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < DZ_WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < DZ_WAKEUP_CHARS)
|
||||
uart_write_wakeup(&dport->port);
|
||||
|
||||
/* Are we are done. */
|
||||
if (uart_circ_empty(xmit)) {
|
||||
if (kfifo_is_empty(&tport->xmit_fifo)) {
|
||||
uart_port_lock(&dport->port);
|
||||
dz_stop_tx(&dport->port);
|
||||
uart_port_unlock(&dport->port);
|
||||
|
@ -174,17 +174,18 @@ static void linflex_put_char(struct uart_port *sport, unsigned char c)
|
||||
|
||||
static inline void linflex_transmit_buffer(struct uart_port *sport)
|
||||
{
|
||||
struct circ_buf *xmit = &sport->state->xmit;
|
||||
struct tty_port *tport = &sport->state->port;
|
||||
unsigned char c;
|
||||
|
||||
while (!uart_circ_empty(xmit)) {
|
||||
linflex_put_char(sport, xmit->buf[xmit->tail]);
|
||||
uart_xmit_advance(sport, 1);
|
||||
while (uart_fifo_get(sport, &c)) {
|
||||
linflex_put_char(sport, c);
|
||||
sport->icount.tx++;
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(sport);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
if (kfifo_is_empty(&tport->xmit_fifo))
|
||||
linflex_stop_tx(sport);
|
||||
}
|
||||
|
||||
@ -200,7 +201,7 @@ static void linflex_start_tx(struct uart_port *port)
|
||||
static irqreturn_t linflex_txint(int irq, void *dev_id)
|
||||
{
|
||||
struct uart_port *sport = dev_id;
|
||||
struct circ_buf *xmit = &sport->state->xmit;
|
||||
struct tty_port *tport = &sport->state->port;
|
||||
unsigned long flags;
|
||||
|
||||
uart_port_lock_irqsave(sport, &flags);
|
||||
@ -210,7 +211,7 @@ static irqreturn_t linflex_txint(int irq, void *dev_id)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(sport)) {
|
||||
if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(sport)) {
|
||||
linflex_stop_tx(sport);
|
||||
goto out;
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/circ_buf.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/delay.h>
|
||||
@ -473,7 +474,7 @@ static void lpuart32_stop_rx(struct uart_port *port)
|
||||
|
||||
static void lpuart_dma_tx(struct lpuart_port *sport)
|
||||
{
|
||||
struct circ_buf *xmit = &sport->port.state->xmit;
|
||||
struct tty_port *tport = &sport->port.state->port;
|
||||
struct scatterlist *sgl = sport->tx_sgl;
|
||||
struct device *dev = sport->port.dev;
|
||||
struct dma_chan *chan = sport->dma_tx_chan;
|
||||
@ -482,18 +483,10 @@ static void lpuart_dma_tx(struct lpuart_port *sport)
|
||||
if (sport->dma_tx_in_progress)
|
||||
return;
|
||||
|
||||
sport->dma_tx_bytes = uart_circ_chars_pending(xmit);
|
||||
|
||||
if (xmit->tail < xmit->head || xmit->head == 0) {
|
||||
sport->dma_tx_nents = 1;
|
||||
sg_init_one(sgl, xmit->buf + xmit->tail, sport->dma_tx_bytes);
|
||||
} else {
|
||||
sport->dma_tx_nents = 2;
|
||||
sg_init_table(sgl, 2);
|
||||
sg_set_buf(sgl, xmit->buf + xmit->tail,
|
||||
UART_XMIT_SIZE - xmit->tail);
|
||||
sg_set_buf(sgl + 1, xmit->buf, xmit->head);
|
||||
}
|
||||
sg_init_table(sgl, ARRAY_SIZE(sport->tx_sgl));
|
||||
sport->dma_tx_bytes = kfifo_len(&tport->xmit_fifo);
|
||||
sport->dma_tx_nents = kfifo_dma_out_prepare(&tport->xmit_fifo, sgl,
|
||||
ARRAY_SIZE(sport->tx_sgl), sport->dma_tx_bytes);
|
||||
|
||||
ret = dma_map_sg(chan->device->dev, sgl, sport->dma_tx_nents,
|
||||
DMA_TO_DEVICE);
|
||||
@ -521,14 +514,15 @@ static void lpuart_dma_tx(struct lpuart_port *sport)
|
||||
|
||||
static bool lpuart_stopped_or_empty(struct uart_port *port)
|
||||
{
|
||||
return uart_circ_empty(&port->state->xmit) || uart_tx_stopped(port);
|
||||
return kfifo_is_empty(&port->state->port.xmit_fifo) ||
|
||||
uart_tx_stopped(port);
|
||||
}
|
||||
|
||||
static void lpuart_dma_tx_complete(void *arg)
|
||||
{
|
||||
struct lpuart_port *sport = arg;
|
||||
struct scatterlist *sgl = &sport->tx_sgl[0];
|
||||
struct circ_buf *xmit = &sport->port.state->xmit;
|
||||
struct tty_port *tport = &sport->port.state->port;
|
||||
struct dma_chan *chan = sport->dma_tx_chan;
|
||||
unsigned long flags;
|
||||
|
||||
@ -545,7 +539,7 @@ static void lpuart_dma_tx_complete(void *arg)
|
||||
sport->dma_tx_in_progress = false;
|
||||
uart_port_unlock_irqrestore(&sport->port, flags);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&sport->port);
|
||||
|
||||
if (waitqueue_active(&sport->dma_wait)) {
|
||||
@ -756,8 +750,9 @@ static inline void lpuart_transmit_buffer(struct lpuart_port *sport)
|
||||
|
||||
static inline void lpuart32_transmit_buffer(struct lpuart_port *sport)
|
||||
{
|
||||
struct circ_buf *xmit = &sport->port.state->xmit;
|
||||
struct tty_port *tport = &sport->port.state->port;
|
||||
unsigned long txcnt;
|
||||
unsigned char c;
|
||||
|
||||
if (sport->port.x_char) {
|
||||
lpuart32_write(&sport->port, sport->port.x_char, UARTDATA);
|
||||
@ -774,18 +769,18 @@ static inline void lpuart32_transmit_buffer(struct lpuart_port *sport)
|
||||
txcnt = lpuart32_read(&sport->port, UARTWATER);
|
||||
txcnt = txcnt >> UARTWATER_TXCNT_OFF;
|
||||
txcnt &= UARTWATER_COUNT_MASK;
|
||||
while (!uart_circ_empty(xmit) && (txcnt < sport->txfifo_size)) {
|
||||
lpuart32_write(&sport->port, xmit->buf[xmit->tail], UARTDATA);
|
||||
uart_xmit_advance(&sport->port, 1);
|
||||
while (txcnt < sport->txfifo_size &&
|
||||
uart_fifo_get(&sport->port, &c)) {
|
||||
lpuart32_write(&sport->port, c, UARTDATA);
|
||||
txcnt = lpuart32_read(&sport->port, UARTWATER);
|
||||
txcnt = txcnt >> UARTWATER_TXCNT_OFF;
|
||||
txcnt &= UARTWATER_COUNT_MASK;
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&sport->port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
if (kfifo_is_empty(&tport->xmit_fifo))
|
||||
lpuart32_stop_tx(&sport->port);
|
||||
}
|
||||
|
||||
@ -2884,8 +2879,7 @@ static int lpuart_probe(struct platform_device *pdev)
|
||||
sport->ipg_clk = devm_clk_get(&pdev->dev, "ipg");
|
||||
if (IS_ERR(sport->ipg_clk)) {
|
||||
ret = PTR_ERR(sport->ipg_clk);
|
||||
dev_err(&pdev->dev, "failed to get uart ipg clk: %d\n", ret);
|
||||
return ret;
|
||||
return dev_err_probe(&pdev->dev, ret, "failed to get uart ipg clk\n");
|
||||
}
|
||||
|
||||
sport->baud_clk = NULL;
|
||||
@ -2893,8 +2887,7 @@ static int lpuart_probe(struct platform_device *pdev)
|
||||
sport->baud_clk = devm_clk_get(&pdev->dev, "baud");
|
||||
if (IS_ERR(sport->baud_clk)) {
|
||||
ret = PTR_ERR(sport->baud_clk);
|
||||
dev_err(&pdev->dev, "failed to get uart baud clk: %d\n", ret);
|
||||
return ret;
|
||||
return dev_err_probe(&pdev->dev, ret, "failed to get uart baud clk\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -877,10 +877,10 @@ unlock:
|
||||
static int icom_write(struct uart_port *port)
|
||||
{
|
||||
struct icom_port *icom_port = to_icom_port(port);
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned long data_count;
|
||||
unsigned char cmdReg;
|
||||
unsigned long offset;
|
||||
int temp_tail = port->state->xmit.tail;
|
||||
|
||||
trace(icom_port, "WRITE", 0);
|
||||
|
||||
@ -890,16 +890,8 @@ static int icom_write(struct uart_port *port)
|
||||
return 0;
|
||||
}
|
||||
|
||||
data_count = 0;
|
||||
while ((port->state->xmit.head != temp_tail) &&
|
||||
(data_count <= XMIT_BUFF_SZ)) {
|
||||
|
||||
icom_port->xmit_buf[data_count++] =
|
||||
port->state->xmit.buf[temp_tail];
|
||||
|
||||
temp_tail++;
|
||||
temp_tail &= (UART_XMIT_SIZE - 1);
|
||||
}
|
||||
data_count = kfifo_out_peek(&tport->xmit_fifo, icom_port->xmit_buf,
|
||||
XMIT_BUFF_SZ);
|
||||
|
||||
if (data_count) {
|
||||
icom_port->statStg->xmit[0].flags =
|
||||
@ -956,7 +948,8 @@ static inline void check_modem_status(struct icom_port *icom_port)
|
||||
|
||||
static void xmit_interrupt(u16 port_int_reg, struct icom_port *icom_port)
|
||||
{
|
||||
u16 count, i;
|
||||
struct tty_port *tport = &icom_port->uart_port.state->port;
|
||||
u16 count;
|
||||
|
||||
if (port_int_reg & (INT_XMIT_COMPLETED)) {
|
||||
trace(icom_port, "XMIT_COMPLETE", 0);
|
||||
@ -968,13 +961,7 @@ static void xmit_interrupt(u16 port_int_reg, struct icom_port *icom_port)
|
||||
count = le16_to_cpu(icom_port->statStg->xmit[0].leLength);
|
||||
icom_port->uart_port.icount.tx += count;
|
||||
|
||||
for (i=0; i<count &&
|
||||
!uart_circ_empty(&icom_port->uart_port.state->xmit); i++) {
|
||||
|
||||
icom_port->uart_port.state->xmit.tail++;
|
||||
icom_port->uart_port.state->xmit.tail &=
|
||||
(UART_XMIT_SIZE - 1);
|
||||
}
|
||||
kfifo_skip_count(&tport->xmit_fifo, count);
|
||||
|
||||
if (!icom_write(&icom_port->uart_port))
|
||||
/* activate write queue */
|
||||
|
@ -8,6 +8,7 @@
|
||||
* Copyright (C) 2004 Pengutronix
|
||||
*/
|
||||
|
||||
#include <linux/circ_buf.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/init.h>
|
||||
@ -26,6 +27,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
@ -521,7 +523,8 @@ static void imx_uart_dma_tx(struct imx_port *sport);
|
||||
/* called with port.lock taken and irqs off */
|
||||
static inline void imx_uart_transmit_buffer(struct imx_port *sport)
|
||||
{
|
||||
struct circ_buf *xmit = &sport->port.state->xmit;
|
||||
struct tty_port *tport = &sport->port.state->port;
|
||||
unsigned char c;
|
||||
|
||||
if (sport->port.x_char) {
|
||||
/* Send next char */
|
||||
@ -531,7 +534,8 @@ static inline void imx_uart_transmit_buffer(struct imx_port *sport)
|
||||
return;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
|
||||
if (kfifo_is_empty(&tport->xmit_fifo) ||
|
||||
uart_tx_stopped(&sport->port)) {
|
||||
imx_uart_stop_tx(&sport->port);
|
||||
return;
|
||||
}
|
||||
@ -555,26 +559,22 @@ static inline void imx_uart_transmit_buffer(struct imx_port *sport)
|
||||
return;
|
||||
}
|
||||
|
||||
while (!uart_circ_empty(xmit) &&
|
||||
!(imx_uart_readl(sport, imx_uart_uts_reg(sport)) & UTS_TXFULL)) {
|
||||
/* send xmit->buf[xmit->tail]
|
||||
* out the port here */
|
||||
imx_uart_writel(sport, xmit->buf[xmit->tail], URTX0);
|
||||
uart_xmit_advance(&sport->port, 1);
|
||||
}
|
||||
while (!(imx_uart_readl(sport, imx_uart_uts_reg(sport)) & UTS_TXFULL) &&
|
||||
uart_fifo_get(&sport->port, &c))
|
||||
imx_uart_writel(sport, c, URTX0);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&sport->port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
if (kfifo_is_empty(&tport->xmit_fifo))
|
||||
imx_uart_stop_tx(&sport->port);
|
||||
}
|
||||
|
||||
static void imx_uart_dma_tx_callback(void *data)
|
||||
{
|
||||
struct imx_port *sport = data;
|
||||
struct tty_port *tport = &sport->port.state->port;
|
||||
struct scatterlist *sgl = &sport->tx_sgl[0];
|
||||
struct circ_buf *xmit = &sport->port.state->xmit;
|
||||
unsigned long flags;
|
||||
u32 ucr1;
|
||||
|
||||
@ -592,10 +592,11 @@ static void imx_uart_dma_tx_callback(void *data)
|
||||
|
||||
sport->dma_is_txing = 0;
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&sport->port);
|
||||
|
||||
if (!uart_circ_empty(xmit) && !uart_tx_stopped(&sport->port))
|
||||
if (!kfifo_is_empty(&tport->xmit_fifo) &&
|
||||
!uart_tx_stopped(&sport->port))
|
||||
imx_uart_dma_tx(sport);
|
||||
else if (sport->port.rs485.flags & SER_RS485_ENABLED) {
|
||||
u32 ucr4 = imx_uart_readl(sport, UCR4);
|
||||
@ -609,7 +610,7 @@ static void imx_uart_dma_tx_callback(void *data)
|
||||
/* called with port.lock taken and irqs off */
|
||||
static void imx_uart_dma_tx(struct imx_port *sport)
|
||||
{
|
||||
struct circ_buf *xmit = &sport->port.state->xmit;
|
||||
struct tty_port *tport = &sport->port.state->port;
|
||||
struct scatterlist *sgl = sport->tx_sgl;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
struct dma_chan *chan = sport->dma_chan_tx;
|
||||
@ -624,18 +625,10 @@ static void imx_uart_dma_tx(struct imx_port *sport)
|
||||
ucr4 &= ~UCR4_TCEN;
|
||||
imx_uart_writel(sport, ucr4, UCR4);
|
||||
|
||||
sport->tx_bytes = uart_circ_chars_pending(xmit);
|
||||
|
||||
if (xmit->tail < xmit->head || xmit->head == 0) {
|
||||
sport->dma_tx_nents = 1;
|
||||
sg_init_one(sgl, xmit->buf + xmit->tail, sport->tx_bytes);
|
||||
} else {
|
||||
sport->dma_tx_nents = 2;
|
||||
sg_init_table(sgl, 2);
|
||||
sg_set_buf(sgl, xmit->buf + xmit->tail,
|
||||
UART_XMIT_SIZE - xmit->tail);
|
||||
sg_set_buf(sgl + 1, xmit->buf, xmit->head);
|
||||
}
|
||||
sg_init_table(sgl, ARRAY_SIZE(sport->tx_sgl));
|
||||
sport->tx_bytes = kfifo_len(&tport->xmit_fifo);
|
||||
sport->dma_tx_nents = kfifo_dma_out_prepare(&tport->xmit_fifo, sgl,
|
||||
ARRAY_SIZE(sport->tx_sgl), sport->tx_bytes);
|
||||
|
||||
ret = dma_map_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
|
||||
if (ret == 0) {
|
||||
@ -653,8 +646,7 @@ static void imx_uart_dma_tx(struct imx_port *sport)
|
||||
desc->callback = imx_uart_dma_tx_callback;
|
||||
desc->callback_param = sport;
|
||||
|
||||
dev_dbg(dev, "TX: prepare to send %lu bytes by DMA.\n",
|
||||
uart_circ_chars_pending(xmit));
|
||||
dev_dbg(dev, "TX: prepare to send %u bytes by DMA.\n", sport->tx_bytes);
|
||||
|
||||
ucr1 = imx_uart_readl(sport, UCR1);
|
||||
ucr1 |= UCR1_TXDMAEN;
|
||||
@ -671,9 +663,10 @@ static void imx_uart_dma_tx(struct imx_port *sport)
|
||||
static void imx_uart_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct imx_port *sport = (struct imx_port *)port;
|
||||
struct tty_port *tport = &sport->port.state->port;
|
||||
u32 ucr1;
|
||||
|
||||
if (!sport->port.x_char && uart_circ_empty(&port->state->xmit))
|
||||
if (!sport->port.x_char && kfifo_is_empty(&tport->xmit_fifo))
|
||||
return;
|
||||
|
||||
/*
|
||||
@ -749,7 +742,7 @@ static void imx_uart_start_tx(struct uart_port *port)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!uart_circ_empty(&port->state->xmit) &&
|
||||
if (!kfifo_is_empty(&tport->xmit_fifo) &&
|
||||
!uart_tx_stopped(port))
|
||||
imx_uart_dma_tx(sport);
|
||||
return;
|
||||
@ -1312,7 +1305,7 @@ static void imx_uart_clear_rx_errors(struct imx_port *sport)
|
||||
|
||||
}
|
||||
|
||||
#define TXTL_DEFAULT 2 /* reset default */
|
||||
#define TXTL_DEFAULT 8
|
||||
#define RXTL_DEFAULT 8 /* 8 characters or aging timer */
|
||||
#define TXTL_DMA 8 /* DMA burst setting */
|
||||
#define RXTL_DMA 9 /* DMA burst setting */
|
||||
@ -2010,7 +2003,7 @@ imx_uart_console_write(struct console *co, const char *s, unsigned int count)
|
||||
struct imx_port *sport = imx_uart_ports[co->index];
|
||||
struct imx_port_ucrs old_ucr;
|
||||
unsigned long flags;
|
||||
unsigned int ucr1;
|
||||
unsigned int ucr1, usr2;
|
||||
int locked = 1;
|
||||
|
||||
if (sport->port.sysrq)
|
||||
@ -2041,8 +2034,8 @@ imx_uart_console_write(struct console *co, const char *s, unsigned int count)
|
||||
* Finally, wait for transmitter to become empty
|
||||
* and restore UCR1/2/3
|
||||
*/
|
||||
while (!(imx_uart_readl(sport, USR2) & USR2_TXDC));
|
||||
|
||||
read_poll_timeout_atomic(imx_uart_readl, usr2, usr2 & USR2_TXDC,
|
||||
0, USEC_PER_SEC, false, sport, USR2);
|
||||
imx_uart_ucrs_restore(sport, &old_ucr);
|
||||
|
||||
if (locked)
|
||||
|
@ -355,7 +355,8 @@ static void ip22zilog_status_handle(struct uart_ip22zilog_port *up,
|
||||
static void ip22zilog_transmit_chars(struct uart_ip22zilog_port *up,
|
||||
struct zilog_channel *channel)
|
||||
{
|
||||
struct circ_buf *xmit;
|
||||
struct tty_port *tport;
|
||||
unsigned char c;
|
||||
|
||||
if (ZS_IS_CONS(up)) {
|
||||
unsigned char status = readb(&channel->control);
|
||||
@ -398,20 +399,18 @@ static void ip22zilog_transmit_chars(struct uart_ip22zilog_port *up,
|
||||
|
||||
if (up->port.state == NULL)
|
||||
goto ack_tx_int;
|
||||
xmit = &up->port.state->xmit;
|
||||
if (uart_circ_empty(xmit))
|
||||
goto ack_tx_int;
|
||||
tport = &up->port.state->port;
|
||||
if (uart_tx_stopped(&up->port))
|
||||
goto ack_tx_int;
|
||||
if (!uart_fifo_get(&up->port, &c))
|
||||
goto ack_tx_int;
|
||||
|
||||
up->flags |= IP22ZILOG_FLAG_TX_ACTIVE;
|
||||
writeb(xmit->buf[xmit->tail], &channel->data);
|
||||
writeb(c, &channel->data);
|
||||
ZSDELAY();
|
||||
ZS_WSYNC(channel);
|
||||
|
||||
uart_xmit_advance(&up->port, 1);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&up->port);
|
||||
|
||||
return;
|
||||
@ -600,17 +599,16 @@ static void ip22zilog_start_tx(struct uart_port *port)
|
||||
port->icount.tx++;
|
||||
port->x_char = 0;
|
||||
} else {
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned char c;
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
if (!uart_fifo_get(port, &c))
|
||||
return;
|
||||
writeb(xmit->buf[xmit->tail], &channel->data);
|
||||
writeb(c, &channel->data);
|
||||
ZSDELAY();
|
||||
ZS_WSYNC(channel);
|
||||
|
||||
uart_xmit_advance(port, 1);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&up->port);
|
||||
}
|
||||
}
|
||||
|
@ -443,20 +443,14 @@ static void cls_copy_data_from_uart_to_queue(struct jsm_channel *ch)
|
||||
|
||||
static void cls_copy_data_from_queue_to_uart(struct jsm_channel *ch)
|
||||
{
|
||||
u16 tail;
|
||||
struct tty_port *tport;
|
||||
int n;
|
||||
int qlen;
|
||||
u32 len_written = 0;
|
||||
struct circ_buf *circ;
|
||||
|
||||
if (!ch)
|
||||
return;
|
||||
|
||||
circ = &ch->uart_port.state->xmit;
|
||||
|
||||
/* No data to write to the UART */
|
||||
if (uart_circ_empty(circ))
|
||||
return;
|
||||
tport = &ch->uart_port.state->port;
|
||||
|
||||
/* If port is "stopped", don't send any data to the UART */
|
||||
if ((ch->ch_flags & CH_STOP) || (ch->ch_flags & CH_BREAK_SENDING))
|
||||
@ -467,29 +461,22 @@ static void cls_copy_data_from_queue_to_uart(struct jsm_channel *ch)
|
||||
return;
|
||||
|
||||
n = 32;
|
||||
|
||||
/* cache tail of queue */
|
||||
tail = circ->tail & (UART_XMIT_SIZE - 1);
|
||||
qlen = uart_circ_chars_pending(circ);
|
||||
|
||||
/* Find minimum of the FIFO space, versus queue length */
|
||||
n = min(n, qlen);
|
||||
|
||||
while (n > 0) {
|
||||
writeb(circ->buf[tail], &ch->ch_cls_uart->txrx);
|
||||
tail = (tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
unsigned char c;
|
||||
|
||||
if (!kfifo_get(&tport->xmit_fifo, &c))
|
||||
break;
|
||||
|
||||
writeb(c, &ch->ch_cls_uart->txrx);
|
||||
n--;
|
||||
ch->ch_txcount++;
|
||||
len_written++;
|
||||
}
|
||||
|
||||
/* Update the final tail */
|
||||
circ->tail = tail & (UART_XMIT_SIZE - 1);
|
||||
|
||||
if (len_written > ch->ch_t_tlevel)
|
||||
ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
|
||||
|
||||
if (uart_circ_empty(circ))
|
||||
if (kfifo_is_empty(&tport->xmit_fifo))
|
||||
uart_write_wakeup(&ch->uart_port);
|
||||
}
|
||||
|
||||
|
@ -474,21 +474,21 @@ static void neo_copy_data_from_uart_to_queue(struct jsm_channel *ch)
|
||||
|
||||
static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch)
|
||||
{
|
||||
u16 head;
|
||||
u16 tail;
|
||||
struct tty_port *tport;
|
||||
unsigned char *tail;
|
||||
unsigned char c;
|
||||
int n;
|
||||
int s;
|
||||
int qlen;
|
||||
u32 len_written = 0;
|
||||
struct circ_buf *circ;
|
||||
|
||||
if (!ch)
|
||||
return;
|
||||
|
||||
circ = &ch->uart_port.state->xmit;
|
||||
tport = &ch->uart_port.state->port;
|
||||
|
||||
/* No data to write to the UART */
|
||||
if (uart_circ_empty(circ))
|
||||
if (kfifo_is_empty(&tport->xmit_fifo))
|
||||
return;
|
||||
|
||||
/* If port is "stopped", don't send any data to the UART */
|
||||
@ -504,10 +504,9 @@ static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch)
|
||||
if (ch->ch_cached_lsr & UART_LSR_THRE) {
|
||||
ch->ch_cached_lsr &= ~(UART_LSR_THRE);
|
||||
|
||||
writeb(circ->buf[circ->tail], &ch->ch_neo_uart->txrx);
|
||||
jsm_dbg(WRITE, &ch->ch_bd->pci_dev,
|
||||
"Tx data: %x\n", circ->buf[circ->tail]);
|
||||
circ->tail = (circ->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
WARN_ON_ONCE(!kfifo_get(&tport->xmit_fifo, &c));
|
||||
writeb(c, &ch->ch_neo_uart->txrx);
|
||||
jsm_dbg(WRITE, &ch->ch_bd->pci_dev, "Tx data: %x\n", c);
|
||||
ch->ch_txcount++;
|
||||
}
|
||||
return;
|
||||
@ -520,38 +519,27 @@ static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch)
|
||||
return;
|
||||
|
||||
n = UART_17158_TX_FIFOSIZE - ch->ch_t_tlevel;
|
||||
|
||||
/* cache head and tail of queue */
|
||||
head = circ->head & (UART_XMIT_SIZE - 1);
|
||||
tail = circ->tail & (UART_XMIT_SIZE - 1);
|
||||
qlen = uart_circ_chars_pending(circ);
|
||||
qlen = kfifo_len(&tport->xmit_fifo);
|
||||
|
||||
/* Find minimum of the FIFO space, versus queue length */
|
||||
n = min(n, qlen);
|
||||
|
||||
while (n > 0) {
|
||||
|
||||
s = ((head >= tail) ? head : UART_XMIT_SIZE) - tail;
|
||||
s = min(s, n);
|
||||
|
||||
s = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail, n);
|
||||
if (s <= 0)
|
||||
break;
|
||||
|
||||
memcpy_toio(&ch->ch_neo_uart->txrxburst, circ->buf + tail, s);
|
||||
/* Add and flip queue if needed */
|
||||
tail = (tail + s) & (UART_XMIT_SIZE - 1);
|
||||
memcpy_toio(&ch->ch_neo_uart->txrxburst, tail, s);
|
||||
kfifo_skip_count(&tport->xmit_fifo, s);
|
||||
n -= s;
|
||||
ch->ch_txcount += s;
|
||||
len_written += s;
|
||||
}
|
||||
|
||||
/* Update the final tail */
|
||||
circ->tail = tail & (UART_XMIT_SIZE - 1);
|
||||
|
||||
if (len_written >= ch->ch_t_tlevel)
|
||||
ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
|
||||
|
||||
if (uart_circ_empty(circ))
|
||||
if (kfifo_is_empty(&tport->xmit_fifo))
|
||||
uart_write_wakeup(&ch->uart_port);
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2008 Christian Pellegrin <chripell@evolware.org>
|
||||
*
|
||||
* Notes: the MAX3100 doesn't provide an interrupt on CTS so we have
|
||||
@ -8,24 +7,6 @@
|
||||
* writing conf clears FIFO buffer and we cannot have this interrupt
|
||||
* always asking us for attention.
|
||||
*
|
||||
* Example platform data:
|
||||
|
||||
static struct plat_max3100 max3100_plat_data = {
|
||||
.loopback = 0,
|
||||
.crystal = 0,
|
||||
.poll_time = 100,
|
||||
};
|
||||
|
||||
static struct spi_board_info spi_board_info[] = {
|
||||
{
|
||||
.modalias = "max3100",
|
||||
.platform_data = &max3100_plat_data,
|
||||
.irq = IRQ_EINT12,
|
||||
.max_speed_hz = 5*1000*1000,
|
||||
.chip_select = 0,
|
||||
},
|
||||
};
|
||||
|
||||
* The initial minor number is 209 in the low-density serial port:
|
||||
* mknod /dev/ttyMAX0 c 204 209
|
||||
*/
|
||||
@ -35,18 +16,23 @@
|
||||
/* 4 MAX3100s should be enough for everyone */
|
||||
#define MAX_MAX3100 4
|
||||
|
||||
#include <linux/container_of.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/freezer.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/freezer.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <linux/serial_max3100.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#define MAX3100_C (1<<14)
|
||||
#define MAX3100_D (0<<14)
|
||||
@ -110,10 +96,8 @@ struct max3100_port {
|
||||
#define MAX3100_7BIT 4
|
||||
int rx_enabled; /* if we should rx chars */
|
||||
|
||||
int irq; /* irq assigned to the max3100 */
|
||||
|
||||
int minor; /* minor number */
|
||||
int crystal; /* 1 if 3.6864Mhz crystal 0 for 1.8432 */
|
||||
int loopback_commit; /* need to change loopback */
|
||||
int loopback; /* 1 if we are in loopback mode */
|
||||
|
||||
/* for handling irqs: need workqueue since we do spi_sync */
|
||||
@ -124,15 +108,14 @@ struct max3100_port {
|
||||
/* need to know we are suspending to avoid deadlock on workqueue */
|
||||
int suspending;
|
||||
|
||||
/* hook for suspending MAX3100 via dedicated pin */
|
||||
void (*max3100_hw_suspend) (int suspend);
|
||||
|
||||
/* poll time (in ms) for ctrl lines */
|
||||
int poll_time;
|
||||
/* and its timer */
|
||||
struct timer_list timer;
|
||||
};
|
||||
|
||||
static inline struct max3100_port *to_max3100_port(struct uart_port *port)
|
||||
{
|
||||
return container_of(port, struct max3100_port, port);
|
||||
}
|
||||
|
||||
static struct max3100_port *max3100s[MAX_MAX3100]; /* the chips */
|
||||
static DEFINE_MUTEX(max3100s_lock); /* race on probe */
|
||||
|
||||
@ -170,28 +153,10 @@ static void max3100_calc_parity(struct max3100_port *s, u16 *c)
|
||||
*c |= max3100_do_parity(s, *c) << 8;
|
||||
}
|
||||
|
||||
static void max3100_work(struct work_struct *w);
|
||||
|
||||
static void max3100_dowork(struct max3100_port *s)
|
||||
{
|
||||
if (!s->force_end_work && !freezing(current) && !s->suspending)
|
||||
queue_work(s->workqueue, &s->work);
|
||||
}
|
||||
|
||||
static void max3100_timeout(struct timer_list *t)
|
||||
{
|
||||
struct max3100_port *s = from_timer(s, t, timer);
|
||||
|
||||
if (s->port.state) {
|
||||
max3100_dowork(s);
|
||||
mod_timer(&s->timer, jiffies + s->poll_time);
|
||||
}
|
||||
}
|
||||
|
||||
static int max3100_sr(struct max3100_port *s, u16 tx, u16 *rx)
|
||||
{
|
||||
struct spi_message message;
|
||||
u16 etx, erx;
|
||||
__be16 etx, erx;
|
||||
int status;
|
||||
struct spi_transfer tran = {
|
||||
.tx_buf = &etx,
|
||||
@ -213,7 +178,7 @@ static int max3100_sr(struct max3100_port *s, u16 tx, u16 *rx)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max3100_handlerx(struct max3100_port *s, u16 rx)
|
||||
static int max3100_handlerx_unlocked(struct max3100_port *s, u16 rx)
|
||||
{
|
||||
unsigned int status = 0;
|
||||
int ret = 0, cts;
|
||||
@ -254,13 +219,25 @@ static int max3100_handlerx(struct max3100_port *s, u16 rx)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max3100_handlerx(struct max3100_port *s, u16 rx)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
uart_port_lock_irqsave(&s->port, &flags);
|
||||
ret = max3100_handlerx_unlocked(s, rx);
|
||||
uart_port_unlock_irqrestore(&s->port, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void max3100_work(struct work_struct *w)
|
||||
{
|
||||
struct max3100_port *s = container_of(w, struct max3100_port, work);
|
||||
struct tty_port *tport = &s->port.state->port;
|
||||
unsigned char ch;
|
||||
int conf, cconf, cloopback, crts;
|
||||
int rxchars;
|
||||
u16 tx, rx;
|
||||
int conf, cconf, crts;
|
||||
struct circ_buf *xmit = &s->port.state->xmit;
|
||||
|
||||
dev_dbg(&s->spi->dev, "%s\n", __func__);
|
||||
|
||||
@ -270,11 +247,15 @@ static void max3100_work(struct work_struct *w)
|
||||
conf = s->conf;
|
||||
cconf = s->conf_commit;
|
||||
s->conf_commit = 0;
|
||||
cloopback = s->loopback_commit;
|
||||
s->loopback_commit = 0;
|
||||
crts = s->rts_commit;
|
||||
s->rts_commit = 0;
|
||||
spin_unlock(&s->conf_lock);
|
||||
if (cconf)
|
||||
max3100_sr(s, MAX3100_WC | conf, &rx);
|
||||
if (cloopback)
|
||||
max3100_sr(s, 0x4001, &rx);
|
||||
if (crts) {
|
||||
max3100_sr(s, MAX3100_WD | MAX3100_TE |
|
||||
(s->rts ? MAX3100_RTS : 0), &rx);
|
||||
@ -290,10 +271,9 @@ static void max3100_work(struct work_struct *w)
|
||||
tx = s->port.x_char;
|
||||
s->port.icount.tx++;
|
||||
s->port.x_char = 0;
|
||||
} else if (!uart_circ_empty(xmit) &&
|
||||
!uart_tx_stopped(&s->port)) {
|
||||
tx = xmit->buf[xmit->tail];
|
||||
uart_xmit_advance(&s->port, 1);
|
||||
} else if (!uart_tx_stopped(&s->port) &&
|
||||
uart_fifo_get(&s->port, &ch)) {
|
||||
tx = ch;
|
||||
}
|
||||
if (tx != 0xffff) {
|
||||
max3100_calc_parity(s, &tx);
|
||||
@ -307,19 +287,33 @@ static void max3100_work(struct work_struct *w)
|
||||
tty_flip_buffer_push(&s->port.state->port);
|
||||
rxchars = 0;
|
||||
}
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&s->port);
|
||||
|
||||
} while (!s->force_end_work &&
|
||||
!freezing(current) &&
|
||||
((rx & MAX3100_R) ||
|
||||
(!uart_circ_empty(xmit) &&
|
||||
(!kfifo_is_empty(&tport->xmit_fifo) &&
|
||||
!uart_tx_stopped(&s->port))));
|
||||
|
||||
if (rxchars > 0)
|
||||
tty_flip_buffer_push(&s->port.state->port);
|
||||
}
|
||||
|
||||
static void max3100_dowork(struct max3100_port *s)
|
||||
{
|
||||
if (!s->force_end_work && !freezing(current) && !s->suspending)
|
||||
queue_work(s->workqueue, &s->work);
|
||||
}
|
||||
|
||||
static void max3100_timeout(struct timer_list *t)
|
||||
{
|
||||
struct max3100_port *s = from_timer(s, t, timer);
|
||||
|
||||
max3100_dowork(s);
|
||||
mod_timer(&s->timer, jiffies + uart_poll_timeout(&s->port));
|
||||
}
|
||||
|
||||
static irqreturn_t max3100_irq(int irqno, void *dev_id)
|
||||
{
|
||||
struct max3100_port *s = dev_id;
|
||||
@ -332,20 +326,15 @@ static irqreturn_t max3100_irq(int irqno, void *dev_id)
|
||||
|
||||
static void max3100_enable_ms(struct uart_port *port)
|
||||
{
|
||||
struct max3100_port *s = container_of(port,
|
||||
struct max3100_port,
|
||||
port);
|
||||
struct max3100_port *s = to_max3100_port(port);
|
||||
|
||||
if (s->poll_time > 0)
|
||||
mod_timer(&s->timer, jiffies);
|
||||
mod_timer(&s->timer, jiffies);
|
||||
dev_dbg(&s->spi->dev, "%s\n", __func__);
|
||||
}
|
||||
|
||||
static void max3100_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct max3100_port *s = container_of(port,
|
||||
struct max3100_port,
|
||||
port);
|
||||
struct max3100_port *s = to_max3100_port(port);
|
||||
|
||||
dev_dbg(&s->spi->dev, "%s\n", __func__);
|
||||
|
||||
@ -354,9 +343,7 @@ static void max3100_start_tx(struct uart_port *port)
|
||||
|
||||
static void max3100_stop_rx(struct uart_port *port)
|
||||
{
|
||||
struct max3100_port *s = container_of(port,
|
||||
struct max3100_port,
|
||||
port);
|
||||
struct max3100_port *s = to_max3100_port(port);
|
||||
|
||||
dev_dbg(&s->spi->dev, "%s\n", __func__);
|
||||
|
||||
@ -370,9 +357,7 @@ static void max3100_stop_rx(struct uart_port *port)
|
||||
|
||||
static unsigned int max3100_tx_empty(struct uart_port *port)
|
||||
{
|
||||
struct max3100_port *s = container_of(port,
|
||||
struct max3100_port,
|
||||
port);
|
||||
struct max3100_port *s = to_max3100_port(port);
|
||||
|
||||
dev_dbg(&s->spi->dev, "%s\n", __func__);
|
||||
|
||||
@ -383,9 +368,7 @@ static unsigned int max3100_tx_empty(struct uart_port *port)
|
||||
|
||||
static unsigned int max3100_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
struct max3100_port *s = container_of(port,
|
||||
struct max3100_port,
|
||||
port);
|
||||
struct max3100_port *s = to_max3100_port(port);
|
||||
|
||||
dev_dbg(&s->spi->dev, "%s\n", __func__);
|
||||
|
||||
@ -397,21 +380,25 @@ static unsigned int max3100_get_mctrl(struct uart_port *port)
|
||||
|
||||
static void max3100_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
struct max3100_port *s = container_of(port,
|
||||
struct max3100_port,
|
||||
port);
|
||||
int rts;
|
||||
struct max3100_port *s = to_max3100_port(port);
|
||||
int loopback, rts;
|
||||
|
||||
dev_dbg(&s->spi->dev, "%s\n", __func__);
|
||||
|
||||
loopback = (mctrl & TIOCM_LOOP) > 0;
|
||||
rts = (mctrl & TIOCM_RTS) > 0;
|
||||
|
||||
spin_lock(&s->conf_lock);
|
||||
if (s->loopback != loopback) {
|
||||
s->loopback = loopback;
|
||||
s->loopback_commit = 1;
|
||||
}
|
||||
if (s->rts != rts) {
|
||||
s->rts = rts;
|
||||
s->rts_commit = 1;
|
||||
max3100_dowork(s);
|
||||
}
|
||||
if (s->loopback_commit || s->rts_commit)
|
||||
max3100_dowork(s);
|
||||
spin_unlock(&s->conf_lock);
|
||||
}
|
||||
|
||||
@ -419,10 +406,9 @@ static void
|
||||
max3100_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
const struct ktermios *old)
|
||||
{
|
||||
struct max3100_port *s = container_of(port,
|
||||
struct max3100_port,
|
||||
port);
|
||||
int baud = 0;
|
||||
struct max3100_port *s = to_max3100_port(port);
|
||||
unsigned int baud = port->uartclk / 16;
|
||||
unsigned int baud230400 = (baud == 230400) ? 1 : 0;
|
||||
unsigned cflag;
|
||||
u32 param_new, param_mask, parity = 0;
|
||||
|
||||
@ -435,40 +421,40 @@ max3100_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
param_new = s->conf & MAX3100_BAUD;
|
||||
switch (baud) {
|
||||
case 300:
|
||||
if (s->crystal)
|
||||
if (baud230400)
|
||||
baud = s->baud;
|
||||
else
|
||||
param_new = 15;
|
||||
break;
|
||||
case 600:
|
||||
param_new = 14 + s->crystal;
|
||||
param_new = 14 + baud230400;
|
||||
break;
|
||||
case 1200:
|
||||
param_new = 13 + s->crystal;
|
||||
param_new = 13 + baud230400;
|
||||
break;
|
||||
case 2400:
|
||||
param_new = 12 + s->crystal;
|
||||
param_new = 12 + baud230400;
|
||||
break;
|
||||
case 4800:
|
||||
param_new = 11 + s->crystal;
|
||||
param_new = 11 + baud230400;
|
||||
break;
|
||||
case 9600:
|
||||
param_new = 10 + s->crystal;
|
||||
param_new = 10 + baud230400;
|
||||
break;
|
||||
case 19200:
|
||||
param_new = 9 + s->crystal;
|
||||
param_new = 9 + baud230400;
|
||||
break;
|
||||
case 38400:
|
||||
param_new = 8 + s->crystal;
|
||||
param_new = 8 + baud230400;
|
||||
break;
|
||||
case 57600:
|
||||
param_new = 1 + s->crystal;
|
||||
param_new = 1 + baud230400;
|
||||
break;
|
||||
case 115200:
|
||||
param_new = 0 + s->crystal;
|
||||
param_new = 0 + baud230400;
|
||||
break;
|
||||
case 230400:
|
||||
if (s->crystal)
|
||||
if (baud230400)
|
||||
param_new = 0;
|
||||
else
|
||||
baud = s->baud;
|
||||
@ -520,9 +506,7 @@ max3100_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
MAX3100_STATUS_PE | MAX3100_STATUS_FE |
|
||||
MAX3100_STATUS_OE;
|
||||
|
||||
if (s->poll_time > 0)
|
||||
del_timer_sync(&s->timer);
|
||||
|
||||
del_timer_sync(&s->timer);
|
||||
uart_update_timeout(port, termios->c_cflag, baud);
|
||||
|
||||
spin_lock(&s->conf_lock);
|
||||
@ -538,9 +522,8 @@ max3100_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
|
||||
static void max3100_shutdown(struct uart_port *port)
|
||||
{
|
||||
struct max3100_port *s = container_of(port,
|
||||
struct max3100_port,
|
||||
port);
|
||||
struct max3100_port *s = to_max3100_port(port);
|
||||
u16 rx;
|
||||
|
||||
dev_dbg(&s->spi->dev, "%s\n", __func__);
|
||||
|
||||
@ -549,38 +532,29 @@ static void max3100_shutdown(struct uart_port *port)
|
||||
|
||||
s->force_end_work = 1;
|
||||
|
||||
if (s->poll_time > 0)
|
||||
del_timer_sync(&s->timer);
|
||||
del_timer_sync(&s->timer);
|
||||
|
||||
if (s->workqueue) {
|
||||
destroy_workqueue(s->workqueue);
|
||||
s->workqueue = NULL;
|
||||
}
|
||||
if (s->irq)
|
||||
free_irq(s->irq, s);
|
||||
if (port->irq)
|
||||
free_irq(port->irq, s);
|
||||
|
||||
/* set shutdown mode to save power */
|
||||
if (s->max3100_hw_suspend)
|
||||
s->max3100_hw_suspend(1);
|
||||
else {
|
||||
u16 tx, rx;
|
||||
|
||||
tx = MAX3100_WC | MAX3100_SHDN;
|
||||
max3100_sr(s, tx, &rx);
|
||||
}
|
||||
max3100_sr(s, MAX3100_WC | MAX3100_SHDN, &rx);
|
||||
}
|
||||
|
||||
static int max3100_startup(struct uart_port *port)
|
||||
{
|
||||
struct max3100_port *s = container_of(port,
|
||||
struct max3100_port,
|
||||
port);
|
||||
struct max3100_port *s = to_max3100_port(port);
|
||||
char b[12];
|
||||
int ret;
|
||||
|
||||
dev_dbg(&s->spi->dev, "%s\n", __func__);
|
||||
|
||||
s->conf = MAX3100_RM;
|
||||
s->baud = s->crystal ? 230400 : 115200;
|
||||
s->baud = port->uartclk / 16;
|
||||
s->rx_enabled = 1;
|
||||
|
||||
if (s->suspending)
|
||||
@ -598,23 +572,15 @@ static int max3100_startup(struct uart_port *port)
|
||||
}
|
||||
INIT_WORK(&s->work, max3100_work);
|
||||
|
||||
if (request_irq(s->irq, max3100_irq,
|
||||
IRQF_TRIGGER_FALLING, "max3100", s) < 0) {
|
||||
dev_warn(&s->spi->dev, "cannot allocate irq %d\n", s->irq);
|
||||
s->irq = 0;
|
||||
ret = request_irq(port->irq, max3100_irq, IRQF_TRIGGER_FALLING, "max3100", s);
|
||||
if (ret < 0) {
|
||||
dev_warn(&s->spi->dev, "cannot allocate irq %d\n", port->irq);
|
||||
port->irq = 0;
|
||||
destroy_workqueue(s->workqueue);
|
||||
s->workqueue = NULL;
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (s->loopback) {
|
||||
u16 tx, rx;
|
||||
tx = 0x4001;
|
||||
max3100_sr(s, tx, &rx);
|
||||
}
|
||||
|
||||
if (s->max3100_hw_suspend)
|
||||
s->max3100_hw_suspend(0);
|
||||
s->conf_commit = 1;
|
||||
max3100_dowork(s);
|
||||
/* wait for clock to settle */
|
||||
@ -627,9 +593,7 @@ static int max3100_startup(struct uart_port *port)
|
||||
|
||||
static const char *max3100_type(struct uart_port *port)
|
||||
{
|
||||
struct max3100_port *s = container_of(port,
|
||||
struct max3100_port,
|
||||
port);
|
||||
struct max3100_port *s = to_max3100_port(port);
|
||||
|
||||
dev_dbg(&s->spi->dev, "%s\n", __func__);
|
||||
|
||||
@ -638,18 +602,14 @@ static const char *max3100_type(struct uart_port *port)
|
||||
|
||||
static void max3100_release_port(struct uart_port *port)
|
||||
{
|
||||
struct max3100_port *s = container_of(port,
|
||||
struct max3100_port,
|
||||
port);
|
||||
struct max3100_port *s = to_max3100_port(port);
|
||||
|
||||
dev_dbg(&s->spi->dev, "%s\n", __func__);
|
||||
}
|
||||
|
||||
static void max3100_config_port(struct uart_port *port, int flags)
|
||||
{
|
||||
struct max3100_port *s = container_of(port,
|
||||
struct max3100_port,
|
||||
port);
|
||||
struct max3100_port *s = to_max3100_port(port);
|
||||
|
||||
dev_dbg(&s->spi->dev, "%s\n", __func__);
|
||||
|
||||
@ -660,9 +620,7 @@ static void max3100_config_port(struct uart_port *port, int flags)
|
||||
static int max3100_verify_port(struct uart_port *port,
|
||||
struct serial_struct *ser)
|
||||
{
|
||||
struct max3100_port *s = container_of(port,
|
||||
struct max3100_port,
|
||||
port);
|
||||
struct max3100_port *s = to_max3100_port(port);
|
||||
int ret = -EINVAL;
|
||||
|
||||
dev_dbg(&s->spi->dev, "%s\n", __func__);
|
||||
@ -674,18 +632,14 @@ static int max3100_verify_port(struct uart_port *port,
|
||||
|
||||
static void max3100_stop_tx(struct uart_port *port)
|
||||
{
|
||||
struct max3100_port *s = container_of(port,
|
||||
struct max3100_port,
|
||||
port);
|
||||
struct max3100_port *s = to_max3100_port(port);
|
||||
|
||||
dev_dbg(&s->spi->dev, "%s\n", __func__);
|
||||
}
|
||||
|
||||
static int max3100_request_port(struct uart_port *port)
|
||||
{
|
||||
struct max3100_port *s = container_of(port,
|
||||
struct max3100_port,
|
||||
port);
|
||||
struct max3100_port *s = to_max3100_port(port);
|
||||
|
||||
dev_dbg(&s->spi->dev, "%s\n", __func__);
|
||||
return 0;
|
||||
@ -693,9 +647,7 @@ static int max3100_request_port(struct uart_port *port)
|
||||
|
||||
static void max3100_break_ctl(struct uart_port *port, int break_state)
|
||||
{
|
||||
struct max3100_port *s = container_of(port,
|
||||
struct max3100_port,
|
||||
port);
|
||||
struct max3100_port *s = to_max3100_port(port);
|
||||
|
||||
dev_dbg(&s->spi->dev, "%s\n", __func__);
|
||||
}
|
||||
@ -731,74 +683,59 @@ static int uart_driver_registered;
|
||||
|
||||
static int max3100_probe(struct spi_device *spi)
|
||||
{
|
||||
struct device *dev = &spi->dev;
|
||||
int i, retval;
|
||||
struct plat_max3100 *pdata;
|
||||
u16 tx, rx;
|
||||
u16 rx;
|
||||
|
||||
mutex_lock(&max3100s_lock);
|
||||
|
||||
if (!uart_driver_registered) {
|
||||
uart_driver_registered = 1;
|
||||
retval = uart_register_driver(&max3100_uart_driver);
|
||||
if (retval) {
|
||||
printk(KERN_ERR "Couldn't register max3100 uart driver\n");
|
||||
mutex_unlock(&max3100s_lock);
|
||||
return retval;
|
||||
return dev_err_probe(dev, retval, "Couldn't register max3100 uart driver\n");
|
||||
}
|
||||
|
||||
uart_driver_registered = 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_MAX3100; i++)
|
||||
if (!max3100s[i])
|
||||
break;
|
||||
if (i == MAX_MAX3100) {
|
||||
dev_warn(&spi->dev, "too many MAX3100 chips\n");
|
||||
mutex_unlock(&max3100s_lock);
|
||||
return -ENOMEM;
|
||||
return dev_err_probe(dev, -ENOMEM, "too many MAX3100 chips\n");
|
||||
}
|
||||
|
||||
max3100s[i] = kzalloc(sizeof(struct max3100_port), GFP_KERNEL);
|
||||
if (!max3100s[i]) {
|
||||
dev_warn(&spi->dev,
|
||||
"kmalloc for max3100 structure %d failed!\n", i);
|
||||
mutex_unlock(&max3100s_lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
max3100s[i]->spi = spi;
|
||||
max3100s[i]->irq = spi->irq;
|
||||
spin_lock_init(&max3100s[i]->conf_lock);
|
||||
spi_set_drvdata(spi, max3100s[i]);
|
||||
pdata = dev_get_platdata(&spi->dev);
|
||||
max3100s[i]->crystal = pdata->crystal;
|
||||
max3100s[i]->loopback = pdata->loopback;
|
||||
max3100s[i]->poll_time = msecs_to_jiffies(pdata->poll_time);
|
||||
if (pdata->poll_time > 0 && max3100s[i]->poll_time == 0)
|
||||
max3100s[i]->poll_time = 1;
|
||||
max3100s[i]->max3100_hw_suspend = pdata->max3100_hw_suspend;
|
||||
max3100s[i]->minor = i;
|
||||
timer_setup(&max3100s[i]->timer, max3100_timeout, 0);
|
||||
|
||||
dev_dbg(&spi->dev, "%s: adding port %d\n", __func__, i);
|
||||
max3100s[i]->port.irq = max3100s[i]->irq;
|
||||
max3100s[i]->port.uartclk = max3100s[i]->crystal ? 3686400 : 1843200;
|
||||
max3100s[i]->port.irq = spi->irq;
|
||||
max3100s[i]->port.fifosize = 16;
|
||||
max3100s[i]->port.ops = &max3100_ops;
|
||||
max3100s[i]->port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
|
||||
max3100s[i]->port.line = i;
|
||||
max3100s[i]->port.type = PORT_MAX3100;
|
||||
max3100s[i]->port.dev = &spi->dev;
|
||||
|
||||
/* Read clock frequency from a property, uart_add_one_port() will fail if it's not set */
|
||||
device_property_read_u32(dev, "clock-frequency", &max3100s[i]->port.uartclk);
|
||||
|
||||
retval = uart_add_one_port(&max3100_uart_driver, &max3100s[i]->port);
|
||||
if (retval < 0)
|
||||
dev_warn(&spi->dev,
|
||||
"uart_add_one_port failed for line %d with error %d\n",
|
||||
i, retval);
|
||||
dev_err_probe(dev, retval, "uart_add_one_port failed for line %d\n", i);
|
||||
|
||||
/* set shutdown mode to save power. Will be woken-up on open */
|
||||
if (max3100s[i]->max3100_hw_suspend)
|
||||
max3100s[i]->max3100_hw_suspend(1);
|
||||
else {
|
||||
tx = MAX3100_WC | MAX3100_SHDN;
|
||||
max3100_sr(max3100s[i], tx, &rx);
|
||||
}
|
||||
max3100_sr(max3100s[i], MAX3100_WC | MAX3100_SHDN, &rx);
|
||||
mutex_unlock(&max3100s_lock);
|
||||
return 0;
|
||||
}
|
||||
@ -830,32 +767,25 @@ static void max3100_remove(struct spi_device *spi)
|
||||
}
|
||||
pr_debug("removing max3100 driver\n");
|
||||
uart_unregister_driver(&max3100_uart_driver);
|
||||
uart_driver_registered = 0;
|
||||
|
||||
mutex_unlock(&max3100s_lock);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
||||
static int max3100_suspend(struct device *dev)
|
||||
{
|
||||
struct max3100_port *s = dev_get_drvdata(dev);
|
||||
u16 rx;
|
||||
|
||||
dev_dbg(&s->spi->dev, "%s\n", __func__);
|
||||
|
||||
disable_irq(s->irq);
|
||||
disable_irq(s->port.irq);
|
||||
|
||||
s->suspending = 1;
|
||||
uart_suspend_port(&max3100_uart_driver, &s->port);
|
||||
|
||||
if (s->max3100_hw_suspend)
|
||||
s->max3100_hw_suspend(1);
|
||||
else {
|
||||
/* no HW suspend, so do SW one */
|
||||
u16 tx, rx;
|
||||
|
||||
tx = MAX3100_WC | MAX3100_SHDN;
|
||||
max3100_sr(s, tx, &rx);
|
||||
}
|
||||
/* no HW suspend, so do SW one */
|
||||
max3100_sr(s, MAX3100_WC | MAX3100_SHDN, &rx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -865,12 +795,10 @@ static int max3100_resume(struct device *dev)
|
||||
|
||||
dev_dbg(&s->spi->dev, "%s\n", __func__);
|
||||
|
||||
if (s->max3100_hw_suspend)
|
||||
s->max3100_hw_suspend(0);
|
||||
uart_resume_port(&max3100_uart_driver, &s->port);
|
||||
s->suspending = 0;
|
||||
|
||||
enable_irq(s->irq);
|
||||
enable_irq(s->port.irq);
|
||||
|
||||
s->conf_commit = 1;
|
||||
if (s->workqueue)
|
||||
@ -879,20 +807,29 @@ static int max3100_resume(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(max3100_pm_ops, max3100_suspend, max3100_resume);
|
||||
#define MAX3100_PM_OPS (&max3100_pm_ops)
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(max3100_pm_ops, max3100_suspend, max3100_resume);
|
||||
|
||||
#else
|
||||
#define MAX3100_PM_OPS NULL
|
||||
#endif
|
||||
static const struct spi_device_id max3100_spi_id[] = {
|
||||
{ "max3100" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, max3100_spi_id);
|
||||
|
||||
static const struct of_device_id max3100_of_match[] = {
|
||||
{ .compatible = "maxim,max3100" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, max3100_of_match);
|
||||
|
||||
static struct spi_driver max3100_driver = {
|
||||
.driver = {
|
||||
.name = "max3100",
|
||||
.pm = MAX3100_PM_OPS,
|
||||
.of_match_table = max3100_of_match,
|
||||
.pm = pm_sleep_ptr(&max3100_pm_ops),
|
||||
},
|
||||
.probe = max3100_probe,
|
||||
.remove = max3100_remove,
|
||||
.id_table = max3100_spi_id,
|
||||
};
|
||||
|
||||
module_spi_driver(max3100_driver);
|
||||
@ -900,4 +837,3 @@ module_spi_driver(max3100_driver);
|
||||
MODULE_DESCRIPTION("MAX3100 driver");
|
||||
MODULE_AUTHOR("Christian Pellegrin <chripell@evolware.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("spi:max3100");
|
||||
|
@ -747,8 +747,9 @@ static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen)
|
||||
|
||||
static void max310x_handle_tx(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
unsigned int txlen, to_send, until_end;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned int txlen, to_send;
|
||||
unsigned char *tail;
|
||||
|
||||
if (unlikely(port->x_char)) {
|
||||
max310x_port_write(port, MAX310X_THR_REG, port->x_char);
|
||||
@ -757,32 +758,26 @@ static void max310x_handle_tx(struct uart_port *port)
|
||||
return;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port))
|
||||
if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port))
|
||||
return;
|
||||
|
||||
/* Get length of data pending in circular buffer */
|
||||
to_send = uart_circ_chars_pending(xmit);
|
||||
until_end = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
|
||||
if (likely(to_send)) {
|
||||
/*
|
||||
* It's a circ buffer -- wrap around.
|
||||
* We could do that in one SPI transaction, but meh.
|
||||
*/
|
||||
while (!kfifo_is_empty(&tport->xmit_fifo)) {
|
||||
/* Limit to space available in TX FIFO */
|
||||
txlen = max310x_port_read(port, MAX310X_TXFIFOLVL_REG);
|
||||
txlen = port->fifosize - txlen;
|
||||
to_send = (to_send > txlen) ? txlen : to_send;
|
||||
if (!txlen)
|
||||
break;
|
||||
|
||||
if (until_end < to_send) {
|
||||
/*
|
||||
* It's a circ buffer -- wrap around.
|
||||
* We could do that in one SPI transaction, but meh.
|
||||
*/
|
||||
max310x_batch_write(port, xmit->buf + xmit->tail, until_end);
|
||||
max310x_batch_write(port, xmit->buf, to_send - until_end);
|
||||
} else {
|
||||
max310x_batch_write(port, xmit->buf + xmit->tail, to_send);
|
||||
}
|
||||
to_send = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail, txlen);
|
||||
max310x_batch_write(port, tail, to_send);
|
||||
uart_xmit_advance(port, to_send);
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
}
|
||||
|
||||
@ -1478,7 +1473,7 @@ static struct regmap_config regcfg = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.write_flag_mask = MAX310X_WRITE_BIT,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.cache_type = REGCACHE_MAPLE,
|
||||
.max_register = MAX310X_REG_1F,
|
||||
.writeable_reg = max310x_reg_writeable,
|
||||
.volatile_reg = max310x_reg_volatile,
|
||||
@ -1582,7 +1577,7 @@ static int max310x_i2c_extended_reg_enable(struct device *dev, bool enable)
|
||||
static struct regmap_config regcfg_i2c = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.cache_type = REGCACHE_MAPLE,
|
||||
.writeable_reg = max310x_reg_writeable,
|
||||
.volatile_reg = max310x_reg_volatile,
|
||||
.precious_reg = max310x_reg_precious,
|
||||
|
@ -293,17 +293,14 @@ static void men_z135_handle_rx(struct men_z135_port *uart)
|
||||
static void men_z135_handle_tx(struct men_z135_port *uart)
|
||||
{
|
||||
struct uart_port *port = &uart->port;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned char *tail;
|
||||
unsigned int n, txfree;
|
||||
u32 txc;
|
||||
u32 wptr;
|
||||
int qlen;
|
||||
int n;
|
||||
int txfree;
|
||||
int head;
|
||||
int tail;
|
||||
int s;
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
if (kfifo_is_empty(&tport->xmit_fifo))
|
||||
goto out;
|
||||
|
||||
if (uart_tx_stopped(port))
|
||||
@ -313,7 +310,7 @@ static void men_z135_handle_tx(struct men_z135_port *uart)
|
||||
goto out;
|
||||
|
||||
/* calculate bytes to copy */
|
||||
qlen = uart_circ_chars_pending(xmit);
|
||||
qlen = kfifo_len(&tport->xmit_fifo);
|
||||
if (qlen <= 0)
|
||||
goto out;
|
||||
|
||||
@ -345,21 +342,18 @@ static void men_z135_handle_tx(struct men_z135_port *uart)
|
||||
if (n <= 0)
|
||||
goto irq_en;
|
||||
|
||||
head = xmit->head & (UART_XMIT_SIZE - 1);
|
||||
tail = xmit->tail & (UART_XMIT_SIZE - 1);
|
||||
n = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail,
|
||||
min_t(unsigned int, UART_XMIT_SIZE, n));
|
||||
memcpy_toio(port->membase + MEN_Z135_TX_RAM, tail, n);
|
||||
|
||||
s = ((head >= tail) ? head : UART_XMIT_SIZE) - tail;
|
||||
n = min(n, s);
|
||||
|
||||
memcpy_toio(port->membase + MEN_Z135_TX_RAM, &xmit->buf[xmit->tail], n);
|
||||
iowrite32(n & 0x3ff, port->membase + MEN_Z135_TX_CTRL);
|
||||
uart_xmit_advance(port, n);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
irq_en:
|
||||
if (!uart_circ_empty(xmit))
|
||||
if (!kfifo_is_empty(&tport->xmit_fifo))
|
||||
men_z135_reg_set(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN);
|
||||
else
|
||||
men_z135_reg_clr(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN);
|
||||
|
@ -141,8 +141,8 @@ static void meson_uart_shutdown(struct uart_port *port)
|
||||
|
||||
static void meson_uart_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
unsigned int ch;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned char ch;
|
||||
u32 val;
|
||||
|
||||
if (uart_tx_stopped(port)) {
|
||||
@ -158,21 +158,19 @@ static void meson_uart_start_tx(struct uart_port *port)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
if (!uart_fifo_get(port, &ch))
|
||||
break;
|
||||
|
||||
ch = xmit->buf[xmit->tail];
|
||||
writel(ch, port->membase + AML_UART_WFIFO);
|
||||
uart_xmit_advance(port, 1);
|
||||
}
|
||||
|
||||
if (!uart_circ_empty(xmit)) {
|
||||
if (!kfifo_is_empty(&tport->xmit_fifo)) {
|
||||
val = readl(port->membase + AML_UART_CONTROL);
|
||||
val |= AML_UART_TX_INT_EN;
|
||||
writel(val, port->membase + AML_UART_CONTROL);
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ static void mlb_usio_stop_tx(struct uart_port *port)
|
||||
|
||||
static void mlb_usio_tx_chars(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
int count;
|
||||
|
||||
writew(readw(port->membase + MLB_USIO_REG_FCR) & ~MLB_USIO_FCR_FTIE,
|
||||
@ -87,7 +87,7 @@ static void mlb_usio_tx_chars(struct uart_port *port)
|
||||
port->x_char = 0;
|
||||
return;
|
||||
}
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
|
||||
if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
|
||||
mlb_usio_stop_tx(port);
|
||||
return;
|
||||
}
|
||||
@ -96,12 +96,13 @@ static void mlb_usio_tx_chars(struct uart_port *port)
|
||||
(readw(port->membase + MLB_USIO_REG_FBYTE) & 0xff);
|
||||
|
||||
do {
|
||||
writew(xmit->buf[xmit->tail], port->membase + MLB_USIO_REG_DR);
|
||||
unsigned char ch;
|
||||
|
||||
uart_xmit_advance(port, 1);
|
||||
if (uart_circ_empty(xmit))
|
||||
if (!uart_fifo_get(port, &ch))
|
||||
break;
|
||||
|
||||
writew(ch, port->membase + MLB_USIO_REG_DR);
|
||||
port->icount.tx++;
|
||||
} while (--count > 0);
|
||||
|
||||
writew(readw(port->membase + MLB_USIO_REG_FCR) & ~MLB_USIO_FCR_FDRQ,
|
||||
@ -110,10 +111,10 @@ static void mlb_usio_tx_chars(struct uart_port *port)
|
||||
writeb(readb(port->membase + MLB_USIO_REG_SCR) | MLB_USIO_SCR_TBIE,
|
||||
port->membase + MLB_USIO_REG_SCR);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
if (kfifo_is_empty(&tport->xmit_fifo))
|
||||
mlb_usio_stop_tx(port);
|
||||
}
|
||||
|
||||
|
@ -161,11 +161,16 @@ enum {
|
||||
struct msm_dma {
|
||||
struct dma_chan *chan;
|
||||
enum dma_data_direction dir;
|
||||
dma_addr_t phys;
|
||||
unsigned char *virt;
|
||||
union {
|
||||
struct {
|
||||
dma_addr_t phys;
|
||||
unsigned char *virt;
|
||||
unsigned int count;
|
||||
} rx;
|
||||
struct scatterlist tx_sg;
|
||||
};
|
||||
dma_cookie_t cookie;
|
||||
u32 enable_bit;
|
||||
unsigned int count;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
};
|
||||
|
||||
@ -249,8 +254,12 @@ static void msm_stop_dma(struct uart_port *port, struct msm_dma *dma)
|
||||
unsigned int mapped;
|
||||
u32 val;
|
||||
|
||||
mapped = dma->count;
|
||||
dma->count = 0;
|
||||
if (dma->dir == DMA_TO_DEVICE) {
|
||||
mapped = sg_dma_len(&dma->tx_sg);
|
||||
} else {
|
||||
mapped = dma->rx.count;
|
||||
dma->rx.count = 0;
|
||||
}
|
||||
|
||||
dmaengine_terminate_all(dma->chan);
|
||||
|
||||
@ -265,8 +274,13 @@ static void msm_stop_dma(struct uart_port *port, struct msm_dma *dma)
|
||||
val &= ~dma->enable_bit;
|
||||
msm_write(port, val, UARTDM_DMEN);
|
||||
|
||||
if (mapped)
|
||||
dma_unmap_single(dev, dma->phys, mapped, dma->dir);
|
||||
if (mapped) {
|
||||
if (dma->dir == DMA_TO_DEVICE) {
|
||||
dma_unmap_sg(dev, &dma->tx_sg, 1, dma->dir);
|
||||
sg_init_table(&dma->tx_sg, 1);
|
||||
} else
|
||||
dma_unmap_single(dev, dma->rx.phys, mapped, dma->dir);
|
||||
}
|
||||
}
|
||||
|
||||
static void msm_release_dma(struct msm_port *msm_port)
|
||||
@ -285,7 +299,7 @@ static void msm_release_dma(struct msm_port *msm_port)
|
||||
if (dma->chan) {
|
||||
msm_stop_dma(&msm_port->uart, dma);
|
||||
dma_release_channel(dma->chan);
|
||||
kfree(dma->virt);
|
||||
kfree(dma->rx.virt);
|
||||
}
|
||||
|
||||
memset(dma, 0, sizeof(*dma));
|
||||
@ -357,8 +371,8 @@ static void msm_request_rx_dma(struct msm_port *msm_port, resource_size_t base)
|
||||
|
||||
of_property_read_u32(dev->of_node, "qcom,rx-crci", &crci);
|
||||
|
||||
dma->virt = kzalloc(UARTDM_RX_SIZE, GFP_KERNEL);
|
||||
if (!dma->virt)
|
||||
dma->rx.virt = kzalloc(UARTDM_RX_SIZE, GFP_KERNEL);
|
||||
if (!dma->rx.virt)
|
||||
goto rel_rx;
|
||||
|
||||
memset(&conf, 0, sizeof(conf));
|
||||
@ -385,7 +399,7 @@ static void msm_request_rx_dma(struct msm_port *msm_port, resource_size_t base)
|
||||
|
||||
return;
|
||||
err:
|
||||
kfree(dma->virt);
|
||||
kfree(dma->rx.virt);
|
||||
rel_rx:
|
||||
dma_release_channel(dma->chan);
|
||||
no_rx:
|
||||
@ -420,7 +434,7 @@ static void msm_start_tx(struct uart_port *port)
|
||||
struct msm_dma *dma = &msm_port->tx_dma;
|
||||
|
||||
/* Already started in DMA mode */
|
||||
if (dma->count)
|
||||
if (sg_dma_len(&dma->tx_sg))
|
||||
return;
|
||||
|
||||
msm_port->imr |= MSM_UART_IMR_TXLEV;
|
||||
@ -438,7 +452,7 @@ static void msm_complete_tx_dma(void *args)
|
||||
{
|
||||
struct msm_port *msm_port = args;
|
||||
struct uart_port *port = &msm_port->uart;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
struct msm_dma *dma = &msm_port->tx_dma;
|
||||
struct dma_tx_state state;
|
||||
unsigned long flags;
|
||||
@ -448,12 +462,12 @@ static void msm_complete_tx_dma(void *args)
|
||||
uart_port_lock_irqsave(port, &flags);
|
||||
|
||||
/* Already stopped */
|
||||
if (!dma->count)
|
||||
if (!sg_dma_len(&dma->tx_sg))
|
||||
goto done;
|
||||
|
||||
dmaengine_tx_status(dma->chan, dma->cookie, &state);
|
||||
|
||||
dma_unmap_single(port->dev, dma->phys, dma->count, dma->dir);
|
||||
dma_unmap_sg(port->dev, &dma->tx_sg, 1, dma->dir);
|
||||
|
||||
val = msm_read(port, UARTDM_DMEN);
|
||||
val &= ~dma->enable_bit;
|
||||
@ -464,15 +478,15 @@ static void msm_complete_tx_dma(void *args)
|
||||
msm_write(port, MSM_UART_CR_TX_ENABLE, MSM_UART_CR);
|
||||
}
|
||||
|
||||
count = dma->count - state.residue;
|
||||
count = sg_dma_len(&dma->tx_sg) - state.residue;
|
||||
uart_xmit_advance(port, count);
|
||||
dma->count = 0;
|
||||
sg_init_table(&dma->tx_sg, 1);
|
||||
|
||||
/* Restore "Tx FIFO below watermark" interrupt */
|
||||
msm_port->imr |= MSM_UART_IMR_TXLEV;
|
||||
msm_write(port, msm_port->imr, MSM_UART_IMR);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
msm_handle_tx(port);
|
||||
@ -482,22 +496,24 @@ done:
|
||||
|
||||
static int msm_handle_tx_dma(struct msm_port *msm_port, unsigned int count)
|
||||
{
|
||||
struct circ_buf *xmit = &msm_port->uart.state->xmit;
|
||||
struct uart_port *port = &msm_port->uart;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
struct msm_dma *dma = &msm_port->tx_dma;
|
||||
void *cpu_addr;
|
||||
unsigned int mapped;
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
cpu_addr = &xmit->buf[xmit->tail];
|
||||
sg_init_table(&dma->tx_sg, 1);
|
||||
kfifo_dma_out_prepare(&tport->xmit_fifo, &dma->tx_sg, 1, count);
|
||||
|
||||
dma->phys = dma_map_single(port->dev, cpu_addr, count, dma->dir);
|
||||
ret = dma_mapping_error(port->dev, dma->phys);
|
||||
if (ret)
|
||||
return ret;
|
||||
mapped = dma_map_sg(port->dev, &dma->tx_sg, 1, dma->dir);
|
||||
if (!mapped) {
|
||||
ret = -EIO;
|
||||
goto zero_sg;
|
||||
}
|
||||
|
||||
dma->desc = dmaengine_prep_slave_single(dma->chan, dma->phys,
|
||||
count, DMA_MEM_TO_DEV,
|
||||
dma->desc = dmaengine_prep_slave_sg(dma->chan, &dma->tx_sg, 1,
|
||||
DMA_MEM_TO_DEV,
|
||||
DMA_PREP_INTERRUPT |
|
||||
DMA_PREP_FENCE);
|
||||
if (!dma->desc) {
|
||||
@ -520,8 +536,6 @@ static int msm_handle_tx_dma(struct msm_port *msm_port, unsigned int count)
|
||||
msm_port->imr &= ~MSM_UART_IMR_TXLEV;
|
||||
msm_write(port, msm_port->imr, MSM_UART_IMR);
|
||||
|
||||
dma->count = count;
|
||||
|
||||
val = msm_read(port, UARTDM_DMEN);
|
||||
val |= dma->enable_bit;
|
||||
|
||||
@ -536,7 +550,9 @@ static int msm_handle_tx_dma(struct msm_port *msm_port, unsigned int count)
|
||||
dma_async_issue_pending(dma->chan);
|
||||
return 0;
|
||||
unmap:
|
||||
dma_unmap_single(port->dev, dma->phys, count, dma->dir);
|
||||
dma_unmap_sg(port->dev, &dma->tx_sg, 1, dma->dir);
|
||||
zero_sg:
|
||||
sg_init_table(&dma->tx_sg, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -553,7 +569,7 @@ static void msm_complete_rx_dma(void *args)
|
||||
uart_port_lock_irqsave(port, &flags);
|
||||
|
||||
/* Already stopped */
|
||||
if (!dma->count)
|
||||
if (!dma->rx.count)
|
||||
goto done;
|
||||
|
||||
val = msm_read(port, UARTDM_DMEN);
|
||||
@ -570,14 +586,14 @@ static void msm_complete_rx_dma(void *args)
|
||||
|
||||
port->icount.rx += count;
|
||||
|
||||
dma->count = 0;
|
||||
dma->rx.count = 0;
|
||||
|
||||
dma_unmap_single(port->dev, dma->phys, UARTDM_RX_SIZE, dma->dir);
|
||||
dma_unmap_single(port->dev, dma->rx.phys, UARTDM_RX_SIZE, dma->dir);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
char flag = TTY_NORMAL;
|
||||
|
||||
if (msm_port->break_detected && dma->virt[i] == 0) {
|
||||
if (msm_port->break_detected && dma->rx.virt[i] == 0) {
|
||||
port->icount.brk++;
|
||||
flag = TTY_BREAK;
|
||||
msm_port->break_detected = false;
|
||||
@ -588,9 +604,9 @@ static void msm_complete_rx_dma(void *args)
|
||||
if (!(port->read_status_mask & MSM_UART_SR_RX_BREAK))
|
||||
flag = TTY_NORMAL;
|
||||
|
||||
sysrq = uart_prepare_sysrq_char(port, dma->virt[i]);
|
||||
sysrq = uart_prepare_sysrq_char(port, dma->rx.virt[i]);
|
||||
if (!sysrq)
|
||||
tty_insert_flip_char(tport, dma->virt[i], flag);
|
||||
tty_insert_flip_char(tport, dma->rx.virt[i], flag);
|
||||
}
|
||||
|
||||
msm_start_rx_dma(msm_port);
|
||||
@ -614,13 +630,13 @@ static void msm_start_rx_dma(struct msm_port *msm_port)
|
||||
if (!dma->chan)
|
||||
return;
|
||||
|
||||
dma->phys = dma_map_single(uart->dev, dma->virt,
|
||||
dma->rx.phys = dma_map_single(uart->dev, dma->rx.virt,
|
||||
UARTDM_RX_SIZE, dma->dir);
|
||||
ret = dma_mapping_error(uart->dev, dma->phys);
|
||||
ret = dma_mapping_error(uart->dev, dma->rx.phys);
|
||||
if (ret)
|
||||
goto sw_mode;
|
||||
|
||||
dma->desc = dmaengine_prep_slave_single(dma->chan, dma->phys,
|
||||
dma->desc = dmaengine_prep_slave_single(dma->chan, dma->rx.phys,
|
||||
UARTDM_RX_SIZE, DMA_DEV_TO_MEM,
|
||||
DMA_PREP_INTERRUPT);
|
||||
if (!dma->desc)
|
||||
@ -648,7 +664,7 @@ static void msm_start_rx_dma(struct msm_port *msm_port)
|
||||
|
||||
msm_write(uart, msm_port->imr, MSM_UART_IMR);
|
||||
|
||||
dma->count = UARTDM_RX_SIZE;
|
||||
dma->rx.count = UARTDM_RX_SIZE;
|
||||
|
||||
dma_async_issue_pending(dma->chan);
|
||||
|
||||
@ -668,7 +684,7 @@ static void msm_start_rx_dma(struct msm_port *msm_port)
|
||||
|
||||
return;
|
||||
unmap:
|
||||
dma_unmap_single(uart->dev, dma->phys, UARTDM_RX_SIZE, dma->dir);
|
||||
dma_unmap_single(uart->dev, dma->rx.phys, UARTDM_RX_SIZE, dma->dir);
|
||||
|
||||
sw_mode:
|
||||
/*
|
||||
@ -831,8 +847,8 @@ static void msm_handle_rx(struct uart_port *port)
|
||||
|
||||
static void msm_handle_tx_pio(struct uart_port *port, unsigned int tx_count)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct msm_port *msm_port = to_msm_port(port);
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned int num_chars;
|
||||
unsigned int tf_pointer = 0;
|
||||
void __iomem *tf;
|
||||
@ -846,8 +862,7 @@ static void msm_handle_tx_pio(struct uart_port *port, unsigned int tx_count)
|
||||
msm_reset_dm_count(port, tx_count);
|
||||
|
||||
while (tf_pointer < tx_count) {
|
||||
int i;
|
||||
char buf[4] = { 0 };
|
||||
unsigned char buf[4] = { 0 };
|
||||
|
||||
if (!(msm_read(port, MSM_UART_SR) & MSM_UART_SR_TX_READY))
|
||||
break;
|
||||
@ -858,26 +873,23 @@ static void msm_handle_tx_pio(struct uart_port *port, unsigned int tx_count)
|
||||
else
|
||||
num_chars = 1;
|
||||
|
||||
for (i = 0; i < num_chars; i++)
|
||||
buf[i] = xmit->buf[xmit->tail + i];
|
||||
|
||||
num_chars = uart_fifo_out(port, buf, num_chars);
|
||||
iowrite32_rep(tf, buf, 1);
|
||||
uart_xmit_advance(port, num_chars);
|
||||
tf_pointer += num_chars;
|
||||
}
|
||||
|
||||
/* disable tx interrupts if nothing more to send */
|
||||
if (uart_circ_empty(xmit))
|
||||
if (kfifo_is_empty(&tport->xmit_fifo))
|
||||
msm_stop_tx(port);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
}
|
||||
|
||||
static void msm_handle_tx(struct uart_port *port)
|
||||
{
|
||||
struct msm_port *msm_port = to_msm_port(port);
|
||||
struct circ_buf *xmit = &msm_port->uart.state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
struct msm_dma *dma = &msm_port->tx_dma;
|
||||
unsigned int pio_count, dma_count, dma_min;
|
||||
char buf[4] = { 0 };
|
||||
@ -901,13 +913,13 @@ static void msm_handle_tx(struct uart_port *port)
|
||||
return;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
|
||||
if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
|
||||
msm_stop_tx(port);
|
||||
return;
|
||||
}
|
||||
|
||||
pio_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
|
||||
dma_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
|
||||
dma_count = pio_count = kfifo_out_linear(&tport->xmit_fifo, NULL,
|
||||
UART_XMIT_SIZE);
|
||||
|
||||
dma_min = 1; /* Always DMA */
|
||||
if (msm_port->is_uartdm > UARTDM_1P3) {
|
||||
@ -955,7 +967,7 @@ static irqreturn_t msm_uart_irq(int irq, void *dev_id)
|
||||
}
|
||||
|
||||
if (misr & (MSM_UART_IMR_RXLEV | MSM_UART_IMR_RXSTALE)) {
|
||||
if (dma->count) {
|
||||
if (dma->rx.count) {
|
||||
val = MSM_UART_CR_CMD_STALE_EVENT_DISABLE;
|
||||
msm_write(port, val, MSM_UART_CR);
|
||||
val = MSM_UART_CR_CMD_RESET_STALE_INT;
|
||||
|
@ -219,12 +219,10 @@ static void mvebu_uart_stop_tx(struct uart_port *port)
|
||||
static void mvebu_uart_start_tx(struct uart_port *port)
|
||||
{
|
||||
unsigned int ctl;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
unsigned char c;
|
||||
|
||||
if (IS_EXTENDED(port) && !uart_circ_empty(xmit)) {
|
||||
writel(xmit->buf[xmit->tail], port->membase + UART_TSH(port));
|
||||
uart_xmit_advance(port, 1);
|
||||
}
|
||||
if (IS_EXTENDED(port) && uart_fifo_get(port, &c))
|
||||
writel(c, port->membase + UART_TSH(port));
|
||||
|
||||
ctl = readl(port->membase + UART_INTR(port));
|
||||
ctl |= CTRL_TX_RDY_INT(port);
|
||||
|
@ -517,7 +517,7 @@ static void mxs_auart_tx_chars(struct mxs_auart_port *s);
|
||||
static void dma_tx_callback(void *param)
|
||||
{
|
||||
struct mxs_auart_port *s = param;
|
||||
struct circ_buf *xmit = &s->port.state->xmit;
|
||||
struct tty_port *tport = &s->port.state->port;
|
||||
|
||||
dma_unmap_sg(s->dev, &s->tx_sgl, 1, DMA_TO_DEVICE);
|
||||
|
||||
@ -526,7 +526,7 @@ static void dma_tx_callback(void *param)
|
||||
smp_mb__after_atomic();
|
||||
|
||||
/* wake up the possible processes. */
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&s->port);
|
||||
|
||||
mxs_auart_tx_chars(s);
|
||||
@ -568,33 +568,22 @@ static int mxs_auart_dma_tx(struct mxs_auart_port *s, int size)
|
||||
|
||||
static void mxs_auart_tx_chars(struct mxs_auart_port *s)
|
||||
{
|
||||
struct circ_buf *xmit = &s->port.state->xmit;
|
||||
struct tty_port *tport = &s->port.state->port;
|
||||
bool pending;
|
||||
u8 ch;
|
||||
|
||||
if (auart_dma_enabled(s)) {
|
||||
u32 i = 0;
|
||||
int size;
|
||||
void *buffer = s->tx_dma_buf;
|
||||
|
||||
if (test_and_set_bit(MXS_AUART_DMA_TX_SYNC, &s->flags))
|
||||
return;
|
||||
|
||||
while (!uart_circ_empty(xmit) && !uart_tx_stopped(&s->port)) {
|
||||
size = min_t(u32, UART_XMIT_SIZE - i,
|
||||
CIRC_CNT_TO_END(xmit->head,
|
||||
xmit->tail,
|
||||
UART_XMIT_SIZE));
|
||||
memcpy(buffer + i, xmit->buf + xmit->tail, size);
|
||||
xmit->tail = (xmit->tail + size) & (UART_XMIT_SIZE - 1);
|
||||
|
||||
i += size;
|
||||
if (i >= UART_XMIT_SIZE)
|
||||
break;
|
||||
}
|
||||
|
||||
if (uart_tx_stopped(&s->port))
|
||||
mxs_auart_stop_tx(&s->port);
|
||||
else
|
||||
i = kfifo_out(&tport->xmit_fifo, buffer,
|
||||
UART_XMIT_SIZE);
|
||||
|
||||
if (i) {
|
||||
mxs_auart_dma_tx(s, i);
|
||||
|
@ -1093,7 +1093,6 @@ static void __maybe_unused wait_for_xmitr(struct uart_omap_port *up)
|
||||
|
||||
/* Wait up to 1s for flow control if necessary */
|
||||
if (up->port.flags & UPF_CONS_FLOW) {
|
||||
tmout = 1000000;
|
||||
for (tmout = 1000000; tmout; tmout--) {
|
||||
unsigned int msr = serial_in(up, UART_MSR);
|
||||
|
||||
|
@ -808,7 +808,7 @@ static int dma_handle_rx(struct eg20t_port *priv)
|
||||
static unsigned int handle_tx(struct eg20t_port *priv)
|
||||
{
|
||||
struct uart_port *port = &priv->port;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
unsigned char ch;
|
||||
int fifo_size;
|
||||
int tx_empty;
|
||||
|
||||
@ -830,9 +830,9 @@ static unsigned int handle_tx(struct eg20t_port *priv)
|
||||
fifo_size--;
|
||||
}
|
||||
|
||||
while (!uart_tx_stopped(port) && !uart_circ_empty(xmit) && fifo_size) {
|
||||
iowrite8(xmit->buf[xmit->tail], priv->membase + PCH_UART_THR);
|
||||
uart_xmit_advance(port, 1);
|
||||
while (!uart_tx_stopped(port) && fifo_size &&
|
||||
uart_fifo_get(port, &ch)) {
|
||||
iowrite8(ch, priv->membase + PCH_UART_THR);
|
||||
fifo_size--;
|
||||
tx_empty = 0;
|
||||
}
|
||||
@ -850,14 +850,14 @@ static unsigned int handle_tx(struct eg20t_port *priv)
|
||||
static unsigned int dma_handle_tx(struct eg20t_port *priv)
|
||||
{
|
||||
struct uart_port *port = &priv->port;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
struct scatterlist *sg;
|
||||
int nent;
|
||||
int fifo_size;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
unsigned int bytes, tail;
|
||||
int num;
|
||||
int i;
|
||||
int bytes;
|
||||
int size;
|
||||
int rem;
|
||||
|
||||
@ -886,7 +886,7 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
|
||||
fifo_size--;
|
||||
}
|
||||
|
||||
bytes = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
|
||||
bytes = kfifo_out_linear(&tport->xmit_fifo, &tail, UART_XMIT_SIZE);
|
||||
if (!bytes) {
|
||||
dev_dbg(priv->port.dev, "%s 0 bytes return\n", __func__);
|
||||
pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
|
||||
@ -920,10 +920,10 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
|
||||
|
||||
for (i = 0; i < num; i++, sg++) {
|
||||
if (i == (num - 1))
|
||||
sg_set_page(sg, virt_to_page(xmit->buf),
|
||||
sg_set_page(sg, virt_to_page(tport->xmit_buf),
|
||||
rem, fifo_size * i);
|
||||
else
|
||||
sg_set_page(sg, virt_to_page(xmit->buf),
|
||||
sg_set_page(sg, virt_to_page(tport->xmit_buf),
|
||||
size, fifo_size * i);
|
||||
}
|
||||
|
||||
@ -937,8 +937,7 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
|
||||
priv->nent = nent;
|
||||
|
||||
for (i = 0; i < nent; i++, sg++) {
|
||||
sg->offset = (xmit->tail & (UART_XMIT_SIZE - 1)) +
|
||||
fifo_size * i;
|
||||
sg->offset = tail + fifo_size * i;
|
||||
sg_dma_address(sg) = (sg_dma_address(sg) &
|
||||
~(UART_XMIT_SIZE - 1)) + sg->offset;
|
||||
if (i == (nent - 1))
|
||||
|
@ -8,11 +8,11 @@
|
||||
* Sorin-Andrei Pistirica <andrei.pistirica@microchip.com>
|
||||
*/
|
||||
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
@ -342,7 +342,7 @@ static void pic32_uart_do_rx(struct uart_port *port)
|
||||
static void pic32_uart_do_tx(struct uart_port *port)
|
||||
{
|
||||
struct pic32_sport *sport = to_pic32_sport(port);
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned int max_count = PIC32_UART_TX_FIFO_DEPTH;
|
||||
|
||||
if (port->x_char) {
|
||||
@ -357,7 +357,7 @@ static void pic32_uart_do_tx(struct uart_port *port)
|
||||
return;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
if (kfifo_is_empty(&tport->xmit_fifo))
|
||||
goto txq_empty;
|
||||
|
||||
/* keep stuffing chars into uart tx buffer
|
||||
@ -371,21 +371,20 @@ static void pic32_uart_do_tx(struct uart_port *port)
|
||||
*/
|
||||
while (!(PIC32_UART_STA_UTXBF &
|
||||
pic32_uart_readl(sport, PIC32_UART_STA))) {
|
||||
unsigned int c = xmit->buf[xmit->tail];
|
||||
unsigned char c;
|
||||
|
||||
if (!uart_fifo_get(port, &c))
|
||||
break;
|
||||
pic32_uart_writel(sport, PIC32_UART_TX, c);
|
||||
|
||||
uart_xmit_advance(port, 1);
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
if (--max_count == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
if (kfifo_is_empty(&tport->xmit_fifo))
|
||||
goto txq_empty;
|
||||
|
||||
return;
|
||||
|
@ -333,7 +333,8 @@ static void pmz_status_handle(struct uart_pmac_port *uap)
|
||||
|
||||
static void pmz_transmit_chars(struct uart_pmac_port *uap)
|
||||
{
|
||||
struct circ_buf *xmit;
|
||||
struct tty_port *tport;
|
||||
unsigned char ch;
|
||||
|
||||
if (ZS_IS_CONS(uap)) {
|
||||
unsigned char status = read_zsreg(uap, R0);
|
||||
@ -384,8 +385,8 @@ static void pmz_transmit_chars(struct uart_pmac_port *uap)
|
||||
|
||||
if (uap->port.state == NULL)
|
||||
goto ack_tx_int;
|
||||
xmit = &uap->port.state->xmit;
|
||||
if (uart_circ_empty(xmit)) {
|
||||
tport = &uap->port.state->port;
|
||||
if (kfifo_is_empty(&tport->xmit_fifo)) {
|
||||
uart_write_wakeup(&uap->port);
|
||||
goto ack_tx_int;
|
||||
}
|
||||
@ -393,12 +394,11 @@ static void pmz_transmit_chars(struct uart_pmac_port *uap)
|
||||
goto ack_tx_int;
|
||||
|
||||
uap->flags |= PMACZILOG_FLAG_TX_ACTIVE;
|
||||
write_zsdata(uap, xmit->buf[xmit->tail]);
|
||||
WARN_ON(!uart_fifo_get(&uap->port, &ch));
|
||||
write_zsdata(uap, ch);
|
||||
zssync(uap);
|
||||
|
||||
uart_xmit_advance(&uap->port, 1);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&uap->port);
|
||||
|
||||
return;
|
||||
@ -606,15 +606,15 @@ static void pmz_start_tx(struct uart_port *port)
|
||||
port->icount.tx++;
|
||||
port->x_char = 0;
|
||||
} else {
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned char ch;
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
if (!uart_fifo_get(&uap->port, &ch))
|
||||
return;
|
||||
write_zsdata(uap, xmit->buf[xmit->tail]);
|
||||
write_zsdata(uap, ch);
|
||||
zssync(uap);
|
||||
uart_xmit_advance(port, 1);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&uap->port);
|
||||
}
|
||||
}
|
||||
@ -1681,7 +1681,7 @@ static void pmz_dispose_port(struct uart_pmac_port *uap)
|
||||
memset(uap, 0, sizeof(struct uart_pmac_port));
|
||||
}
|
||||
|
||||
static int __init pmz_attach(struct platform_device *pdev)
|
||||
static int pmz_attach(struct platform_device *pdev)
|
||||
{
|
||||
struct uart_pmac_port *uap;
|
||||
int i;
|
||||
@ -1700,7 +1700,7 @@ static int __init pmz_attach(struct platform_device *pdev)
|
||||
return uart_add_one_port(&pmz_uart_reg, &uap->port);
|
||||
}
|
||||
|
||||
static void __exit pmz_detach(struct platform_device *pdev)
|
||||
static void pmz_detach(struct platform_device *pdev)
|
||||
{
|
||||
struct uart_pmac_port *uap = platform_get_drvdata(pdev);
|
||||
|
||||
@ -1775,7 +1775,8 @@ static struct macio_driver pmz_driver = {
|
||||
#else
|
||||
|
||||
static struct platform_driver pmz_driver = {
|
||||
.remove_new = __exit_p(pmz_detach),
|
||||
.probe = pmz_attach,
|
||||
.remove_new = pmz_detach,
|
||||
.driver = {
|
||||
.name = "scc",
|
||||
},
|
||||
@ -1823,7 +1824,7 @@ static int __init init_pmz(void)
|
||||
#ifdef CONFIG_PPC_PMAC
|
||||
return macio_register_driver(&pmz_driver);
|
||||
#else
|
||||
return platform_driver_probe(&pmz_driver, pmz_attach);
|
||||
return platform_driver_register(&pmz_driver);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -505,7 +505,7 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s,
|
||||
*/
|
||||
qcom_geni_serial_poll_tx_done(uport);
|
||||
|
||||
if (!uart_circ_empty(&uport->state->xmit)) {
|
||||
if (!kfifo_is_empty(&uport->state->port.xmit_fifo)) {
|
||||
irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN);
|
||||
writel(irq_en | M_TX_FIFO_WATERMARK_EN,
|
||||
uport->membase + SE_GENI_M_IRQ_EN);
|
||||
@ -620,22 +620,24 @@ static void qcom_geni_serial_stop_tx_dma(struct uart_port *uport)
|
||||
static void qcom_geni_serial_start_tx_dma(struct uart_port *uport)
|
||||
{
|
||||
struct qcom_geni_serial_port *port = to_dev_port(uport);
|
||||
struct circ_buf *xmit = &uport->state->xmit;
|
||||
struct tty_port *tport = &uport->state->port;
|
||||
unsigned int xmit_size;
|
||||
u8 *tail;
|
||||
int ret;
|
||||
|
||||
if (port->tx_dma_addr)
|
||||
return;
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
if (kfifo_is_empty(&tport->xmit_fifo))
|
||||
return;
|
||||
|
||||
xmit_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
|
||||
xmit_size = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail,
|
||||
UART_XMIT_SIZE);
|
||||
|
||||
qcom_geni_serial_setup_tx(uport, xmit_size);
|
||||
|
||||
ret = geni_se_tx_dma_prep(&port->se, &xmit->buf[xmit->tail],
|
||||
xmit_size, &port->tx_dma_addr);
|
||||
ret = geni_se_tx_dma_prep(&port->se, tail, xmit_size,
|
||||
&port->tx_dma_addr);
|
||||
if (ret) {
|
||||
dev_err(uport->dev, "unable to start TX SE DMA: %d\n", ret);
|
||||
qcom_geni_serial_stop_tx_dma(uport);
|
||||
@ -853,18 +855,14 @@ static void qcom_geni_serial_send_chunk_fifo(struct uart_port *uport,
|
||||
unsigned int chunk)
|
||||
{
|
||||
struct qcom_geni_serial_port *port = to_dev_port(uport);
|
||||
struct circ_buf *xmit = &uport->state->xmit;
|
||||
unsigned int tx_bytes, c, remaining = chunk;
|
||||
unsigned int tx_bytes, remaining = chunk;
|
||||
u8 buf[BYTES_PER_FIFO_WORD];
|
||||
|
||||
while (remaining) {
|
||||
memset(buf, 0, sizeof(buf));
|
||||
tx_bytes = min(remaining, BYTES_PER_FIFO_WORD);
|
||||
|
||||
for (c = 0; c < tx_bytes ; c++) {
|
||||
buf[c] = xmit->buf[xmit->tail];
|
||||
uart_xmit_advance(uport, 1);
|
||||
}
|
||||
tx_bytes = uart_fifo_out(uport, buf, tx_bytes);
|
||||
|
||||
iowrite32_rep(uport->membase + SE_GENI_TX_FIFOn, buf, 1);
|
||||
|
||||
@ -877,7 +875,7 @@ static void qcom_geni_serial_handle_tx_fifo(struct uart_port *uport,
|
||||
bool done, bool active)
|
||||
{
|
||||
struct qcom_geni_serial_port *port = to_dev_port(uport);
|
||||
struct circ_buf *xmit = &uport->state->xmit;
|
||||
struct tty_port *tport = &uport->state->port;
|
||||
size_t avail;
|
||||
size_t pending;
|
||||
u32 status;
|
||||
@ -890,7 +888,7 @@ static void qcom_geni_serial_handle_tx_fifo(struct uart_port *uport,
|
||||
if (active)
|
||||
pending = port->tx_remaining;
|
||||
else
|
||||
pending = uart_circ_chars_pending(xmit);
|
||||
pending = kfifo_len(&tport->xmit_fifo);
|
||||
|
||||
/* All data has been transmitted and acknowledged as received */
|
||||
if (!pending && !status && done) {
|
||||
@ -933,24 +931,24 @@ out_write_wakeup:
|
||||
uport->membase + SE_GENI_M_IRQ_EN);
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(uport);
|
||||
}
|
||||
|
||||
static void qcom_geni_serial_handle_tx_dma(struct uart_port *uport)
|
||||
{
|
||||
struct qcom_geni_serial_port *port = to_dev_port(uport);
|
||||
struct circ_buf *xmit = &uport->state->xmit;
|
||||
struct tty_port *tport = &uport->state->port;
|
||||
|
||||
uart_xmit_advance(uport, port->tx_remaining);
|
||||
geni_se_tx_dma_unprep(&port->se, port->tx_dma_addr, port->tx_remaining);
|
||||
port->tx_dma_addr = 0;
|
||||
port->tx_remaining = 0;
|
||||
|
||||
if (!uart_circ_empty(xmit))
|
||||
if (!kfifo_is_empty(&tport->xmit_fifo))
|
||||
qcom_geni_serial_start_tx_dma(uport);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(uport);
|
||||
}
|
||||
|
||||
|
@ -330,8 +330,8 @@ static void rda_uart_set_termios(struct uart_port *port,
|
||||
|
||||
static void rda_uart_send_chars(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
unsigned int ch;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned char ch;
|
||||
u32 val;
|
||||
|
||||
if (uart_tx_stopped(port))
|
||||
@ -347,19 +347,14 @@ static void rda_uart_send_chars(struct uart_port *port)
|
||||
port->x_char = 0;
|
||||
}
|
||||
|
||||
while (rda_uart_read(port, RDA_UART_STATUS) & RDA_UART_TX_FIFO_MASK) {
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
|
||||
ch = xmit->buf[xmit->tail];
|
||||
while ((rda_uart_read(port, RDA_UART_STATUS) & RDA_UART_TX_FIFO_MASK) &&
|
||||
uart_fifo_get(port, &ch))
|
||||
rda_uart_write(port, ch, RDA_UART_RXTX_BUFFER);
|
||||
uart_xmit_advance(port, 1);
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (!uart_circ_empty(xmit)) {
|
||||
if (!kfifo_is_empty(&tport->xmit_fifo)) {
|
||||
/* Re-enable Tx FIFO interrupt */
|
||||
val = rda_uart_read(port, RDA_UART_IRQ_MASK);
|
||||
val |= RDA_UART_TX_DATA_NEEDED;
|
||||
|
@ -329,7 +329,7 @@ static void s3c24xx_serial_tx_dma_complete(void *args)
|
||||
{
|
||||
struct s3c24xx_uart_port *ourport = args;
|
||||
struct uart_port *port = &ourport->port;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
struct s3c24xx_uart_dma *dma = ourport->dma;
|
||||
struct dma_tx_state state;
|
||||
unsigned long flags;
|
||||
@ -348,7 +348,7 @@ static void s3c24xx_serial_tx_dma_complete(void *args)
|
||||
uart_xmit_advance(port, count);
|
||||
ourport->tx_in_progress = 0;
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
s3c24xx_serial_start_next_tx(ourport);
|
||||
@ -431,17 +431,15 @@ static void s3c24xx_serial_start_tx_pio(struct s3c24xx_uart_port *ourport)
|
||||
}
|
||||
|
||||
static int s3c24xx_serial_start_tx_dma(struct s3c24xx_uart_port *ourport,
|
||||
unsigned int count)
|
||||
unsigned int count, unsigned int tail)
|
||||
{
|
||||
struct uart_port *port = &ourport->port;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct s3c24xx_uart_dma *dma = ourport->dma;
|
||||
|
||||
if (ourport->tx_mode != S3C24XX_TX_DMA)
|
||||
enable_tx_dma(ourport);
|
||||
|
||||
dma->tx_size = count & ~(dma_get_cache_alignment() - 1);
|
||||
dma->tx_transfer_addr = dma->tx_addr + xmit->tail;
|
||||
dma->tx_transfer_addr = dma->tx_addr + tail;
|
||||
|
||||
dma_sync_single_for_device(dma->tx_chan->device->dev,
|
||||
dma->tx_transfer_addr, dma->tx_size,
|
||||
@ -468,11 +466,11 @@ static int s3c24xx_serial_start_tx_dma(struct s3c24xx_uart_port *ourport,
|
||||
static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport)
|
||||
{
|
||||
struct uart_port *port = &ourport->port;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
unsigned long count;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned int count, tail;
|
||||
|
||||
/* Get data size up to the end of buffer */
|
||||
count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
|
||||
count = kfifo_out_linear(&tport->xmit_fifo, &tail, UART_XMIT_SIZE);
|
||||
|
||||
if (!count) {
|
||||
s3c24xx_serial_stop_tx(port);
|
||||
@ -481,16 +479,16 @@ static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport)
|
||||
|
||||
if (!ourport->dma || !ourport->dma->tx_chan ||
|
||||
count < ourport->min_dma_size ||
|
||||
xmit->tail & (dma_get_cache_alignment() - 1))
|
||||
tail & (dma_get_cache_alignment() - 1))
|
||||
s3c24xx_serial_start_tx_pio(ourport);
|
||||
else
|
||||
s3c24xx_serial_start_tx_dma(ourport, count);
|
||||
s3c24xx_serial_start_tx_dma(ourport, count, tail);
|
||||
}
|
||||
|
||||
static void s3c24xx_serial_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct s3c24xx_uart_port *ourport = to_ourport(port);
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
|
||||
if (!ourport->tx_enabled) {
|
||||
if (port->flags & UPF_CONS_FLOW)
|
||||
@ -502,7 +500,8 @@ static void s3c24xx_serial_start_tx(struct uart_port *port)
|
||||
}
|
||||
|
||||
if (ourport->dma && ourport->dma->tx_chan) {
|
||||
if (!uart_circ_empty(xmit) && !ourport->tx_in_progress)
|
||||
if (!kfifo_is_empty(&tport->xmit_fifo) &&
|
||||
!ourport->tx_in_progress)
|
||||
s3c24xx_serial_start_next_tx(ourport);
|
||||
}
|
||||
}
|
||||
@ -868,18 +867,19 @@ static irqreturn_t s3c24xx_serial_rx_irq(int irq, void *dev_id)
|
||||
static void s3c24xx_serial_tx_chars(struct s3c24xx_uart_port *ourport)
|
||||
{
|
||||
struct uart_port *port = &ourport->port;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
int count, dma_count = 0;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned int count, dma_count = 0, tail;
|
||||
|
||||
count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
|
||||
count = kfifo_out_linear(&tport->xmit_fifo, &tail, UART_XMIT_SIZE);
|
||||
|
||||
if (ourport->dma && ourport->dma->tx_chan &&
|
||||
count >= ourport->min_dma_size) {
|
||||
int align = dma_get_cache_alignment() -
|
||||
(xmit->tail & (dma_get_cache_alignment() - 1));
|
||||
(tail & (dma_get_cache_alignment() - 1));
|
||||
if (count - align >= ourport->min_dma_size) {
|
||||
dma_count = count - align;
|
||||
count = align;
|
||||
tail += align;
|
||||
}
|
||||
}
|
||||
|
||||
@ -894,7 +894,7 @@ static void s3c24xx_serial_tx_chars(struct s3c24xx_uart_port *ourport)
|
||||
* stopped, disable the uart and exit
|
||||
*/
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
|
||||
if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
|
||||
s3c24xx_serial_stop_tx(port);
|
||||
return;
|
||||
}
|
||||
@ -906,24 +906,25 @@ static void s3c24xx_serial_tx_chars(struct s3c24xx_uart_port *ourport)
|
||||
dma_count = 0;
|
||||
}
|
||||
|
||||
while (!uart_circ_empty(xmit) && count > 0) {
|
||||
if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)
|
||||
while (!(rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)) {
|
||||
unsigned char ch;
|
||||
|
||||
if (!uart_fifo_get(port, &ch))
|
||||
break;
|
||||
|
||||
wr_reg(port, S3C2410_UTXH, xmit->buf[xmit->tail]);
|
||||
uart_xmit_advance(port, 1);
|
||||
wr_reg(port, S3C2410_UTXH, ch);
|
||||
count--;
|
||||
}
|
||||
|
||||
if (!count && dma_count) {
|
||||
s3c24xx_serial_start_tx_dma(ourport, dma_count);
|
||||
s3c24xx_serial_start_tx_dma(ourport, dma_count, tail);
|
||||
return;
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
if (kfifo_is_empty(&tport->xmit_fifo))
|
||||
s3c24xx_serial_stop_tx(port);
|
||||
}
|
||||
|
||||
@ -1118,7 +1119,8 @@ static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
|
||||
|
||||
/* TX buffer */
|
||||
dma->tx_addr = dma_map_single(dma->tx_chan->device->dev,
|
||||
p->port.state->xmit.buf, UART_XMIT_SIZE,
|
||||
p->port.state->port.xmit_buf,
|
||||
UART_XMIT_SIZE,
|
||||
DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(dma->tx_chan->device->dev, dma->tx_addr)) {
|
||||
reason = "DMA mapping error for TX buffer";
|
||||
|
@ -382,7 +382,8 @@ static void sbd_receive_chars(struct sbd_port *sport)
|
||||
static void sbd_transmit_chars(struct sbd_port *sport)
|
||||
{
|
||||
struct uart_port *uport = &sport->port;
|
||||
struct circ_buf *xmit = &sport->port.state->xmit;
|
||||
struct tty_port *tport = &sport->port.state->port;
|
||||
unsigned char ch;
|
||||
unsigned int mask;
|
||||
int stop_tx;
|
||||
|
||||
@ -395,19 +396,19 @@ static void sbd_transmit_chars(struct sbd_port *sport)
|
||||
}
|
||||
|
||||
/* If nothing to do or stopped or hardware stopped. */
|
||||
stop_tx = (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port));
|
||||
stop_tx = uart_tx_stopped(&sport->port) ||
|
||||
!uart_fifo_get(&sport->port, &ch);
|
||||
|
||||
/* Send char. */
|
||||
if (!stop_tx) {
|
||||
write_sbdchn(sport, R_DUART_TX_HOLD, xmit->buf[xmit->tail]);
|
||||
uart_xmit_advance(&sport->port, 1);
|
||||
write_sbdchn(sport, R_DUART_TX_HOLD, ch);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&sport->port);
|
||||
}
|
||||
|
||||
/* Are we are done? */
|
||||
if (stop_tx || uart_circ_empty(xmit)) {
|
||||
if (stop_tx || kfifo_is_empty(&tport->xmit_fifo)) {
|
||||
/* Disable tx interrupts. */
|
||||
mask = read_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2));
|
||||
mask &= ~M_DUART_IMR_TX;
|
||||
|
@ -1,35 +1,38 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* SC16IS7xx tty serial driver - Copyright (C) 2014 GridPoint
|
||||
* Author: Jon Ringle <jringle@gridpoint.com>
|
||||
* SC16IS7xx tty serial driver - common code
|
||||
*
|
||||
* Based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
|
||||
* Copyright (C) 2014 GridPoint
|
||||
* Author: Jon Ringle <jringle@gridpoint.com>
|
||||
* Based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
#undef DEFAULT_SYMBOL_NAMESPACE
|
||||
#define DEFAULT_SYMBOL_NAMESPACE SERIAL_NXP_SC16IS7XX
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/units.h>
|
||||
#include <uapi/linux/sched/types.h>
|
||||
|
||||
#define SC16IS7XX_NAME "sc16is7xx"
|
||||
#include "sc16is7xx.h"
|
||||
|
||||
#define SC16IS7XX_MAX_DEVS 8
|
||||
#define SC16IS7XX_MAX_PORTS 2 /* Maximum number of UART ports per IC. */
|
||||
|
||||
/* SC16IS7XX register definitions */
|
||||
#define SC16IS7XX_RHR_REG (0x00) /* RX FIFO */
|
||||
@ -302,16 +305,9 @@
|
||||
|
||||
|
||||
/* Misc definitions */
|
||||
#define SC16IS7XX_SPI_READ_BIT BIT(7)
|
||||
#define SC16IS7XX_FIFO_SIZE (64)
|
||||
#define SC16IS7XX_GPIOS_PER_BANK 4
|
||||
|
||||
struct sc16is7xx_devtype {
|
||||
char name[10];
|
||||
int nr_gpio;
|
||||
int nr_uart;
|
||||
};
|
||||
|
||||
#define SC16IS7XX_RECONF_MD (1 << 0)
|
||||
#define SC16IS7XX_RECONF_IER (1 << 1)
|
||||
#define SC16IS7XX_RECONF_RS485 (1 << 2)
|
||||
@ -349,7 +345,7 @@ struct sc16is7xx_port {
|
||||
struct sc16is7xx_one p[];
|
||||
};
|
||||
|
||||
static DECLARE_BITMAP(sc16is7xx_lines, SC16IS7XX_MAX_DEVS);
|
||||
static DEFINE_IDA(sc16is7xx_lines);
|
||||
|
||||
static struct uart_driver sc16is7xx_uart = {
|
||||
.owner = THIS_MODULE,
|
||||
@ -492,35 +488,40 @@ static void sc16is7xx_stop_rx(struct uart_port *port)
|
||||
sc16is7xx_ier_clear(port, SC16IS7XX_IER_RDI_BIT);
|
||||
}
|
||||
|
||||
static const struct sc16is7xx_devtype sc16is74x_devtype = {
|
||||
const struct sc16is7xx_devtype sc16is74x_devtype = {
|
||||
.name = "SC16IS74X",
|
||||
.nr_gpio = 0,
|
||||
.nr_uart = 1,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(sc16is74x_devtype);
|
||||
|
||||
static const struct sc16is7xx_devtype sc16is750_devtype = {
|
||||
const struct sc16is7xx_devtype sc16is750_devtype = {
|
||||
.name = "SC16IS750",
|
||||
.nr_gpio = 8,
|
||||
.nr_uart = 1,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(sc16is750_devtype);
|
||||
|
||||
static const struct sc16is7xx_devtype sc16is752_devtype = {
|
||||
const struct sc16is7xx_devtype sc16is752_devtype = {
|
||||
.name = "SC16IS752",
|
||||
.nr_gpio = 8,
|
||||
.nr_uart = 2,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(sc16is752_devtype);
|
||||
|
||||
static const struct sc16is7xx_devtype sc16is760_devtype = {
|
||||
const struct sc16is7xx_devtype sc16is760_devtype = {
|
||||
.name = "SC16IS760",
|
||||
.nr_gpio = 8,
|
||||
.nr_uart = 1,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(sc16is760_devtype);
|
||||
|
||||
static const struct sc16is7xx_devtype sc16is762_devtype = {
|
||||
const struct sc16is7xx_devtype sc16is762_devtype = {
|
||||
.name = "SC16IS762",
|
||||
.nr_gpio = 8,
|
||||
.nr_uart = 2,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(sc16is762_devtype);
|
||||
|
||||
static bool sc16is7xx_regmap_volatile(struct device *dev, unsigned int reg)
|
||||
{
|
||||
@ -676,9 +677,9 @@ static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen,
|
||||
static void sc16is7xx_handle_tx(struct uart_port *port)
|
||||
{
|
||||
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
unsigned int txlen, to_send, i;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned long flags;
|
||||
unsigned int txlen;
|
||||
|
||||
if (unlikely(port->x_char)) {
|
||||
sc16is7xx_port_write(port, SC16IS7XX_THR_REG, port->x_char);
|
||||
@ -687,40 +688,30 @@ static void sc16is7xx_handle_tx(struct uart_port *port)
|
||||
return;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
|
||||
if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
|
||||
uart_port_lock_irqsave(port, &flags);
|
||||
sc16is7xx_stop_tx(port);
|
||||
uart_port_unlock_irqrestore(port, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get length of data pending in circular buffer */
|
||||
to_send = uart_circ_chars_pending(xmit);
|
||||
if (likely(to_send)) {
|
||||
/* Limit to space available in TX FIFO */
|
||||
txlen = sc16is7xx_port_read(port, SC16IS7XX_TXLVL_REG);
|
||||
if (txlen > SC16IS7XX_FIFO_SIZE) {
|
||||
dev_err_ratelimited(port->dev,
|
||||
"chip reports %d free bytes in TX fifo, but it only has %d",
|
||||
txlen, SC16IS7XX_FIFO_SIZE);
|
||||
txlen = 0;
|
||||
}
|
||||
to_send = (to_send > txlen) ? txlen : to_send;
|
||||
|
||||
/* Convert to linear buffer */
|
||||
for (i = 0; i < to_send; ++i) {
|
||||
s->buf[i] = xmit->buf[xmit->tail];
|
||||
uart_xmit_advance(port, 1);
|
||||
}
|
||||
|
||||
sc16is7xx_fifo_write(port, s->buf, to_send);
|
||||
/* Limit to space available in TX FIFO */
|
||||
txlen = sc16is7xx_port_read(port, SC16IS7XX_TXLVL_REG);
|
||||
if (txlen > SC16IS7XX_FIFO_SIZE) {
|
||||
dev_err_ratelimited(port->dev,
|
||||
"chip reports %d free bytes in TX fifo, but it only has %d",
|
||||
txlen, SC16IS7XX_FIFO_SIZE);
|
||||
txlen = 0;
|
||||
}
|
||||
|
||||
txlen = uart_fifo_out(port, s->buf, txlen);
|
||||
sc16is7xx_fifo_write(port, s->buf, txlen);
|
||||
|
||||
uart_port_lock_irqsave(port, &flags);
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
if (kfifo_is_empty(&tport->xmit_fifo))
|
||||
sc16is7xx_stop_tx(port);
|
||||
else
|
||||
sc16is7xx_ier_set(port, SC16IS7XX_IER_THRI_BIT);
|
||||
@ -1463,15 +1454,15 @@ static const struct serial_rs485 sc16is7xx_rs485_supported = {
|
||||
.delay_rts_after_send = 1, /* Not supported but keep returning -EINVAL */
|
||||
};
|
||||
|
||||
static int sc16is7xx_probe(struct device *dev,
|
||||
const struct sc16is7xx_devtype *devtype,
|
||||
struct regmap *regmaps[], int irq)
|
||||
int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype,
|
||||
struct regmap *regmaps[], int irq)
|
||||
{
|
||||
unsigned long freq = 0, *pfreq = dev_get_platdata(dev);
|
||||
unsigned int val;
|
||||
u32 uartclk = 0;
|
||||
int i, ret;
|
||||
struct sc16is7xx_port *s;
|
||||
bool port_registered[SC16IS7XX_MAX_PORTS];
|
||||
|
||||
for (i = 0; i < devtype->nr_uart; i++)
|
||||
if (IS_ERR(regmaps[i]))
|
||||
@ -1536,13 +1527,19 @@ static int sc16is7xx_probe(struct device *dev,
|
||||
regmap_write(regmaps[0], SC16IS7XX_IOCONTROL_REG,
|
||||
SC16IS7XX_IOCONTROL_SRESET_BIT);
|
||||
|
||||
/* Mark each port line and status as uninitialised. */
|
||||
for (i = 0; i < devtype->nr_uart; ++i) {
|
||||
s->p[i].port.line = find_first_zero_bit(sc16is7xx_lines,
|
||||
SC16IS7XX_MAX_DEVS);
|
||||
if (s->p[i].port.line >= SC16IS7XX_MAX_DEVS) {
|
||||
ret = -ERANGE;
|
||||
s->p[i].port.line = SC16IS7XX_MAX_DEVS;
|
||||
port_registered[i] = false;
|
||||
}
|
||||
|
||||
for (i = 0; i < devtype->nr_uart; ++i) {
|
||||
ret = ida_alloc_max(&sc16is7xx_lines,
|
||||
SC16IS7XX_MAX_DEVS - 1, GFP_KERNEL);
|
||||
if (ret < 0)
|
||||
goto out_ports;
|
||||
}
|
||||
|
||||
s->p[i].port.line = ret;
|
||||
|
||||
/* Initialize port data */
|
||||
s->p[i].port.dev = dev;
|
||||
@ -1588,7 +1585,7 @@ static int sc16is7xx_probe(struct device *dev,
|
||||
if (ret)
|
||||
goto out_ports;
|
||||
|
||||
set_bit(s->p[i].port.line, sc16is7xx_lines);
|
||||
port_registered[i] = true;
|
||||
|
||||
/* Enable EFR */
|
||||
sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_LCR_REG,
|
||||
@ -1646,9 +1643,12 @@ static int sc16is7xx_probe(struct device *dev,
|
||||
#endif
|
||||
|
||||
out_ports:
|
||||
for (i = 0; i < devtype->nr_uart; i++)
|
||||
if (test_and_clear_bit(s->p[i].port.line, sc16is7xx_lines))
|
||||
for (i = 0; i < devtype->nr_uart; i++) {
|
||||
if (s->p[i].port.line < SC16IS7XX_MAX_DEVS)
|
||||
ida_free(&sc16is7xx_lines, s->p[i].port.line);
|
||||
if (port_registered[i])
|
||||
uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port);
|
||||
}
|
||||
|
||||
kthread_stop(s->kworker_task);
|
||||
|
||||
@ -1657,8 +1657,9 @@ out_clk:
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sc16is7xx_probe);
|
||||
|
||||
static void sc16is7xx_remove(struct device *dev)
|
||||
void sc16is7xx_remove(struct device *dev)
|
||||
{
|
||||
struct sc16is7xx_port *s = dev_get_drvdata(dev);
|
||||
int i;
|
||||
@ -1670,8 +1671,8 @@ static void sc16is7xx_remove(struct device *dev)
|
||||
|
||||
for (i = 0; i < s->devtype->nr_uart; i++) {
|
||||
kthread_cancel_delayed_work_sync(&s->p[i].ms_work);
|
||||
if (test_and_clear_bit(s->p[i].port.line, sc16is7xx_lines))
|
||||
uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port);
|
||||
ida_free(&sc16is7xx_lines, s->p[i].port.line);
|
||||
uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port);
|
||||
sc16is7xx_power(&s->p[i].port, 0);
|
||||
}
|
||||
|
||||
@ -1680,8 +1681,9 @@ static void sc16is7xx_remove(struct device *dev)
|
||||
|
||||
clk_disable_unprepare(s->clk);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sc16is7xx_remove);
|
||||
|
||||
static const struct of_device_id __maybe_unused sc16is7xx_dt_ids[] = {
|
||||
const struct of_device_id __maybe_unused sc16is7xx_dt_ids[] = {
|
||||
{ .compatible = "nxp,sc16is740", .data = &sc16is74x_devtype, },
|
||||
{ .compatible = "nxp,sc16is741", .data = &sc16is74x_devtype, },
|
||||
{ .compatible = "nxp,sc16is750", .data = &sc16is750_devtype, },
|
||||
@ -1690,13 +1692,14 @@ static const struct of_device_id __maybe_unused sc16is7xx_dt_ids[] = {
|
||||
{ .compatible = "nxp,sc16is762", .data = &sc16is762_devtype, },
|
||||
{ }
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(sc16is7xx_dt_ids);
|
||||
MODULE_DEVICE_TABLE(of, sc16is7xx_dt_ids);
|
||||
|
||||
static struct regmap_config regcfg = {
|
||||
const struct regmap_config sc16is7xx_regcfg = {
|
||||
.reg_bits = 5,
|
||||
.pad_bits = 3,
|
||||
.val_bits = 8,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.cache_type = REGCACHE_MAPLE,
|
||||
.volatile_reg = sc16is7xx_regmap_volatile,
|
||||
.precious_reg = sc16is7xx_regmap_precious,
|
||||
.writeable_noinc_reg = sc16is7xx_regmap_noinc,
|
||||
@ -1705,8 +1708,9 @@ static struct regmap_config regcfg = {
|
||||
.max_raw_write = SC16IS7XX_FIFO_SIZE,
|
||||
.max_register = SC16IS7XX_EFCR_REG,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(sc16is7xx_regcfg);
|
||||
|
||||
static const char *sc16is7xx_regmap_name(u8 port_id)
|
||||
const char *sc16is7xx_regmap_name(u8 port_id)
|
||||
{
|
||||
switch (port_id) {
|
||||
case 0: return "port0";
|
||||
@ -1716,184 +1720,27 @@ static const char *sc16is7xx_regmap_name(u8 port_id)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sc16is7xx_regmap_name);
|
||||
|
||||
static unsigned int sc16is7xx_regmap_port_mask(unsigned int port_id)
|
||||
unsigned int sc16is7xx_regmap_port_mask(unsigned int port_id)
|
||||
{
|
||||
/* CH1,CH0 are at bits 2:1. */
|
||||
return port_id << 1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_SC16IS7XX_SPI
|
||||
static int sc16is7xx_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
const struct sc16is7xx_devtype *devtype;
|
||||
struct regmap *regmaps[SC16IS7XX_MAX_PORTS];
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
/* Setup SPI bus */
|
||||
spi->bits_per_word = 8;
|
||||
/* For all variants, only mode 0 is supported */
|
||||
if ((spi->mode & SPI_MODE_X_MASK) != SPI_MODE_0)
|
||||
return dev_err_probe(&spi->dev, -EINVAL, "Unsupported SPI mode\n");
|
||||
|
||||
spi->mode = spi->mode ? : SPI_MODE_0;
|
||||
spi->max_speed_hz = spi->max_speed_hz ? : 4 * HZ_PER_MHZ;
|
||||
ret = spi_setup(spi);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
devtype = spi_get_device_match_data(spi);
|
||||
if (!devtype)
|
||||
return dev_err_probe(&spi->dev, -ENODEV, "Failed to match device\n");
|
||||
|
||||
for (i = 0; i < devtype->nr_uart; i++) {
|
||||
regcfg.name = sc16is7xx_regmap_name(i);
|
||||
/*
|
||||
* If read_flag_mask is 0, the regmap code sets it to a default
|
||||
* of 0x80. Since we specify our own mask, we must add the READ
|
||||
* bit ourselves:
|
||||
*/
|
||||
regcfg.read_flag_mask = sc16is7xx_regmap_port_mask(i) |
|
||||
SC16IS7XX_SPI_READ_BIT;
|
||||
regcfg.write_flag_mask = sc16is7xx_regmap_port_mask(i);
|
||||
regmaps[i] = devm_regmap_init_spi(spi, ®cfg);
|
||||
}
|
||||
|
||||
return sc16is7xx_probe(&spi->dev, devtype, regmaps, spi->irq);
|
||||
}
|
||||
|
||||
static void sc16is7xx_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
sc16is7xx_remove(&spi->dev);
|
||||
}
|
||||
|
||||
static const struct spi_device_id sc16is7xx_spi_id_table[] = {
|
||||
{ "sc16is74x", (kernel_ulong_t)&sc16is74x_devtype, },
|
||||
{ "sc16is740", (kernel_ulong_t)&sc16is74x_devtype, },
|
||||
{ "sc16is741", (kernel_ulong_t)&sc16is74x_devtype, },
|
||||
{ "sc16is750", (kernel_ulong_t)&sc16is750_devtype, },
|
||||
{ "sc16is752", (kernel_ulong_t)&sc16is752_devtype, },
|
||||
{ "sc16is760", (kernel_ulong_t)&sc16is760_devtype, },
|
||||
{ "sc16is762", (kernel_ulong_t)&sc16is762_devtype, },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(spi, sc16is7xx_spi_id_table);
|
||||
|
||||
static struct spi_driver sc16is7xx_spi_uart_driver = {
|
||||
.driver = {
|
||||
.name = SC16IS7XX_NAME,
|
||||
.of_match_table = sc16is7xx_dt_ids,
|
||||
},
|
||||
.probe = sc16is7xx_spi_probe,
|
||||
.remove = sc16is7xx_spi_remove,
|
||||
.id_table = sc16is7xx_spi_id_table,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SERIAL_SC16IS7XX_I2C
|
||||
static int sc16is7xx_i2c_probe(struct i2c_client *i2c)
|
||||
{
|
||||
const struct sc16is7xx_devtype *devtype;
|
||||
struct regmap *regmaps[SC16IS7XX_MAX_PORTS];
|
||||
unsigned int i;
|
||||
|
||||
devtype = i2c_get_match_data(i2c);
|
||||
if (!devtype)
|
||||
return dev_err_probe(&i2c->dev, -ENODEV, "Failed to match device\n");
|
||||
|
||||
for (i = 0; i < devtype->nr_uart; i++) {
|
||||
regcfg.name = sc16is7xx_regmap_name(i);
|
||||
regcfg.read_flag_mask = sc16is7xx_regmap_port_mask(i);
|
||||
regcfg.write_flag_mask = sc16is7xx_regmap_port_mask(i);
|
||||
regmaps[i] = devm_regmap_init_i2c(i2c, ®cfg);
|
||||
}
|
||||
|
||||
return sc16is7xx_probe(&i2c->dev, devtype, regmaps, i2c->irq);
|
||||
}
|
||||
|
||||
static void sc16is7xx_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
sc16is7xx_remove(&client->dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id sc16is7xx_i2c_id_table[] = {
|
||||
{ "sc16is74x", (kernel_ulong_t)&sc16is74x_devtype, },
|
||||
{ "sc16is740", (kernel_ulong_t)&sc16is74x_devtype, },
|
||||
{ "sc16is741", (kernel_ulong_t)&sc16is74x_devtype, },
|
||||
{ "sc16is750", (kernel_ulong_t)&sc16is750_devtype, },
|
||||
{ "sc16is752", (kernel_ulong_t)&sc16is752_devtype, },
|
||||
{ "sc16is760", (kernel_ulong_t)&sc16is760_devtype, },
|
||||
{ "sc16is762", (kernel_ulong_t)&sc16is762_devtype, },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, sc16is7xx_i2c_id_table);
|
||||
|
||||
static struct i2c_driver sc16is7xx_i2c_uart_driver = {
|
||||
.driver = {
|
||||
.name = SC16IS7XX_NAME,
|
||||
.of_match_table = sc16is7xx_dt_ids,
|
||||
},
|
||||
.probe = sc16is7xx_i2c_probe,
|
||||
.remove = sc16is7xx_i2c_remove,
|
||||
.id_table = sc16is7xx_i2c_id_table,
|
||||
};
|
||||
|
||||
#endif
|
||||
EXPORT_SYMBOL_GPL(sc16is7xx_regmap_port_mask);
|
||||
|
||||
static int __init sc16is7xx_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = uart_register_driver(&sc16is7xx_uart);
|
||||
if (ret) {
|
||||
pr_err("Registering UART driver failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_SC16IS7XX_I2C
|
||||
ret = i2c_add_driver(&sc16is7xx_i2c_uart_driver);
|
||||
if (ret < 0) {
|
||||
pr_err("failed to init sc16is7xx i2c --> %d\n", ret);
|
||||
goto err_i2c;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SERIAL_SC16IS7XX_SPI
|
||||
ret = spi_register_driver(&sc16is7xx_spi_uart_driver);
|
||||
if (ret < 0) {
|
||||
pr_err("failed to init sc16is7xx spi --> %d\n", ret);
|
||||
goto err_spi;
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
|
||||
#ifdef CONFIG_SERIAL_SC16IS7XX_SPI
|
||||
err_spi:
|
||||
#endif
|
||||
#ifdef CONFIG_SERIAL_SC16IS7XX_I2C
|
||||
i2c_del_driver(&sc16is7xx_i2c_uart_driver);
|
||||
err_i2c:
|
||||
#endif
|
||||
uart_unregister_driver(&sc16is7xx_uart);
|
||||
return ret;
|
||||
return uart_register_driver(&sc16is7xx_uart);
|
||||
}
|
||||
module_init(sc16is7xx_init);
|
||||
|
||||
static void __exit sc16is7xx_exit(void)
|
||||
{
|
||||
#ifdef CONFIG_SERIAL_SC16IS7XX_I2C
|
||||
i2c_del_driver(&sc16is7xx_i2c_uart_driver);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SERIAL_SC16IS7XX_SPI
|
||||
spi_unregister_driver(&sc16is7xx_spi_uart_driver);
|
||||
#endif
|
||||
uart_unregister_driver(&sc16is7xx_uart);
|
||||
}
|
||||
module_exit(sc16is7xx_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Jon Ringle <jringle@gridpoint.com>");
|
||||
MODULE_DESCRIPTION("SC16IS7XX serial driver");
|
||||
MODULE_DESCRIPTION("SC16IS7xx tty serial core driver");
|
||||
|
41
drivers/tty/serial/sc16is7xx.h
Normal file
41
drivers/tty/serial/sc16is7xx.h
Normal file
@ -0,0 +1,41 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/* SC16IS7xx SPI/I2C tty serial driver */
|
||||
|
||||
#ifndef _SC16IS7XX_H_
|
||||
#define _SC16IS7XX_H_
|
||||
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define SC16IS7XX_NAME "sc16is7xx"
|
||||
#define SC16IS7XX_MAX_PORTS 2 /* Maximum number of UART ports per IC. */
|
||||
|
||||
struct device;
|
||||
|
||||
struct sc16is7xx_devtype {
|
||||
char name[10];
|
||||
int nr_gpio;
|
||||
int nr_uart;
|
||||
};
|
||||
|
||||
extern const struct regmap_config sc16is7xx_regcfg;
|
||||
|
||||
extern const struct of_device_id sc16is7xx_dt_ids[];
|
||||
|
||||
extern const struct sc16is7xx_devtype sc16is74x_devtype;
|
||||
extern const struct sc16is7xx_devtype sc16is750_devtype;
|
||||
extern const struct sc16is7xx_devtype sc16is752_devtype;
|
||||
extern const struct sc16is7xx_devtype sc16is760_devtype;
|
||||
extern const struct sc16is7xx_devtype sc16is762_devtype;
|
||||
|
||||
const char *sc16is7xx_regmap_name(u8 port_id);
|
||||
|
||||
unsigned int sc16is7xx_regmap_port_mask(unsigned int port_id);
|
||||
|
||||
int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype,
|
||||
struct regmap *regmaps[], int irq);
|
||||
|
||||
void sc16is7xx_remove(struct device *dev);
|
||||
|
||||
#endif /* _SC16IS7XX_H_ */
|
67
drivers/tty/serial/sc16is7xx_i2c.c
Normal file
67
drivers/tty/serial/sc16is7xx_i2c.c
Normal file
@ -0,0 +1,67 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/* SC16IS7xx I2C interface driver */
|
||||
|
||||
#include <linux/dev_printk.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include "sc16is7xx.h"
|
||||
|
||||
static int sc16is7xx_i2c_probe(struct i2c_client *i2c)
|
||||
{
|
||||
const struct sc16is7xx_devtype *devtype;
|
||||
struct regmap *regmaps[SC16IS7XX_MAX_PORTS];
|
||||
struct regmap_config regcfg;
|
||||
unsigned int i;
|
||||
|
||||
devtype = i2c_get_match_data(i2c);
|
||||
if (!devtype)
|
||||
return dev_err_probe(&i2c->dev, -ENODEV, "Failed to match device\n");
|
||||
|
||||
memcpy(®cfg, &sc16is7xx_regcfg, sizeof(struct regmap_config));
|
||||
|
||||
for (i = 0; i < devtype->nr_uart; i++) {
|
||||
regcfg.name = sc16is7xx_regmap_name(i);
|
||||
regcfg.read_flag_mask = sc16is7xx_regmap_port_mask(i);
|
||||
regcfg.write_flag_mask = sc16is7xx_regmap_port_mask(i);
|
||||
regmaps[i] = devm_regmap_init_i2c(i2c, ®cfg);
|
||||
}
|
||||
|
||||
return sc16is7xx_probe(&i2c->dev, devtype, regmaps, i2c->irq);
|
||||
}
|
||||
|
||||
static void sc16is7xx_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
sc16is7xx_remove(&client->dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id sc16is7xx_i2c_id_table[] = {
|
||||
{ "sc16is74x", (kernel_ulong_t)&sc16is74x_devtype, },
|
||||
{ "sc16is740", (kernel_ulong_t)&sc16is74x_devtype, },
|
||||
{ "sc16is741", (kernel_ulong_t)&sc16is74x_devtype, },
|
||||
{ "sc16is750", (kernel_ulong_t)&sc16is750_devtype, },
|
||||
{ "sc16is752", (kernel_ulong_t)&sc16is752_devtype, },
|
||||
{ "sc16is760", (kernel_ulong_t)&sc16is760_devtype, },
|
||||
{ "sc16is762", (kernel_ulong_t)&sc16is762_devtype, },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, sc16is7xx_i2c_id_table);
|
||||
|
||||
static struct i2c_driver sc16is7xx_i2c_driver = {
|
||||
.driver = {
|
||||
.name = SC16IS7XX_NAME,
|
||||
.of_match_table = sc16is7xx_dt_ids,
|
||||
},
|
||||
.probe = sc16is7xx_i2c_probe,
|
||||
.remove = sc16is7xx_i2c_remove,
|
||||
.id_table = sc16is7xx_i2c_id_table,
|
||||
};
|
||||
|
||||
module_i2c_driver(sc16is7xx_i2c_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("SC16IS7xx I2C interface driver");
|
||||
MODULE_IMPORT_NS(SERIAL_NXP_SC16IS7XX);
|
90
drivers/tty/serial/sc16is7xx_spi.c
Normal file
90
drivers/tty/serial/sc16is7xx_spi.c
Normal file
@ -0,0 +1,90 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/* SC16IS7xx SPI interface driver */
|
||||
|
||||
#include <linux/dev_printk.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/units.h>
|
||||
|
||||
#include "sc16is7xx.h"
|
||||
|
||||
/* SPI definitions */
|
||||
#define SC16IS7XX_SPI_READ_BIT BIT(7)
|
||||
|
||||
static int sc16is7xx_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
const struct sc16is7xx_devtype *devtype;
|
||||
struct regmap *regmaps[SC16IS7XX_MAX_PORTS];
|
||||
struct regmap_config regcfg;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
/* Setup SPI bus */
|
||||
spi->bits_per_word = 8;
|
||||
/* For all variants, only mode 0 is supported */
|
||||
if ((spi->mode & SPI_MODE_X_MASK) != SPI_MODE_0)
|
||||
return dev_err_probe(&spi->dev, -EINVAL, "Unsupported SPI mode\n");
|
||||
|
||||
spi->mode = spi->mode ? : SPI_MODE_0;
|
||||
spi->max_speed_hz = spi->max_speed_hz ? : 4 * HZ_PER_MHZ;
|
||||
ret = spi_setup(spi);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
devtype = spi_get_device_match_data(spi);
|
||||
if (!devtype)
|
||||
return dev_err_probe(&spi->dev, -ENODEV, "Failed to match device\n");
|
||||
|
||||
memcpy(®cfg, &sc16is7xx_regcfg, sizeof(struct regmap_config));
|
||||
|
||||
for (i = 0; i < devtype->nr_uart; i++) {
|
||||
regcfg.name = sc16is7xx_regmap_name(i);
|
||||
/*
|
||||
* If read_flag_mask is 0, the regmap code sets it to a default
|
||||
* of 0x80. Since we specify our own mask, we must add the READ
|
||||
* bit ourselves:
|
||||
*/
|
||||
regcfg.read_flag_mask = sc16is7xx_regmap_port_mask(i) |
|
||||
SC16IS7XX_SPI_READ_BIT;
|
||||
regcfg.write_flag_mask = sc16is7xx_regmap_port_mask(i);
|
||||
regmaps[i] = devm_regmap_init_spi(spi, ®cfg);
|
||||
}
|
||||
|
||||
return sc16is7xx_probe(&spi->dev, devtype, regmaps, spi->irq);
|
||||
}
|
||||
|
||||
static void sc16is7xx_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
sc16is7xx_remove(&spi->dev);
|
||||
}
|
||||
|
||||
static const struct spi_device_id sc16is7xx_spi_id_table[] = {
|
||||
{ "sc16is74x", (kernel_ulong_t)&sc16is74x_devtype, },
|
||||
{ "sc16is740", (kernel_ulong_t)&sc16is74x_devtype, },
|
||||
{ "sc16is741", (kernel_ulong_t)&sc16is74x_devtype, },
|
||||
{ "sc16is750", (kernel_ulong_t)&sc16is750_devtype, },
|
||||
{ "sc16is752", (kernel_ulong_t)&sc16is752_devtype, },
|
||||
{ "sc16is760", (kernel_ulong_t)&sc16is760_devtype, },
|
||||
{ "sc16is762", (kernel_ulong_t)&sc16is762_devtype, },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, sc16is7xx_spi_id_table);
|
||||
|
||||
static struct spi_driver sc16is7xx_spi_driver = {
|
||||
.driver = {
|
||||
.name = SC16IS7XX_NAME,
|
||||
.of_match_table = sc16is7xx_dt_ids,
|
||||
},
|
||||
.probe = sc16is7xx_spi_probe,
|
||||
.remove = sc16is7xx_spi_remove,
|
||||
.id_table = sc16is7xx_spi_id_table,
|
||||
};
|
||||
|
||||
module_spi_driver(sc16is7xx_spi_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("SC16IS7xx SPI interface driver");
|
||||
MODULE_IMPORT_NS(SERIAL_NXP_SC16IS7XX);
|
@ -439,7 +439,7 @@ static void sccnxp_handle_rx(struct uart_port *port)
|
||||
static void sccnxp_handle_tx(struct uart_port *port)
|
||||
{
|
||||
u8 sr;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
struct sccnxp_port *s = dev_get_drvdata(port->dev);
|
||||
|
||||
if (unlikely(port->x_char)) {
|
||||
@ -449,7 +449,7 @@ static void sccnxp_handle_tx(struct uart_port *port)
|
||||
return;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
|
||||
if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
|
||||
/* Disable TX if FIFO is empty */
|
||||
if (sccnxp_port_read(port, SCCNXP_SR_REG) & SR_TXEMT) {
|
||||
sccnxp_disable_irq(port, IMR_TXRDY);
|
||||
@ -461,16 +461,20 @@ static void sccnxp_handle_tx(struct uart_port *port)
|
||||
return;
|
||||
}
|
||||
|
||||
while (!uart_circ_empty(xmit)) {
|
||||
while (1) {
|
||||
unsigned char ch;
|
||||
|
||||
sr = sccnxp_port_read(port, SCCNXP_SR_REG);
|
||||
if (!(sr & SR_TXRDY))
|
||||
break;
|
||||
|
||||
sccnxp_port_write(port, SCCNXP_THR_REG, xmit->buf[xmit->tail]);
|
||||
uart_xmit_advance(port, 1);
|
||||
if (!uart_fifo_get(port, &ch))
|
||||
break;
|
||||
|
||||
sccnxp_port_write(port, SCCNXP_THR_REG, ch);
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
}
|
||||
|
||||
|
@ -484,18 +484,18 @@ static void tegra_uart_release_port(struct uart_port *u)
|
||||
|
||||
static void tegra_uart_fill_tx_fifo(struct tegra_uart_port *tup, int max_bytes)
|
||||
{
|
||||
struct circ_buf *xmit = &tup->uport.state->xmit;
|
||||
unsigned char ch;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < max_bytes; i++) {
|
||||
BUG_ON(uart_circ_empty(xmit));
|
||||
if (tup->cdata->tx_fifo_full_status) {
|
||||
unsigned long lsr = tegra_uart_read(tup, UART_LSR);
|
||||
if ((lsr & TEGRA_UART_LSR_TXFIFO_FULL))
|
||||
break;
|
||||
}
|
||||
tegra_uart_write(tup, xmit->buf[xmit->tail], UART_TX);
|
||||
uart_xmit_advance(&tup->uport, 1);
|
||||
if (WARN_ON_ONCE(!uart_fifo_get(&tup->uport, &ch)))
|
||||
break;
|
||||
tegra_uart_write(tup, ch, UART_TX);
|
||||
}
|
||||
}
|
||||
|
||||
@ -514,7 +514,7 @@ static void tegra_uart_start_pio_tx(struct tegra_uart_port *tup,
|
||||
static void tegra_uart_tx_dma_complete(void *args)
|
||||
{
|
||||
struct tegra_uart_port *tup = args;
|
||||
struct circ_buf *xmit = &tup->uport.state->xmit;
|
||||
struct tty_port *tport = &tup->uport.state->port;
|
||||
struct dma_tx_state state;
|
||||
unsigned long flags;
|
||||
unsigned int count;
|
||||
@ -525,7 +525,7 @@ static void tegra_uart_tx_dma_complete(void *args)
|
||||
uart_port_lock_irqsave(&tup->uport, &flags);
|
||||
uart_xmit_advance(&tup->uport, count);
|
||||
tup->tx_in_progress = 0;
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&tup->uport);
|
||||
tegra_uart_start_next_tx(tup);
|
||||
uart_port_unlock_irqrestore(&tup->uport, flags);
|
||||
@ -534,11 +534,14 @@ static void tegra_uart_tx_dma_complete(void *args)
|
||||
static int tegra_uart_start_tx_dma(struct tegra_uart_port *tup,
|
||||
unsigned long count)
|
||||
{
|
||||
struct circ_buf *xmit = &tup->uport.state->xmit;
|
||||
struct tty_port *tport = &tup->uport.state->port;
|
||||
dma_addr_t tx_phys_addr;
|
||||
unsigned int tail;
|
||||
|
||||
tup->tx_bytes = count & ~(0xF);
|
||||
tx_phys_addr = tup->tx_dma_buf_phys + xmit->tail;
|
||||
WARN_ON_ONCE(kfifo_out_linear(&tport->xmit_fifo, &tail,
|
||||
UART_XMIT_SIZE) < count);
|
||||
tx_phys_addr = tup->tx_dma_buf_phys + tail;
|
||||
|
||||
dma_sync_single_for_device(tup->uport.dev, tx_phys_addr,
|
||||
tup->tx_bytes, DMA_TO_DEVICE);
|
||||
@ -562,18 +565,21 @@ static int tegra_uart_start_tx_dma(struct tegra_uart_port *tup,
|
||||
|
||||
static void tegra_uart_start_next_tx(struct tegra_uart_port *tup)
|
||||
{
|
||||
struct tty_port *tport = &tup->uport.state->port;
|
||||
unsigned char *tail_ptr;
|
||||
unsigned long tail;
|
||||
unsigned long count;
|
||||
struct circ_buf *xmit = &tup->uport.state->xmit;
|
||||
unsigned int count;
|
||||
|
||||
if (!tup->current_baud)
|
||||
return;
|
||||
|
||||
tail = (unsigned long)&xmit->buf[xmit->tail];
|
||||
count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
|
||||
count = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail_ptr,
|
||||
UART_XMIT_SIZE);
|
||||
if (!count)
|
||||
return;
|
||||
|
||||
tail = (unsigned long)tail_ptr;
|
||||
|
||||
if (tup->use_tx_pio || count < TEGRA_UART_MIN_DMA)
|
||||
tegra_uart_start_pio_tx(tup, count);
|
||||
else if (BYTES_TO_ALIGN(tail) > 0)
|
||||
@ -586,9 +592,9 @@ static void tegra_uart_start_next_tx(struct tegra_uart_port *tup)
|
||||
static void tegra_uart_start_tx(struct uart_port *u)
|
||||
{
|
||||
struct tegra_uart_port *tup = to_tegra_uport(u);
|
||||
struct circ_buf *xmit = &u->state->xmit;
|
||||
struct tty_port *tport = &u->state->port;
|
||||
|
||||
if (!uart_circ_empty(xmit) && !tup->tx_in_progress)
|
||||
if (!kfifo_is_empty(&tport->xmit_fifo) && !tup->tx_in_progress)
|
||||
tegra_uart_start_next_tx(tup);
|
||||
}
|
||||
|
||||
@ -628,11 +634,11 @@ static void tegra_uart_stop_tx(struct uart_port *u)
|
||||
|
||||
static void tegra_uart_handle_tx_pio(struct tegra_uart_port *tup)
|
||||
{
|
||||
struct circ_buf *xmit = &tup->uport.state->xmit;
|
||||
struct tty_port *tport = &tup->uport.state->port;
|
||||
|
||||
tegra_uart_fill_tx_fifo(tup, tup->tx_bytes);
|
||||
tup->tx_in_progress = 0;
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&tup->uport);
|
||||
tegra_uart_start_next_tx(tup);
|
||||
}
|
||||
@ -1169,15 +1175,14 @@ static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup,
|
||||
tup->rx_dma_buf_virt = dma_buf;
|
||||
tup->rx_dma_buf_phys = dma_phys;
|
||||
} else {
|
||||
dma_buf = tup->uport.state->port.xmit_buf;
|
||||
dma_phys = dma_map_single(tup->uport.dev,
|
||||
tup->uport.state->xmit.buf, UART_XMIT_SIZE,
|
||||
DMA_TO_DEVICE);
|
||||
dma_buf, UART_XMIT_SIZE, DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(tup->uport.dev, dma_phys)) {
|
||||
dev_err(tup->uport.dev, "dma_map_single tx failed\n");
|
||||
dma_release_channel(dma_chan);
|
||||
return -ENOMEM;
|
||||
}
|
||||
dma_buf = tup->uport.state->xmit.buf;
|
||||
dma_sconfig.dst_addr = tup->uport.mapbase;
|
||||
dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||
dma_sconfig.dst_maxburst = 16;
|
||||
|
@ -49,3 +49,33 @@ void serial_ctrl_unregister_port(struct uart_driver *drv, struct uart_port *port
|
||||
|
||||
int serial_core_register_port(struct uart_driver *drv, struct uart_port *port);
|
||||
void serial_core_unregister_port(struct uart_driver *drv, struct uart_port *port);
|
||||
|
||||
#ifdef CONFIG_SERIAL_CORE_CONSOLE
|
||||
|
||||
int serial_base_add_preferred_console(struct uart_driver *drv,
|
||||
struct uart_port *port);
|
||||
|
||||
#else
|
||||
|
||||
static inline
|
||||
int serial_base_add_preferred_console(struct uart_driver *drv,
|
||||
struct uart_port *port)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_CONSOLE
|
||||
|
||||
int serial_base_add_isa_preferred_console(const char *name, int idx);
|
||||
|
||||
#else
|
||||
|
||||
static inline
|
||||
int serial_base_add_isa_preferred_console(const char *name, int idx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -8,6 +8,7 @@
|
||||
* The serial core bus manages the serial core controller instances.
|
||||
*/
|
||||
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/container_of.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/idr.h>
|
||||
@ -204,6 +205,134 @@ void serial_base_port_device_remove(struct serial_port_device *port_dev)
|
||||
put_device(&port_dev->dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_CORE_CONSOLE
|
||||
|
||||
static int serial_base_add_one_prefcon(const char *match, const char *dev_name,
|
||||
int port_id)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = add_preferred_console_match(match, dev_name, port_id);
|
||||
if (ret == -ENOENT)
|
||||
return 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef __sparc__
|
||||
|
||||
/* Handle Sparc ttya and ttyb options as done in console_setup() */
|
||||
static int serial_base_add_sparc_console(const char *dev_name, int idx)
|
||||
{
|
||||
const char *name;
|
||||
|
||||
switch (idx) {
|
||||
case 0:
|
||||
name = "ttya";
|
||||
break;
|
||||
case 1:
|
||||
name = "ttyb";
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return serial_base_add_one_prefcon(name, dev_name, idx);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline int serial_base_add_sparc_console(const char *dev_name, int idx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int serial_base_add_prefcon(const char *name, int idx)
|
||||
{
|
||||
const char *char_match __free(kfree) = NULL;
|
||||
const char *nmbr_match __free(kfree) = NULL;
|
||||
int ret;
|
||||
|
||||
/* Handle ttyS specific options */
|
||||
if (strstarts(name, "ttyS")) {
|
||||
/* No name, just a number */
|
||||
nmbr_match = kasprintf(GFP_KERNEL, "%i", idx);
|
||||
if (!nmbr_match)
|
||||
return -ENODEV;
|
||||
|
||||
ret = serial_base_add_one_prefcon(nmbr_match, name, idx);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Sparc ttya and ttyb */
|
||||
ret = serial_base_add_sparc_console(name, idx);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Handle the traditional character device name style console=ttyS0 */
|
||||
char_match = kasprintf(GFP_KERNEL, "%s%i", name, idx);
|
||||
if (!char_match)
|
||||
return -ENOMEM;
|
||||
|
||||
return serial_base_add_one_prefcon(char_match, name, idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* serial_base_add_preferred_console - Adds a preferred console
|
||||
* @drv: Serial port device driver
|
||||
* @port: Serial port instance
|
||||
*
|
||||
* Tries to add a preferred console for a serial port if specified in the
|
||||
* kernel command line. Supports both the traditional character device such
|
||||
* as console=ttyS0, and a hardware addressing based console=DEVNAME:0.0
|
||||
* style name.
|
||||
*
|
||||
* Translates the kernel command line option using a hardware based addressing
|
||||
* console=DEVNAME:0.0 to the serial port character device such as ttyS0.
|
||||
* Cannot be called early for ISA ports, depends on struct device.
|
||||
*
|
||||
* Note that duplicates are ignored by add_preferred_console().
|
||||
*
|
||||
* Return: 0 on success, negative error code on failure.
|
||||
*/
|
||||
int serial_base_add_preferred_console(struct uart_driver *drv,
|
||||
struct uart_port *port)
|
||||
{
|
||||
const char *port_match __free(kfree) = NULL;
|
||||
int ret;
|
||||
|
||||
ret = serial_base_add_prefcon(drv->dev_name, port->line);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
port_match = kasprintf(GFP_KERNEL, "%s:%i.%i", dev_name(port->dev),
|
||||
port->ctrl_id, port->port_id);
|
||||
if (!port_match)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Translate a hardware addressing style console=DEVNAME:0.0 */
|
||||
return serial_base_add_one_prefcon(port_match, drv->dev_name, port->line);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_CONSOLE
|
||||
|
||||
/*
|
||||
* Early ISA ports initialize the console before there is no struct device.
|
||||
* This should be only called from serial8250_isa_init_preferred_console(),
|
||||
* other callers are likely wrong and should rely on earlycon instead.
|
||||
*/
|
||||
int serial_base_add_isa_preferred_console(const char *name, int idx)
|
||||
{
|
||||
return serial_base_add_prefcon(name, idx);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int serial_base_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
@ -243,25 +243,12 @@ static void uart_change_line_settings(struct tty_struct *tty, struct uart_state
|
||||
uart_port_unlock_irq(uport);
|
||||
}
|
||||
|
||||
/*
|
||||
* Startup the port. This will be called once per open. All calls
|
||||
* will be serialised by the per-port mutex.
|
||||
*/
|
||||
static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
|
||||
bool init_hw)
|
||||
static int uart_alloc_xmit_buf(struct tty_port *port)
|
||||
{
|
||||
struct uart_port *uport = uart_port_check(state);
|
||||
struct uart_state *state = container_of(port, struct uart_state, port);
|
||||
struct uart_port *uport;
|
||||
unsigned long flags;
|
||||
unsigned long page;
|
||||
int retval = 0;
|
||||
|
||||
if (uport->type == PORT_UNKNOWN)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Make sure the device is in D0 state.
|
||||
*/
|
||||
uart_change_pm(state, UART_PM_STATE_ON);
|
||||
|
||||
/*
|
||||
* Initialise and allocate the transmit and temporary
|
||||
@ -271,20 +258,68 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
|
||||
uart_port_lock(state, flags);
|
||||
if (!state->xmit.buf) {
|
||||
state->xmit.buf = (unsigned char *) page;
|
||||
uart_circ_clear(&state->xmit);
|
||||
uport = uart_port_lock(state, flags);
|
||||
if (!state->port.xmit_buf) {
|
||||
state->port.xmit_buf = (unsigned char *)page;
|
||||
kfifo_init(&state->port.xmit_fifo, state->port.xmit_buf,
|
||||
PAGE_SIZE);
|
||||
uart_port_unlock(uport, flags);
|
||||
} else {
|
||||
uart_port_unlock(uport, flags);
|
||||
/*
|
||||
* Do not free() the page under the port lock, see
|
||||
* uart_shutdown().
|
||||
* uart_free_xmit_buf().
|
||||
*/
|
||||
free_page(page);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uart_free_xmit_buf(struct tty_port *port)
|
||||
{
|
||||
struct uart_state *state = container_of(port, struct uart_state, port);
|
||||
struct uart_port *uport;
|
||||
unsigned long flags;
|
||||
char *xmit_buf;
|
||||
|
||||
/*
|
||||
* 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 end up in printk() recursion.
|
||||
*/
|
||||
uport = uart_port_lock(state, flags);
|
||||
xmit_buf = port->xmit_buf;
|
||||
port->xmit_buf = NULL;
|
||||
INIT_KFIFO(port->xmit_fifo);
|
||||
uart_port_unlock(uport, flags);
|
||||
|
||||
free_page((unsigned long)xmit_buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Startup the port. This will be called once per open. All calls
|
||||
* will be serialised by the per-port mutex.
|
||||
*/
|
||||
static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
|
||||
bool init_hw)
|
||||
{
|
||||
struct uart_port *uport = uart_port_check(state);
|
||||
int retval;
|
||||
|
||||
if (uport->type == PORT_UNKNOWN)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Make sure the device is in D0 state.
|
||||
*/
|
||||
uart_change_pm(state, UART_PM_STATE_ON);
|
||||
|
||||
retval = uart_alloc_xmit_buf(&state->port);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = uport->ops->startup(uport);
|
||||
if (retval == 0) {
|
||||
if (uart_console(uport) && uport->cons->cflag) {
|
||||
@ -356,8 +391,6 @@ 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;
|
||||
char *xmit_buf = NULL;
|
||||
|
||||
/*
|
||||
* Set the TTY IO error marker
|
||||
@ -393,18 +426,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
|
||||
*/
|
||||
tty_port_set_suspended(port, false);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
xmit_buf = state->xmit.buf;
|
||||
state->xmit.buf = NULL;
|
||||
uart_port_unlock(uport, flags);
|
||||
|
||||
free_page((unsigned long)xmit_buf);
|
||||
uart_free_xmit_buf(port);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -565,22 +587,17 @@ static int uart_put_char(struct tty_struct *tty, u8 c)
|
||||
{
|
||||
struct uart_state *state = tty->driver_data;
|
||||
struct uart_port *port;
|
||||
struct circ_buf *circ;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
circ = &state->xmit;
|
||||
port = uart_port_lock(state, flags);
|
||||
if (!circ->buf) {
|
||||
if (!state->port.xmit_buf) {
|
||||
uart_port_unlock(port, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (port && uart_circ_chars_free(circ) != 0) {
|
||||
circ->buf[circ->head] = c;
|
||||
circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1);
|
||||
ret = 1;
|
||||
}
|
||||
if (port)
|
||||
ret = kfifo_put(&state->port.xmit_fifo, c);
|
||||
uart_port_unlock(port, flags);
|
||||
return ret;
|
||||
}
|
||||
@ -594,9 +611,8 @@ static ssize_t uart_write(struct tty_struct *tty, const u8 *buf, size_t count)
|
||||
{
|
||||
struct uart_state *state = tty->driver_data;
|
||||
struct uart_port *port;
|
||||
struct circ_buf *circ;
|
||||
unsigned long flags;
|
||||
int c, ret = 0;
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* This means you called this function _after_ the port was
|
||||
@ -606,24 +622,13 @@ static ssize_t uart_write(struct tty_struct *tty, const u8 *buf, size_t count)
|
||||
return -EL3HLT;
|
||||
|
||||
port = uart_port_lock(state, flags);
|
||||
circ = &state->xmit;
|
||||
if (!circ->buf) {
|
||||
if (WARN_ON_ONCE(!state->port.xmit_buf)) {
|
||||
uart_port_unlock(port, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (port) {
|
||||
c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
|
||||
if (count < c)
|
||||
c = count;
|
||||
if (c <= 0)
|
||||
break;
|
||||
memcpy(circ->buf + circ->head, buf, c);
|
||||
circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1);
|
||||
buf += c;
|
||||
count -= c;
|
||||
ret += c;
|
||||
}
|
||||
if (port)
|
||||
ret = kfifo_in(&state->port.xmit_fifo, buf, count);
|
||||
|
||||
__uart_start(state);
|
||||
uart_port_unlock(port, flags);
|
||||
@ -638,7 +643,7 @@ static unsigned int uart_write_room(struct tty_struct *tty)
|
||||
unsigned int ret;
|
||||
|
||||
port = uart_port_lock(state, flags);
|
||||
ret = uart_circ_chars_free(&state->xmit);
|
||||
ret = kfifo_avail(&state->port.xmit_fifo);
|
||||
uart_port_unlock(port, flags);
|
||||
return ret;
|
||||
}
|
||||
@ -651,7 +656,7 @@ static unsigned int uart_chars_in_buffer(struct tty_struct *tty)
|
||||
unsigned int ret;
|
||||
|
||||
port = uart_port_lock(state, flags);
|
||||
ret = uart_circ_chars_pending(&state->xmit);
|
||||
ret = kfifo_len(&state->port.xmit_fifo);
|
||||
uart_port_unlock(port, flags);
|
||||
return ret;
|
||||
}
|
||||
@ -674,7 +679,7 @@ static void uart_flush_buffer(struct tty_struct *tty)
|
||||
port = uart_port_lock(state, flags);
|
||||
if (!port)
|
||||
return;
|
||||
uart_circ_clear(&state->xmit);
|
||||
kfifo_reset(&state->port.xmit_fifo);
|
||||
if (port->ops->flush_buffer)
|
||||
port->ops->flush_buffer(port);
|
||||
uart_port_unlock(port, flags);
|
||||
@ -1077,7 +1082,7 @@ static int uart_get_lsr_info(struct tty_struct *tty,
|
||||
* interrupt happens).
|
||||
*/
|
||||
if (uport->x_char ||
|
||||
((uart_circ_chars_pending(&state->xmit) > 0) &&
|
||||
(!kfifo_is_empty(&state->port.xmit_fifo) &&
|
||||
!uart_tx_stopped(uport)))
|
||||
result &= ~TIOCSER_TEMT;
|
||||
|
||||
@ -1775,7 +1780,6 @@ static void uart_tty_port_shutdown(struct tty_port *port)
|
||||
{
|
||||
struct uart_state *state = container_of(port, struct uart_state, port);
|
||||
struct uart_port *uport = uart_port_check(state);
|
||||
char *buf;
|
||||
|
||||
/*
|
||||
* At this point, we stop accepting input. To do this, we
|
||||
@ -1798,16 +1802,7 @@ static void uart_tty_port_shutdown(struct tty_port *port)
|
||||
*/
|
||||
tty_port_set_suspended(port, false);
|
||||
|
||||
/*
|
||||
* Free the transmit buffer.
|
||||
*/
|
||||
uart_port_lock_irq(uport);
|
||||
uart_circ_clear(&state->xmit);
|
||||
buf = state->xmit.buf;
|
||||
state->xmit.buf = NULL;
|
||||
uart_port_unlock_irq(uport);
|
||||
|
||||
free_page((unsigned long)buf);
|
||||
uart_free_xmit_buf(port);
|
||||
|
||||
uart_change_pm(state, UART_PM_STATE_OFF);
|
||||
}
|
||||
@ -2413,6 +2408,7 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
|
||||
uport->ops->stop_rx(uport);
|
||||
uart_port_unlock_irq(uport);
|
||||
}
|
||||
device_set_awake_path(uport->dev);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
@ -3211,6 +3207,9 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
|
||||
if (uport->attr_group)
|
||||
uport->tty_groups[1] = uport->attr_group;
|
||||
|
||||
/* Ensure serdev drivers can call serdev_device_open() right away */
|
||||
uport->flags &= ~UPF_DEAD;
|
||||
|
||||
/*
|
||||
* Register the port whether it's detected or not. This allows
|
||||
* setserial to be used to alter this port's parameters.
|
||||
@ -3221,6 +3220,7 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
|
||||
if (!IS_ERR(tty_dev)) {
|
||||
device_set_wakeup_capable(tty_dev, 1);
|
||||
} else {
|
||||
uport->flags |= UPF_DEAD;
|
||||
dev_err(uport->dev, "Cannot register tty device on line %d\n",
|
||||
uport->line);
|
||||
}
|
||||
@ -3422,11 +3422,13 @@ int serial_core_register_port(struct uart_driver *drv, struct uart_port *port)
|
||||
if (ret)
|
||||
goto err_unregister_ctrl_dev;
|
||||
|
||||
ret = serial_core_add_one_port(drv, port);
|
||||
ret = serial_base_add_preferred_console(drv, port);
|
||||
if (ret)
|
||||
goto err_unregister_port_dev;
|
||||
|
||||
port->flags &= ~UPF_DEAD;
|
||||
ret = serial_core_add_one_port(drv, port);
|
||||
if (ret)
|
||||
goto err_unregister_port_dev;
|
||||
|
||||
mutex_unlock(&port_mutex);
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pnp.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/spinlock.h>
|
||||
@ -23,7 +24,7 @@
|
||||
static int __serial_port_busy(struct uart_port *port)
|
||||
{
|
||||
return !uart_tx_stopped(port) &&
|
||||
uart_circ_chars_pending(&port->state->xmit);
|
||||
!kfifo_is_empty(&port->state->port.xmit_fifo);
|
||||
}
|
||||
|
||||
static int serial_port_runtime_resume(struct device *dev)
|
||||
@ -255,7 +256,11 @@ static int __uart_read_properties(struct uart_port *port, bool use_defaults)
|
||||
|
||||
if (dev_is_platform(dev))
|
||||
ret = platform_get_irq(to_platform_device(dev), 0);
|
||||
else
|
||||
else if (dev_is_pnp(dev)) {
|
||||
ret = pnp_irq(to_pnp_dev(dev), 0);
|
||||
if (ret < 0)
|
||||
ret = -ENXIO;
|
||||
} else
|
||||
ret = fwnode_irq_get(dev_fwnode(dev), 0);
|
||||
if (ret == -EPROBE_DEFER)
|
||||
return ret;
|
||||
|
@ -585,7 +585,7 @@ static void sci_start_tx(struct uart_port *port)
|
||||
sci_serial_out(port, SCSCR, new);
|
||||
}
|
||||
|
||||
if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) &&
|
||||
if (s->chan_tx && !kfifo_is_empty(&port->state->port.xmit_fifo) &&
|
||||
dma_submit_error(s->cookie_tx)) {
|
||||
if (s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE)
|
||||
/* Switch irq from SCIF to DMA */
|
||||
@ -817,7 +817,7 @@ static int sci_rxfill(struct uart_port *port)
|
||||
|
||||
static void sci_transmit_chars(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned int stopped = uart_tx_stopped(port);
|
||||
unsigned short status;
|
||||
unsigned short ctrl;
|
||||
@ -826,7 +826,7 @@ static void sci_transmit_chars(struct uart_port *port)
|
||||
status = sci_serial_in(port, SCxSR);
|
||||
if (!(status & SCxSR_TDxE(port))) {
|
||||
ctrl = sci_serial_in(port, SCSCR);
|
||||
if (uart_circ_empty(xmit))
|
||||
if (kfifo_is_empty(&tport->xmit_fifo))
|
||||
ctrl &= ~SCSCR_TIE;
|
||||
else
|
||||
ctrl |= SCSCR_TIE;
|
||||
@ -842,15 +842,14 @@ static void sci_transmit_chars(struct uart_port *port)
|
||||
if (port->x_char) {
|
||||
c = port->x_char;
|
||||
port->x_char = 0;
|
||||
} else if (!uart_circ_empty(xmit) && !stopped) {
|
||||
c = xmit->buf[xmit->tail];
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
} else if (port->type == PORT_SCI && uart_circ_empty(xmit)) {
|
||||
ctrl = sci_serial_in(port, SCSCR);
|
||||
ctrl &= ~SCSCR_TE;
|
||||
sci_serial_out(port, SCSCR, ctrl);
|
||||
return;
|
||||
} else {
|
||||
} else if (stopped || !kfifo_get(&tport->xmit_fifo, &c)) {
|
||||
if (port->type == PORT_SCI &&
|
||||
kfifo_is_empty(&tport->xmit_fifo)) {
|
||||
ctrl = sci_serial_in(port, SCSCR);
|
||||
ctrl &= ~SCSCR_TE;
|
||||
sci_serial_out(port, SCSCR, ctrl);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -861,9 +860,9 @@ static void sci_transmit_chars(struct uart_port *port)
|
||||
|
||||
sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port));
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
if (uart_circ_empty(xmit)) {
|
||||
if (kfifo_is_empty(&tport->xmit_fifo)) {
|
||||
if (port->type == PORT_SCI) {
|
||||
ctrl = sci_serial_in(port, SCSCR);
|
||||
ctrl &= ~SCSCR_TIE;
|
||||
@ -1199,7 +1198,7 @@ static void sci_dma_tx_complete(void *arg)
|
||||
{
|
||||
struct sci_port *s = arg;
|
||||
struct uart_port *port = &s->port;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned long flags;
|
||||
|
||||
dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
|
||||
@ -1208,10 +1207,10 @@ static void sci_dma_tx_complete(void *arg)
|
||||
|
||||
uart_xmit_advance(port, s->tx_dma_len);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (!uart_circ_empty(xmit)) {
|
||||
if (!kfifo_is_empty(&tport->xmit_fifo)) {
|
||||
s->cookie_tx = 0;
|
||||
schedule_work(&s->work_tx);
|
||||
} else {
|
||||
@ -1258,6 +1257,7 @@ static int sci_dma_rx_find_active(struct sci_port *s)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Must only be called with uart_port_lock taken */
|
||||
static void sci_dma_rx_chan_invalidate(struct sci_port *s)
|
||||
{
|
||||
unsigned int i;
|
||||
@ -1271,9 +1271,14 @@ static void sci_dma_rx_chan_invalidate(struct sci_port *s)
|
||||
static void sci_dma_rx_release(struct sci_port *s)
|
||||
{
|
||||
struct dma_chan *chan = s->chan_rx_saved;
|
||||
struct uart_port *port = &s->port;
|
||||
unsigned long flags;
|
||||
|
||||
uart_port_lock_irqsave(port, &flags);
|
||||
s->chan_rx_saved = NULL;
|
||||
sci_dma_rx_chan_invalidate(s);
|
||||
uart_port_unlock_irqrestore(port, flags);
|
||||
|
||||
dmaengine_terminate_sync(chan);
|
||||
dma_free_coherent(chan->device->dev, s->buf_len_rx * 2, s->rx_buf[0],
|
||||
sg_dma_address(&s->sg_rx[0]));
|
||||
@ -1319,14 +1324,14 @@ static void sci_dma_rx_complete(void *arg)
|
||||
dev_dbg(port->dev, "%s(%d) active cookie %d\n", __func__, port->line,
|
||||
s->active_rx);
|
||||
|
||||
hrtimer_cancel(&s->rx_timer);
|
||||
|
||||
uart_port_lock_irqsave(port, &flags);
|
||||
|
||||
active = sci_dma_rx_find_active(s);
|
||||
if (active >= 0)
|
||||
count = sci_dma_rx_push(s, s->rx_buf[active], s->buf_len_rx);
|
||||
|
||||
start_hrtimer_us(&s->rx_timer, s->rx_timeout);
|
||||
|
||||
if (count)
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
|
||||
@ -1349,17 +1354,18 @@ static void sci_dma_rx_complete(void *arg)
|
||||
uart_port_unlock_irqrestore(port, flags);
|
||||
dev_dbg(port->dev, "%s: cookie %d #%d, new active cookie %d\n",
|
||||
__func__, s->cookie_rx[active], active, s->active_rx);
|
||||
|
||||
start_hrtimer_us(&s->rx_timer, s->rx_timeout);
|
||||
|
||||
return;
|
||||
|
||||
fail:
|
||||
uart_port_unlock_irqrestore(port, flags);
|
||||
dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n");
|
||||
/* Switch to PIO */
|
||||
uart_port_lock_irqsave(port, &flags);
|
||||
dmaengine_terminate_async(chan);
|
||||
sci_dma_rx_chan_invalidate(s);
|
||||
sci_dma_rx_reenable_irq(s);
|
||||
uart_port_unlock_irqrestore(port, flags);
|
||||
dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n");
|
||||
}
|
||||
|
||||
static void sci_dma_tx_release(struct sci_port *s)
|
||||
@ -1424,10 +1430,10 @@ static void sci_dma_tx_work_fn(struct work_struct *work)
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
struct dma_chan *chan = s->chan_tx;
|
||||
struct uart_port *port = &s->port;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned long flags;
|
||||
unsigned int tail;
|
||||
dma_addr_t buf;
|
||||
int head, tail;
|
||||
|
||||
/*
|
||||
* DMA is idle now.
|
||||
@ -1437,10 +1443,9 @@ static void sci_dma_tx_work_fn(struct work_struct *work)
|
||||
* consistent xmit buffer state.
|
||||
*/
|
||||
uart_port_lock_irq(port);
|
||||
head = xmit->head;
|
||||
tail = xmit->tail;
|
||||
s->tx_dma_len = kfifo_out_linear(&tport->xmit_fifo, &tail,
|
||||
UART_XMIT_SIZE);
|
||||
buf = s->tx_dma_addr + tail;
|
||||
s->tx_dma_len = CIRC_CNT_TO_END(head, tail, UART_XMIT_SIZE);
|
||||
if (!s->tx_dma_len) {
|
||||
/* Transmit buffer has been flushed */
|
||||
uart_port_unlock_irq(port);
|
||||
@ -1469,8 +1474,8 @@ static void sci_dma_tx_work_fn(struct work_struct *work)
|
||||
}
|
||||
|
||||
uart_port_unlock_irq(port);
|
||||
dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n",
|
||||
__func__, xmit->buf, tail, head, s->cookie_tx);
|
||||
dev_dbg(port->dev, "%s: %p: %u, cookie %d\n",
|
||||
__func__, tport->xmit_buf, tail, s->cookie_tx);
|
||||
|
||||
dma_async_issue_pending(chan);
|
||||
return;
|
||||
@ -1585,6 +1590,7 @@ static struct dma_chan *sci_request_dma_chan(struct uart_port *port,
|
||||
static void sci_request_dma(struct uart_port *port)
|
||||
{
|
||||
struct sci_port *s = to_sci_port(port);
|
||||
struct tty_port *tport = &port->state->port;
|
||||
struct dma_chan *chan;
|
||||
|
||||
dev_dbg(port->dev, "%s: port %d\n", __func__, port->line);
|
||||
@ -1613,7 +1619,7 @@ static void sci_request_dma(struct uart_port *port)
|
||||
if (chan) {
|
||||
/* UART circular tx buffer is an aligned page. */
|
||||
s->tx_dma_addr = dma_map_single(chan->device->dev,
|
||||
port->state->xmit.buf,
|
||||
tport->xmit_buf,
|
||||
UART_XMIT_SIZE,
|
||||
DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(chan->device->dev, s->tx_dma_addr)) {
|
||||
@ -1622,7 +1628,7 @@ static void sci_request_dma(struct uart_port *port)
|
||||
} else {
|
||||
dev_dbg(port->dev, "%s: mapped %lu@%p to %pad\n",
|
||||
__func__, UART_XMIT_SIZE,
|
||||
port->state->xmit.buf, &s->tx_dma_addr);
|
||||
tport->xmit_buf, &s->tx_dma_addr);
|
||||
|
||||
INIT_WORK(&s->work_tx, sci_dma_tx_work_fn);
|
||||
s->chan_tx_saved = s->chan_tx = chan;
|
||||
|
@ -761,7 +761,7 @@ static int __init early_sifive_serial_setup(struct earlycon_device *dev,
|
||||
}
|
||||
|
||||
OF_EARLYCON_DECLARE(sifive, "sifive,uart0", early_sifive_serial_setup);
|
||||
OF_EARLYCON_DECLARE(sifive, "sifive,fu540-c000-uart0",
|
||||
OF_EARLYCON_DECLARE(sifive, "sifive,fu540-c000-uart",
|
||||
early_sifive_serial_setup);
|
||||
#endif /* CONFIG_SERIAL_EARLYCON */
|
||||
|
||||
@ -1032,7 +1032,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(sifive_uart_pm_ops, sifive_serial_suspend,
|
||||
sifive_serial_resume);
|
||||
|
||||
static const struct of_device_id sifive_serial_of_match[] = {
|
||||
{ .compatible = "sifive,fu540-c000-uart0" },
|
||||
{ .compatible = "sifive,fu540-c000-uart" },
|
||||
{ .compatible = "sifive,uart0" },
|
||||
{},
|
||||
};
|
||||
|
@ -227,13 +227,13 @@ static int sprd_tx_buf_remap(struct uart_port *port)
|
||||
{
|
||||
struct sprd_uart_port *sp =
|
||||
container_of(port, struct sprd_uart_port, port);
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned char *tail;
|
||||
|
||||
sp->tx_dma.trans_len =
|
||||
CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
|
||||
sp->tx_dma.trans_len = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail,
|
||||
UART_XMIT_SIZE);
|
||||
|
||||
sp->tx_dma.phys_addr = dma_map_single(port->dev,
|
||||
(void *)&(xmit->buf[xmit->tail]),
|
||||
sp->tx_dma.phys_addr = dma_map_single(port->dev, tail,
|
||||
sp->tx_dma.trans_len,
|
||||
DMA_TO_DEVICE);
|
||||
return dma_mapping_error(port->dev, sp->tx_dma.phys_addr);
|
||||
@ -244,7 +244,7 @@ static void sprd_complete_tx_dma(void *data)
|
||||
struct uart_port *port = (struct uart_port *)data;
|
||||
struct sprd_uart_port *sp =
|
||||
container_of(port, struct sprd_uart_port, port);
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned long flags;
|
||||
|
||||
uart_port_lock_irqsave(port, &flags);
|
||||
@ -253,10 +253,10 @@ static void sprd_complete_tx_dma(void *data)
|
||||
|
||||
uart_xmit_advance(port, sp->tx_dma.trans_len);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (uart_circ_empty(xmit) || sprd_tx_buf_remap(port) ||
|
||||
if (kfifo_is_empty(&tport->xmit_fifo) || sprd_tx_buf_remap(port) ||
|
||||
sprd_tx_dma_config(port))
|
||||
sp->tx_dma.trans_len = 0;
|
||||
|
||||
@ -319,7 +319,7 @@ static void sprd_start_tx_dma(struct uart_port *port)
|
||||
{
|
||||
struct sprd_uart_port *sp =
|
||||
container_of(port, struct sprd_uart_port, port);
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
|
||||
if (port->x_char) {
|
||||
serial_out(port, SPRD_TXD, port->x_char);
|
||||
@ -328,7 +328,7 @@ static void sprd_start_tx_dma(struct uart_port *port)
|
||||
return;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
|
||||
if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
|
||||
sprd_stop_tx_dma(port);
|
||||
return;
|
||||
}
|
||||
|
@ -387,9 +387,9 @@ static unsigned int asc_get_mctrl(struct uart_port *port)
|
||||
/* There are probably characters waiting to be transmitted. */
|
||||
static void asc_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
|
||||
if (!uart_circ_empty(xmit))
|
||||
if (!kfifo_is_empty(&tport->xmit_fifo))
|
||||
asc_enable_tx_interrupts(port);
|
||||
}
|
||||
|
||||
|
@ -696,18 +696,23 @@ static void stm32_usart_transmit_chars_pio(struct uart_port *port)
|
||||
{
|
||||
struct stm32_port *stm32_port = to_stm32_port(port);
|
||||
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
|
||||
while (1) {
|
||||
unsigned char ch;
|
||||
|
||||
while (!uart_circ_empty(xmit)) {
|
||||
/* Check that TDR is empty before filling FIFO */
|
||||
if (!(readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE))
|
||||
break;
|
||||
writel_relaxed(xmit->buf[xmit->tail], port->membase + ofs->tdr);
|
||||
uart_xmit_advance(port, 1);
|
||||
|
||||
if (!uart_fifo_get(port, &ch))
|
||||
break;
|
||||
|
||||
writel_relaxed(ch, port->membase + ofs->tdr);
|
||||
}
|
||||
|
||||
/* rely on TXE irq (mask or unmask) for sending remaining data */
|
||||
if (uart_circ_empty(xmit))
|
||||
if (kfifo_is_empty(&tport->xmit_fifo))
|
||||
stm32_usart_tx_interrupt_disable(port);
|
||||
else
|
||||
stm32_usart_tx_interrupt_enable(port);
|
||||
@ -716,7 +721,7 @@ static void stm32_usart_transmit_chars_pio(struct uart_port *port)
|
||||
static void stm32_usart_transmit_chars_dma(struct uart_port *port)
|
||||
{
|
||||
struct stm32_port *stm32port = to_stm32_port(port);
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
struct dma_async_tx_descriptor *desc = NULL;
|
||||
unsigned int count;
|
||||
int ret;
|
||||
@ -728,25 +733,8 @@ static void stm32_usart_transmit_chars_dma(struct uart_port *port)
|
||||
return;
|
||||
}
|
||||
|
||||
count = uart_circ_chars_pending(xmit);
|
||||
|
||||
if (count > TX_BUF_L)
|
||||
count = TX_BUF_L;
|
||||
|
||||
if (xmit->tail < xmit->head) {
|
||||
memcpy(&stm32port->tx_buf[0], &xmit->buf[xmit->tail], count);
|
||||
} else {
|
||||
size_t one = UART_XMIT_SIZE - xmit->tail;
|
||||
size_t two;
|
||||
|
||||
if (one > count)
|
||||
one = count;
|
||||
two = count - one;
|
||||
|
||||
memcpy(&stm32port->tx_buf[0], &xmit->buf[xmit->tail], one);
|
||||
if (two)
|
||||
memcpy(&stm32port->tx_buf[one], &xmit->buf[0], two);
|
||||
}
|
||||
count = kfifo_out_peek(&tport->xmit_fifo, &stm32port->tx_buf[0],
|
||||
TX_BUF_L);
|
||||
|
||||
desc = dmaengine_prep_slave_single(stm32port->tx_ch,
|
||||
stm32port->tx_dma_buf,
|
||||
@ -792,14 +780,14 @@ static void stm32_usart_transmit_chars(struct uart_port *port)
|
||||
{
|
||||
struct stm32_port *stm32_port = to_stm32_port(port);
|
||||
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
u32 isr;
|
||||
int ret;
|
||||
|
||||
if (!stm32_port->hw_flow_control &&
|
||||
port->rs485.flags & SER_RS485_ENABLED &&
|
||||
(port->x_char ||
|
||||
!(uart_circ_empty(xmit) || uart_tx_stopped(port)))) {
|
||||
!(kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)))) {
|
||||
stm32_usart_tc_interrupt_disable(port);
|
||||
stm32_usart_rs485_rts_enable(port);
|
||||
}
|
||||
@ -826,7 +814,7 @@ static void stm32_usart_transmit_chars(struct uart_port *port)
|
||||
return;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
|
||||
if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
|
||||
stm32_usart_tx_interrupt_disable(port);
|
||||
return;
|
||||
}
|
||||
@ -841,10 +829,10 @@ static void stm32_usart_transmit_chars(struct uart_port *port)
|
||||
else
|
||||
stm32_usart_transmit_chars_pio(port);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (uart_circ_empty(xmit)) {
|
||||
if (kfifo_is_empty(&tport->xmit_fifo)) {
|
||||
stm32_usart_tx_interrupt_disable(port);
|
||||
if (!stm32_port->hw_flow_control &&
|
||||
port->rs485.flags & SER_RS485_ENABLED) {
|
||||
@ -975,9 +963,9 @@ static void stm32_usart_stop_tx(struct uart_port *port)
|
||||
/* There are probably characters waiting to be transmitted. */
|
||||
static void stm32_usart_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
|
||||
if (uart_circ_empty(xmit) && !port->x_char) {
|
||||
if (kfifo_is_empty(&tport->xmit_fifo) && !port->x_char) {
|
||||
stm32_usart_rs485_rts_disable(port);
|
||||
return;
|
||||
}
|
||||
|
@ -39,10 +39,13 @@ static char *con_read_page;
|
||||
|
||||
static int hung_up = 0;
|
||||
|
||||
static void transmit_chars_putchar(struct uart_port *port, struct circ_buf *xmit)
|
||||
static void transmit_chars_putchar(struct uart_port *port,
|
||||
struct tty_port *tport)
|
||||
{
|
||||
while (!uart_circ_empty(xmit)) {
|
||||
long status = sun4v_con_putchar(xmit->buf[xmit->tail]);
|
||||
unsigned char ch;
|
||||
|
||||
while (kfifo_peek(&tport->xmit_fifo, &ch)) {
|
||||
long status = sun4v_con_putchar(ch);
|
||||
|
||||
if (status != HV_EOK)
|
||||
break;
|
||||
@ -51,14 +54,16 @@ static void transmit_chars_putchar(struct uart_port *port, struct circ_buf *xmit
|
||||
}
|
||||
}
|
||||
|
||||
static void transmit_chars_write(struct uart_port *port, struct circ_buf *xmit)
|
||||
static void transmit_chars_write(struct uart_port *port, struct tty_port *tport)
|
||||
{
|
||||
while (!uart_circ_empty(xmit)) {
|
||||
unsigned long ra = __pa(xmit->buf + xmit->tail);
|
||||
unsigned long len, status, sent;
|
||||
while (!kfifo_is_empty(&tport->xmit_fifo)) {
|
||||
unsigned long len, ra, status, sent;
|
||||
unsigned char *tail;
|
||||
|
||||
len = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail,
|
||||
UART_XMIT_SIZE);
|
||||
ra = __pa(tail);
|
||||
|
||||
len = CIRC_CNT_TO_END(xmit->head, xmit->tail,
|
||||
UART_XMIT_SIZE);
|
||||
status = sun4v_con_write(ra, len, &sent);
|
||||
if (status != HV_EOK)
|
||||
break;
|
||||
@ -165,7 +170,7 @@ static int receive_chars_read(struct uart_port *port)
|
||||
}
|
||||
|
||||
struct sunhv_ops {
|
||||
void (*transmit_chars)(struct uart_port *port, struct circ_buf *xmit);
|
||||
void (*transmit_chars)(struct uart_port *port, struct tty_port *tport);
|
||||
int (*receive_chars)(struct uart_port *port);
|
||||
};
|
||||
|
||||
@ -196,18 +201,18 @@ static struct tty_port *receive_chars(struct uart_port *port)
|
||||
|
||||
static void transmit_chars(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit;
|
||||
struct tty_port *tport;
|
||||
|
||||
if (!port->state)
|
||||
return;
|
||||
|
||||
xmit = &port->state->xmit;
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port))
|
||||
tport = &port->state->port;
|
||||
if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port))
|
||||
return;
|
||||
|
||||
sunhv_ops->transmit_chars(port, xmit);
|
||||
sunhv_ops->transmit_chars(port, tport);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
}
|
||||
|
||||
|
@ -200,7 +200,7 @@ static void sunplus_break_ctl(struct uart_port *port, int ctl)
|
||||
|
||||
static void transmit_chars(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
|
||||
if (port->x_char) {
|
||||
sp_uart_put_char(port, port->x_char);
|
||||
@ -209,22 +209,24 @@ static void transmit_chars(struct uart_port *port)
|
||||
return;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
|
||||
if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
|
||||
sunplus_stop_tx(port);
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
sp_uart_put_char(port, xmit->buf[xmit->tail]);
|
||||
uart_xmit_advance(port, 1);
|
||||
if (uart_circ_empty(xmit))
|
||||
unsigned char ch;
|
||||
|
||||
if (!uart_fifo_get(port, &ch))
|
||||
break;
|
||||
|
||||
sp_uart_put_char(port, ch);
|
||||
} while (sunplus_tx_buf_not_full(port));
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
if (kfifo_is_empty(&tport->xmit_fifo))
|
||||
sunplus_stop_tx(port);
|
||||
}
|
||||
|
||||
|
@ -232,7 +232,7 @@ static void sunsab_tx_idle(struct uart_sunsab_port *);
|
||||
static void transmit_chars(struct uart_sunsab_port *up,
|
||||
union sab82532_irq_status *stat)
|
||||
{
|
||||
struct circ_buf *xmit = &up->port.state->xmit;
|
||||
struct tty_port *tport = &up->port.state->port;
|
||||
int i;
|
||||
|
||||
if (stat->sreg.isr1 & SAB82532_ISR1_ALLS) {
|
||||
@ -252,7 +252,7 @@ static void transmit_chars(struct uart_sunsab_port *up,
|
||||
set_bit(SAB82532_XPR, &up->irqflags);
|
||||
sunsab_tx_idle(up);
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
|
||||
if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(&up->port)) {
|
||||
up->interrupt_mask1 |= SAB82532_IMR1_XPR;
|
||||
writeb(up->interrupt_mask1, &up->regs->w.imr1);
|
||||
return;
|
||||
@ -265,21 +265,22 @@ static void transmit_chars(struct uart_sunsab_port *up,
|
||||
/* Stuff 32 bytes into Transmit FIFO. */
|
||||
clear_bit(SAB82532_XPR, &up->irqflags);
|
||||
for (i = 0; i < up->port.fifosize; i++) {
|
||||
writeb(xmit->buf[xmit->tail],
|
||||
&up->regs->w.xfifo[i]);
|
||||
uart_xmit_advance(&up->port, 1);
|
||||
if (uart_circ_empty(xmit))
|
||||
unsigned char ch;
|
||||
|
||||
if (!uart_fifo_get(&up->port, &ch))
|
||||
break;
|
||||
|
||||
writeb(ch, &up->regs->w.xfifo[i]);
|
||||
}
|
||||
|
||||
/* Issue a Transmit Frame command. */
|
||||
sunsab_cec_wait(up);
|
||||
writeb(SAB82532_CMDR_XF, &up->regs->w.cmdr);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&up->port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
if (kfifo_is_empty(&tport->xmit_fifo))
|
||||
sunsab_stop_tx(&up->port);
|
||||
}
|
||||
|
||||
@ -435,10 +436,10 @@ static void sunsab_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct uart_sunsab_port *up =
|
||||
container_of(port, struct uart_sunsab_port, port);
|
||||
struct circ_buf *xmit = &up->port.state->xmit;
|
||||
struct tty_port *tport = &up->port.state->port;
|
||||
int i;
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port))
|
||||
if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port))
|
||||
return;
|
||||
|
||||
up->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS|SAB82532_IMR1_XPR);
|
||||
@ -451,11 +452,12 @@ static void sunsab_start_tx(struct uart_port *port)
|
||||
clear_bit(SAB82532_XPR, &up->irqflags);
|
||||
|
||||
for (i = 0; i < up->port.fifosize; i++) {
|
||||
writeb(xmit->buf[xmit->tail],
|
||||
&up->regs->w.xfifo[i]);
|
||||
uart_xmit_advance(&up->port, 1);
|
||||
if (uart_circ_empty(xmit))
|
||||
unsigned char ch;
|
||||
|
||||
if (!uart_fifo_get(&up->port, &ch))
|
||||
break;
|
||||
|
||||
writeb(ch, &up->regs->w.xfifo[i]);
|
||||
}
|
||||
|
||||
/* Issue a Transmit Frame command. */
|
||||
|
@ -396,7 +396,8 @@ receive_chars(struct uart_sunsu_port *up, unsigned char *status)
|
||||
|
||||
static void transmit_chars(struct uart_sunsu_port *up)
|
||||
{
|
||||
struct circ_buf *xmit = &up->port.state->xmit;
|
||||
struct tty_port *tport = &up->port.state->port;
|
||||
unsigned char ch;
|
||||
int count;
|
||||
|
||||
if (up->port.x_char) {
|
||||
@ -409,23 +410,23 @@ static void transmit_chars(struct uart_sunsu_port *up)
|
||||
sunsu_stop_tx(&up->port);
|
||||
return;
|
||||
}
|
||||
if (uart_circ_empty(xmit)) {
|
||||
if (kfifo_is_empty(&tport->xmit_fifo)) {
|
||||
__stop_tx(up);
|
||||
return;
|
||||
}
|
||||
|
||||
count = up->port.fifosize;
|
||||
do {
|
||||
serial_out(up, UART_TX, xmit->buf[xmit->tail]);
|
||||
uart_xmit_advance(&up->port, 1);
|
||||
if (uart_circ_empty(xmit))
|
||||
if (!uart_fifo_get(&up->port, &ch))
|
||||
break;
|
||||
|
||||
serial_out(up, UART_TX, ch);
|
||||
} while (--count > 0);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&up->port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
if (kfifo_is_empty(&tport->xmit_fifo))
|
||||
__stop_tx(up);
|
||||
}
|
||||
|
||||
|
@ -453,7 +453,8 @@ static void sunzilog_status_handle(struct uart_sunzilog_port *up,
|
||||
static void sunzilog_transmit_chars(struct uart_sunzilog_port *up,
|
||||
struct zilog_channel __iomem *channel)
|
||||
{
|
||||
struct circ_buf *xmit;
|
||||
struct tty_port *tport;
|
||||
unsigned char ch;
|
||||
|
||||
if (ZS_IS_CONS(up)) {
|
||||
unsigned char status = readb(&channel->control);
|
||||
@ -496,21 +497,20 @@ static void sunzilog_transmit_chars(struct uart_sunzilog_port *up,
|
||||
|
||||
if (up->port.state == NULL)
|
||||
goto ack_tx_int;
|
||||
xmit = &up->port.state->xmit;
|
||||
if (uart_circ_empty(xmit))
|
||||
goto ack_tx_int;
|
||||
tport = &up->port.state->port;
|
||||
|
||||
if (uart_tx_stopped(&up->port))
|
||||
goto ack_tx_int;
|
||||
|
||||
if (!uart_fifo_get(&up->port, &ch))
|
||||
goto ack_tx_int;
|
||||
|
||||
up->flags |= SUNZILOG_FLAG_TX_ACTIVE;
|
||||
writeb(xmit->buf[xmit->tail], &channel->data);
|
||||
writeb(ch, &channel->data);
|
||||
ZSDELAY();
|
||||
ZS_WSYNC(channel);
|
||||
|
||||
uart_xmit_advance(&up->port, 1);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&up->port);
|
||||
|
||||
return;
|
||||
@ -700,17 +700,16 @@ static void sunzilog_start_tx(struct uart_port *port)
|
||||
port->icount.tx++;
|
||||
port->x_char = 0;
|
||||
} else {
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned char ch;
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
if (!uart_fifo_get(&up->port, &ch))
|
||||
return;
|
||||
writeb(xmit->buf[xmit->tail], &channel->data);
|
||||
writeb(ch, &channel->data);
|
||||
ZSDELAY();
|
||||
ZS_WSYNC(channel);
|
||||
|
||||
uart_xmit_advance(port, 1);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&up->port);
|
||||
}
|
||||
}
|
||||
|
@ -91,15 +91,17 @@ static void tegra_tcu_write(struct tegra_tcu *tcu, const char *s,
|
||||
static void tegra_tcu_uart_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct tegra_tcu *tcu = port->private_data;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
unsigned long count;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned char *tail;
|
||||
unsigned int count;
|
||||
|
||||
for (;;) {
|
||||
count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
|
||||
count = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail,
|
||||
UART_XMIT_SIZE);
|
||||
if (!count)
|
||||
break;
|
||||
|
||||
tegra_tcu_write(tcu, &xmit->buf[xmit->tail], count);
|
||||
tegra_tcu_write(tcu, tail, count);
|
||||
uart_xmit_advance(port, count);
|
||||
}
|
||||
|
||||
|
@ -95,14 +95,11 @@ static void timbuart_rx_chars(struct uart_port *port)
|
||||
|
||||
static void timbuart_tx_chars(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
unsigned char ch;
|
||||
|
||||
while (!(ioread32(port->membase + TIMBUART_ISR) & TXBF) &&
|
||||
!uart_circ_empty(xmit)) {
|
||||
iowrite8(xmit->buf[xmit->tail],
|
||||
port->membase + TIMBUART_TXFIFO);
|
||||
uart_xmit_advance(port, 1);
|
||||
}
|
||||
uart_fifo_get(port, &ch))
|
||||
iowrite8(ch, port->membase + TIMBUART_TXFIFO);
|
||||
|
||||
dev_dbg(port->dev,
|
||||
"%s - total written %d bytes, CTL: %x, RTS: %x, baud: %x\n",
|
||||
@ -117,9 +114,9 @@ static void timbuart_handle_tx_port(struct uart_port *port, u32 isr, u32 *ier)
|
||||
{
|
||||
struct timbuart_port *uart =
|
||||
container_of(port, struct timbuart_port, port);
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port))
|
||||
if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port))
|
||||
return;
|
||||
|
||||
if (port->x_char)
|
||||
@ -130,7 +127,7 @@ static void timbuart_handle_tx_port(struct uart_port *port, u32 isr, u32 *ier)
|
||||
/* clear all TX interrupts */
|
||||
iowrite32(TXFLAGS, port->membase + TIMBUART_ISR);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
} else
|
||||
/* Re-enable any tx interrupt */
|
||||
@ -141,7 +138,7 @@ static void timbuart_handle_tx_port(struct uart_port *port, u32 isr, u32 *ier)
|
||||
* we wake up the upper layer later when we got the interrupt
|
||||
* to give it some time to go out...
|
||||
*/
|
||||
if (!uart_circ_empty(xmit))
|
||||
if (!kfifo_is_empty(&tport->xmit_fifo))
|
||||
*ier |= TXBAE;
|
||||
|
||||
dev_dbg(port->dev, "%s - leaving\n", __func__);
|
||||
|
@ -189,7 +189,8 @@ static int ulite_receive(struct uart_port *port, int stat)
|
||||
|
||||
static int ulite_transmit(struct uart_port *port, int stat)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned char ch;
|
||||
|
||||
if (stat & ULITE_STATUS_TXFULL)
|
||||
return 0;
|
||||
@ -201,14 +202,16 @@ static int ulite_transmit(struct uart_port *port, int stat)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port))
|
||||
if (uart_tx_stopped(port))
|
||||
return 0;
|
||||
|
||||
uart_out32(xmit->buf[xmit->tail], ULITE_TX, port);
|
||||
uart_xmit_advance(port, 1);
|
||||
if (!uart_fifo_get(port, &ch))
|
||||
return 0;
|
||||
|
||||
uart_out32(ch, ULITE_TX, port);
|
||||
|
||||
/* wake up */
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
return 1;
|
||||
|
@ -334,7 +334,7 @@ static int qe_uart_tx_pump(struct uart_qe_port *qe_port)
|
||||
unsigned char *p;
|
||||
unsigned int count;
|
||||
struct uart_port *port = &qe_port->port;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
|
||||
/* Handle xon/xoff */
|
||||
if (port->x_char) {
|
||||
@ -358,7 +358,7 @@ static int qe_uart_tx_pump(struct uart_qe_port *qe_port)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
|
||||
if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
|
||||
qe_uart_stop_tx(port);
|
||||
return 0;
|
||||
}
|
||||
@ -366,16 +366,10 @@ static int qe_uart_tx_pump(struct uart_qe_port *qe_port)
|
||||
/* Pick next descriptor and fill from buffer */
|
||||
bdp = qe_port->tx_cur;
|
||||
|
||||
while (!(ioread16be(&bdp->status) & BD_SC_READY) && !uart_circ_empty(xmit)) {
|
||||
count = 0;
|
||||
while (!(ioread16be(&bdp->status) & BD_SC_READY) &&
|
||||
!kfifo_is_empty(&tport->xmit_fifo)) {
|
||||
p = qe2cpu_addr(ioread32be(&bdp->buf), qe_port);
|
||||
while (count < qe_port->tx_fifosize) {
|
||||
*p++ = xmit->buf[xmit->tail];
|
||||
uart_xmit_advance(port, 1);
|
||||
count++;
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
}
|
||||
count = uart_fifo_out(port, p, qe_port->tx_fifosize);
|
||||
|
||||
iowrite16be(count, &bdp->length);
|
||||
qe_setbits_be16(&bdp->status, BD_SC_READY);
|
||||
@ -388,10 +382,10 @@ static int qe_uart_tx_pump(struct uart_qe_port *qe_port)
|
||||
}
|
||||
qe_port->tx_cur = bdp;
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (uart_circ_empty(xmit)) {
|
||||
if (kfifo_is_empty(&tport->xmit_fifo)) {
|
||||
/* The kernel buffer is empty, so turn off TX interrupts. We
|
||||
don't need to be told when the QE is finished transmitting
|
||||
the data. */
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#define CDNS_UART_TTY_NAME "ttyPS"
|
||||
#define CDNS_UART_NAME "xuartps"
|
||||
@ -198,6 +199,7 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
|
||||
* @gpiod_rts: Pointer to the gpio descriptor
|
||||
* @rs485_tx_started: RS485 tx state
|
||||
* @tx_timer: Timer for tx
|
||||
* @rstc: Pointer to the reset control
|
||||
*/
|
||||
struct cdns_uart {
|
||||
struct uart_port *port;
|
||||
@ -211,6 +213,7 @@ struct cdns_uart {
|
||||
struct gpio_desc *gpiod_rts;
|
||||
bool rs485_tx_started;
|
||||
struct hrtimer tx_timer;
|
||||
struct reset_control *rstc;
|
||||
};
|
||||
struct cdns_platform_data {
|
||||
u32 quirks;
|
||||
@ -425,32 +428,32 @@ static void cdns_uart_handle_tx(void *dev_id)
|
||||
{
|
||||
struct uart_port *port = (struct uart_port *)dev_id;
|
||||
struct cdns_uart *cdns_uart = port->private_data;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned int numbytes;
|
||||
unsigned char ch;
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
|
||||
if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
|
||||
/* Disable the TX Empty interrupt */
|
||||
writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR);
|
||||
return;
|
||||
}
|
||||
|
||||
numbytes = port->fifosize;
|
||||
while (numbytes && !uart_circ_empty(xmit) &&
|
||||
!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL)) {
|
||||
|
||||
writel(xmit->buf[xmit->tail], port->membase + CDNS_UART_FIFO);
|
||||
uart_xmit_advance(port, 1);
|
||||
while (numbytes &&
|
||||
!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL) &&
|
||||
uart_fifo_get(port, &ch)) {
|
||||
writel(ch, port->membase + CDNS_UART_FIFO);
|
||||
numbytes--;
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
/* Enable the TX Empty interrupt */
|
||||
writel(CDNS_UART_IXR_TXEMPTY, cdns_uart->port->membase + CDNS_UART_IER);
|
||||
|
||||
if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED &&
|
||||
(uart_circ_empty(xmit) || uart_tx_stopped(port))) {
|
||||
(kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port))) {
|
||||
cdns_uart->tx_timer.function = &cdns_rs485_rx_callback;
|
||||
hrtimer_start(&cdns_uart->tx_timer,
|
||||
ns_to_ktime(cdns_calc_after_tx_delay(cdns_uart)), HRTIMER_MODE_REL);
|
||||
@ -723,7 +726,7 @@ static void cdns_uart_start_tx(struct uart_port *port)
|
||||
status |= CDNS_UART_CR_TX_EN;
|
||||
writel(status, port->membase + CDNS_UART_CR);
|
||||
|
||||
if (uart_circ_empty(&port->state->xmit))
|
||||
if (kfifo_is_empty(&port->state->port.xmit_fifo))
|
||||
return;
|
||||
|
||||
/* Clear the TX Empty interrupt */
|
||||
@ -948,6 +951,10 @@ static int cdns_uart_startup(struct uart_port *port)
|
||||
|
||||
is_brk_support = cdns_uart->quirks & CDNS_UART_RXBS_SUPPORT;
|
||||
|
||||
ret = reset_control_deassert(cdns_uart->rstc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
uart_port_lock_irqsave(port, &flags);
|
||||
|
||||
/* Disable the TX and RX */
|
||||
@ -1721,6 +1728,13 @@ static int cdns_uart_probe(struct platform_device *pdev)
|
||||
dev_err(&pdev->dev, "clock name 'ref_clk' is deprecated.\n");
|
||||
}
|
||||
|
||||
cdns_uart_data->rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
|
||||
if (IS_ERR(cdns_uart_data->rstc)) {
|
||||
rc = PTR_ERR(cdns_uart_data->rstc);
|
||||
dev_err_probe(&pdev->dev, rc, "Cannot get UART reset\n");
|
||||
goto err_out_unregister_driver;
|
||||
}
|
||||
|
||||
rc = clk_prepare_enable(cdns_uart_data->pclk);
|
||||
if (rc) {
|
||||
dev_err(&pdev->dev, "Unable to enable pclk clock.\n");
|
||||
@ -1881,6 +1895,7 @@ static void cdns_uart_remove(struct platform_device *pdev)
|
||||
if (console_port == port)
|
||||
console_port = NULL;
|
||||
#endif
|
||||
reset_control_assert(cdns_uart_data->rstc);
|
||||
|
||||
if (!--instances)
|
||||
uart_unregister_driver(cdns_uart_data->cdns_uart_driver);
|
||||
|
@ -606,7 +606,8 @@ static void zs_receive_chars(struct zs_port *zport)
|
||||
|
||||
static void zs_raw_transmit_chars(struct zs_port *zport)
|
||||
{
|
||||
struct circ_buf *xmit = &zport->port.state->xmit;
|
||||
struct tty_port *tport = &zport->port.state->port;
|
||||
unsigned char ch;
|
||||
|
||||
/* XON/XOFF chars. */
|
||||
if (zport->port.x_char) {
|
||||
@ -617,20 +618,20 @@ static void zs_raw_transmit_chars(struct zs_port *zport)
|
||||
}
|
||||
|
||||
/* If nothing to do or stopped or hardware stopped. */
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(&zport->port)) {
|
||||
if (uart_tx_stopped(&zport->port) ||
|
||||
!uart_fifo_get(&zport->port, &ch)) {
|
||||
zs_raw_stop_tx(zport);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Send char. */
|
||||
write_zsdata(zport, xmit->buf[xmit->tail]);
|
||||
uart_xmit_advance(&zport->port, 1);
|
||||
write_zsdata(zport, ch);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&zport->port);
|
||||
|
||||
/* Are we are done? */
|
||||
if (uart_circ_empty(xmit))
|
||||
if (kfifo_is_empty(&tport->xmit_fifo))
|
||||
zs_raw_stop_tx(zport);
|
||||
}
|
||||
|
||||
|
@ -450,6 +450,17 @@ static const struct sysrq_key_op sysrq_unrt_op = {
|
||||
.enable_mask = SYSRQ_ENABLE_RTNICE,
|
||||
};
|
||||
|
||||
static void sysrq_handle_replay_logs(u8 key)
|
||||
{
|
||||
console_replay_all();
|
||||
}
|
||||
static struct sysrq_key_op sysrq_replay_logs_op = {
|
||||
.handler = sysrq_handle_replay_logs,
|
||||
.help_msg = "replay-kernel-logs(R)",
|
||||
.action_msg = "Replay kernel logs on consoles",
|
||||
.enable_mask = SYSRQ_ENABLE_DUMP,
|
||||
};
|
||||
|
||||
/* Key Operations table and lock */
|
||||
static DEFINE_SPINLOCK(sysrq_key_table_lock);
|
||||
|
||||
@ -519,7 +530,7 @@ static const struct sysrq_key_op *sysrq_key_table[62] = {
|
||||
NULL, /* O */
|
||||
NULL, /* P */
|
||||
NULL, /* Q */
|
||||
NULL, /* R */
|
||||
&sysrq_replay_logs_op, /* R */
|
||||
NULL, /* S */
|
||||
NULL, /* T */
|
||||
NULL, /* U */
|
||||
|
@ -545,6 +545,12 @@ int tty_set_ldisc(struct tty_struct *tty, int disc)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (tty->ops->ldisc_ok) {
|
||||
retval = tty->ops->ldisc_ok(tty, disc);
|
||||
if (retval)
|
||||
goto out;
|
||||
}
|
||||
|
||||
old_ldisc = tty->ldisc;
|
||||
|
||||
/* Shutdown the old discipline. */
|
||||
|
@ -76,7 +76,8 @@ static void addpair(int fp, int un)
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
FILE *ctbl;
|
||||
char *tblname;
|
||||
const char *tblname, *rel_tblname;
|
||||
const char *abs_srctree;
|
||||
char buffer[65536];
|
||||
int fontlen;
|
||||
int i, nuni, nent;
|
||||
@ -101,6 +102,16 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
abs_srctree = getenv("abs_srctree");
|
||||
if (abs_srctree && !strncmp(abs_srctree, tblname, strlen(abs_srctree)))
|
||||
{
|
||||
rel_tblname = tblname + strlen(abs_srctree);
|
||||
while (*rel_tblname == '/')
|
||||
++rel_tblname;
|
||||
}
|
||||
else
|
||||
rel_tblname = tblname;
|
||||
|
||||
/* For now we assume the default font is always 256 characters. */
|
||||
fontlen = 256;
|
||||
|
||||
@ -253,7 +264,7 @@ int main(int argc, char *argv[])
|
||||
#include <linux/types.h>\n\
|
||||
\n\
|
||||
u8 dfont_unicount[%d] = \n\
|
||||
{\n\t", argv[1], fontlen);
|
||||
{\n\t", rel_tblname, fontlen);
|
||||
|
||||
for ( i = 0 ; i < fontlen ; i++ )
|
||||
{
|
||||
|
@ -3576,6 +3576,15 @@ static void con_cleanup(struct tty_struct *tty)
|
||||
tty_port_put(&vc->port);
|
||||
}
|
||||
|
||||
/*
|
||||
* We can't deal with anything but the N_TTY ldisc,
|
||||
* because we can sleep in our write() routine.
|
||||
*/
|
||||
static int con_ldisc_ok(struct tty_struct *tty, int ldisc)
|
||||
{
|
||||
return ldisc == N_TTY ? 0 : -EINVAL;
|
||||
}
|
||||
|
||||
static int default_color = 7; /* white */
|
||||
static int default_italic_color = 2; // green (ASCII)
|
||||
static int default_underline_color = 3; // cyan (ASCII)
|
||||
@ -3695,6 +3704,7 @@ static const struct tty_operations con_ops = {
|
||||
.resize = vt_resize,
|
||||
.shutdown = con_shutdown,
|
||||
.cleanup = con_cleanup,
|
||||
.ldisc_ok = con_ldisc_ok,
|
||||
};
|
||||
|
||||
static struct cdev vc0_cdev;
|
||||
|
@ -37,6 +37,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/array_size.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/types.h>
|
||||
@ -309,19 +310,25 @@ __kfifo_uint_must_check_helper( \
|
||||
)
|
||||
|
||||
/**
|
||||
* kfifo_skip - skip output data
|
||||
* kfifo_skip_count - skip output data
|
||||
* @fifo: address of the fifo to be used
|
||||
* @count: count of data to skip
|
||||
*/
|
||||
#define kfifo_skip(fifo) \
|
||||
(void)({ \
|
||||
#define kfifo_skip_count(fifo, count) do { \
|
||||
typeof((fifo) + 1) __tmp = (fifo); \
|
||||
const size_t __recsize = sizeof(*__tmp->rectype); \
|
||||
struct __kfifo *__kfifo = &__tmp->kfifo; \
|
||||
if (__recsize) \
|
||||
__kfifo_skip_r(__kfifo, __recsize); \
|
||||
else \
|
||||
__kfifo->out++; \
|
||||
})
|
||||
__kfifo->out += (count); \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
* kfifo_skip - skip output data
|
||||
* @fifo: address of the fifo to be used
|
||||
*/
|
||||
#define kfifo_skip(fifo) kfifo_skip_count(fifo, 1)
|
||||
|
||||
/**
|
||||
* kfifo_peek_len - gets the size of the next fifo record
|
||||
@ -583,7 +590,7 @@ __kfifo_uint_must_check_helper( \
|
||||
* @buf: pointer to the storage buffer
|
||||
* @n: max. number of elements to get
|
||||
*
|
||||
* This macro get some data from the fifo and return the numbers of elements
|
||||
* This macro gets some data from the fifo and returns the numbers of elements
|
||||
* copied.
|
||||
*
|
||||
* Note that with only one concurrent reader and one concurrent
|
||||
@ -610,7 +617,7 @@ __kfifo_uint_must_check_helper( \
|
||||
* @n: max. number of elements to get
|
||||
* @lock: pointer to the spinlock to use for locking
|
||||
*
|
||||
* This macro get the data from the fifo and return the numbers of elements
|
||||
* This macro gets the data from the fifo and returns the numbers of elements
|
||||
* copied.
|
||||
*/
|
||||
#define kfifo_out_spinlocked(fifo, buf, n, lock) \
|
||||
@ -708,11 +715,12 @@ __kfifo_int_must_check_helper( \
|
||||
)
|
||||
|
||||
/**
|
||||
* kfifo_dma_in_prepare - setup a scatterlist for DMA input
|
||||
* kfifo_dma_in_prepare_mapped - setup a scatterlist for DMA input
|
||||
* @fifo: address of the fifo to be used
|
||||
* @sgl: pointer to the scatterlist array
|
||||
* @nents: number of entries in the scatterlist array
|
||||
* @len: number of elements to transfer
|
||||
* @dma: mapped dma address to fill into @sgl
|
||||
*
|
||||
* This macro fills a scatterlist for DMA input.
|
||||
* It returns the number entries in the scatterlist array.
|
||||
@ -720,7 +728,7 @@ __kfifo_int_must_check_helper( \
|
||||
* Note that with only one concurrent reader and one concurrent
|
||||
* writer, you don't need extra locking to use these macros.
|
||||
*/
|
||||
#define kfifo_dma_in_prepare(fifo, sgl, nents, len) \
|
||||
#define kfifo_dma_in_prepare_mapped(fifo, sgl, nents, len, dma) \
|
||||
({ \
|
||||
typeof((fifo) + 1) __tmp = (fifo); \
|
||||
struct scatterlist *__sgl = (sgl); \
|
||||
@ -729,16 +737,20 @@ __kfifo_int_must_check_helper( \
|
||||
const size_t __recsize = sizeof(*__tmp->rectype); \
|
||||
struct __kfifo *__kfifo = &__tmp->kfifo; \
|
||||
(__recsize) ? \
|
||||
__kfifo_dma_in_prepare_r(__kfifo, __sgl, __nents, __len, __recsize) : \
|
||||
__kfifo_dma_in_prepare(__kfifo, __sgl, __nents, __len); \
|
||||
__kfifo_dma_in_prepare_r(__kfifo, __sgl, __nents, __len, __recsize, \
|
||||
dma) : \
|
||||
__kfifo_dma_in_prepare(__kfifo, __sgl, __nents, __len, dma); \
|
||||
})
|
||||
|
||||
#define kfifo_dma_in_prepare(fifo, sgl, nents, len) \
|
||||
kfifo_dma_in_prepare_mapped(fifo, sgl, nents, len, DMA_MAPPING_ERROR)
|
||||
|
||||
/**
|
||||
* kfifo_dma_in_finish - finish a DMA IN operation
|
||||
* @fifo: address of the fifo to be used
|
||||
* @len: number of bytes to received
|
||||
*
|
||||
* This macro finish a DMA IN operation. The in counter will be updated by
|
||||
* This macro finishes a DMA IN operation. The in counter will be updated by
|
||||
* the len parameter. No error checking will be done.
|
||||
*
|
||||
* Note that with only one concurrent reader and one concurrent
|
||||
@ -757,11 +769,12 @@ __kfifo_int_must_check_helper( \
|
||||
})
|
||||
|
||||
/**
|
||||
* kfifo_dma_out_prepare - setup a scatterlist for DMA output
|
||||
* kfifo_dma_out_prepare_mapped - setup a scatterlist for DMA output
|
||||
* @fifo: address of the fifo to be used
|
||||
* @sgl: pointer to the scatterlist array
|
||||
* @nents: number of entries in the scatterlist array
|
||||
* @len: number of elements to transfer
|
||||
* @dma: mapped dma address to fill into @sgl
|
||||
*
|
||||
* This macro fills a scatterlist for DMA output which at most @len bytes
|
||||
* to transfer.
|
||||
@ -771,7 +784,7 @@ __kfifo_int_must_check_helper( \
|
||||
* Note that with only one concurrent reader and one concurrent
|
||||
* writer, you don't need extra locking to use these macros.
|
||||
*/
|
||||
#define kfifo_dma_out_prepare(fifo, sgl, nents, len) \
|
||||
#define kfifo_dma_out_prepare_mapped(fifo, sgl, nents, len, dma) \
|
||||
({ \
|
||||
typeof((fifo) + 1) __tmp = (fifo); \
|
||||
struct scatterlist *__sgl = (sgl); \
|
||||
@ -780,32 +793,29 @@ __kfifo_int_must_check_helper( \
|
||||
const size_t __recsize = sizeof(*__tmp->rectype); \
|
||||
struct __kfifo *__kfifo = &__tmp->kfifo; \
|
||||
(__recsize) ? \
|
||||
__kfifo_dma_out_prepare_r(__kfifo, __sgl, __nents, __len, __recsize) : \
|
||||
__kfifo_dma_out_prepare(__kfifo, __sgl, __nents, __len); \
|
||||
__kfifo_dma_out_prepare_r(__kfifo, __sgl, __nents, __len, __recsize, \
|
||||
dma) : \
|
||||
__kfifo_dma_out_prepare(__kfifo, __sgl, __nents, __len, dma); \
|
||||
})
|
||||
|
||||
#define kfifo_dma_out_prepare(fifo, sgl, nents, len) \
|
||||
kfifo_dma_out_prepare_mapped(fifo, sgl, nents, len, DMA_MAPPING_ERROR)
|
||||
|
||||
/**
|
||||
* kfifo_dma_out_finish - finish a DMA OUT operation
|
||||
* @fifo: address of the fifo to be used
|
||||
* @len: number of bytes transferred
|
||||
*
|
||||
* This macro finish a DMA OUT operation. The out counter will be updated by
|
||||
* This macro finishes a DMA OUT operation. The out counter will be updated by
|
||||
* the len parameter. No error checking will be done.
|
||||
*
|
||||
* Note that with only one concurrent reader and one concurrent
|
||||
* writer, you don't need extra locking to use these macros.
|
||||
*/
|
||||
#define kfifo_dma_out_finish(fifo, len) \
|
||||
(void)({ \
|
||||
typeof((fifo) + 1) __tmp = (fifo); \
|
||||
unsigned int __len = (len); \
|
||||
const size_t __recsize = sizeof(*__tmp->rectype); \
|
||||
struct __kfifo *__kfifo = &__tmp->kfifo; \
|
||||
if (__recsize) \
|
||||
__kfifo_dma_out_finish_r(__kfifo, __recsize); \
|
||||
else \
|
||||
__kfifo->out += __len / sizeof(*__tmp->type); \
|
||||
})
|
||||
#define kfifo_dma_out_finish(fifo, len) do { \
|
||||
typeof((fifo) + 1) ___tmp = (fifo); \
|
||||
kfifo_skip_count(___tmp, (len) / sizeof(*___tmp->type)); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* kfifo_out_peek - gets some data from the fifo
|
||||
@ -813,7 +823,7 @@ __kfifo_int_must_check_helper( \
|
||||
* @buf: pointer to the storage buffer
|
||||
* @n: max. number of elements to get
|
||||
*
|
||||
* This macro get the data from the fifo and return the numbers of elements
|
||||
* This macro gets the data from the fifo and returns the numbers of elements
|
||||
* copied. The data is not removed from the fifo.
|
||||
*
|
||||
* Note that with only one concurrent reader and one concurrent
|
||||
@ -833,6 +843,63 @@ __kfifo_uint_must_check_helper( \
|
||||
}) \
|
||||
)
|
||||
|
||||
/**
|
||||
* kfifo_out_linear - gets a tail of/offset to available data
|
||||
* @fifo: address of the fifo to be used
|
||||
* @tail: pointer to an unsigned int to store the value of tail
|
||||
* @n: max. number of elements to point at
|
||||
*
|
||||
* This macro obtains the offset (tail) to the available data in the fifo
|
||||
* buffer and returns the
|
||||
* numbers of elements available. It returns the available count till the end
|
||||
* of data or till the end of the buffer. So that it can be used for linear
|
||||
* data processing (like memcpy() of (@fifo->data + @tail) with count
|
||||
* returned).
|
||||
*
|
||||
* Note that with only one concurrent reader and one concurrent
|
||||
* writer, you don't need extra locking to use these macro.
|
||||
*/
|
||||
#define kfifo_out_linear(fifo, tail, n) \
|
||||
__kfifo_uint_must_check_helper( \
|
||||
({ \
|
||||
typeof((fifo) + 1) __tmp = (fifo); \
|
||||
unsigned int *__tail = (tail); \
|
||||
unsigned long __n = (n); \
|
||||
const size_t __recsize = sizeof(*__tmp->rectype); \
|
||||
struct __kfifo *__kfifo = &__tmp->kfifo; \
|
||||
(__recsize) ? \
|
||||
__kfifo_out_linear_r(__kfifo, __tail, __n, __recsize) : \
|
||||
__kfifo_out_linear(__kfifo, __tail, __n); \
|
||||
}) \
|
||||
)
|
||||
|
||||
/**
|
||||
* kfifo_out_linear_ptr - gets a pointer to the available data
|
||||
* @fifo: address of the fifo to be used
|
||||
* @ptr: pointer to data to store the pointer to tail
|
||||
* @n: max. number of elements to point at
|
||||
*
|
||||
* Similarly to kfifo_out_linear(), this macro obtains the pointer to the
|
||||
* available data in the fifo buffer and returns the numbers of elements
|
||||
* available. It returns the available count till the end of available data or
|
||||
* till the end of the buffer. So that it can be used for linear data
|
||||
* processing (like memcpy() of @ptr with count returned).
|
||||
*
|
||||
* Note that with only one concurrent reader and one concurrent
|
||||
* writer, you don't need extra locking to use these macro.
|
||||
*/
|
||||
#define kfifo_out_linear_ptr(fifo, ptr, n) \
|
||||
__kfifo_uint_must_check_helper( \
|
||||
({ \
|
||||
typeof((fifo) + 1) ___tmp = (fifo); \
|
||||
unsigned int ___tail; \
|
||||
unsigned int ___n = kfifo_out_linear(___tmp, &___tail, (n)); \
|
||||
*(ptr) = ___tmp->kfifo.data + ___tail * kfifo_esize(___tmp); \
|
||||
___n; \
|
||||
}) \
|
||||
)
|
||||
|
||||
|
||||
extern int __kfifo_alloc(struct __kfifo *fifo, unsigned int size,
|
||||
size_t esize, gfp_t gfp_mask);
|
||||
|
||||
@ -854,14 +921,17 @@ extern int __kfifo_to_user(struct __kfifo *fifo,
|
||||
void __user *to, unsigned long len, unsigned int *copied);
|
||||
|
||||
extern unsigned int __kfifo_dma_in_prepare(struct __kfifo *fifo,
|
||||
struct scatterlist *sgl, int nents, unsigned int len);
|
||||
struct scatterlist *sgl, int nents, unsigned int len, dma_addr_t dma);
|
||||
|
||||
extern unsigned int __kfifo_dma_out_prepare(struct __kfifo *fifo,
|
||||
struct scatterlist *sgl, int nents, unsigned int len);
|
||||
struct scatterlist *sgl, int nents, unsigned int len, dma_addr_t dma);
|
||||
|
||||
extern unsigned int __kfifo_out_peek(struct __kfifo *fifo,
|
||||
void *buf, unsigned int len);
|
||||
|
||||
extern unsigned int __kfifo_out_linear(struct __kfifo *fifo,
|
||||
unsigned int *tail, unsigned int n);
|
||||
|
||||
extern unsigned int __kfifo_in_r(struct __kfifo *fifo,
|
||||
const void *buf, unsigned int len, size_t recsize);
|
||||
|
||||
@ -876,15 +946,15 @@ extern int __kfifo_to_user_r(struct __kfifo *fifo, void __user *to,
|
||||
unsigned long len, unsigned int *copied, size_t recsize);
|
||||
|
||||
extern unsigned int __kfifo_dma_in_prepare_r(struct __kfifo *fifo,
|
||||
struct scatterlist *sgl, int nents, unsigned int len, size_t recsize);
|
||||
struct scatterlist *sgl, int nents, unsigned int len, size_t recsize,
|
||||
dma_addr_t dma);
|
||||
|
||||
extern void __kfifo_dma_in_finish_r(struct __kfifo *fifo,
|
||||
unsigned int len, size_t recsize);
|
||||
|
||||
extern unsigned int __kfifo_dma_out_prepare_r(struct __kfifo *fifo,
|
||||
struct scatterlist *sgl, int nents, unsigned int len, size_t recsize);
|
||||
|
||||
extern void __kfifo_dma_out_finish_r(struct __kfifo *fifo, size_t recsize);
|
||||
struct scatterlist *sgl, int nents, unsigned int len, size_t recsize,
|
||||
dma_addr_t dma);
|
||||
|
||||
extern unsigned int __kfifo_len_r(struct __kfifo *fifo, size_t recsize);
|
||||
|
||||
@ -893,6 +963,9 @@ extern void __kfifo_skip_r(struct __kfifo *fifo, size_t recsize);
|
||||
extern unsigned int __kfifo_out_peek_r(struct __kfifo *fifo,
|
||||
void *buf, unsigned int len, size_t recsize);
|
||||
|
||||
extern unsigned int __kfifo_out_linear_r(struct __kfifo *fifo,
|
||||
unsigned int *tail, unsigned int n, size_t recsize);
|
||||
|
||||
extern unsigned int __kfifo_max_r(unsigned int len, size_t recsize);
|
||||
|
||||
#endif
|
||||
|
@ -469,6 +469,8 @@ int compare_pnp_id(struct pnp_id *pos, const char *id);
|
||||
int pnp_register_driver(struct pnp_driver *drv);
|
||||
void pnp_unregister_driver(struct pnp_driver *drv);
|
||||
|
||||
#define dev_is_pnp(d) ((d)->bus == &pnp_bus_type)
|
||||
|
||||
#else
|
||||
|
||||
/* device management */
|
||||
@ -500,6 +502,8 @@ static inline int compare_pnp_id(struct pnp_id *pos, const char *id) { return -E
|
||||
static inline int pnp_register_driver(struct pnp_driver *drv) { return -ENODEV; }
|
||||
static inline void pnp_unregister_driver(struct pnp_driver *drv) { }
|
||||
|
||||
#define dev_is_pnp(d) false
|
||||
|
||||
#endif /* CONFIG_PNP */
|
||||
|
||||
/**
|
||||
|
@ -60,6 +60,9 @@ static inline const char *printk_skip_headers(const char *buffer)
|
||||
#define CONSOLE_LOGLEVEL_DEFAULT CONFIG_CONSOLE_LOGLEVEL_DEFAULT
|
||||
#define CONSOLE_LOGLEVEL_QUIET CONFIG_CONSOLE_LOGLEVEL_QUIET
|
||||
|
||||
int add_preferred_console_match(const char *match, const char *name,
|
||||
const short idx);
|
||||
|
||||
extern int console_printk[];
|
||||
|
||||
#define console_loglevel (console_printk[0])
|
||||
@ -192,6 +195,7 @@ void show_regs_print_info(const char *log_lvl);
|
||||
extern asmlinkage void dump_stack_lvl(const char *log_lvl) __cold;
|
||||
extern asmlinkage void dump_stack(void) __cold;
|
||||
void printk_trigger_flush(void);
|
||||
void console_replay_all(void);
|
||||
#else
|
||||
static inline __printf(1, 0)
|
||||
int vprintk(const char *s, va_list args)
|
||||
@ -271,6 +275,9 @@ static inline void dump_stack(void)
|
||||
static inline void printk_trigger_flush(void)
|
||||
{
|
||||
}
|
||||
static inline void console_replay_all(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
bool this_cpu_in_panic(void);
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/circ_buf.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/tty.h>
|
||||
@ -699,7 +698,6 @@ struct uart_state {
|
||||
struct tty_port port;
|
||||
|
||||
enum uart_pm_state pm_state;
|
||||
struct circ_buf xmit;
|
||||
|
||||
atomic_t refcount;
|
||||
wait_queue_head_t remove_wait;
|
||||
@ -723,12 +721,35 @@ struct uart_state {
|
||||
*/
|
||||
static inline void uart_xmit_advance(struct uart_port *up, unsigned int chars)
|
||||
{
|
||||
struct circ_buf *xmit = &up->state->xmit;
|
||||
struct tty_port *tport = &up->state->port;
|
||||
|
||||
xmit->tail = (xmit->tail + chars) & (UART_XMIT_SIZE - 1);
|
||||
kfifo_skip_count(&tport->xmit_fifo, chars);
|
||||
up->icount.tx += chars;
|
||||
}
|
||||
|
||||
static inline unsigned int uart_fifo_out(struct uart_port *up,
|
||||
unsigned char *buf, unsigned int chars)
|
||||
{
|
||||
struct tty_port *tport = &up->state->port;
|
||||
|
||||
chars = kfifo_out(&tport->xmit_fifo, buf, chars);
|
||||
up->icount.tx += chars;
|
||||
|
||||
return chars;
|
||||
}
|
||||
|
||||
static inline unsigned int uart_fifo_get(struct uart_port *up,
|
||||
unsigned char *ch)
|
||||
{
|
||||
struct tty_port *tport = &up->state->port;
|
||||
unsigned int chars;
|
||||
|
||||
chars = kfifo_get(&tport->xmit_fifo, ch);
|
||||
up->icount.tx += chars;
|
||||
|
||||
return chars;
|
||||
}
|
||||
|
||||
struct module;
|
||||
struct tty_driver;
|
||||
|
||||
@ -764,7 +785,7 @@ enum UART_TX_FLAGS {
|
||||
for_test, for_post) \
|
||||
({ \
|
||||
struct uart_port *__port = (uport); \
|
||||
struct circ_buf *xmit = &__port->state->xmit; \
|
||||
struct tty_port *__tport = &__port->state->port; \
|
||||
unsigned int pending; \
|
||||
\
|
||||
for (; (for_test) && (tx_ready); (for_post), __port->icount.tx++) { \
|
||||
@ -775,17 +796,18 @@ enum UART_TX_FLAGS {
|
||||
continue; \
|
||||
} \
|
||||
\
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(__port)) \
|
||||
if (uart_tx_stopped(__port)) \
|
||||
break; \
|
||||
\
|
||||
if (!kfifo_get(&__tport->xmit_fifo, &(ch))) \
|
||||
break; \
|
||||
\
|
||||
(ch) = xmit->buf[xmit->tail]; \
|
||||
(put_char); \
|
||||
xmit->tail = (xmit->tail + 1) % UART_XMIT_SIZE; \
|
||||
} \
|
||||
\
|
||||
(tx_done); \
|
||||
\
|
||||
pending = uart_circ_chars_pending(xmit); \
|
||||
pending = kfifo_len(&__tport->xmit_fifo); \
|
||||
if (pending < WAKEUP_CHARS) { \
|
||||
uart_write_wakeup(__port); \
|
||||
\
|
||||
@ -974,15 +996,6 @@ bool uart_match_port(const struct uart_port *port1,
|
||||
int uart_suspend_port(struct uart_driver *reg, struct uart_port *port);
|
||||
int uart_resume_port(struct uart_driver *reg, struct uart_port *port);
|
||||
|
||||
#define uart_circ_empty(circ) ((circ)->head == (circ)->tail)
|
||||
#define uart_circ_clear(circ) ((circ)->head = (circ)->tail = 0)
|
||||
|
||||
#define uart_circ_chars_pending(circ) \
|
||||
(CIRC_CNT((circ)->head, (circ)->tail, UART_XMIT_SIZE))
|
||||
|
||||
#define uart_circ_chars_free(circ) \
|
||||
(CIRC_SPACE((circ)->head, (circ)->tail, UART_XMIT_SIZE))
|
||||
|
||||
static inline int uart_tx_stopped(struct uart_port *port)
|
||||
{
|
||||
struct tty_struct *tty = port->state->port.tty;
|
||||
|
@ -1,48 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2007 Christian Pellegrin
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _LINUX_SERIAL_MAX3100_H
|
||||
#define _LINUX_SERIAL_MAX3100_H 1
|
||||
|
||||
|
||||
/**
|
||||
* struct plat_max3100 - MAX3100 SPI UART platform data
|
||||
* @loopback: force MAX3100 in loopback
|
||||
* @crystal: 1 for 3.6864 Mhz, 0 for 1.8432
|
||||
* @max3100_hw_suspend: MAX3100 has a shutdown pin. This is a hook
|
||||
* called on suspend and resume to activate it.
|
||||
* @poll_time: poll time for CTS signal in ms, 0 disables (so no hw
|
||||
* flow ctrl is possible but you have less CPU usage)
|
||||
*
|
||||
* You should use this structure in your machine description to specify
|
||||
* how the MAX3100 is connected. Example:
|
||||
*
|
||||
* static struct plat_max3100 max3100_plat_data = {
|
||||
* .loopback = 0,
|
||||
* .crystal = 0,
|
||||
* .poll_time = 100,
|
||||
* };
|
||||
*
|
||||
* static struct spi_board_info spi_board_info[] = {
|
||||
* {
|
||||
* .modalias = "max3100",
|
||||
* .platform_data = &max3100_plat_data,
|
||||
* .irq = IRQ_EINT12,
|
||||
* .max_speed_hz = 5*1000*1000,
|
||||
* .chip_select = 0,
|
||||
* },
|
||||
* };
|
||||
*
|
||||
**/
|
||||
struct plat_max3100 {
|
||||
int loopback;
|
||||
int crystal;
|
||||
void (*max3100_hw_suspend) (int suspend);
|
||||
int poll_time;
|
||||
};
|
||||
|
||||
#endif
|
@ -154,6 +154,13 @@ struct serial_struct;
|
||||
*
|
||||
* Optional. Called under the @tty->termios_rwsem. May sleep.
|
||||
*
|
||||
* @ldisc_ok: ``int ()(struct tty_struct *tty, int ldisc)``
|
||||
*
|
||||
* This routine allows the @tty driver to decide if it can deal
|
||||
* with a particular @ldisc.
|
||||
*
|
||||
* Optional. Called under the @tty->ldisc_sem and @tty->termios_rwsem.
|
||||
*
|
||||
* @set_ldisc: ``void ()(struct tty_struct *tty)``
|
||||
*
|
||||
* This routine allows the @tty driver to be notified when the device's
|
||||
@ -372,6 +379,7 @@ struct tty_operations {
|
||||
void (*hangup)(struct tty_struct *tty);
|
||||
int (*break_ctl)(struct tty_struct *tty, int state);
|
||||
void (*flush_buffer)(struct tty_struct *tty);
|
||||
int (*ldisc_ok)(struct tty_struct *tty, int ldisc);
|
||||
void (*set_ldisc)(struct tty_struct *tty);
|
||||
void (*wait_until_sent)(struct tty_struct *tty, int timeout);
|
||||
void (*send_xchar)(struct tty_struct *tty, u8 ch);
|
||||
|
@ -5,60 +5,61 @@
|
||||
#include <linux/compiler.h>
|
||||
|
||||
/* 0x4B is 'K', to avoid collision with termios and vt */
|
||||
#define KD_IOCTL_BASE 'K'
|
||||
|
||||
#define GIO_FONT 0x4B60 /* gets font in expanded form */
|
||||
#define PIO_FONT 0x4B61 /* use font in expanded form */
|
||||
#define GIO_FONT _IO(KD_IOCTL_BASE, 0x60) /* gets font in expanded form */
|
||||
#define PIO_FONT _IO(KD_IOCTL_BASE, 0x61) /* use font in expanded form */
|
||||
|
||||
#define GIO_FONTX 0x4B6B /* get font using struct consolefontdesc */
|
||||
#define PIO_FONTX 0x4B6C /* set font using struct consolefontdesc */
|
||||
#define GIO_FONTX _IO(KD_IOCTL_BASE, 0x6B) /* get font using struct consolefontdesc */
|
||||
#define PIO_FONTX _IO(KD_IOCTL_BASE, 0x6C) /* set font using struct consolefontdesc */
|
||||
struct consolefontdesc {
|
||||
unsigned short charcount; /* characters in font (256 or 512) */
|
||||
unsigned short charheight; /* scan lines per character (1-32) */
|
||||
char __user *chardata; /* font data in expanded form */
|
||||
};
|
||||
|
||||
#define PIO_FONTRESET 0x4B6D /* reset to default font */
|
||||
#define PIO_FONTRESET _IO(KD_IOCTL_BASE, 0x6D) /* reset to default font */
|
||||
|
||||
#define GIO_CMAP 0x4B70 /* gets colour palette on VGA+ */
|
||||
#define PIO_CMAP 0x4B71 /* sets colour palette on VGA+ */
|
||||
#define GIO_CMAP _IO(KD_IOCTL_BASE, 0x70) /* gets colour palette on VGA+ */
|
||||
#define PIO_CMAP _IO(KD_IOCTL_BASE, 0x71) /* sets colour palette on VGA+ */
|
||||
|
||||
#define KIOCSOUND 0x4B2F /* start sound generation (0 for off) */
|
||||
#define KDMKTONE 0x4B30 /* generate tone */
|
||||
#define KIOCSOUND _IO(KD_IOCTL_BASE, 0x2F) /* start sound generation (0 for off) */
|
||||
#define KDMKTONE _IO(KD_IOCTL_BASE, 0x30) /* generate tone */
|
||||
|
||||
#define KDGETLED 0x4B31 /* return current led state */
|
||||
#define KDSETLED 0x4B32 /* set led state [lights, not flags] */
|
||||
#define KDGETLED _IO(KD_IOCTL_BASE, 0x31) /* return current led state */
|
||||
#define KDSETLED _IO(KD_IOCTL_BASE, 0x32) /* set led state [lights, not flags] */
|
||||
#define LED_SCR 0x01 /* scroll lock led */
|
||||
#define LED_NUM 0x02 /* num lock led */
|
||||
#define LED_CAP 0x04 /* caps lock led */
|
||||
|
||||
#define KDGKBTYPE 0x4B33 /* get keyboard type */
|
||||
#define KDGKBTYPE _IO(KD_IOCTL_BASE, 0x33) /* get keyboard type */
|
||||
#define KB_84 0x01
|
||||
#define KB_101 0x02 /* this is what we always answer */
|
||||
#define KB_OTHER 0x03
|
||||
|
||||
#define KDADDIO 0x4B34 /* add i/o port as valid */
|
||||
#define KDDELIO 0x4B35 /* del i/o port as valid */
|
||||
#define KDENABIO 0x4B36 /* enable i/o to video board */
|
||||
#define KDDISABIO 0x4B37 /* disable i/o to video board */
|
||||
#define KDADDIO _IO(KD_IOCTL_BASE, 0x34) /* add i/o port as valid */
|
||||
#define KDDELIO _IO(KD_IOCTL_BASE, 0x35) /* del i/o port as valid */
|
||||
#define KDENABIO _IO(KD_IOCTL_BASE, 0x36) /* enable i/o to video board */
|
||||
#define KDDISABIO _IO(KD_IOCTL_BASE, 0x37) /* disable i/o to video board */
|
||||
|
||||
#define KDSETMODE 0x4B3A /* set text/graphics mode */
|
||||
#define KDSETMODE _IO(KD_IOCTL_BASE, 0x3A) /* set text/graphics mode */
|
||||
#define KD_TEXT 0x00
|
||||
#define KD_GRAPHICS 0x01
|
||||
#define KD_TEXT0 0x02 /* obsolete */
|
||||
#define KD_TEXT1 0x03 /* obsolete */
|
||||
#define KDGETMODE 0x4B3B /* get current mode */
|
||||
#define KDGETMODE _IO(KD_IOCTL_BASE, 0x3B) /* get current mode */
|
||||
|
||||
#define KDMAPDISP 0x4B3C /* map display into address space */
|
||||
#define KDUNMAPDISP 0x4B3D /* unmap display from address space */
|
||||
#define KDMAPDISP _IO(KD_IOCTL_BASE, 0x3C) /* map display into address space */
|
||||
#define KDUNMAPDISP _IO(KD_IOCTL_BASE, 0x3D) /* unmap display from address space */
|
||||
|
||||
typedef char scrnmap_t;
|
||||
#define E_TABSZ 256
|
||||
#define GIO_SCRNMAP 0x4B40 /* get screen mapping from kernel */
|
||||
#define PIO_SCRNMAP 0x4B41 /* put screen mapping table in kernel */
|
||||
#define GIO_UNISCRNMAP 0x4B69 /* get full Unicode screen mapping */
|
||||
#define PIO_UNISCRNMAP 0x4B6A /* set full Unicode screen mapping */
|
||||
#define GIO_SCRNMAP _IO(KD_IOCTL_BASE, 0x40) /* get screen mapping from kernel */
|
||||
#define PIO_SCRNMAP _IO(KD_IOCTL_BASE, 0x41) /* put screen mapping table in kernel */
|
||||
#define GIO_UNISCRNMAP _IO(KD_IOCTL_BASE, 0x69) /* get full Unicode screen mapping */
|
||||
#define PIO_UNISCRNMAP _IO(KD_IOCTL_BASE, 0x6A) /* set full Unicode screen mapping */
|
||||
|
||||
#define GIO_UNIMAP 0x4B66 /* get unicode-to-font mapping from kernel */
|
||||
#define GIO_UNIMAP _IO(KD_IOCTL_BASE, 0x66) /* get unicode-to-font mapping from kernel */
|
||||
struct unipair {
|
||||
unsigned short unicode;
|
||||
unsigned short fontpos;
|
||||
@ -67,8 +68,8 @@ struct unimapdesc {
|
||||
unsigned short entry_ct;
|
||||
struct unipair __user *entries;
|
||||
};
|
||||
#define PIO_UNIMAP 0x4B67 /* put unicode-to-font mapping in kernel */
|
||||
#define PIO_UNIMAPCLR 0x4B68 /* clear table, possibly advise hash algorithm */
|
||||
#define PIO_UNIMAP _IO(KD_IOCTL_BASE, 0x67) /* put unicode-to-font mapping in kernel */
|
||||
#define PIO_UNIMAPCLR _IO(KD_IOCTL_BASE, 0x68) /* clear table, possibly advise hash algorithm */
|
||||
struct unimapinit {
|
||||
unsigned short advised_hashsize; /* 0 if no opinion */
|
||||
unsigned short advised_hashstep; /* 0 if no opinion */
|
||||
@ -83,19 +84,19 @@ struct unimapinit {
|
||||
#define K_MEDIUMRAW 0x02
|
||||
#define K_UNICODE 0x03
|
||||
#define K_OFF 0x04
|
||||
#define KDGKBMODE 0x4B44 /* gets current keyboard mode */
|
||||
#define KDSKBMODE 0x4B45 /* sets current keyboard mode */
|
||||
#define KDGKBMODE _IO(KD_IOCTL_BASE, 0x44) /* gets current keyboard mode */
|
||||
#define KDSKBMODE _IO(KD_IOCTL_BASE, 0x45) /* sets current keyboard mode */
|
||||
|
||||
#define K_METABIT 0x03
|
||||
#define K_ESCPREFIX 0x04
|
||||
#define KDGKBMETA 0x4B62 /* gets meta key handling mode */
|
||||
#define KDSKBMETA 0x4B63 /* sets meta key handling mode */
|
||||
#define KDGKBMETA _IO(KD_IOCTL_BASE, 0x62) /* gets meta key handling mode */
|
||||
#define KDSKBMETA _IO(KD_IOCTL_BASE, 0x63) /* sets meta key handling mode */
|
||||
|
||||
#define K_SCROLLLOCK 0x01
|
||||
#define K_NUMLOCK 0x02
|
||||
#define K_CAPSLOCK 0x04
|
||||
#define KDGKBLED 0x4B64 /* get led flags (not lights) */
|
||||
#define KDSKBLED 0x4B65 /* set led flags (not lights) */
|
||||
#define KDGKBLED _IO(KD_IOCTL_BASE, 0x64) /* get led flags (not lights) */
|
||||
#define KDSKBLED _IO(KD_IOCTL_BASE, 0x65) /* set led flags (not lights) */
|
||||
|
||||
struct kbentry {
|
||||
unsigned char kb_table;
|
||||
@ -107,15 +108,15 @@ struct kbentry {
|
||||
#define K_ALTTAB 0x02
|
||||
#define K_ALTSHIFTTAB 0x03
|
||||
|
||||
#define KDGKBENT 0x4B46 /* gets one entry in translation table */
|
||||
#define KDSKBENT 0x4B47 /* sets one entry in translation table */
|
||||
#define KDGKBENT _IO(KD_IOCTL_BASE, 0x46) /* gets one entry in translation table */
|
||||
#define KDSKBENT _IO(KD_IOCTL_BASE, 0x47) /* sets one entry in translation table */
|
||||
|
||||
struct kbsentry {
|
||||
unsigned char kb_func;
|
||||
unsigned char kb_string[512];
|
||||
};
|
||||
#define KDGKBSENT 0x4B48 /* gets one function key string entry */
|
||||
#define KDSKBSENT 0x4B49 /* sets one function key string entry */
|
||||
#define KDGKBSENT _IO(KD_IOCTL_BASE, 0x48) /* gets one function key string entry */
|
||||
#define KDSKBSENT _IO(KD_IOCTL_BASE, 0x49) /* sets one function key string entry */
|
||||
|
||||
struct kbdiacr {
|
||||
unsigned char diacr, base, result;
|
||||
@ -124,8 +125,8 @@ struct kbdiacrs {
|
||||
unsigned int kb_cnt; /* number of entries in following array */
|
||||
struct kbdiacr kbdiacr[256]; /* MAX_DIACR from keyboard.h */
|
||||
};
|
||||
#define KDGKBDIACR 0x4B4A /* read kernel accent table */
|
||||
#define KDSKBDIACR 0x4B4B /* write kernel accent table */
|
||||
#define KDGKBDIACR _IO(KD_IOCTL_BASE, 0x4A) /* read kernel accent table */
|
||||
#define KDSKBDIACR _IO(KD_IOCTL_BASE, 0x4B) /* write kernel accent table */
|
||||
|
||||
struct kbdiacruc {
|
||||
unsigned int diacr, base, result;
|
||||
@ -134,16 +135,16 @@ struct kbdiacrsuc {
|
||||
unsigned int kb_cnt; /* number of entries in following array */
|
||||
struct kbdiacruc kbdiacruc[256]; /* MAX_DIACR from keyboard.h */
|
||||
};
|
||||
#define KDGKBDIACRUC 0x4BFA /* read kernel accent table - UCS */
|
||||
#define KDSKBDIACRUC 0x4BFB /* write kernel accent table - UCS */
|
||||
#define KDGKBDIACRUC _IO(KD_IOCTL_BASE, 0xFA) /* read kernel accent table - UCS */
|
||||
#define KDSKBDIACRUC _IO(KD_IOCTL_BASE, 0xFB) /* write kernel accent table - UCS */
|
||||
|
||||
struct kbkeycode {
|
||||
unsigned int scancode, keycode;
|
||||
};
|
||||
#define KDGETKEYCODE 0x4B4C /* read kernel keycode table entry */
|
||||
#define KDSETKEYCODE 0x4B4D /* write kernel keycode table entry */
|
||||
#define KDGETKEYCODE _IO(KD_IOCTL_BASE, 0x4C) /* read kernel keycode table entry */
|
||||
#define KDSETKEYCODE _IO(KD_IOCTL_BASE, 0x4D) /* write kernel keycode table entry */
|
||||
|
||||
#define KDSIGACCEPT 0x4B4E /* accept kbd generated signals */
|
||||
#define KDSIGACCEPT _IO(KD_IOCTL_BASE, 0x4E) /* accept kbd generated signals */
|
||||
|
||||
struct kbd_repeat {
|
||||
int delay; /* in msec; <= 0: don't change */
|
||||
@ -151,10 +152,11 @@ struct kbd_repeat {
|
||||
/* earlier this field was misnamed "rate" */
|
||||
};
|
||||
|
||||
#define KDKBDREP 0x4B52 /* set keyboard delay/repeat rate;
|
||||
* actually used values are returned */
|
||||
#define KDKBDREP _IO(KD_IOCTL_BASE, 0x52) /* set keyboard delay/repeat rate;
|
||||
* actually used values are returned
|
||||
*/
|
||||
|
||||
#define KDFONTOP 0x4B72 /* font operations */
|
||||
#define KDFONTOP _IO(KD_IOCTL_BASE, 0x72) /* font operations */
|
||||
|
||||
struct console_font_op {
|
||||
unsigned int op; /* operation code KD_FONT_OP_* */
|
||||
|
@ -1,5 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
obj-y = printk.o
|
||||
obj-y = printk.o conopt.o
|
||||
obj-$(CONFIG_PRINTK) += printk_safe.o nbcon.o
|
||||
obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) += braille.o
|
||||
obj-$(CONFIG_PRINTK_INDEX) += index.o
|
||||
|
146
kernel/printk/conopt.c
Normal file
146
kernel/printk/conopt.c
Normal file
@ -0,0 +1,146 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Kernel command line console options for hardware based addressing
|
||||
*
|
||||
* Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/
|
||||
* Author: Tony Lindgren <tony@atomide.com>
|
||||
*/
|
||||
|
||||
#include <linux/console.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/errno.h>
|
||||
|
||||
#include "console_cmdline.h"
|
||||
|
||||
/*
|
||||
* Allow longer DEVNAME:0.0 style console naming such as abcd0000.serial:0.0
|
||||
* in addition to the legacy ttyS0 style naming.
|
||||
*/
|
||||
#define CONSOLE_NAME_MAX 32
|
||||
|
||||
#define CONSOLE_OPT_MAX 16
|
||||
#define CONSOLE_BRL_OPT_MAX 16
|
||||
|
||||
struct console_option {
|
||||
char name[CONSOLE_NAME_MAX];
|
||||
char opt[CONSOLE_OPT_MAX];
|
||||
char brl_opt[CONSOLE_BRL_OPT_MAX];
|
||||
u8 has_brl_opt:1;
|
||||
};
|
||||
|
||||
/* Updated only at console_setup() time, no locking needed */
|
||||
static struct console_option conopt[MAX_CMDLINECONSOLES];
|
||||
|
||||
/**
|
||||
* console_opt_save - Saves kernel command line console option for driver use
|
||||
* @str: Kernel command line console name and option
|
||||
* @brl_opt: Braille console options
|
||||
*
|
||||
* Saves a kernel command line console option for driver subsystems to use for
|
||||
* adding a preferred console during init. Called from console_setup() only.
|
||||
*
|
||||
* Return: 0 on success, negative error code on failure.
|
||||
*/
|
||||
int __init console_opt_save(const char *str, const char *brl_opt)
|
||||
{
|
||||
struct console_option *con;
|
||||
size_t namelen, optlen;
|
||||
const char *opt;
|
||||
int i;
|
||||
|
||||
namelen = strcspn(str, ",");
|
||||
if (namelen == 0 || namelen >= CONSOLE_NAME_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
opt = str + namelen;
|
||||
if (*opt == ',')
|
||||
opt++;
|
||||
|
||||
optlen = strlen(opt);
|
||||
if (optlen >= CONSOLE_OPT_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < MAX_CMDLINECONSOLES; i++) {
|
||||
con = &conopt[i];
|
||||
|
||||
if (con->name[0]) {
|
||||
if (!strncmp(str, con->name, namelen))
|
||||
return 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* The name isn't terminated, only opt is. Empty opt is fine,
|
||||
* but brl_opt can be either empty or NULL. For more info, see
|
||||
* _braille_console_setup().
|
||||
*/
|
||||
strscpy(con->name, str, namelen + 1);
|
||||
strscpy(con->opt, opt, CONSOLE_OPT_MAX);
|
||||
if (brl_opt) {
|
||||
strscpy(con->brl_opt, brl_opt, CONSOLE_BRL_OPT_MAX);
|
||||
con->has_brl_opt = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static struct console_option *console_opt_find(const char *name)
|
||||
{
|
||||
struct console_option *con;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_CMDLINECONSOLES; i++) {
|
||||
con = &conopt[i];
|
||||
if (!strcmp(name, con->name))
|
||||
return con;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* add_preferred_console_match - Adds a preferred console if a match is found
|
||||
* @match: Expected console on kernel command line, such as console=DEVNAME:0.0
|
||||
* @name: Name of the console character device to add such as ttyS
|
||||
* @idx: Index for the console
|
||||
*
|
||||
* Allows driver subsystems to add a console after translating the command
|
||||
* line name to the character device name used for the console. Options are
|
||||
* added automatically based on the kernel command line. Duplicate preferred
|
||||
* consoles are ignored by __add_preferred_console().
|
||||
*
|
||||
* Return: 0 on success, negative error code on failure.
|
||||
*/
|
||||
int add_preferred_console_match(const char *match, const char *name,
|
||||
const short idx)
|
||||
{
|
||||
struct console_option *con;
|
||||
char *brl_opt = NULL;
|
||||
|
||||
if (!match || !strlen(match) || !name || !strlen(name) ||
|
||||
idx < 0)
|
||||
return -EINVAL;
|
||||
|
||||
con = console_opt_find(match);
|
||||
if (!con)
|
||||
return -ENOENT;
|
||||
|
||||
/*
|
||||
* See __add_preferred_console(). It checks for NULL brl_options to set
|
||||
* the preferred_console flag. Empty brl_opt instead of NULL leads into
|
||||
* the preferred_console flag not set, and CON_CONSDEV not being set,
|
||||
* and the boot console won't get disabled at the end of console_setup().
|
||||
*/
|
||||
if (con->has_brl_opt)
|
||||
brl_opt = con->brl_opt;
|
||||
|
||||
console_opt_add_preferred_console(name, idx, con->opt, brl_opt);
|
||||
|
||||
return 0;
|
||||
}
|
@ -2,6 +2,12 @@
|
||||
#ifndef _CONSOLE_CMDLINE_H
|
||||
#define _CONSOLE_CMDLINE_H
|
||||
|
||||
#define MAX_CMDLINECONSOLES 8
|
||||
|
||||
int console_opt_save(const char *str, const char *brl_opt);
|
||||
int console_opt_add_preferred_console(const char *name, const short idx,
|
||||
char *options, char *brl_options);
|
||||
|
||||
struct console_cmdline
|
||||
{
|
||||
char name[16]; /* Name of the driver */
|
||||
|
@ -383,9 +383,6 @@ static int console_locked;
|
||||
/*
|
||||
* Array of consoles built from command line options (console=)
|
||||
*/
|
||||
|
||||
#define MAX_CMDLINECONSOLES 8
|
||||
|
||||
static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES];
|
||||
|
||||
static int preferred_console = -1;
|
||||
@ -2503,6 +2500,17 @@ static int __init console_setup(char *str)
|
||||
if (_braille_console_setup(&str, &brl_options))
|
||||
return 1;
|
||||
|
||||
/* Save the console for driver subsystem use */
|
||||
if (console_opt_save(str, brl_options))
|
||||
return 1;
|
||||
|
||||
/* Flag register_console() to not call try_enable_default_console() */
|
||||
console_set_on_cmdline = 1;
|
||||
|
||||
/* Don't attempt to parse a DEVNAME:0.0 style console */
|
||||
if (strchr(str, ':'))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Decode str into name, index, options.
|
||||
*/
|
||||
@ -2533,6 +2541,13 @@ static int __init console_setup(char *str)
|
||||
}
|
||||
__setup("console=", console_setup);
|
||||
|
||||
/* Only called from add_preferred_console_match() */
|
||||
int console_opt_add_preferred_console(const char *name, const short idx,
|
||||
char *options, char *brl_options)
|
||||
{
|
||||
return __add_preferred_console(name, idx, options, brl_options, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* add_preferred_console - add a device to the list of preferred consoles.
|
||||
* @name: device name
|
||||
@ -3146,6 +3161,40 @@ void console_unblank(void)
|
||||
pr_flush(1000, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Rewind all consoles to the oldest available record.
|
||||
*
|
||||
* IMPORTANT: The function is safe only when called under
|
||||
* console_lock(). It is not enforced because
|
||||
* it is used as a best effort in panic().
|
||||
*/
|
||||
static void __console_rewind_all(void)
|
||||
{
|
||||
struct console *c;
|
||||
short flags;
|
||||
int cookie;
|
||||
u64 seq;
|
||||
|
||||
seq = prb_first_valid_seq(prb);
|
||||
|
||||
cookie = console_srcu_read_lock();
|
||||
for_each_console_srcu(c) {
|
||||
flags = console_srcu_read_flags(c);
|
||||
|
||||
if (flags & CON_NBCON) {
|
||||
nbcon_seq_force(c, seq);
|
||||
} else {
|
||||
/*
|
||||
* This assignment is safe only when called under
|
||||
* console_lock(). On panic, legacy consoles are
|
||||
* only best effort.
|
||||
*/
|
||||
c->seq = seq;
|
||||
}
|
||||
}
|
||||
console_srcu_read_unlock(cookie);
|
||||
}
|
||||
|
||||
/**
|
||||
* console_flush_on_panic - flush console content on panic
|
||||
* @mode: flush all messages in buffer or just the pending ones
|
||||
@ -3174,30 +3223,8 @@ void console_flush_on_panic(enum con_flush_mode mode)
|
||||
*/
|
||||
console_may_schedule = 0;
|
||||
|
||||
if (mode == CONSOLE_REPLAY_ALL) {
|
||||
struct console *c;
|
||||
short flags;
|
||||
int cookie;
|
||||
u64 seq;
|
||||
|
||||
seq = prb_first_valid_seq(prb);
|
||||
|
||||
cookie = console_srcu_read_lock();
|
||||
for_each_console_srcu(c) {
|
||||
flags = console_srcu_read_flags(c);
|
||||
|
||||
if (flags & CON_NBCON) {
|
||||
nbcon_seq_force(c, seq);
|
||||
} else {
|
||||
/*
|
||||
* This is an unsynchronized assignment. On
|
||||
* panic legacy consoles are only best effort.
|
||||
*/
|
||||
c->seq = seq;
|
||||
}
|
||||
}
|
||||
console_srcu_read_unlock(cookie);
|
||||
}
|
||||
if (mode == CONSOLE_REPLAY_ALL)
|
||||
__console_rewind_all();
|
||||
|
||||
console_flush_all(false, &next_seq, &handover);
|
||||
}
|
||||
@ -3495,7 +3522,7 @@ void register_console(struct console *newcon)
|
||||
* Note that a console with tty binding will have CON_CONSDEV
|
||||
* flag set and will be first in the list.
|
||||
*/
|
||||
if (preferred_console < 0) {
|
||||
if (preferred_console < 0 && !console_set_on_cmdline) {
|
||||
if (hlist_empty(&console_list) || !console_first()->device ||
|
||||
console_first()->flags & CON_BOOT) {
|
||||
try_enable_default_console(newcon);
|
||||
@ -4286,6 +4313,23 @@ void kmsg_dump_rewind(struct kmsg_dump_iter *iter)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kmsg_dump_rewind);
|
||||
|
||||
/**
|
||||
* console_replay_all - replay kernel log on consoles
|
||||
*
|
||||
* Try to obtain lock on console subsystem and replay all
|
||||
* available records in printk buffer on the consoles.
|
||||
* Does nothing if lock is not obtained.
|
||||
*
|
||||
* Context: Any context.
|
||||
*/
|
||||
void console_replay_all(void)
|
||||
{
|
||||
if (console_trylock()) {
|
||||
__console_rewind_all();
|
||||
/* Consoles are flushed as part of console_unlock(). */
|
||||
console_unlock();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
|
107
lib/kfifo.c
107
lib/kfifo.c
@ -5,6 +5,7 @@
|
||||
* Copyright (C) 2009/2010 Stefani Seibold <stefani@seibold.net>
|
||||
*/
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/kfifo.h>
|
||||
@ -163,6 +164,19 @@ unsigned int __kfifo_out_peek(struct __kfifo *fifo,
|
||||
}
|
||||
EXPORT_SYMBOL(__kfifo_out_peek);
|
||||
|
||||
unsigned int __kfifo_out_linear(struct __kfifo *fifo,
|
||||
unsigned int *tail, unsigned int n)
|
||||
{
|
||||
unsigned int size = fifo->mask + 1;
|
||||
unsigned int off = fifo->out & fifo->mask;
|
||||
|
||||
if (tail)
|
||||
*tail = off;
|
||||
|
||||
return min3(n, fifo->in - fifo->out, size - off);
|
||||
}
|
||||
EXPORT_SYMBOL(__kfifo_out_linear);
|
||||
|
||||
unsigned int __kfifo_out(struct __kfifo *fifo,
|
||||
void *buf, unsigned int len)
|
||||
{
|
||||
@ -292,51 +306,31 @@ int __kfifo_to_user(struct __kfifo *fifo, void __user *to,
|
||||
}
|
||||
EXPORT_SYMBOL(__kfifo_to_user);
|
||||
|
||||
static int setup_sgl_buf(struct scatterlist *sgl, void *buf,
|
||||
int nents, unsigned int len)
|
||||
static unsigned int setup_sgl_buf(struct __kfifo *fifo, struct scatterlist *sgl,
|
||||
unsigned int data_offset, int nents,
|
||||
unsigned int len, dma_addr_t dma)
|
||||
{
|
||||
int n;
|
||||
unsigned int l;
|
||||
unsigned int off;
|
||||
struct page *page;
|
||||
const void *buf = fifo->data + data_offset;
|
||||
|
||||
if (!nents)
|
||||
if (!nents || !len)
|
||||
return 0;
|
||||
|
||||
if (!len)
|
||||
return 0;
|
||||
sg_set_buf(sgl, buf, len);
|
||||
|
||||
n = 0;
|
||||
page = virt_to_page(buf);
|
||||
off = offset_in_page(buf);
|
||||
l = 0;
|
||||
|
||||
while (len >= l + PAGE_SIZE - off) {
|
||||
struct page *npage;
|
||||
|
||||
l += PAGE_SIZE;
|
||||
buf += PAGE_SIZE;
|
||||
npage = virt_to_page(buf);
|
||||
if (page_to_phys(page) != page_to_phys(npage) - l) {
|
||||
sg_set_page(sgl, page, l - off, off);
|
||||
sgl = sg_next(sgl);
|
||||
if (++n == nents || sgl == NULL)
|
||||
return n;
|
||||
page = npage;
|
||||
len -= l - off;
|
||||
l = off = 0;
|
||||
}
|
||||
if (dma != DMA_MAPPING_ERROR) {
|
||||
sg_dma_address(sgl) = dma + data_offset;
|
||||
sg_dma_len(sgl) = len;
|
||||
}
|
||||
sg_set_page(sgl, page, len, off);
|
||||
return n + 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static unsigned int setup_sgl(struct __kfifo *fifo, struct scatterlist *sgl,
|
||||
int nents, unsigned int len, unsigned int off)
|
||||
int nents, unsigned int len, unsigned int off, dma_addr_t dma)
|
||||
{
|
||||
unsigned int size = fifo->mask + 1;
|
||||
unsigned int esize = fifo->esize;
|
||||
unsigned int l;
|
||||
unsigned int len_to_end;
|
||||
unsigned int n;
|
||||
|
||||
off &= fifo->mask;
|
||||
@ -345,16 +339,17 @@ static unsigned int setup_sgl(struct __kfifo *fifo, struct scatterlist *sgl,
|
||||
size *= esize;
|
||||
len *= esize;
|
||||
}
|
||||
l = min(len, size - off);
|
||||
len_to_end = min(len, size - off);
|
||||
|
||||
n = setup_sgl_buf(sgl, fifo->data + off, nents, l);
|
||||
n += setup_sgl_buf(sgl + n, fifo->data, nents - n, len - l);
|
||||
n = setup_sgl_buf(fifo, sgl, off, nents, len_to_end, dma);
|
||||
n += setup_sgl_buf(fifo, sgl + n, 0, nents - n, len - len_to_end, dma);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
unsigned int __kfifo_dma_in_prepare(struct __kfifo *fifo,
|
||||
struct scatterlist *sgl, int nents, unsigned int len)
|
||||
struct scatterlist *sgl, int nents, unsigned int len,
|
||||
dma_addr_t dma)
|
||||
{
|
||||
unsigned int l;
|
||||
|
||||
@ -362,12 +357,13 @@ unsigned int __kfifo_dma_in_prepare(struct __kfifo *fifo,
|
||||
if (len > l)
|
||||
len = l;
|
||||
|
||||
return setup_sgl(fifo, sgl, nents, len, fifo->in);
|
||||
return setup_sgl(fifo, sgl, nents, len, fifo->in, dma);
|
||||
}
|
||||
EXPORT_SYMBOL(__kfifo_dma_in_prepare);
|
||||
|
||||
unsigned int __kfifo_dma_out_prepare(struct __kfifo *fifo,
|
||||
struct scatterlist *sgl, int nents, unsigned int len)
|
||||
struct scatterlist *sgl, int nents, unsigned int len,
|
||||
dma_addr_t dma)
|
||||
{
|
||||
unsigned int l;
|
||||
|
||||
@ -375,7 +371,7 @@ unsigned int __kfifo_dma_out_prepare(struct __kfifo *fifo,
|
||||
if (len > l)
|
||||
len = l;
|
||||
|
||||
return setup_sgl(fifo, sgl, nents, len, fifo->out);
|
||||
return setup_sgl(fifo, sgl, nents, len, fifo->out, dma);
|
||||
}
|
||||
EXPORT_SYMBOL(__kfifo_dma_out_prepare);
|
||||
|
||||
@ -473,6 +469,19 @@ unsigned int __kfifo_out_peek_r(struct __kfifo *fifo, void *buf,
|
||||
}
|
||||
EXPORT_SYMBOL(__kfifo_out_peek_r);
|
||||
|
||||
unsigned int __kfifo_out_linear_r(struct __kfifo *fifo,
|
||||
unsigned int *tail, unsigned int n, size_t recsize)
|
||||
{
|
||||
if (fifo->in == fifo->out)
|
||||
return 0;
|
||||
|
||||
if (tail)
|
||||
*tail = fifo->out + recsize;
|
||||
|
||||
return min(n, __kfifo_peek_n(fifo, recsize));
|
||||
}
|
||||
EXPORT_SYMBOL(__kfifo_out_linear_r);
|
||||
|
||||
unsigned int __kfifo_out_r(struct __kfifo *fifo, void *buf,
|
||||
unsigned int len, size_t recsize)
|
||||
{
|
||||
@ -546,7 +555,8 @@ int __kfifo_to_user_r(struct __kfifo *fifo, void __user *to,
|
||||
EXPORT_SYMBOL(__kfifo_to_user_r);
|
||||
|
||||
unsigned int __kfifo_dma_in_prepare_r(struct __kfifo *fifo,
|
||||
struct scatterlist *sgl, int nents, unsigned int len, size_t recsize)
|
||||
struct scatterlist *sgl, int nents, unsigned int len, size_t recsize,
|
||||
dma_addr_t dma)
|
||||
{
|
||||
BUG_ON(!nents);
|
||||
|
||||
@ -555,7 +565,7 @@ unsigned int __kfifo_dma_in_prepare_r(struct __kfifo *fifo,
|
||||
if (len + recsize > kfifo_unused(fifo))
|
||||
return 0;
|
||||
|
||||
return setup_sgl(fifo, sgl, nents, len, fifo->in + recsize);
|
||||
return setup_sgl(fifo, sgl, nents, len, fifo->in + recsize, dma);
|
||||
}
|
||||
EXPORT_SYMBOL(__kfifo_dma_in_prepare_r);
|
||||
|
||||
@ -569,7 +579,8 @@ void __kfifo_dma_in_finish_r(struct __kfifo *fifo,
|
||||
EXPORT_SYMBOL(__kfifo_dma_in_finish_r);
|
||||
|
||||
unsigned int __kfifo_dma_out_prepare_r(struct __kfifo *fifo,
|
||||
struct scatterlist *sgl, int nents, unsigned int len, size_t recsize)
|
||||
struct scatterlist *sgl, int nents, unsigned int len, size_t recsize,
|
||||
dma_addr_t dma)
|
||||
{
|
||||
BUG_ON(!nents);
|
||||
|
||||
@ -578,15 +589,7 @@ unsigned int __kfifo_dma_out_prepare_r(struct __kfifo *fifo,
|
||||
if (len + recsize > fifo->in - fifo->out)
|
||||
return 0;
|
||||
|
||||
return setup_sgl(fifo, sgl, nents, len, fifo->out + recsize);
|
||||
return setup_sgl(fifo, sgl, nents, len, fifo->out + recsize, dma);
|
||||
}
|
||||
EXPORT_SYMBOL(__kfifo_dma_out_prepare_r);
|
||||
|
||||
void __kfifo_dma_out_finish_r(struct __kfifo *fifo, size_t recsize)
|
||||
{
|
||||
unsigned int len;
|
||||
|
||||
len = __kfifo_peek_n(fifo, recsize);
|
||||
fifo->out += len + recsize;
|
||||
}
|
||||
EXPORT_SYMBOL(__kfifo_dma_out_finish_r);
|
||||
|
Loading…
Reference in New Issue
Block a user