diff options
| author | Mark Brown <broonie@kernel.org> | 2026-10-23 15:56:31 +0100 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2026-10-23 15:56:31 +0100 |
| commit | 51ff321c064a601506fcdb9fd78c7ecdb1f3087f (patch) | |
| tree | 055a04914f3bb47df4c2f658d6742113ec9d91a8 | |
| parent | fa13cfae8561df78a4993460172dc9c2b5fadab6 (diff) | |
| parent | 1184f87e2790e8af9be3116f608d2e86b4792d7d (diff) | |
| download | linux-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
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) |
