diff options
35 files changed, 709 insertions, 452 deletions
diff --git a/Documentation/devicetree/bindings/serial/maxim,max310x.yaml b/Documentation/devicetree/bindings/serial/maxim,max310x.yaml index 889eeaca64a0..e598dda4d13f 100644 --- a/Documentation/devicetree/bindings/serial/maxim,max310x.yaml +++ b/Documentation/devicetree/bindings/serial/maxim,max310x.yaml @@ -9,6 +9,13 @@ title: Maxim MAX310X Advanced Universal Asynchronous Receiver-Transmitter (UART) maintainers: - Hugo Villeneuve <hvilleneuve@dimonoff.com> +description: + The MAX310X is a family of SPI/I2C UARTs with one (max3107, max3108), + two (max3109) or four (max14830) channels. Single-channel parts are + described as a serial node with RS-485 properties on the chip node; + multi-channel parts use one "serial@N" child node per channel, each + carrying its own serial/RS-485 properties. + properties: compatible: enum: @@ -49,8 +56,55 @@ required: allOf: - $ref: /schemas/spi/spi-peripheral-props.yaml# - - $ref: /schemas/serial/serial.yaml# - - $ref: /schemas/serial/rs485.yaml# + + - if: + properties: + compatible: + contains: + enum: + - maxim,max3107 + - maxim,max3108 + then: + allOf: + - $ref: /schemas/serial/serial.yaml# + - $ref: /schemas/serial/rs485.yaml# + + - if: + properties: + compatible: + contains: + enum: + - maxim,max3109 + - maxim,max14830 + then: + properties: + "#address-cells": + const: 1 + "#size-cells": + const: 0 + patternProperties: + "^serial@[0-3]$": + type: object + description: A single UART channel of the chip. + allOf: + - $ref: /schemas/serial/serial.yaml# + - $ref: /schemas/serial/rs485.yaml# + properties: + reg: + description: UART channel number on the chip. + maximum: 3 + required: + - reg + unevaluatedProperties: false + + - if: + properties: + compatible: + contains: + const: maxim,max3109 + then: + patternProperties: + "^serial@[23]$": false unevaluatedProperties: false @@ -70,5 +124,39 @@ examples: interrupts = <7 IRQ_TYPE_LEVEL_LOW>; gpio-controller; #gpio-cells = <2>; + rs485-rts-active-low; + linux,rs485-enabled-at-boot-time; + }; + }; + + - | + #include <dt-bindings/interrupt-controller/irq.h> + spi { + #address-cells = <1>; + #size-cells = <0>; + + serial@0 { + compatible = "maxim,max14830"; + reg = <0>; + spi-max-frequency = <26000000>; + clocks = <&xtal4m>; + clock-names = "xtal"; + interrupt-parent = <&gpio3>; + interrupts = <7 IRQ_TYPE_LEVEL_LOW>; + gpio-controller; + #gpio-cells = <2>; + #address-cells = <1>; + #size-cells = <0>; + + serial@0 { + reg = <0>; + rs485-rts-active-low; + linux,rs485-enabled-at-boot-time; + }; + + serial@2 { + reg = <2>; + rs485-rts-active-low; + }; }; }; diff --git a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml index 49f51b002879..c0d0524458c1 100644 --- a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml +++ b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml @@ -72,6 +72,7 @@ properties: - rockchip,rk3576-uart - rockchip,rk3588-uart - rockchip,rv1103b-uart + - rockchip,rv1106-uart - rockchip,rv1108-uart - rockchip,rv1126-uart - sophgo,sg2044-uart diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 81eaca751541..28af0fd98181 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -443,23 +443,23 @@ static int rs_startup(struct tty_struct *tty, struct serial_state *info) struct tty_port *port = &info->tport; unsigned long flags; int retval=0; - unsigned long page; + void *buffer; - page = get_zeroed_page(GFP_KERNEL); - if (!page) + buffer = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!buffer) return -ENOMEM; local_irq_save(flags); if (tty_port_initialized(port)) { - free_page(page); + kfree(buffer); goto errout; } if (info->xmit.buf) - free_page(page); + kfree(buffer); else - info->xmit.buf = (unsigned char *) page; + info->xmit.buf = buffer; #ifdef SERIAL_DEBUG_OPEN printk("starting up ttys%d ...", info->line); @@ -537,7 +537,7 @@ static void rs_shutdown(struct tty_struct *tty, struct serial_state *info) */ free_irq(IRQ_AMIGA_VERTB, info); - free_page((unsigned long)info->xmit.buf); + kfree(info->xmit.buf); info->xmit.buf = NULL; info->IER = 0; diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c index 16edd71a0d8d..fa723a4ba7b3 100644 --- a/drivers/tty/goldfish.c +++ b/drivers/tty/goldfish.c @@ -17,6 +17,7 @@ #include <linux/mm.h> #include <linux/dma-mapping.h> #include <linux/serial_core.h> +#include <linux/wordpart.h> /* Goldfish tty register's offsets */ #define GOLDFISH_TTY_REG_BYTES_READY 0x04 @@ -37,7 +38,6 @@ struct goldfish_tty { spinlock_t lock; void __iomem *base; u32 irq; - int opencount; struct console console; u32 version; struct device *dev; @@ -49,15 +49,23 @@ static u32 goldfish_tty_line_count = 8; static u32 goldfish_tty_current_line_count; static struct goldfish_tty *goldfish_ttys; +static inline void gf_write_addr(unsigned long addr, void __iomem *portl, void __iomem *porth) +{ + gf_iowrite32(lower_32_bits(addr), portl); +#ifdef CONFIG_64BIT + gf_iowrite32(upper_32_bits(addr), porth); +#endif +} + static void do_rw_io(struct goldfish_tty *qtty, unsigned long address, size_t count, bool is_write) { - unsigned long irq_flags; void __iomem *base = qtty->base; - spin_lock_irqsave(&qtty->lock, irq_flags); - gf_write_ptr((void *)address, base + GOLDFISH_TTY_REG_DATA_PTR, - base + GOLDFISH_TTY_REG_DATA_PTR_HIGH); + guard(spinlock_irqsave)(&qtty->lock); + + gf_write_addr(address, base + GOLDFISH_TTY_REG_DATA_PTR, + base + GOLDFISH_TTY_REG_DATA_PTR_HIGH); gf_iowrite32(count, base + GOLDFISH_TTY_REG_DATA_LEN); if (is_write) @@ -66,8 +74,6 @@ static void do_rw_io(struct goldfish_tty *qtty, unsigned long address, else gf_iowrite32(GOLDFISH_TTY_CMD_READ_BUFFER, base + GOLDFISH_TTY_REG_CMD); - - spin_unlock_irqrestore(&qtty->lock, irq_flags); } static void goldfish_tty_rw(struct goldfish_tty *qtty, unsigned long addr, @@ -409,7 +415,7 @@ static void goldfish_tty_remove(struct platform_device *pdev) { struct goldfish_tty *qtty = platform_get_drvdata(pdev); - mutex_lock(&goldfish_tty_lock); + guard(mutex)(&goldfish_tty_lock); unregister_console(&qtty->console); tty_unregister_device(goldfish_tty_driver, qtty->console.index); @@ -420,7 +426,6 @@ static void goldfish_tty_remove(struct platform_device *pdev) goldfish_tty_current_line_count--; if (goldfish_tty_current_line_count == 0) goldfish_tty_delete_driver(); - mutex_unlock(&goldfish_tty_lock); } #ifdef CONFIG_GOLDFISH_TTY_EARLY_CONSOLE diff --git a/drivers/tty/hvc/Kconfig b/drivers/tty/hvc/Kconfig index c2a4e88b328f..5866195de26a 100644 --- a/drivers/tty/hvc/Kconfig +++ b/drivers/tty/hvc/Kconfig @@ -79,7 +79,7 @@ config HVC_UDBG config HVC_DCC bool "ARM JTAG DCC console" - depends on ARM || ARM64 + depends on (ARM && (CPU_V6 || CPU_V6K || CPU_V7)) || ARM64 select HVC_DRIVER select SERIAL_CORE_CONSOLE help diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index e9d044a331b0..7500efcdfc21 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -651,11 +651,11 @@ static int acpi_serdev_do_lookup(struct acpi_device *adev, INIT_LIST_HEAD(&resource_list); ret = acpi_dev_get_resources(adev, &resource_list, acpi_serdev_parse_resource, lookup); - acpi_dev_free_resource_list(&resource_list); - if (ret < 0) return -EINVAL; + acpi_dev_free_resource_list(&resource_list); + return 0; } diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 77fe0588fd6b..b62f88eec881 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -8,6 +8,7 @@ */ #include <linux/bits.h> +#include <linux/kconfig.h> #include <linux/serial_8250.h> #include <linux/serial_core.h> #include <linux/dmaengine.h> @@ -334,6 +335,13 @@ 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) +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) +{ return false; } +#endif + #ifdef CONFIG_ARCH_OMAP1 #include <linux/soc/ti/omap1-soc.h> static inline int is_omap1_8250(struct uart_8250_port *pt) diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index f49862d90eeb..c0e8a4efbdcc 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -720,8 +720,12 @@ int serial8250_register_8250_port(const struct uart_8250_port *up) /* Preserve specified console flow control. */ cons_flow = uart_cons_flow_enabled(&uart->port); - if (uart->port.dev) + if (uart->port.dev) { + if (uart_console(&uart->port)) + uart->port.cons->flags &= ~CON_PRINTBUFFER; + uart_remove_one_port(&serial8250_reg, &uart->port); + } uart->port.ctrl_id = up->port.ctrl_id; uart->port.port_id = up->port.port_id; diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c index dc0371857ecb..44ec209f37c4 100644 --- a/drivers/tty/serial/8250/8250_early.c +++ b/drivers/tty/serial/8250/8250_early.c @@ -23,6 +23,7 @@ * console=uart8250,mmio32,0xff5e0000,115200n8 */ +#include <linux/align.h> #include <linux/tty.h> #include <linux/init.h> #include <linux/console.h> @@ -177,6 +178,23 @@ OF_EARLYCON_DECLARE(ns16550a, "ns16550a", early_serial8250_setup); OF_EARLYCON_DECLARE(uart, "nvidia,tegra20-uart", early_serial8250_setup); OF_EARLYCON_DECLARE(uart, "snps,dw-apb-uart", early_serial8250_setup); +static int __init early_serial8250_xscale_setup(struct earlycon_device *device, + const char *options) +{ + /* + * Adjust for BE32 register accesses: drop any hardcoded + * address for the big endian byte target, add it explicitly + * if running on BE32. + */ + device->port.membase = PTR_ALIGN_DOWN(device->port.membase, 4); + if (IS_ENABLED(CONFIG_CPU_ENDIAN_BE32)) + device->port.membase += 3; + device->port.regshift = 2; + + return early_serial8250_setup(device, options); +} +OF_EARLYCON_DECLARE(uart, "intel,xscale-uart", early_serial8250_xscale_setup); + static int __init early_serial8250_rs2_setup(struct earlycon_device *device, const char *options) { @@ -184,7 +202,6 @@ static int __init early_serial8250_rs2_setup(struct earlycon_device *device, return early_serial8250_setup(device, options); } -OF_EARLYCON_DECLARE(uart, "intel,xscale-uart", early_serial8250_rs2_setup); OF_EARLYCON_DECLARE(uart, "mrvl,mmp-uart", early_serial8250_rs2_setup); OF_EARLYCON_DECLARE(uart, "mrvl,pxa-uart", early_serial8250_rs2_setup); diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index c682c0d0dffa..f9a14eaa13cb 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -1642,14 +1642,14 @@ static const struct exar8250_board pbn_exar_XR17V8358 = { .exit = pci_xr17v35x_exit, }; -#define CTI_EXAR_DEVICE(devid, bd) { \ - PCI_DEVICE_SUB( \ - PCI_VENDOR_ID_EXAR, \ - PCI_DEVICE_ID_EXAR_##devid, \ - PCI_SUBVENDOR_ID_CONNECT_TECH, \ - PCI_ANY_ID), 0, 0, \ - (kernel_ulong_t)&bd \ - } +#define CTI_EXAR_DEVICE(devid, bd) { \ + PCI_DEVICE_SUB( \ + PCI_VENDOR_ID_EXAR, \ + PCI_DEVICE_ID_EXAR_##devid, \ + PCI_SUBVENDOR_ID_CONNECT_TECH, \ + PCI_ANY_ID), \ + .driver_data = (kernel_ulong_t)&bd \ +} #define EXAR_DEVICE(vend, devid, bd) { PCI_DEVICE_DATA(vend, devid, &bd) } @@ -1658,18 +1658,18 @@ static const struct exar8250_board pbn_exar_XR17V8358 = { PCI_VENDOR_ID_EXAR, \ PCI_DEVICE_ID_EXAR_##devid, \ PCI_SUBVENDOR_ID_IBM, \ - PCI_SUBDEVICE_ID_IBM_##sdevid), 0, 0, \ - (kernel_ulong_t)&bd \ - } + PCI_SUBDEVICE_ID_IBM_##sdevid), \ + .driver_data = (kernel_ulong_t)&bd \ +} #define USR_DEVICE(devid, sdevid, bd) { \ PCI_DEVICE_SUB( \ PCI_VENDOR_ID_USR, \ PCI_DEVICE_ID_EXAR_##devid, \ PCI_VENDOR_ID_EXAR, \ - PCI_SUBDEVICE_ID_USR_##sdevid), 0, 0, \ - (kernel_ulong_t)&bd \ - } + PCI_SUBDEVICE_ID_USR_##sdevid), \ + .driver_data = (kernel_ulong_t)&bd \ +} static const struct pci_device_id exar_pci_tbl[] = { EXAR_DEVICE(ACCESSIO, COM_2S, pbn_exar_XR17C15x), @@ -1726,7 +1726,7 @@ static const struct pci_device_id exar_pci_tbl[] = { EXAR_DEVICE(COMMTECH, 4224PCI335, pbn_fastcom335_4), EXAR_DEVICE(COMMTECH, 2324PCI335, pbn_fastcom335_4), EXAR_DEVICE(COMMTECH, 2328PCI335, pbn_fastcom335_8), - { 0, } + { } }; MODULE_DEVICE_TABLE(pci, exar_pci_tbl); diff --git a/drivers/tty/serial/8250/8250_hub6.c b/drivers/tty/serial/8250/8250_hub6.c index 273f59b9bca5..b6767633c966 100644 --- a/drivers/tty/serial/8250/8250_hub6.c +++ b/drivers/tty/serial/8250/8250_hub6.c @@ -7,6 +7,8 @@ #include <linux/init.h> #include <linux/serial_8250.h> +#include "8250.h" + #define HUB6(card, port) \ { \ .iobase = 0x302, \ @@ -41,6 +43,12 @@ static struct platform_device hub6_device = { }, }; +bool hub6_match_port(const struct uart_port *port1, const struct uart_port *port2) +{ + return port1->iobase == port2->iobase && port1->hub6 == port2->hub6; +} +EXPORT_SYMBOL_GPL(hub6_match_port); + static int __init hub6_init(void) { return platform_device_register(&hub6_device); diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c index 81644d40b09a..f0537fb6ef4f 100644 --- a/drivers/tty/serial/8250/8250_of.c +++ b/drivers/tty/serial/8250/8250_of.c @@ -5,6 +5,7 @@ * Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>, IBM Corp. */ +#include <linux/align.h> #include <linux/bits.h> #include <linux/console.h> #include <linux/math.h> @@ -122,6 +123,17 @@ static int of_platform_serial_setup(struct platform_device *ofdev, if (ret) goto err_pmruntime; + if (IS_ENABLED(CONFIG_CPU_XSCALE) && type == PORT_XSCALE) { + /* + * Adjust for BE32 register accesses: drop any hardcoded + * address for the big endian byte target, add it explicitly + * if running on BE32. + */ + port->mapbase = PTR_ALIGN_DOWN(port->mapbase, 4); + if (IS_ENABLED(CONFIG_CPU_ENDIAN_BE32)) + port->mapbase += 3; + } + /* Get clk rate through clk driver if present */ if (!port->uartclk) { struct clk *bus_clk; diff --git a/drivers/tty/serial/8250/8250_platform.c b/drivers/tty/serial/8250/8250_platform.c index ad3a7bc31d6f..af946d12e764 100644 --- a/drivers/tty/serial/8250/8250_platform.c +++ b/drivers/tty/serial/8250/8250_platform.c @@ -284,6 +284,7 @@ static struct platform_driver serial8250_isa_driver = { .driver = { .name = "serial8250", .acpi_match_table = acpi_platform_serial_table, + .probe_type = PROBE_FORCE_SYNCHRONOUS, }, }; diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c index 7a837fdf9df1..6bfdeff5fe22 100644 --- a/drivers/tty/serial/8250/8250_pnp.c +++ b/drivers/tty/serial/8250/8250_pnp.c @@ -28,351 +28,351 @@ static const struct pnp_device_id pnp_dev_table[] = { /* Archtek America Corp. */ /* Archtek SmartLink Modem 3334BT Plug & Play */ - { "AAC000F", 0 }, + { .id = "AAC000F", .driver_data = 0 }, /* Anchor Datacomm BV */ /* SXPro 144 External Data Fax Modem Plug & Play */ - { "ADC0001", 0 }, + { .id = "ADC0001", .driver_data = 0 }, /* SXPro 288 External Data Fax Modem Plug & Play */ - { "ADC0002", 0 }, + { .id = "ADC0002", .driver_data = 0 }, /* PROLiNK 1456VH ISA PnP K56flex Fax Modem */ - { "AEI0250", 0 }, + { .id = "AEI0250", .driver_data = 0 }, /* Actiontec ISA PNP 56K X2 Fax Modem */ - { "AEI1240", 0 }, + { .id = "AEI1240", .driver_data = 0 }, /* Rockwell 56K ACF II Fax+Data+Voice Modem */ - { "AKY1021", 0 /*SPCI_FL_NO_SHIRQ*/ }, + { .id ="AKY1021", .driver_data = 0 /*SPCI_FL_NO_SHIRQ*/ }, /* * ALi Fast Infrared Controller * Native driver (ali-ircc) is broken so at least * it can be used with irtty-sir. */ - { "ALI5123", 0 }, + { .id = "ALI5123", .driver_data = 0 }, /* AZT3005 PnP SOUND DEVICE */ - { "AZT4001", 0 }, + { .id = "AZT4001", .driver_data = 0 }, /* Best Data Products Inc. Smart One 336F PnP Modem */ - { "BDP3336", 0 }, + { .id = "BDP3336", .driver_data = 0 }, /* Boca Research */ /* Boca Complete Ofc Communicator 14.4 Data-FAX */ - { "BRI0A49", 0 }, + { .id = "BRI0A49", .driver_data = 0 }, /* Boca Research 33,600 ACF Modem */ - { "BRI1400", 0 }, + { .id = "BRI1400", .driver_data = 0 }, /* Boca 33.6 Kbps Internal FD34FSVD */ - { "BRI3400", 0 }, + { .id = "BRI3400", .driver_data = 0 }, /* Computer Peripherals Inc */ /* EuroViVa CommCenter-33.6 SP PnP */ - { "CPI4050", 0 }, + { .id = "CPI4050", .driver_data = 0 }, /* Creative Labs */ /* Creative Labs Phone Blaster 28.8 DSVD PnP Voice */ - { "CTL3001", 0 }, + { .id = "CTL3001", .driver_data = 0 }, /* Creative Labs Modem Blaster 28.8 DSVD PnP Voice */ - { "CTL3011", 0 }, + { .id = "CTL3011", .driver_data = 0 }, /* Davicom ISA 33.6K Modem */ - { "DAV0336", 0 }, + { .id = "DAV0336", .driver_data = 0 }, /* Creative */ /* Creative Modem Blaster Flash56 DI5601-1 */ - { "DMB1032", 0 }, + { .id = "DMB1032", .driver_data = 0 }, /* Creative Modem Blaster V.90 DI5660 */ - { "DMB2001", 0 }, + { .id = "DMB2001", .driver_data = 0 }, /* E-Tech */ /* E-Tech CyberBULLET PC56RVP */ - { "ETT0002", 0 }, + { .id = "ETT0002", .driver_data = 0 }, /* FUJITSU */ /* Fujitsu 33600 PnP-I2 R Plug & Play */ - { "FUJ0202", 0 }, + { .id = "FUJ0202", .driver_data = 0 }, /* Fujitsu FMV-FX431 Plug & Play */ - { "FUJ0205", 0 }, + { .id = "FUJ0205", .driver_data = 0 }, /* Fujitsu 33600 PnP-I4 R Plug & Play */ - { "FUJ0206", 0 }, + { .id = "FUJ0206", .driver_data = 0 }, /* Fujitsu Fax Voice 33600 PNP-I5 R Plug & Play */ - { "FUJ0209", 0 }, + { .id = "FUJ0209", .driver_data = 0 }, /* Archtek America Corp. */ /* Archtek SmartLink Modem 3334BT Plug & Play */ - { "GVC000F", 0 }, + { .id = "GVC000F", .driver_data = 0 }, /* Archtek SmartLink Modem 3334BRV 33.6K Data Fax Voice */ - { "GVC0303", 0 }, + { .id = "GVC0303", .driver_data = 0 }, /* Hayes */ /* Hayes Optima 288 V.34-V.FC + FAX + Voice Plug & Play */ - { "HAY0001", 0 }, + { .id = "HAY0001", .driver_data = 0 }, /* Hayes Optima 336 V.34 + FAX + Voice PnP */ - { "HAY000C", 0 }, + { .id = "HAY000C", .driver_data = 0 }, /* Hayes Optima 336B V.34 + FAX + Voice PnP */ - { "HAY000D", 0 }, + { .id = "HAY000D", .driver_data = 0 }, /* Hayes Accura 56K Ext Fax Modem PnP */ - { "HAY5670", 0 }, + { .id = "HAY5670", .driver_data = 0 }, /* Hayes Accura 56K Ext Fax Modem PnP */ - { "HAY5674", 0 }, + { .id = "HAY5674", .driver_data = 0 }, /* Hayes Accura 56K Fax Modem PnP */ - { "HAY5675", 0 }, + { .id = "HAY5675", .driver_data = 0 }, /* Hayes 288, V.34 + FAX */ - { "HAYF000", 0 }, + { .id = "HAYF000", .driver_data = 0 }, /* Hayes Optima 288 V.34 + FAX + Voice, Plug & Play */ - { "HAYF001", 0 }, + { .id = "HAYF001", .driver_data = 0 }, /* IBM */ /* IBM Thinkpad 701 Internal Modem Voice */ - { "IBM0033", 0 }, + { .id = "IBM0033", .driver_data = 0 }, /* Intermec */ /* Intermec CV60 touchscreen port */ - { "PNP4972", 0 }, + { .id = "PNP4972", .driver_data = 0 }, /* Intertex */ /* Intertex 28k8 33k6 Voice EXT PnP */ - { "IXDC801", 0 }, + { .id = "IXDC801", .driver_data = 0 }, /* Intertex 33k6 56k Voice EXT PnP */ - { "IXDC901", 0 }, + { .id = "IXDC901", .driver_data = 0 }, /* Intertex 28k8 33k6 Voice SP EXT PnP */ - { "IXDD801", 0 }, + { .id = "IXDD801", .driver_data = 0 }, /* Intertex 33k6 56k Voice SP EXT PnP */ - { "IXDD901", 0 }, + { .id = "IXDD901", .driver_data = 0 }, /* Intertex 28k8 33k6 Voice SP INT PnP */ - { "IXDF401", 0 }, + { .id = "IXDF401", .driver_data = 0 }, /* Intertex 28k8 33k6 Voice SP EXT PnP */ - { "IXDF801", 0 }, + { .id = "IXDF801", .driver_data = 0 }, /* Intertex 33k6 56k Voice SP EXT PnP */ - { "IXDF901", 0 }, + { .id = "IXDF901", .driver_data = 0 }, /* Kortex International */ /* KORTEX 28800 Externe PnP */ - { "KOR4522", 0 }, + { .id = "KOR4522", .driver_data = 0 }, /* KXPro 33.6 Vocal ASVD PnP */ - { "KORF661", 0 }, + { .id = "KORF661", .driver_data = 0 }, /* Lasat */ /* LASAT Internet 33600 PnP */ - { "LAS4040", 0 }, + { .id = "LAS4040", .driver_data = 0 }, /* Lasat Safire 560 PnP */ - { "LAS4540", 0 }, + { .id = "LAS4540", .driver_data = 0 }, /* Lasat Safire 336 PnP */ - { "LAS5440", 0 }, + { .id = "LAS5440", .driver_data = 0 }, /* Microcom, Inc. */ /* Microcom TravelPorte FAST V.34 Plug & Play */ - { "MNP0281", 0 }, + { .id = "MNP0281", .driver_data = 0 }, /* Microcom DeskPorte V.34 FAST or FAST+ Plug & Play */ - { "MNP0336", 0 }, + { .id = "MNP0336", .driver_data = 0 }, /* Microcom DeskPorte FAST EP 28.8 Plug & Play */ - { "MNP0339", 0 }, + { .id = "MNP0339", .driver_data = 0 }, /* Microcom DeskPorte 28.8P Plug & Play */ - { "MNP0342", 0 }, + { .id = "MNP0342", .driver_data = 0 }, /* Microcom DeskPorte FAST ES 28.8 Plug & Play */ - { "MNP0500", 0 }, + { .id = "MNP0500", .driver_data = 0 }, /* Microcom DeskPorte FAST ES 28.8 Plug & Play */ - { "MNP0501", 0 }, + { .id = "MNP0501", .driver_data = 0 }, /* Microcom DeskPorte 28.8S Internal Plug & Play */ - { "MNP0502", 0 }, + { .id = "MNP0502", .driver_data = 0 }, /* Motorola */ /* Motorola BitSURFR Plug & Play */ - { "MOT1105", 0 }, + { .id = "MOT1105", .driver_data = 0 }, /* Motorola TA210 Plug & Play */ - { "MOT1111", 0 }, + { .id = "MOT1111", .driver_data = 0 }, /* Motorola HMTA 200 (ISDN) Plug & Play */ - { "MOT1114", 0 }, + { .id = "MOT1114", .driver_data = 0 }, /* Motorola BitSURFR Plug & Play */ - { "MOT1115", 0 }, + { .id = "MOT1115", .driver_data = 0 }, /* Motorola Lifestyle 28.8 Internal */ - { "MOT1190", 0 }, + { .id = "MOT1190", .driver_data = 0 }, /* Motorola V.3400 Plug & Play */ - { "MOT1501", 0 }, + { .id = "MOT1501", .driver_data = 0 }, /* Motorola Lifestyle 28.8 V.34 Plug & Play */ - { "MOT1502", 0 }, + { .id = "MOT1502", .driver_data = 0 }, /* Motorola Power 28.8 V.34 Plug & Play */ - { "MOT1505", 0 }, + { .id = "MOT1505", .driver_data = 0 }, /* Motorola ModemSURFR External 28.8 Plug & Play */ - { "MOT1509", 0 }, + { .id = "MOT1509", .driver_data = 0 }, /* Motorola Premier 33.6 Desktop Plug & Play */ - { "MOT150A", 0 }, + { .id = "MOT150A", .driver_data = 0 }, /* Motorola VoiceSURFR 56K External PnP */ - { "MOT150F", 0 }, + { .id = "MOT150F", .driver_data = 0 }, /* Motorola ModemSURFR 56K External PnP */ - { "MOT1510", 0 }, + { .id = "MOT1510", .driver_data = 0 }, /* Motorola ModemSURFR 56K Internal PnP */ - { "MOT1550", 0 }, + { .id = "MOT1550", .driver_data = 0 }, /* Motorola ModemSURFR Internal 28.8 Plug & Play */ - { "MOT1560", 0 }, + { .id = "MOT1560", .driver_data = 0 }, /* Motorola Premier 33.6 Internal Plug & Play */ - { "MOT1580", 0 }, + { .id = "MOT1580", .driver_data = 0 }, /* Motorola OnlineSURFR 28.8 Internal Plug & Play */ - { "MOT15B0", 0 }, + { .id = "MOT15B0", .driver_data = 0 }, /* Motorola VoiceSURFR 56K Internal PnP */ - { "MOT15F0", 0 }, + { .id = "MOT15F0", .driver_data = 0 }, /* Com 1 */ /* Deskline K56 Phone System PnP */ - { "MVX00A1", 0 }, + { .id = "MVX00A1", .driver_data = 0 }, /* PC Rider K56 Phone System PnP */ - { "MVX00F2", 0 }, + { .id = "MVX00F2", .driver_data = 0 }, /* NEC 98NOTE SPEAKER PHONE FAX MODEM(33600bps) */ - { "nEC8241", 0 }, + { .id = "nEC8241", .driver_data = 0 }, /* Pace 56 Voice Internal Plug & Play Modem */ - { "PMC2430", 0 }, + { .id = "PMC2430", .driver_data = 0 }, /* Generic */ /* Generic standard PC COM port */ - { "PNP0500", 0 }, + { .id = "PNP0500", .driver_data = 0 }, /* Generic 16550A-compatible COM port */ - { "PNP0501", 0 }, + { .id = "PNP0501", .driver_data = 0 }, /* Compaq 14400 Modem */ - { "PNPC000", 0 }, + { .id = "PNPC000", .driver_data = 0 }, /* Compaq 2400/9600 Modem */ - { "PNPC001", 0 }, + { .id = "PNPC001", .driver_data = 0 }, /* Dial-Up Networking Serial Cable between 2 PCs */ - { "PNPC031", 0 }, + { .id = "PNPC031", .driver_data = 0 }, /* Dial-Up Networking Parallel Cable between 2 PCs */ - { "PNPC032", 0 }, + { .id = "PNPC032", .driver_data = 0 }, /* Standard 9600 bps Modem */ - { "PNPC100", 0 }, + { .id = "PNPC100", .driver_data = 0 }, /* Standard 14400 bps Modem */ - { "PNPC101", 0 }, + { .id = "PNPC101", .driver_data = 0 }, /* Standard 28800 bps Modem*/ - { "PNPC102", 0 }, + { .id = "PNPC102", .driver_data = 0 }, /* Standard Modem*/ - { "PNPC103", 0 }, + { .id = "PNPC103", .driver_data = 0 }, /* Standard 9600 bps Modem*/ - { "PNPC104", 0 }, + { .id = "PNPC104", .driver_data = 0 }, /* Standard 14400 bps Modem*/ - { "PNPC105", 0 }, + { .id = "PNPC105", .driver_data = 0 }, /* Standard 28800 bps Modem*/ - { "PNPC106", 0 }, + { .id = "PNPC106", .driver_data = 0 }, /* Standard Modem */ - { "PNPC107", 0 }, + { .id = "PNPC107", .driver_data = 0 }, /* Standard 9600 bps Modem */ - { "PNPC108", 0 }, + { .id = "PNPC108", .driver_data = 0 }, /* Standard 14400 bps Modem */ - { "PNPC109", 0 }, + { .id = "PNPC109", .driver_data = 0 }, /* Standard 28800 bps Modem */ - { "PNPC10A", 0 }, + { .id = "PNPC10A", .driver_data = 0 }, /* Standard Modem */ - { "PNPC10B", 0 }, + { .id = "PNPC10B", .driver_data = 0 }, /* Standard 9600 bps Modem */ - { "PNPC10C", 0 }, + { .id = "PNPC10C", .driver_data = 0 }, /* Standard 14400 bps Modem */ - { "PNPC10D", 0 }, + { .id = "PNPC10D", .driver_data = 0 }, /* Standard 28800 bps Modem */ - { "PNPC10E", 0 }, + { .id = "PNPC10E", .driver_data = 0 }, /* Standard Modem */ - { "PNPC10F", 0 }, + { .id = "PNPC10F", .driver_data = 0 }, /* Standard PCMCIA Card Modem */ - { "PNP2000", 0 }, + { .id = "PNP2000", .driver_data = 0 }, /* Rockwell */ /* Modular Technology */ /* Rockwell 33.6 DPF Internal PnP */ /* Modular Technology 33.6 Internal PnP */ - { "ROK0030", 0 }, + { .id = "ROK0030", .driver_data = 0 }, /* Kortex International */ /* KORTEX 14400 Externe PnP */ - { "ROK0100", 0 }, + { .id = "ROK0100", .driver_data = 0 }, /* Rockwell 28.8 */ - { "ROK4120", 0 }, + { .id = "ROK4120", .driver_data = 0 }, /* Viking Components, Inc */ /* Viking 28.8 INTERNAL Fax+Data+Voice PnP */ - { "ROK4920", 0 }, + { .id = "ROK4920", .driver_data = 0 }, /* Rockwell */ /* British Telecom */ /* Modular Technology */ /* Rockwell 33.6 DPF External PnP */ /* BT Prologue 33.6 External PnP */ /* Modular Technology 33.6 External PnP */ - { "RSS00A0", 0 }, + { .id = "RSS00A0", .driver_data = 0 }, /* Viking 56K FAX INT */ - { "RSS0262", 0 }, + { .id = "RSS0262", .driver_data = 0 }, /* K56 par,VV,Voice,Speakphone,AudioSpan,PnP */ - { "RSS0250", 0 }, + { .id = "RSS0250", .driver_data = 0 }, /* SupraExpress 28.8 Data/Fax PnP modem */ - { "SUP1310", 0 }, + { .id = "SUP1310", .driver_data = 0 }, /* SupraExpress 336i PnP Voice Modem */ - { "SUP1381", 0 }, + { .id = "SUP1381", .driver_data = 0 }, /* SupraExpress 33.6 Data/Fax PnP modem */ - { "SUP1421", 0 }, + { .id = "SUP1421", .driver_data = 0 }, /* SupraExpress 33.6 Data/Fax PnP modem */ - { "SUP1590", 0 }, + { .id = "SUP1590", .driver_data = 0 }, /* SupraExpress 336i Sp ASVD */ - { "SUP1620", 0 }, + { .id = "SUP1620", .driver_data = 0 }, /* SupraExpress 33.6 Data/Fax PnP modem */ - { "SUP1760", 0 }, + { .id = "SUP1760", .driver_data = 0 }, /* SupraExpress 56i Sp Intl */ - { "SUP2171", 0 }, + { .id = "SUP2171", .driver_data = 0 }, /* Phoebe Micro */ /* Phoebe Micro 33.6 Data Fax 1433VQH Plug & Play */ - { "TEX0011", 0 }, + { .id = "TEX0011", .driver_data = 0 }, /* Archtek America Corp. */ /* Archtek SmartLink Modem 3334BT Plug & Play */ - { "UAC000F", 0 }, + { .id = "UAC000F", .driver_data = 0 }, /* 3Com Corp. */ /* Gateway Telepath IIvi 33.6 */ - { "USR0000", 0 }, + { .id = "USR0000", .driver_data = 0 }, /* U.S. Robotics Sporster 33.6K Fax INT PnP */ - { "USR0002", 0 }, + { .id = "USR0002", .driver_data = 0 }, /* Sportster Vi 14.4 PnP FAX Voicemail */ - { "USR0004", 0 }, + { .id = "USR0004", .driver_data = 0 }, /* U.S. Robotics 33.6K Voice INT PnP */ - { "USR0006", 0 }, + { .id = "USR0006", .driver_data = 0 }, /* U.S. Robotics 33.6K Voice EXT PnP */ - { "USR0007", 0 }, + { .id = "USR0007", .driver_data = 0 }, /* U.S. Robotics Courier V.Everything INT PnP */ - { "USR0009", 0 }, + { .id = "USR0009", .driver_data = 0 }, /* U.S. Robotics 33.6K Voice INT PnP */ - { "USR2002", 0 }, + { .id = "USR2002", .driver_data = 0 }, /* U.S. Robotics 56K Voice INT PnP */ - { "USR2070", 0 }, + { .id = "USR2070", .driver_data = 0 }, /* U.S. Robotics 56K Voice EXT PnP */ - { "USR2080", 0 }, + { .id = "USR2080", .driver_data = 0 }, /* U.S. Robotics 56K FAX INT */ - { "USR3031", 0 }, + { .id = "USR3031", .driver_data = 0 }, /* U.S. Robotics 56K FAX INT */ - { "USR3050", 0 }, + { .id = "USR3050", .driver_data = 0 }, /* U.S. Robotics 56K Voice INT PnP */ - { "USR3070", 0 }, + { .id = "USR3070", .driver_data = 0 }, /* U.S. Robotics 56K Voice EXT PnP */ - { "USR3080", 0 }, + { .id = "USR3080", .driver_data = 0 }, /* U.S. Robotics 56K Voice INT PnP */ - { "USR3090", 0 }, + { .id = "USR3090", .driver_data = 0 }, /* U.S. Robotics 56K Message */ - { "USR9100", 0 }, + { .id = "USR9100", .driver_data = 0 }, /* U.S. Robotics 56K FAX EXT PnP*/ - { "USR9160", 0 }, + { .id = "USR9160", .driver_data = 0 }, /* U.S. Robotics 56K FAX INT PnP*/ - { "USR9170", 0 }, + { .id = "USR9170", .driver_data = 0 }, /* U.S. Robotics 56K Voice EXT PnP*/ - { "USR9180", 0 }, + { .id = "USR9180", .driver_data = 0 }, /* U.S. Robotics 56K Voice INT PnP*/ - { "USR9190", 0 }, + { .id = "USR9190", .driver_data = 0 }, /* Wacom tablets */ - { "WACFXXX", 0 }, + { .id = "WACFXXX", .driver_data = 0 }, /* Compaq touchscreen */ - { "FPI2002", 0 }, + { .id = "FPI2002", .driver_data = 0 }, /* Fujitsu Stylistic touchscreens */ - { "FUJ02B2", 0 }, - { "FUJ02B3", 0 }, + { .id = "FUJ02B2", .driver_data = 0 }, + { .id = "FUJ02B3", .driver_data = 0 }, /* Fujitsu Stylistic LT touchscreens */ - { "FUJ02B4", 0 }, + { .id = "FUJ02B4", .driver_data = 0 }, /* Passive Fujitsu Stylistic touchscreens */ - { "FUJ02B6", 0 }, - { "FUJ02B7", 0 }, - { "FUJ02B8", 0 }, - { "FUJ02B9", 0 }, - { "FUJ02BC", 0 }, + { .id = "FUJ02B6", .driver_data = 0 }, + { .id = "FUJ02B7", .driver_data = 0 }, + { .id = "FUJ02B8", .driver_data = 0 }, + { .id = "FUJ02B9", .driver_data = 0 }, + { .id = "FUJ02BC", .driver_data = 0 }, /* Fujitsu Wacom Tablet PC device */ - { "FUJ02E5", 0 }, + { .id = "FUJ02E5", .driver_data = 0 }, /* Fujitsu P-series tablet PC device */ - { "FUJ02E6", 0 }, + { .id = "FUJ02E6", .driver_data = 0 }, /* Fujitsu Wacom 2FGT Tablet PC device */ - { "FUJ02E7", 0 }, + { .id = "FUJ02E7", .driver_data = 0 }, /* Fujitsu Wacom 1FGT Tablet PC device */ - { "FUJ02E9", 0 }, + { .id = "FUJ02E9", .driver_data = 0 }, /* * LG C1 EXPRESS DUAL (C1-PB11A3) touch screen (actually a FUJ02E6 * in disguise). */ - { "LTS0001", 0 }, + { .id = "LTS0001", .driver_data = 0 }, /* Rockwell's (PORALiNK) 33600 INT PNP */ - { "WCI0003", 0 }, + { .id = "WCI0003", .driver_data = 0 }, /* Unknown PnP modems */ - { "PNPCXXX", UNKNOWN_DEV }, + { .id = "PNPCXXX", .driver_data = UNKNOWN_DEV }, /* More unknown PnP modems */ - { "PNPDXXX", UNKNOWN_DEV }, + { .id = "PNPDXXX", .driver_data = UNKNOWN_DEV }, /* * Winbond CIR port, should not be probed. We should keep track of * it to prevent the legacy serial driver from probing it. */ - { "WEC1022", CIR_PORT }, + { .id = "WEC1022", .driver_data = CIR_PORT }, /* * SMSC IrCC SIR/FIR port, should not be probed by serial driver as * well so its own driver can bind to it. */ - { "SMCF010", CIR_PORT }, - { "", 0 } + { .id = "SMCF010", .driver_data = CIR_PORT }, + { } }; MODULE_DEVICE_TABLE(pnp, pnp_dev_table); @@ -521,6 +521,7 @@ static struct pnp_driver serial_pnp_driver = { .remove = serial_pnp_remove, .driver = { .pm = pm_sleep_ptr(&serial_pnp_pm_ops), + .probe_type = PROBE_FORCE_SYNCHRONOUS, }, .id_table = pnp_dev_table, }; diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index e94a0802cbdd..8c241ec7f4f2 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -474,16 +474,10 @@ static void set_io_from_upio(struct uart_port *p) static void serial_port_out_sync(struct uart_port *p, int offset, int value) { - switch (p->iotype) { - case UPIO_MEM: - case UPIO_MEM16: - case UPIO_MEM32: - case UPIO_MEM32BE: - case UPIO_AU: + if (uart_iotype_mmio(p->iotype)) { p->serial_out(p, offset, value); p->serial_in(p, UART_LCR); /* safe, no side-effects */ - break; - default: + } else { p->serial_out(p, offset, value); } } @@ -2891,13 +2885,7 @@ static int serial8250_request_std_resource(struct uart_8250_port *up) unsigned int size = serial8250_port_size(up); struct uart_port *port = &up->port; - switch (port->iotype) { - case UPIO_AU: - case UPIO_TSI: - case UPIO_MEM32: - case UPIO_MEM32BE: - case UPIO_MEM16: - case UPIO_MEM: + if (uart_iotype_mmio(port->iotype)) { if (!port->mapbase) return -EINVAL; @@ -2911,14 +2899,9 @@ static int serial8250_request_std_resource(struct uart_8250_port *up) return -ENOMEM; } } - return 0; - case UPIO_HUB6: - case UPIO_PORT: + } else if (uart_iotype_io(port->iotype)) { if (!request_region(port->iobase, size, "serial")) return -EBUSY; - return 0; - case UPIO_UNKNOWN: - break; } return 0; @@ -2929,15 +2912,9 @@ static void serial8250_release_std_resource(struct uart_8250_port *up) unsigned int size = serial8250_port_size(up); struct uart_port *port = &up->port; - switch (port->iotype) { - case UPIO_AU: - case UPIO_TSI: - case UPIO_MEM32: - case UPIO_MEM32BE: - case UPIO_MEM16: - case UPIO_MEM: + if (uart_iotype_mmio(port->iotype)) { if (!port->mapbase) - break; + return; if (port->flags & UPF_IOREMAP) { iounmap(port->membase); @@ -2945,14 +2922,8 @@ static void serial8250_release_std_resource(struct uart_8250_port *up) } release_mem_region(port->mapbase, size); - break; - - case UPIO_HUB6: - case UPIO_PORT: + } else if (uart_iotype_io(port->iotype)) { release_region(port->iobase, size); - break; - case UPIO_UNKNOWN: - break; } } diff --git a/drivers/tty/serial/8250/8250_rsa.c b/drivers/tty/serial/8250/8250_rsa.c index fff9395948e3..da971437e89c 100644 --- a/drivers/tty/serial/8250/8250_rsa.c +++ b/drivers/tty/serial/8250/8250_rsa.c @@ -19,35 +19,33 @@ static const struct uart_ops *core_port_base_ops; static int rsa8250_request_resource(struct uart_8250_port *up) { struct uart_port *port = &up->port; - unsigned long start = UART_RSA_BASE << port->regshift; - unsigned int size = 8 << port->regshift; - - switch (port->iotype) { - case UPIO_HUB6: - case UPIO_PORT: - start += port->iobase; - if (!request_region(start, size, "serial-rsa")) - return -EBUSY; - return 0; - default: + unsigned long start; + unsigned int size; + + if (!uart_iotype_io(port->iotype)) return -EINVAL; - } + + start = UART_RSA_BASE << port->regshift; + start += port->iobase; + size = 8 << port->regshift; + + if (!request_region(start, size, "serial-rsa")) + return -EBUSY; + return 0; } static void rsa8250_release_resource(struct uart_8250_port *up) { struct uart_port *port = &up->port; - unsigned long offset = UART_RSA_BASE << port->regshift; - unsigned int size = 8 << port->regshift; - - switch (port->iotype) { - case UPIO_HUB6: - case UPIO_PORT: - release_region(port->iobase + offset, size); - break; - default: - break; - } + unsigned long offset; + unsigned int size; + + if (!uart_iotype_io(port->iotype)) + return; + + offset = UART_RSA_BASE << port->regshift; + size = 8 << port->regshift; + release_region(port->iobase + offset, size); } static void univ8250_config_port(struct uart_port *port, int flags) diff --git a/drivers/tty/serial/cpm_uart.c b/drivers/tty/serial/cpm_uart.c index b778a20ec9b1..39f54bb7b485 100644 --- a/drivers/tty/serial/cpm_uart.c +++ b/drivers/tty/serial/cpm_uart.c @@ -27,7 +27,6 @@ #include <linux/memblock.h> #include <linux/dma-mapping.h> #include <linux/of_address.h> -#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/gpio/consumer.h> #include <linux/clk.h> @@ -1530,16 +1529,14 @@ static int cpm_uart_probe(struct platform_device *ofdev) /* initialize the device pointer for the port */ pinfo->port.dev = &ofdev->dev; - pinfo->port.irq = irq_of_parse_and_map(ofdev->dev.of_node, 0); - if (!pinfo->port.irq) - return -EINVAL; + pinfo->port.irq = platform_get_irq(ofdev, 0); + if (pinfo->port.irq < 0) + return pinfo->port.irq; ret = cpm_uart_init_port(ofdev->dev.of_node, pinfo); if (!ret) return uart_add_one_port(&cpm_reg, &pinfo->port); - irq_dispose_mapping(pinfo->port.irq); - return ret; } diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c index ab9af37f6cda..ce740cdc7ceb 100644 --- a/drivers/tty/serial/earlycon.c +++ b/drivers/tty/serial/earlycon.c @@ -75,19 +75,12 @@ static void __init earlycon_print_info(struct earlycon_device *device) { struct console *earlycon = device->con; struct uart_port *port = &device->port; + char ioinfos[64]; - if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM16 || - port->iotype == UPIO_MEM32 || port->iotype == UPIO_MEM32BE) - pr_info("%s%d at MMIO%s %pa (options '%s')\n", - earlycon->name, earlycon->index, - (port->iotype == UPIO_MEM) ? "" : - (port->iotype == UPIO_MEM16) ? "16" : - (port->iotype == UPIO_MEM32) ? "32" : "32be", - &port->mapbase, device->options); - else - pr_info("%s%d at I/O port 0x%lx (options '%s')\n", - earlycon->name, earlycon->index, - port->iobase, device->options); + uart_get_ioinfos(port, ioinfos, sizeof(ioinfos)); + + pr_info("%s%d%s (options '%s')\n", earlycon->name, earlycon->index, + ioinfos, device->options); } static int __init parse_options(struct earlycon_device *device, char *options) diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c index 5a955c80a853..09648d643897 100644 --- a/drivers/tty/serial/kgdboc.c +++ b/drivers/tty/serial/kgdboc.c @@ -363,7 +363,7 @@ static int param_set_kgdboc_var(const char *kmessage, mutex_lock(&config_mutex); - strcpy(config, kmessage); + strscpy(config, kmessage); /* Chop out \n char as a result of echo */ if (len && config[len - 1] == '\n') config[len - 1] = '\0'; diff --git a/drivers/tty/serial/ma35d1_serial.c b/drivers/tty/serial/ma35d1_serial.c index 285b0fe41a86..920fe7ff5083 100644 --- a/drivers/tty/serial/ma35d1_serial.c +++ b/drivers/tty/serial/ma35d1_serial.c @@ -608,8 +608,14 @@ static int __init ma35d1serial_console_setup(struct console *co, char *options) if (!np || !p) return -ENODEV; - if (of_property_read_u32_array(np, "reg", val32, ARRAY_SIZE(val32)) != 0) + if (of_property_read_u32_array(np, "reg", val32, ARRAY_SIZE(val32)) != 0) { + of_node_put(np); + ma35d1serial_uart_nodes[co->index] = NULL; return -EINVAL; + } + + of_node_put(np); + ma35d1serial_uart_nodes[co->index] = NULL; p->port.iobase = val32[1]; p->port.membase = ioremap(p->port.iobase, MA35_UART_REG_SIZE); @@ -648,8 +654,10 @@ static void ma35d1serial_console_init_port(void) of_node_get(np); ma35d1serial_uart_nodes[i] = np; i++; - if (i == MA35_UART_NR) + if (i == MA35_UART_NR) { + of_node_put(np); break; + } } } } diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index 44b745fa26c6..a5a5cd68f696 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -724,6 +724,7 @@ static int max3100_probe(struct spi_device *spi) max3100s[i]->port.ops = &max3100_ops; max3100s[i]->port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF; max3100s[i]->port.line = i; + max3100s[i]->port.iotype = UPIO_BUS; max3100s[i]->port.type = PORT_MAX3100; max3100s[i]->port.dev = &spi->dev; diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 5fe12577ce8b..41a7bff941c1 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1400,30 +1400,18 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty dev_dbg(dev, "Reference clock set to %i Hz\n", uartclk); + /* + * Set up each port's state before registering the gpiochip, + * since the gpiochip callbacks will read s->p[i].regmap as + * soon as gpiolib exposes the controller. + */ for (i = 0; i < devtype->nr; i++) { - unsigned int line; - - line = find_first_zero_bit(max310x_lines, MAX310X_UART_NRMAX); - if (line == MAX310X_UART_NRMAX) { - ret = -ERANGE; - goto out_uart; - } - - /* Initialize port data */ - s->p[i].port.line = line; s->p[i].port.dev = dev; s->p[i].port.irq = irq; s->p[i].port.type = PORT_MAX310X; s->p[i].port.fifosize = MAX310X_FIFO_SIZE; s->p[i].port.flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY; - s->p[i].port.iotype = UPIO_PORT; - s->p[i].port.iobase = i; - /* - * Use all ones as membase to make sure uart_configure_port() in - * serial_core.c does not abort for SPI/I2C devices where the - * membase address is not applicable. - */ - s->p[i].port.membase = (void __iomem *)~0; + s->p[i].port.iotype = UPIO_BUS; s->p[i].port.uartclk = uartclk; s->p[i].port.rs485_config = max310x_rs485_config; s->p[i].port.rs485_supported = max310x_rs485_supported; @@ -1440,20 +1428,16 @@ 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); - - /* Register port */ - ret = uart_add_one_port(&max310x_uart, &s->p[i].port); - if (ret) - goto out_uart; - - set_bit(line, max310x_lines); - - /* Go to suspend mode */ - max310x_power(&s->p[i].port, 0); } #ifdef CONFIG_GPIOLIB - /* Setup GPIO controller */ + /* + * Register the GPIO controller before adding the UART ports so + * that consumers referencing the chip's own GPIOs from device + * tree (for example rs485-term-gpios = <&max310x ...>) can + * resolve them at uart_add_one_port() time instead of receiving + * -EPROBE_DEFER from their own provider. + */ s->gpio.owner = THIS_MODULE; s->gpio.parent = dev; s->gpio.label = devtype->name; @@ -1471,6 +1455,64 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty goto out_uart; #endif + for (i = 0; i < devtype->nr; i++) { + struct fwnode_handle *saved_fwnode = dev_fwnode(dev); + struct device_node *port_np = NULL; + struct device_node *child; + unsigned int line; + + line = find_first_zero_bit(max310x_lines, MAX310X_UART_NRMAX); + if (line == MAX310X_UART_NRMAX) { + ret = -ERANGE; + goto out_uart; + } + s->p[i].port.line = line; + + /* Locate the matching "serial@i" DT subnode, if any. */ + for_each_available_child_of_node(dev->of_node, child) { + u32 reg; + + if (!of_node_name_eq(child, "serial")) + continue; + if (of_property_read_u32(child, "reg", ®)) + continue; + if (reg == i) { + port_np = child; + break; + } + } + + /* + * Temporarily retarget dev's fwnode to the per-port subnode + * so uart_get_rs485_mode() picks up the per-port properties. + * For single-port variants, fall back to the chip's own + * fwnode so legacy DTs that declare rs485 properties at the + * top level keep working. + */ + if (port_np) { + device_set_node(dev, of_fwnode_handle(port_np)); + ret = uart_get_rs485_mode(&s->p[i].port); + device_set_node(dev, saved_fwnode); + of_node_put(port_np); + if (ret) + goto out_uart; + } else if (devtype->nr == 1) { + ret = uart_get_rs485_mode(&s->p[i].port); + if (ret) + goto out_uart; + } + + /* Register port */ + ret = uart_add_one_port(&max310x_uart, &s->p[i].port); + if (ret) + goto out_uart; + + set_bit(line, max310x_lines); + + /* Go to suspend mode */ + max310x_power(&s->p[i].port, 0); + } + /* Setup interrupt */ ret = devm_request_threaded_irq(dev, irq, NULL, max310x_ist, IRQF_ONESHOT | IRQF_SHARED, dev_name(dev), s); diff --git a/drivers/tty/serial/men_z135_uart.c b/drivers/tty/serial/men_z135_uart.c index 6fad57fee912..9138fa29d301 100644 --- a/drivers/tty/serial/men_z135_uart.c +++ b/drivers/tty/serial/men_z135_uart.c @@ -16,6 +16,7 @@ #include <linux/tty_flip.h> #include <linux/bitops.h> #include <linux/mcb.h> +#include <linux/slab.h> #define MEN_Z135_MAX_PORTS 12 #define MEN_Z135_BASECLK 29491200 @@ -811,7 +812,7 @@ static int men_z135_probe(struct mcb_device *mdev, if (!uart) return -ENOMEM; - uart->rxbuf = (unsigned char *)__get_free_page(GFP_KERNEL); + uart->rxbuf = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!uart->rxbuf) return -ENOMEM; @@ -841,7 +842,7 @@ static int men_z135_probe(struct mcb_device *mdev, return 0; err: - free_page((unsigned long) uart->rxbuf); + kfree(uart->rxbuf); dev_err(dev, "Failed to add UART: %d\n", err); return err; @@ -858,7 +859,7 @@ static void men_z135_remove(struct mcb_device *mdev) line--; uart_remove_one_port(&men_z135_driver, &uart->port); - free_page((unsigned long) uart->rxbuf); + kfree(uart->rxbuf); } static const struct mcb_device_id men_z135_ids[] = { diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c index 37eb701b0b46..b566206f42a2 100644 --- a/drivers/tty/serial/mpc52xx_uart.c +++ b/drivers/tty/serial/mpc52xx_uart.c @@ -645,6 +645,8 @@ static irqreturn_t mpc512x_psc_handle_irq(struct uart_port *port) /* Check if it is an interrupt for this port */ psc_num = (port->mapbase & 0xf00) >> 8; + if (psc_num >= ARRAY_SIZE(psc_mclk_clk)) + return IRQ_NONE; if (test_bit(psc_num, &fifoc_int) || test_bit(psc_num + 16, &fifoc_int)) return mpc5xxx_uart_process_int(port); @@ -663,6 +665,8 @@ static int mpc512x_psc_alloc_clock(struct uart_port *port) int err; psc_num = (port->mapbase & 0xf00) >> 8; + if (psc_num >= ARRAY_SIZE(psc_mclk_clk)) + return -EINVAL; clk = devm_clk_get(port->dev, "mclk"); if (IS_ERR(clk)) { @@ -711,6 +715,8 @@ static void mpc512x_psc_relse_clock(struct uart_port *port) struct clk *clk; psc_num = (port->mapbase & 0xf00) >> 8; + if (psc_num >= ARRAY_SIZE(psc_mclk_clk)) + return; clk = psc_mclk_clk[psc_num]; if (clk) { clk_disable_unprepare(clk); @@ -733,6 +739,8 @@ static int mpc512x_psc_endis_clock(struct uart_port *port, int enable) return 0; psc_num = (port->mapbase & 0xf00) >> 8; + if (psc_num >= ARRAY_SIZE(psc_mclk_clk)) + return -ENODEV; psc_clk = psc_mclk_clk[psc_num]; if (!psc_clk) { dev_err(port->dev, "Failed to get PSC clock entry!\n"); diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 80e31c4d9536..db5c62b0322f 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -678,6 +678,11 @@ static void pch_request_dma(struct uart_port *port) /* Get DMA's dev information */ dma_dev = pci_get_slot(priv->pdev->bus, PCI_DEVFN(PCI_SLOT(priv->pdev->devfn), 0)); + if (!dma_dev) { + dev_err(priv->port.dev, "%s: failed to get DMA device\n", + __func__); + return; + } /* Set Tx DMA */ param = &priv->param_tx; @@ -1662,7 +1667,7 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, if (priv == NULL) goto init_port_alloc_err; - rxbuf = (unsigned char *)__get_free_page(GFP_KERNEL); + rxbuf = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!rxbuf) goto init_port_free_txbuf; @@ -1735,7 +1740,7 @@ init_port_hal_free: #ifdef CONFIG_SERIAL_PCH_UART_CONSOLE pch_uart_ports[board->line_no] = NULL; #endif - free_page((unsigned long)rxbuf); + kfree(rxbuf); init_port_free_txbuf: kfree(priv); init_port_alloc_err: @@ -1750,7 +1755,7 @@ static void pch_uart_exit_port(struct eg20t_port *priv) snprintf(name, sizeof(name), "uart%d_regs", priv->port.line); debugfs_lookup_and_remove(name, NULL); uart_remove_one_port(&pch_uart_driver, &priv->port); - free_page((unsigned long)priv->rxbuf.buf); + kfree(priv->rxbuf.buf); } static void pch_uart_pci_remove(struct pci_dev *pdev) diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index 7ead87b4eb65..67b14fda4ff9 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -7,13 +7,18 @@ /* Disable MMIO tracing to prevent excessive logging of unwanted MMIO traces */ #define __DISABLE_TRACE_MMIO__ +#define CREATE_TRACE_POINTS +#include <trace/events/qcom_geni_serial.h> + #include <linux/clk.h> #include <linux/console.h> +#include <linux/dma-mapping.h> #include <linux/io.h> #include <linux/iopoll.h> #include <linux/irq.h> #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> @@ -143,6 +148,7 @@ struct qcom_geni_serial_port { unsigned int tx_remaining; unsigned int tx_queued; + bool tx_dma_stale; int wakeup_irq; bool rx_tx_swap; bool cts_rts_swap; @@ -151,6 +157,7 @@ struct qcom_geni_serial_port { struct qcom_geni_private_data private_data; const struct qcom_geni_device_data *dev_data; struct dev_pm_domain_list *pd_list; + struct notifier_block panic_nb; }; static const struct uart_ops qcom_geni_console_pops; @@ -226,7 +233,7 @@ static void qcom_geni_serial_config_port(struct uart_port *uport, int cfg_flags) static unsigned int qcom_geni_serial_get_mctrl(struct uart_port *uport) { unsigned int mctrl = TIOCM_DSR | TIOCM_CAR; - u32 geni_ios; + u32 geni_ios = 0; if (uart_console(uport)) { mctrl |= TIOCM_CTS; @@ -236,6 +243,8 @@ static unsigned int qcom_geni_serial_get_mctrl(struct uart_port *uport) mctrl |= TIOCM_CTS; } + trace_geni_serial_get_mctrl(uport->dev, mctrl, geni_ios); + return mctrl; } @@ -254,6 +263,8 @@ static void qcom_geni_serial_set_mctrl(struct uart_port *uport, if (port->manual_flow && !(mctrl & TIOCM_RTS) && !uport->suspended) uart_manual_rfr = UART_MANUAL_RFR_EN | UART_RFR_NOT_READY; writel(uart_manual_rfr, uport->membase + SE_UART_MANUAL_RFR); + + trace_geni_serial_set_mctrl(uport->dev, mctrl, uart_manual_rfr); } static const char *qcom_geni_serial_get_type(struct uart_port *uport) @@ -684,6 +695,8 @@ static void qcom_geni_serial_start_tx_dma(struct uart_port *uport) xmit_size = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail, UART_XMIT_SIZE); + trace_geni_serial_tx_data(uport->dev, tail, xmit_size); + qcom_geni_set_rs485_mode(uport, SER_RS485_RTS_ON_SEND); qcom_geni_serial_setup_tx(uport, xmit_size); @@ -697,6 +710,7 @@ static void qcom_geni_serial_start_tx_dma(struct uart_port *uport) } port->tx_remaining = xmit_size; + port->tx_dma_stale = false; } static void qcom_geni_serial_start_tx_fifo(struct uart_port *uport) @@ -863,37 +877,31 @@ static void qcom_geni_serial_stop_rx_dma(struct uart_port *uport) uport->membase + SE_DMA_RX_IRQ_CLR); } - if (port->rx_dma_addr) { - geni_se_rx_dma_unprep(&port->se, port->rx_dma_addr, - DMA_RX_BUF_SIZE); - port->rx_dma_addr = 0; - } } static void qcom_geni_serial_start_rx_dma(struct uart_port *uport) { struct qcom_geni_serial_port *port = to_dev_port(uport); - int ret; if (qcom_geni_serial_secondary_active(uport)) qcom_geni_serial_stop_rx_dma(uport); geni_se_setup_s_cmd(&port->se, UART_START_READ, UART_PARAM_RFR_OPEN); - ret = geni_se_rx_dma_prep(&port->se, port->rx_buf, - DMA_RX_BUF_SIZE, - &port->rx_dma_addr); - if (ret) { - dev_err(uport->dev, "unable to start RX SE DMA: %d\n", ret); - qcom_geni_serial_stop_rx_dma(uport); + if (!port->rx_dma_addr) { + dev_err(uport->dev, "RX DMA buffer not mapped\n"); + return; } + + dma_sync_single_for_device(uport->dev->parent, port->rx_dma_addr, + DMA_RX_BUF_SIZE, DMA_FROM_DEVICE); + geni_se_rx_init_dma(&port->se, port->rx_dma_addr, DMA_RX_BUF_SIZE); } static void qcom_geni_serial_handle_rx_dma(struct uart_port *uport, bool drop) { struct qcom_geni_serial_port *port = to_dev_port(uport); u32 rx_in; - int ret; if (!qcom_geni_serial_secondary_active(uport)) return; @@ -901,22 +909,20 @@ static void qcom_geni_serial_handle_rx_dma(struct uart_port *uport, bool drop) if (!port->rx_dma_addr) return; - geni_se_rx_dma_unprep(&port->se, port->rx_dma_addr, DMA_RX_BUF_SIZE); - port->rx_dma_addr = 0; + dma_sync_single_for_cpu(uport->dev->parent, port->rx_dma_addr, + DMA_RX_BUF_SIZE, DMA_FROM_DEVICE); rx_in = readl(uport->membase + SE_DMA_RX_LEN_IN); if (!rx_in) dev_warn_ratelimited(uport->dev, "serial engine reports 0 RX bytes in!\n"); - else if (!drop) + else if (!drop) { + trace_geni_serial_rx_data(uport->dev, port->rx_buf, rx_in); handle_rx_uart(uport, rx_in); - - ret = geni_se_rx_dma_prep(&port->se, port->rx_buf, - DMA_RX_BUF_SIZE, - &port->rx_dma_addr); - if (ret) { - dev_err(uport->dev, "unable to start RX SE DMA: %d\n", ret); - qcom_geni_serial_stop_rx_dma(uport); } + + dma_sync_single_for_device(uport->dev->parent, port->rx_dma_addr, + DMA_RX_BUF_SIZE, DMA_FROM_DEVICE); + geni_se_rx_init_dma(&port->se, port->rx_dma_addr, DMA_RX_BUF_SIZE); } static void qcom_geni_serial_start_rx(struct uart_port *uport) @@ -1029,6 +1035,7 @@ static void qcom_geni_serial_handle_tx_dma(struct uart_port *uport) struct qcom_geni_serial_port *port = to_dev_port(uport); struct tty_port *tport = &uport->state->port; unsigned int fifo_len = kfifo_len(&tport->xmit_fifo); + bool tx_dma_stale = port->tx_dma_stale; /* * Only advance the kfifo if it still contains the bytes that were @@ -1039,12 +1046,13 @@ static void qcom_geni_serial_handle_tx_dma(struct uart_port *uport) * kfifo->in, making kfifo_len() wrap to UART_XMIT_SIZE - tx_remaining * and triggering a spurious large DMA transfer of stale data. */ - if (fifo_len >= port->tx_remaining) + if (!tx_dma_stale && fifo_len >= port->tx_remaining) uart_xmit_advance(uport, port->tx_remaining); geni_se_tx_dma_unprep(&port->se, port->tx_dma_addr, port->tx_remaining); port->tx_dma_addr = 0; port->tx_remaining = 0; + port->tx_dma_stale = false; if (!kfifo_is_empty(&tport->xmit_fifo)) qcom_geni_serial_start_tx_dma(uport); @@ -1079,6 +1087,10 @@ static irqreturn_t qcom_geni_serial_isr(int isr, void *dev) geni_status = readl(uport->membase + SE_GENI_STATUS); dma = readl(uport->membase + SE_GENI_DMA_MODE_EN); m_irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); + + trace_geni_serial_irq(uport->dev, m_irq_status, s_irq_status, + dma_tx_status, dma_rx_status); + writel(m_irq_status, uport->membase + SE_GENI_M_IRQ_CLEAR); writel(s_irq_status, uport->membase + SE_GENI_S_IRQ_CLEAR); writel(dma_tx_status, uport->membase + SE_DMA_TX_IRQ_CLR); @@ -1182,6 +1194,10 @@ static void qcom_geni_serial_shutdown(struct uart_port *uport) static void qcom_geni_serial_flush_buffer(struct uart_port *uport) { + struct qcom_geni_serial_port *port = to_dev_port(uport); + + if (port->tx_dma_addr) + port->tx_dma_stale = true; qcom_geni_serial_cancel_tx_cmd(uport); } @@ -1245,6 +1261,7 @@ static int qcom_geni_serial_startup(struct uart_port *uport) { int ret; struct qcom_geni_serial_port *port = to_dev_port(uport); + struct tty_port *tport = &uport->state->port; if (!port->setup) { ret = qcom_geni_serial_port_setup(uport); @@ -1252,6 +1269,13 @@ static int qcom_geni_serial_startup(struct uart_port *uport) return ret; } + /* + * Skip the close-time transmit drain for console ports so that + * shutdown can proceed without waiting for pending TX completion. + */ + if (uart_console(uport)) + tport->closing_wait = ASYNC_CLOSING_WAIT_NONE; + uart_port_lock_irq(uport); qcom_geni_serial_start_rx(uport); uart_port_unlock_irq(uport); @@ -1291,8 +1315,8 @@ static int geni_serial_set_rate(struct uart_port *uport, unsigned int baud) return -EINVAL; } - dev_dbg(port->se.dev, "desired_rate = %u, clk_rate = %lu, clk_div = %u, clk_idx = %u\n", - baud * sampling_rate, clk_rate, clk_div, clk_idx); + trace_geni_serial_clk_cfg(uport->dev, baud * sampling_rate, clk_rate, + clk_div, clk_idx); uport->uartclk = clk_rate; port->clk_rate = clk_rate; @@ -1452,6 +1476,10 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport, writel(bits_per_char, uport->membase + SE_UART_TX_WORD_LEN); writel(bits_per_char, uport->membase + SE_UART_RX_WORD_LEN); writel(stop_bit_len, uport->membase + SE_UART_TX_STOP_BIT_LEN); + + trace_geni_serial_set_termios(uport->dev, baud, bits_per_char, + tx_trans_cfg, tx_parity_cfg, rx_trans_cfg, + rx_parity_cfg, stop_bit_len); } #ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE @@ -1798,6 +1826,22 @@ static const struct uart_ops qcom_geni_uart_pops = { .pm = qcom_geni_serial_pm, }; +static int qcom_geni_serial_panic_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct qcom_geni_serial_port *port = + container_of(nb, struct qcom_geni_serial_port, panic_nb); + struct uart_port *uport = &port->uport; + + if (pm_runtime_status_suspended(uport->dev)) + return NOTIFY_OK; + + qcom_geni_serial_stop_tx(uport); + qcom_geni_serial_stop_rx(uport); + + return NOTIFY_OK; +} + static int qcom_geni_serial_probe(struct platform_device *pdev) { int ret = 0; @@ -1864,6 +1908,14 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) ret = -ENOMEM; goto error; } + + port->rx_dma_addr = dma_map_single(pdev->dev.parent, port->rx_buf, + DMA_RX_BUF_SIZE, DMA_FROM_DEVICE); + if (dma_mapping_error(pdev->dev.parent, port->rx_dma_addr)) { + ret = -EIO; + dev_err(&pdev->dev, "Failed to map RX DMA buffer: %d\n", ret); + goto error; + } } port->name = devm_kasprintf(uport->dev, GFP_KERNEL, @@ -1925,9 +1977,17 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) if (ret) goto error; + port->panic_nb.notifier_call = qcom_geni_serial_panic_notifier; + atomic_notifier_chain_register(&panic_notifier_list, &port->panic_nb); + return 0; error: + 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->pd_list); return ret; } @@ -1938,10 +1998,19 @@ static void qcom_geni_serial_remove(struct platform_device *pdev) struct uart_port *uport = &port->uport; struct uart_driver *drv = port->private_data.drv; + atomic_notifier_chain_unregister(&panic_notifier_list, &port->panic_nb); + dev_pm_clear_wake_irq(&pdev->dev); device_init_wakeup(&pdev->dev, false); ida_free(&port_ida, uport->line); uart_remove_one_port(drv, &port->uport); + + 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->pd_list); } @@ -1974,6 +2043,7 @@ static int qcom_geni_serial_suspend(struct device *dev) struct qcom_geni_serial_port *port = dev_get_drvdata(dev); struct uart_port *uport = &port->uport; struct qcom_geni_private_data *private_data = uport->private_data; + int ret; /* * This is done so we can hit the lowest possible state in suspend @@ -1983,7 +2053,19 @@ static int qcom_geni_serial_suspend(struct device *dev) geni_icc_set_tag(&port->se, QCOM_ICC_TAG_ACTIVE_ONLY); geni_icc_set_bw(&port->se); } - return uart_suspend_port(private_data->drv, uport); + + ret = uart_suspend_port(private_data->drv, uport); + if (ret) + return ret; + + /* + * When no_console_suspend is set the console must remain active + * across system sleep, so skip the force suspend path. + */ + if (!console_suspend_enabled && uart_console(uport)) + return 0; + + return pm_runtime_force_suspend(dev); } static int qcom_geni_serial_resume(struct device *dev) @@ -1993,6 +2075,10 @@ static int qcom_geni_serial_resume(struct device *dev) struct uart_port *uport = &port->uport; struct qcom_geni_private_data *private_data = uport->private_data; + ret = pm_runtime_force_resume(dev); + if (ret) + return ret; + ret = uart_resume_port(private_data->drv, uport); if (uart_console(uport)) { geni_icc_set_tag(&port->se, QCOM_ICC_TAG_ALWAYS); @@ -2049,6 +2135,18 @@ static const struct dev_pm_ops qcom_geni_serial_pm_ops = { SYSTEM_SLEEP_PM_OPS(qcom_geni_serial_suspend, qcom_geni_serial_resume) }; +static void qcom_geni_serial_sys_shutdown(struct platform_device *pdev) +{ + struct qcom_geni_serial_port *port = platform_get_drvdata(pdev); + struct uart_port *uport = &port->uport; + + if (pm_runtime_status_suspended(uport->dev)) + return; + + qcom_geni_serial_stop_tx(uport); + qcom_geni_serial_stop_rx(uport); +} + static const struct of_device_id qcom_geni_serial_match_table[] = { #if IS_ENABLED(CONFIG_SERIAL_QCOM_GENI_CONSOLE) { @@ -2075,6 +2173,7 @@ MODULE_DEVICE_TABLE(of, qcom_geni_serial_match_table); static struct platform_driver qcom_geni_serial_platform_driver = { .remove = qcom_geni_serial_remove, .probe = qcom_geni_serial_probe, + .shutdown = qcom_geni_serial_sys_shutdown, .driver = { .name = "qcom_geni_serial", .of_match_table = qcom_geni_serial_match_table, diff --git a/drivers/tty/serial/rp2.c b/drivers/tty/serial/rp2.c index 6d99a02dd439..51e81ec0ffdb 100644 --- a/drivers/tty/serial/rp2.c +++ b/drivers/tty/serial/rp2.c @@ -197,7 +197,7 @@ struct rp2_card { }; #define RP_ID(prod) PCI_VDEVICE(RP, (prod)) -#define RP_CAP(ports, smpte) (((ports) << 8) | ((smpte) << 0)) +#define RP_CAP(ports, smpte) .driver_data = (((ports) << 8) | ((smpte) << 0)) static inline void rp2_decode_cap(const struct pci_device_id *id, int *ports, int *smpte) diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 6c97953d593b..943be318de41 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -1483,14 +1483,7 @@ static int sc16is7xx_setup_channel(struct sc16is7xx_one *one, int i, port->type = PORT_SC16IS7XX; port->fifosize = SC16IS7XX_FIFO_SIZE; port->flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY; - port->iobase = i; - /* - * Use all ones as membase to make sure uart_configure_port() in - * serial_core.c does not abort for SPI/I2C devices where the - * membase address is not applicable. - */ - port->membase = (void __iomem *)~0; - port->iotype = UPIO_PORT; + port->iotype = UPIO_BUS; port->rs485_config = sc16is7xx_config_rs485; port->rs485_supported = sc16is7xx_rs485_supported; port->ops = &sc16is7xx_ops; diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index a530ad372b43..edd1e7be2a5c 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -33,6 +33,7 @@ #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. @@ -1962,6 +1963,34 @@ static const char *uart_type(struct uart_port *port) return str; } +bool uart_iotype_mmio(enum uart_iotype iotype) +{ + switch (iotype) { + case UPIO_MEM: + case UPIO_MEM32: + case UPIO_AU: + case UPIO_TSI: + case UPIO_MEM32BE: + case UPIO_MEM16: + return true; + default: + return false; + } +} +EXPORT_SYMBOL_GPL(uart_iotype_mmio); + +bool uart_iotype_io(enum uart_iotype iotype) +{ + switch (iotype) { + case UPIO_PORT: + case UPIO_HUB6: + return true; + default: + return false; + } +} +EXPORT_SYMBOL_GPL(uart_iotype_io); + #ifdef CONFIG_PROC_FS static void uart_line_info(struct seq_file *m, struct uart_state *state) @@ -1969,9 +1998,9 @@ static void uart_line_info(struct seq_file *m, struct uart_state *state) struct tty_port *port = &state->port; enum uart_pm_state pm_state; struct uart_port *uport; + char ioinfos[64]; char stat_buf[32]; unsigned int status; - int mmio; guard(mutex)(&port->mutex); @@ -1979,13 +2008,10 @@ static void uart_line_info(struct seq_file *m, struct uart_state *state) if (!uport) return; - mmio = uport->iotype >= UPIO_MEM; - seq_printf(m, "%u: uart:%s %s%08llX irq:%u", - uport->line, uart_type(uport), - mmio ? "mmio:0x" : "port:", - mmio ? (unsigned long long)uport->mapbase - : (unsigned long long)uport->iobase, - uport->irq); + seq_printf(m, "%u: uart:%s", uport->line, uart_type(uport)); + uart_get_ioinfos(uport, ioinfos, sizeof(ioinfos)); + seq_printf(m, "%s", ioinfos); + seq_printf(m, " irq:%u", uport->irq); if (uport->type == PORT_UNKNOWN) { seq_putc(m, '\n'); @@ -2459,38 +2485,47 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) } EXPORT_SYMBOL(uart_resume_port); -static inline void -uart_report_port(struct uart_driver *drv, struct uart_port *port) +static const char *uart_get_mmio_width(struct uart_port *port) { - char address[64]; - switch (port->iotype) { - case UPIO_PORT: - snprintf(address, sizeof(address), "I/O 0x%lx", port->iobase); - break; - case UPIO_HUB6: - snprintf(address, sizeof(address), - "I/O 0x%lx offset 0x%x", port->iobase, port->hub6); - break; - case UPIO_MEM: case UPIO_MEM16: + return "16"; case UPIO_MEM32: case UPIO_MEM32BE: + return "32"; case UPIO_AU: - case UPIO_TSI: - snprintf(address, sizeof(address), - "MMIO 0x%llx", (unsigned long long)port->mapbase); - break; + case UPIO_MEM: default: - strscpy(address, "*unknown*", sizeof(address)); - break; + return ""; + } +} + +void uart_get_ioinfos(struct uart_port *port, char *buf, size_t size) +{ + buf[0] = '\0'; + + if (uart_iotype_mmio(port->iotype)) { + scnprintf(buf, size, " MMIO%s:%pa", uart_get_mmio_width(port), &port->mapbase); + } else if (uart_iotype_io(port->iotype)) { + if (port->iotype == UPIO_PORT) + scnprintf(buf, size, " I/O:0x%lx", port->iobase); + else if (port->iotype == UPIO_HUB6) + scnprintf(buf, size, " I/O:0x%lx, offset 0x%x", port->iobase, port->hub6); } +} +EXPORT_SYMBOL(uart_get_ioinfos); + +static inline void +uart_report_port(struct uart_driver *drv, struct uart_port *port) +{ + char ioinfos[64]; + + uart_get_ioinfos(port, ioinfos, sizeof(ioinfos)); - pr_info("%s%s%s at %s (irq = %u, base_baud = %u) is a %s\n", - port->dev ? dev_name(port->dev) : "", - port->dev ? ": " : "", - port->name, - address, port->irq, port->uartclk / 16, uart_type(port)); + pr_info("%s%s%s%s (irq = %u, base_baud = %u) is a %s\n", + port->dev ? dev_name(port->dev) : "", + port->dev ? ": " : "", + port->name, ioinfos, port->irq, port->uartclk / 16, uart_type(port)); /* The magic multiplier feature is a bit obscure, so report it too. */ if (port->flags & UPF_MAGIC_MULTIPLIER) @@ -2507,11 +2542,10 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state, { unsigned int flags; - /* - * If there isn't a port here, don't do anything further. - */ - if (!port->iobase && !port->mapbase && !port->membase) - return; + /* If there isn't a port here, don't do anything further. */ + if (uart_iotype_mmio(port->iotype) || uart_iotype_io(port->iotype)) + if (!port->iobase && !port->mapbase && !port->membase) + return; /* * Now do the auto configuration stuff. Note that config_port @@ -3208,23 +3242,16 @@ bool uart_match_port(const struct uart_port *port1, { if (port1->iotype != port2->iotype) return false; - - switch (port1->iotype) { - case UPIO_PORT: + else if (port1->iotype == UPIO_PORT) return port1->iobase == port2->iobase; - case UPIO_HUB6: - return port1->iobase == port2->iobase && - port1->hub6 == port2->hub6; - case UPIO_MEM: - case UPIO_MEM16: - case UPIO_MEM32: - case UPIO_MEM32BE: - case UPIO_AU: - case UPIO_TSI: + else if (port1->iotype == UPIO_HUB6) + return hub6_match_port(port1, port2); + else if (uart_iotype_mmio(port1->iotype)) return port1->mapbase == port2->mapbase; - default: + else if (port1->iotype == UPIO_BUS) + return true; + else return false; - } } EXPORT_SYMBOL(uart_match_port); diff --git a/drivers/tty/tty_jobctrl.c b/drivers/tty/tty_jobctrl.c index ef8741c3e662..37929fb56174 100644 --- a/drivers/tty/tty_jobctrl.c +++ b/drivers/tty/tty_jobctrl.c @@ -506,29 +506,23 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t if (pgrp_nr < 0) return -EINVAL; - spin_lock_irq(&real_tty->ctrl.lock); + guard(spinlock_irq)(&real_tty->ctrl.lock); if (!current->signal->tty || (current->signal->tty != real_tty) || - (real_tty->ctrl.session != task_session(current))) { - retval = -ENOTTY; - goto out_unlock_ctrl; - } - rcu_read_lock(); + (real_tty->ctrl.session != task_session(current))) + return -ENOTTY; + + guard(rcu)(); pgrp = find_vpid(pgrp_nr); - retval = -ESRCH; if (!pgrp) - goto out_unlock; - retval = -EPERM; + return -ESRCH; if (session_of_pgrp(pgrp) != task_session(current)) - goto out_unlock; - retval = 0; + return -EPERM; + put_pid(real_tty->ctrl.pgrp); real_tty->ctrl.pgrp = get_pid(pgrp); -out_unlock: - rcu_read_unlock(); -out_unlock_ctrl: - spin_unlock_irq(&real_tty->ctrl.lock); - return retval; + + return 0; } /** @@ -542,7 +536,6 @@ out_unlock_ctrl: */ static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) { - unsigned long flags; pid_t sid; /* @@ -552,17 +545,13 @@ static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t _ if (tty == real_tty && current->signal->tty != real_tty) return -ENOTTY; - spin_lock_irqsave(&real_tty->ctrl.lock, flags); - if (!real_tty->ctrl.session) - goto err; - sid = pid_vnr(real_tty->ctrl.session); - spin_unlock_irqrestore(&real_tty->ctrl.lock, flags); + scoped_guard(spinlock_irqsave, &real_tty->ctrl.lock) { + if (!real_tty->ctrl.session) + return -ENOTTY; + sid = pid_vnr(real_tty->ctrl.session); + } return put_user(sid, p); - -err: - spin_unlock_irqrestore(&real_tty->ctrl.lock, flags); - return -ENOTTY; } /* diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c index 7d40eacc21b3..bf1502fd5bd4 100644 --- a/drivers/tty/vt/vc_screen.c +++ b/drivers/tty/vt/vc_screen.c @@ -53,8 +53,6 @@ #define HEADER_SIZE 4u #define CON_BUF_SIZE (IS_ENABLED(CONFIG_BASE_SMALL) ? 256 : PAGE_SIZE) -DEFINE_FREE(free_page_ptr, void *, if (_T) free_page((unsigned long)_T)); - /* * Our minor space: * @@ -371,7 +369,7 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) loff_t pos; bool viewed, attr, uni_mode; - char *con_buf __free(free_page_ptr) = (char *)__get_free_page(GFP_KERNEL); + char *con_buf __free(kfree) = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!con_buf) return -ENOMEM; @@ -596,7 +594,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) if (use_unicode(inode)) return -EOPNOTSUPP; - char *con_buf __free(free_page_ptr) = (char *)__get_free_page(GFP_KERNEL); + char *con_buf __free(kfree) = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!con_buf) return -ENOMEM; diff --git a/include/linux/goldfish.h b/include/linux/goldfish.h index bcc17f95b906..98a4719c6776 100644 --- a/include/linux/goldfish.h +++ b/include/linux/goldfish.h @@ -2,8 +2,6 @@ #ifndef __LINUX_GOLDFISH_H #define __LINUX_GOLDFISH_H -#include <linux/kernel.h> -#include <linux/types.h> #include <linux/io.h> /* Helpers for Goldfish virtual platform */ @@ -15,26 +13,4 @@ #define gf_iowrite32 iowrite32 #endif -static inline void gf_write_ptr(const void *ptr, void __iomem *portl, - void __iomem *porth) -{ - const unsigned long addr = (unsigned long)ptr; - - gf_iowrite32(lower_32_bits(addr), portl); -#ifdef CONFIG_64BIT - gf_iowrite32(upper_32_bits(addr), porth); -#endif -} - -static inline void gf_write_dma_addr(const dma_addr_t addr, - void __iomem *portl, - void __iomem *porth) -{ - gf_iowrite32(lower_32_bits(addr), portl); -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - gf_iowrite32(upper_32_bits(addr), porth); -#endif -} - - #endif /* __LINUX_GOLDFISH_H */ diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index bdc214386e4a..c4cc4f66af4b 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -437,6 +437,7 @@ enum uart_iotype { UPIO_TSI = SERIAL_IO_TSI, /* Tsi108/109 type IO */ UPIO_MEM32BE = SERIAL_IO_MEM32BE, /* 32b big endian */ UPIO_MEM16 = SERIAL_IO_MEM16, /* 16b little endian */ + UPIO_BUS = SERIAL_IO_BUS, /* Serial bus I/O access (ex: SPI, I2C) */ }; struct uart_port { @@ -1338,4 +1339,9 @@ static inline int uart_handle_break(struct uart_port *port) !((cflag) & CLOCAL)) int uart_get_rs485_mode(struct uart_port *port); + +void uart_get_ioinfos(struct uart_port *port, char *buf, size_t size); +bool uart_iotype_mmio(enum uart_iotype iotype); +bool uart_iotype_io(enum uart_iotype iotype); + #endif /* LINUX_SERIAL_CORE_H */ diff --git a/include/trace/events/qcom_geni_serial.h b/include/trace/events/qcom_geni_serial.h index 417ec01f9fc8..e1aa551d525e 100644 --- a/include/trace/events/qcom_geni_serial.h +++ b/include/trace/events/qcom_geni_serial.h @@ -97,18 +97,17 @@ DECLARE_EVENT_CLASS(geni_serial_data, TP_ARGS(dev, buf, len), TP_STRUCT__entry(__string(name, dev_name(dev)) - __field(unsigned int, len) __dynamic_array(u8, data, len) ), TP_fast_assign(__assign_str(name); - __entry->len = len; memcpy(__get_dynamic_array(data), buf, len); ), TP_printk("%s: len=%u data=%s", - __get_str(name), __entry->len, - __print_hex(__get_dynamic_array(data), __entry->len)) + __get_str(name), __get_dynamic_array_len(data), + __print_hex(__get_dynamic_array(data), + __get_dynamic_array_len(data))) ); DEFINE_EVENT(geni_serial_data, geni_serial_tx_data, diff --git a/include/uapi/linux/serial.h b/include/uapi/linux/serial.h index de9b4733607e..e6f61538fc28 100644 --- a/include/uapi/linux/serial.h +++ b/include/uapi/linux/serial.h @@ -72,6 +72,7 @@ struct serial_struct { #define SERIAL_IO_TSI 5 #define SERIAL_IO_MEM32BE 6 #define SERIAL_IO_MEM16 7 +#define SERIAL_IO_BUS 8 #define UART_CLEAR_FIFO 0x01 #define UART_USE_FIFO 0x02 |
