summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-10-23 15:56:31 +0100
committerMark Brown <broonie@kernel.org>2026-10-23 15:56:31 +0100
commit51ff321c064a601506fcdb9fd78c7ecdb1f3087f (patch)
tree055a04914f3bb47df4c2f658d6742113ec9d91a8
parentfa13cfae8561df78a4993460172dc9c2b5fadab6 (diff)
parent1184f87e2790e8af9be3116f608d2e86b4792d7d (diff)
downloadlinux-next-51ff321c064a601506fcdb9fd78c7ecdb1f3087f.tar.gz
linux-next-51ff321c064a601506fcdb9fd78c7ecdb1f3087f.zip
Merge branch 'tty-next' of https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git
-rw-r--r--Documentation/admin-guide/devices.txt13
-rw-r--r--Documentation/devicetree/bindings/serial/8250.yaml32
-rw-r--r--Documentation/devicetree/bindings/serial/cdns,uart.yaml1
-rw-r--r--Documentation/devicetree/bindings/serial/renesas,hscif.yaml4
-rw-r--r--Documentation/devicetree/bindings/serial/renesas,scif.yaml4
-rw-r--r--Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml13
-rw-r--r--Documentation/driver-api/serial/driver.rst2
-rw-r--r--MAINTAINERS2
-rw-r--r--drivers/acpi/acpi_apd.c1
-rw-r--r--drivers/mmc/core/Kconfig7
-rw-r--r--drivers/mmc/core/Makefile1
-rw-r--r--drivers/ptp/ptp_ocp.c36
-rw-r--r--drivers/tty/Kconfig10
-rw-r--r--drivers/tty/Makefile1
-rw-r--r--drivers/tty/hvc/hvc_dcc.c30
-rw-r--r--drivers/tty/hvc/hvc_opal.c11
-rw-r--r--drivers/tty/hvc/hvcs.c6
-rw-r--r--drivers/tty/moxa.c2136
-rw-r--r--drivers/tty/pty.c5
-rw-r--r--drivers/tty/serdev/serdev-ttyport.c2
-rw-r--r--drivers/tty/serial/8250/8250.h17
-rw-r--r--drivers/tty/serial/8250/8250_acorn.c5
-rw-r--r--drivers/tty/serial/8250/8250_airoha.c178
-rw-r--r--drivers/tty/serial/8250/8250_aspeed_vuart.c13
-rw-r--r--drivers/tty/serial/8250/8250_bcm2835aux.c187
-rw-r--r--drivers/tty/serial/8250/8250_bcm7271.c33
-rw-r--r--drivers/tty/serial/8250/8250_core.c153
-rw-r--r--drivers/tty/serial/8250/8250_dfl.c22
-rw-r--r--drivers/tty/serial/8250/8250_dma.c29
-rw-r--r--drivers/tty/serial/8250/8250_dw.c32
-rw-r--r--drivers/tty/serial/8250/8250_dwlib.c5
-rw-r--r--drivers/tty/serial/8250/8250_dwlib.h7
-rw-r--r--drivers/tty/serial/8250/8250_early.c1
-rw-r--r--drivers/tty/serial/8250/8250_em.c26
-rw-r--r--drivers/tty/serial/8250/8250_exar.c59
-rw-r--r--drivers/tty/serial/8250/8250_fsl.c24
-rw-r--r--drivers/tty/serial/8250/8250_hp300.c27
-rw-r--r--drivers/tty/serial/8250/8250_hub6.c11
-rw-r--r--drivers/tty/serial/8250/8250_ingenic.c11
-rw-r--r--drivers/tty/serial/8250/8250_ioc3.c26
-rw-r--r--drivers/tty/serial/8250/8250_keba.c13
-rw-r--r--drivers/tty/serial/8250/8250_loongson.c20
-rw-r--r--drivers/tty/serial/8250/8250_lpc18xx.c11
-rw-r--r--drivers/tty/serial/8250/8250_lpss.c17
-rw-r--r--drivers/tty/serial/8250/8250_men_mcb.c14
-rw-r--r--drivers/tty/serial/8250/8250_mid.c29
-rw-r--r--drivers/tty/serial/8250/8250_mtk.c19
-rw-r--r--drivers/tty/serial/8250/8250_mxpcie.c43
-rw-r--r--drivers/tty/serial/8250/8250_ni.c12
-rw-r--r--drivers/tty/serial/8250/8250_of.c25
-rw-r--r--drivers/tty/serial/8250/8250_omap.c45
-rw-r--r--drivers/tty/serial/8250/8250_parisc.c14
-rw-r--r--drivers/tty/serial/8250/8250_pci.c23
-rw-r--r--drivers/tty/serial/8250/8250_pci1xxxx.c41
-rw-r--r--drivers/tty/serial/8250/8250_pericom.c15
-rw-r--r--drivers/tty/serial/8250/8250_platform.c32
-rw-r--r--drivers/tty/serial/8250/8250_pnp.c23
-rw-r--r--drivers/tty/serial/8250/8250_port.c50
-rw-r--r--drivers/tty/serial/8250/8250_pxa.c17
-rw-r--r--drivers/tty/serial/8250/8250_tegra.c20
-rw-r--r--drivers/tty/serial/8250/8250_uniphier.c43
-rw-r--r--drivers/tty/serial/8250/Kconfig15
-rw-r--r--drivers/tty/serial/8250/Makefile3
-rw-r--r--drivers/tty/serial/8250/serial_cs.c15
-rw-r--r--drivers/tty/serial/Kconfig11
-rw-r--r--drivers/tty/serial/Makefile1
-rw-r--r--drivers/tty/serial/amba-pl011.c123
-rw-r--r--drivers/tty/serial/arc_uart.c2
-rw-r--r--drivers/tty/serial/atmel_serial.c8
-rw-r--r--drivers/tty/serial/earlycon.c10
-rw-r--r--drivers/tty/serial/fsl_lpuart.c18
-rw-r--r--drivers/tty/serial/kgdboc.c2
-rw-r--r--drivers/tty/serial/ma35d1_serial.c2
-rw-r--r--drivers/tty/serial/max310x.c632
-rw-r--r--drivers/tty/serial/mcf.c4
-rw-r--r--drivers/tty/serial/pch_uart.c4
-rw-r--r--drivers/tty/serial/pmac_zilog.c5
-rw-r--r--drivers/tty/serial/qcom_geni_serial.c49
-rw-r--r--drivers/tty/serial/samsung_tty.c27
-rw-r--r--drivers/tty/serial/sc16is7xx.c4
-rw-r--r--drivers/tty/serial/sdio_uart.c (renamed from drivers/mmc/core/sdio_uart.c)0
-rw-r--r--drivers/tty/serial/serial_core.c70
-rw-r--r--drivers/tty/serial/serial_txx9.c62
-rw-r--r--drivers/tty/serial/sh-sci.c22
-rw-r--r--drivers/tty/serial/sifive.c2
-rw-r--r--drivers/tty/serial/tegra-tcu.c22
-rw-r--r--drivers/tty/sysrq.c5
-rw-r--r--drivers/tty/tty_port.c8
-rw-r--r--drivers/tty/vt/keyboard.c4
-rw-r--r--include/linux/serial_8250.h8
-rw-r--r--include/linux/serial_core.h2
-rw-r--r--include/linux/soc/qcom/geni-se.h12
92 files changed, 1862 insertions, 2999 deletions
diff --git a/Documentation/admin-guide/devices.txt b/Documentation/admin-guide/devices.txt
index f544399675fa..855f2cad0535 100644
--- a/Documentation/admin-guide/devices.txt
+++ b/Documentation/admin-guide/devices.txt
@@ -2388,18 +2388,9 @@
171 char Reserved for IEEE 1394 (Firewire)
- 172 char Moxa Intellio serial card
- 0 = /dev/ttyMX0 First Moxa port
- 1 = /dev/ttyMX1 Second Moxa port
- ...
- 127 = /dev/ttyMX127 128th Moxa port
- 128 = /dev/moxactl Moxa control port
+ 172 char
- 173 char Moxa Intellio serial card - alternate devices
- 0 = /dev/cumx0 Callout device for ttyMX0
- 1 = /dev/cumx1 Callout device for ttyMX1
- ...
- 127 = /dev/cumx127 Callout device for ttyMX127
+ 173 char
174 char SmartIO serial card
0 = /dev/ttySI0 First SmartIO port
diff --git a/Documentation/devicetree/bindings/serial/8250.yaml b/Documentation/devicetree/bindings/serial/8250.yaml
index 8c2c177faf89..50d5c977afa3 100644
--- a/Documentation/devicetree/bindings/serial/8250.yaml
+++ b/Documentation/devicetree/bindings/serial/8250.yaml
@@ -100,19 +100,25 @@ allOf:
properties:
compatible:
oneOf:
- - const: ns8250
- - const: ns16450
- - const: ns16550
- - const: ns16550a
- - const: ns16850
- - const: aspeed,ast2400-vuart
- - const: aspeed,ast2500-vuart
- - const: intel,xscale-uart
- - const: mrvl,pxa-uart
- - const: nuvoton,wpcm450-uart
- - const: nuvoton,npcm750-uart
- - const: nvidia,tegra20-uart
- - const: nxp,lpc3220-uart
+ - enum:
+ - ns8250
+ - ns16450
+ - ns16550
+ - ns16550a
+ - ns16850
+ - airoha,an7581-hsuart
+ - airoha,en7523-uart
+ - aspeed,ast2400-vuart
+ - aspeed,ast2500-vuart
+ - intel,xscale-uart
+ - mrvl,pxa-uart
+ - nuvoton,npcm750-uart
+ - nuvoton,wpcm450-uart
+ - nvidia,tegra20-uart
+ - nxp,lpc3220-uart
+ - items:
+ - const: airoha,an7581-uart
+ - const: airoha,en7523-uart
- items:
- enum:
- exar,xr16l2552
diff --git a/Documentation/devicetree/bindings/serial/cdns,uart.yaml b/Documentation/devicetree/bindings/serial/cdns,uart.yaml
index 9d3e5c1d8502..11292de42c67 100644
--- a/Documentation/devicetree/bindings/serial/cdns,uart.yaml
+++ b/Documentation/devicetree/bindings/serial/cdns,uart.yaml
@@ -19,6 +19,7 @@ properties:
- items:
- enum:
- axiado,ax3000-uart
+ - axiado,ax3005-uart
- xlnx,zynqmp-uart
- const: cdns,uart-r1p12
diff --git a/Documentation/devicetree/bindings/serial/renesas,hscif.yaml b/Documentation/devicetree/bindings/serial/renesas,hscif.yaml
index 4b3f98a46cd9..409cab32de3d 100644
--- a/Documentation/devicetree/bindings/serial/renesas,hscif.yaml
+++ b/Documentation/devicetree/bindings/serial/renesas,hscif.yaml
@@ -97,14 +97,14 @@ properties:
dmas:
minItems: 2
- maxItems: 4
+ maxItems: 6
description:
Must contain a list of pairs of references to DMA specifiers, one for
transmission, and one for reception.
dma-names:
minItems: 2
- maxItems: 4
+ maxItems: 6
items:
enum:
- tx
diff --git a/Documentation/devicetree/bindings/serial/renesas,scif.yaml b/Documentation/devicetree/bindings/serial/renesas,scif.yaml
index 82f54446835e..b465c93c8357 100644
--- a/Documentation/devicetree/bindings/serial/renesas,scif.yaml
+++ b/Documentation/devicetree/bindings/serial/renesas,scif.yaml
@@ -145,14 +145,14 @@ properties:
dmas:
minItems: 2
- maxItems: 4
+ maxItems: 6
description:
Must contain a list of pairs of references to DMA specifiers, one for
transmission, and one for reception.
dma-names:
minItems: 2
- maxItems: 4
+ maxItems: 6
items:
enum:
- tx
diff --git a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml
index 664305de4986..e2ca126d58ba 100644
--- a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml
+++ b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml
@@ -34,7 +34,16 @@ allOf:
properties:
resets:
minItems: 2
- else:
+
+ - if:
+ not:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - starfive,jh7110-uart
+ - syna,sl2610-uart
+ then:
properties:
resets:
maxItems: 1
@@ -80,6 +89,8 @@ properties:
- starfive,jh7100-hsuart
- starfive,jh7100-uart
- starfive,jh7110-uart
+ - syna,sl2610-uart
+ - ti,tda54-uart
- ultrarisc,dp1000-uart
- const: snps,dw-apb-uart
- const: snps,dw-apb-uart
diff --git a/Documentation/driver-api/serial/driver.rst b/Documentation/driver-api/serial/driver.rst
index c1db6a1a67c4..975b0ba53e98 100644
--- a/Documentation/driver-api/serial/driver.rst
+++ b/Documentation/driver-api/serial/driver.rst
@@ -70,7 +70,7 @@ Other functions
.. kernel-doc:: drivers/tty/serial/serial_core.c
:identifiers: uart_update_timeout uart_get_baud_rate uart_get_divisor
- uart_match_port uart_write_wakeup uart_register_driver
+ uart_write_wakeup uart_register_driver
uart_unregister_driver uart_suspend_port uart_resume_port
uart_add_one_port uart_remove_one_port uart_console_write
uart_parse_earlycon uart_parse_options uart_set_options
diff --git a/MAINTAINERS b/MAINTAINERS
index b16fc08cf2b1..aa1e595a5477 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18783,7 +18783,7 @@ F: Documentation/devicetree/bindings/net/dsa/motorcomm,yt921x.yaml
F: drivers/net/dsa/motorcomm/
F: net/dsa/tag_yt921x.c
-MOXA SMARTIO/INDUSTIO/INTELLIO SERIAL CARD
+MOXA SMARTIO/INDUSTIO SERIAL CARD
M: Jiri Slaby <jirislaby@kernel.org>
S: Maintained
F: Documentation/driver-api/tty/moxa-smartio.rst
diff --git a/drivers/acpi/acpi_apd.c b/drivers/acpi/acpi_apd.c
index e7366fcb76ee..9fc667d6776c 100644
--- a/drivers/acpi/acpi_apd.c
+++ b/drivers/acpi/acpi_apd.c
@@ -256,6 +256,7 @@ static const struct acpi_device_id acpi_apd_device_ids[] = {
{ "AMDI0015", APD_ADDR(wt_i3c_desc) },
{ "AMDI0019", APD_ADDR(wt_i2c_desc) },
{ "AMDI0020", APD_ADDR(cz_uart_desc) },
+ { "AMDI0021", APD_ADDR(cz_uart_desc) },
{ "AMDI0022", APD_ADDR(cz_uart_desc) },
{ "HYGO0010", APD_ADDR(wt_i2c_desc) },
#endif
diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig
index 14d2ecbb04d3..03061b1045a8 100644
--- a/drivers/mmc/core/Kconfig
+++ b/drivers/mmc/core/Kconfig
@@ -64,13 +64,6 @@ config MMC_BLOCK_MINORS
If unsure, say 8 here.
-config SDIO_UART
- tristate "SDIO UART/GPS class support"
- depends on TTY
- help
- SDIO function driver for SDIO cards that implements the UART
- class, as well as the GPS class which appears like a UART.
-
config MMC_TEST
tristate "MMC host test driver"
help
diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile
index 15b067e8b0d1..0fa4abada538 100644
--- a/drivers/mmc/core/Makefile
+++ b/drivers/mmc/core/Makefile
@@ -17,5 +17,4 @@ mmc_core-$(CONFIG_DEBUG_FS) += debugfs.o
obj-$(CONFIG_MMC_BLOCK) += mmc_block.o
mmc_block-objs := block.o queue.o
obj-$(CONFIG_MMC_TEST) += mmc_test.o
-obj-$(CONFIG_SDIO_UART) += sdio_uart.o
mmc_core-$(CONFIG_MMC_CRYPTO) += crypto.o
diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index d23e0d1e071e..625a85b2dc7e 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -344,7 +344,7 @@ struct ptp_ocp_signal {
};
struct ptp_ocp_serial_port {
- int line;
+ struct uart_8250_port *uport;
int baud;
};
@@ -2629,7 +2629,7 @@ out:
return err;
}
-static int
+static struct uart_8250_port *
ptp_ocp_serial_line(struct ptp_ocp *bp, struct ocp_resource *r)
{
struct pci_dev *pdev = bp->pdev;
@@ -2657,9 +2657,11 @@ ptp_ocp_register_serial(struct ptp_ocp *bp, struct ocp_resource *r)
struct ptp_ocp_serial_port *p = (struct ptp_ocp_serial_port *)r->extra;
struct ptp_ocp_serial_port port = {};
- port.line = ptp_ocp_serial_line(bp, r);
- if (port.line < 0)
- return port.line;
+ struct uart_8250_port *uport = ptp_ocp_serial_line(bp, r);
+ if (IS_ERR(uport))
+ return PTR_ERR(uport);
+
+ port.uport = uport;
if (p)
port.baud = p->baud;
@@ -3804,7 +3806,7 @@ ptp_ocp_tty_show(struct device *dev, struct device_attribute *attr, char *buf)
* as a device path (e.g., "/dev/ttyS4"), and adding a newline would
* break those applications. Do not add a newline to this output.
*/
- return sysfs_emit(buf, "ttyS%d", bp->port[(uintptr_t)ea->var].line);
+ return sysfs_emit(buf, "ttyS%d", bp->port[(uintptr_t)ea->var].uport->port.line);
}
static umode_t
@@ -3821,7 +3823,7 @@ ptp_ocp_timecard_tty_is_visible(struct kobject *kobj, struct attribute *attr, in
dattr = container_of(attr, struct device_attribute, attr);
ea = container_of(dattr, struct dev_ext_attribute, attr);
port = &bp->port[(uintptr_t)ea->var];
- return port->line == -1 ? 0 : 0444;
+ return port->uport ? 0444 : 0;
}
#define EXT_TTY_ATTR_RO(_name, _val) \
@@ -5287,9 +5289,9 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
seq_printf(s, "%7s: /dev/ptp%d\n", "PTP", ptp_clock_index(bp->ptp));
for (i = 0; i < __PORT_COUNT; i++) {
- if (bp->port[i].line != -1)
+ if (bp->port[i].uport)
seq_printf(s, "%7s: /dev/ttyS%d\n", ptp_ocp_tty_port_name(i),
- bp->port[i].line);
+ bp->port[i].uport->port.line);
}
memset(sma_val, 0xff, sizeof(sma_val));
@@ -5613,7 +5615,7 @@ ptp_ocp_device_init(struct ptp_ocp *bp, struct pci_dev *pdev)
spin_lock_init(&bp->lock);
for (i = 0; i < __PORT_COUNT; i++)
- bp->port[i].line = -1;
+ bp->port[i].uport = NULL;
bp->pdev = pdev;
@@ -5702,10 +5704,10 @@ ptp_ocp_phc_info(struct ptp_ocp *bp)
}
static void
-ptp_ocp_serial_info(struct device *dev, const char *name, int port, int baud)
+ptp_ocp_serial_info(struct device *dev, const char *name, struct uart_8250_port *port, int baud)
{
- if (port != -1)
- dev_info(dev, "%5s: /dev/ttyS%-2d @ %6d\n", name, port, baud);
+ if (port)
+ dev_info(dev, "%5s: /dev/ttyS%-2d @ %6d\n", name, port->port.line, baud);
}
static void
@@ -5723,14 +5725,14 @@ ptp_ocp_info(struct ptp_ocp *bp)
ptp_ocp_phc_info(bp);
for (i = 0; i < __PORT_COUNT; i++) {
- if (i == PORT_NMEA && bp->nmea_out && bp->port[PORT_NMEA].line != -1) {
+ if (i == PORT_NMEA && bp->nmea_out && bp->port[PORT_NMEA].uport) {
bp->port[PORT_NMEA].baud = -1;
reg = ioread32(&bp->nmea_out->uart_baud);
if (reg < ARRAY_SIZE(nmea_baud))
bp->port[PORT_NMEA].baud = nmea_baud[reg];
}
- ptp_ocp_serial_info(dev, ptp_ocp_tty_port_name(i), bp->port[i].line,
+ ptp_ocp_serial_info(dev, ptp_ocp_tty_port_name(i), bp->port[i].uport,
bp->port[i].baud);
}
}
@@ -5778,8 +5780,8 @@ ptp_ocp_detach(struct ptp_ocp *bp)
for (i = 0; i < 4; i++)
ptp_ocp_unregister_ext(bp->signal_out[i]);
for (i = 0; i < __PORT_COUNT; i++)
- if (bp->port[i].line != -1)
- serial8250_unregister_port(bp->port[i].line);
+ if (bp->port[i].uport)
+ serial8250_unregister_port(bp->port[i].uport);
platform_device_unregister(bp->spi_flash);
platform_device_unregister(bp->i2c_ctrl);
if (bp->i2c_clk)
diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig
index 5d6b0dd4d423..2ed4f1e0e9ef 100644
--- a/drivers/tty/Kconfig
+++ b/drivers/tty/Kconfig
@@ -208,16 +208,6 @@ config SERIAL_NONSTANDARD
Most people can say N here.
-config MOXA_INTELLIO
- tristate "Moxa Intellio support"
- depends on SERIAL_NONSTANDARD && PCI
- select FW_LOADER
- help
- Say Y here if you have a Moxa Intellio multiport serial card.
-
- To compile this driver as a module, choose M here: the
- module will be called moxa.
-
config MOXA_SMARTIO
tristate "Moxa SmartIO support v. 2.0"
depends on SERIAL_NONSTANDARD && PCI && HAS_IOPORT
diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile
index c6a063a541fd..43aa3f93b09a 100644
--- a/drivers/tty/Makefile
+++ b/drivers/tty/Makefile
@@ -17,7 +17,6 @@ obj-$(CONFIG_SERIAL_DEV_BUS) += serdev/
# tty drivers
obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
-obj-$(CONFIG_MOXA_INTELLIO) += moxa.o
obj-$(CONFIG_MOXA_SMARTIO) += mxser.o
obj-$(CONFIG_NOZOMI) += nozomi.o
obj-$(CONFIG_NULL_TTY) += ttynull.o
diff --git a/drivers/tty/hvc/hvc_dcc.c b/drivers/tty/hvc/hvc_dcc.c
index dfc5c9c38f07..0223b26b5b28 100644
--- a/drivers/tty/hvc/hvc_dcc.c
+++ b/drivers/tty/hvc/hvc_dcc.c
@@ -29,6 +29,9 @@ static DEFINE_SPINLOCK(dcc_lock);
static DEFINE_KFIFO(inbuf, u8, DCC_INBUF_SIZE);
static DEFINE_KFIFO(outbuf, u8, DCC_OUTBUF_SIZE);
+/* Cached result of hvc_dcc_check() on core 0 */
+static bool dcc_core0_available;
+
static void dcc_uart_console_putchar(struct uart_port *port, u8 ch)
{
while (__dcc_getstatus() & DCC_STATUS_TX)
@@ -90,36 +93,18 @@ static ssize_t hvc_dcc_get_chars(uint32_t vt, u8 *buf, size_t count)
}
/*
- * Check if the DCC is enabled. If CONFIG_HVC_DCC_SERIALIZE_SMP is enabled,
- * then we assume then this function will be called first on core0. That way,
- * dcc_core0_available will be true only if it's available on core0.
+ * Check if the DCC is enabled. This function will be called once on core 0.
*/
static bool hvc_dcc_check(void)
{
unsigned long time = jiffies + (HZ / 10);
- static bool dcc_core0_available;
-
- /*
- * If we're not on core 0, but we previously confirmed that DCC is
- * active, then just return true.
- */
- int cpu = get_cpu();
-
- if (IS_ENABLED(CONFIG_HVC_DCC_SERIALIZE_SMP) && cpu && dcc_core0_available) {
- put_cpu();
- return true;
- }
-
- put_cpu();
/* Write a test character to check if it is handled */
__dcc_putchar('\n');
while (time_is_after_jiffies(time)) {
- if (!(__dcc_getstatus() & DCC_STATUS_TX)) {
- dcc_core0_available = true;
+ if (!(__dcc_getstatus() & DCC_STATUS_TX))
return true;
- }
}
return false;
@@ -265,7 +250,8 @@ static int __init hvc_dcc_console_init(void)
{
int ret;
- if (!hvc_dcc_check())
+ dcc_core0_available = hvc_dcc_check();
+ if (!dcc_core0_available)
return -ENODEV;
/* Returns -1 if error */
@@ -279,7 +265,7 @@ static int __init hvc_dcc_init(void)
{
struct hvc_struct *p;
- if (!hvc_dcc_check())
+ if (!dcc_core0_available)
return -ENODEV;
if (IS_ENABLED(CONFIG_HVC_DCC_SERIALIZE_SMP)) {
diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c
index 402da9e7c534..fb9a566ca213 100644
--- a/drivers/tty/hvc/hvc_opal.c
+++ b/drivers/tty/hvc/hvc_opal.c
@@ -13,7 +13,6 @@
#include <linux/slab.h>
#include <linux/console.h>
#include <linux/of.h>
-#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/export.h>
#include <linux/interrupt.h>
@@ -157,8 +156,9 @@ static int hvc_opal_probe(struct platform_device *dev)
struct hvc_struct *hp;
struct hvc_opal_priv *pv;
hv_protocol_t proto;
- unsigned int termno, irq, boot = 0;
+ unsigned int termno, boot = 0;
const __be32 *reg;
+ int irq;
if (of_device_is_compatible(dev->dev.of_node, "ibm,opal-console-raw")) {
proto = HV_PROTOCOL_RAW;
@@ -176,6 +176,10 @@ static int hvc_opal_probe(struct platform_device *dev)
reg = of_get_property(dev->dev.of_node, "reg", NULL);
termno = reg ? be32_to_cpup(reg) : 0;
+ irq = platform_get_irq_optional(dev, 0);
+ if (irq == -EPROBE_DEFER)
+ return irq;
+
/* Is it our boot one ? */
if (hvc_opal_privs[termno] == &hvc_opal_boot_priv) {
pv = hvc_opal_privs[termno];
@@ -209,8 +213,7 @@ static int hvc_opal_probe(struct platform_device *dev)
dev->dev.of_node,
boot ? " (boot console)" : "");
- irq = irq_of_parse_and_map(dev->dev.of_node, 0);
- if (!irq) {
+ if (irq < 0) {
pr_info("hvc%d: No interrupts property, using OPAL event\n",
termno);
irq = opal_event_request(ilog2(OPAL_EVENT_CONSOLE_INPUT));
diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c
index d32b1e3c50bf..b94d59fa3627 100644
--- a/drivers/tty/hvc/hvcs.c
+++ b/drivers/tty/hvc/hvcs.c
@@ -1470,7 +1470,7 @@ static int hvcs_initialize(void)
goto register_fail;
}
- hvcs_pi_buff = (unsigned long *) __get_free_page(GFP_KERNEL);
+ hvcs_pi_buff = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!hvcs_pi_buff) {
rc = -ENOMEM;
goto buff_alloc_fail;
@@ -1486,7 +1486,7 @@ static int hvcs_initialize(void)
return 0;
kthread_fail:
- free_page((unsigned long)hvcs_pi_buff);
+ kfree(hvcs_pi_buff);
buff_alloc_fail:
tty_unregister_driver(hvcs_tty_driver);
register_fail:
@@ -1528,7 +1528,7 @@ static void __exit hvcs_module_exit(void)
kthread_stop(hvcs_task);
spin_lock(&hvcs_pi_lock);
- free_page((unsigned long)hvcs_pi_buff);
+ kfree(hvcs_pi_buff);
hvcs_pi_buff = NULL;
spin_unlock(&hvcs_pi_lock);
diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c
deleted file mode 100644
index 40a1c614e23b..000000000000
--- a/drivers/tty/moxa.c
+++ /dev/null
@@ -1,2136 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*****************************************************************************/
-/*
- * moxa.c -- MOXA Intellio family multiport serial driver.
- *
- * Copyright (C) 1999-2000 Moxa Technologies (support@moxa.com).
- * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
- *
- * This code is loosely based on the Linux serial driver, written by
- * Linus Torvalds, Theodore T'so and others.
- */
-
-/*
- * MOXA Intellio Series Driver
- * for : LINUX
- * date : 1999/1/7
- * version : 5.1
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/errno.h>
-#include <linux/firmware.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
-#include <linux/serial.h>
-#include <linux/tty_driver.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <linux/slab.h>
-#include <linux/ratelimit.h>
-
-#include <asm/io.h>
-
-/*
- * System Configuration
- */
-
-#define Magic_code 0x404
-
-/*
- * for C218 BIOS initialization
- */
-#define C218_ConfBase 0x800
-#define C218_status (C218_ConfBase + 0) /* BIOS running status */
-#define C218_diag (C218_ConfBase + 2) /* diagnostic status */
-#define C218_key (C218_ConfBase + 4) /* WORD (0x218 for C218) */
-#define C218DLoad_len (C218_ConfBase + 6) /* WORD */
-#define C218check_sum (C218_ConfBase + 8) /* BYTE */
-#define C218chksum_ok (C218_ConfBase + 0x0a) /* BYTE (1:ok) */
-#define C218_TestRx (C218_ConfBase + 0x10) /* 8 bytes for 8 ports */
-#define C218_TestTx (C218_ConfBase + 0x18) /* 8 bytes for 8 ports */
-#define C218_RXerr (C218_ConfBase + 0x20) /* 8 bytes for 8 ports */
-#define C218_ErrFlag (C218_ConfBase + 0x28) /* 8 bytes for 8 ports */
-
-#define C218_LoadBuf 0x0F00
-#define C218_KeyCode 0x218
-#define CP204J_KeyCode 0x204
-
-/*
- * for C320 BIOS initialization
- */
-#define C320_ConfBase 0x800
-#define C320_LoadBuf 0x0f00
-#define STS_init 0x05 /* for C320_status */
-
-#define C320_status C320_ConfBase + 0 /* BIOS running status */
-#define C320_diag C320_ConfBase + 2 /* diagnostic status */
-#define C320_key C320_ConfBase + 4 /* WORD (0320H for C320) */
-#define C320DLoad_len C320_ConfBase + 6 /* WORD */
-#define C320check_sum C320_ConfBase + 8 /* WORD */
-#define C320chksum_ok C320_ConfBase + 0x0a /* WORD (1:ok) */
-#define C320bapi_len C320_ConfBase + 0x0c /* WORD */
-#define C320UART_no C320_ConfBase + 0x0e /* WORD */
-
-#define C320_KeyCode 0x320
-
-#define FixPage_addr 0x0000 /* starting addr of static page */
-#define DynPage_addr 0x2000 /* starting addr of dynamic page */
-#define C218_start 0x3000 /* starting addr of C218 BIOS prg */
-#define Control_reg 0x1ff0 /* select page and reset control */
-#define HW_reset 0x80
-
-/*
- * Function Codes
- */
-#define FC_CardReset 0x80
-#define FC_ChannelReset 1 /* C320 firmware not supported */
-#define FC_EnableCH 2
-#define FC_DisableCH 3
-#define FC_SetParam 4
-#define FC_SetMode 5
-#define FC_SetRate 6
-#define FC_LineControl 7
-#define FC_LineStatus 8
-#define FC_XmitControl 9
-#define FC_FlushQueue 10
-#define FC_SendBreak 11
-#define FC_StopBreak 12
-#define FC_LoopbackON 13
-#define FC_LoopbackOFF 14
-#define FC_ClrIrqTable 15
-#define FC_SendXon 16
-#define FC_SetTermIrq 17 /* C320 firmware not supported */
-#define FC_SetCntIrq 18 /* C320 firmware not supported */
-#define FC_SetBreakIrq 19
-#define FC_SetLineIrq 20
-#define FC_SetFlowCtl 21
-#define FC_GenIrq 22
-#define FC_InCD180 23
-#define FC_OutCD180 24
-#define FC_InUARTreg 23
-#define FC_OutUARTreg 24
-#define FC_SetXonXoff 25
-#define FC_OutCD180CCR 26
-#define FC_ExtIQueue 27
-#define FC_ExtOQueue 28
-#define FC_ClrLineIrq 29
-#define FC_HWFlowCtl 30
-#define FC_GetClockRate 35
-#define FC_SetBaud 36
-#define FC_SetDataMode 41
-#define FC_GetCCSR 43
-#define FC_GetDataError 45
-#define FC_RxControl 50
-#define FC_ImmSend 51
-#define FC_SetXonState 52
-#define FC_SetXoffState 53
-#define FC_SetRxFIFOTrig 54
-#define FC_SetTxFIFOCnt 55
-#define FC_UnixRate 56
-#define FC_UnixResetTimer 57
-
-#define RxFIFOTrig1 0
-#define RxFIFOTrig4 1
-#define RxFIFOTrig8 2
-#define RxFIFOTrig14 3
-
-/*
- * Dual-Ported RAM
- */
-#define DRAM_global 0
-#define INT_data (DRAM_global + 0)
-#define Config_base (DRAM_global + 0x108)
-
-#define IRQindex (INT_data + 0)
-#define IRQpending (INT_data + 4)
-#define IRQtable (INT_data + 8)
-
-/*
- * Interrupt Status
- */
-#define IntrRx 0x01 /* receiver data O.K. */
-#define IntrTx 0x02 /* transmit buffer empty */
-#define IntrFunc 0x04 /* function complete */
-#define IntrBreak 0x08 /* received break */
-#define IntrLine 0x10 /* line status change
- for transmitter */
-#define IntrIntr 0x20 /* received INTR code */
-#define IntrQuit 0x40 /* received QUIT code */
-#define IntrEOF 0x80 /* received EOF code */
-
-#define IntrRxTrigger 0x100 /* rx data count reach trigger value */
-#define IntrTxTrigger 0x200 /* tx data count below trigger value */
-
-#define Magic_no (Config_base + 0)
-#define Card_model_no (Config_base + 2)
-#define Total_ports (Config_base + 4)
-#define Module_cnt (Config_base + 8)
-#define Module_no (Config_base + 10)
-#define Timer_10ms (Config_base + 14)
-#define Disable_IRQ (Config_base + 20)
-#define TMS320_PORT1 (Config_base + 22)
-#define TMS320_PORT2 (Config_base + 24)
-#define TMS320_CLOCK (Config_base + 26)
-
-/*
- * DATA BUFFER in DRAM
- */
-#define Extern_table 0x400 /* Base address of the external table
- (24 words * 64) total 3K bytes
- (24 words * 128) total 6K bytes */
-#define Extern_size 0x60 /* 96 bytes */
-#define RXrptr 0x00 /* read pointer for RX buffer */
-#define RXwptr 0x02 /* write pointer for RX buffer */
-#define TXrptr 0x04 /* read pointer for TX buffer */
-#define TXwptr 0x06 /* write pointer for TX buffer */
-#define HostStat 0x08 /* IRQ flag and general flag */
-#define FlagStat 0x0A
-#define FlowControl 0x0C /* B7 B6 B5 B4 B3 B2 B1 B0 */
- /* x x x x | | | | */
- /* | | | + CTS flow */
- /* | | +--- RTS flow */
- /* | +------ TX Xon/Xoff */
- /* +--------- RX Xon/Xoff */
-#define Break_cnt 0x0E /* received break count */
-#define CD180TXirq 0x10 /* if non-0: enable TX irq */
-#define RX_mask 0x12
-#define TX_mask 0x14
-#define Ofs_rxb 0x16
-#define Ofs_txb 0x18
-#define Page_rxb 0x1A
-#define Page_txb 0x1C
-#define EndPage_rxb 0x1E
-#define EndPage_txb 0x20
-#define Data_error 0x22
-#define RxTrigger 0x28
-#define TxTrigger 0x2a
-
-#define rRXwptr 0x34
-#define Low_water 0x36
-
-#define FuncCode 0x40
-#define FuncArg 0x42
-#define FuncArg1 0x44
-
-#define C218rx_size 0x2000 /* 8K bytes */
-#define C218tx_size 0x8000 /* 32K bytes */
-
-#define C218rx_mask (C218rx_size - 1)
-#define C218tx_mask (C218tx_size - 1)
-
-#define C320p8rx_size 0x2000
-#define C320p8tx_size 0x8000
-#define C320p8rx_mask (C320p8rx_size - 1)
-#define C320p8tx_mask (C320p8tx_size - 1)
-
-#define C320p16rx_size 0x2000
-#define C320p16tx_size 0x4000
-#define C320p16rx_mask (C320p16rx_size - 1)
-#define C320p16tx_mask (C320p16tx_size - 1)
-
-#define C320p24rx_size 0x2000
-#define C320p24tx_size 0x2000
-#define C320p24rx_mask (C320p24rx_size - 1)
-#define C320p24tx_mask (C320p24tx_size - 1)
-
-#define C320p32rx_size 0x1000
-#define C320p32tx_size 0x1000
-#define C320p32rx_mask (C320p32rx_size - 1)
-#define C320p32tx_mask (C320p32tx_size - 1)
-
-#define Page_size 0x2000U
-#define Page_mask (Page_size - 1)
-#define C218rx_spage 3
-#define C218tx_spage 4
-#define C218rx_pageno 1
-#define C218tx_pageno 4
-#define C218buf_pageno 5
-
-#define C320p8rx_spage 3
-#define C320p8tx_spage 4
-#define C320p8rx_pgno 1
-#define C320p8tx_pgno 4
-#define C320p8buf_pgno 5
-
-#define C320p16rx_spage 3
-#define C320p16tx_spage 4
-#define C320p16rx_pgno 1
-#define C320p16tx_pgno 2
-#define C320p16buf_pgno 3
-
-#define C320p24rx_spage 3
-#define C320p24tx_spage 4
-#define C320p24rx_pgno 1
-#define C320p24tx_pgno 1
-#define C320p24buf_pgno 2
-
-#define C320p32rx_spage 3
-#define C320p32tx_ofs C320p32rx_size
-#define C320p32tx_spage 3
-#define C320p32buf_pgno 1
-
-/*
- * Host Status
- */
-#define WakeupRx 0x01
-#define WakeupTx 0x02
-#define WakeupBreak 0x08
-#define WakeupLine 0x10
-#define WakeupIntr 0x20
-#define WakeupQuit 0x40
-#define WakeupEOF 0x80 /* used in VTIME control */
-#define WakeupRxTrigger 0x100
-#define WakeupTxTrigger 0x200
-/*
- * Flag status
- */
-#define Rx_over 0x01
-#define Xoff_state 0x02
-#define Tx_flowOff 0x04
-#define Tx_enable 0x08
-#define CTS_state 0x10
-#define DSR_state 0x20
-#define DCD_state 0x80
-/*
- * FlowControl
- */
-#define CTS_FlowCtl 1
-#define RTS_FlowCtl 2
-#define Tx_FlowCtl 4
-#define Rx_FlowCtl 8
-#define IXM_IXANY 0x10
-
-#define LowWater 128
-
-#define DTR_ON 1
-#define RTS_ON 2
-#define CTS_ON 1
-#define DSR_ON 2
-#define DCD_ON 8
-
-/* mode definition */
-#define MX_CS8 0x03
-#define MX_CS7 0x02
-#define MX_CS6 0x01
-#define MX_CS5 0x00
-
-#define MX_STOP1 0x00
-#define MX_STOP15 0x04
-#define MX_STOP2 0x08
-
-#define MX_PARNONE 0x00
-#define MX_PAREVEN 0x40
-#define MX_PARODD 0xC0
-#define MX_PARMARK 0xA0
-#define MX_PARSPACE 0x20
-
-#define MOXA_FW_HDRLEN 32
-
-#define MOXAMAJOR 172
-
-#define MAX_BOARDS 4 /* Don't change this value */
-#define MAX_PORTS_PER_BOARD 32 /* Don't change this value */
-#define MAX_PORTS (MAX_BOARDS * MAX_PORTS_PER_BOARD)
-
-#define MOXA_IS_320(brd) ((brd)->boardType == MOXA_BOARD_C320_PCI)
-
-enum {
- MOXA_BOARD_C218_PCI = 1,
- MOXA_BOARD_C320_PCI,
- MOXA_BOARD_CP204J,
-};
-
-static char *moxa_brdname[] =
-{
- "C218 Turbo PCI series",
- "C320 Turbo PCI series",
- "CP-204J series",
-};
-
-static const struct pci_device_id moxa_pcibrds[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C218),
- .driver_data = MOXA_BOARD_C218_PCI },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C320),
- .driver_data = MOXA_BOARD_C320_PCI },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP204J),
- .driver_data = MOXA_BOARD_CP204J },
- { 0 }
-};
-MODULE_DEVICE_TABLE(pci, moxa_pcibrds);
-
-struct moxa_port;
-
-static struct moxa_board_conf {
- int boardType;
- int numPorts;
-
- unsigned int ready;
-
- struct moxa_port *ports;
-
- void __iomem *basemem;
- void __iomem *intNdx;
- void __iomem *intPend;
- void __iomem *intTable;
-} moxa_boards[MAX_BOARDS];
-
-struct moxa_port {
- struct tty_port port;
- struct moxa_board_conf *board;
- void __iomem *tableAddr;
-
- int type;
- int cflag;
- unsigned long statusflags;
-
- u8 DCDState; /* Protected by the port lock */
- u8 lineCtrl;
- u8 lowChkFlag;
-};
-
-/* statusflags */
-#define TXSTOPPED 1
-#define LOWWAIT 2
-#define EMPTYWAIT 3
-
-
-#define WAKEUP_CHARS 256
-
-static int ttymajor = MOXAMAJOR;
-static unsigned int moxaFuncTout = HZ / 2;
-static unsigned int moxaLowWaterChk;
-static DEFINE_MUTEX(moxa_openlock);
-static DEFINE_SPINLOCK(moxa_lock);
-
-MODULE_AUTHOR("William Chen");
-MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver");
-MODULE_LICENSE("GPL");
-MODULE_FIRMWARE("c218tunx.cod");
-MODULE_FIRMWARE("cp204unx.cod");
-MODULE_FIRMWARE("c320tunx.cod");
-
-module_param(ttymajor, int, 0);
-
-/*
- * static functions:
- */
-static int moxa_open(struct tty_struct *, struct file *);
-static void moxa_close(struct tty_struct *, struct file *);
-static ssize_t moxa_write(struct tty_struct *, const u8 *, size_t);
-static unsigned int moxa_write_room(struct tty_struct *);
-static void moxa_flush_buffer(struct tty_struct *);
-static unsigned int moxa_chars_in_buffer(struct tty_struct *);
-static void moxa_set_termios(struct tty_struct *, const struct ktermios *);
-static void moxa_stop(struct tty_struct *);
-static void moxa_start(struct tty_struct *);
-static void moxa_hangup(struct tty_struct *);
-static int moxa_tiocmget(struct tty_struct *tty);
-static int moxa_tiocmset(struct tty_struct *tty,
- unsigned int set, unsigned int clear);
-static void moxa_poll(struct timer_list *);
-static void moxa_set_tty_param(struct tty_struct *, const struct ktermios *);
-static void moxa_shutdown(struct tty_port *);
-static bool moxa_carrier_raised(struct tty_port *);
-static void moxa_dtr_rts(struct tty_port *, bool);
-/*
- * moxa board interface functions:
- */
-static void MoxaPortEnable(struct moxa_port *);
-static void MoxaPortDisable(struct moxa_port *);
-static int MoxaPortSetTermio(struct moxa_port *, struct ktermios *, speed_t);
-static int MoxaPortGetLineOut(struct moxa_port *, bool *, bool *);
-static void MoxaPortLineCtrl(struct moxa_port *, bool, bool);
-static void MoxaPortFlowCtrl(struct moxa_port *, int, int, int, int, int);
-static int MoxaPortLineStatus(struct moxa_port *);
-static void MoxaPortFlushData(struct moxa_port *, int);
-static ssize_t MoxaPortWriteData(struct tty_struct *, const u8 *, size_t);
-static int MoxaPortReadData(struct moxa_port *);
-static unsigned int MoxaPortTxQueue(struct moxa_port *);
-static int MoxaPortRxQueue(struct moxa_port *);
-static unsigned int MoxaPortTxFree(struct moxa_port *);
-static void MoxaPortTxDisable(struct moxa_port *);
-static void MoxaPortTxEnable(struct moxa_port *);
-static int moxa_get_serial_info(struct tty_struct *, struct serial_struct *);
-static int moxa_set_serial_info(struct tty_struct *, struct serial_struct *);
-static void MoxaSetFifo(struct moxa_port *port, int enable);
-
-/*
- * I/O functions
- */
-
-static DEFINE_SPINLOCK(moxafunc_lock);
-
-static void moxa_wait_finish(void __iomem *ofsAddr)
-{
- unsigned long end = jiffies + moxaFuncTout;
-
- while (readw(ofsAddr + FuncCode) != 0)
- if (time_after(jiffies, end))
- return;
- if (readw(ofsAddr + FuncCode) != 0)
- printk_ratelimited(KERN_WARNING "moxa function expired\n");
-}
-
-static void moxafunc(void __iomem *ofsAddr, u16 cmd, u16 arg)
-{
- guard(spinlock_irqsave)(&moxafunc_lock);
- writew(arg, ofsAddr + FuncArg);
- writew(cmd, ofsAddr + FuncCode);
- moxa_wait_finish(ofsAddr);
-}
-
-static int moxafuncret(void __iomem *ofsAddr, u16 cmd, u16 arg)
-{
- guard(spinlock_irqsave)(&moxafunc_lock);
- writew(arg, ofsAddr + FuncArg);
- writew(cmd, ofsAddr + FuncCode);
- moxa_wait_finish(ofsAddr);
-
- return readw(ofsAddr + FuncArg);
-}
-
-static void moxa_low_water_check(void __iomem *ofsAddr)
-{
- u16 rptr, wptr, mask, len;
-
- if (readb(ofsAddr + FlagStat) & Xoff_state) {
- rptr = readw(ofsAddr + RXrptr);
- wptr = readw(ofsAddr + RXwptr);
- mask = readw(ofsAddr + RX_mask);
- len = (wptr - rptr) & mask;
- if (len <= Low_water)
- moxafunc(ofsAddr, FC_SendXon, 0);
- }
-}
-
-/*
- * TTY operations
- */
-
-static int moxa_break_ctl(struct tty_struct *tty, int state)
-{
- struct moxa_port *port = tty->driver_data;
-
- moxafunc(port->tableAddr, state ? FC_SendBreak : FC_StopBreak,
- Magic_code);
- return 0;
-}
-
-static const struct tty_operations moxa_ops = {
- .open = moxa_open,
- .close = moxa_close,
- .write = moxa_write,
- .write_room = moxa_write_room,
- .flush_buffer = moxa_flush_buffer,
- .chars_in_buffer = moxa_chars_in_buffer,
- .set_termios = moxa_set_termios,
- .stop = moxa_stop,
- .start = moxa_start,
- .hangup = moxa_hangup,
- .break_ctl = moxa_break_ctl,
- .tiocmget = moxa_tiocmget,
- .tiocmset = moxa_tiocmset,
- .set_serial = moxa_set_serial_info,
- .get_serial = moxa_get_serial_info,
-};
-
-static const struct tty_port_operations moxa_port_ops = {
- .carrier_raised = moxa_carrier_raised,
- .dtr_rts = moxa_dtr_rts,
- .shutdown = moxa_shutdown,
-};
-
-static struct tty_driver *moxaDriver;
-static DEFINE_TIMER(moxaTimer, moxa_poll);
-
-/*
- * HW init
- */
-
-static int moxa_check_fw_model(struct moxa_board_conf *brd, u8 model)
-{
- switch (brd->boardType) {
- case MOXA_BOARD_C218_PCI:
- if (model != 1)
- goto err;
- break;
- case MOXA_BOARD_CP204J:
- if (model != 3)
- goto err;
- break;
- default:
- if (model != 2)
- goto err;
- break;
- }
- return 0;
-err:
- return -EINVAL;
-}
-
-static int moxa_check_fw(const void *ptr)
-{
- const __le16 *lptr = ptr;
-
- if (*lptr != cpu_to_le16(0x7980))
- return -EINVAL;
-
- return 0;
-}
-
-static int moxa_load_bios(struct moxa_board_conf *brd, const u8 *buf,
- size_t len)
-{
- void __iomem *baseAddr = brd->basemem;
- u16 tmp;
-
- writeb(HW_reset, baseAddr + Control_reg); /* reset */
- msleep(10);
- memset_io(baseAddr, 0, 4096);
- memcpy_toio(baseAddr, buf, len); /* download BIOS */
- writeb(0, baseAddr + Control_reg); /* restart */
-
- msleep(2000);
-
- switch (brd->boardType) {
- case MOXA_BOARD_C218_PCI:
- tmp = readw(baseAddr + C218_key);
- if (tmp != C218_KeyCode)
- goto err;
- break;
- case MOXA_BOARD_CP204J:
- tmp = readw(baseAddr + C218_key);
- if (tmp != CP204J_KeyCode)
- goto err;
- break;
- default:
- tmp = readw(baseAddr + C320_key);
- if (tmp != C320_KeyCode)
- goto err;
- tmp = readw(baseAddr + C320_status);
- if (tmp != STS_init) {
- printk(KERN_ERR "MOXA: bios upload failed -- CPU/Basic "
- "module not found\n");
- return -EIO;
- }
- break;
- }
-
- return 0;
-err:
- printk(KERN_ERR "MOXA: bios upload failed -- board not found\n");
- return -EIO;
-}
-
-static int moxa_load_320b(struct moxa_board_conf *brd, const u8 *ptr,
- size_t len)
-{
- void __iomem *baseAddr = brd->basemem;
-
- if (len < 7168) {
- printk(KERN_ERR "MOXA: invalid 320 bios -- too short\n");
- return -EINVAL;
- }
-
- writew(len - 7168 - 2, baseAddr + C320bapi_len);
- writeb(1, baseAddr + Control_reg); /* Select Page 1 */
- memcpy_toio(baseAddr + DynPage_addr, ptr, 7168);
- writeb(2, baseAddr + Control_reg); /* Select Page 2 */
- memcpy_toio(baseAddr + DynPage_addr, ptr + 7168, len - 7168);
-
- return 0;
-}
-
-static int moxa_real_load_code(struct moxa_board_conf *brd, const void *ptr,
- size_t len)
-{
- void __iomem *baseAddr = brd->basemem;
- const __le16 *uptr = ptr;
- size_t wlen, len2, j;
- unsigned long key, loadbuf, loadlen, checksum, checksum_ok;
- unsigned int i, retry;
- u16 usum, keycode;
-
- keycode = (brd->boardType == MOXA_BOARD_CP204J) ? CP204J_KeyCode :
- C218_KeyCode;
-
- switch (brd->boardType) {
- case MOXA_BOARD_CP204J:
- case MOXA_BOARD_C218_PCI:
- key = C218_key;
- loadbuf = C218_LoadBuf;
- loadlen = C218DLoad_len;
- checksum = C218check_sum;
- checksum_ok = C218chksum_ok;
- break;
- default:
- key = C320_key;
- keycode = C320_KeyCode;
- loadbuf = C320_LoadBuf;
- loadlen = C320DLoad_len;
- checksum = C320check_sum;
- checksum_ok = C320chksum_ok;
- break;
- }
-
- usum = 0;
- wlen = len >> 1;
- for (i = 0; i < wlen; i++)
- usum += le16_to_cpu(uptr[i]);
- retry = 0;
- do {
- wlen = len >> 1;
- j = 0;
- while (wlen) {
- len2 = (wlen > 2048) ? 2048 : wlen;
- wlen -= len2;
- memcpy_toio(baseAddr + loadbuf, ptr + j, len2 << 1);
- j += len2 << 1;
-
- writew(len2, baseAddr + loadlen);
- writew(0, baseAddr + key);
- for (i = 0; i < 100; i++) {
- if (readw(baseAddr + key) == keycode)
- break;
- msleep(10);
- }
- if (readw(baseAddr + key) != keycode)
- return -EIO;
- }
- writew(0, baseAddr + loadlen);
- writew(usum, baseAddr + checksum);
- writew(0, baseAddr + key);
- for (i = 0; i < 100; i++) {
- if (readw(baseAddr + key) == keycode)
- break;
- msleep(10);
- }
- retry++;
- } while ((readb(baseAddr + checksum_ok) != 1) && (retry < 3));
- if (readb(baseAddr + checksum_ok) != 1)
- return -EIO;
-
- writew(0, baseAddr + key);
- for (i = 0; i < 600; i++) {
- if (readw(baseAddr + Magic_no) == Magic_code)
- break;
- msleep(10);
- }
- if (readw(baseAddr + Magic_no) != Magic_code)
- return -EIO;
-
- if (MOXA_IS_320(brd)) {
- writew(0x3800, baseAddr + TMS320_PORT1);
- writew(0x3900, baseAddr + TMS320_PORT2);
- writew(28499, baseAddr + TMS320_CLOCK);
- }
- writew(1, baseAddr + Disable_IRQ);
- writew(0, baseAddr + Magic_no);
- for (i = 0; i < 500; i++) {
- if (readw(baseAddr + Magic_no) == Magic_code)
- break;
- msleep(10);
- }
- if (readw(baseAddr + Magic_no) != Magic_code)
- return -EIO;
-
- if (MOXA_IS_320(brd)) {
- j = readw(baseAddr + Module_cnt);
- if (j <= 0)
- return -EIO;
- brd->numPorts = j * 8;
- writew(j, baseAddr + Module_no);
- writew(0, baseAddr + Magic_no);
- for (i = 0; i < 600; i++) {
- if (readw(baseAddr + Magic_no) == Magic_code)
- break;
- msleep(10);
- }
- if (readw(baseAddr + Magic_no) != Magic_code)
- return -EIO;
- }
- brd->intNdx = baseAddr + IRQindex;
- brd->intPend = baseAddr + IRQpending;
- brd->intTable = baseAddr + IRQtable;
-
- return 0;
-}
-
-static int moxa_load_code(struct moxa_board_conf *brd, const void *ptr,
- size_t len)
-{
- void __iomem *ofsAddr, *baseAddr = brd->basemem;
- struct moxa_port *port;
- int retval, i;
-
- if (len % 2) {
- printk(KERN_ERR "MOXA: bios length is not even\n");
- return -EINVAL;
- }
-
- retval = moxa_real_load_code(brd, ptr, len); /* may change numPorts */
- if (retval)
- return retval;
-
- switch (brd->boardType) {
- case MOXA_BOARD_C218_PCI:
- case MOXA_BOARD_CP204J:
- port = brd->ports;
- for (i = 0; i < brd->numPorts; i++, port++) {
- port->board = brd;
- port->DCDState = 0;
- port->tableAddr = baseAddr + Extern_table +
- Extern_size * i;
- ofsAddr = port->tableAddr;
- writew(C218rx_mask, ofsAddr + RX_mask);
- writew(C218tx_mask, ofsAddr + TX_mask);
- writew(C218rx_spage + i * C218buf_pageno, ofsAddr + Page_rxb);
- writew(readw(ofsAddr + Page_rxb) + C218rx_pageno, ofsAddr + EndPage_rxb);
-
- writew(C218tx_spage + i * C218buf_pageno, ofsAddr + Page_txb);
- writew(readw(ofsAddr + Page_txb) + C218tx_pageno, ofsAddr + EndPage_txb);
-
- }
- break;
- default:
- port = brd->ports;
- for (i = 0; i < brd->numPorts; i++, port++) {
- port->board = brd;
- port->DCDState = 0;
- port->tableAddr = baseAddr + Extern_table +
- Extern_size * i;
- ofsAddr = port->tableAddr;
- switch (brd->numPorts) {
- case 8:
- writew(C320p8rx_mask, ofsAddr + RX_mask);
- writew(C320p8tx_mask, ofsAddr + TX_mask);
- writew(C320p8rx_spage + i * C320p8buf_pgno, ofsAddr + Page_rxb);
- writew(readw(ofsAddr + Page_rxb) + C320p8rx_pgno, ofsAddr + EndPage_rxb);
- writew(C320p8tx_spage + i * C320p8buf_pgno, ofsAddr + Page_txb);
- writew(readw(ofsAddr + Page_txb) + C320p8tx_pgno, ofsAddr + EndPage_txb);
-
- break;
- case 16:
- writew(C320p16rx_mask, ofsAddr + RX_mask);
- writew(C320p16tx_mask, ofsAddr + TX_mask);
- writew(C320p16rx_spage + i * C320p16buf_pgno, ofsAddr + Page_rxb);
- writew(readw(ofsAddr + Page_rxb) + C320p16rx_pgno, ofsAddr + EndPage_rxb);
- writew(C320p16tx_spage + i * C320p16buf_pgno, ofsAddr + Page_txb);
- writew(readw(ofsAddr + Page_txb) + C320p16tx_pgno, ofsAddr + EndPage_txb);
- break;
-
- case 24:
- writew(C320p24rx_mask, ofsAddr + RX_mask);
- writew(C320p24tx_mask, ofsAddr + TX_mask);
- writew(C320p24rx_spage + i * C320p24buf_pgno, ofsAddr + Page_rxb);
- writew(readw(ofsAddr + Page_rxb) + C320p24rx_pgno, ofsAddr + EndPage_rxb);
- writew(C320p24tx_spage + i * C320p24buf_pgno, ofsAddr + Page_txb);
- writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb);
- break;
- case 32:
- writew(C320p32rx_mask, ofsAddr + RX_mask);
- writew(C320p32tx_mask, ofsAddr + TX_mask);
- writew(C320p32tx_ofs, ofsAddr + Ofs_txb);
- writew(C320p32rx_spage + i * C320p32buf_pgno, ofsAddr + Page_rxb);
- writew(readb(ofsAddr + Page_rxb), ofsAddr + EndPage_rxb);
- writew(C320p32tx_spage + i * C320p32buf_pgno, ofsAddr + Page_txb);
- writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb);
- break;
- }
- }
- break;
- }
- return 0;
-}
-
-static int moxa_load_fw(struct moxa_board_conf *brd, const struct firmware *fw)
-{
- const void *ptr = fw->data;
- char rsn[64];
- u16 lens[5];
- size_t len;
- unsigned int a, lenp, lencnt;
- int ret = -EINVAL;
- struct {
- __le32 magic; /* 0x34303430 */
- u8 reserved1[2];
- u8 type; /* UNIX = 3 */
- u8 model; /* C218T=1, C320T=2, CP204=3 */
- u8 reserved2[8];
- __le16 len[5];
- } const *hdr = ptr;
-
- BUILD_BUG_ON(ARRAY_SIZE(hdr->len) != ARRAY_SIZE(lens));
-
- if (fw->size < MOXA_FW_HDRLEN) {
- strcpy(rsn, "too short (even header won't fit)");
- goto err;
- }
- if (hdr->magic != cpu_to_le32(0x30343034)) {
- sprintf(rsn, "bad magic: %.8x", le32_to_cpu(hdr->magic));
- goto err;
- }
- if (hdr->type != 3) {
- sprintf(rsn, "not for linux, type is %u", hdr->type);
- goto err;
- }
- if (moxa_check_fw_model(brd, hdr->model)) {
- sprintf(rsn, "not for this card, model is %u", hdr->model);
- goto err;
- }
-
- len = MOXA_FW_HDRLEN;
- lencnt = hdr->model == 2 ? 5 : 3;
- for (a = 0; a < ARRAY_SIZE(lens); a++) {
- lens[a] = le16_to_cpu(hdr->len[a]);
- if (lens[a] && len + lens[a] <= fw->size &&
- moxa_check_fw(&fw->data[len]))
- printk(KERN_WARNING "MOXA firmware: unexpected input "
- "at offset %u, but going on\n", (u32)len);
- if (!lens[a] && a < lencnt) {
- sprintf(rsn, "too few entries in fw file");
- goto err;
- }
- len += lens[a];
- }
-
- if (len != fw->size) {
- sprintf(rsn, "bad length: %u (should be %u)", (u32)fw->size,
- (u32)len);
- goto err;
- }
-
- ptr += MOXA_FW_HDRLEN;
- lenp = 0; /* bios */
-
- strcpy(rsn, "read above");
-
- ret = moxa_load_bios(brd, ptr, lens[lenp]);
- if (ret)
- goto err;
-
- /* we skip the tty section (lens[1]), since we don't need it */
- ptr += lens[lenp] + lens[lenp + 1];
- lenp += 2; /* comm */
-
- if (hdr->model == 2) {
- ret = moxa_load_320b(brd, ptr, lens[lenp]);
- if (ret)
- goto err;
- /* skip another tty */
- ptr += lens[lenp] + lens[lenp + 1];
- lenp += 2;
- }
-
- ret = moxa_load_code(brd, ptr, lens[lenp]);
- if (ret)
- goto err;
-
- return 0;
-err:
- printk(KERN_ERR "firmware failed to load, reason: %s\n", rsn);
- return ret;
-}
-
-static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev)
-{
- const struct firmware *fw;
- const char *file;
- struct moxa_port *p;
- unsigned int i, first_idx;
- int ret;
-
- brd->ports = kzalloc_objs(*brd->ports, MAX_PORTS_PER_BOARD);
- if (brd->ports == NULL) {
- printk(KERN_ERR "cannot allocate memory for ports\n");
- ret = -ENOMEM;
- goto err;
- }
-
- for (i = 0, p = brd->ports; i < MAX_PORTS_PER_BOARD; i++, p++) {
- tty_port_init(&p->port);
- p->port.ops = &moxa_port_ops;
- p->type = PORT_16550A;
- p->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
- }
-
- switch (brd->boardType) {
- case MOXA_BOARD_C218_PCI:
- file = "c218tunx.cod";
- break;
- case MOXA_BOARD_CP204J:
- file = "cp204unx.cod";
- break;
- default:
- file = "c320tunx.cod";
- break;
- }
-
- ret = request_firmware(&fw, file, dev);
- if (ret) {
- printk(KERN_ERR "MOXA: request_firmware failed. Make sure "
- "you've placed '%s' file into your firmware "
- "loader directory (e.g. /lib/firmware)\n",
- file);
- goto err_free;
- }
-
- ret = moxa_load_fw(brd, fw);
-
- release_firmware(fw);
-
- if (ret)
- goto err_free;
-
- scoped_guard(spinlock_bh, &moxa_lock) {
- brd->ready = 1;
- if (!timer_pending(&moxaTimer))
- mod_timer(&moxaTimer, jiffies + HZ / 50);
- }
-
- first_idx = (brd - moxa_boards) * MAX_PORTS_PER_BOARD;
- for (i = 0; i < brd->numPorts; i++)
- tty_port_register_device(&brd->ports[i].port, moxaDriver,
- first_idx + i, dev);
-
- return 0;
-err_free:
- for (i = 0; i < MAX_PORTS_PER_BOARD; i++)
- tty_port_destroy(&brd->ports[i].port);
- kfree(brd->ports);
-err:
- return ret;
-}
-
-static void moxa_board_deinit(struct moxa_board_conf *brd)
-{
- unsigned int a, opened, first_idx;
-
- scoped_guard(mutex, &moxa_openlock) {
- scoped_guard(spinlock_bh, &moxa_lock)
- brd->ready = 0;
-
- /* pci hot-un-plug support */
- for (a = 0; a < brd->numPorts; a++)
- if (tty_port_initialized(&brd->ports[a].port))
- tty_port_tty_hangup(&brd->ports[a].port, false);
-
- for (a = 0; a < MAX_PORTS_PER_BOARD; a++)
- tty_port_destroy(&brd->ports[a].port);
-
- while (1) {
- opened = 0;
- for (a = 0; a < brd->numPorts; a++)
- if (tty_port_initialized(&brd->ports[a].port))
- opened++;
- if (!opened)
- break;
- mutex_unlock(&moxa_openlock);
- msleep(50);
- mutex_lock(&moxa_openlock);
- }
- }
-
- first_idx = (brd - moxa_boards) * MAX_PORTS_PER_BOARD;
- for (a = 0; a < brd->numPorts; a++)
- tty_unregister_device(moxaDriver, first_idx + a);
-
- iounmap(brd->basemem);
- brd->basemem = NULL;
- kfree(brd->ports);
-}
-
-static int moxa_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- struct moxa_board_conf *board;
- unsigned int i;
- int board_type = ent->driver_data;
- int retval;
-
- retval = pci_enable_device(pdev);
- if (retval) {
- dev_err(&pdev->dev, "can't enable pci device\n");
- goto err;
- }
-
- for (i = 0; i < MAX_BOARDS; i++)
- if (moxa_boards[i].basemem == NULL)
- break;
-
- retval = -ENODEV;
- if (i >= MAX_BOARDS) {
- dev_warn(&pdev->dev, "more than %u MOXA Intellio family boards "
- "found. Board is ignored.\n", MAX_BOARDS);
- goto err;
- }
-
- board = &moxa_boards[i];
-
- retval = pci_request_region(pdev, 2, "moxa-base");
- if (retval) {
- dev_err(&pdev->dev, "can't request pci region 2\n");
- goto err;
- }
-
- board->basemem = ioremap(pci_resource_start(pdev, 2), 0x4000);
- if (board->basemem == NULL) {
- dev_err(&pdev->dev, "can't remap io space 2\n");
- retval = -ENOMEM;
- goto err_reg;
- }
-
- board->boardType = board_type;
- switch (board_type) {
- case MOXA_BOARD_C218_PCI:
- board->numPorts = 8;
- break;
-
- case MOXA_BOARD_CP204J:
- board->numPorts = 4;
- break;
- default:
- board->numPorts = 0;
- break;
- }
-
- retval = moxa_init_board(board, &pdev->dev);
- if (retval)
- goto err_base;
-
- pci_set_drvdata(pdev, board);
-
- dev_info(&pdev->dev, "board '%s' ready (%u ports, firmware loaded)\n",
- moxa_brdname[board_type - 1], board->numPorts);
-
- return 0;
-err_base:
- iounmap(board->basemem);
- board->basemem = NULL;
-err_reg:
- pci_release_region(pdev, 2);
-err:
- return retval;
-}
-
-static void moxa_pci_remove(struct pci_dev *pdev)
-{
- struct moxa_board_conf *brd = pci_get_drvdata(pdev);
-
- moxa_board_deinit(brd);
-
- pci_release_region(pdev, 2);
-}
-
-static struct pci_driver moxa_pci_driver = {
- .name = "moxa",
- .id_table = moxa_pcibrds,
- .probe = moxa_pci_probe,
- .remove = moxa_pci_remove
-};
-
-static int __init moxa_init(void)
-{
- int retval = 0;
-
- moxaDriver = tty_alloc_driver(MAX_PORTS,
- TTY_DRIVER_REAL_RAW |
- TTY_DRIVER_DYNAMIC_DEV);
- if (IS_ERR(moxaDriver))
- return PTR_ERR(moxaDriver);
-
- moxaDriver->name = "ttyMX";
- moxaDriver->major = ttymajor;
- moxaDriver->minor_start = 0;
- moxaDriver->type = TTY_DRIVER_TYPE_SERIAL;
- moxaDriver->subtype = SERIAL_TYPE_NORMAL;
- moxaDriver->init_termios = tty_std_termios;
- moxaDriver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
- moxaDriver->init_termios.c_ispeed = 9600;
- moxaDriver->init_termios.c_ospeed = 9600;
- tty_set_operations(moxaDriver, &moxa_ops);
-
- if (tty_register_driver(moxaDriver)) {
- printk(KERN_ERR "can't register MOXA Smartio tty driver!\n");
- tty_driver_kref_put(moxaDriver);
- return -1;
- }
-
- retval = pci_register_driver(&moxa_pci_driver);
- if (retval)
- printk(KERN_ERR "Can't register MOXA pci driver!\n");
-
- return retval;
-}
-
-static void __exit moxa_exit(void)
-{
- pci_unregister_driver(&moxa_pci_driver);
-
- timer_delete_sync(&moxaTimer);
-
- tty_unregister_driver(moxaDriver);
- tty_driver_kref_put(moxaDriver);
-}
-
-module_init(moxa_init);
-module_exit(moxa_exit);
-
-static void moxa_shutdown(struct tty_port *port)
-{
- struct moxa_port *ch = container_of(port, struct moxa_port, port);
- MoxaPortDisable(ch);
- MoxaPortFlushData(ch, 2);
-}
-
-static bool moxa_carrier_raised(struct tty_port *port)
-{
- struct moxa_port *ch = container_of(port, struct moxa_port, port);
-
- guard(spinlock_irq)(&port->lock);
- return ch->DCDState;
-}
-
-static void moxa_dtr_rts(struct tty_port *port, bool active)
-{
- struct moxa_port *ch = container_of(port, struct moxa_port, port);
- MoxaPortLineCtrl(ch, active, active);
-}
-
-
-static int moxa_open(struct tty_struct *tty, struct file *filp)
-{
- struct moxa_board_conf *brd;
- struct moxa_port *ch;
- int port = tty->index;
-
- scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &moxa_openlock) {
- brd = &moxa_boards[port / MAX_PORTS_PER_BOARD];
- if (!brd->ready)
- return -ENODEV;
-
- if (port % MAX_PORTS_PER_BOARD >= brd->numPorts)
- return -ENODEV;
-
- ch = &brd->ports[port % MAX_PORTS_PER_BOARD];
- ch->port.count++;
- tty->driver_data = ch;
- tty_port_tty_set(&ch->port, tty);
-
- guard(mutex)(&ch->port.mutex);
- if (!tty_port_initialized(&ch->port)) {
- ch->statusflags = 0;
- moxa_set_tty_param(tty, &tty->termios);
- MoxaPortLineCtrl(ch, true, true);
- MoxaPortEnable(ch);
- MoxaSetFifo(ch, ch->type == PORT_16550A);
- tty_port_set_initialized(&ch->port, true);
- }
- }
-
- return tty_port_block_til_ready(&ch->port, tty, filp);
-}
-
-static void moxa_close(struct tty_struct *tty, struct file *filp)
-{
- struct moxa_port *ch = tty->driver_data;
- ch->cflag = tty->termios.c_cflag;
- tty_port_close(&ch->port, tty, filp);
-}
-
-static ssize_t moxa_write(struct tty_struct *tty, const u8 *buf, size_t count)
-{
- struct moxa_port *ch = tty->driver_data;
- int len;
-
- if (ch == NULL)
- return 0;
-
- scoped_guard(spinlock_irqsave, &moxa_lock)
- len = MoxaPortWriteData(tty, buf, count);
-
- set_bit(LOWWAIT, &ch->statusflags);
- return len;
-}
-
-static unsigned int moxa_write_room(struct tty_struct *tty)
-{
- struct moxa_port *ch;
-
- if (tty->flow.stopped)
- return 0;
- ch = tty->driver_data;
- if (ch == NULL)
- return 0;
- return MoxaPortTxFree(ch);
-}
-
-static void moxa_flush_buffer(struct tty_struct *tty)
-{
- struct moxa_port *ch = tty->driver_data;
-
- if (ch == NULL)
- return;
- MoxaPortFlushData(ch, 1);
- tty_wakeup(tty);
-}
-
-static unsigned int moxa_chars_in_buffer(struct tty_struct *tty)
-{
- struct moxa_port *ch = tty->driver_data;
- unsigned int chars;
-
- chars = MoxaPortTxQueue(ch);
- if (chars)
- /*
- * Make it possible to wakeup anything waiting for output
- * in tty_ioctl.c, etc.
- */
- set_bit(EMPTYWAIT, &ch->statusflags);
- return chars;
-}
-
-static int moxa_tiocmget(struct tty_struct *tty)
-{
- struct moxa_port *ch = tty->driver_data;
- bool dtr_active, rts_active;
- int flag = 0;
- int status;
-
- MoxaPortGetLineOut(ch, &dtr_active, &rts_active);
- if (dtr_active)
- flag |= TIOCM_DTR;
- if (rts_active)
- flag |= TIOCM_RTS;
- status = MoxaPortLineStatus(ch);
- if (status & 1)
- flag |= TIOCM_CTS;
- if (status & 2)
- flag |= TIOCM_DSR;
- if (status & 4)
- flag |= TIOCM_CD;
- return flag;
-}
-
-static int moxa_tiocmset(struct tty_struct *tty,
- unsigned int set, unsigned int clear)
-{
- bool dtr_active, rts_active;
- struct moxa_port *ch;
-
- guard(mutex)(&moxa_openlock);
- ch = tty->driver_data;
- if (!ch)
- return -EINVAL;
-
- MoxaPortGetLineOut(ch, &dtr_active, &rts_active);
- if (set & TIOCM_RTS)
- rts_active = true;
- if (set & TIOCM_DTR)
- dtr_active = true;
- if (clear & TIOCM_RTS)
- rts_active = false;
- if (clear & TIOCM_DTR)
- dtr_active = false;
- MoxaPortLineCtrl(ch, dtr_active, rts_active);
-
- return 0;
-}
-
-static void moxa_set_termios(struct tty_struct *tty,
- const struct ktermios *old_termios)
-{
- struct moxa_port *ch = tty->driver_data;
-
- if (ch == NULL)
- return;
- moxa_set_tty_param(tty, old_termios);
- if (!(old_termios->c_cflag & CLOCAL) && C_CLOCAL(tty))
- wake_up_interruptible(&ch->port.open_wait);
-}
-
-static void moxa_stop(struct tty_struct *tty)
-{
- struct moxa_port *ch = tty->driver_data;
-
- if (ch == NULL)
- return;
- MoxaPortTxDisable(ch);
- set_bit(TXSTOPPED, &ch->statusflags);
-}
-
-
-static void moxa_start(struct tty_struct *tty)
-{
- struct moxa_port *ch = tty->driver_data;
-
- if (ch == NULL)
- return;
-
- if (!test_bit(TXSTOPPED, &ch->statusflags))
- return;
-
- MoxaPortTxEnable(ch);
- clear_bit(TXSTOPPED, &ch->statusflags);
-}
-
-static void moxa_hangup(struct tty_struct *tty)
-{
- struct moxa_port *ch = tty->driver_data;
- tty_port_hangup(&ch->port);
-}
-
-static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
-{
- dcd = !!dcd;
-
- scoped_guard(spinlock_irqsave, &p->port.lock) {
- if (dcd == p->DCDState)
- return;
-
- p->DCDState = dcd;
- }
-
- if (!dcd)
- tty_port_tty_hangup(&p->port, true);
-}
-
-static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
- u16 __iomem *ip)
-{
- struct tty_struct *tty = tty_port_tty_get(&p->port);
- bool inited = tty_port_initialized(&p->port);
- void __iomem *ofsAddr;
- u16 intr;
-
- if (tty) {
- if (test_bit(EMPTYWAIT, &p->statusflags) &&
- MoxaPortTxQueue(p) == 0) {
- clear_bit(EMPTYWAIT, &p->statusflags);
- tty_wakeup(tty);
- }
- if (test_bit(LOWWAIT, &p->statusflags) && !tty->flow.stopped &&
- MoxaPortTxQueue(p) <= WAKEUP_CHARS) {
- clear_bit(LOWWAIT, &p->statusflags);
- tty_wakeup(tty);
- }
-
- if (inited && !tty_throttled(tty) &&
- MoxaPortRxQueue(p) > 0) { /* RX */
- MoxaPortReadData(p);
- tty_flip_buffer_push(&p->port);
- }
- } else {
- clear_bit(EMPTYWAIT, &p->statusflags);
- MoxaPortFlushData(p, 0); /* flush RX */
- }
-
- if (!handle) /* nothing else to do */
- goto put;
-
- intr = readw(ip); /* port irq status */
- if (intr == 0)
- goto put;
-
- writew(0, ip); /* ACK port */
- ofsAddr = p->tableAddr;
- if (intr & IntrTx) /* disable tx intr */
- writew(readw(ofsAddr + HostStat) & ~WakeupTx,
- ofsAddr + HostStat);
-
- if (!inited)
- goto put;
-
- if (tty && (intr & IntrBreak) && !I_IGNBRK(tty)) { /* BREAK */
- tty_insert_flip_char(&p->port, 0, TTY_BREAK);
- tty_flip_buffer_push(&p->port);
- }
-
- if (intr & IntrLine)
- moxa_new_dcdstate(p, readb(ofsAddr + FlagStat) & DCD_state);
-put:
- tty_kref_put(tty);
-
- return 0;
-}
-
-static void moxa_poll(struct timer_list *unused)
-{
- struct moxa_board_conf *brd;
- u16 __iomem *ip;
- unsigned int card, port, served = 0;
-
- guard(spinlock)(&moxa_lock);
- for (card = 0; card < MAX_BOARDS; card++) {
- brd = &moxa_boards[card];
- if (!brd->ready)
- continue;
-
- served++;
-
- ip = NULL;
- if (readb(brd->intPend) == 0xff)
- ip = brd->intTable + readb(brd->intNdx);
-
- for (port = 0; port < brd->numPorts; port++)
- moxa_poll_port(&brd->ports[port], !!ip, ip + port);
-
- if (ip)
- writeb(0, brd->intPend); /* ACK */
-
- if (moxaLowWaterChk) {
- struct moxa_port *p = brd->ports;
- for (port = 0; port < brd->numPorts; port++, p++)
- if (p->lowChkFlag) {
- p->lowChkFlag = 0;
- moxa_low_water_check(p->tableAddr);
- }
- }
- }
- moxaLowWaterChk = 0;
-
- if (served)
- mod_timer(&moxaTimer, jiffies + HZ / 50);
-}
-
-/******************************************************************************/
-
-static void moxa_set_tty_param(struct tty_struct *tty,
- const struct ktermios *old_termios)
-{
- register struct ktermios *ts = &tty->termios;
- struct moxa_port *ch = tty->driver_data;
- int rts, cts, txflow, rxflow, xany, baud;
-
- rts = cts = txflow = rxflow = xany = 0;
- if (ts->c_cflag & CRTSCTS)
- rts = cts = 1;
- if (ts->c_iflag & IXON)
- txflow = 1;
- if (ts->c_iflag & IXOFF)
- rxflow = 1;
- if (ts->c_iflag & IXANY)
- xany = 1;
-
- MoxaPortFlowCtrl(ch, rts, cts, txflow, rxflow, xany);
- baud = MoxaPortSetTermio(ch, ts, tty_get_baud_rate(tty));
- if (baud == -1)
- baud = tty_termios_baud_rate(old_termios);
- /* Not put the baud rate into the termios data */
- tty_encode_baud_rate(tty, baud, baud);
-}
-
-/*****************************************************************************
- * Driver level functions: *
- *****************************************************************************/
-
-static void MoxaPortFlushData(struct moxa_port *port, int mode)
-{
- void __iomem *ofsAddr;
- if (mode < 0 || mode > 2)
- return;
- ofsAddr = port->tableAddr;
- moxafunc(ofsAddr, FC_FlushQueue, mode);
- if (mode != 1) {
- port->lowChkFlag = 0;
- moxa_low_water_check(ofsAddr);
- }
-}
-
-/*
- * Moxa Port Number Description:
- *
- * MOXA serial driver supports up to 4 MOXA-C218/C320 boards. And,
- * the port number using in MOXA driver functions will be 0 to 31 for
- * first MOXA board, 32 to 63 for second, 64 to 95 for third and 96
- * to 127 for fourth. For example, if you setup three MOXA boards,
- * first board is C218, second board is C320-16 and third board is
- * C320-32. The port number of first board (C218 - 8 ports) is from
- * 0 to 7. The port number of second board (C320 - 16 ports) is form
- * 32 to 47. The port number of third board (C320 - 32 ports) is from
- * 64 to 95. And those port numbers form 8 to 31, 48 to 63 and 96 to
- * 127 will be invalid.
- *
- *
- * Moxa Functions Description:
- *
- * Function 1: Driver initialization routine, this routine must be
- * called when initialized driver.
- * Syntax:
- * void MoxaDriverInit();
- *
- *
- * Function 2: Moxa driver private IOCTL command processing.
- * Syntax:
- * int MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port);
- *
- * unsigned int cmd : IOCTL command
- * unsigned long arg : IOCTL argument
- * int port : port number (0 - 127)
- *
- * return: 0 (OK)
- * -EINVAL
- * -ENOIOCTLCMD
- *
- *
- * Function 6: Enable this port to start Tx/Rx data.
- * Syntax:
- * void MoxaPortEnable(int port);
- * int port : port number (0 - 127)
- *
- *
- * Function 7: Disable this port
- * Syntax:
- * void MoxaPortDisable(int port);
- * int port : port number (0 - 127)
- *
- *
- * Function 10: Setting baud rate of this port.
- * Syntax:
- * speed_t MoxaPortSetBaud(int port, speed_t baud);
- * int port : port number (0 - 127)
- * long baud : baud rate (50 - 115200)
- *
- * return: 0 : this port is invalid or baud < 50
- * 50 - 115200 : the real baud rate set to the port, if
- * the argument baud is large than maximun
- * available baud rate, the real setting
- * baud rate will be the maximun baud rate.
- *
- *
- * Function 12: Configure the port.
- * Syntax:
- * int MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud);
- * int port : port number (0 - 127)
- * struct ktermios * termio : termio structure pointer
- * speed_t baud : baud rate
- *
- * return: -1 : this port is invalid or termio == NULL
- * 0 : setting O.K.
- *
- *
- * Function 13: Get the DTR/RTS state of this port.
- * Syntax:
- * int MoxaPortGetLineOut(int port, bool *dtrState, bool *rtsState);
- * int port : port number (0 - 127)
- * bool * dtr_active : pointer to bool to receive the current DTR
- * state. (if NULL, this function will not
- * write to this address)
- * bool * rts_active : pointer to bool to receive the current RTS
- * state. (if NULL, this function will not
- * write to this address)
- *
- * return: -1 : this port is invalid
- * 0 : O.K.
- *
- *
- * Function 14: Setting the DTR/RTS output state of this port.
- * Syntax:
- * void MoxaPortLineCtrl(int port, bool dtrState, bool rtsState);
- * int port : port number (0 - 127)
- * bool dtr_active : DTR output state
- * bool rts_active : RTS output state
- *
- *
- * Function 15: Setting the flow control of this port.
- * Syntax:
- * void MoxaPortFlowCtrl(int port, int rtsFlow, int ctsFlow, int rxFlow,
- * int txFlow,int xany);
- * int port : port number (0 - 127)
- * int rtsFlow : H/W RTS flow control (0: no, 1: yes)
- * int ctsFlow : H/W CTS flow control (0: no, 1: yes)
- * int rxFlow : S/W Rx XON/XOFF flow control (0: no, 1: yes)
- * int txFlow : S/W Tx XON/XOFF flow control (0: no, 1: yes)
- * int xany : S/W XANY flow control (0: no, 1: yes)
- *
- *
- * Function 16: Get ths line status of this port
- * Syntax:
- * int MoxaPortLineStatus(int port);
- * int port : port number (0 - 127)
- *
- * return: Bit 0 - CTS state (0: off, 1: on)
- * Bit 1 - DSR state (0: off, 1: on)
- * Bit 2 - DCD state (0: off, 1: on)
- *
- *
- * Function 19: Flush the Rx/Tx buffer data of this port.
- * Syntax:
- * void MoxaPortFlushData(int port, int mode);
- * int port : port number (0 - 127)
- * int mode
- * 0 : flush the Rx buffer
- * 1 : flush the Tx buffer
- * 2 : flush the Rx and Tx buffer
- *
- *
- * Function 20: Write data.
- * Syntax:
- * ssize_t MoxaPortWriteData(int port, u8 *buffer, size_t length);
- * int port : port number (0 - 127)
- * u8 *buffer : pointer to write data buffer.
- * size_t length : write data length
- *
- * return: 0 - length : real write data length
- *
- *
- * Function 21: Read data.
- * Syntax:
- * int MoxaPortReadData(int port, struct tty_struct *tty);
- * int port : port number (0 - 127)
- * struct tty_struct *tty : tty for data
- *
- * return: 0 - length : real read data length
- *
- *
- * Function 24: Get the Tx buffer current queued data bytes
- * Syntax:
- * int MoxaPortTxQueue(int port);
- * int port : port number (0 - 127)
- *
- * return: .. : Tx buffer current queued data bytes
- *
- *
- * Function 25: Get the Tx buffer current free space
- * Syntax:
- * int MoxaPortTxFree(int port);
- * int port : port number (0 - 127)
- *
- * return: .. : Tx buffer current free space
- *
- *
- * Function 26: Get the Rx buffer current queued data bytes
- * Syntax:
- * int MoxaPortRxQueue(int port);
- * int port : port number (0 - 127)
- *
- * return: .. : Rx buffer current queued data bytes
- *
- *
- * Function 28: Disable port data transmission.
- * Syntax:
- * void MoxaPortTxDisable(int port);
- * int port : port number (0 - 127)
- *
- *
- * Function 29: Enable port data transmission.
- * Syntax:
- * void MoxaPortTxEnable(int port);
- * int port : port number (0 - 127)
- *
- *
- * Function 31: Get the received BREAK signal count and reset it.
- * Syntax:
- * int MoxaPortResetBrkCnt(int port);
- * int port : port number (0 - 127)
- *
- * return: 0 - .. : BREAK signal count
- *
- *
- */
-
-static void MoxaPortEnable(struct moxa_port *port)
-{
- void __iomem *ofsAddr;
- u16 lowwater = 512;
-
- ofsAddr = port->tableAddr;
- writew(lowwater, ofsAddr + Low_water);
- if (MOXA_IS_320(port->board))
- moxafunc(ofsAddr, FC_SetBreakIrq, 0);
- else
- writew(readw(ofsAddr + HostStat) | WakeupBreak,
- ofsAddr + HostStat);
-
- moxafunc(ofsAddr, FC_SetLineIrq, Magic_code);
- moxafunc(ofsAddr, FC_FlushQueue, 2);
-
- moxafunc(ofsAddr, FC_EnableCH, Magic_code);
- MoxaPortLineStatus(port);
-}
-
-static void MoxaPortDisable(struct moxa_port *port)
-{
- void __iomem *ofsAddr = port->tableAddr;
-
- moxafunc(ofsAddr, FC_SetFlowCtl, 0); /* disable flow control */
- moxafunc(ofsAddr, FC_ClrLineIrq, Magic_code);
- writew(0, ofsAddr + HostStat);
- moxafunc(ofsAddr, FC_DisableCH, Magic_code);
-}
-
-static speed_t MoxaPortSetBaud(struct moxa_port *port, speed_t baud)
-{
- void __iomem *ofsAddr = port->tableAddr;
- unsigned int clock, val;
- speed_t max;
-
- max = MOXA_IS_320(port->board) ? 460800 : 921600;
- if (baud < 50)
- return 0;
- if (baud > max)
- baud = max;
- clock = 921600;
- val = clock / baud;
- moxafunc(ofsAddr, FC_SetBaud, val);
- baud = clock / val;
- return baud;
-}
-
-static int MoxaPortSetTermio(struct moxa_port *port, struct ktermios *termio,
- speed_t baud)
-{
- void __iomem *ofsAddr;
- tcflag_t mode = 0;
-
- ofsAddr = port->tableAddr;
-
- mode = termio->c_cflag & CSIZE;
- if (mode == CS5)
- mode = MX_CS5;
- else if (mode == CS6)
- mode = MX_CS6;
- else if (mode == CS7)
- mode = MX_CS7;
- else if (mode == CS8)
- mode = MX_CS8;
-
- if (termio->c_cflag & CSTOPB) {
- if (mode == MX_CS5)
- mode |= MX_STOP15;
- else
- mode |= MX_STOP2;
- } else
- mode |= MX_STOP1;
-
- if (termio->c_cflag & PARENB) {
- if (termio->c_cflag & PARODD) {
- if (termio->c_cflag & CMSPAR)
- mode |= MX_PARMARK;
- else
- mode |= MX_PARODD;
- } else {
- if (termio->c_cflag & CMSPAR)
- mode |= MX_PARSPACE;
- else
- mode |= MX_PAREVEN;
- }
- } else
- mode |= MX_PARNONE;
-
- moxafunc(ofsAddr, FC_SetDataMode, (u16)mode);
-
- if (MOXA_IS_320(port->board) && baud >= 921600)
- return -1;
-
- baud = MoxaPortSetBaud(port, baud);
-
- if (termio->c_iflag & (IXON | IXOFF | IXANY)) {
- guard(spinlock_irq)(&moxafunc_lock);
- writeb(termio->c_cc[VSTART], ofsAddr + FuncArg);
- writeb(termio->c_cc[VSTOP], ofsAddr + FuncArg1);
- writeb(FC_SetXonXoff, ofsAddr + FuncCode);
- moxa_wait_finish(ofsAddr);
- }
- return baud;
-}
-
-static int MoxaPortGetLineOut(struct moxa_port *port, bool *dtr_active,
- bool *rts_active)
-{
- if (dtr_active)
- *dtr_active = port->lineCtrl & DTR_ON;
- if (rts_active)
- *rts_active = port->lineCtrl & RTS_ON;
-
- return 0;
-}
-
-static void MoxaPortLineCtrl(struct moxa_port *port, bool dtr_active, bool rts_active)
-{
- u8 mode = 0;
-
- if (dtr_active)
- mode |= DTR_ON;
- if (rts_active)
- mode |= RTS_ON;
- port->lineCtrl = mode;
- moxafunc(port->tableAddr, FC_LineControl, mode);
-}
-
-static void MoxaPortFlowCtrl(struct moxa_port *port, int rts, int cts,
- int txflow, int rxflow, int txany)
-{
- int mode = 0;
-
- if (rts)
- mode |= RTS_FlowCtl;
- if (cts)
- mode |= CTS_FlowCtl;
- if (txflow)
- mode |= Tx_FlowCtl;
- if (rxflow)
- mode |= Rx_FlowCtl;
- if (txany)
- mode |= IXM_IXANY;
- moxafunc(port->tableAddr, FC_SetFlowCtl, mode);
-}
-
-static int MoxaPortLineStatus(struct moxa_port *port)
-{
- void __iomem *ofsAddr;
- int val;
-
- ofsAddr = port->tableAddr;
- if (MOXA_IS_320(port->board))
- val = moxafuncret(ofsAddr, FC_LineStatus, 0);
- else
- val = readw(ofsAddr + FlagStat) >> 4;
- val &= 0x0B;
- if (val & 8)
- val |= 4;
- moxa_new_dcdstate(port, val & 8);
- val &= 7;
- return val;
-}
-
-static ssize_t MoxaPortWriteData(struct tty_struct *tty, const u8 *buffer,
- size_t len)
-{
- struct moxa_port *port = tty->driver_data;
- void __iomem *baseAddr, *ofsAddr, *ofs;
- size_t c, total;
- u16 head, tail, tx_mask, spage, epage;
- u16 pageno, pageofs, bufhead;
-
- ofsAddr = port->tableAddr;
- baseAddr = port->board->basemem;
- tx_mask = readw(ofsAddr + TX_mask);
- spage = readw(ofsAddr + Page_txb);
- epage = readw(ofsAddr + EndPage_txb);
- tail = readw(ofsAddr + TXwptr);
- head = readw(ofsAddr + TXrptr);
- c = (head > tail) ? (head - tail - 1) : (head - tail + tx_mask);
- if (c > len)
- c = len;
- total = c;
- if (spage == epage) {
- bufhead = readw(ofsAddr + Ofs_txb);
- writew(spage, baseAddr + Control_reg);
- while (c > 0) {
- if (head > tail)
- len = head - tail - 1;
- else
- len = tx_mask + 1 - tail;
- len = (c > len) ? len : c;
- ofs = baseAddr + DynPage_addr + bufhead + tail;
- memcpy_toio(ofs, buffer, len);
- buffer += len;
- tail = (tail + len) & tx_mask;
- c -= len;
- }
- } else {
- pageno = spage + (tail >> 13);
- pageofs = tail & Page_mask;
- while (c > 0) {
- len = Page_size - pageofs;
- if (len > c)
- len = c;
- writeb(pageno, baseAddr + Control_reg);
- ofs = baseAddr + DynPage_addr + pageofs;
- memcpy_toio(ofs, buffer, len);
- buffer += len;
- if (++pageno == epage)
- pageno = spage;
- pageofs = 0;
- c -= len;
- }
- tail = (tail + total) & tx_mask;
- }
- writew(tail, ofsAddr + TXwptr);
- writeb(1, ofsAddr + CD180TXirq); /* start to send */
- return total;
-}
-
-static int MoxaPortReadData(struct moxa_port *port)
-{
- void __iomem *baseAddr, *ofsAddr, *ofs;
- u8 *dst;
- unsigned int count, len, total;
- u16 tail, rx_mask, spage, epage;
- u16 pageno, pageofs, bufhead, head;
-
- ofsAddr = port->tableAddr;
- baseAddr = port->board->basemem;
- head = readw(ofsAddr + RXrptr);
- tail = readw(ofsAddr + RXwptr);
- rx_mask = readw(ofsAddr + RX_mask);
- spage = readw(ofsAddr + Page_rxb);
- epage = readw(ofsAddr + EndPage_rxb);
- count = (tail >= head) ? (tail - head) : (tail - head + rx_mask + 1);
- if (count == 0)
- return 0;
-
- total = count;
- if (spage == epage) {
- bufhead = readw(ofsAddr + Ofs_rxb);
- writew(spage, baseAddr + Control_reg);
- while (count > 0) {
- ofs = baseAddr + DynPage_addr + bufhead + head;
- len = (tail >= head) ? (tail - head) :
- (rx_mask + 1 - head);
- len = tty_prepare_flip_string(&port->port, &dst,
- min(len, count));
- memcpy_fromio(dst, ofs, len);
- head = (head + len) & rx_mask;
- count -= len;
- }
- } else {
- pageno = spage + (head >> 13);
- pageofs = head & Page_mask;
- while (count > 0) {
- writew(pageno, baseAddr + Control_reg);
- ofs = baseAddr + DynPage_addr + pageofs;
- len = tty_prepare_flip_string(&port->port, &dst,
- min(Page_size - pageofs, count));
- memcpy_fromio(dst, ofs, len);
-
- count -= len;
- pageofs = (pageofs + len) & Page_mask;
- if (pageofs == 0 && ++pageno == epage)
- pageno = spage;
- }
- head = (head + total) & rx_mask;
- }
- writew(head, ofsAddr + RXrptr);
- if (readb(ofsAddr + FlagStat) & Xoff_state) {
- moxaLowWaterChk = 1;
- port->lowChkFlag = 1;
- }
- return total;
-}
-
-
-static unsigned int MoxaPortTxQueue(struct moxa_port *port)
-{
- void __iomem *ofsAddr = port->tableAddr;
- u16 rptr, wptr, mask;
-
- rptr = readw(ofsAddr + TXrptr);
- wptr = readw(ofsAddr + TXwptr);
- mask = readw(ofsAddr + TX_mask);
- return (wptr - rptr) & mask;
-}
-
-static unsigned int MoxaPortTxFree(struct moxa_port *port)
-{
- void __iomem *ofsAddr = port->tableAddr;
- u16 rptr, wptr, mask;
-
- rptr = readw(ofsAddr + TXrptr);
- wptr = readw(ofsAddr + TXwptr);
- mask = readw(ofsAddr + TX_mask);
- return mask - ((wptr - rptr) & mask);
-}
-
-static int MoxaPortRxQueue(struct moxa_port *port)
-{
- void __iomem *ofsAddr = port->tableAddr;
- u16 rptr, wptr, mask;
-
- rptr = readw(ofsAddr + RXrptr);
- wptr = readw(ofsAddr + RXwptr);
- mask = readw(ofsAddr + RX_mask);
- return (wptr - rptr) & mask;
-}
-
-static void MoxaPortTxDisable(struct moxa_port *port)
-{
- moxafunc(port->tableAddr, FC_SetXoffState, Magic_code);
-}
-
-static void MoxaPortTxEnable(struct moxa_port *port)
-{
- moxafunc(port->tableAddr, FC_SetXonState, Magic_code);
-}
-
-static int moxa_get_serial_info(struct tty_struct *tty,
- struct serial_struct *ss)
-{
- struct moxa_port *info = tty->driver_data;
-
- if (!info)
- return -ENODEV;
- guard(mutex)(&info->port.mutex);
- ss->type = info->type;
- ss->line = info->port.tty->index;
- ss->flags = info->port.flags;
- ss->baud_base = 921600;
- ss->close_delay = jiffies_to_msecs(info->port.close_delay) / 10;
-
- return 0;
-}
-
-
-static int moxa_set_serial_info(struct tty_struct *tty,
- struct serial_struct *ss)
-{
- struct moxa_port *info = tty->driver_data;
- unsigned int close_delay;
-
- if (!info)
- return -ENODEV;
-
- close_delay = msecs_to_jiffies(ss->close_delay * 10);
-
- guard(mutex)(&info->port.mutex);
- if (!capable(CAP_SYS_ADMIN)) {
- if (close_delay != info->port.close_delay ||
- ss->type != info->type ||
- ((ss->flags & ~ASYNC_USR_MASK) !=
- (info->port.flags & ~ASYNC_USR_MASK))) {
- return -EPERM;
- }
- } else {
- info->port.close_delay = close_delay;
-
- MoxaSetFifo(info, ss->type == PORT_16550A);
-
- info->type = ss->type;
- }
-
- return 0;
-}
-
-
-
-/*****************************************************************************
- * Static local functions: *
- *****************************************************************************/
-
-static void MoxaSetFifo(struct moxa_port *port, int enable)
-{
- void __iomem *ofsAddr = port->tableAddr;
-
- if (!enable) {
- moxafunc(ofsAddr, FC_SetRxFIFOTrig, 0);
- moxafunc(ofsAddr, FC_SetTxFIFOCnt, 1);
- } else {
- moxafunc(ofsAddr, FC_SetRxFIFOTrig, 3);
- moxafunc(ofsAddr, FC_SetTxFIFOCnt, 16);
- }
-}
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index cc7f7091ed9a..9a37008c4e91 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -138,10 +138,7 @@ static int pty_set_lock(struct tty_struct *tty, int __user *arg)
if (get_user(val, arg))
return -EFAULT;
- if (val)
- set_bit(TTY_PTY_LOCK, &tty->flags);
- else
- clear_bit(TTY_PTY_LOCK, &tty->flags);
+ assign_bit(TTY_PTY_LOCK, &tty->flags, val);
return 0;
}
diff --git a/drivers/tty/serdev/serdev-ttyport.c b/drivers/tty/serdev/serdev-ttyport.c
index bab1b143b8a6..b6638f9f40d2 100644
--- a/drivers/tty/serdev/serdev-ttyport.c
+++ b/drivers/tty/serdev/serdev-ttyport.c
@@ -137,6 +137,7 @@ err_close:
err_unlock:
tty_unlock(tty);
tty_release_struct(tty, serport->tty_idx);
+ serport->tty = NULL;
return ret;
}
@@ -154,6 +155,7 @@ static void ttyport_close(struct serdev_controller *ctrl)
tty_unlock(tty);
tty_release_struct(tty, serport->tty_idx);
+ serport->tty = NULL;
}
static unsigned int ttyport_set_baudrate(struct serdev_controller *ctrl, unsigned int speed)
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index 9337fec9394e..21ed9c41b751 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -73,6 +73,12 @@ struct serial8250_config {
unsigned int flags;
};
+enum uart_port_type {
+ /* Internal 8250 only */
+ UART_PORT_AIROHA = 124,
+ UART_PORT_AIROHA_HS = 125,
+};
+
#define UART_CAP_FIFO BIT(8) /* UART has FIFO */
#define UART_CAP_EFR BIT(9) /* UART has EFR */
#define UART_CAP_SLEEP BIT(10) /* UART has IER sleep */
@@ -180,6 +186,7 @@ void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p);
void serial8250_fifo_wait_for_lsr_thre(struct uart_8250_port *up,
struct nbcon_write_context *wctxt,
unsigned int count);
+void serial8250_wait_for_xmitr(struct uart_8250_port *up, int bits);
void serial8250_rpm_get(struct uart_8250_port *p);
void serial8250_rpm_put(struct uart_8250_port *p);
@@ -316,6 +323,14 @@ static inline int serial8250_pnp_init(void) { return 0; }
static inline void serial8250_pnp_exit(void) { }
#endif
+#ifdef CONFIG_SERIAL_8250_HUB6
+int serial8250_hub6_init(void);
+void serial8250_hub6_exit(void);
+#else
+static inline int serial8250_hub6_init(void) { return 0; }
+static inline void serial8250_hub6_exit(void) { }
+#endif
+
#ifdef CONFIG_SERIAL_8250_RSA
void univ8250_rsa_support(struct uart_ops *ops, const struct uart_ops *core_ops);
void rsa_enable(struct uart_8250_port *up);
@@ -336,7 +351,7 @@ int fintek_8250_probe(struct uart_8250_port *uart);
static inline int fintek_8250_probe(struct uart_8250_port *uart) { return 0; }
#endif
-#if IS_REACHABLE(CONFIG_SERIAL_8250_HUB6)
+#if IS_ENABLED(CONFIG_SERIAL_8250_HUB6)
bool hub6_match_port(const struct uart_port *port1, const struct uart_port *port2);
#else
static inline bool hub6_match_port(const struct uart_port *port1, const struct uart_port *port2)
diff --git a/drivers/tty/serial/8250/8250_acorn.c b/drivers/tty/serial/8250/8250_acorn.c
index fb596262b9c7..d0696668493a 100644
--- a/drivers/tty/serial/8250/8250_acorn.c
+++ b/drivers/tty/serial/8250/8250_acorn.c
@@ -8,6 +8,7 @@
#include <linux/types.h>
#include <linux/tty.h>
#include <linux/serial_core.h>
+#include <linux/err.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/slab.h>
@@ -31,7 +32,7 @@ struct serial_card_type {
struct serial_card_info {
unsigned int num_ports;
- int ports[MAX_PORTS];
+ struct uart_8250_port *ports[MAX_PORTS];
void __iomem *vaddr;
};
@@ -85,7 +86,7 @@ static void serial_card_remove(struct expansion_card *ec)
ecard_set_drvdata(ec, NULL);
for (i = 0; i < info->num_ports; i++)
- if (info->ports[i] > 0)
+ if (!IS_ERR_OR_NULL(info->ports[i]))
serial8250_unregister_port(info->ports[i]);
kfree(info);
diff --git a/drivers/tty/serial/8250/8250_airoha.c b/drivers/tty/serial/8250/8250_airoha.c
new file mode 100644
index 000000000000..21f248e20771
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_airoha.c
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Airoha UART driver
+ *
+ * Copyright (c) 2025 Genexis Sweden AB
+ * Author: Benjamin Larsson <benjamin.larsson@genexis.eu>
+ * Christian Marangi <ansuelsmth@gmail.com>
+ */
+
+#include <linux/array_size.h>
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/platform_device.h>
+#include <linux/serial_8250.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+#include <linux/types.h>
+#include <linux/units.h>
+
+#include "8250.h"
+
+#define UART_AIROHA_XINCLKDR 10
+#define UART_AIROHA_XYD 11
+#define UART_AIROHA_XYD_X GENMASK(31, 16)
+#define UART_AIROHA_XYD_Y GENMASK(15, 0)
+
+#define UART_BRD_20M 0x0001
+
+#define XINDIV_CLOCK (20 * HZ_PER_MHZ)
+#define XYD_Y 65000
+
+static const unsigned int airoha_clk_divs[] = { 2, 4, 10 };
+
+static unsigned int airoha_get_divisor(struct uart_port *port,
+ unsigned int baud,
+ unsigned int *frac)
+{
+ /* Hardware always uses BRDIV = 1. */
+ *frac = 0;
+
+ return UART_BRD_20M;
+}
+
+/*
+ * Airoha UART baud rate calculation logic
+ *
+ * crystal_clock = 20 MHz (fixed frequency)
+ * xindiv_clock = crystal_clock / clock_div
+ * (x/y) = XYD, 32 bit register with 16 bits of x and then 16 bits of y
+ * clock_div = XINCLK_DIVCNT (default set to 10 (0x4)),
+ * - 3 bit register [ 1, 2, 4, 8, 10, 12, 16, 20 ]
+ *
+ * baud_rate = ((xindiv_clock) * (x/y)) / ([BRDH,BRDL] * 16)
+ *
+ * Selecting divider needs to fulfill
+ * 1.8432 MHz <= xindiv_clk <= APB clock / 2
+ * The clocks are unknown but a divider of value 1 did not result in a valid
+ * waveform.
+ *
+ * XYD_y seems to need to be larger then XYD_x for proper waveform generation.
+ * Setting [BRDH,BRDL] to [0,1] and XYD_y to 65000 gives even values
+ * for usual baud rates.
+ */
+static void airoha_set_divisor(struct uart_port *port, unsigned int baud,
+ unsigned int quot, unsigned int quot_frac)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+ u32 xindiv_clk;
+ u64 xyd_x, nom;
+ int div_bit;
+
+ /* Set baud rate calculation defaults (BRDIV [BRDH,BRDL] to 1) */
+ serial8250_do_set_divisor(port, baud, UART_BRD_20M);
+
+ /*
+ * Calculate XYD_x and XINCLKDR register by searching
+ * through a table of crystal_clock divisors.
+ */
+ nom = (u64)baud * XYD_Y;
+ for (div_bit = ARRAY_SIZE(airoha_clk_divs) - 1; div_bit >= 0; div_bit--) {
+ unsigned int div = airoha_clk_divs[div_bit];
+
+ xindiv_clk = XINDIV_CLOCK / div;
+ xyd_x = div_u64(nom * 16, xindiv_clk);
+
+ /* For the HSUART xyd_x needs to be scaled by a factor of 2 */
+ if (port->type == UART_PORT_AIROHA_HS)
+ xyd_x /= 2;
+
+ if (xyd_x < XYD_Y)
+ break;
+ }
+
+ /* Couldn't find a valid xyd_x */
+ if (div_bit < 0) {
+ dev_err(port->dev, "failed to find suitable clock divisor for baud %u\n",
+ baud);
+ return;
+ }
+
+ serial_port_out(port, UART_AIROHA_XINCLKDR, BIT(div_bit));
+ serial_port_out(port, UART_AIROHA_XYD,
+ FIELD_PREP(UART_AIROHA_XYD_X, xyd_x) |
+ FIELD_PREP(UART_AIROHA_XYD_Y, XYD_Y));
+
+ /* Restore normal register access. */
+ serial_port_out(port, UART_LCR, up->lcr);
+}
+
+static int airoha_8250_probe(struct platform_device *pdev)
+{
+ struct uart_8250_port uart = { };
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return dev_err_probe(dev, -EINVAL, "invalid address\n");
+
+ uart.port.dev = dev;
+ if (device_is_compatible(dev, "airoha,an7581-hsuart"))
+ uart.port.type = UART_PORT_AIROHA_HS;
+ else
+ uart.port.type = UART_PORT_AIROHA;
+ uart.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT |
+ UPF_FIXED_TYPE | UPF_IOREMAP;
+ uart.port.set_divisor = airoha_set_divisor;
+ uart.port.get_divisor = airoha_get_divisor;
+ uart.port.mapbase = res->start;
+ uart.port.mapsize = resource_size(res);
+
+ ret = uart_read_and_validate_port_properties(&uart.port);
+ if (ret)
+ return ret;
+
+ struct uart_8250_port *uport = serial8250_register_8250_port(&uart);
+ if (IS_ERR(uport))
+ return PTR_ERR(uport);
+
+ platform_set_drvdata(pdev, uport);
+
+ return 0;
+}
+
+static void airoha_8250_remove(struct platform_device *ofdev)
+{
+ struct uart_8250_port *uport = platform_get_drvdata(ofdev);
+
+ serial8250_unregister_port(uport);
+}
+
+static const struct of_device_id airoha_8250_dt_ids[] = {
+ { .compatible = "airoha,en7523-uart" },
+ { .compatible = "airoha,an7581-hsuart" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, airoha_8250_dt_ids);
+
+static struct platform_driver airoha_8250_driver = {
+ .driver = {
+ .name = "8250_airoha",
+ .of_match_table = airoha_8250_dt_ids,
+ },
+ .probe = airoha_8250_probe,
+ .remove = airoha_8250_remove,
+};
+module_platform_driver(airoha_8250_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Airoha UART driver");
+MODULE_AUTHOR("Benjamin Larsson <benjamin.larsson@genexis.eu>");
+MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>");
diff --git a/drivers/tty/serial/8250/8250_aspeed_vuart.c b/drivers/tty/serial/8250/8250_aspeed_vuart.c
index 26fc0464f1cc..c8dc87f6886c 100644
--- a/drivers/tty/serial/8250/8250_aspeed_vuart.c
+++ b/drivers/tty/serial/8250/8250_aspeed_vuart.c
@@ -6,6 +6,7 @@
* Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>, IBM Corp.
*/
#include <linux/device.h>
+#include <linux/err.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
@@ -34,7 +35,6 @@
struct aspeed_vuart {
struct device *dev;
- int line;
struct timer_list unthrottle_timer;
struct uart_8250_port *port;
};
@@ -484,12 +484,13 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
if (of_property_read_bool(np, "auto-flow-control"))
port.capabilities |= UART_CAP_AFE;
- rc = serial8250_register_8250_port(&port);
- if (rc < 0)
+ struct uart_8250_port *uport = serial8250_register_8250_port(&port);
+ if (IS_ERR(uport)) {
+ rc = PTR_ERR(uport);
goto err_sysfs_remove;
+ }
- vuart->line = rc;
- vuart->port = serial8250_get_port(vuart->line);
+ vuart->port = uport;
rc = of_parse_phandle_with_fixed_args(
np, "aspeed,sirq-polarity-sense", 2, 0,
@@ -553,7 +554,7 @@ static void aspeed_vuart_remove(struct platform_device *pdev)
timer_delete_sync(&vuart->unthrottle_timer);
aspeed_vuart_set_enabled(vuart, false);
- serial8250_unregister_port(vuart->line);
+ serial8250_unregister_port(vuart->port);
sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
}
diff --git a/drivers/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c
index 0609582a62f7..b842dba3059d 100644
--- a/drivers/tty/serial/8250/8250_bcm2835aux.c
+++ b/drivers/tty/serial/8250/8250_bcm2835aux.c
@@ -7,18 +7,20 @@
* Based on 8250_lpc18xx.c:
* Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
*
- * The bcm2835aux is capable of RTS auto flow-control, but this driver doesn't
- * take advantage of it yet. When adding support, be sure not to enable it
- * simultaneously to rs485.
+ * The bcm2835aux's RTS/CTS auto flow-control is enabled for ports declaring
+ * the "uart-has-rtscts" property, but never simultaneously to rs485, which
+ * repurposes RTS as the transceiver direction control.
*/
#include <linux/clk.h>
#include <linux/console.h>
+#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/property.h>
+#include <linux/tty.h>
#include "8250.h"
@@ -34,18 +36,170 @@
#define BCM2835_AUX_UART_CNTL_RTSINV 0x40 /* Invert auto RTS polarity */
#define BCM2835_AUX_UART_CNTL_CTSINV 0x80 /* Invert auto CTS polarity */
+/*
+ * Set auto RTS to de-assert with 4 FIFO slots left (RTS4).
+ *
+ * The RTSINV/CTSINV bits select the auto flow assert level, which out of
+ * reset is active-high. Set them to get the conventional active-low RTS/CTS.
+ */
+#define BCM2835_AUX_UART_CNTL_AUTORTS_MASK \
+ (BCM2835_AUX_UART_CNTL_AUTORTS | BCM2835_AUX_UART_CNTL_RTS4 | \
+ BCM2835_AUX_UART_CNTL_RTSINV)
+#define BCM2835_AUX_UART_CNTL_AUTOCTS_MASK \
+ (BCM2835_AUX_UART_CNTL_AUTOCTS | BCM2835_AUX_UART_CNTL_CTSINV)
+
/**
* struct bcm2835aux_data - driver private data of BCM2835 auxiliary UART
* @clk: clock producer of the port's uartclk
- * @line: index of the port's serial8250_ports[] entry
+ * @uport: the underlying uart_8250_port
* @cntl: cached copy of CNTL register
*/
struct bcm2835aux_data {
struct clk *clk;
- int line;
+ struct uart_8250_port *uport;
u32 cntl;
};
+static bool bcm2835aux_tty_throttled(struct uart_port *port)
+{
+ if (!port->state)
+ return false;
+
+ scoped_guard(tty_port_tty, &port->state->port)
+ return tty_throttled(scoped_tty());
+
+ return false;
+}
+
+/* Program the CNTL auto flow bits from port->status and mctrl */
+static void bcm2835aux_update_flow(struct uart_port *port, unsigned int mctrl)
+{
+ struct bcm2835aux_data *data = dev_get_drvdata(port->dev);
+ struct uart_8250_port *up = up_to_u8250p(port);
+
+ data->cntl &= ~(BCM2835_AUX_UART_CNTL_AUTORTS_MASK |
+ BCM2835_AUX_UART_CNTL_AUTOCTS_MASK);
+ if ((port->status & UPSTAT_AUTORTS) && (mctrl & TIOCM_RTS))
+ data->cntl |= BCM2835_AUX_UART_CNTL_AUTORTS_MASK;
+ if (port->status & UPSTAT_AUTOCTS)
+ data->cntl |= BCM2835_AUX_UART_CNTL_AUTOCTS_MASK;
+
+ serial_out(up, BCM2835_AUX_UART_CNTL, data->cntl);
+}
+
+static void bcm2835aux_enable_rx_irq(struct uart_port *port)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+
+ up->ier |= UART_IER_RLSI | UART_IER_RDI;
+ serial_out(up, UART_IER, up->ier);
+}
+
+static void bcm2835aux_set_autoflow(struct uart_port *port, tcflag_t cflag,
+ bool rs485_enabled)
+{
+ bool was_enabled = port->status & UPSTAT_AUTORTS;
+ bool enable;
+
+ /*
+ * rs485 uses RTS as the transceiver direction control, which is
+ * mutually exclusive with the auto flow-control of the pin.
+ */
+ enable = (cflag & CRTSCTS) && (port->flags & UPF_HARD_FLOW) &&
+ !rs485_enabled;
+
+ if (enable) {
+ port->status |= UPSTAT_AUTORTS | UPSTAT_AUTOCTS;
+ /* Restore the throttle state lost in startup/resume/rs485 paths */
+ if (bcm2835aux_tty_throttled(port)) {
+ /* let the FIFO fill up and de-assert RTS in hardware */
+ port->ops->stop_rx(port);
+ /* reclaim an RTS lowered by software flow control */
+ if ((cflag & CBAUD) != B0)
+ port->mctrl |= TIOCM_RTS;
+ }
+ } else {
+ port->status &= ~(UPSTAT_AUTORTS | UPSTAT_AUTOCTS);
+ /* unthrottle() will no longer be called after leaving auto-RTS mode */
+ if (was_enabled)
+ bcm2835aux_enable_rx_irq(port);
+ }
+
+ bcm2835aux_update_flow(port, port->mctrl);
+}
+
+static void bcm2835aux_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ serial8250_do_set_mctrl(port, mctrl);
+ bcm2835aux_update_flow(port, mctrl);
+}
+
+static void bcm2835aux_set_termios(struct uart_port *port,
+ struct ktermios *termios,
+ const struct ktermios *old)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+ bool hw_flow = (port->flags & UPF_HARD_FLOW) &&
+ !(port->rs485.flags & SER_RS485_ENABLED);
+
+ /*
+ * Strip CRTSCTS when the hardware auto flow-control cannot be
+ * used, as the serial core's software CTS fallback cannot work
+ * without a modem status interrupt. A CTS GPIO provides one.
+ */
+ if (!hw_flow && !mctrl_gpio_to_gpiod(up->gpios, UART_GPIO_CTS))
+ termios->c_cflag &= ~CRTSCTS;
+
+ serial8250_do_set_termios(port, termios, old);
+
+ guard(uart_port_lock_irqsave)(port);
+
+ bcm2835aux_set_autoflow(port, termios->c_cflag,
+ port->rs485.flags & SER_RS485_ENABLED);
+}
+
+static void bcm2835aux_throttle(struct uart_port *port)
+{
+ guard(uart_port_lock_irqsave)(port);
+
+ port->ops->stop_rx(port);
+}
+
+static void bcm2835aux_unthrottle(struct uart_port *port)
+{
+ guard(uart_port_lock_irqsave)(port);
+
+ bcm2835aux_enable_rx_irq(port);
+}
+
+static int bcm2835aux_rs485_config(struct uart_port *port,
+ struct ktermios *termios,
+ struct serial_rs485 *rs485)
+{
+ tcflag_t cflag = termios ? termios->c_cflag : 0;
+ bool rs485_enabled;
+ int ret;
+
+ ret = serial8250_em485_config(port, termios, rs485);
+ if (ret)
+ return ret;
+
+ rs485_enabled = rs485->flags & SER_RS485_ENABLED;
+ if (!rs485_enabled) {
+ struct bcm2835aux_data *data = dev_get_drvdata(port->dev);
+
+ data->cntl |= BCM2835_AUX_UART_CNTL_RXEN;
+ }
+
+ /*
+ * termios is NULL when rs485 is set up from firmware properties at
+ * port registration, before the port has been opened.
+ */
+ bcm2835aux_set_autoflow(port, cflag, rs485_enabled);
+
+ return 0;
+}
+
static void bcm2835aux_rs485_start_tx(struct uart_8250_port *up, bool toggle_ier)
{
if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) {
@@ -99,7 +253,11 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
up.port.dev = &pdev->dev;
up.port.type = PORT_16550;
up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SKIP_TEST | UPF_IOREMAP;
- up.port.rs485_config = serial8250_em485_config;
+ up.port.set_termios = bcm2835aux_set_termios;
+ up.port.set_mctrl = bcm2835aux_set_mctrl;
+ up.port.throttle = bcm2835aux_throttle;
+ up.port.unthrottle = bcm2835aux_unthrottle;
+ up.port.rs485_config = bcm2835aux_rs485_config;
up.port.rs485_supported = serial8250_em485_supported;
up.rs485_start_tx = bcm2835aux_rs485_start_tx;
up.rs485_stop_tx = bcm2835aux_rs485_stop_tx;
@@ -134,6 +292,8 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
ret = uart_read_port_properties(&up.port);
if (ret)
goto rm_swnode;
+ if (device_property_read_bool(&pdev->dev, "uart-has-rtscts"))
+ up.port.flags |= UPF_HARD_FLOW;
up.port.regshift = 2;
up.port.fifosize = 8;
@@ -157,12 +317,12 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
up.port.uartclk *= 2;
/* register the port */
- ret = serial8250_register_8250_port(&up);
- if (ret < 0) {
+ data->uport = serial8250_register_8250_port(&up);
+ if (IS_ERR(data->uport)) {
+ ret = PTR_ERR(data->uport);
dev_err_probe(&pdev->dev, ret, "unable to register 8250 port\n");
goto dis_clk;
}
- data->line = ret;
return 0;
@@ -177,7 +337,7 @@ static void bcm2835aux_serial_remove(struct platform_device *pdev)
{
struct bcm2835aux_data *data = platform_get_drvdata(pdev);
- serial8250_unregister_port(data->line);
+ serial8250_unregister_port(data->uport);
clk_disable_unprepare(data->clk);
device_remove_software_node(&pdev->dev);
}
@@ -217,12 +377,11 @@ MODULE_DEVICE_TABLE(acpi, bcm2835aux_serial_acpi_match);
static bool bcm2835aux_can_disable_clock(struct device *dev)
{
struct bcm2835aux_data *data = dev_get_drvdata(dev);
- struct uart_8250_port *up = serial8250_get_port(data->line);
if (device_may_wakeup(dev))
return false;
- if (uart_console(&up->port) && !console_suspend_enabled)
+ if (uart_console(&data->uport->port) && !console_suspend_enabled)
return false;
return true;
@@ -232,7 +391,7 @@ static int bcm2835aux_suspend(struct device *dev)
{
struct bcm2835aux_data *data = dev_get_drvdata(dev);
- serial8250_suspend_port(data->line);
+ serial8250_suspend_port(data->uport);
if (!bcm2835aux_can_disable_clock(dev))
return 0;
@@ -252,7 +411,7 @@ static int bcm2835aux_resume(struct device *dev)
return ret;
}
- serial8250_resume_port(data->line);
+ serial8250_resume_port(data->uport);
return 0;
}
diff --git a/drivers/tty/serial/8250/8250_bcm7271.c b/drivers/tty/serial/8250/8250_bcm7271.c
index 5f1140f05150..974d9af146a1 100644
--- a/drivers/tty/serial/8250/8250_bcm7271.c
+++ b/drivers/tty/serial/8250/8250_bcm7271.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/tty.h>
+#include <linux/err.h>
#include <linux/errno.h>
#include <linux/device.h>
#include <linux/io.h>
@@ -204,13 +205,12 @@ static const u32 brcmstb_rate_table_7278[] = {
};
struct brcmuart_priv {
- int line;
struct clk *baud_mux_clk;
unsigned long default_mux_rate;
u32 real_rates[ARRAY_SIZE(brcmstb_rate_table)];
const u32 *rate_table;
ktime_t char_wait;
- struct uart_port *up;
+ struct uart_8250_port *uport;
struct hrtimer hrt;
bool shutdown;
bool dma_enabled;
@@ -839,8 +839,8 @@ static int brcmuart_handle_irq(struct uart_port *p)
static enum hrtimer_restart brcmuart_hrtimer_func(struct hrtimer *t)
{
struct brcmuart_priv *priv = container_of(t, struct brcmuart_priv, hrt);
- struct uart_port *p = priv->up;
- struct uart_8250_port *up = up_to_u8250p(p);
+ struct uart_8250_port *up = priv->uport;
+ struct uart_port *p = &up->port;
unsigned int status;
unsigned long flags;
@@ -953,7 +953,6 @@ static int brcmuart_probe(struct platform_device *pdev)
{
struct resource *regs;
const struct of_device_id *of_id = NULL;
- struct uart_8250_port *new_port;
struct device *dev = &pdev->dev;
struct brcmuart_priv *priv;
struct clk *baud_mux_clk;
@@ -1083,14 +1082,12 @@ static int brcmuart_probe(struct platform_device *pdev)
}
}
- ret = serial8250_register_8250_port(&up);
- if (ret < 0) {
+ priv->uport = serial8250_register_8250_port(&up);
+ if (IS_ERR(priv->uport)) {
+ ret = PTR_ERR(priv->uport);
dev_err_probe(dev, ret, "unable to register 8250 port\n");
goto err;
}
- priv->line = ret;
- new_port = serial8250_get_port(ret);
- priv->up = &new_port->port;
if (priv->dma_enabled) {
dma_irq = platform_get_irq_byname(pdev, "dma");
if (dma_irq < 0) {
@@ -1098,7 +1095,7 @@ static int brcmuart_probe(struct platform_device *pdev)
goto err1;
}
ret = devm_request_irq(dev, dma_irq, brcmuart_isr,
- IRQF_SHARED, "uart DMA irq", &new_port->port);
+ IRQF_SHARED, "uart DMA irq", &priv->uport->port);
if (ret)
goto err1;
}
@@ -1107,7 +1104,7 @@ static int brcmuart_probe(struct platform_device *pdev)
return 0;
err1:
- serial8250_unregister_port(priv->line);
+ serial8250_unregister_port(priv->uport);
err:
brcmuart_free_bufs(dev, priv);
release_dma:
@@ -1121,7 +1118,7 @@ static void brcmuart_remove(struct platform_device *pdev)
struct brcmuart_priv *priv = platform_get_drvdata(pdev);
debugfs_remove_recursive(priv->debugfs_dir);
- serial8250_unregister_port(priv->line);
+ serial8250_unregister_port(priv->uport);
hrtimer_cancel(&priv->hrt);
brcmuart_free_bufs(&pdev->dev, priv);
if (priv->dma_enabled)
@@ -1131,7 +1128,7 @@ static void brcmuart_remove(struct platform_device *pdev)
static int __maybe_unused brcmuart_suspend(struct device *dev)
{
struct brcmuart_priv *priv = dev_get_drvdata(dev);
- struct uart_8250_port *up = serial8250_get_port(priv->line);
+ struct uart_8250_port *up = priv->uport;
struct uart_port *port = &up->port;
unsigned long flags;
@@ -1144,7 +1141,7 @@ static int __maybe_unused brcmuart_suspend(struct device *dev)
port->mctrl &= ~TIOCM_RTS;
uart_port_unlock_irqrestore(port, flags);
- serial8250_suspend_port(priv->line);
+ serial8250_suspend_port(up);
clk_disable_unprepare(priv->baud_mux_clk);
return 0;
@@ -1153,7 +1150,7 @@ static int __maybe_unused brcmuart_suspend(struct device *dev)
static int __maybe_unused brcmuart_resume(struct device *dev)
{
struct brcmuart_priv *priv = dev_get_drvdata(dev);
- struct uart_8250_port *up = serial8250_get_port(priv->line);
+ struct uart_8250_port *up = priv->uport;
struct uart_port *port = &up->port;
unsigned long flags;
int ret;
@@ -1175,9 +1172,9 @@ static int __maybe_unused brcmuart_resume(struct device *dev)
return(-EBUSY);
}
brcmuart_init_dma_hardware(priv);
- start_rx_dma(serial8250_get_port(priv->line));
+ start_rx_dma(up);
}
- serial8250_resume_port(priv->line);
+ serial8250_resume_port(up);
if (priv->saved_mctrl & TIOCM_RTS) {
/* Restore RTS */
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index b875d394796f..42319843cb5b 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -16,6 +16,7 @@
#include <linux/hashtable.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
+#include <linux/err.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/console.h>
@@ -333,7 +334,6 @@ struct uart_8250_port *serial8250_get_port(int line)
{
return &serial8250_ports[line];
}
-EXPORT_SYMBOL_GPL(serial8250_get_port);
static inline void serial8250_apply_quirks(struct uart_8250_port *up)
{
@@ -600,13 +600,12 @@ int __init early_serial_setup(struct uart_port *port)
/**
* serial8250_suspend_port - suspend one serial port
- * @line: serial line number
+ * @up: serial port
*
* Suspend one serial port.
*/
-void serial8250_suspend_port(int line)
+void serial8250_suspend_port(struct uart_8250_port *up)
{
- struct uart_8250_port *up = &serial8250_ports[line];
struct uart_port *port = &up->port;
if (uart_console(port)) {
@@ -630,13 +629,12 @@ EXPORT_SYMBOL(serial8250_suspend_port);
/**
* serial8250_resume_port - resume one serial port
- * @line: serial line number
+ * @up: serial port
*
* Resume one serial port.
*/
-void serial8250_resume_port(int line)
+void serial8250_resume_port(struct uart_8250_port *up)
{
- struct uart_8250_port *up = &serial8250_ports[line];
struct uart_port *port = &up->port;
up->canary = 0;
@@ -673,6 +671,29 @@ EXPORT_SYMBOL(serial8250_resume_port);
*/
static DEFINE_MUTEX(serial_mutex);
+/**
+ * serial8250_match_port - are the two ports equivalent?
+ * @port1: first port
+ * @port2: second port
+ *
+ * This utility function can be used to determine whether two uart_port
+ * structures describe the same port.
+ */
+static bool serial8250_match_port(const struct uart_port *port1,
+ const struct uart_port *port2)
+{
+ if (port1->iotype != port2->iotype)
+ return false;
+ else if (port1->iotype == UPIO_PORT)
+ return port1->iobase == port2->iobase;
+ else if (port1->iotype == UPIO_HUB6)
+ return hub6_match_port(port1, port2);
+ else if (uart_iotype_mmio(port1->iotype))
+ return port1->mapbase == port2->mapbase;
+ else
+ return false;
+}
+
static struct uart_8250_port *serial8250_find_match_or_unused(const struct uart_port *port)
{
int i;
@@ -681,7 +702,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(const struct uart_
* First, find a port entry which matches.
*/
for (i = 0; i < nr_uarts; i++)
- if (uart_match_port(&serial8250_ports[i].port, port))
+ if (serial8250_match_port(&serial8250_ports[i].port, port))
return &serial8250_ports[i];
/* try line number first if still available */
@@ -720,46 +741,12 @@ static void serial_8250_overrun_backoff_work(struct work_struct *work)
serial_out(up, UART_IER, up->ier);
}
-/**
- * serial8250_register_8250_port - register a serial port
- * @up: serial port template
- *
- * Configure the serial port specified by the request. If the
- * port exists and is in use, it is hung up and unregistered
- * first.
- *
- * The port is then probed and if necessary the IRQ is autodetected
- * If this fails an error is returned.
- *
- * On success the port is ready to use and the line number is returned.
- */
-int serial8250_register_8250_port(const struct uart_8250_port *up)
+static int __serial8250_register_8250_port(struct uart_8250_port *uart,
+ const struct uart_8250_port *up)
{
- struct uart_8250_port *uart;
bool cons_flow;
int ret;
- if (up->port.uartclk == 0)
- return -EINVAL;
-
- guard(mutex)(&serial_mutex);
-
- uart = serial8250_find_match_or_unused(&up->port);
- if (!uart) {
- /*
- * If the port is past the initial isa ports, initialize a new
- * port and increment nr_uarts accordingly.
- */
- uart = serial8250_setup_port(nr_uarts);
- if (!uart)
- return -ENOSPC;
- nr_uarts++;
- }
-
- /* Check if it is CIR already. We check this below again, see there why. */
- if (uart->port.type == PORT_8250_CIR)
- return -ENODEV;
-
/* Preserve specified console flow control. */
cons_flow = uart_cons_flow_enabled(&uart->port);
@@ -803,7 +790,7 @@ int serial8250_register_8250_port(const struct uart_8250_port *up)
uart->port.dev = up->port.dev;
ret = uart_get_rs485_mode(&uart->port);
if (ret)
- goto err;
+ return ret;
}
if (up->port.flags & UPF_FIXED_TYPE)
@@ -815,12 +802,10 @@ int serial8250_register_8250_port(const struct uart_8250_port *up)
*/
if (uart->port.dev && !has_acpi_companion(uart->port.dev)) {
struct mctrl_gpios *gpios = mctrl_gpio_init(&uart->port, 0);
- if (IS_ERR(gpios)) {
- ret = PTR_ERR(gpios);
- goto err;
- } else {
- uart->gpios = gpios;
- }
+ if (IS_ERR(gpios))
+ return PTR_ERR(gpios);
+
+ uart->gpios = gpios;
}
serial8250_set_defaults(uart);
@@ -877,17 +862,13 @@ int serial8250_register_8250_port(const struct uart_8250_port *up)
ret = uart_add_one_port(&serial8250_reg,
&uart->port);
if (ret)
- goto err;
-
- ret = uart->port.line;
+ return ret;
} else {
dev_info(uart->port.dev,
"skipping CIR port at 0x%lx / 0x%llx, IRQ %d\n",
uart->port.iobase,
(unsigned long long)uart->port.mapbase,
uart->port.irq);
-
- ret = 0;
}
if (!uart->lsr_save_mask)
@@ -903,25 +884,67 @@ int serial8250_register_8250_port(const struct uart_8250_port *up)
uart->overrun_backoff_time_ms = 0;
}
- return ret;
+ return 0;
+}
-err:
- uart->port.dev = NULL;
- return ret;
+/**
+ * serial8250_register_8250_port - register a serial port
+ * @up: serial port template
+ *
+ * Configure the serial port specified by the request. If the
+ * port exists and is in use, it is hung up and unregistered
+ * first.
+ *
+ * The port is then probed and if necessary the IRQ is autodetected
+ * If this fails an error is returned.
+ *
+ * On success the port is ready to use and the line number is returned.
+ */
+struct uart_8250_port *serial8250_register_8250_port(const struct uart_8250_port *up)
+{
+ struct uart_8250_port *uart;
+ int ret;
+
+ if (up->port.uartclk == 0)
+ return ERR_PTR(-EINVAL);
+
+ guard(mutex)(&serial_mutex);
+
+ uart = serial8250_find_match_or_unused(&up->port);
+ if (!uart) {
+ /*
+ * If the port is past the initial isa ports, initialize a new
+ * port and increment nr_uarts accordingly.
+ */
+ uart = serial8250_setup_port(nr_uarts);
+ if (!uart)
+ return ERR_PTR(-ENOSPC);
+ nr_uarts++;
+ }
+
+ /* Check if it is CIR already. We check this below again, see there why. */
+ if (uart->port.type == PORT_8250_CIR)
+ return ERR_PTR(-ENODEV);
+
+ ret = __serial8250_register_8250_port(uart, up);
+ if (ret < 0) {
+ uart->port.dev = NULL;
+ return ERR_PTR(ret);
+ }
+
+ return uart;
}
EXPORT_SYMBOL(serial8250_register_8250_port);
/**
* serial8250_unregister_port - remove a 16x50 serial port at runtime
- * @line: serial line number
+ * @uart: port
*
* Remove one serial port. This may not be called from interrupt
* context. We hand the port back to the our control.
*/
-void serial8250_unregister_port(int line)
+void serial8250_unregister_port(struct uart_8250_port *uart)
{
- struct uart_8250_port *uart = &serial8250_ports[line];
-
guard(mutex)(&serial_mutex);
if (uart->em485) {
@@ -934,7 +957,7 @@ void serial8250_unregister_port(int line)
uart->port.flags &= ~UPF_BOOT_AUTOCONF;
uart->port.type = PORT_UNKNOWN;
uart->port.dev = &serial8250_isa_devs->dev;
- uart->port.port_id = line;
+ uart->port.port_id = uart->port.line;
uart->capabilities = 0;
serial8250_init_port(uart);
serial8250_apply_quirks(uart);
diff --git a/drivers/tty/serial/8250/8250_dfl.c b/drivers/tty/serial/8250/8250_dfl.c
index 475ca340948c..1343375897a8 100644
--- a/drivers/tty/serial/8250/8250_dfl.c
+++ b/drivers/tty/serial/8250/8250_dfl.c
@@ -12,6 +12,7 @@
#include <linux/bitfield.h>
#include <linux/device.h>
#include <linux/dfl.h>
+#include <linux/err.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/module.h>
@@ -27,10 +28,6 @@
#define DFHv1_PARAM_REG_LAYOUT_WIDTH GENMASK_ULL(63, 32)
#define DFHv1_PARAM_REG_LAYOUT_SHIFT GENMASK_ULL(31, 0)
-struct dfl_uart {
- int line;
-};
-
static int dfh_get_u64_param_val(struct dfl_device *dfl_dev, int param_id, u64 *pval)
{
size_t psize;
@@ -109,7 +106,6 @@ static int dfl_uart_probe(struct dfl_device *dfl_dev)
{
struct device *dev = &dfl_dev->dev;
struct uart_8250_port uart = { };
- struct dfl_uart *dfluart;
int ret;
uart.port.flags = UPF_IOREMAP;
@@ -123,24 +119,20 @@ static int dfl_uart_probe(struct dfl_device *dfl_dev)
if (dfl_dev->num_irqs == 1)
uart.port.irq = dfl_dev->irqs[0];
- dfluart = devm_kzalloc(dev, sizeof(*dfluart), GFP_KERNEL);
- if (!dfluart)
- return -ENOMEM;
-
- dfluart->line = serial8250_register_8250_port(&uart);
- if (dfluart->line < 0)
- return dev_err_probe(dev, dfluart->line, "unable to register 8250 port.\n");
+ struct uart_8250_port *uport = serial8250_register_8250_port(&uart);
+ if (IS_ERR(uport))
+ return dev_err_probe(dev, PTR_ERR(uport), "unable to register 8250 port.\n");
- dev_set_drvdata(dev, dfluart);
+ dev_set_drvdata(dev, uport);
return 0;
}
static void dfl_uart_remove(struct dfl_device *dfl_dev)
{
- struct dfl_uart *dfluart = dev_get_drvdata(&dfl_dev->dev);
+ struct uart_8250_port *uport = dev_get_drvdata(&dfl_dev->dev);
- serial8250_unregister_port(dfluart->line);
+ serial8250_unregister_port(uport);
}
#define FME_FEATURE_ID_UART 0x24
diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c
index 5a83e5269b41..1da605cc8601 100644
--- a/drivers/tty/serial/8250/8250_dma.c
+++ b/drivers/tty/serial/8250/8250_dma.c
@@ -19,7 +19,7 @@ static void __dma_tx_complete(void *param)
unsigned long flags;
int ret;
- dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr,
+ dma_sync_single_for_cpu(dmaengine_get_dma_device(dma->txchan), dma->tx_addr,
UART_XMIT_SIZE, DMA_TO_DEVICE);
uart_port_lock_irqsave(&p->port, &flags);
@@ -136,7 +136,7 @@ int serial8250_tx_dma(struct uart_8250_port *p)
dma->tx_cookie = dmaengine_submit(desc);
- dma_sync_single_for_device(dma->txchan->device->dev, dma->tx_addr,
+ dma_sync_single_for_device(dmaengine_get_dma_device(dma->txchan), dma->tx_addr,
UART_XMIT_SIZE, DMA_TO_DEVICE);
dma_async_issue_pending(dma->txchan);
@@ -223,6 +223,8 @@ EXPORT_SYMBOL_GPL(serial8250_rx_dma_flush);
int serial8250_request_dma(struct uart_8250_port *p)
{
struct uart_8250_dma *dma = p->dma;
+ struct device *rx_dev;
+ struct device *tx_dev;
phys_addr_t rx_dma_addr = dma->rx_dma_addr ?
dma->rx_dma_addr : p->port.mapbase;
phys_addr_t tx_dma_addr = dma->tx_dma_addr ?
@@ -282,24 +284,25 @@ int serial8250_request_dma(struct uart_8250_port *p)
dmaengine_slave_config(dma->txchan, &dma->txconf);
+ rx_dev = dmaengine_get_dma_device(dma->rxchan);
+ tx_dev = dmaengine_get_dma_device(dma->txchan);
+
/* RX buffer */
if (!dma->rx_size)
dma->rx_size = PAGE_SIZE;
- dma->rx_buf = dma_alloc_coherent(dma->rxchan->device->dev, dma->rx_size,
- &dma->rx_addr, GFP_KERNEL);
+ dma->rx_buf = dma_alloc_coherent(rx_dev, dma->rx_size, &dma->rx_addr,
+ GFP_KERNEL);
if (!dma->rx_buf) {
ret = -ENOMEM;
goto err;
}
/* TX buffer */
- dma->tx_addr = dma_map_single(dma->txchan->device->dev,
- p->port.state->port.xmit_buf,
- UART_XMIT_SIZE,
- DMA_TO_DEVICE);
- if (dma_mapping_error(dma->txchan->device->dev, dma->tx_addr)) {
- dma_free_coherent(dma->rxchan->device->dev, dma->rx_size,
+ dma->tx_addr = dma_map_single(tx_dev, p->port.state->port.xmit_buf,
+ UART_XMIT_SIZE, DMA_TO_DEVICE);
+ if (dma_mapping_error(tx_dev, dma->tx_addr)) {
+ dma_free_coherent(rx_dev, dma->rx_size,
dma->rx_buf, dma->rx_addr);
ret = -ENOMEM;
goto err;
@@ -326,14 +329,14 @@ void serial8250_release_dma(struct uart_8250_port *p)
/* Release RX resources */
dmaengine_terminate_sync(dma->rxchan);
dma->rx_running = 0;
- dma_free_coherent(dma->rxchan->device->dev, dma->rx_size, dma->rx_buf,
- dma->rx_addr);
+ dma_free_coherent(dmaengine_get_dma_device(dma->rxchan), dma->rx_size,
+ dma->rx_buf, dma->rx_addr);
dma_release_channel(dma->rxchan);
dma->rxchan = NULL;
/* Release TX resources */
dmaengine_terminate_sync(dma->txchan);
- dma_unmap_single(dma->txchan->device->dev, dma->tx_addr,
+ dma_unmap_single(dmaengine_get_dma_device(dma->txchan), dma->tx_addr,
UART_XMIT_SIZE, DMA_TO_DEVICE);
dma_release_channel(dma->txchan);
dma->txchan = NULL;
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index 51d026f20825..eca02e8bd6d1 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -15,6 +15,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/err.h>
#include <linux/io.h>
#include <linux/lockdep.h>
#include <linux/module.h>
@@ -51,6 +52,7 @@
#define DW_UART_QUIRK_APMC0D08 BIT(4)
#define DW_UART_QUIRK_CPR_VALUE BIT(5)
#define DW_UART_QUIRK_IER_KICK BIT(6)
+#define DW_UART_QUIRK_SKIP_EMPTY_FIFO_READ BIT(7)
/*
* Number of consecutive IIR_NO_INT interrupts required to trigger interrupt
@@ -436,11 +438,18 @@ static int dw8250_handle_irq(struct uart_port *p)
* This problem has only been observed so far when not in DMA mode
* so we limit the workaround only to non-DMA mode.
*/
- if (!up->dma && rx_timeout) {
+ if (!(quirks & DW_UART_QUIRK_SKIP_EMPTY_FIFO_READ) && !up->dma && rx_timeout) {
status = serial_lsr_in(up);
+ /*
+ * Do the bogus read from Shadow RBR (SRBR) if provided.
+ * Both RBR and SRBR are supported ways to workaround
+ * this problem. But read RBR can cause hardware error
+ * (PSLVERR) if hardware choose to implement in this way
+ * (implement REG_TIMEOUT_WIDTH to 0), whereas SRBR won't.
+ */
if (!(status & (UART_LSR_DR | UART_LSR_BI)))
- serial_port_in(p, UART_RX);
+ serial_port_in(p, d->data.srbr);
}
/* Manually stop the Rx DMA transfer when acting as flow controller */
@@ -766,9 +775,9 @@ static int dw8250_probe(struct platform_device *pdev)
up->dma = &data->data.dma;
}
- data->data.line = serial8250_register_8250_port(up);
- if (data->data.line < 0)
- return data->data.line;
+ data->data.uport = serial8250_register_8250_port(up);
+ if (IS_ERR(data->data.uport))
+ return PTR_ERR(data->data.uport);
platform_set_drvdata(pdev, data);
@@ -784,7 +793,7 @@ static void dw8250_remove(struct platform_device *pdev)
pm_runtime_get_sync(dev);
- serial8250_unregister_port(data->data.line);
+ serial8250_unregister_port(data->data.uport);
pm_runtime_disable(dev);
pm_runtime_put_noidle(dev);
@@ -794,7 +803,7 @@ static int dw8250_suspend(struct device *dev)
{
struct dw8250_data *data = dev_get_drvdata(dev);
- serial8250_suspend_port(data->data.line);
+ serial8250_suspend_port(data->data.uport);
return 0;
}
@@ -803,7 +812,7 @@ static int dw8250_resume(struct device *dev)
{
struct dw8250_data *data = dev_get_drvdata(dev);
- serial8250_resume_port(data->data.line);
+ serial8250_resume_port(data->data.uport);
return 0;
}
@@ -888,6 +897,11 @@ static const struct dw8250_platform_data dw8250_ultrarisc_dp1000_data = {
.quirks = DW_UART_QUIRK_CPR_VALUE,
};
+static const struct dw8250_platform_data dw8250_tda54 = {
+ .usr_reg = DW_UART_USR,
+ .quirks = DW_UART_QUIRK_SKIP_EMPTY_FIFO_READ,
+};
+
static const struct of_device_id dw8250_of_match[] = {
{ .compatible = "snps,dw-apb-uart", .data = &dw8250_dw_apb },
{ .compatible = "cavium,octeon-3860-uart", .data = &dw8250_octeon_3860_data },
@@ -895,6 +909,7 @@ static const struct of_device_id dw8250_of_match[] = {
{ .compatible = "renesas,rzn1-uart", .data = &dw8250_renesas_rzn1_data },
{ .compatible = "sophgo,sg2044-uart", .data = &dw8250_skip_set_rate_data },
{ .compatible = "starfive,jh7100-uart", .data = &dw8250_skip_set_rate_data },
+ { .compatible = "ti,tda54-uart", .data = &dw8250_tda54 },
{ .compatible = "ultrarisc,dp1000-uart", .data = &dw8250_ultrarisc_dp1000_data },
{ /* Sentinel */ }
};
@@ -910,6 +925,7 @@ static const struct acpi_device_id dw8250_acpi_match[] = {
{ "8086228A", (kernel_ulong_t)&dw8250_dw_apb },
{ "AMD0020", (kernel_ulong_t)&dw8250_dw_apb },
{ "AMDI0020", (kernel_ulong_t)&dw8250_dw_apb },
+ { "AMDI0021", (kernel_ulong_t)&dw8250_dw_apb },
{ "AMDI0022", (kernel_ulong_t)&dw8250_dw_apb },
{ "APMC0D08", (kernel_ulong_t)&dw8250_apmc0d08 },
{ "BRCM2032", (kernel_ulong_t)&dw8250_dw_apb },
diff --git a/drivers/tty/serial/8250/8250_dwlib.c b/drivers/tty/serial/8250/8250_dwlib.c
index 8859e66d2d71..9bb02a4ab11f 100644
--- a/drivers/tty/serial/8250/8250_dwlib.c
+++ b/drivers/tty/serial/8250/8250_dwlib.c
@@ -247,5 +247,10 @@ void dw8250_setup_port(struct uart_port *p)
if (reg & DW_UART_CPR_SIR_MODE)
up->capabilities |= UART_CAP_IRDA;
+
+ if (reg & DW_UART_CPR_SHADOW)
+ pd->srbr = DW_UART_SRBR_0;
+ else
+ pd->srbr = UART_RX;
}
EXPORT_SYMBOL_GPL(dw8250_setup_port);
diff --git a/drivers/tty/serial/8250/8250_dwlib.h b/drivers/tty/serial/8250/8250_dwlib.h
index 1fe52332e774..39fcb1b323ad 100644
--- a/drivers/tty/serial/8250/8250_dwlib.h
+++ b/drivers/tty/serial/8250/8250_dwlib.h
@@ -13,6 +13,7 @@
#include "8250.h"
/* Offsets for the DesignWare specific registers */
+#define DW_UART_SRBR_0 0x0c /* Shadow Receive Buffer Register */
#define DW_UART_USR 0x1f /* UART Status Register */
#define DW_UART_DMASA 0xa8 /* DMA Software Ack */
#define DW_UART_TCR 0xac /* Transceiver Control Register (RS485) */
@@ -79,7 +80,7 @@
struct dw8250_port_data {
/* Port properties */
- int line;
+ struct uart_8250_port *uport;
/* DMA operations */
struct uart_8250_dma dma;
@@ -90,6 +91,10 @@ struct dw8250_port_data {
/* RS485 variables */
bool hw_rs485_support;
+
+ /* Register offsets */
+ /* Shadow RBR (if not defined RBR will be used) */
+ int srbr;
};
void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios, const struct ktermios *old);
diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c
index 44ec209f37c4..265d49850e15 100644
--- a/drivers/tty/serial/8250/8250_early.c
+++ b/drivers/tty/serial/8250/8250_early.c
@@ -175,6 +175,7 @@ EARLYCON_DECLARE(uart8250, early_serial8250_setup);
EARLYCON_DECLARE(uart, early_serial8250_setup);
OF_EARLYCON_DECLARE(ns16550, "ns16550", early_serial8250_setup);
OF_EARLYCON_DECLARE(ns16550a, "ns16550a", early_serial8250_setup);
+OF_EARLYCON_DECLARE(uart, "marvell,armada-38x-uart", early_serial8250_setup);
OF_EARLYCON_DECLARE(uart, "nvidia,tegra20-uart", early_serial8250_setup);
OF_EARLYCON_DECLARE(uart, "snps,dw-apb-uart", early_serial8250_setup);
diff --git a/drivers/tty/serial/8250/8250_em.c b/drivers/tty/serial/8250/8250_em.c
index 32d077da076a..bcb71ff8ee8b 100644
--- a/drivers/tty/serial/8250/8250_em.c
+++ b/drivers/tty/serial/8250/8250_em.c
@@ -6,6 +6,7 @@
*/
#include <linux/device.h>
+#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/serial_8250.h>
@@ -28,10 +29,6 @@
#define UART_HCR0_EM_SW_RESET BIT(7) /* SW Reset */
-struct serial8250_em_priv {
- int line;
-};
-
static void serial8250_em_serial_out_helper(struct uart_port *p, int offset,
int value)
{
@@ -151,12 +148,11 @@ static void serial8250_em_serial_dl_write(struct uart_8250_port *up, u32 value)
static int serial8250_em_probe(struct platform_device *pdev)
{
- struct serial8250_em_priv *priv;
struct device *dev = &pdev->dev;
struct uart_8250_port up;
struct resource *regs;
struct clk *sclk;
- int irq, ret;
+ int irq;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
@@ -166,10 +162,6 @@ static int serial8250_em_probe(struct platform_device *pdev)
if (!regs)
return dev_err_probe(dev, -EINVAL, "missing registers\n");
- priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
sclk = devm_clk_get_enabled(dev, "sclk");
if (IS_ERR(sclk))
return dev_err_probe(dev, PTR_ERR(sclk), "unable to get clock\n");
@@ -180,7 +172,6 @@ static int serial8250_em_probe(struct platform_device *pdev)
up.port.type = PORT_16750;
up.port.flags = UPF_FIXED_PORT | UPF_IOREMAP | UPF_FIXED_TYPE;
up.port.dev = dev;
- up.port.private_data = priv;
up.port.uartclk = clk_get_rate(sclk);
@@ -190,20 +181,19 @@ static int serial8250_em_probe(struct platform_device *pdev)
up.dl_read = serial8250_em_serial_dl_read;
up.dl_write = serial8250_em_serial_dl_write;
- ret = serial8250_register_8250_port(&up);
- if (ret < 0)
- return dev_err_probe(dev, ret, "unable to register 8250 port\n");
+ struct uart_8250_port *uport = serial8250_register_8250_port(&up);
+ if (IS_ERR(uport))
+ return dev_err_probe(dev, PTR_ERR(uport), "unable to register 8250 port\n");
- priv->line = ret;
- platform_set_drvdata(pdev, priv);
+ platform_set_drvdata(pdev, uport);
return 0;
}
static void serial8250_em_remove(struct platform_device *pdev)
{
- struct serial8250_em_priv *priv = platform_get_drvdata(pdev);
+ struct uart_8250_port *up = platform_get_drvdata(pdev);
- serial8250_unregister_port(priv->line);
+ serial8250_unregister_port(up);
}
static const struct of_device_id serial8250_em_dt_ids[] = {
diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c
index 836792e861bf..57847c5bd2fc 100644
--- a/drivers/tty/serial/8250/8250_exar.c
+++ b/drivers/tty/serial/8250/8250_exar.c
@@ -12,6 +12,7 @@
#include <linux/device.h>
#include <linux/dmi.h>
#include <linux/eeprom_93cx6.h>
+#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/math.h>
@@ -231,8 +232,9 @@ struct exar8250_platform {
int (*rs485_config)(struct uart_port *port, struct ktermios *termios,
struct serial_rs485 *rs485);
const struct serial_rs485 *rs485_supported;
- int (*register_gpio)(struct pci_dev *pcidev, struct uart_8250_port *port);
- void (*unregister_gpio)(struct uart_8250_port *port);
+ int (*register_gpio)(struct exar8250 *priv, struct pci_dev *pcidev,
+ struct uart_8250_port *port);
+ void (*unregister_gpio)(struct exar8250 *priv);
};
/**
@@ -256,7 +258,8 @@ struct exar8250 {
struct exar8250_board *board;
struct eeprom_93cx6 eeprom;
void __iomem *virt;
- int line[];
+ struct platform_device *gpio;
+ struct uart_8250_port *uport[];
};
static inline void exar_write_reg(struct exar8250 *priv,
@@ -799,7 +802,7 @@ static int cti_rs485_config_mpio_tristate(struct uart_port *port,
struct ktermios *termios,
struct serial_rs485 *rs485)
{
- struct exar8250 *priv = (struct exar8250 *)port->private_data;
+ struct exar8250 *priv = port->private_data;
int ret;
ret = generic_rs485_config(port, termios, rs485);
@@ -837,7 +840,7 @@ static int cti_port_setup_common(struct exar8250 *priv,
if (ret)
return ret;
- port->port.private_data = (void *)priv;
+ port->port.private_data = priv;
port->port.pm = exar_pm;
port->port.shutdown = exar_shutdown;
@@ -1167,22 +1170,21 @@ static const struct software_node exar_gpio_node = {
.properties = exar_gpio_properties,
};
-static int xr17v35x_register_gpio(struct pci_dev *pcidev, struct uart_8250_port *port)
+static int xr17v35x_register_gpio(struct exar8250 *priv, struct pci_dev *pcidev,
+ struct uart_8250_port *port)
{
if (pcidev->vendor == PCI_VENDOR_ID_EXAR)
- port->port.private_data =
- __xr17v35x_register_gpio(pcidev, &exar_gpio_node);
+ priv->gpio = __xr17v35x_register_gpio(pcidev, &exar_gpio_node);
return 0;
}
-static void xr17v35x_unregister_gpio(struct uart_8250_port *port)
+static void xr17v35x_unregister_gpio(struct exar8250 *priv)
{
- if (!port->port.private_data)
- return;
-
- __xr17v35x_unregister_gpio(port->port.private_data);
- port->port.private_data = NULL;
+ if (priv->gpio) {
+ __xr17v35x_unregister_gpio(priv->gpio);
+ priv->gpio = NULL;
+ }
}
static int sealevel_rs485_config(struct uart_port *port, struct ktermios *termios,
@@ -1279,8 +1281,9 @@ static const struct software_node iot2040_gpio_node = {
.properties = iot2040_gpio_properties,
};
-static int iot2040_register_gpio(struct pci_dev *pcidev,
- struct uart_8250_port *port)
+static int iot2040_register_gpio(struct exar8250 *priv,
+ struct pci_dev *pcidev,
+ struct uart_8250_port *port)
{
u8 __iomem *p = port->port.membase;
@@ -1289,8 +1292,7 @@ static int iot2040_register_gpio(struct pci_dev *pcidev,
writeb(IOT2040_UARTS_ENABLE, p + UART_EXAR_MPIOLVL_15_8);
writeb(IOT2040_UARTS_GPIO_HI_MODE, p + UART_EXAR_MPIOSEL_15_8);
- port->port.private_data =
- __xr17v35x_register_gpio(pcidev, &iot2040_gpio_node);
+ priv->gpio = __xr17v35x_register_gpio(pcidev, &iot2040_gpio_node);
return 0;
}
@@ -1367,7 +1369,7 @@ pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev,
/* Setup Multipurpose Input/Output pins. */
setup_gpio(pcidev, p);
- ret = platform->register_gpio(pcidev, port);
+ ret = platform->register_gpio(priv, pcidev, port);
}
return ret;
@@ -1377,9 +1379,8 @@ static void pci_xr17v35x_exit(struct pci_dev *pcidev)
{
const struct exar8250_platform *platform = exar_get_platform();
struct exar8250 *priv = pci_get_drvdata(pcidev);
- struct uart_8250_port *port = serial8250_get_port(priv->line[0]);
- platform->unregister_gpio(port);
+ platform->unregister_gpio(priv);
}
static inline void exar_misc_clear(struct exar8250 *priv)
@@ -1460,7 +1461,7 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
if (nr_ports == 0)
return dev_err_probe(&pcidev->dev, -ENODEV, "failed to get number of ports\n");
- priv = devm_kzalloc(&pcidev->dev, struct_size(priv, line, nr_ports), GFP_KERNEL);
+ priv = devm_kzalloc(&pcidev->dev, struct_size(priv, uport, nr_ports), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -1500,9 +1501,9 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
dev_dbg(&pcidev->dev, "Setup PCI port: port %lx, irq %d, type %d\n",
uart.port.iobase, uart.port.irq, uart.port.iotype);
- priv->line[i] = serial8250_register_8250_port(&uart);
- if (priv->line[i] < 0) {
- dev_err_probe(&pcidev->dev, priv->line[i],
+ priv->uport[i] = serial8250_register_8250_port(&uart);
+ if (IS_ERR(priv->uport[i])) {
+ dev_err_probe(&pcidev->dev, PTR_ERR(priv->uport[i]),
"Couldn't register serial port %lx, type %d, irq %d\n",
uart.port.iobase, uart.port.iotype, uart.port.irq);
break;
@@ -1519,7 +1520,7 @@ static void exar_pci_remove(struct pci_dev *pcidev)
unsigned int i;
for (i = 0; i < priv->nr; i++)
- serial8250_unregister_port(priv->line[i]);
+ serial8250_unregister_port(priv->uport[i]);
/* Ensure that every init quirk is properly torn down */
if (priv->board->exit)
@@ -1532,8 +1533,7 @@ static int exar_suspend(struct device *dev)
unsigned int i;
for (i = 0; i < priv->nr; i++)
- if (priv->line[i] >= 0)
- serial8250_suspend_port(priv->line[i]);
+ serial8250_suspend_port(priv->uport[i]);
return 0;
}
@@ -1546,8 +1546,7 @@ static int exar_resume(struct device *dev)
exar_misc_clear(priv);
for (i = 0; i < priv->nr; i++)
- if (priv->line[i] >= 0)
- serial8250_resume_port(priv->line[i]);
+ serial8250_resume_port(priv->uport[i]);
return 0;
}
diff --git a/drivers/tty/serial/8250/8250_fsl.c b/drivers/tty/serial/8250/8250_fsl.c
index 649ae5c8304d..3578d70594ed 100644
--- a/drivers/tty/serial/8250/8250_fsl.c
+++ b/drivers/tty/serial/8250/8250_fsl.c
@@ -18,6 +18,7 @@
*/
#include <linux/acpi.h>
+#include <linux/err.h>
#include <linux/serial_reg.h>
#include <linux/serial_8250.h>
@@ -99,14 +100,9 @@ int fsl8250_handle_irq(struct uart_port *port)
EXPORT_SYMBOL_GPL(fsl8250_handle_irq);
#ifdef CONFIG_ACPI
-struct fsl8250_data {
- int line;
-};
-
static int fsl8250_acpi_probe(struct platform_device *pdev)
{
- struct fsl8250_data *data;
- struct uart_8250_port port8250;
+ struct uart_8250_port *uport, port8250;
struct device *dev = &pdev->dev;
struct resource *regs;
@@ -148,23 +144,19 @@ static int fsl8250_acpi_probe(struct platform_device *pdev)
if (!port8250.port.membase)
return -ENOMEM;
- data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- data->line = serial8250_register_8250_port(&port8250);
- if (data->line < 0)
- return data->line;
+ uport = serial8250_register_8250_port(&port8250);
+ if (IS_ERR(uport))
+ return PTR_ERR(uport);
- platform_set_drvdata(pdev, data);
+ platform_set_drvdata(pdev, uport);
return 0;
}
static void fsl8250_acpi_remove(struct platform_device *pdev)
{
- struct fsl8250_data *data = platform_get_drvdata(pdev);
+ struct uart_8250_port *uport = platform_get_drvdata(pdev);
- serial8250_unregister_port(data->line);
+ serial8250_unregister_port(uport);
}
static const struct acpi_device_id fsl_8250_acpi_id[] = {
diff --git a/drivers/tty/serial/8250/8250_hp300.c b/drivers/tty/serial/8250/8250_hp300.c
index 59ec0c7377a1..e9599c5c2fea 100644
--- a/drivers/tty/serial/8250/8250_hp300.c
+++ b/drivers/tty/serial/8250/8250_hp300.c
@@ -7,6 +7,7 @@
* by Kars de Jong <jongk@linux-m68k.org>, May 2004.
*/
#include <linux/module.h>
+#include <linux/err.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/kernel.h>
@@ -27,7 +28,7 @@
#ifdef CONFIG_HPAPCI
struct hp300_port {
struct hp300_port *next; /* next port */
- int line; /* line (tty) number */
+ struct uart_8250_port *uport;
};
static struct hp300_port *hp300_ports;
@@ -157,8 +158,7 @@ int __init hp300_setup_serial_console(void)
static int hpdca_init_one(struct dio_dev *d,
const struct dio_device_id *ent)
{
- struct uart_8250_port uart;
- int line;
+ struct uart_8250_port *uport, uart;
#ifdef CONFIG_SERIAL_8250_CONSOLE
if (hp300_uart_scode == d->scode) {
@@ -177,9 +177,8 @@ static int hpdca_init_one(struct dio_dev *d,
uart.port.membase = (char *)(uart.port.mapbase + DIO_VIRADDRBASE);
uart.port.regshift = 1;
uart.port.dev = &d->dev;
- line = serial8250_register_8250_port(&uart);
-
- if (line < 0) {
+ uport = serial8250_register_8250_port(&uart);
+ if (IS_ERR(uport)) {
dev_notice(&d->dev,
"8250_hp300: register_serial() DCA scode %d irq %d failed\n",
d->scode, uart.port.irq);
@@ -188,7 +187,7 @@ static int hpdca_init_one(struct dio_dev *d,
/* Enable board-interrupts */
out_8(d->resource.start + DIO_VIRADDRBASE + DCA_IC, DCA_IC_IE);
- dio_set_drvdata(d, (void *)line);
+ dio_set_drvdata(d, uport);
/* Reset the DCA */
out_8(d->resource.start + DIO_VIRADDRBASE + DCA_ID, 0xff);
@@ -204,7 +203,6 @@ static int __init hp300_8250_init(void)
{
static int called;
#ifdef CONFIG_HPAPCI
- int line;
unsigned long base;
struct uart_8250_port uart;
struct hp300_port *port;
@@ -259,9 +257,8 @@ static int __init hp300_8250_init(void)
uart.port.membase = (char *)(base + DIO_VIRADDRBASE);
uart.port.regshift = 2;
- line = serial8250_register_8250_port(&uart);
-
- if (line < 0) {
+ port->uport = serial8250_register_8250_port(&uart);
+ if (IS_ERR(port->uport)) {
dev_notice(uart.port.dev,
"8250_hp300: register_serial() APCI %d irq %d failed\n",
i, uart.port.irq);
@@ -269,7 +266,6 @@ static int __init hp300_8250_init(void)
continue;
}
- port->line = line;
port->next = hp300_ports;
hp300_ports = port;
@@ -287,14 +283,13 @@ static int __init hp300_8250_init(void)
#ifdef CONFIG_HPDCA
static void hpdca_remove_one(struct dio_dev *d)
{
- int line;
+ struct uart_8250_port *uport = dio_get_drvdata(d);
- line = (int) dio_get_drvdata(d);
if (d->resource.start) {
/* Disable board-interrupts */
out_8(d->resource.start + DIO_VIRADDRBASE + DCA_IC, 0);
}
- serial8250_unregister_port(line);
+ serial8250_unregister_port(uport);
}
#endif
@@ -304,7 +299,7 @@ static void __exit hp300_8250_exit(void)
struct hp300_port *port, *to_free;
for (port = hp300_ports; port; ) {
- serial8250_unregister_port(port->line);
+ serial8250_unregister_port(port->uport);
to_free = port;
port = port->next;
kfree(to_free);
diff --git a/drivers/tty/serial/8250/8250_hub6.c b/drivers/tty/serial/8250/8250_hub6.c
index b6767633c966..848d9723ac56 100644
--- a/drivers/tty/serial/8250/8250_hub6.c
+++ b/drivers/tty/serial/8250/8250_hub6.c
@@ -49,13 +49,12 @@ bool hub6_match_port(const struct uart_port *port1, const struct uart_port *port
}
EXPORT_SYMBOL_GPL(hub6_match_port);
-static int __init hub6_init(void)
+int __init serial8250_hub6_init(void)
{
return platform_device_register(&hub6_device);
}
-module_init(hub6_init);
-
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("8250 serial probe module for Hub6 cards");
-MODULE_LICENSE("GPL");
+void serial8250_hub6_exit(void)
+{
+ platform_device_unregister(&hub6_device);
+}
diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c
index 94542fc143c2..0cdadacd7019 100644
--- a/drivers/tty/serial/8250/8250_ingenic.c
+++ b/drivers/tty/serial/8250/8250_ingenic.c
@@ -8,6 +8,7 @@
#include <linux/clk.h>
#include <linux/console.h>
+#include <linux/err.h>
#include <linux/io.h>
#include <linux/libfdt.h>
#include <linux/module.h>
@@ -29,7 +30,7 @@ struct ingenic_uart_config {
struct ingenic_uart_data {
struct clk *clk_module;
struct clk *clk_baud;
- int line;
+ struct uart_8250_port *uport;
};
static const struct of_device_id of_match[];
@@ -297,9 +298,9 @@ static int ingenic_uart_probe(struct platform_device *pdev)
}
uart.port.uartclk = clk_get_rate(data->clk_baud);
- data->line = serial8250_register_8250_port(&uart);
- if (data->line < 0) {
- err = data->line;
+ data->uport = serial8250_register_8250_port(&uart);
+ if (IS_ERR(data->uport)) {
+ err = PTR_ERR(data->uport);
goto out_disable_baudclk;
}
@@ -318,7 +319,7 @@ static void ingenic_uart_remove(struct platform_device *pdev)
{
struct ingenic_uart_data *data = platform_get_drvdata(pdev);
- serial8250_unregister_port(data->line);
+ serial8250_unregister_port(data->uport);
clk_disable_unprepare(data->clk_module);
clk_disable_unprepare(data->clk_baud);
}
diff --git a/drivers/tty/serial/8250/8250_ioc3.c b/drivers/tty/serial/8250/8250_ioc3.c
index 28e28076782b..088242de2eff 100644
--- a/drivers/tty/serial/8250/8250_ioc3.c
+++ b/drivers/tty/serial/8250/8250_ioc3.c
@@ -9,6 +9,7 @@
*/
#include <linux/module.h>
+#include <linux/err.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/platform_device.h>
@@ -17,10 +18,6 @@
#define IOC3_UARTCLK (22000000 / 3)
-struct ioc3_8250_data {
- int line;
-};
-
static u32 ioc3_serial_in(struct uart_port *p, unsigned int offset)
{
return readb(p->membase + (offset ^ 3));
@@ -33,20 +30,15 @@ static void ioc3_serial_out(struct uart_port *p, unsigned int offset, u32 value)
static int serial8250_ioc3_probe(struct platform_device *pdev)
{
- struct ioc3_8250_data *data;
- struct uart_8250_port up;
+ struct uart_8250_port *uport, up;
struct resource *r;
void __iomem *membase;
- int irq, line;
+ int irq;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r)
return -ENODEV;
- data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
membase = devm_ioremap(&pdev->dev, r->start, resource_size(r));
if (!membase)
return -ENOMEM;
@@ -67,19 +59,19 @@ static int serial8250_ioc3_probe(struct platform_device *pdev)
up.port.mapbase = r->start;
up.port.serial_in = ioc3_serial_in;
up.port.serial_out = ioc3_serial_out;
- line = serial8250_register_8250_port(&up);
- if (line < 0)
- return line;
+ uport = serial8250_register_8250_port(&up);
+ if (IS_ERR(uport))
+ return PTR_ERR(uport);
- platform_set_drvdata(pdev, data);
+ platform_set_drvdata(pdev, uport);
return 0;
}
static void serial8250_ioc3_remove(struct platform_device *pdev)
{
- struct ioc3_8250_data *data = platform_get_drvdata(pdev);
+ struct uart_8250_port *uport = platform_get_drvdata(pdev);
- serial8250_unregister_port(data->line);
+ serial8250_unregister_port(uport);
}
static struct platform_driver serial8250_ioc3_driver = {
diff --git a/drivers/tty/serial/8250/8250_keba.c b/drivers/tty/serial/8250/8250_keba.c
index 5b791b6eefd0..c53ca05a57d7 100644
--- a/drivers/tty/serial/8250/8250_keba.c
+++ b/drivers/tty/serial/8250/8250_keba.c
@@ -62,7 +62,7 @@ enum kuart_mode {
struct kuart {
struct keba_uart_auxdev *auxdev;
void __iomem *base;
- unsigned int line;
+ struct uart_8250_port *uport;
unsigned int flags;
u8 capability;
@@ -174,7 +174,6 @@ static int kuart_probe(struct auxiliary_device *auxdev,
struct uart_8250_port uart = {};
struct resource res;
struct kuart *kuart;
- int retval;
kuart = devm_kzalloc(dev, sizeof(*kuart), GFP_KERNEL);
if (!kuart)
@@ -250,12 +249,10 @@ static int kuart_probe(struct auxiliary_device *auxdev,
}
}
- retval = serial8250_register_8250_port(&uart);
- if (retval < 0)
- return dev_err_probe(&auxdev->dev, retval,
+ kuart->uport = serial8250_register_8250_port(&uart);
+ if (IS_ERR(kuart->uport))
+ return dev_err_probe(&auxdev->dev, PTR_ERR(kuart->uport),
"UART registration failed!\n");
- kuart->line = retval;
-
return 0;
}
@@ -266,7 +263,7 @@ static void kuart_remove(struct auxiliary_device *auxdev)
if (kuart->flags & KUART_USE_CAPABILITY)
kuart_set_phy_mode(kuart, KUART_MODE_NONE);
- serial8250_unregister_port(kuart->line);
+ serial8250_unregister_port(kuart->uport);
}
static const struct auxiliary_device_id kuart_devtype_aux[] = {
diff --git a/drivers/tty/serial/8250/8250_loongson.c b/drivers/tty/serial/8250/8250_loongson.c
index 19acb2c6b611..6d06ed28382d 100644
--- a/drivers/tty/serial/8250/8250_loongson.c
+++ b/drivers/tty/serial/8250/8250_loongson.c
@@ -10,6 +10,7 @@
#include <linux/clk.h>
#include <linux/console.h>
#include <linux/module.h>
+#include <linux/err.h>
#include <linux/io.h>
#include <linux/property.h>
#include <linux/math.h>
@@ -43,7 +44,7 @@ static const struct loongson_uart_ddata ls2k1500_uart_data = {
};
struct loongson_uart_priv {
- int line;
+ struct uart_8250_port *uport;
struct clk *clk;
struct resource *res;
struct reset_control *rst;
@@ -160,13 +161,12 @@ static int loongson_uart_probe(struct platform_device *pdev)
if (ret)
return ret;
- ret = serial8250_register_8250_port(&uart);
- if (ret < 0) {
+ priv->uport = serial8250_register_8250_port(&uart);
+ if (IS_ERR(priv->uport)) {
reset_control_assert(priv->rst);
- return ret;
+ return PTR_ERR(priv->uport);
}
- priv->line = ret;
platform_set_drvdata(pdev, priv);
return 0;
@@ -176,16 +176,16 @@ static void loongson_uart_remove(struct platform_device *pdev)
{
struct loongson_uart_priv *priv = platform_get_drvdata(pdev);
- serial8250_unregister_port(priv->line);
+ serial8250_unregister_port(priv->uport);
reset_control_assert(priv->rst);
}
static int loongson_uart_suspend(struct device *dev)
{
struct loongson_uart_priv *priv = dev_get_drvdata(dev);
- struct uart_8250_port *up = serial8250_get_port(priv->line);
+ struct uart_8250_port *up = priv->uport;
- serial8250_suspend_port(priv->line);
+ serial8250_suspend_port(up);
if (!uart_console(&up->port) || console_suspend_enabled)
clk_disable_unprepare(priv->clk);
@@ -196,7 +196,7 @@ static int loongson_uart_suspend(struct device *dev)
static int loongson_uart_resume(struct device *dev)
{
struct loongson_uart_priv *priv = dev_get_drvdata(dev);
- struct uart_8250_port *up = serial8250_get_port(priv->line);
+ struct uart_8250_port *up = priv->uport;
int ret;
if (!uart_console(&up->port) || console_suspend_enabled) {
@@ -205,7 +205,7 @@ static int loongson_uart_resume(struct device *dev)
return ret;
}
- serial8250_resume_port(priv->line);
+ serial8250_resume_port(up);
return 0;
}
diff --git a/drivers/tty/serial/8250/8250_lpc18xx.c b/drivers/tty/serial/8250/8250_lpc18xx.c
index 6c0489c9c253..5d4d4366e711 100644
--- a/drivers/tty/serial/8250/8250_lpc18xx.c
+++ b/drivers/tty/serial/8250/8250_lpc18xx.c
@@ -10,6 +10,7 @@
*/
#include <linux/clk.h>
+#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -29,7 +30,7 @@ struct lpc18xx_uart_data {
struct uart_8250_dma dma;
struct clk *clk_uart;
struct clk *clk_reg;
- int line;
+ struct uart_8250_port *uport;
};
static int lpc18xx_rs485_config(struct uart_port *port, struct ktermios *termios,
@@ -160,13 +161,13 @@ static int lpc18xx_serial_probe(struct platform_device *pdev)
uart.dma->rxconf.src_maxburst = 1;
uart.dma->txconf.dst_maxburst = 1;
- ret = serial8250_register_8250_port(&uart);
- if (ret < 0) {
+ data->uport = serial8250_register_8250_port(&uart);
+ if (IS_ERR(data->uport)) {
+ ret = PTR_ERR(data->uport);
dev_err(&pdev->dev, "unable to register 8250 port\n");
goto dis_uart_clk;
}
- data->line = ret;
platform_set_drvdata(pdev, data);
return 0;
@@ -182,7 +183,7 @@ static void lpc18xx_serial_remove(struct platform_device *pdev)
{
struct lpc18xx_uart_data *data = platform_get_drvdata(pdev);
- serial8250_unregister_port(data->line);
+ serial8250_unregister_port(data->uport);
clk_disable_unprepare(data->clk_uart);
clk_disable_unprepare(data->clk_reg);
}
diff --git a/drivers/tty/serial/8250/8250_lpss.c b/drivers/tty/serial/8250/8250_lpss.c
index 776ec1ef29d6..f1b4b975571a 100644
--- a/drivers/tty/serial/8250/8250_lpss.c
+++ b/drivers/tty/serial/8250/8250_lpss.c
@@ -7,6 +7,7 @@
*/
#include <linux/bitops.h>
+#include <linux/err.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/rational.h>
@@ -183,9 +184,8 @@ static int ehl_serial_setup(struct lpss8250 *lpss, struct uart_port *port)
static void ehl_serial_exit(struct lpss8250 *lpss)
{
- struct uart_8250_port *up = serial8250_get_port(lpss->data.line);
-
- up->dma = NULL;
+ if (lpss->data.uport)
+ lpss->data.uport->dma = NULL;
}
#ifdef CONFIG_SERIAL_8250_DMA
@@ -356,11 +356,12 @@ static int lpss8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (ret)
goto err_exit;
- ret = serial8250_register_8250_port(&uart);
- if (ret < 0)
+ struct uart_8250_port *uport = serial8250_register_8250_port(&uart);
+ if (IS_ERR(uport)) {
+ ret = PTR_ERR(uport);
goto err_exit;
-
- lpss->data.line = ret;
+ }
+ lpss->data.uport = uport;
pci_set_drvdata(pdev, lpss);
return 0;
@@ -375,7 +376,7 @@ static void lpss8250_remove(struct pci_dev *pdev)
{
struct lpss8250 *lpss = pci_get_drvdata(pdev);
- serial8250_unregister_port(lpss->data.line);
+ serial8250_unregister_port(lpss->data.uport);
lpss->board->exit(lpss);
pci_free_irq_vectors(pdev);
diff --git a/drivers/tty/serial/8250/8250_men_mcb.c b/drivers/tty/serial/8250/8250_men_mcb.c
index 6373234da03d..1f34e58aaeaf 100644
--- a/drivers/tty/serial/8250/8250_men_mcb.c
+++ b/drivers/tty/serial/8250/8250_men_mcb.c
@@ -2,6 +2,7 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/err.h>
#include <linux/io.h>
#include <linux/mcb.h>
#include <linux/serial.h>
@@ -42,7 +43,7 @@
struct serial_8250_men_mcb_data {
int num_ports;
- int line[MEN_Z025_MAX_UARTS];
+ struct uart_8250_port *uport[MEN_Z025_MAX_UARTS];
unsigned int offset[MEN_Z025_MAX_UARTS];
};
@@ -218,14 +219,13 @@ static int serial_8250_men_mcb_probe(struct mcb_device *mdev,
+ data->offset[i];
/* ok, register the port */
- res = serial8250_register_8250_port(&uart);
- if (res < 0) {
+ data->uport[i] = serial8250_register_8250_port(&uart);
+ if (IS_ERR(data->uport[i])) {
dev_err(&mdev->dev, "unable to register UART port\n");
- return res;
+ return PTR_ERR(data->uport[i]);
}
- data->line[i] = res;
- dev_info(&mdev->dev, "found MCB UART: ttyS%d\n", data->line[i]);
+ dev_info(&mdev->dev, "found MCB UART: ttyS%d\n", data->uport[i]->port.line);
}
return 0;
@@ -240,7 +240,7 @@ static void serial_8250_men_mcb_remove(struct mcb_device *mdev)
return;
for (i = 0; i < data->num_ports; i++)
- serial8250_unregister_port(data->line[i]);
+ serial8250_unregister_port(data->uport[i]);
}
static const struct mcb_device_id serial_8250_men_mcb_ids[] = {
diff --git a/drivers/tty/serial/8250/8250_mid.c b/drivers/tty/serial/8250/8250_mid.c
index 82656645b8a6..44b43163df51 100644
--- a/drivers/tty/serial/8250/8250_mid.c
+++ b/drivers/tty/serial/8250/8250_mid.c
@@ -7,6 +7,8 @@
*/
#include <linux/bitops.h>
+#include <linux/cleanup.h>
+#include <linux/err.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/rational.h>
@@ -40,7 +42,7 @@ struct mid8250_board {
};
struct mid8250 {
- int line;
+ struct uart_8250_port *uport;
int dma_index;
struct pci_dev *dma_dev;
struct uart_8250_dma dma;
@@ -209,6 +211,7 @@ static void mid8250_set_termios(struct uart_port *p, struct ktermios *termios,
const struct ktermios *old)
{
unsigned int baud = tty_termios_baud_rate(termios);
+ struct uart_8250_port *up = up_to_u8250p(p);
struct mid8250 *mid = p->private_data;
unsigned short ps = 16;
unsigned long fuart = baud * ps;
@@ -231,11 +234,16 @@ static void mid8250_set_termios(struct uart_port *p, struct ktermios *termios,
}
rational_best_approximation(fuart, mid->board->freq, w, w, &mul, &div);
- p->uartclk = fuart * 16 / ps; /* core uses ps = 16 always */
- writel(ps, p->membase + INTEL_MID_UART_PS); /* set PS */
- writel(mul, p->membase + INTEL_MID_UART_MUL); /* set MUL */
- writel(div, p->membase + INTEL_MID_UART_DIV);
+ scoped_guard(spinlock_irq, &p->lock) {
+ p->uartclk = fuart * 16 / ps; /* core uses ps = 16 always */
+
+ serial8250_wait_for_xmitr(up, UART_LSR_BOTH_EMPTY);
+
+ writel(ps, p->membase + INTEL_MID_UART_PS); /* set PS */
+ writel(mul, p->membase + INTEL_MID_UART_MUL); /* set MUL */
+ writel(div, p->membase + INTEL_MID_UART_DIV);
+ }
serial8250_do_set_termios(p, termios, old);
}
@@ -328,11 +336,11 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (ret)
goto err;
- ret = serial8250_register_8250_port(&uart);
- if (ret < 0)
+ mid->uport = serial8250_register_8250_port(&uart);
+ if (IS_ERR(mid->uport)) {
+ ret = PTR_ERR(mid->uport);
goto err;
-
- mid->line = ret;
+ }
pci_set_drvdata(pdev, mid);
return 0;
@@ -347,7 +355,7 @@ static void mid8250_remove(struct pci_dev *pdev)
{
struct mid8250 *mid = pci_get_drvdata(pdev);
- serial8250_unregister_port(mid->line);
+ serial8250_unregister_port(mid->uport);
if (mid->board->exit)
mid->board->exit(mid);
@@ -408,3 +416,4 @@ module_pci_driver(mid8250_pci_driver);
MODULE_AUTHOR("Intel Corporation");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Intel MID UART driver");
+MODULE_IMPORT_NS("SERIAL_8250");
diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c
index 841d64f6a707..d1fb917b762a 100644
--- a/drivers/tty/serial/8250/8250_mtk.c
+++ b/drivers/tty/serial/8250/8250_mtk.c
@@ -6,6 +6,7 @@
* Author: Matthias Brugger <matthias.bgg@gmail.com>
*/
#include <linux/clk.h>
+#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -68,7 +69,7 @@ enum dma_rx_status {
#endif
struct mtk8250_data {
- int line;
+ struct uart_8250_port *uport;
unsigned int rx_pos;
unsigned int clk_count;
struct clk *uart_clk;
@@ -431,7 +432,7 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
static int __maybe_unused mtk8250_runtime_suspend(struct device *dev)
{
struct mtk8250_data *data = dev_get_drvdata(dev);
- struct uart_8250_port *up = serial8250_get_port(data->line);
+ struct uart_8250_port *up = data->uport;
/* wait until UART in idle status */
while
@@ -587,9 +588,9 @@ static int mtk8250_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, data);
- data->line = serial8250_register_8250_port(&uart);
- if (data->line < 0)
- return data->line;
+ data->uport = serial8250_register_8250_port(&uart);
+ if (IS_ERR(data->uport))
+ return PTR_ERR(data->uport);
data->rx_wakeup_irq = platform_get_irq_optional(pdev, 1);
@@ -605,7 +606,7 @@ static void mtk8250_remove(struct platform_device *pdev)
pm_runtime_get_sync(&pdev->dev);
- serial8250_unregister_port(data->line);
+ serial8250_unregister_port(data->uport);
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
@@ -617,7 +618,7 @@ static int __maybe_unused mtk8250_suspend(struct device *dev)
int irq = data->rx_wakeup_irq;
int err;
- serial8250_suspend_port(data->line);
+ serial8250_suspend_port(data->uport);
pinctrl_pm_select_sleep_state(dev);
if (irq >= 0) {
@@ -627,7 +628,7 @@ static int __maybe_unused mtk8250_suspend(struct device *dev)
"failed to enable irq wake on IRQ %d: %d\n",
irq, err);
pinctrl_pm_select_default_state(dev);
- serial8250_resume_port(data->line);
+ serial8250_resume_port(data->uport);
return err;
}
}
@@ -644,7 +645,7 @@ static int __maybe_unused mtk8250_resume(struct device *dev)
disable_irq_wake(irq);
pinctrl_pm_select_default_state(dev);
- serial8250_resume_port(data->line);
+ serial8250_resume_port(data->uport);
return 0;
}
diff --git a/drivers/tty/serial/8250/8250_mxpcie.c b/drivers/tty/serial/8250/8250_mxpcie.c
index ce873fbd62e9..4935a5d1c1a3 100644
--- a/drivers/tty/serial/8250/8250_mxpcie.c
+++ b/drivers/tty/serial/8250/8250_mxpcie.c
@@ -9,6 +9,7 @@
#include <linux/bits.h>
#include <linux/device.h>
#include <linux/dev_printk.h>
+#include <linux/err.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/module.h>
@@ -102,13 +103,14 @@
#define MOXA_ODD_RS_MASK GENMASK(7, 4)
struct mxpcie8250_port {
- int line;
+ struct uart_8250_port *uport;
u8 rx_trig_level;
};
struct mxpcie8250 {
unsigned int supp_rs;
unsigned int num_ports;
+ unsigned int nr; /* ports actually registered */
void __iomem *bar1_base; /* UART registers (MMIO) */
void __iomem *bar2_base; /* UIR / GPIO / CPLD (IO) */
struct mxpcie8250_port port[] __counted_by(num_ports);
@@ -217,8 +219,6 @@ static void mxpcie8250_set_termios(struct uart_port *port,
const struct ktermios *old)
{
struct uart_8250_port *up = up_to_u8250p(port);
- struct tty_struct *tty = port->state->port.tty;
- unsigned int cflag = tty->termios.c_cflag;
u8 efr, val;
serial8250_do_set_termios(port, new, old);
@@ -228,23 +228,25 @@ static void mxpcie8250_set_termios(struct uart_port *port,
efr = serial_in(up, MOXA_PUART_EFR);
efr &= ~(MOXA_PUART_EFR_AUTO_RTS | MOXA_PUART_EFR_AUTO_CTS);
- if (cflag & CRTSCTS) {
+ if (new->c_cflag & CRTSCTS) {
efr |= (MOXA_PUART_EFR_AUTO_RTS | MOXA_PUART_EFR_AUTO_CTS);
up->port.status |= (UPSTAT_AUTORTS | UPSTAT_AUTOCTS);
}
/* Set on-chip software flow control character */
- serial_out(up, MOXA_PUART_XON1, START_CHAR(tty));
- serial_out(up, MOXA_PUART_XON2, START_CHAR(tty));
- serial_out(up, MOXA_PUART_XOFF1, STOP_CHAR(tty));
- serial_out(up, MOXA_PUART_XOFF2, STOP_CHAR(tty));
+ serial_out(up, MOXA_PUART_XON1, new->c_cc[VSTART]);
+ serial_out(up, MOXA_PUART_XON2, new->c_cc[VSTART]);
+ serial_out(up, MOXA_PUART_XOFF1, new->c_cc[VSTOP]);
+ serial_out(up, MOXA_PUART_XOFF2, new->c_cc[VSTOP]);
- val = I_IXON(tty) ? MOXA_PUART_EFR_RX_FLOW_XON1_XOFF1 : MOXA_PUART_EFR_RX_FLOW_DISABLED;
+ val = (new->c_iflag & IXON) ? MOXA_PUART_EFR_RX_FLOW_XON1_XOFF1 :
+ MOXA_PUART_EFR_RX_FLOW_DISABLED;
FIELD_MODIFY(MOXA_PUART_EFR_RX_FLOW_MASK, &efr, val);
- val = I_IXOFF(tty) ? MOXA_PUART_EFR_TX_FLOW_XON1_XOFF1 : MOXA_PUART_EFR_TX_FLOW_DISABLED;
+ val = (new->c_iflag & IXOFF) ? MOXA_PUART_EFR_TX_FLOW_XON1_XOFF1 :
+ MOXA_PUART_EFR_TX_FLOW_DISABLED;
FIELD_MODIFY(MOXA_PUART_EFR_TX_FLOW_MASK, &efr, val);
- if (I_IXOFF(tty))
+ if (new->c_iflag & IXOFF)
up->port.status |= UPSTAT_AUTOXOFF;
serial_out(up, MOXA_PUART_EFR, efr);
@@ -517,6 +519,7 @@ static int mxpcie8250_probe(struct pci_dev *pdev, const struct pci_device_id *id
struct mxpcie8250 *priv;
unsigned short device = pdev->device;
unsigned int num_ports;
+ unsigned int i;
int ret;
ret = pcim_enable_device(pdev);
@@ -542,6 +545,8 @@ static int mxpcie8250_probe(struct pci_dev *pdev, const struct pci_device_id *id
mxpcie8250_init_board(pdev, priv);
+ pci_set_drvdata(pdev, priv);
+
up.port.dev = dev;
up.port.irq = pdev->irq;
up.port.uartclk = MOXA_PUART_BASE_BAUD * 16;
@@ -562,23 +567,23 @@ static int mxpcie8250_probe(struct pci_dev *pdev, const struct pci_device_id *id
up.port.handle_irq = mxpcie8250_handle_irq;
up.port.break_ctl = mxpcie8250_break_ctl;
- for (unsigned int i = 0; i < num_ports; i++) {
+ for (i = 0; i < num_ports; i++) {
mxpcie8250_setup_port(pdev, priv, &up, i);
dev_dbg(dev, "Setup PCI port: port %lx, irq %d, type %d\n",
up.port.iobase, up.port.irq, up.port.iotype);
- priv->port[i].line = serial8250_register_8250_port(&up);
- if (priv->port[i].line < 0) {
+ priv->port[i].uport = serial8250_register_8250_port(&up);
+ if (IS_ERR(priv->port[i].uport)) {
dev_err(dev,
- "Couldn't register serial port %lx, irq %d, type %d, error %d\n",
+ "Couldn't register serial port %lx, irq %d, type %d, error %pe\n",
up.port.iobase, up.port.irq,
- up.port.iotype, priv->port[i].line);
+ up.port.iotype, priv->port[i].uport);
break;
}
priv->port[i].rx_trig_level = MOXA_PUART_RX_TRIG_DEFAULT;
}
- pci_set_drvdata(pdev, priv);
+ priv->nr = i;
return 0;
}
@@ -587,8 +592,8 @@ static void mxpcie8250_remove(struct pci_dev *pdev)
{
struct mxpcie8250 *priv = pci_get_drvdata(pdev);
- for (unsigned int i = 0; i < priv->num_ports; i++)
- serial8250_unregister_port(priv->port[i].line);
+ for (unsigned int i = 0; i < priv->nr; i++)
+ serial8250_unregister_port(priv->port[i].uport);
}
static const struct pci_device_id mxpcie8250_pci_ids[] = {
diff --git a/drivers/tty/serial/8250/8250_ni.c b/drivers/tty/serial/8250/8250_ni.c
index 9f945f8ed1de..509c1814cc87 100644
--- a/drivers/tty/serial/8250/8250_ni.c
+++ b/drivers/tty/serial/8250/8250_ni.c
@@ -14,6 +14,7 @@
#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/device.h>
+#include <linux/err.h>
#include <linux/io.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -73,7 +74,7 @@ struct ni16550_device_info {
};
struct ni16550_data {
- int line;
+ struct uart_8250_port *uport;
struct clk *clk;
};
@@ -383,10 +384,9 @@ static int ni16550_probe(struct platform_device *pdev)
ni16550_rs485_setup(&uart->port);
}
- ret = serial8250_register_8250_port(uart);
- if (ret < 0)
- return ret;
- data->line = ret;
+ data->uport = serial8250_register_8250_port(uart);
+ if (IS_ERR(data->uport))
+ return PTR_ERR(data->uport);
platform_set_drvdata(pdev, data);
return 0;
@@ -396,7 +396,7 @@ static void ni16550_remove(struct platform_device *pdev)
{
struct ni16550_data *data = platform_get_drvdata(pdev);
- serial8250_unregister_port(data->line);
+ serial8250_unregister_port(data->uport);
}
/* NI 16550 RS-485 Interface */
diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c
index b1561c499acd..b41ca604083f 100644
--- a/drivers/tty/serial/8250/8250_of.c
+++ b/drivers/tty/serial/8250/8250_of.c
@@ -8,6 +8,7 @@
#include <linux/align.h>
#include <linux/bits.h>
#include <linux/console.h>
+#include <linux/err.h>
#include <linux/math.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -28,7 +29,7 @@ struct of_serial_info {
struct clk *bus_clk;
struct reset_control *rst;
int type;
- int line;
+ struct uart_8250_port *uport;
struct notifier_block clk_notifier;
};
@@ -71,11 +72,10 @@ static int of_platform_serial_clk_notifier_cb(struct notifier_block *nb, unsigne
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);
+ serial8250_update_uartclk(&info->uport->port, ndata->new_rate);
return NOTIFY_OK;
}
@@ -292,12 +292,13 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
&port8250.overrun_backoff_time_ms) != 0)
port8250.overrun_backoff_time_ms = 0;
- ret = serial8250_register_8250_port(&port8250);
- if (ret < 0)
+ info->uport = serial8250_register_8250_port(&port8250);
+ if (IS_ERR(info->uport)) {
+ ret = PTR_ERR(info->uport);
goto err_dispose;
+ }
info->type = port_type;
- info->line = ret;
platform_set_drvdata(ofdev, info);
if (info->clk) {
@@ -311,7 +312,7 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
return 0;
err_unregister:
- serial8250_unregister_port(info->line);
+ serial8250_unregister_port(info->uport);
err_dispose:
pm_runtime_put_sync(&ofdev->dev);
pm_runtime_disable(&ofdev->dev);
@@ -330,7 +331,7 @@ static void of_platform_serial_remove(struct platform_device *ofdev)
if (info->clk)
clk_notifier_unregister(info->clk, &info->clk_notifier);
- serial8250_unregister_port(info->line);
+ serial8250_unregister_port(info->uport);
reset_control_assert(info->rst);
pm_runtime_put_sync(&ofdev->dev);
@@ -342,10 +343,10 @@ static void of_platform_serial_remove(struct platform_device *ofdev)
static int of_serial_suspend(struct device *dev)
{
struct of_serial_info *info = dev_get_drvdata(dev);
- struct uart_8250_port *port8250 = serial8250_get_port(info->line);
+ struct uart_8250_port *port8250 = info->uport;
struct uart_port *port = &port8250->port;
- serial8250_suspend_port(info->line);
+ serial8250_suspend_port(port8250);
if (!uart_console(port) || console_suspend_enabled) {
pm_runtime_put_sync(dev);
@@ -358,7 +359,7 @@ static int of_serial_suspend(struct device *dev)
static int of_serial_resume(struct device *dev)
{
struct of_serial_info *info = dev_get_drvdata(dev);
- struct uart_8250_port *port8250 = serial8250_get_port(info->line);
+ struct uart_8250_port *port8250 = info->uport;
struct uart_port *port = &port8250->port;
if (!uart_console(port) || console_suspend_enabled) {
@@ -367,7 +368,7 @@ static int of_serial_resume(struct device *dev)
clk_prepare_enable(info->clk);
}
- serial8250_resume_port(info->line);
+ serial8250_resume_port(port8250);
return 0;
}
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index ceecb39fb82d..29a203ed93fd 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -11,6 +11,7 @@
#include <linux/atomic.h>
#include <linux/clk.h>
#include <linux/device.h>
+#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/serial_8250.h>
@@ -124,7 +125,7 @@
#define UART_OMAP_TO_H 0x27
struct omap8250_priv {
void __iomem *membase;
- int line;
+ struct uart_8250_port *uport;
u8 habit;
u8 mdr1;
u8 mdr3;
@@ -628,7 +629,7 @@ static int omap_8250_dma_handle_irq(struct uart_port *port);
static irqreturn_t omap8250_irq(int irq, void *dev_id)
{
struct omap8250_priv *priv = dev_id;
- struct uart_8250_port *up = serial8250_get_port(priv->line);
+ struct uart_8250_port *up = priv->uport;
struct uart_port *port = &up->port;
unsigned int iir, lsr;
int ret;
@@ -711,6 +712,9 @@ static int omap_8250_startup(struct uart_port *port)
struct uart_8250_dma *dma = &priv->omap8250_dma;
int ret;
+ /* ISR and runtime PM need the uport; probe sets it only after registration */
+ priv->uport = up;
+
#ifdef CONFIG_PM
up->capabilities |= UART_CAP_RPM;
#endif
@@ -1076,7 +1080,7 @@ static void omap_8250_dma_tx_complete(void *param)
bool en_thri = false;
struct omap8250_priv *priv = p->port.private_data;
- dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr,
+ dma_sync_single_for_cpu(dmaengine_get_dma_device(dma->txchan), dma->tx_addr,
UART_XMIT_SIZE, DMA_TO_DEVICE);
guard(uart_port_lock_irqsave)(&p->port);
@@ -1193,7 +1197,7 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
dma->tx_cookie = dmaengine_submit(desc);
- dma_sync_single_for_device(dma->txchan->device->dev, dma->tx_addr,
+ dma_sync_single_for_device(dmaengine_get_dma_device(dma->txchan), dma->tx_addr,
UART_XMIT_SIZE, DMA_TO_DEVICE);
dma_async_issue_pending(dma->txchan);
@@ -1506,7 +1510,7 @@ static int omap8250_probe(struct platform_device *pdev)
}
priv->membase = membase;
- priv->line = -ENODEV;
+ priv->uport = NULL;
priv->latency = PM_QOS_CPU_LATENCY_DEFAULT_VALUE;
priv->calc_latency = PM_QOS_CPU_LATENCY_DEFAULT_VALUE;
cpu_latency_qos_add_request(&priv->pm_qos_request, priv->latency);
@@ -1587,12 +1591,13 @@ static int omap8250_probe(struct platform_device *pdev)
goto err;
}
- ret = serial8250_register_8250_port(&up);
- if (ret < 0) {
+ struct uart_8250_port *uport = serial8250_register_8250_port(&up);
+ if (IS_ERR(uport)) {
+ ret = PTR_ERR(uport);
dev_err(&pdev->dev, "unable to register 8250 port\n");
goto err;
}
- priv->line = ret;
+ priv->uport = uport;
pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
@@ -1621,10 +1626,10 @@ static void omap8250_remove(struct platform_device *pdev)
if (err)
dev_err(&pdev->dev, "Failed to resume hardware\n");
- up = serial8250_get_port(priv->line);
+ up = priv->uport;
omap_8250_shutdown(&up->port);
- serial8250_unregister_port(priv->line);
- priv->line = -ENODEV;
+ serial8250_unregister_port(up);
+ priv->uport = NULL;
dev_pm_clear_wake_irq(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
pm_runtime_put_sync(&pdev->dev);
@@ -1656,7 +1661,7 @@ static void omap8250_complete(struct device *dev)
static int omap8250_suspend(struct device *dev)
{
struct omap8250_priv *priv = dev_get_drvdata(dev);
- struct uart_8250_port *up = serial8250_get_port(priv->line);
+ struct uart_8250_port *up = priv->uport;
int err = 0;
err = omap8250_select_wakeup_pinctrl(dev, priv);
@@ -1666,7 +1671,7 @@ static int omap8250_suspend(struct device *dev)
return err;
}
- serial8250_suspend_port(priv->line);
+ serial8250_suspend_port(up);
err = pm_runtime_resume_and_get(dev);
if (err)
@@ -1684,7 +1689,7 @@ static int omap8250_suspend(struct device *dev)
static int omap8250_resume(struct device *dev)
{
struct omap8250_priv *priv = dev_get_drvdata(dev);
- struct uart_8250_port *up = serial8250_get_port(priv->line);
+ struct uart_8250_port *up = priv->uport;
int err;
err = pinctrl_select_default_state(dev);
@@ -1700,7 +1705,7 @@ static int omap8250_resume(struct device *dev)
return err;
}
- serial8250_resume_port(priv->line);
+ serial8250_resume_port(up);
/* Paired with pm_runtime_resume_and_get() in omap8250_suspend() */
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
@@ -1772,10 +1777,7 @@ static int omap8250_soft_reset(struct device *dev)
static int omap8250_runtime_suspend(struct device *dev)
{
struct omap8250_priv *priv = dev_get_drvdata(dev);
- struct uart_8250_port *up = NULL;
-
- if (priv->line >= 0)
- up = serial8250_get_port(priv->line);
+ struct uart_8250_port *up = priv->uport;
if (priv->habit & UART_ERRATA_CLOCK_DISABLE) {
int ret;
@@ -1805,15 +1807,12 @@ static int omap8250_runtime_suspend(struct device *dev)
static int omap8250_runtime_resume(struct device *dev)
{
struct omap8250_priv *priv = dev_get_drvdata(dev);
- struct uart_8250_port *up = NULL;
+ struct uart_8250_port *up = priv->uport;
/* Did the hardware wake to a device IO interrupt before a wakeirq? */
if (atomic_read(&priv->active))
return 0;
- if (priv->line >= 0)
- up = serial8250_get_port(priv->line);
-
if (up && omap8250_lost_context(up)) {
guard(uart_port_lock_irq)(&up->port);
omap8250_restore_regs(up);
diff --git a/drivers/tty/serial/8250/8250_parisc.c b/drivers/tty/serial/8250/8250_parisc.c
index 4ba05a98791c..1bb15cbde655 100644
--- a/drivers/tty/serial/8250/8250_parisc.c
+++ b/drivers/tty/serial/8250/8250_parisc.c
@@ -5,6 +5,7 @@
* (c) Copyright Matthew Wilcox <willy@debian.org> 2001-2002
*/
+#include <linux/err.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@@ -22,9 +23,8 @@
static int __init serial_init_chip(struct parisc_device *dev)
{
- struct uart_8250_port uart;
+ struct uart_8250_port *uport, uart;
unsigned long address;
- int err;
#if defined(CONFIG_64BIT) && defined(CONFIG_IOSAPIC)
if (!dev->irq && (dev->id.sversion == 0xad))
@@ -64,13 +64,13 @@ static int __init serial_init_chip(struct parisc_device *dev)
uart.port.flags = UPF_BOOT_AUTOCONF;
uart.port.dev = &dev->dev;
- err = serial8250_register_8250_port(&uart);
- if (err < 0) {
+ uport = serial8250_register_8250_port(&uart);
+ if (IS_ERR(uport)) {
dev_warn(&dev->dev,
- "serial8250_register_8250_port returned error %d\n",
- err);
+ "serial8250_register_8250_port returned error %pe\n",
+ uport);
iounmap(uart.port.membase);
- return err;
+ return PTR_ERR(uport);
}
return 0;
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index c24a59896982..1dda63be6b89 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -20,6 +20,7 @@
#include <linux/8250_pci.h>
#include <linux/bitops.h>
#include <linux/bitfield.h>
+#include <linux/err.h>
#include <asm/byteorder.h>
#include <asm/io.h>
@@ -116,7 +117,7 @@ struct serial_private {
unsigned int nr;
struct pci_serial_quirk *quirk;
const struct pciserial_board *board;
- int line[];
+ struct uart_8250_port *uport[];
};
#define PCI_DEVICE_ID_HPE_PCI_SERIAL 0x37e
@@ -3894,7 +3895,7 @@ static const struct pci_device_id blacklist[] = {
{ PCI_VDEVICE(ACCESSIO, PCI_ANY_ID), .driver_data = REPORT_8250_CONFIG(PERICOM), },
/* Moxa devices */
- { PCI_VDEVICE(MOXA, PCI_ANY_ID), REPORT_8250_CONFIG(MOXA), },
+ { PCI_VDEVICE(MOXA, PCI_ANY_ID), .driver_data = REPORT_8250_CONFIG(MOXA), },
/* End of the black list */
{ }
@@ -4028,7 +4029,7 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board)
nr_ports = rc;
}
- priv = kzalloc_flex(*priv, line, nr_ports);
+ priv = kzalloc_flex(*priv, uport, nr_ports);
if (!priv) {
priv = ERR_PTR(-ENOMEM);
goto err_deinit;
@@ -4071,12 +4072,12 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board)
pci_dbg(dev, "Setup PCI port: port %lx, irq %d, type %d\n",
uart.port.iobase, uart.port.irq, uart.port.iotype);
- priv->line[i] = serial8250_register_8250_port(&uart);
- if (priv->line[i] < 0) {
+ priv->uport[i] = serial8250_register_8250_port(&uart);
+ if (IS_ERR(priv->uport[i])) {
pci_err(dev,
- "Couldn't register serial port %lx, irq %d, type %d, error %d\n",
+ "Couldn't register serial port %lx, irq %d, type %d, error %pe\n",
uart.port.iobase, uart.port.irq,
- uart.port.iotype, priv->line[i]);
+ uart.port.iotype, priv->uport[i]);
break;
}
}
@@ -4098,7 +4099,7 @@ static void pciserial_detach_ports(struct serial_private *priv)
int i;
for (i = 0; i < priv->nr; i++)
- serial8250_unregister_port(priv->line[i]);
+ serial8250_unregister_port(priv->uport[i]);
/*
* Find the exit quirks.
@@ -4120,8 +4121,7 @@ void pciserial_suspend_ports(struct serial_private *priv)
int i;
for (i = 0; i < priv->nr; i++)
- if (priv->line[i] >= 0)
- serial8250_suspend_port(priv->line[i]);
+ serial8250_suspend_port(priv->uport[i]);
/*
* Ensure that every init quirk is properly torn down
@@ -4142,8 +4142,7 @@ void pciserial_resume_ports(struct serial_private *priv)
priv->quirk->init(priv->dev);
for (i = 0; i < priv->nr; i++)
- if (priv->line[i] >= 0)
- serial8250_resume_port(priv->line[i]);
+ serial8250_resume_port(priv->uport[i]);
}
EXPORT_SYMBOL_GPL(pciserial_resume_ports);
diff --git a/drivers/tty/serial/8250/8250_pci1xxxx.c b/drivers/tty/serial/8250/8250_pci1xxxx.c
index feeede164886..af4c5c745fa9 100644
--- a/drivers/tty/serial/8250/8250_pci1xxxx.c
+++ b/drivers/tty/serial/8250/8250_pci1xxxx.c
@@ -12,6 +12,7 @@
#include <linux/bits.h>
#include <linux/circ_buf.h>
#include <linux/device.h>
+#include <linux/err.h>
#include <linux/errno.h>
#include <linux/gfp_types.h>
#include <linux/io.h>
@@ -152,7 +153,7 @@ struct pci1xxxx_8250 {
u8 dev_rev;
u8 pad[3];
void __iomem *membase;
- int line[] __counted_by(nr);
+ struct uart_8250_port *uport[] __counted_by(nr);
};
static const struct serial_rs485 pci1xxxx_rs485_supported = {
@@ -551,9 +552,8 @@ static int pci1xxxx_handle_irq(struct uart_port *port)
return 1;
}
-static bool pci1xxxx_port_suspend(int line)
+static bool pci1xxxx_port_suspend(struct uart_8250_port *up)
{
- struct uart_8250_port *up = serial8250_get_port(line);
struct uart_port *port = &up->port;
struct tty_port *tport = &port->state->port;
unsigned long flags;
@@ -578,9 +578,8 @@ static bool pci1xxxx_port_suspend(int line)
return ret;
}
-static void pci1xxxx_port_resume(int line)
+static void pci1xxxx_port_resume(struct uart_8250_port *up)
{
- struct uart_8250_port *up = serial8250_get_port(line);
struct uart_port *port = &up->port;
struct tty_port *tport = &port->state->port;
unsigned long flags;
@@ -608,9 +607,9 @@ static int pci1xxxx_suspend(struct device *dev)
int i;
for (i = 0; i < priv->nr; i++) {
- if (priv->line[i] >= 0) {
- serial8250_suspend_port(priv->line[i]);
- wakeup |= pci1xxxx_port_suspend(priv->line[i]);
+ if (priv->uport[i]) {
+ serial8250_suspend_port(priv->uport[i]);
+ wakeup |= pci1xxxx_port_suspend(priv->uport[i]);
}
}
@@ -661,9 +660,9 @@ static int pci1xxxx_resume(struct device *dev)
iounmap(p);
for (i = 0; i < priv->nr; i++) {
- if (priv->line[i] >= 0) {
- pci1xxxx_port_resume(priv->line[i]);
- serial8250_resume_port(priv->line[i]);
+ if (priv->uport[i]) {
+ pci1xxxx_port_resume(priv->uport[i]);
+ serial8250_resume_port(priv->uport[i]);
}
}
@@ -779,7 +778,7 @@ static int pci1xxxx_serial_probe(struct pci_dev *pdev,
nr_ports = pci1xxxx_get_num_ports(pdev);
- priv = devm_kzalloc(dev, struct_size(priv, line, nr_ports), GFP_KERNEL);
+ priv = devm_kzalloc(dev, struct_size(priv, uport, nr_ports), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -812,8 +811,6 @@ static int pci1xxxx_serial_probe(struct pci_dev *pdev,
writeb(UART_PCI_CTRL_SET_MULTIPLE_MSI, priv->membase + UART_PCI_CTRL_REG);
for (i = 0; i < nr_ports; i++) {
- priv->line[i] = -ENODEV;
-
port_idx = pci1xxxx_logical_to_physical_port_translate(subsys_dev, i);
if (num_vectors == max_vec_reqd)
@@ -827,13 +824,15 @@ static int pci1xxxx_serial_probe(struct pci_dev *pdev,
continue;
}
- priv->line[i] = serial8250_register_8250_port(&uart);
- if (priv->line[i] < 0) {
+ struct uart_8250_port *uport = serial8250_register_8250_port(&uart);
+ if (IS_ERR(uport)) {
dev_warn(dev,
- "Couldn't register serial port %lx, irq %d, type %d, error %d\n",
- uart.port.iobase, uart.port.irq, uart.port.iotype,
- priv->line[i]);
+ "Couldn't register serial port %lx, irq %d, type %d, error %pe\n",
+ uart.port.iobase, uart.port.irq, uart.port.iotype, uport);
+ continue;
}
+
+ priv->uport[i] = uport;
}
pci_set_drvdata(pdev, priv);
@@ -847,8 +846,8 @@ static void pci1xxxx_serial_remove(struct pci_dev *dev)
unsigned int i;
for (i = 0; i < priv->nr; i++) {
- if (priv->line[i] >= 0)
- serial8250_unregister_port(priv->line[i]);
+ if (priv->uport[i])
+ serial8250_unregister_port(priv->uport[i]);
}
pci_free_irq_vectors(dev);
diff --git a/drivers/tty/serial/8250/8250_pericom.c b/drivers/tty/serial/8250/8250_pericom.c
index b8d5b7714a9d..bbbf48c6d07d 100644
--- a/drivers/tty/serial/8250/8250_pericom.c
+++ b/drivers/tty/serial/8250/8250_pericom.c
@@ -2,6 +2,7 @@
/* Driver for Pericom UART */
#include <linux/bits.h>
+#include <linux/err.h>
#include <linux/module.h>
#include <linux/overflow.h>
#include <linux/pci.h>
@@ -45,7 +46,7 @@
struct pericom8250 {
void __iomem *virt;
unsigned int nr;
- int line[];
+ struct uart_8250_port *uport[];
};
static void pericom_do_set_divisor(struct uart_port *port, unsigned int baud,
@@ -102,7 +103,7 @@ static int pericom8250_probe(struct pci_dev *pdev, const struct pci_device_id *i
else
nr = 1;
- pericom = devm_kzalloc(&pdev->dev, struct_size(pericom, line, nr), GFP_KERNEL);
+ pericom = devm_kzalloc(&pdev->dev, struct_size(pericom, uport, nr), GFP_KERNEL);
if (!pericom)
return -ENOMEM;
@@ -127,12 +128,12 @@ static int pericom8250_probe(struct pci_dev *pdev, const struct pci_device_id *i
dev_dbg(&pdev->dev, "Setup PCI port: port %lx, irq %d, type %d\n",
uart.port.iobase, uart.port.irq, uart.port.iotype);
- pericom->line[i] = serial8250_register_8250_port(&uart);
- if (pericom->line[i] < 0) {
+ pericom->uport[i] = serial8250_register_8250_port(&uart);
+ if (IS_ERR(pericom->uport[i])) {
dev_err(&pdev->dev,
- "Couldn't register serial port %lx, irq %d, type %d, error %d\n",
+ "Couldn't register serial port %lx, irq %d, type %d, error %pe\n",
uart.port.iobase, uart.port.irq,
- uart.port.iotype, pericom->line[i]);
+ uart.port.iotype, pericom->uport[i]);
break;
}
}
@@ -148,7 +149,7 @@ static void pericom8250_remove(struct pci_dev *pdev)
unsigned int i;
for (i = 0; i < pericom->nr; i++)
- serial8250_unregister_port(pericom->line[i]);
+ serial8250_unregister_port(pericom->uport[i]);
}
static const struct pci_device_id pericom8250_pci_ids[] = {
diff --git a/drivers/tty/serial/8250/8250_platform.c b/drivers/tty/serial/8250/8250_platform.c
index e060e0427fc9..7ce7ad295fae 100644
--- a/drivers/tty/serial/8250/8250_platform.c
+++ b/drivers/tty/serial/8250/8250_platform.c
@@ -11,6 +11,7 @@
#include <linux/acpi.h>
#include <linux/array_size.h>
#include <linux/cleanup.h>
+#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -110,7 +111,7 @@ static int serial8250_probe_acpi(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *regs;
- int ret, line;
+ int ret;
struct uart_8250_port *uart __free(kfree) = kzalloc_obj(*uart);
if (!uart)
@@ -146,16 +147,12 @@ static int serial8250_probe_acpi(struct platform_device *pdev)
if (ret)
return ret;
- line = serial8250_register_8250_port(uart);
- if (line < 0)
- return line;
-
- return 0;
+ return PTR_ERR_OR_ZERO(serial8250_register_8250_port(uart));
}
static int serial8250_probe_platform(struct platform_device *dev, struct plat_serial8250_port *p)
{
- int ret, i;
+ int i;
struct uart_8250_port *uart __free(kfree) = kzalloc_obj(*uart);
if (!uart)
@@ -192,12 +189,12 @@ static int serial8250_probe_platform(struct platform_device *dev, struct plat_se
if (share_irqs)
uart->port.irqflags |= IRQF_SHARED;
- ret = serial8250_register_8250_port(uart);
- if (ret < 0) {
+ struct uart_8250_port *uport = serial8250_register_8250_port(uart);
+ if (IS_ERR(uport)) {
dev_err(&dev->dev, "unable to register port at index %d "
- "(IO%lx MEM%llx IRQ%d): %d\n", i,
+ "(IO%lx MEM%llx IRQ%d): %pe\n", i,
p->iobase, (unsigned long long)p->mapbase,
- p->irq, ret);
+ p->irq, uport);
}
}
return 0;
@@ -239,7 +236,7 @@ static void serial8250_remove(struct platform_device *dev)
struct uart_8250_port *up = serial8250_get_port(i);
if (up->port.dev == &dev->dev)
- serial8250_unregister_port(i);
+ serial8250_unregister_port(up);
}
}
@@ -265,7 +262,7 @@ static int serial8250_resume(struct platform_device *dev)
struct uart_8250_port *up = serial8250_get_port(i);
if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
- serial8250_resume_port(i);
+ serial8250_resume_port(up);
}
return 0;
@@ -320,10 +317,14 @@ static int __init serial8250_init(void)
if (ret)
goto unreg_uart_drv;
+ ret = serial8250_hub6_init();
+ if (ret)
+ goto unreg_pnp;
+
serial8250_isa_devs = platform_device_alloc("serial8250", PLAT8250_DEV_LEGACY);
if (!serial8250_isa_devs) {
ret = -ENOMEM;
- goto unreg_pnp;
+ goto unreg_hub6;
}
ret = platform_device_add(serial8250_isa_devs);
@@ -339,6 +340,8 @@ static int __init serial8250_init(void)
platform_device_del(serial8250_isa_devs);
put_dev:
platform_device_put(serial8250_isa_devs);
+unreg_hub6:
+ serial8250_hub6_exit();
unreg_pnp:
serial8250_pnp_exit();
unreg_uart_drv:
@@ -366,6 +369,7 @@ static void __exit serial8250_exit(void)
platform_driver_unregister(&serial8250_isa_driver);
platform_device_unregister(isa_dev);
+ serial8250_hub6_exit();
serial8250_pnp_exit();
#ifdef CONFIG_SPARC
diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c
index 6bfdeff5fe22..f9558df37108 100644
--- a/drivers/tty/serial/8250/8250_pnp.c
+++ b/drivers/tty/serial/8250/8250_pnp.c
@@ -8,6 +8,7 @@
*
* Ported to the Linux PnP Layer - (C) Adam Belay.
*/
+#include <linux/err.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pm.h>
@@ -436,7 +437,6 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
{
struct uart_8250_port uart, *port;
int ret, flags = dev_id->driver_data;
- long line;
if (flags & UNKNOWN_DEV) {
ret = serial_pnp_guess_board(dev);
@@ -477,39 +477,38 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
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))
+ port = serial8250_register_8250_port(&uart);
+ if (IS_ERR(port) || (flags & CIR_PORT))
return -ENODEV;
- port = serial8250_get_port(line);
if (uart_console(&port->port))
dev->capabilities |= PNP_CONSOLE;
- pnp_set_drvdata(dev, (void *)line);
+ pnp_set_drvdata(dev, port);
return 0;
}
static void serial_pnp_remove(struct pnp_dev *dev)
{
- long line = (long)pnp_get_drvdata(dev);
+ struct uart_8250_port *uport = pnp_get_drvdata(dev);
dev->capabilities &= ~PNP_CONSOLE;
- serial8250_unregister_port(line);
+ serial8250_unregister_port(uport);
}
static int serial_pnp_suspend(struct device *dev)
{
- long line = (long)dev_get_drvdata(dev);
+ struct uart_8250_port *uport = dev_get_drvdata(dev);
- serial8250_suspend_port(line);
+ serial8250_suspend_port(uport);
return 0;
}
static int serial_pnp_resume(struct device *dev)
{
- long line = (long)dev_get_drvdata(dev);
+ struct uart_8250_port *uport = dev_get_drvdata(dev);
- serial8250_resume_port(line);
+ serial8250_resume_port(uport);
return 0;
}
@@ -526,7 +525,7 @@ static struct pnp_driver serial_pnp_driver = {
.id_table = pnp_dev_table,
};
-int serial8250_pnp_init(void)
+int __init serial8250_pnp_init(void)
{
return pnp_register_driver(&serial_pnp_driver);
}
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index b01baff71f60..36b2b0a2c05c 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -319,6 +319,22 @@ static const struct serial8250_config uart_config[] = {
.rxtrig_bytes = {15, 31, 63, 111},
.flags = UART_CAP_FIFO,
},
+ [UART_PORT_AIROHA] = {
+ .name = "Airoha UART",
+ .fifo_size = 8,
+ .tx_loadsz = 1,
+ .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | UART_FCR_CLEAR_RCVR,
+ .rxtrig_bytes = {1, 4, 4, 4},
+ .flags = UART_CAP_FIFO,
+ },
+ [UART_PORT_AIROHA_HS] = {
+ .name = "Airoha HSUART",
+ .fifo_size = 128,
+ .tx_loadsz = 128,
+ .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | UART_FCR_CLEAR_RCVR,
+ .rxtrig_bytes = {1, 4},
+ .flags = UART_CAP_FIFO,
+ },
};
/* Uart divisor latch read */
@@ -526,7 +542,6 @@ void serial8250_rpm_put(struct uart_8250_port *p)
{
if (!(p->capabilities & UART_CAP_RPM))
return;
- pm_runtime_mark_last_busy(p->port.dev);
pm_runtime_put_autosuspend(p->port.dev);
}
EXPORT_SYMBOL_GPL(serial8250_rpm_put);
@@ -667,7 +682,6 @@ static void serial8250_rpm_put_tx(struct uart_8250_port *p)
rpm_active = xchg(&p->rpm_tx_active, 0);
if (!rpm_active)
return;
- pm_runtime_mark_last_busy(p->port.dev);
pm_runtime_put_autosuspend(p->port.dev);
}
@@ -1880,13 +1894,22 @@ EXPORT_SYMBOL_GPL(serial8250_handle_irq);
static int serial8250_default_handle_irq(struct uart_port *port)
{
- struct uart_8250_port *up = up_to_u8250p(port);
unsigned int iir;
+ int pm_status;
+ int ret;
- guard(serial8250_rpm)(up);
+ /* if driver suspended, return, probably shared interrupt */
+ pm_status = pm_runtime_get_if_active(port->dev);
+ if (!pm_status)
+ return 0;
iir = serial_port_in(port, UART_IIR);
- return serial8250_handle_irq(port, iir);
+ ret = serial8250_handle_irq(port, iir);
+
+ if (pm_status > 0)
+ pm_runtime_put_autosuspend(port->dev);
+
+ return ret;
}
/*
@@ -2024,7 +2047,7 @@ static bool wait_for_lsr(struct uart_8250_port *up, int bits)
}
/* Wait for transmitter and holding register to empty with timeout */
-static void wait_for_xmitr(struct uart_8250_port *up, int bits)
+void serial8250_wait_for_xmitr(struct uart_8250_port *up, int bits)
{
unsigned int tmout;
bool tx_ready;
@@ -2052,6 +2075,7 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits)
}
}
}
+EXPORT_SYMBOL_NS_GPL(serial8250_wait_for_xmitr, "SERIAL_8250");
#ifdef CONFIG_CONSOLE_POLL
/*
@@ -2098,7 +2122,7 @@ static void serial8250_put_poll_char(struct uart_port *port,
ier = serial_port_in(port, UART_IER);
__serial8250_clear_IER(up);
- wait_for_xmitr(up, UART_LSR_BOTH_EMPTY);
+ serial8250_wait_for_xmitr(up, UART_LSR_BOTH_EMPTY);
/*
* Send the character out.
*/
@@ -2108,7 +2132,7 @@ static void serial8250_put_poll_char(struct uart_port *port,
* Finally, wait for transmitter to become empty
* and restore the IER
*/
- wait_for_xmitr(up, UART_LSR_BOTH_EMPTY);
+ serial8250_wait_for_xmitr(up, UART_LSR_BOTH_EMPTY);
serial_port_out(port, UART_IER, ier);
}
@@ -2223,7 +2247,7 @@ static void serial8250_THRE_test(struct uart_port *port)
* Synchronize UART_IER access against the console.
*/
scoped_guard(uart_port_lock_irqsave, port) {
- wait_for_xmitr(up, UART_LSR_THRE);
+ serial8250_wait_for_xmitr(up, UART_LSR_THRE);
serial_port_out_sync(port, UART_IER, UART_IER_THRI);
udelay(1); /* allow THRE to set */
iir_noint1 = serial_port_in(port, UART_IIR) & UART_IIR_NO_INT;
@@ -2428,8 +2452,8 @@ void serial8250_do_shutdown(struct uart_port *port)
synchronize_irq(port->irq);
- serial8250_release_dma(up);
- up->dma = NULL;
+ if (up->dma)
+ serial8250_release_dma(up);
scoped_guard(uart_port_lock_irqsave, port) {
if (port->flags & UPF_FOURPORT) {
@@ -3293,7 +3317,7 @@ static void serial8250_console_wait_putchar(struct uart_port *port, unsigned cha
{
struct uart_8250_port *up = up_to_u8250p(port);
- wait_for_xmitr(up, UART_LSR_THRE);
+ serial8250_wait_for_xmitr(up, UART_LSR_THRE);
serial8250_console_putchar(port, ch);
}
@@ -3507,7 +3531,7 @@ void serial8250_console_write(struct uart_8250_port *up,
* Finally, wait for transmitter to become empty
* and restore the IER
*/
- wait_for_xmitr(up, UART_LSR_BOTH_EMPTY);
+ serial8250_wait_for_xmitr(up, UART_LSR_BOTH_EMPTY);
if (em485) {
mdelay(port->rs485.delay_rts_after_send);
diff --git a/drivers/tty/serial/8250/8250_pxa.c b/drivers/tty/serial/8250/8250_pxa.c
index 6dd0190b4843..a56aa5fec563 100644
--- a/drivers/tty/serial/8250/8250_pxa.c
+++ b/drivers/tty/serial/8250/8250_pxa.c
@@ -11,6 +11,7 @@
*/
#include <linux/device.h>
+#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -26,7 +27,7 @@
#include "8250.h"
struct pxa8250_data {
- int line;
+ struct uart_8250_port *uport;
struct clk *clk;
};
@@ -34,7 +35,7 @@ static int __maybe_unused serial_pxa_suspend(struct device *dev)
{
struct pxa8250_data *data = dev_get_drvdata(dev);
- serial8250_suspend_port(data->line);
+ serial8250_suspend_port(data->uport);
return 0;
}
@@ -43,7 +44,7 @@ static int __maybe_unused serial_pxa_resume(struct device *dev)
{
struct pxa8250_data *data = dev_get_drvdata(dev);
- serial8250_resume_port(data->line);
+ serial8250_resume_port(data->uport);
return 0;
}
@@ -128,11 +129,11 @@ static int serial_pxa_probe(struct platform_device *pdev)
uart.tx_loadsz = 32;
uart.dl_write = serial_pxa_dl_write;
- ret = serial8250_register_8250_port(&uart);
- if (ret < 0)
+ data->uport = serial8250_register_8250_port(&uart);
+ if (IS_ERR(data->uport)) {
+ ret = PTR_ERR(data->uport);
goto err_clk;
-
- data->line = ret;
+ }
platform_set_drvdata(pdev, data);
@@ -147,7 +148,7 @@ static void serial_pxa_remove(struct platform_device *pdev)
{
struct pxa8250_data *data = platform_get_drvdata(pdev);
- serial8250_unregister_port(data->line);
+ serial8250_unregister_port(data->uport);
clk_unprepare(data->clk);
}
diff --git a/drivers/tty/serial/8250/8250_tegra.c b/drivers/tty/serial/8250/8250_tegra.c
index 2f3b0075763f..2f6b822f79a8 100644
--- a/drivers/tty/serial/8250/8250_tegra.c
+++ b/drivers/tty/serial/8250/8250_tegra.c
@@ -9,6 +9,7 @@
#include <linux/clk.h>
#include <linux/console.h>
#include <linux/delay.h>
+#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -20,7 +21,7 @@
struct tegra_uart {
struct clk *clk;
struct reset_control *rst;
- int line;
+ struct uart_8250_port *uport;
};
static void tegra_uart_handle_break(struct uart_port *p)
@@ -103,12 +104,13 @@ static int tegra_uart_probe(struct platform_device *pdev)
if (ret)
goto err_clkdisable;
- ret = serial8250_register_8250_port(&port8250);
- if (ret < 0)
+ uart->uport = serial8250_register_8250_port(&port8250);
+ if (IS_ERR(uart->uport)) {
+ ret = PTR_ERR(uart->uport);
goto err_ctrl_assert;
+ }
platform_set_drvdata(pdev, uart);
- uart->line = ret;
return 0;
@@ -124,7 +126,7 @@ static void tegra_uart_remove(struct platform_device *pdev)
{
struct tegra_uart *uart = platform_get_drvdata(pdev);
- serial8250_unregister_port(uart->line);
+ serial8250_unregister_port(uart->uport);
reset_control_assert(uart->rst);
clk_disable_unprepare(uart->clk);
}
@@ -133,10 +135,10 @@ static void tegra_uart_remove(struct platform_device *pdev)
static int tegra_uart_suspend(struct device *dev)
{
struct tegra_uart *uart = dev_get_drvdata(dev);
- struct uart_8250_port *port8250 = serial8250_get_port(uart->line);
+ struct uart_8250_port *port8250 = uart->uport;
struct uart_port *port = &port8250->port;
- serial8250_suspend_port(uart->line);
+ serial8250_suspend_port(port8250);
if (!uart_console(port) || console_suspend_enabled)
clk_disable_unprepare(uart->clk);
@@ -147,13 +149,13 @@ static int tegra_uart_suspend(struct device *dev)
static int tegra_uart_resume(struct device *dev)
{
struct tegra_uart *uart = dev_get_drvdata(dev);
- struct uart_8250_port *port8250 = serial8250_get_port(uart->line);
+ struct uart_8250_port *port8250 = uart->uport;
struct uart_port *port = &port8250->port;
if (!uart_console(port) || console_suspend_enabled)
clk_prepare_enable(uart->clk);
- serial8250_resume_port(uart->line);
+ serial8250_resume_port(port8250);
return 0;
}
diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c
index e3db60bf50c9..a8ee45a0d41e 100644
--- a/drivers/tty/serial/8250/8250_uniphier.c
+++ b/drivers/tty/serial/8250/8250_uniphier.c
@@ -5,6 +5,7 @@
#include <linux/clk.h>
#include <linux/console.h>
+#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -31,7 +32,7 @@
#define UNIPHIER_UART_DLR (9 << (UNIPHIER_UART_REGSHIFT))
struct uniphier8250_priv {
- int line;
+ struct uart_8250_port *uport;
struct clk *clk;
spinlock_t atomic_write_lock;
};
@@ -165,10 +166,8 @@ static int uniphier_uart_probe(struct platform_device *pdev)
int ret;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!regs) {
- dev_err(dev, "failed to get memory resource\n");
- return -EINVAL;
- }
+ if (!regs)
+ return dev_err_probe(dev, -EINVAL, "failed to get memory resource\n");
membase = devm_ioremap(dev, regs->start, resource_size(regs));
if (!membase)
@@ -180,15 +179,10 @@ static int uniphier_uart_probe(struct platform_device *pdev)
memset(&up, 0, sizeof(up));
- priv->clk = devm_clk_get(dev, NULL);
- if (IS_ERR(priv->clk)) {
- dev_err(dev, "failed to get clock\n");
- return PTR_ERR(priv->clk);
- }
-
- ret = clk_prepare_enable(priv->clk);
- if (ret)
- return ret;
+ priv->clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(priv->clk))
+ return dev_err_probe(dev, PTR_ERR(priv->clk),
+ "failed to get and enable clock\n");
up.port.uartclk = clk_get_rate(priv->clk);
@@ -219,13 +213,9 @@ static int uniphier_uart_probe(struct platform_device *pdev)
up.dl_read = uniphier_serial_dl_read;
up.dl_write = uniphier_serial_dl_write;
- ret = serial8250_register_8250_port(&up);
- if (ret < 0) {
- dev_err(dev, "failed to register 8250 port\n");
- clk_disable_unprepare(priv->clk);
- return ret;
- }
- priv->line = ret;
+ priv->uport = serial8250_register_8250_port(&up);
+ if (IS_ERR(priv->uport))
+ return dev_err_probe(dev, PTR_ERR(priv->uport), "failed to register 8250 port\n");
platform_set_drvdata(pdev, priv);
@@ -236,16 +226,15 @@ static void uniphier_uart_remove(struct platform_device *pdev)
{
struct uniphier8250_priv *priv = platform_get_drvdata(pdev);
- serial8250_unregister_port(priv->line);
- clk_disable_unprepare(priv->clk);
+ serial8250_unregister_port(priv->uport);
}
static int __maybe_unused uniphier_uart_suspend(struct device *dev)
{
struct uniphier8250_priv *priv = dev_get_drvdata(dev);
- struct uart_8250_port *up = serial8250_get_port(priv->line);
+ struct uart_8250_port *up = priv->uport;
- serial8250_suspend_port(priv->line);
+ serial8250_suspend_port(up);
if (!uart_console(&up->port) || console_suspend_enabled)
clk_disable_unprepare(priv->clk);
@@ -256,7 +245,7 @@ static int __maybe_unused uniphier_uart_suspend(struct device *dev)
static int __maybe_unused uniphier_uart_resume(struct device *dev)
{
struct uniphier8250_priv *priv = dev_get_drvdata(dev);
- struct uart_8250_port *up = serial8250_get_port(priv->line);
+ struct uart_8250_port *up = priv->uport;
int ret;
if (!uart_console(&up->port) || console_suspend_enabled) {
@@ -265,7 +254,7 @@ static int __maybe_unused uniphier_uart_resume(struct device *dev)
return ret;
}
- serial8250_resume_port(priv->line);
+ serial8250_resume_port(up);
return 0;
}
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index fa6f33303cb0..82e761b8298a 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -304,8 +304,8 @@ config SERIAL_8250_EXAR_ST16C554
will be called 8250_exar_st16c554.
config SERIAL_8250_HUB6
- tristate "Support Hub6 cards"
- depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
+ bool "Support Hub6 cards"
+ depends on SERIAL_8250_MANY_PORTS && ISA
help
Say Y here if you have a HUB6 serial board.
@@ -347,6 +347,17 @@ config SERIAL_8250_ACORN
system, say Y to this option. The driver can handle 1, 2, or 3 port
cards. If unsure, say N.
+config SERIAL_8250_AIROHA
+ tristate "Airoha UART support"
+ depends on ARCH_AIROHA || COMPILE_TEST
+ depends on SERIAL_8250
+ help
+ Selecting this option enables an Airoha SoC specific baud rate
+ calculation routine on an otherwise 16550 compatible UART hardware.
+
+ If you have an Airoha based board and want to use the serial port,
+ say Y to this option. If unsure, say N.
+
config SERIAL_8250_BCM2835AUX
tristate "BCM2835 auxiliar mini UART support"
depends on ARCH_BCM2835 || COMPILE_TEST
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index 46adadcfe072..5ff2ba414e13 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_SERIAL_8250) += 8250.o
8250-y := 8250_core.o
8250-y += 8250_platform.o
8250-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
+8250-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
obj-$(CONFIG_SERIAL_8250) += 8250_base.o
8250_base-y := 8250_port.o
@@ -20,6 +21,7 @@ obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o
obj-$(CONFIG_SERIAL_8250_ACCENT) += 8250_accent.o
obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o
+obj-$(CONFIG_SERIAL_8250_AIROHA) += 8250_airoha.o
obj-$(CONFIG_SERIAL_8250_ASPEED_VUART) += 8250_aspeed_vuart.o
obj-$(CONFIG_SERIAL_8250_BCM2835AUX) += 8250_bcm2835aux.o
obj-$(CONFIG_SERIAL_8250_BCM7271) += 8250_bcm7271.o
@@ -35,7 +37,6 @@ obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o
obj-$(CONFIG_SERIAL_8250_FOURPORT) += 8250_fourport.o
obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o
obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o
-obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
obj-$(CONFIG_SERIAL_8250_INGENIC) += 8250_ingenic.o
obj-$(CONFIG_SERIAL_8250_IOC3) += 8250_ioc3.o
obj-$(CONFIG_SERIAL_8250_KEBA) += 8250_keba.o
diff --git a/drivers/tty/serial/8250/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c
index 80483fc7388d..5dcd1544e478 100644
--- a/drivers/tty/serial/8250/serial_cs.c
+++ b/drivers/tty/serial/8250/serial_cs.c
@@ -34,6 +34,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
+#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
@@ -86,7 +87,7 @@ struct serial_info {
int manfid;
int prodid;
int c950ctrl;
- int line[4];
+ struct uart_8250_port *uport[4];
const struct serial_quirk *quirk;
};
@@ -266,7 +267,7 @@ static void serial_remove(struct pcmcia_device *link)
* Recheck to see if the device is still configured.
*/
for (i = 0; i < info->ndev; i++)
- serial8250_unregister_port(info->line[i]);
+ serial8250_unregister_port(info->uport[i]);
if (!info->slave)
pcmcia_disable_device(link);
@@ -278,7 +279,7 @@ static int serial_suspend(struct pcmcia_device *link)
int i;
for (i = 0; i < info->ndev; i++)
- serial8250_suspend_port(info->line[i]);
+ serial8250_suspend_port(info->uport[i]);
return 0;
}
@@ -289,7 +290,7 @@ static int serial_resume(struct pcmcia_device *link)
int i;
for (i = 0; i < info->ndev; i++)
- serial8250_resume_port(info->line[i]);
+ serial8250_resume_port(info->uport[i]);
if (info->quirk && info->quirk->wakeup)
info->quirk->wakeup(link);
@@ -347,7 +348,6 @@ static int setup_serial(struct pcmcia_device *handle, struct serial_info *info,
unsigned int iobase, int irq)
{
struct uart_8250_port uart;
- int line;
memset(&uart, 0, sizeof(uart));
uart.port.iobase = iobase;
@@ -361,14 +361,13 @@ static int setup_serial(struct pcmcia_device *handle, struct serial_info *info,
if (info->quirk && info->quirk->setup)
info->quirk->setup(handle, &uart);
- line = serial8250_register_8250_port(&uart);
- if (line < 0) {
+ info->uport[info->ndev] = serial8250_register_8250_port(&uart);
+ if (IS_ERR(info->uport[info->ndev])) {
pr_err("serial_cs: serial8250_register_8250_port() at 0x%04lx, irq %d failed\n",
(unsigned long)iobase, irq);
return -EINVAL;
}
- info->line[info->ndev] = line;
info->ndev++;
return 0;
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index cf7dba473b20..3864cef711a6 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -904,6 +904,7 @@ config SERIAL_JSM
config SERIAL_MSM
tristate "MSM on-chip serial port support"
depends on ARCH_QCOM || COMPILE_TEST
+ select PM_OPP
select SERIAL_CORE
config SERIAL_MSM_CONSOLE
@@ -1386,6 +1387,16 @@ config SERIAL_MEN_Z135
This driver can also be build as a module. If so, the module will be called
men_z135_uart.ko
+config SDIO_UART
+ tristate "SDIO UART/GPS class support"
+ depends on TTY && MMC
+ help
+ SDIO function driver for SDIO cards that implements the UART
+ class, as well as the GPS class which appears like a UART.
+
+ This driver can also be built as a module. If so, the module will
+ be called sdio_uart.
+
config SERIAL_SPRD
tristate "Support for Spreadtrum serial"
select SERIAL_CORE
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index bba7b21a4a1d..d63b126f40ca 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -77,6 +77,7 @@ obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o
obj-$(CONFIG_SERIAL_SC16IS7XX) += sc16is7xx.o
obj-$(CONFIG_SERIAL_SC16IS7XX_SPI) += sc16is7xx_spi.o
obj-$(CONFIG_SERIAL_SC16IS7XX_I2C) += sc16is7xx_i2c.o
+obj-$(CONFIG_SDIO_UART) += sdio_uart.o
obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
obj-$(CONFIG_SERIAL_SIFIVE) += sifive.o
obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index e67f2ac454b6..e6f652905ca6 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -327,6 +327,7 @@ struct uart_amba_port {
char type[12];
ktime_t rs485_tx_drain_interval; /* nano */
enum pl011_rs485_tx_state rs485_tx_state;
+ bool rs485_break;
struct hrtimer trigger_start_tx;
struct hrtimer trigger_stop_tx;
bool console_line_ended;
@@ -435,8 +436,8 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap)
static int pl011_dmabuf_init(struct dma_chan *chan, struct pl011_dmabuf *db,
enum dma_data_direction dir)
{
- db->buf = dma_alloc_coherent(chan->device->dev, PL011_DMA_BUFFER_SIZE,
- &db->dma, GFP_KERNEL);
+ db->buf = dma_alloc_coherent(dmaengine_get_dma_device(chan),
+ PL011_DMA_BUFFER_SIZE, &db->dma, GFP_KERNEL);
if (!db->buf)
return -ENOMEM;
db->len = PL011_DMA_BUFFER_SIZE;
@@ -448,7 +449,7 @@ static void pl011_dmabuf_free(struct dma_chan *chan, struct pl011_dmabuf *db,
enum dma_data_direction dir)
{
if (db->buf) {
- dma_free_coherent(chan->device->dev,
+ dma_free_coherent(dmaengine_get_dma_device(chan),
PL011_DMA_BUFFER_SIZE, db->buf, db->dma);
}
}
@@ -609,7 +610,7 @@ static void pl011_dma_tx_callback(void *data)
uart_port_lock_irqsave(&uap->port, &flags);
if (uap->dmatx.queued)
- dma_unmap_single(dmatx->chan->device->dev, dmatx->dma,
+ dma_unmap_single(dmaengine_get_dma_device(dmatx->chan), dmatx->dma,
dmatx->len, DMA_TO_DEVICE);
dmacr = uap->dmacr;
@@ -721,7 +722,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap)
dmaengine_submit(desc);
/* Fire the DMA transaction */
- dma_dev->device_issue_pending(chan);
+ dma_async_issue_pending(chan);
uap->dmacr |= UART011_TXDMAE;
pl011_write(uap->dmacr, uap, REG_DMACR);
@@ -867,7 +868,7 @@ __acquires(&uap->port.lock)
dmaengine_terminate_async(uap->dmatx.chan);
if (uap->dmatx.queued) {
- dma_unmap_single(uap->dmatx.chan->device->dev, uap->dmatx.dma,
+ dma_unmap_single(dmaengine_get_dma_device(uap->dmatx.chan), uap->dmatx.dma,
uap->dmatx.len, DMA_TO_DEVICE);
uap->dmatx.queued = false;
uap->dmacr &= ~UART011_TXDMAE;
@@ -1011,8 +1012,7 @@ static void pl011_dma_rx_irq(struct uart_amba_port *uap)
*/
if (dmaengine_pause(rxchan))
dev_err(uap->port.dev, "unable to pause DMA transfer\n");
- dmastat = rxchan->device->device_tx_status(rxchan,
- dmarx->cookie, &state);
+ dmastat = dmaengine_tx_status(rxchan, dmarx->cookie, &state);
if (dmastat != DMA_PAUSED)
dev_err(uap->port.dev, "unable to pause DMA transfer\n");
@@ -1066,7 +1066,7 @@ static void pl011_dma_rx_callback(void *data)
* Rx data can be taken by the UART interrupts during
* the DMA irq handler. So we check the residue here.
*/
- rxchan->device->device_tx_status(rxchan, dmarx->cookie, &state);
+ dmaengine_tx_status(rxchan, dmarx->cookie, &state);
pending = dbuf->len - state.residue;
BUG_ON(pending > PL011_DMA_BUFFER_SIZE);
/* Then we terminate the transfer - we now know our residue */
@@ -1124,7 +1124,7 @@ static void pl011_dma_rx_poll(struct timer_list *t)
struct dma_tx_state state;
dbuf = dmarx->use_buf_b ? &uap->dmarx.dbuf_b : &uap->dmarx.dbuf_a;
- rxchan->device->device_tx_status(rxchan, dmarx->cookie, &state);
+ dmaengine_tx_status(rxchan, dmarx->cookie, &state);
if (likely(state.residue < dmarx->last_residue)) {
dmataken = dbuf->len - dmarx->last_residue;
size = dmarx->last_residue - state.residue;
@@ -1249,7 +1249,7 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap)
/* In theory, this should already be done by pl011_dma_flush_buffer */
dmaengine_terminate_sync(uap->dmatx.chan);
if (uap->dmatx.queued) {
- dma_unmap_single(uap->dmatx.chan->device->dev,
+ dma_unmap_single(dmaengine_get_dma_device(uap->dmatx.chan),
uap->dmatx.dma, uap->dmatx.len,
DMA_TO_DEVICE);
uap->dmatx.queued = false;
@@ -1280,6 +1280,11 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
return uap->using_rx_dma && uap->dmarx.running;
}
+static inline bool pl011_dma_tx_queued(struct uart_amba_port *uap)
+{
+ return uap->dmatx.queued;
+}
+
#else
/* Blank functions if the DMA engine is not available */
static inline void pl011_dma_remove(struct uart_amba_port *uap)
@@ -1331,6 +1336,11 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
return false;
}
+static inline bool pl011_dma_tx_queued(struct uart_amba_port *uap)
+{
+ return false;
+}
+
#define pl011_dma_flush_buffer NULL
#endif
@@ -1358,6 +1368,10 @@ static void pl011_rs485_tx_stop(struct uart_amba_port *uap)
{
struct uart_port *port = &uap->port;
+ /* pl011_break_ctl() stops the transmission when the break ends */
+ if (uap->rs485_break)
+ return;
+
if (uap->rs485_tx_state == SEND)
uap->rs485_tx_state = WAIT_AFTER_SEND;
@@ -1420,10 +1434,6 @@ static void pl011_rs485_tx_start(struct uart_amba_port *uap)
struct uart_port *port = &uap->port;
u32 cr;
- if (uap->rs485_tx_state == WAIT_AFTER_RTS) {
- uap->rs485_tx_state = SEND;
- return;
- }
if (uap->rs485_tx_state == WAIT_AFTER_SEND ||
uap->rs485_tx_state == WAIT_AFTER_SEND_DELAY) {
hrtimer_try_to_cancel(&uap->trigger_stop_tx);
@@ -1462,6 +1472,10 @@ static void pl011_start_tx(struct uart_port *port)
if ((uap->port.rs485.flags & SER_RS485_ENABLED) &&
uap->rs485_tx_state != SEND) {
+ /* trigger_start_tx starts TX once delay_rts_before_send passed */
+ if (uap->rs485_tx_state == WAIT_AFTER_RTS)
+ return;
+
pl011_rs485_tx_start(uap);
if (uap->rs485_tx_state == WAIT_AFTER_RTS)
return;
@@ -1478,8 +1492,12 @@ static enum hrtimer_restart pl011_trigger_start_tx(struct hrtimer *t)
unsigned long flags;
uart_port_lock_irqsave(&uap->port, &flags);
- if (uap->rs485_tx_state == WAIT_AFTER_RTS)
- pl011_start_tx(&uap->port);
+ if (uap->rs485_tx_state == WAIT_AFTER_RTS) {
+ uap->rs485_tx_state = SEND;
+ /* A break can arm the timer while TX is stopped */
+ if (!uart_tx_stopped(&uap->port))
+ pl011_start_tx(&uap->port);
+ }
uart_port_unlock_irqrestore(&uap->port, flags);
return HRTIMER_NORESTART;
@@ -1771,16 +1789,60 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
{
struct uart_amba_port *uap =
container_of(port, struct uart_amba_port, port);
+ struct tty_port *tport = &port->state->port;
+ bool rs485 = port->rs485.flags & SER_RS485_ENABLED;
unsigned long flags;
unsigned int lcr_h;
uart_port_lock_irqsave(&uap->port, &flags);
+
+ /*
+ * In RS485 mode the transceiver only drives the bus while
+ * transmitting. Treat a break as a transmission.
+ */
+ if (rs485 && break_state == -1 && !uap->rs485_break) {
+ uap->rs485_break = true;
+
+ /* Pending data already enabled the transceiver */
+ if (uap->rs485_tx_state != SEND &&
+ uap->rs485_tx_state != WAIT_AFTER_RTS)
+ pl011_rs485_tx_start(uap);
+
+ /*
+ * Wait out delay_rts_before_send before starting the break.
+ * The state stays WAIT_AFTER_RTS, so the TX path behaves as
+ * without a break. Start it here if trigger_start_tx is late.
+ */
+ if (uap->rs485_tx_state == WAIT_AFTER_RTS) {
+ uart_port_unlock_irqrestore(&uap->port, flags);
+ msleep(port->rs485.delay_rts_before_send);
+ uart_port_lock_irqsave(&uap->port, &flags);
+
+ if (uap->rs485_tx_state == WAIT_AFTER_RTS) {
+ hrtimer_try_to_cancel(&uap->trigger_start_tx);
+ uap->rs485_tx_state = SEND;
+ if (!uart_tx_stopped(port))
+ pl011_start_tx(port);
+ }
+ }
+ }
+
lcr_h = pl011_read(uap, REG_LCRH_TX);
if (break_state == -1)
lcr_h |= UART01x_LCRH_BRK;
else
lcr_h &= ~UART01x_LCRH_BRK;
pl011_write(lcr_h, uap, REG_LCRH_TX);
+
+ if (break_state == 0 && uap->rs485_break) {
+ uap->rs485_break = false;
+ /* An active TX path stops the transmission when it is done */
+ if (rs485 && (uart_tx_stopped(port) ||
+ (!pl011_dma_tx_queued(uap) &&
+ kfifo_is_empty(&tport->xmit_fifo))))
+ pl011_rs485_tx_stop(uap);
+ }
+
uart_port_unlock_irqrestore(&uap->port, flags);
}
@@ -2101,6 +2163,7 @@ static void pl011_shutdown(struct uart_port *port)
hrtimer_cancel(&uap->trigger_stop_tx);
uart_port_lock_irq(port);
+ uap->rs485_break = false;
if (uap->rs485_tx_state != OFF)
pl011_rs485_tx_stop_now(uap);
uart_port_unlock_irq(port);
@@ -2397,8 +2460,32 @@ static int pl011_rs485_config(struct uart_port *port, struct ktermios *termios,
struct uart_amba_port *uap =
container_of(port, struct uart_amba_port, port);
- if (port->rs485.flags & SER_RS485_ENABLED)
+ uap->rs485_break = false;
+ if ((port->rs485.flags & SER_RS485_ENABLED) &&
+ !(rs485->flags & SER_RS485_ENABLED)) {
+ bool tx_pending = uap->rs485_tx_state == WAIT_AFTER_RTS;
+ u32 cr = pl011_read(uap, REG_CR);
+
+ /*
+ * Leaving RS485 mode, which only enables the transmitter while
+ * sending. Don't stop it, as that stalls a DMA transfer still
+ * in flight. Drop pending deferred starts and stops and keep
+ * it enabled.
+ */
+ hrtimer_try_to_cancel(&uap->trigger_start_tx);
+ hrtimer_try_to_cancel(&uap->trigger_stop_tx);
+ uap->rs485_tx_state = OFF;
+
+ cr |= UART011_CR_TXE | UART011_CR_RXE;
+ pl011_write(cr, uap, REG_CR);
+
+ /* Start TX that was still waiting for delay_rts_before_send */
+ if (tx_pending && !uart_tx_stopped(port) &&
+ !pl011_dma_tx_start(uap))
+ pl011_start_tx_pio(uap);
+ } else if (port->rs485.flags & SER_RS485_ENABLED) {
pl011_rs485_tx_stop(uap);
+ }
/* Make sure auto RTS is disabled */
if (rs485->flags & SER_RS485_ENABLED) {
diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c
index 5c4895d154c0..3988e5958896 100644
--- a/drivers/tty/serial/arc_uart.c
+++ b/drivers/tty/serial/arc_uart.c
@@ -304,7 +304,7 @@ static unsigned int arc_serial_get_mctrl(struct uart_port *port)
{
/*
* Pretend we have a Modem status reg and following bits are
- * always set, to satify the serial core state machine
+ * always set, to satisfy the serial core state machine
* (DSR) Data Set Ready
* (CTS) Clear To Send
* (CAR) Carrier Detect
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 5d8c1cfc1c60..c3880259e3bc 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -2723,7 +2723,7 @@ static bool atmel_serial_clk_will_stop(void)
#endif
}
-static int __maybe_unused atmel_serial_suspend(struct device *dev)
+static int atmel_serial_suspend(struct device *dev)
{
struct uart_port *port = dev_get_drvdata(dev);
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
@@ -2765,7 +2765,7 @@ static int __maybe_unused atmel_serial_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused atmel_serial_resume(struct device *dev)
+static int atmel_serial_resume(struct device *dev)
{
struct uart_port *port = dev_get_drvdata(dev);
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
@@ -2996,7 +2996,7 @@ static void atmel_serial_remove(struct platform_device *pdev)
pdev->dev.of_node = NULL;
}
-static SIMPLE_DEV_PM_OPS(atmel_serial_pm_ops, atmel_serial_suspend,
+static DEFINE_SIMPLE_DEV_PM_OPS(atmel_serial_pm_ops, atmel_serial_suspend,
atmel_serial_resume);
static struct platform_driver atmel_serial_driver = {
@@ -3005,7 +3005,7 @@ static struct platform_driver atmel_serial_driver = {
.driver = {
.name = "atmel_usart_serial",
.of_match_table = of_match_ptr(atmel_serial_dt_ids),
- .pm = pm_ptr(&atmel_serial_pm_ops),
+ .pm = pm_sleep_ptr(&atmel_serial_pm_ops),
},
};
diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c
index ce740cdc7ceb..05d99ec6e709 100644
--- a/drivers/tty/serial/earlycon.c
+++ b/drivers/tty/serial/earlycon.c
@@ -11,6 +11,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/console.h>
+#include <linux/ctype.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
@@ -59,11 +60,10 @@ static void __init earlycon_init(struct earlycon_device *device,
const char *s;
size_t len;
- /* scan backwards from end of string for first non-numeral */
- for (s = name + strlen(name);
- s > name && s[-1] >= '0' && s[-1] <= '9';
- s--)
- ;
+ /* Scan backwards to split the trailing index from the console name. */
+ s = name + strlen(name);
+ while (s > name && isdigit(s[-1]))
+ s--;
if (*s)
earlycon->index = simple_strtoul(s, NULL, 10);
len = s - name;
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index b7919c05f0fb..c8575c965203 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -491,7 +491,7 @@ static void lpuart_dma_tx(struct lpuart_port *sport)
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,
+ ret = dma_map_sg(dmaengine_get_dma_device(chan), sgl, sport->dma_tx_nents,
DMA_TO_DEVICE);
if (!ret) {
dev_err(dev, "DMA mapping error for TX.\n");
@@ -502,7 +502,7 @@ static void lpuart_dma_tx(struct lpuart_port *sport)
ret, DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT);
if (!sport->dma_tx_desc) {
- dma_unmap_sg(chan->device->dev, sgl, sport->dma_tx_nents,
+ dma_unmap_sg(dmaengine_get_dma_device(chan), sgl, sport->dma_tx_nents,
DMA_TO_DEVICE);
dev_err(dev, "Cannot prepare TX slave DMA!\n");
return;
@@ -535,7 +535,7 @@ static void lpuart_dma_tx_complete(void *arg)
return;
}
- dma_unmap_sg(chan->device->dev, sgl, sport->dma_tx_nents,
+ dma_unmap_sg(dmaengine_get_dma_device(chan), sgl, sport->dma_tx_nents,
DMA_TO_DEVICE);
uart_xmit_advance(&sport->port, sport->dma_tx_bytes);
@@ -606,7 +606,7 @@ static void lpuart_flush_buffer(struct uart_port *port)
if (sport->lpuart_dma_tx_use) {
if (sport->dma_tx_in_progress) {
- dma_unmap_sg(chan->device->dev, &sport->tx_sgl[0],
+ dma_unmap_sg(dmaengine_get_dma_device(chan), &sport->tx_sgl[0],
sport->dma_tx_nents, DMA_TO_DEVICE);
sport->dma_tx_in_progress = false;
}
@@ -1176,7 +1176,7 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
}
/* CPU claims ownership of RX DMA buffer */
- dma_sync_sg_for_cpu(chan->device->dev, &sport->rx_sgl, 1,
+ dma_sync_sg_for_cpu(dmaengine_get_dma_device(chan), &sport->rx_sgl, 1,
DMA_FROM_DEVICE);
/*
@@ -1237,7 +1237,7 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
sport->last_residue = state.residue;
exit:
- dma_sync_sg_for_device(chan->device->dev, &sport->rx_sgl, 1,
+ dma_sync_sg_for_device(dmaengine_get_dma_device(chan), &sport->rx_sgl, 1,
DMA_FROM_DEVICE);
uart_port_unlock_irqrestore(&sport->port, flags);
@@ -1374,7 +1374,7 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport)
return -ENOMEM;
sg_init_one(&sport->rx_sgl, ring->buf, sport->rx_dma_rng_buf_len);
- nent = dma_map_sg(chan->device->dev, &sport->rx_sgl, 1,
+ nent = dma_map_sg(dmaengine_get_dma_device(chan), &sport->rx_sgl, 1,
DMA_FROM_DEVICE);
if (!nent) {
@@ -1430,7 +1430,7 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport)
return 0;
err_unmap_sg:
- dma_unmap_sg(chan->device->dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE);
+ dma_unmap_sg(dmaengine_get_dma_device(chan), &sport->rx_sgl, 1, DMA_FROM_DEVICE);
err_free_buf:
kfree(ring->buf);
ring->buf = NULL;
@@ -1447,7 +1447,7 @@ static void lpuart_dma_rx_free(struct uart_port *port)
if (!sport->dma_idle_int)
timer_delete_sync(&sport->lpuart_timer);
- dma_unmap_sg(chan->device->dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE);
+ dma_unmap_sg(dmaengine_get_dma_device(chan), &sport->rx_sgl, 1, DMA_FROM_DEVICE);
kfree(sport->rx_ring.buf);
sport->rx_ring.tail = 0;
sport->rx_ring.head = 0;
diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c
index 64e3f8cf2f55..f3fba4ec5a29 100644
--- a/drivers/tty/serial/kgdboc.c
+++ b/drivers/tty/serial/kgdboc.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Based on the same principle as kgdboe using the NETPOLL api, this
- * driver uses a console polling api to implement a gdb serial inteface
+ * driver uses a console polling api to implement a gdb serial interface
* which is multiplexed on a console port.
*
* Maintainer: Jason Wessel <jason.wessel@windriver.com>
diff --git a/drivers/tty/serial/ma35d1_serial.c b/drivers/tty/serial/ma35d1_serial.c
index 0809655f4395..3be30fb05513 100644
--- a/drivers/tty/serial/ma35d1_serial.c
+++ b/drivers/tty/serial/ma35d1_serial.c
@@ -639,7 +639,7 @@ static struct console ma35d1serial_console = {
.write = ma35d1serial_console_write,
.device = uart_console_device,
.setup = ma35d1serial_console_setup,
- .flags = CON_PRINTBUFFER | CON_ENABLED,
+ .flags = CON_PRINTBUFFER,
.index = -1,
.data = &ma35d1serial_reg,
};
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index 9e62778e4191..a0ed70185555 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -15,6 +15,7 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/gpio/driver.h>
+#include <linux/hrtimer.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/property.h>
@@ -156,10 +157,17 @@
#define MAX310X_LCR_FORCEPARITY_BIT (1 << 5) /* 9-bit multidrop parity */
#define MAX310X_LCR_TXBREAK_BIT (1 << 6) /* TX break enable */
#define MAX310X_LCR_RTS_BIT (1 << 7) /* RTS pin control */
+/* LCR bits owned by termios; TX break and RTS are driven elsewhere */
+#define MAX310X_LCR_TERMIOS_MASK GENMASK(5, 0)
/* IRDA register bits */
#define MAX310X_IRDA_IRDAEN_BIT (1 << 0) /* IRDA mode enable */
#define MAX310X_IRDA_SIR_BIT (1 << 1) /* SIR mode enable */
+#define MAX310X_IRDA_RTSINVERT_BIT (1 << 2) /* Invert RTS output */
+
+/* HDPIXDELAY accessor macros */
+#define MAX310X_HDPIXDELAY_SETUP(val) (((val) & 0x0f) << 4)
+#define MAX310X_HDPIXDELAY_HOLD(val) ((val) & 0x0f)
/* Flow control trigger level register masks */
#define MAX310X_FLOWLVL_HALT_MASK GENMASK(3, 0) /* Flow control halt level */
@@ -288,12 +296,30 @@ struct max310x_devtype {
u8 power_bit; /* Bit for sleep or power-off mode (active high). */
};
+/* Software-timed RS485 RTS envelope phase */
+enum max310x_tx_state {
+ MAX310X_TX_OFF, /* idle, RTS released */
+ MAX310X_TX_WAIT_BEFORE_SEND, /* RTS asserted, before-send delay */
+ MAX310X_TX_SEND, /* data in flight, awaiting TX-empty */
+ MAX310X_TX_WAIT_AFTER_SEND, /* data drained, after-send hold */
+};
+
struct max310x_one {
struct uart_port port;
struct work_struct tx_work;
struct work_struct md_work;
struct work_struct rs_work;
+ struct work_struct rts_work;
+ struct hrtimer tx_delay_tmr;
struct regmap *regmap;
+ unsigned int char_time_us;
+ unsigned int baud;
+ bool sw_rts_during_tx;
+ bool cancel_tx_delay_tmr;
+ bool tx_teardown; /* envelope being torn down */
+ bool rs485_pending; /* rs_work not yet applied */
+ bool tx_break; /* break_ctl() owns the transceiver */
+ enum max310x_tx_state tx_state;
u8 rx_buf[MAX310X_FIFO_SIZE];
};
@@ -678,6 +704,44 @@ static void max310x_batch_read(struct uart_port *port, u8 *rxbuf, unsigned int l
regmap_noinc_read(one->regmap, MAX310X_RHR_REG, rxbuf, len);
}
+static void max310x_rts_ctl(struct uart_port *port, bool rts_state)
+{
+ max310x_port_update(port, MAX310X_LCR_REG, MAX310X_LCR_RTS_BIT,
+ rts_state ? MAX310X_LCR_RTS_BIT : 0);
+}
+
+/* RTS level for the transmitting or the idle phase of an RS485 envelope */
+static bool max310x_rts_level(struct uart_port *port, bool active)
+{
+ return active ? (port->rs485.flags & SER_RS485_RTS_ON_SEND) :
+ (port->rs485.flags & SER_RS485_RTS_AFTER_SEND);
+}
+
+/*
+ * Drive the RS485 RTS line to match the current tx_state and break
+ * ownership. This is the only place that touches RTS, and it reads the
+ * state rather than a fixed assert/deassert intent, so a newer assert is
+ * never clobbered by a stale release and an expiring after-send hold never
+ * releases a break in progress. It also arms the before-send timer once the
+ * RTS edge is on the wire, so data is never shifted before RTS is asserted.
+ */
+static void max310x_rts_work_proc(struct work_struct *ws)
+{
+ struct max310x_one *one = container_of(ws, struct max310x_one, rts_work);
+ struct uart_port *port = &one->port;
+ bool rts_on = READ_ONCE(one->tx_state) != MAX310X_TX_OFF ||
+ READ_ONCE(one->tx_break);
+
+ max310x_rts_ctl(port, max310x_rts_level(port, rts_on));
+
+ guard(spinlock_irqsave)(&port->lock);
+ if (READ_ONCE(one->tx_state) == MAX310X_TX_WAIT_BEFORE_SEND &&
+ !one->cancel_tx_delay_tmr && !hrtimer_active(&one->tx_delay_tmr))
+ hrtimer_start(&one->tx_delay_tmr,
+ ms_to_ktime(port->rs485.delay_rts_before_send),
+ HRTIMER_MODE_REL);
+}
+
static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen)
{
struct max310x_one *one = to_max310x_port(port);
@@ -774,6 +838,77 @@ static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen)
tty_flip_buffer_push(&port->state->port);
}
+static enum hrtimer_restart max310x_tmr_tx(struct hrtimer *timer)
+{
+ struct max310x_one *one = container_of(timer, struct max310x_one,
+ tx_delay_tmr);
+
+ guard(spinlock_irqsave)(&one->port.lock);
+ if (!one->cancel_tx_delay_tmr) {
+ if (READ_ONCE(one->tx_state) == MAX310X_TX_WAIT_AFTER_SEND) {
+ /* After-send hold elapsed: drop RTS via the rts worker. */
+ WRITE_ONCE(one->tx_state, MAX310X_TX_OFF);
+ schedule_work(&one->rts_work);
+ } else {
+ WRITE_ONCE(one->tx_state, MAX310X_TX_SEND);
+ schedule_work(&one->tx_work);
+ }
+ }
+
+ return HRTIMER_NORESTART;
+}
+
+static void max310x_delayed_stop_tx(struct uart_port *port)
+{
+ struct max310x_one *one = to_max310x_port(port);
+ unsigned int txlvl;
+
+ if (READ_ONCE(one->tx_state) == MAX310X_TX_OFF)
+ return;
+
+ /*
+ * Data still queued for transmission defers the hold: a refill is
+ * coming and the envelope is not over. Stopped output does not
+ * count - it drains nowhere, and the envelope must end.
+ */
+ if (!kfifo_is_empty(&port->state->port.xmit_fifo) &&
+ !uart_tx_stopped(port))
+ return;
+
+ /*
+ * The kfifo can be empty while the chip TX FIFO is still draining, so arm
+ * the after-send hold only once the chip FIFO is empty too - the TX-empty
+ * interrupt re-invokes us then. Otherwise the hold starts early and RTS
+ * drops mid-character, clipping the last byte(s).
+ */
+ txlvl = max310x_port_read(port, MAX310X_TXFIFOLVL_REG);
+ if (txlvl)
+ return;
+
+ /*
+ * Runs from tx_work without port->lock, so re-check the state under it:
+ * shutdown() may have cancelled the envelope meanwhile. Only
+ * MAX310X_TX_SEND may arm the hold.
+ */
+ guard(spinlock_irqsave)(&one->port.lock);
+ if (one->cancel_tx_delay_tmr ||
+ READ_ONCE(one->tx_state) != MAX310X_TX_SEND)
+ return;
+
+ if (!hrtimer_active(&one->tx_delay_tmr)) {
+ /*
+ * Add one character for the byte still in the shift register -
+ * TX-empty fires as it enters, not as it leaves.
+ */
+ ktime_t delay = us_to_ktime(one->char_time_us +
+ port->rs485.delay_rts_after_send *
+ USEC_PER_MSEC);
+
+ WRITE_ONCE(one->tx_state, MAX310X_TX_WAIT_AFTER_SEND);
+ hrtimer_start(&one->tx_delay_tmr, delay, HRTIMER_MODE_REL);
+ }
+}
+
static void max310x_handle_tx(struct uart_port *port)
{
struct tty_port *tport = &port->state->port;
@@ -785,8 +920,16 @@ static void max310x_handle_tx(struct uart_port *port)
return;
}
- if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port))
+ if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
+ /*
+ * Unwind the envelope even if a reconfigure has moved the
+ * port to the hardware path mid-envelope: a stranded
+ * tx_state would make a later reconfigure believe a
+ * software envelope still owns RTS.
+ */
+ max310x_delayed_stop_tx(port);
return;
+ }
/*
* It's a circ buffer -- wrap around.
@@ -811,11 +954,75 @@ static void max310x_handle_tx(struct uart_port *port)
uart_write_wakeup(port);
}
+/*
+ * Begin a software-timed RTS envelope: set the before-send phase and queue the
+ * rts worker to assert RTS. tx_state is set synchronously here (start_tx() holds
+ * port.lock) so close()/shutdown can see an envelope is in flight; rts_work then
+ * asserts RTS and arms the before-send timer (see there).
+ */
+static void max310x_delayed_start_tx(struct uart_port *port)
+{
+ struct max310x_one *one = to_max310x_port(port);
+
+ WRITE_ONCE(one->tx_state, MAX310X_TX_WAIT_BEFORE_SEND);
+ one->cancel_tx_delay_tmr = false;
+ schedule_work(&one->rts_work);
+}
+
+/* called with port.lock taken and irqs off */
static void max310x_start_tx(struct uart_port *port)
{
struct max310x_one *one = to_max310x_port(port);
- schedule_work(&one->tx_work);
+ /* A teardown is in progress; nothing may start an envelope or TX. */
+ if (one->tx_teardown)
+ return;
+
+ /*
+ * An RS485 reconfigure is scheduled but not applied yet: transmitting
+ * now would use the old path against half-programmed registers - a
+ * TIOCSRS485 switching paths followed immediately by a write puts the
+ * data on the wire with the transceiver released. Leave the data in
+ * the kfifo; rs_work restarts TX once the configuration is applied.
+ */
+ if (one->rs485_pending)
+ return;
+
+ if (READ_ONCE(one->sw_rts_during_tx)) {
+ /*
+ * The before- and after-send phases share one delay timer. If an
+ * after-send release is pending, cancel it before starting a new
+ * TX so the just-asserted RTS is not yanked; re-arming the timer
+ * for the before-send phase then supersedes the release.
+ */
+ int res = 0;
+
+ if (READ_ONCE(one->tx_state) == MAX310X_TX_WAIT_AFTER_SEND)
+ res = hrtimer_try_to_cancel(&one->tx_delay_tmr);
+ if (unlikely(res == -1)) {
+ one->cancel_tx_delay_tmr = true;
+ uart_port_unlock(port);
+ hrtimer_cancel(&one->tx_delay_tmr);
+ uart_port_lock(port);
+ /*
+ * The lock was dropped: a teardown may have run to
+ * completion or a reconfigure may have been posted
+ * meanwhile. Re-check before starting.
+ */
+ if (one->tx_teardown || one->rs485_pending)
+ return;
+ }
+
+ /* Already sending: pump the new data, don't rewind. */
+ if (READ_ONCE(one->tx_state) == MAX310X_TX_SEND) {
+ schedule_work(&one->tx_work);
+ return;
+ }
+
+ max310x_delayed_start_tx(port);
+ } else {
+ schedule_work(&one->tx_work);
+ }
}
static irqreturn_t max310x_port_irq(struct max310x_port *s, int portno)
@@ -840,8 +1047,12 @@ static irqreturn_t max310x_port_irq(struct max310x_port *s, int portno)
}
if (rxlen)
max310x_handle_rx(port, rxlen);
+ /*
+ * TXEMPTY latches on the FIFO becoming empty, so a stale
+ * interrupt cannot pump data during an RTS setup delay.
+ */
if (ists & MAX310X_IRQ_TXEMPTY_BIT)
- max310x_start_tx(port);
+ schedule_work(&s->p[portno].tx_work);
} while (1);
return res;
@@ -923,17 +1134,198 @@ static void max310x_set_mctrl(struct uart_port *port, unsigned int mctrl)
schedule_work(&one->md_work);
}
+/*
+ * A reconfigure can move the port off the hardware RTS path while the chip's
+ * auto-RTS still owns a transmission in flight; tx_state does not track
+ * those. Take such a transfer over before auto-RTS is disabled: enter
+ * MAX310X_TX_SEND, so the caller keeps RTS driven across the handover and
+ * the normal drain path arms the after-send hold. Returns true when a
+ * transmission owns RTS - adopted here or started concurrently - and false
+ * when the line is really idle.
+ */
+static bool max310x_adopt_hw_tx(struct max310x_one *one)
+{
+ struct uart_port *port = &one->port;
+
+ if (!max310x_port_read(port, MAX310X_TXFIFOLVL_REG) &&
+ kfifo_is_empty(&port->state->port.xmit_fifo))
+ return false;
+
+ scoped_guard(spinlock_irqsave, &port->lock) {
+ if (one->tx_teardown)
+ return false;
+ if (READ_ONCE(one->tx_state) != MAX310X_TX_OFF)
+ return true;
+ WRITE_ONCE(one->tx_state, MAX310X_TX_SEND);
+ one->cancel_tx_delay_tmr = false;
+ }
+
+ return true;
+}
+
+/*
+ * Pick hardware or software RTS timing for the current port. The chip can
+ * deliver up to 15 bit-times of setup/hold delay via HDPIXDELAY; anything
+ * longer (or any RTS polarity the chip cannot produce automatically) must
+ * be driven by software via tx_delay_tmr and rts_work.
+ */
+static void max310x_set_rts_ctl_params(struct max310x_one *one)
+{
+ const unsigned int max_bit_dly = 15;
+ struct uart_port *port = &one->port;
+ unsigned int setup = 0, hold = 0;
+ u8 mode1 = 0, irda = 0;
+ bool sw_rts = false;
+
+ if (!(port->rs485.flags & SER_RS485_ENABLED))
+ goto out;
+
+ /* Convert milliseconds to bit-times, rounding up. */
+ setup = DIV_ROUND_UP(one->baud * port->rs485.delay_rts_before_send,
+ MSEC_PER_SEC);
+ hold = DIV_ROUND_UP(one->baud * port->rs485.delay_rts_after_send,
+ MSEC_PER_SEC);
+
+ /*
+ * Compare in bit-times: a delay of exactly max_bit_dly bit-times
+ * must stay on the hardware path, which a nanosecond ceiling
+ * computed from the truncated per-bit time would reject. Without
+ * a baud rate the conversion is meaningless - use software.
+ */
+ if (!one->baud || setup > max_bit_dly || hold > max_bit_dly ||
+ !!(port->rs485.flags & SER_RS485_RTS_ON_SEND) ==
+ !!(port->rs485.flags & SER_RS485_RTS_AFTER_SEND)) {
+ sw_rts = true;
+ setup = 0;
+ hold = 0;
+ }
+
+out:
+ /* Assign once; a transient false would be seen by other readers. */
+ WRITE_ONCE(one->sw_rts_during_tx, sw_rts);
+
+ max310x_port_write(port, MAX310X_HDPIXDELAY_REG,
+ MAX310X_HDPIXDELAY_SETUP(setup) |
+ MAX310X_HDPIXDELAY_HOLD(hold));
+
+ /*
+ * A break owns the transceiver: break_ctl() disabled auto-RTS and
+ * drives RTS manually, and restores it from the current
+ * configuration when the break ends. Touching them here would
+ * release the transceiver mid-break.
+ */
+ if (one->tx_break)
+ return;
+
+ if (port->rs485.flags & SER_RS485_ENABLED) {
+ if (sw_rts) {
+ /*
+ * Only settle RTS at idle when no transmission owns it.
+ * A reconfigure while one is in flight - rs_work runs
+ * on every TIOCSRS485 - would otherwise release the
+ * transceiver mid-character. A transfer the hardware
+ * path owns is invisible to tx_state - adopt it
+ * instead of settling. The reverse strand also
+ * exists: an envelope the hardware path inherited
+ * mid-envelope leaves tx_state set with nothing
+ * driving the pin.
+ */
+ if (READ_ONCE(one->tx_state) != MAX310X_TX_OFF ||
+ max310x_adopt_hw_tx(one)) {
+ /*
+ * The transfer may be running under auto-RTS:
+ * assert before auto-RTS is disabled below so
+ * the pin is never released under it, and arm
+ * the after-send hold - with the chip FIFO
+ * already drained no TX-empty interrupt
+ * arrives to arm it.
+ */
+ max310x_rts_ctl(port,
+ max310x_rts_level(port, true));
+ max310x_delayed_stop_tx(port);
+ } else {
+ max310x_rts_ctl(port,
+ max310x_rts_level(port, false));
+ /*
+ * serial_core calls set_termios() without
+ * port->lock, so an envelope may have started
+ * while the idle level was written and the
+ * settle can land after its RTS assert.
+ * rts_work re-derives the level from
+ * tx_state; requeue it to converge.
+ */
+ if (READ_ONCE(one->tx_state) != MAX310X_TX_OFF)
+ schedule_work(&one->rts_work);
+ }
+ } else {
+ mode1 = MAX310X_MODE1_TRNSCVCTRL_BIT;
+ /*
+ * The auto-RTS engine asserts RTS high on send; for an
+ * active-low RTS let IRDA.RTSINVERT invert the output
+ * stage.
+ */
+ if (!(port->rs485.flags & SER_RS485_RTS_ON_SEND))
+ irda = MAX310X_IRDA_RTSINVERT_BIT;
+ }
+ } else {
+ max310x_rts_ctl(port, 0);
+ }
+
+ max310x_port_update(port, MAX310X_MODE1_REG,
+ MAX310X_MODE1_TRNSCVCTRL_BIT, mode1);
+ max310x_port_update(port, MAX310X_IRDA_REG,
+ MAX310X_IRDA_RTSINVERT_BIT, irda);
+}
+
static void max310x_break_ctl(struct uart_port *port, int break_state)
{
+ struct max310x_one *one = to_max310x_port(port);
+
+ one->tx_break = break_state;
+
max310x_port_update(port, MAX310X_LCR_REG,
MAX310X_LCR_TXBREAK_BIT,
break_state ? MAX310X_LCR_TXBREAK_BIT : 0);
+
+ /*
+ * The chip's auto-RTS asserts the transceiver only while FIFO data is
+ * shifting out, and a break is not FIFO data. Disable auto-RTS for the
+ * break duration and drive RTS manually so the break reaches the wire;
+ * restore auto-RTS when the break ends. For an active-low RTS,
+ * IRDA.RTSINVERT already inverts the RTS_ output stage, so break_state
+ * is driven as it is.
+ */
+ if (break_state) {
+ if (!(port->rs485.flags & SER_RS485_ENABLED))
+ return;
+ if (READ_ONCE(one->sw_rts_during_tx)) {
+ max310x_rts_ctl(port, max310x_rts_level(port, 1));
+ } else {
+ max310x_port_update(port, MAX310X_MODE1_REG,
+ MAX310X_MODE1_TRNSCVCTRL_BIT, 0);
+ max310x_rts_ctl(port, 1);
+ }
+ } else {
+ /*
+ * Reapply the current configuration: a reconfigure that
+ * arrived during the break was deferred by the tx_break
+ * guard, and RS485 may have been disabled outright - the
+ * manually driven RTS must not leak past the break. On the
+ * software path the helper also settles the idle level; on
+ * the hardware path release the manual RTS - auto-RTS owns
+ * the pin again.
+ */
+ max310x_set_rts_ctl_params(one);
+ if (!READ_ONCE(one->sw_rts_during_tx))
+ max310x_rts_ctl(port, 0);
+ }
}
static void max310x_set_termios(struct uart_port *port,
struct ktermios *termios,
const struct ktermios *old)
{
+ unsigned int frame_bits = tty_get_frame_size(termios->c_cflag);
unsigned int lcr = 0, flow = 0;
int baud;
@@ -967,8 +1359,13 @@ static void max310x_set_termios(struct uart_port *port,
if (termios->c_cflag & CSTOPB)
lcr |= MAX310X_LCR_STOPLEN_BIT; /* 2 stops */
- /* Update LCR register */
- max310x_port_write(port, MAX310X_LCR_REG, lcr);
+ /*
+ * Update LCR register. Leave the TX break and RTS bits alone: they are
+ * driven by break_ctl() and by the software-timed RS485 RTS, and a
+ * whole-register write here would end a break in progress or release
+ * the transceiver mid-character.
+ */
+ max310x_port_update(port, MAX310X_LCR_REG, MAX310X_LCR_TERMIOS_MASK, lcr);
/* Set read status mask */
port->read_status_mask = MAX310X_LSR_RXOVR_BIT;
@@ -1040,41 +1437,101 @@ static void max310x_set_termios(struct uart_port *port,
/* Update timeout according to new baud rate */
uart_update_timeout(port, termios->c_cflag, baud);
+
+ /*
+ * Cache the new baud rate and the time it takes to clock out one
+ * character before reprogramming the RS485 RTS delays: the
+ * millisecond-to-bit-time conversion divides by the baud rate, and
+ * taking over an in-flight transfer arms the after-send hold from
+ * the character time.
+ */
+ to_max310x_port(port)->baud = baud;
+ to_max310x_port(port)->char_time_us =
+ DIV_ROUND_UP(USEC_PER_SEC * frame_bits, baud);
+ max310x_set_rts_ctl_params(to_max310x_port(port));
}
static void max310x_rs_proc(struct work_struct *ws)
{
struct max310x_one *one = container_of(ws, struct max310x_one, rs_work);
- unsigned int delay, mode1 = 0, mode2 = 0;
+ unsigned int mode2 = 0;
+ unsigned long flags;
+ bool chip_tx_empty;
+
+ /*
+ * Serialize against break_ctl() and set_termios(), which run under
+ * port->mutex: the tx_break-guarded register writes must not
+ * straddle a break starting or ending.
+ */
+ guard(mutex)(&one->port.state->port.mutex);
- delay = (one->port.rs485.delay_rts_before_send << 4) |
- one->port.rs485.delay_rts_after_send;
- max310x_port_write(&one->port, MAX310X_HDPIXDELAY_REG, delay);
+ /* Flush an rts_work that read tx_state before the disable cleared it. */
+ if (!(one->port.rs485.flags & SER_RS485_ENABLED))
+ cancel_work_sync(&one->rts_work);
- if (one->port.rs485.flags & SER_RS485_ENABLED) {
- mode1 = MAX310X_MODE1_TRNSCVCTRL_BIT;
+ max310x_set_rts_ctl_params(one);
- if (!(one->port.rs485.flags & SER_RS485_RX_DURING_TX))
- mode2 = MAX310X_MODE2_ECHOSUPR_BIT;
- }
+ if (one->port.rs485.flags & SER_RS485_ENABLED &&
+ !(one->port.rs485.flags & SER_RS485_RX_DURING_TX))
+ mode2 = MAX310X_MODE2_ECHOSUPR_BIT;
- max310x_port_update(&one->port, MAX310X_MODE1_REG,
- MAX310X_MODE1_TRNSCVCTRL_BIT, mode1);
max310x_port_update(&one->port, MAX310X_MODE2_REG,
- MAX310X_MODE2_ECHOSUPR_BIT, mode2);
+ MAX310X_MODE2_ECHOSUPR_BIT, mode2);
+
+ /*
+ * The configuration is applied: release any TX that start_tx()
+ * deferred while the reconfigure was pending, now on the right
+ * path. start_tx() can drop and retake the lock through the
+ * uart_port API - a raw spinlock guard here would unbalance it.
+ */
+ chip_tx_empty = !max310x_port_read(&one->port,
+ MAX310X_TXFIFOLVL_REG);
+
+ uart_port_lock_irqsave(&one->port, &flags);
+ one->rs485_pending = false;
+ if (one->port.x_char ||
+ !kfifo_is_empty(&one->port.state->port.xmit_fifo)) {
+ /*
+ * A send state adopted without chip data is the deferred
+ * write itself: restart it as a fresh envelope so the
+ * before-send delay is honoured.
+ */
+ if (chip_tx_empty &&
+ READ_ONCE(one->tx_state) == MAX310X_TX_SEND)
+ WRITE_ONCE(one->tx_state, MAX310X_TX_OFF);
+ max310x_start_tx(&one->port);
+ }
+ uart_port_unlock_irqrestore(&one->port, flags);
}
+/* called with port.lock taken and irqs off */
static int max310x_rs485_config(struct uart_port *port, struct ktermios *termios,
struct serial_rs485 *rs485)
{
struct max310x_one *one = to_max310x_port(port);
- if ((rs485->delay_rts_before_send > 0x0f) ||
- (rs485->delay_rts_after_send > 0x0f))
- return -ERANGE;
+ rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
+ rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U);
+
+ /*
+ * Make sure no SW-timed RTS toggle survives an RS485 disable, even
+ * if the delay timer happens to be running right now.
+ */
+ if (!(rs485->flags & SER_RS485_ENABLED)) {
+ one->tx_teardown = true;
+ one->cancel_tx_delay_tmr = true;
+ if (hrtimer_try_to_cancel(&one->tx_delay_tmr) == -1) {
+ uart_port_unlock(port);
+ hrtimer_cancel(&one->tx_delay_tmr);
+ uart_port_lock(port);
+ }
+ WRITE_ONCE(one->tx_state, MAX310X_TX_OFF);
+ one->tx_teardown = false;
+ }
port->rs485 = *rs485;
+ one->rs485_pending = true;
schedule_work(&one->rs_work);
return 0;
@@ -1082,13 +1539,23 @@ static int max310x_rs485_config(struct uart_port *port, struct ktermios *termios
static int max310x_startup(struct uart_port *port)
{
+ struct max310x_one *one = to_max310x_port(port);
unsigned int val;
max310x_power(port, 1);
- /* Configure MODE1 register */
+ /*
+ * Clear a latched break: nothing clears TXBREAK when a port is
+ * closed with a break still asserted, and set_termios() no longer
+ * rewrites it.
+ */
+ one->tx_break = false;
+ max310x_port_update(port, MAX310X_LCR_REG, MAX310X_LCR_TXBREAK_BIT, 0);
+
+ /* Configure MODE1: re-enable the transmitter shutdown() stopped */
max310x_port_update(port, MAX310X_MODE1_REG,
- MAX310X_MODE1_TRNSCVCTRL_BIT, 0);
+ MAX310X_MODE1_TRNSCVCTRL_BIT |
+ MAX310X_MODE1_TXDIS_BIT, 0);
/* Configure MODE2 register & Reset FIFOs*/
val = MAX310X_MODE2_RXEMPTINV_BIT | MAX310X_MODE2_FIFORST_BIT;
@@ -1096,21 +1563,22 @@ static int max310x_startup(struct uart_port *port)
max310x_port_update(port, MAX310X_MODE2_REG,
MAX310X_MODE2_FIFORST_BIT, 0);
- /* Configure mode1/mode2 to have rs485/rs232 enabled at startup */
- val = (clamp(port->rs485.delay_rts_before_send, 0U, 15U) << 4) |
- clamp(port->rs485.delay_rts_after_send, 0U, 15U);
- max310x_port_write(port, MAX310X_HDPIXDELAY_REG, val);
+ one->tx_teardown = false;
- if (port->rs485.flags & SER_RS485_ENABLED) {
- max310x_port_update(port, MAX310X_MODE1_REG,
- MAX310X_MODE1_TRNSCVCTRL_BIT,
- MAX310X_MODE1_TRNSCVCTRL_BIT);
+ /*
+ * Configure the RS485 RTS timing (HW auto-RTS vs software-driven) and
+ * the RS485/RS232 mode bits. Don't hardcode HW auto-RTS here - let
+ * max310x_set_rts_ctl_params() pick HW or SW per the configured
+ * delays, otherwise the chip's auto-RTS would override the software
+ * RTS hold and the after-send delay is lost.
+ */
+ max310x_set_rts_ctl_params(one);
- if (!(port->rs485.flags & SER_RS485_RX_DURING_TX))
- max310x_port_update(port, MAX310X_MODE2_REG,
- MAX310X_MODE2_ECHOSUPR_BIT,
- MAX310X_MODE2_ECHOSUPR_BIT);
- }
+ if (port->rs485.flags & SER_RS485_ENABLED &&
+ !(port->rs485.flags & SER_RS485_RX_DURING_TX))
+ max310x_port_update(port, MAX310X_MODE2_REG,
+ MAX310X_MODE2_ECHOSUPR_BIT,
+ MAX310X_MODE2_ECHOSUPR_BIT);
/*
* Configure flow control levels:
@@ -1132,9 +1600,91 @@ static int max310x_startup(struct uart_port *port)
static void max310x_shutdown(struct uart_port *port)
{
- /* Disable all interrupts */
+ struct max310x_one *one = to_max310x_port(port);
+
+ /*
+ * Gate new transmissions and interrupts first: a concurrent
+ * start_tx() either sees the interlock or happens-before it, and
+ * nothing below may start a new envelope. The timer and the works
+ * stay live for now - they are what completes a running after-send
+ * hold.
+ */
+ scoped_guard(spinlock_irqsave, &port->lock)
+ one->tx_teardown = true;
max310x_port_write(port, MAX310X_IRQEN_REG, 0);
+ /*
+ * Stop the transmitter: the character in flight completes, data
+ * still queued is abandoned (the next startup() resets the FIFOs).
+ */
+ max310x_port_update(port, MAX310X_MODE1_REG,
+ MAX310X_MODE1_TXDIS_BIT, MAX310X_MODE1_TXDIS_BIT);
+
+ if (READ_ONCE(one->sw_rts_during_tx)) {
+ /*
+ * Honour a running after-send hold before the port is
+ * powered down. The bound covers the final character -
+ * tx_empty() cannot see the transmit shift register - plus
+ * the hold itself. Data beyond that is abandoned: it is
+ * only still queued when the tty layer was told not to
+ * wait, and the release below drives RTS to idle
+ * regardless.
+ */
+ unsigned int tries = port->rs485.delay_rts_after_send +
+ 2 * DIV_ROUND_UP(one->char_time_us, USEC_PER_MSEC);
+
+ while (READ_ONCE(one->tx_state) != MAX310X_TX_OFF && tries-- > 0)
+ fsleep(USEC_PER_MSEC);
+ } else {
+ /*
+ * Let the character in flight finish (the chip has no
+ * transmitter-idle status), then empty the FIFO: auto-RTS
+ * releases only once the transmitter is empty, and the
+ * power-off below would freeze an asserted pin until the
+ * next open. The hold is at most 15 bit-times.
+ */
+ fsleep(one->char_time_us);
+ max310x_port_update(port, MAX310X_MODE2_REG,
+ MAX310X_MODE2_FIFORST_BIT,
+ MAX310X_MODE2_FIFORST_BIT);
+ max310x_port_update(port, MAX310X_MODE2_REG,
+ MAX310X_MODE2_FIFORST_BIT, 0);
+ if (port->rs485.flags & SER_RS485_ENABLED && one->baud) {
+ unsigned int hold = DIV_ROUND_UP(one->baud *
+ port->rs485.delay_rts_after_send,
+ MSEC_PER_SEC);
+
+ fsleep(max(DIV_ROUND_UP((hold + 1) * USEC_PER_SEC,
+ one->baud), 100U));
+ }
+ }
+
+ /*
+ * The wind-down is over: cancel unconditionally. The SW/HW decision
+ * is recomputed on every reconfigure, so a TIOCSRS485 can clear
+ * sw_rts_during_tx while an envelope is still in flight, and
+ * neither the timer nor the works may outlive the port.
+ */
+ scoped_guard(spinlock_irqsave, &port->lock)
+ one->cancel_tx_delay_tmr = true;
+ cancel_work_sync(&one->tx_work);
+ hrtimer_cancel(&one->tx_delay_tmr);
+ cancel_work_sync(&one->rts_work);
+ WRITE_ONCE(one->tx_state, MAX310X_TX_OFF);
+
+ if (READ_ONCE(one->sw_rts_during_tx)) {
+ max310x_rts_ctl(port, max310x_rts_level(port, false));
+ /*
+ * The power-off below stops the UART clock that moves the
+ * RTS pin: released too late, the write reaches the register
+ * but the pin stays at its old level until the next startup
+ * restarts the clock. Give the release one bit time (at
+ * least 100 us) to reach the pin - the measured propagation
+ * is about one tick of the 16x oversampling clock.
+ */
+ fsleep(max(one->char_time_us / 10, 100U));
+ }
+
max310x_power(port, 0);
}
@@ -1300,7 +1850,8 @@ static int max310x_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
#endif
static const struct serial_rs485 max310x_rs485_supported = {
- .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RX_DURING_TX,
+ .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
+ SER_RS485_RTS_AFTER_SEND | SER_RS485_RX_DURING_TX,
.delay_rts_before_send = 1,
.delay_rts_after_send = 1,
};
@@ -1427,6 +1978,11 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
INIT_WORK(&s->p[i].md_work, max310x_md_proc);
/* Initialize queue for changing RS485 mode */
INIT_WORK(&s->p[i].rs_work, max310x_rs_proc);
+ /* Initialize queue for software-driven RTS toggling */
+ INIT_WORK(&s->p[i].rts_work, max310x_rts_work_proc);
+ hrtimer_setup(&s->p[i].tx_delay_tmr, max310x_tmr_tx,
+ CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ s->p[i].tx_state = MAX310X_TX_OFF;
}
#ifdef CONFIG_GPIOLIB
@@ -1538,6 +2094,8 @@ static void max310x_remove(struct device *dev)
int i;
for (i = 0; i < s->devtype->nr; i++) {
+ hrtimer_cancel(&s->p[i].tx_delay_tmr);
+ cancel_work_sync(&s->p[i].rts_work);
cancel_work_sync(&s->p[i].tx_work);
cancel_work_sync(&s->p[i].md_work);
cancel_work_sync(&s->p[i].rs_work);
diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c
index 93e7dda4d39a..2b862dfe39ab 100644
--- a/drivers/tty/serial/mcf.c
+++ b/drivers/tty/serial/mcf.c
@@ -4,7 +4,7 @@
/*
* mcf.c -- Freescale ColdFire UART driver
*
- * (C) Copyright 2003-2007, Greg Ungerer <gerg@uclinux.org>
+ * (C) Copyright 2003-2007, Greg Ungerer <gerg@linux-m68k.org>
*/
/****************************************************************************/
@@ -654,7 +654,7 @@ static void __exit mcf_exit(void)
module_init(mcf_init);
module_exit(mcf_exit);
-MODULE_AUTHOR("Greg Ungerer <gerg@uclinux.org>");
+MODULE_AUTHOR("Greg Ungerer <gerg@linux-m68k.org>");
MODULE_DESCRIPTION("Freescale ColdFire UART driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:mcfuart");
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index db5c62b0322f..9505d255f09c 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -811,7 +811,7 @@ static int dma_handle_rx(struct eg20t_port *priv)
priv->desc_rx = desc;
desc->callback = pch_dma_rx_complete;
desc->callback_param = priv;
- desc->tx_submit(desc);
+ dmaengine_submit(desc);
dma_async_issue_pending(priv->chan_rx);
return PCH_UART_HANDLED_RX_INT;
@@ -971,7 +971,7 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
desc->callback = pch_dma_tx_complete;
desc->callback_param = priv;
- desc->tx_submit(desc);
+ dmaengine_submit(desc);
dma_async_issue_pending(priv->chan_tx);
diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c
index e3a919328695..a612f1db9f18 100644
--- a/drivers/tty/serial/pmac_zilog.c
+++ b/drivers/tty/serial/pmac_zilog.c
@@ -233,6 +233,7 @@ static bool pmz_receive_chars(struct uart_pmac_port *uap)
ch &= uap->parity_mask;
if (ch == 0 && uap->flags & PMACZILOG_FLAG_BREAK) {
uap->flags &= ~PMACZILOG_FLAG_BREAK;
+ r1 |= BRK_ABRT;
}
#if defined(CONFIG_MAGIC_SYSRQ) && defined(CONFIG_SERIAL_CORE_CONSOLE)
@@ -444,7 +445,7 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id)
skip_a:
uart_port_unlock(&uap_a->port);
if (push)
- tty_flip_buffer_push(&uap->port.state->port);
+ tty_flip_buffer_push(&uap_a->port.state->port);
if (!uap_b)
goto out;
@@ -469,7 +470,7 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id)
skip_b:
uart_port_unlock(&uap_b->port);
if (push)
- tty_flip_buffer_push(&uap->port.state->port);
+ tty_flip_buffer_push(&uap_b->port.state->port);
out:
return rc;
diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c
index a851b8f0ef04..bfdc155c128d 100644
--- a/drivers/tty/serial/qcom_geni_serial.c
+++ b/drivers/tty/serial/qcom_geni_serial.c
@@ -20,7 +20,6 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/panic_notifier.h>
-#include <linux/pm_domain.h>
#include <linux/pm_opp.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@@ -288,6 +287,10 @@ static struct qcom_geni_serial_port *get_port_from_line(int line, bool console,
} else {
int max_alias_num = of_alias_get_highest_id("serial");
+ port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
+ if (!port)
+ return ERR_PTR(-ENOMEM);
+
if (line < 0 || line >= nr_ports)
line = ida_alloc_range(&port_ida, max_alias_num + 1,
nr_ports - 1, GFP_KERNEL);
@@ -298,10 +301,6 @@ static struct qcom_geni_serial_port *get_port_from_line(int line, bool console,
if (line < 0)
return ERR_PTR(-ENXIO);
- port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
- if (!port)
- return ERR_PTR(-ENOMEM);
-
port->uport.iotype = UPIO_MEM;
port->uport.ops = &qcom_geni_uart_pops;
port->uport.flags = UPF_BOOT_AUTOCONF;
@@ -1293,7 +1292,6 @@ out_unlock:
static int setup_fifos(struct qcom_geni_serial_port *port)
{
struct uart_port *uport;
- u32 old_rx_fifo_depth = port->rx_fifo_depth;
uport = &port->uport;
port->tx_fifo_depth = geni_se_get_tx_fifo_depth(&port->se);
@@ -1302,19 +1300,6 @@ static int setup_fifos(struct qcom_geni_serial_port *port)
uport->fifosize =
(port->tx_fifo_depth * port->tx_fifo_width) / BITS_PER_BYTE;
- if (port->rx_buf && (old_rx_fifo_depth != port->rx_fifo_depth) && port->rx_fifo_depth) {
- /*
- * Use krealloc rather than krealloc_array because rx_buf is
- * accessed as 1 byte entries as well as 4 byte entries so it's
- * not necessarily an array.
- */
- port->rx_buf = devm_krealloc(uport->dev, port->rx_buf,
- port->rx_fifo_depth * sizeof(u32),
- GFP_KERNEL);
- if (!port->rx_buf)
- return -ENOMEM;
- }
-
return 0;
}
@@ -1484,7 +1469,7 @@ static int geni_serial_set_rate(struct geni_se *se, unsigned long baud)
* Bump up BW vote on CPU and CORE path as driver supports FIFO mode
* only.
*/
- avg_bw_core = baud > 115200 ? CORE_2X_50_MHZ : CORE_2X_19_2_MHZ;
+ avg_bw_core = (baud > 115200) ? CORE_2X_50_MHZ : CORE_2X_19_2_MHZ;
port->se.icc_paths[GENI_TO_CORE].avg_bw = Bps_to_icc(avg_bw_core);
port->se.icc_paths[CPU_TO_GENI].avg_bw = Bps_to_icc(baud);
geni_icc_set_bw(&port->se);
@@ -1920,7 +1905,7 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
ret = port->dev_data->resources_init(&port->se);
if (ret)
- return ret;
+ goto error;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
@@ -1970,8 +1955,13 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
uport->irq = irq;
uport->has_sysrq = IS_ENABLED(CONFIG_SERIAL_QCOM_GENI_CONSOLE);
- if (!data->console)
+ if (!data->console) {
port->wakeup_irq = platform_get_irq_optional(pdev, 1);
+ if (port->wakeup_irq < 0 && port->wakeup_irq != -ENXIO) {
+ ret = port->wakeup_irq;
+ goto error;
+ }
+ }
if (of_property_read_bool(pdev->dev.of_node, "rx-tx-swap"))
port->rx_tx_swap = true;
@@ -2002,7 +1992,6 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
port->wakeup_irq);
if (ret) {
device_init_wakeup(&pdev->dev, false);
- ida_free(&port_ida, uport->line);
goto error;
}
}
@@ -2026,12 +2015,13 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
return 0;
error:
+ if (!data->console)
+ ida_free(&port_ida, uport->line);
if (port->rx_dma_addr) {
dma_unmap_single(pdev->dev.parent, port->rx_dma_addr,
DMA_RX_BUF_SIZE, DMA_FROM_DEVICE);
port->rx_dma_addr = 0;
}
- dev_pm_domain_detach_list(port->se.pd_list);
return ret;
}
@@ -2047,7 +2037,8 @@ static void qcom_geni_serial_remove(struct platform_device *pdev)
irq_work_sync(&port->tx_kick);
dev_pm_clear_wake_irq(&pdev->dev);
device_init_wakeup(&pdev->dev, false);
- ida_free(&port_ida, uport->line);
+ if (!port->dev_data->console)
+ ida_free(&port_ida, uport->line);
uart_remove_one_port(drv, &port->uport);
if (port->rx_dma_addr) {
@@ -2055,8 +2046,6 @@ static void qcom_geni_serial_remove(struct platform_device *pdev)
DMA_RX_BUF_SIZE, DMA_FROM_DEVICE);
port->rx_dma_addr = 0;
}
-
- dev_pm_domain_detach_list(port->se.pd_list);
}
static int __maybe_unused qcom_geni_serial_runtime_suspend(struct device *dev)
@@ -2128,6 +2117,12 @@ static int qcom_geni_serial_resume(struct device *dev)
return ret;
}
+ if (console_suspend_enabled && uart_console(uport)) {
+ ret = pm_runtime_resume(dev);
+ if (ret < 0)
+ return ret;
+ }
+
ret = uart_resume_port(private_data->drv, uport);
if (uart_console(uport)) {
geni_icc_set_tag(&port->se, QCOM_ICC_TAG_ALWAYS);
diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c
index 63d0232dffc2..640f85e2d636 100644
--- a/drivers/tty/serial/samsung_tty.c
+++ b/drivers/tty/serial/samsung_tty.c
@@ -300,7 +300,7 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port)
dmaengine_pause(dma->tx_chan);
dmaengine_tx_status(dma->tx_chan, dma->tx_cookie, &state);
dmaengine_terminate_all(dma->tx_chan);
- dma_sync_single_for_cpu(dma->tx_chan->device->dev,
+ dma_sync_single_for_cpu(dmaengine_get_dma_device(dma->tx_chan),
dma->tx_transfer_addr, dma->tx_size,
DMA_TO_DEVICE);
async_tx_ack(dma->tx_desc);
@@ -333,7 +333,7 @@ static void s3c24xx_serial_tx_dma_complete(void *args)
count = dma->tx_bytes_requested - state.residue;
async_tx_ack(dma->tx_desc);
- dma_sync_single_for_cpu(dma->tx_chan->device->dev,
+ dma_sync_single_for_cpu(dmaengine_get_dma_device(dma->tx_chan),
dma->tx_transfer_addr, dma->tx_size,
DMA_TO_DEVICE);
@@ -435,7 +435,7 @@ static int s3c24xx_serial_start_tx_dma(struct s3c24xx_uart_port *ourport,
dma->tx_size = count & ~(dma_get_cache_alignment() - 1);
dma->tx_transfer_addr = dma->tx_addr + tail;
- dma_sync_single_for_device(dma->tx_chan->device->dev,
+ dma_sync_single_for_device(dmaengine_get_dma_device(dma->tx_chan),
dma->tx_transfer_addr, dma->tx_size,
DMA_TO_DEVICE);
@@ -509,7 +509,7 @@ static void s3c24xx_uart_copy_rx_to_tty(struct s3c24xx_uart_port *ourport,
if (!count)
return;
- dma_sync_single_for_cpu(dma->rx_chan->device->dev, dma->rx_addr,
+ dma_sync_single_for_cpu(dmaengine_get_dma_device(dma->rx_chan), dma->rx_addr,
dma->rx_size, DMA_FROM_DEVICE);
ourport->port.icount.rx += count;
@@ -631,7 +631,7 @@ static void s3c64xx_start_rx_dma(struct s3c24xx_uart_port *ourport)
{
struct s3c24xx_uart_dma *dma = ourport->dma;
- dma_sync_single_for_device(dma->rx_chan->device->dev, dma->rx_addr,
+ dma_sync_single_for_device(dmaengine_get_dma_device(dma->rx_chan), dma->rx_addr,
dma->rx_size, DMA_FROM_DEVICE);
dma->rx_desc = dmaengine_prep_slave_single(dma->rx_chan,
@@ -1101,20 +1101,23 @@ static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
goto err_release_tx;
}
- dma->rx_addr = dma_map_single(dma->rx_chan->device->dev, dma->rx_buf,
+ struct device *rx_dev = dmaengine_get_dma_device(dma->rx_chan);
+ struct device *tx_dev = dmaengine_get_dma_device(dma->tx_chan);
+
+ dma->rx_addr = dma_map_single(rx_dev, dma->rx_buf,
dma->rx_size, DMA_FROM_DEVICE);
- if (dma_mapping_error(dma->rx_chan->device->dev, dma->rx_addr)) {
+ if (dma_mapping_error(rx_dev, dma->rx_addr)) {
reason = "DMA mapping error for RX buffer";
ret = -EIO;
goto err_free_rx;
}
/* TX buffer */
- dma->tx_addr = dma_map_single(dma->tx_chan->device->dev,
+ dma->tx_addr = dma_map_single(tx_dev,
p->port.state->port.xmit_buf,
UART_XMIT_SIZE,
DMA_TO_DEVICE);
- if (dma_mapping_error(dma->tx_chan->device->dev, dma->tx_addr)) {
+ if (dma_mapping_error(tx_dev, dma->tx_addr)) {
reason = "DMA mapping error for TX buffer";
ret = -EIO;
goto err_unmap_rx;
@@ -1123,7 +1126,7 @@ static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
return 0;
err_unmap_rx:
- dma_unmap_single(dma->rx_chan->device->dev, dma->rx_addr,
+ dma_unmap_single(dmaengine_get_dma_device(dma->rx_chan), dma->rx_addr,
dma->rx_size, DMA_FROM_DEVICE);
err_free_rx:
kfree(dma->rx_buf);
@@ -1143,7 +1146,7 @@ static void s3c24xx_serial_release_dma(struct s3c24xx_uart_port *p)
if (dma->rx_chan) {
dmaengine_terminate_all(dma->rx_chan);
- dma_unmap_single(dma->rx_chan->device->dev, dma->rx_addr,
+ dma_unmap_single(dmaengine_get_dma_device(dma->rx_chan), dma->rx_addr,
dma->rx_size, DMA_FROM_DEVICE);
kfree(dma->rx_buf);
dma_release_channel(dma->rx_chan);
@@ -1152,7 +1155,7 @@ static void s3c24xx_serial_release_dma(struct s3c24xx_uart_port *p)
if (dma->tx_chan) {
dmaengine_terminate_all(dma->tx_chan);
- dma_unmap_single(dma->tx_chan->device->dev, dma->tx_addr,
+ dma_unmap_single(dmaengine_get_dma_device(dma->tx_chan), dma->tx_addr,
UART_XMIT_SIZE, DMA_TO_DEVICE);
dma_release_channel(dma->tx_chan);
dma->tx_chan = NULL;
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index 296079c16fdb..fba588559595 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -501,7 +501,9 @@ static bool sc16is7xx_regmap_volatile(struct device *dev, unsigned int reg)
{
switch (reg) {
case SC16IS7XX_RHR_REG: /* Shared address space with THR & DLL */
+ case SC16IS7XX_IER_REG: /* Shared address space with DLH */
case SC16IS7XX_IIR_REG: /* Shared address space with FCR & EFR */
+ case SC16IS7XX_MCR_REG: /* Shared address space with XON1 */
case SC16IS7XX_LSR_REG: /* Shared address space with XON2 */
case SC16IS7XX_MSR_REG: /* Shared address space with TCR & XOFF1 */
case SC16IS7XX_SPR_REG: /* Shared address space with TLR & XOFF2 */
@@ -1516,7 +1518,7 @@ static int sc16is7xx_setup_channel(struct sc16is7xx_one *one, int i,
/* Initialize port data */
port->type = PORT_SC16IS7XX;
port->fifosize = SC16IS7XX_FIFO_SIZE;
- port->flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY;
+ port->flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY | UPF_SOFT_FLOW;
port->iotype = UPIO_BUS;
port->rs485_config = sc16is7xx_config_rs485;
port->rs485_supported = sc16is7xx_rs485_supported;
diff --git a/drivers/mmc/core/sdio_uart.c b/drivers/tty/serial/sdio_uart.c
index 705163c42972..705163c42972 100644
--- a/drivers/mmc/core/sdio_uart.c
+++ b/drivers/tty/serial/sdio_uart.c
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 6332ed545c89..c0deec0e6af4 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -14,6 +14,7 @@
#include <linux/sched/signal.h>
#include <linux/init.h>
#include <linux/console.h>
+#include <linux/ctype.h>
#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
#include <linux/of.h>
@@ -33,7 +34,6 @@
#include <linux/uaccess.h>
#include "serial_base.h"
-#include "8250/8250.h" /* For hub6_match_port() */
/*
* This is used to lock changes in serial line configuration.
@@ -247,29 +247,29 @@ static int uart_alloc_xmit_buf(struct tty_port *port)
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport;
unsigned long flags;
- unsigned long page;
+ u8 *buf;
/*
* Initialise and allocate the transmit and temporary
* buffer.
*/
- page = get_zeroed_page(GFP_KERNEL);
- if (!page)
+ buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
return -ENOMEM;
uport = uart_port_ref_lock(state, &flags);
if (!state->port.xmit_buf) {
- state->port.xmit_buf = (unsigned char *)page;
+ state->port.xmit_buf = buf;
kfifo_init(&state->port.xmit_fifo, state->port.xmit_buf,
PAGE_SIZE);
uart_port_unlock_deref(uport, flags);
} else {
uart_port_unlock_deref(uport, flags);
/*
- * Do not free() the page under the port lock, see
+ * Do not free() the buffer under the port lock, see
* uart_free_xmit_buf().
*/
- free_page(page);
+ kfree(buf);
}
return 0;
@@ -280,10 +280,10 @@ 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;
+ u8 *xmit_buf;
/*
- * Do not free() the transmit buffer page under the port lock since
+ * Do not free() the transmit buffer 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.
@@ -294,7 +294,7 @@ static void uart_free_xmit_buf(struct tty_port *port)
INIT_KFIFO(port->xmit_fifo);
uart_port_unlock_deref(uport, flags);
- free_page((unsigned long)xmit_buf);
+ kfree(xmit_buf);
}
/*
@@ -896,7 +896,11 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
upf_t old_flags, new_flags;
int retval;
- if (!uport || tty_io_error(tty))
+ /*
+ * TTY_IO_ERROR is also set on a port that could not be started, and
+ * this is how such a port is configured. Only refuse a hung up port.
+ */
+ if (!uport || !tty_port_active(port))
return -EIO;
new_port = new_info->port;
@@ -1144,7 +1148,8 @@ static int uart_do_autoconfig(struct tty_struct *tty, struct uart_state *state)
*/
scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &port->mutex) {
uport = uart_port_check(state);
- if (!uport || tty_io_error(tty))
+ /* As in uart_set_info(), only refuse a hung up port. */
+ if (!uport || !tty_port_active(port))
return -EIO;
if (tty_port_users(port) != 1)
@@ -2133,7 +2138,8 @@ EXPORT_SYMBOL_GPL(uart_console_write);
/**
* uart_parse_earlycon - Parse earlycon options
- * @p: ptr to 2nd field (ie., just beyond '<name>,')
+ * @p: ptr to 2nd field (ie., just beyond '<name>,'); %NULL if
+ * no console options were supplied
* @iotype: ptr for decoded iotype (out)
* @addr: ptr for decoded mapbase/iobase (out)
* @options: ptr for <options> field; %NULL if not present (out)
@@ -2153,6 +2159,9 @@ EXPORT_SYMBOL_GPL(uart_console_write);
int uart_parse_earlycon(char *p, enum uart_iotype *iotype,
resource_size_t *addr, char **options)
{
+ if (!p)
+ return -EINVAL;
+
if (strncmp(p, "mmio,", 5) == 0) {
*iotype = UPIO_MEM;
p += 5;
@@ -2211,7 +2220,7 @@ uart_parse_options(const char *options, int *baud, int *parity,
const char *s = options;
*baud = simple_strtoul(s, NULL, 10);
- while (*s >= '0' && *s <= '9')
+ while (isdigit(*s))
s++;
if (*s)
*parity = *s++;
@@ -3236,6 +3245,13 @@ static void serial_core_remove_one_port(struct uart_driver *drv,
if (uart_console(uport))
unregister_console(uport->cons);
+ scoped_guard(mutex, &port->mutex) {
+ port->console = false;
+
+ if (tty_port_initialized(port))
+ uart_shutdown(NULL, state);
+ }
+
/*
* Free the port IO and memory resources, if any.
*/
@@ -3256,32 +3272,6 @@ static void serial_core_remove_one_port(struct uart_driver *drv,
state->uart_port = NULL;
}
-/**
- * uart_match_port - are the two ports equivalent?
- * @port1: first port
- * @port2: second port
- *
- * This utility function can be used to determine whether two uart_port
- * structures describe the same port.
- */
-bool uart_match_port(const struct uart_port *port1,
- const struct uart_port *port2)
-{
- if (port1->iotype != port2->iotype)
- return false;
- else if (port1->iotype == UPIO_PORT)
- return port1->iobase == port2->iobase;
- else if (port1->iotype == UPIO_HUB6)
- return hub6_match_port(port1, port2);
- else if (uart_iotype_mmio(port1->iotype))
- return port1->mapbase == port2->mapbase;
- else if (port1->iotype == UPIO_BUS)
- return true;
- else
- return false;
-}
-EXPORT_SYMBOL(uart_match_port);
-
static struct serial_ctrl_device *
serial_core_get_ctrl_dev(struct serial_port_device *port_dev)
{
diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c
index 4ae9a45c8e3a..5b574ed276b2 100644
--- a/drivers/tty/serial/serial_txx9.c
+++ b/drivers/tty/serial/serial_txx9.c
@@ -965,7 +965,12 @@ static int serial_txx9_register_port(struct uart_port *port)
mutex_lock(&serial_txx9_mutex);
for (i = 0; i < UART_NR; i++) {
uart = &serial_txx9_ports[i];
- if (uart_match_port(uart, port)) {
+ /*
+ * serial_txx9_register_port() is only called from
+ * pciserial_txx9_init_one(). So .iotype is UPIO_PORT and
+ * comparing .iobase serves to distinguish ports.
+ */
+ if (uart->iobase == port->iobase) {
uart_remove_one_port(&serial_txx9_reg, uart);
break;
}
@@ -1009,7 +1014,8 @@ static void serial_txx9_unregister_port(int line)
struct uart_port *uart = &serial_txx9_ports[line];
mutex_lock(&serial_txx9_mutex);
- uart_remove_one_port(&serial_txx9_reg, uart);
+ if (uart->iobase || uart->mapbase)
+ uart_remove_one_port(&serial_txx9_reg, uart);
uart->flags = 0;
uart->type = PORT_UNKNOWN;
uart->iobase = 0;
@@ -1019,52 +1025,6 @@ static void serial_txx9_unregister_port(int line)
mutex_unlock(&serial_txx9_mutex);
}
-/*
- * Register a set of serial devices attached to a platform device.
- */
-static int serial_txx9_probe(struct platform_device *dev)
-{
- struct uart_port *p = dev_get_platdata(&dev->dev);
- struct uart_port port;
- int ret, i;
-
- memset(&port, 0, sizeof(struct uart_port));
- for (i = 0; p && p->uartclk != 0; p++, i++) {
- port.iobase = p->iobase;
- port.membase = p->membase;
- port.irq = p->irq;
- port.uartclk = p->uartclk;
- port.iotype = p->iotype;
- port.flags = p->flags;
- port.mapbase = p->mapbase;
- port.dev = &dev->dev;
- port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_TXX9_CONSOLE);
- ret = serial_txx9_register_port(&port);
- if (ret < 0) {
- dev_err(&dev->dev, "unable to register port at index %d "
- "(IO%lx MEM%llx IRQ%d): %d\n", i,
- p->iobase, (unsigned long long)p->mapbase,
- p->irq, ret);
- }
- }
- return 0;
-}
-
-/*
- * Remove serial ports registered against a platform device.
- */
-static void serial_txx9_remove(struct platform_device *dev)
-{
- int i;
-
- for (i = 0; i < UART_NR; i++) {
- struct uart_port *up = &serial_txx9_ports[i];
-
- if (up->dev == &dev->dev)
- serial_txx9_unregister_port(i);
- }
-}
-
#ifdef CONFIG_PM
static int serial_txx9_suspend(struct platform_device *dev, pm_message_t state)
{
@@ -1096,8 +1056,6 @@ static int serial_txx9_resume(struct platform_device *dev)
#endif
static struct platform_driver serial_txx9_plat_driver = {
- .probe = serial_txx9_probe,
- .remove = serial_txx9_remove,
#ifdef CONFIG_PM
.suspend = serial_txx9_suspend,
.resume = serial_txx9_resume,
@@ -1251,9 +1209,7 @@ static void __exit serial_txx9_exit(void)
platform_driver_unregister(&serial_txx9_plat_driver);
platform_device_unregister(serial_txx9_plat_devs);
for (i = 0; i < UART_NR; i++) {
- struct uart_port *up = &serial_txx9_ports[i];
- if (up->iobase || up->mapbase)
- uart_remove_one_port(&serial_txx9_reg, up);
+ serial_txx9_unregister_port(i);
}
uart_unregister_driver(&serial_txx9_reg);
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 92193eb26abf..bd58bbfa65aa 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -1495,7 +1495,7 @@ static void sci_dma_rx_release(struct sci_port *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],
+ dma_free_coherent(dmaengine_get_dma_device(chan), s->buf_len_rx * 2, s->rx_buf[0],
sg_dma_address(&s->sg_rx[0]));
dma_release_channel(chan);
}
@@ -1591,7 +1591,7 @@ static void sci_dma_tx_release(struct sci_port *s)
s->chan_tx_saved = s->chan_tx = NULL;
s->cookie_tx = -EINVAL;
dmaengine_terminate_sync(chan);
- dma_unmap_single(chan->device->dev, s->tx_dma_addr, UART_XMIT_SIZE,
+ dma_unmap_single(dmaengine_get_dma_device(chan), s->tx_dma_addr, UART_XMIT_SIZE,
DMA_TO_DEVICE);
dma_release_channel(chan);
}
@@ -1676,7 +1676,7 @@ static void sci_dma_tx_work_fn(struct work_struct *work)
goto switch_to_pio;
}
- dma_sync_single_for_device(chan->device->dev, buf, s->tx_dma_len,
+ dma_sync_single_for_device(dmaengine_get_dma_device(chan), buf, s->tx_dma_len,
DMA_TO_DEVICE);
desc->callback = sci_dma_tx_complete;
@@ -1832,12 +1832,13 @@ static void sci_request_dma(struct uart_port *port)
chan = sci_request_dma_chan(port, DMA_MEM_TO_DEV);
dev_dbg(port->dev, "%s: TX: got channel %p\n", __func__, chan);
if (chan) {
+ struct device *dma_dev = dmaengine_get_dma_device(chan);
/* UART circular tx buffer is an aligned page. */
- s->tx_dma_addr = dma_map_single(chan->device->dev,
+ s->tx_dma_addr = dma_map_single(dma_dev,
tport->xmit_buf,
UART_XMIT_SIZE,
DMA_TO_DEVICE);
- if (dma_mapping_error(chan->device->dev, s->tx_dma_addr)) {
+ if (dma_mapping_error(dma_dev, s->tx_dma_addr)) {
dev_warn(port->dev, "Failed mapping Tx DMA descriptor\n");
dma_release_channel(chan);
} else {
@@ -1853,12 +1854,13 @@ static void sci_request_dma(struct uart_port *port)
chan = sci_request_dma_chan(port, DMA_DEV_TO_MEM);
dev_dbg(port->dev, "%s: RX: got channel %p\n", __func__, chan);
if (chan) {
+ struct device *dma_dev = dmaengine_get_dma_device(chan);
unsigned int i;
dma_addr_t dma;
void *buf;
s->buf_len_rx = 2 * max_t(size_t, 16, port->fifosize);
- buf = dma_alloc_coherent(chan->device->dev, s->buf_len_rx * 2,
+ buf = dma_alloc_coherent(dma_dev, s->buf_len_rx * 2,
&dma, GFP_KERNEL);
if (!buf) {
dev_warn(port->dev,
@@ -3937,12 +3939,12 @@ static int sci_probe(struct platform_device *dev)
if (sp->port.fifosize > 1) {
ret = device_create_file(&dev->dev, &dev_attr_rx_fifo_trigger);
if (ret)
- return ret;
+ goto err_remove_port;
ret = device_create_file(&dev->dev, &dev_attr_rx_fifo_timeout);
if (ret) {
device_remove_file(&dev->dev, &dev_attr_rx_fifo_trigger);
- return ret;
+ goto err_remove_port;
}
}
@@ -3952,6 +3954,10 @@ static int sci_probe(struct platform_device *dev)
sci_ports_in_use |= BIT(dev_id);
return 0;
+
+err_remove_port:
+ uart_remove_one_port(&sci_uart_driver, &sp->port);
+ return ret;
}
static int sci_suspend(struct device *dev)
diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c
index f615701fceb7..c720e9888416 100644
--- a/drivers/tty/serial/sifive.c
+++ b/drivers/tty/serial/sifive.c
@@ -999,7 +999,7 @@ static int sifive_serial_probe(struct platform_device *pdev)
}
#ifdef CONFIG_SERIAL_SIFIVE_CONSOLE
- if (id > SIFIVE_SERIAL_MAX_PORTS) {
+ if (id >= SIFIVE_SERIAL_MAX_PORTS) {
dev_err(&pdev->dev, "too many UARTs (%d)\n", id);
return -EINVAL;
}
diff --git a/drivers/tty/serial/tegra-tcu.c b/drivers/tty/serial/tegra-tcu.c
index 7033dbfe8ba1..077023ce1842 100644
--- a/drivers/tty/serial/tegra-tcu.c
+++ b/drivers/tty/serial/tegra-tcu.c
@@ -179,9 +179,10 @@ static int tegra_tcu_probe(struct platform_device *pdev)
{
struct uart_port *port;
struct tegra_tcu *tcu;
+ struct device *dev = &pdev->dev;
int err;
- tcu = devm_kzalloc(&pdev->dev, sizeof(*tcu), GFP_KERNEL);
+ tcu = devm_kzalloc(dev, sizeof(*tcu), GFP_KERNEL);
if (!tcu)
return -ENOMEM;
@@ -190,11 +191,9 @@ static int tegra_tcu_probe(struct platform_device *pdev)
tcu->rx_client.rx_callback = tegra_tcu_receive;
tcu->tx = mbox_request_channel_byname(&tcu->tx_client, "tx");
- if (IS_ERR(tcu->tx)) {
- err = PTR_ERR(tcu->tx);
- dev_err(&pdev->dev, "failed to get tx mailbox: %d\n", err);
- return err;
- }
+ if (IS_ERR(tcu->tx))
+ return dev_err_probe(dev, PTR_ERR(tcu->tx),
+ "failed to get tx mailbox\n");
#if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE)
/* setup the console */
@@ -218,15 +217,14 @@ static int tegra_tcu_probe(struct platform_device *pdev)
err = uart_register_driver(&tcu->driver);
if (err) {
- dev_err(&pdev->dev, "failed to register UART driver: %d\n",
- err);
+ dev_err_probe(dev, err, "failed to register UART driver\n");
goto free_tx;
}
/* setup the port */
port = &tcu->port;
spin_lock_init(&port->lock);
- port->dev = &pdev->dev;
+ port->dev = dev;
port->type = PORT_TEGRA_TCU;
port->ops = &tegra_tcu_uart_ops;
port->fifosize = 1;
@@ -236,7 +234,7 @@ static int tegra_tcu_probe(struct platform_device *pdev)
err = uart_add_one_port(&tcu->driver, port);
if (err) {
- dev_err(&pdev->dev, "failed to add UART port: %d\n", err);
+ dev_err_probe(dev, err, "failed to add UART port\n");
goto unregister_uart;
}
@@ -246,8 +244,8 @@ static int tegra_tcu_probe(struct platform_device *pdev)
*/
tcu->rx = mbox_request_channel_byname(&tcu->rx_client, "rx");
if (IS_ERR(tcu->rx)) {
- err = PTR_ERR(tcu->rx);
- dev_err(&pdev->dev, "failed to get rx mailbox: %d\n", err);
+ err = dev_err_probe(dev, PTR_ERR(tcu->rx),
+ "failed to get rx mailbox\n");
goto remove_uart_port;
}
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index c2e4b31b699a..f4571d05b496 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -911,10 +911,7 @@ static bool sysrq_handle_keypress(struct sysrq_state *sysrq,
* keyboard state so we can release keys that have been
* pressed before entering SysRq mode.
*/
- if (value)
- set_bit(code, sysrq->key_down);
- else
- clear_bit(code, sysrq->key_down);
+ assign_bit(code, sysrq->key_down, value);
if (was_active)
schedule_work(&sysrq->reinject_work);
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index b22ff9eb7778..4ca4796d1309 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -240,13 +240,13 @@ EXPORT_SYMBOL_GPL(tty_port_unregister_device);
int tty_port_alloc_xmit_buf(struct tty_port *port)
{
- /* We may sleep in get_zeroed_page() */
+ /* We may sleep in kzalloc() */
guard(mutex)(&port->buf_mutex);
if (port->xmit_buf)
return 0;
- port->xmit_buf = (u8 *)get_zeroed_page(GFP_KERNEL);
+ port->xmit_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (port->xmit_buf == NULL)
return -ENOMEM;
@@ -259,7 +259,7 @@ EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
void tty_port_free_xmit_buf(struct tty_port *port)
{
guard(mutex)(&port->buf_mutex);
- free_page((unsigned long)port->xmit_buf);
+ kfree(port->xmit_buf);
port->xmit_buf = NULL;
INIT_KFIFO(port->xmit_fifo);
}
@@ -288,7 +288,7 @@ static void tty_port_destructor(struct kref *kref)
/* check if last port ref was dropped before tty release */
if (WARN_ON(port->itty))
return;
- free_page((unsigned long)port->xmit_buf);
+ kfree(port->xmit_buf);
tty_port_destroy(port);
if (port->ops && port->ops->destruct)
port->ops->destruct(port);
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index c41d850b29c6..ef4a19aeb3ce 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -2002,7 +2002,9 @@ static int vt_kdskbent(unsigned char kbdmode, unsigned char idx,
return 0;
#endif
- unsigned short __free(kfree) *new_map = kmalloc(sizeof(plain_map), GFP_KERNEL);
+ unsigned short __free(kfree) *new_map =
+ kmalloc_array(ARRAY_SIZE(plain_map), sizeof(*new_map),
+ GFP_KERNEL);
if (!new_map)
return -ENOMEM;
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
index eeb868e93e15..d91c0477be9d 100644
--- a/include/linux/serial_8250.h
+++ b/include/linux/serial_8250.h
@@ -186,10 +186,10 @@ static inline struct uart_8250_port *up_to_u8250p(struct uart_port *up)
return container_of(up, struct uart_8250_port, port);
}
-int serial8250_register_8250_port(const struct uart_8250_port *);
-void serial8250_unregister_port(int line);
-void serial8250_suspend_port(int line);
-void serial8250_resume_port(int line);
+struct uart_8250_port *serial8250_register_8250_port(const struct uart_8250_port *);
+void serial8250_unregister_port(struct uart_8250_port *);
+void serial8250_suspend_port(struct uart_8250_port *);
+void serial8250_resume_port(struct uart_8250_port *);
int early_serial_setup(struct uart_port *port);
int early_serial8250_setup(struct earlycon_device *device, const char *options);
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 904760876ca8..4eeb8253752a 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -1140,8 +1140,6 @@ int uart_add_one_port(struct uart_driver *reg, struct uart_port *port);
void uart_remove_one_port(struct uart_driver *reg, struct uart_port *port);
int uart_read_port_properties(struct uart_port *port);
int uart_read_and_validate_port_properties(struct uart_port *port);
-bool uart_match_port(const struct uart_port *port1,
- const struct uart_port *port2);
/*
* Power Management
diff --git a/include/linux/soc/qcom/geni-se.h b/include/linux/soc/qcom/geni-se.h
index 645609b57df8..b3372a3147a0 100644
--- a/include/linux/soc/qcom/geni-se.h
+++ b/include/linux/soc/qcom/geni-se.h
@@ -347,12 +347,18 @@ struct geni_se {
#define QUP_SE_VERSION_2_5 0x20050000
/*
- * QUP Core 2X clock votes used by GENI clients through the "qup-core" ICC
- * path. Values are in Bps and must be converted with Bps_to_icc() before
- * setting avg_bw.
+ * ICC bandwidth values in Bps for the GENI_TO_CORE ("qup-core") path.
+ * Convert them with Bps_to_icc() before setting avg_bw. The QUP ICC provider
+ * maps each threshold to the Core 2X rate named by the macro suffix.
+ *
+ * These values are core clock votes, not GENI transfer bandwidths.
*/
#define CORE_2X_19_2_MHZ 9600000
#define CORE_2X_50_MHZ 25000000
+#define CORE_2X_100_MHZ 50000000
+#define CORE_2X_150_MHZ 75000000
+#define CORE_2X_200_MHZ 100000000
+#define CORE_2X_236_MHZ 118000000
#define GENI_DEFAULT_BW Bps_to_icc(1000)