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:
Linus Torvalds 2024-05-22 11:53:02 -07:00
commit f6b8e86b7a
98 changed files with 3141 additions and 1808 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -46,6 +46,9 @@ properties:
power-domains:
maxItems: 1
resets:
maxItems: 1
required:
- compatible
- reg

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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, &regcfg);
}
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, &regcfg);
}
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");

View 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_ */

View 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(&regcfg, &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, &regcfg);
}
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);

View 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(&regcfg, &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, &regcfg);
}
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);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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" },
{},
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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