diff options
Diffstat (limited to 'drivers/tty/serial')
25 files changed, 569 insertions, 257 deletions
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index a3a0154da567..53f57c3b9f42 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -338,23 +338,16 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios, rate = clk_round_rate(d->clk, newrate); if (rate > 0) { /* - * Premilinary set the uartclk to the new clock rate so the - * clock update event handler caused by the clk_set_rate() - * calling wouldn't actually update the UART divisor since - * we about to do this anyway. + * Note that any clock-notifer worker will block in + * serial8250_update_uartclk() until we are done. */ - swap(p->uartclk, rate); ret = clk_set_rate(d->clk, newrate); - if (ret) - swap(p->uartclk, rate); + if (!ret) + p->uartclk = rate; } clk_prepare_enable(d->clk); - p->status &= ~UPSTAT_AUTOCTS; - if (termios->c_cflag & CRTSCTS) - p->status |= UPSTAT_AUTOCTS; - - serial8250_do_set_termios(p, termios, old); + dw8250_do_set_termios(p, termios, old); } static void dw8250_set_ldisc(struct uart_port *p, struct ktermios *termios) @@ -393,8 +386,9 @@ static bool dw8250_idma_filter(struct dma_chan *chan, void *param) static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data) { - if (p->dev->of_node) { - struct device_node *np = p->dev->of_node; + struct device_node *np = p->dev->of_node; + + if (np) { int id; /* get index of serial line, if found in DT aliases */ @@ -411,11 +405,13 @@ static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data) data->skip_autocfg = true; } #endif - if (of_device_is_big_endian(p->dev->of_node)) { + + if (of_device_is_big_endian(np)) { p->iotype = UPIO_MEM32BE; p->serial_in = dw8250_serial_in32be; p->serial_out = dw8250_serial_out32be; } + if (of_device_is_compatible(np, "marvell,armada-38x-uart")) p->serial_out = dw8250_serial_out38x; @@ -726,7 +722,7 @@ static struct platform_driver dw8250_platform_driver = { .name = "dw-apb-uart", .pm = &dw8250_pm_ops, .of_match_table = dw8250_of_match, - .acpi_match_table = ACPI_PTR(dw8250_acpi_match), + .acpi_match_table = dw8250_acpi_match, }, .probe = dw8250_probe, .remove = dw8250_remove, diff --git a/drivers/tty/serial/8250/8250_dwlib.c b/drivers/tty/serial/8250/8250_dwlib.c index 6d6a78eead3e..622d3b0d89e7 100644 --- a/drivers/tty/serial/8250/8250_dwlib.c +++ b/drivers/tty/serial/8250/8250_dwlib.c @@ -77,6 +77,16 @@ static void dw8250_set_divisor(struct uart_port *p, unsigned int baud, serial8250_do_set_divisor(p, baud, quot, quot_frac); } +void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios, struct ktermios *old) +{ + p->status &= ~UPSTAT_AUTOCTS; + if (termios->c_cflag & CRTSCTS) + p->status |= UPSTAT_AUTOCTS; + + serial8250_do_set_termios(p, termios, old); +} +EXPORT_SYMBOL_GPL(dw8250_do_set_termios); + void dw8250_setup_port(struct uart_port *p) { struct uart_8250_port *up = up_to_u8250p(p); diff --git a/drivers/tty/serial/8250/8250_dwlib.h b/drivers/tty/serial/8250/8250_dwlib.h index 9a12953832d3..83d528e5cc21 100644 --- a/drivers/tty/serial/8250/8250_dwlib.h +++ b/drivers/tty/serial/8250/8250_dwlib.h @@ -16,4 +16,5 @@ struct dw8250_port_data { u8 dlf_size; }; +void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios, struct ktermios *old); void dw8250_setup_port(struct uart_port *p); diff --git a/drivers/tty/serial/8250/8250_fsl.c b/drivers/tty/serial/8250/8250_fsl.c index fc65a2293ce9..9c01c531349d 100644 --- a/drivers/tty/serial/8250/8250_fsl.c +++ b/drivers/tty/serial/8250/8250_fsl.c @@ -23,10 +23,6 @@ #include "8250.h" -struct fsl8250_data { - int line; -}; - int fsl8250_handle_irq(struct uart_port *port) { unsigned char lsr, orig_lsr; @@ -90,6 +86,10 @@ 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; diff --git a/drivers/tty/serial/8250/8250_lpss.c b/drivers/tty/serial/8250/8250_lpss.c index 848d81e3838c..d3bafec7619d 100644 --- a/drivers/tty/serial/8250/8250_lpss.c +++ b/drivers/tty/serial/8250/8250_lpss.c @@ -100,11 +100,7 @@ static void byt_set_termios(struct uart_port *p, struct ktermios *termios, reg |= BYT_PRV_CLK_EN | BYT_PRV_CLK_UPDATE; writel(reg, p->membase + BYT_PRV_CLK); - p->status &= ~UPSTAT_AUTOCTS; - if (termios->c_cflag & CRTSCTS) - p->status |= UPSTAT_AUTOCTS; - - serial8250_do_set_termios(p, termios, old); + dw8250_do_set_termios(p, termios, old); } static unsigned int byt_get_mctrl(struct uart_port *port) @@ -168,6 +164,9 @@ static int ehl_serial_setup(struct lpss8250 *lpss, struct uart_port *port) * matching with the registered General Purpose DMA controllers. */ up->dma = dma; + + port->set_termios = dw8250_do_set_termios; + return 0; } diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 891fd8345e25..73e5f1dbd075 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -106,7 +106,7 @@ #define UART_OMAP_EFR2_TIMEOUT_BEHAVE BIT(6) /* RX FIFO occupancy indicator */ -#define UART_OMAP_RX_LVL 0x64 +#define UART_OMAP_RX_LVL 0x19 struct omap8250_priv { int line; diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 726912b16a55..5d43de143f33 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -75,13 +75,12 @@ static int pci_default_setup(struct serial_private*, static void moan_device(const char *str, struct pci_dev *dev) { - dev_err(&dev->dev, - "%s: %s\n" + pci_err(dev, "%s\n" "Please send the output of lspci -vv, this\n" "message (0x%04x,0x%04x,0x%04x,0x%04x), the\n" "manufacturer and name of serial board or\n" "modem board to <linux-serial@vger.kernel.org>.\n", - pci_name(dev), str, dev->vendor, dev->device, + str, dev->vendor, dev->device, dev->subsystem_vendor, dev->subsystem_device); } @@ -238,7 +237,7 @@ static int pci_inteli960ni_init(struct pci_dev *dev) /* is firmware started? */ pci_read_config_dword(dev, 0x44, &oldval); if (oldval == 0x00001000L) { /* RESET value */ - dev_dbg(&dev->dev, "Local i960 firmware missing\n"); + pci_dbg(dev, "Local i960 firmware missing\n"); return -ENODEV; } return 0; @@ -515,7 +514,7 @@ static int pci_siig_init(struct pci_dev *dev) if (type == 0x1000) return pci_siig10x_init(dev); - else if (type == 0x2000) + if (type == 0x2000) return pci_siig20x_init(dev); moan_device("Unknown SIIG card", dev); @@ -588,9 +587,8 @@ static int pci_timedia_probe(struct pci_dev *dev) * (0,2,3,5,6: serial only -- 7,8,9: serial + parallel) */ if ((dev->subsystem_device & 0x00f0) >= 0x70) { - dev_info(&dev->dev, - "ignoring Timedia subdevice %04x for parport_serial\n", - dev->subsystem_device); + pci_info(dev, "ignoring Timedia subdevice %04x for parport_serial\n", + dev->subsystem_device); return -ENODEV; } @@ -792,9 +790,9 @@ static int pci_netmos_9900_setup(struct serial_private *priv, bar = 3 * idx; return setup_port(priv, port, bar, 0, board->reg_shift); - } else { - return pci_default_setup(priv, board, port, idx); } + + return pci_default_setup(priv, board, port, idx); } /* the 99xx series comes with a range of device IDs and a variety @@ -827,8 +825,7 @@ static int pci_netmos_9900_numports(struct pci_dev *dev) if (sub_serports > 0) return sub_serports; - dev_err(&dev->dev, - "NetMos/Mostech serial driver ignoring port on ambiguous config.\n"); + pci_err(dev, "NetMos/Mostech serial driver ignoring port on ambiguous config.\n"); return 0; } @@ -897,18 +894,16 @@ static int pci_netmos_init(struct pci_dev *dev) /* enable IO_Space bit */ #define ITE_887x_POSIO_ENABLE (1 << 31) +/* inta_addr are the configuration addresses of the ITE */ +static const short inta_addr[] = { 0x2a0, 0x2c0, 0x220, 0x240, 0x1e0, 0x200, 0x280 }; static int pci_ite887x_init(struct pci_dev *dev) { - /* inta_addr are the configuration addresses of the ITE */ - static const short inta_addr[] = { 0x2a0, 0x2c0, 0x220, 0x240, 0x1e0, - 0x200, 0x280, 0 }; int ret, i, type; struct resource *iobase = NULL; u32 miscr, uartbar, ioport; /* search for the base-ioport */ - i = 0; - while (inta_addr[i] && iobase == NULL) { + for (i = 0; i < ARRAY_SIZE(inta_addr); i++) { iobase = request_region(inta_addr[i], ITE_887x_IOSIZE, "ite887x"); if (iobase != NULL) { @@ -925,13 +920,11 @@ static int pci_ite887x_init(struct pci_dev *dev) break; } release_region(iobase->start, ITE_887x_IOSIZE); - iobase = NULL; } - i++; } - if (!inta_addr[i]) { - dev_err(&dev->dev, "ite887x: could not find iobase\n"); + if (i == ARRAY_SIZE(inta_addr)) { + pci_err(dev, "could not find iobase\n"); return -ENODEV; } @@ -1026,9 +1019,7 @@ static int pci_endrun_init(struct pci_dev *dev) /* EndRun device */ if (deviceID == 0x07000200) { number_uarts = ioread8(p + 4); - dev_dbg(&dev->dev, - "%d ports detected on EndRun PCI Express device\n", - number_uarts); + pci_dbg(dev, "%d ports detected on EndRun PCI Express device\n", number_uarts); } pci_iounmap(dev, p); return number_uarts; @@ -1058,9 +1049,7 @@ static int pci_oxsemi_tornado_init(struct pci_dev *dev) /* Tornado device */ if (deviceID == 0x07000200) { number_uarts = ioread8(p + 4); - dev_dbg(&dev->dev, - "%d ports detected on Oxford PCI Express device\n", - number_uarts); + pci_dbg(dev, "%d ports detected on Oxford PCI Express device\n", number_uarts); } pci_iounmap(dev, p); return number_uarts; @@ -1074,13 +1063,6 @@ static int pci_asix_setup(struct serial_private *priv, return pci_default_setup(priv, board, port, idx); } -/* Quatech devices have their own extra interface features */ - -struct quatech_feature { - u16 devid; - bool amcc; -}; - #define QPCR_TEST_FOR1 0x3F #define QPCR_TEST_GET1 0x00 #define QPCR_TEST_FOR2 0x40 @@ -1096,42 +1078,30 @@ struct quatech_feature { #define QOPR_CLOCK_X8 0x0003 #define QOPR_CLOCK_RATE_MASK 0x0003 - -static struct quatech_feature quatech_cards[] = { - { PCI_DEVICE_ID_QUATECH_QSC100, 1 }, - { PCI_DEVICE_ID_QUATECH_DSC100, 1 }, - { PCI_DEVICE_ID_QUATECH_DSC100E, 0 }, - { PCI_DEVICE_ID_QUATECH_DSC200, 1 }, - { PCI_DEVICE_ID_QUATECH_DSC200E, 0 }, - { PCI_DEVICE_ID_QUATECH_ESC100D, 1 }, - { PCI_DEVICE_ID_QUATECH_ESC100M, 1 }, - { PCI_DEVICE_ID_QUATECH_QSCP100, 1 }, - { PCI_DEVICE_ID_QUATECH_DSCP100, 1 }, - { PCI_DEVICE_ID_QUATECH_QSCP200, 1 }, - { PCI_DEVICE_ID_QUATECH_DSCP200, 1 }, - { PCI_DEVICE_ID_QUATECH_ESCLP100, 0 }, - { PCI_DEVICE_ID_QUATECH_QSCLP100, 0 }, - { PCI_DEVICE_ID_QUATECH_DSCLP100, 0 }, - { PCI_DEVICE_ID_QUATECH_SSCLP100, 0 }, - { PCI_DEVICE_ID_QUATECH_QSCLP200, 0 }, - { PCI_DEVICE_ID_QUATECH_DSCLP200, 0 }, - { PCI_DEVICE_ID_QUATECH_SSCLP200, 0 }, - { PCI_DEVICE_ID_QUATECH_SPPXP_100, 0 }, +/* Quatech devices have their own extra interface features */ +static struct pci_device_id quatech_cards[] = { + { PCI_DEVICE_DATA(QUATECH, QSC100, 1) }, + { PCI_DEVICE_DATA(QUATECH, DSC100, 1) }, + { PCI_DEVICE_DATA(QUATECH, DSC100E, 0) }, + { PCI_DEVICE_DATA(QUATECH, DSC200, 1) }, + { PCI_DEVICE_DATA(QUATECH, DSC200E, 0) }, + { PCI_DEVICE_DATA(QUATECH, ESC100D, 1) }, + { PCI_DEVICE_DATA(QUATECH, ESC100M, 1) }, + { PCI_DEVICE_DATA(QUATECH, QSCP100, 1) }, + { PCI_DEVICE_DATA(QUATECH, DSCP100, 1) }, + { PCI_DEVICE_DATA(QUATECH, QSCP200, 1) }, + { PCI_DEVICE_DATA(QUATECH, DSCP200, 1) }, + { PCI_DEVICE_DATA(QUATECH, ESCLP100, 0) }, + { PCI_DEVICE_DATA(QUATECH, QSCLP100, 0) }, + { PCI_DEVICE_DATA(QUATECH, DSCLP100, 0) }, + { PCI_DEVICE_DATA(QUATECH, SSCLP100, 0) }, + { PCI_DEVICE_DATA(QUATECH, QSCLP200, 0) }, + { PCI_DEVICE_DATA(QUATECH, DSCLP200, 0) }, + { PCI_DEVICE_DATA(QUATECH, SSCLP200, 0) }, + { PCI_DEVICE_DATA(QUATECH, SPPXP_100, 0) }, { 0, } }; -static int pci_quatech_amcc(u16 devid) -{ - struct quatech_feature *qf = &quatech_cards[0]; - while (qf->devid) { - if (qf->devid == devid) - return qf->amcc; - qf++; - } - pr_err("quatech: unknown port type '0x%04X'.\n", devid); - return 0; -}; - static int pci_quatech_rqopr(struct uart_8250_port *port) { unsigned long base = port->port.iobase; @@ -1291,7 +1261,16 @@ static int pci_quatech_rs422(struct uart_8250_port *port) static int pci_quatech_init(struct pci_dev *dev) { - if (pci_quatech_amcc(dev->device)) { + const struct pci_device_id *match; + bool amcc = false; + + match = pci_match_id(quatech_cards, dev); + if (match) + amcc = match->driver_data; + else + pci_err(dev, "unknown port type '0x%04X'.\n", dev->device); + + if (amcc) { unsigned long base = pci_resource_start(dev, 0); if (base) { u32 tmp; @@ -1315,14 +1294,10 @@ static int pci_quatech_setup(struct serial_private *priv, port->port.uartclk = pci_quatech_clock(port); /* For now just warn about RS422 */ if (pci_quatech_rs422(port)) - pr_warn("quatech: software control of RS422 features not currently supported.\n"); + pci_warn(priv->dev, "software control of RS422 features not currently supported.\n"); return pci_default_setup(priv, board, port, idx); } -static void pci_quatech_exit(struct pci_dev *dev) -{ -} - static int pci_default_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) @@ -1525,7 +1500,7 @@ static int pci_fintek_setup(struct serial_private *priv, /* Get the io address from configuration space */ pci_read_config_word(pdev, config_base + 4, &iobase); - dev_dbg(&pdev->dev, "%s: idx=%d iobase=0x%x", __func__, idx, iobase); + pci_dbg(pdev, "idx=%d iobase=0x%x", idx, iobase); port->port.iotype = UPIO_PORT; port->port.iobase = iobase; @@ -1689,7 +1664,7 @@ static int skip_tx_en_setup(struct serial_private *priv, struct uart_8250_port *port, int idx) { port->port.quirks |= UPQ_NO_TXEN_TEST; - dev_dbg(&priv->dev->dev, + pci_dbg(priv->dev, "serial8250: skipping TxEn test for device [%04x:%04x] subsystem [%04x:%04x]\n", priv->dev->vendor, priv->dev->device, priv->dev->subsystem_vendor, priv->dev->subsystem_device); @@ -2197,7 +2172,6 @@ static struct pci_serial_quirk pci_serial_quirks[] = { .subdevice = PCI_ANY_ID, .init = pci_quatech_init, .setup = pci_quatech_setup, - .exit = pci_quatech_exit, }, /* * Panacom @@ -3981,9 +3955,7 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board) nr_ports = rc; } - priv = kzalloc(sizeof(struct serial_private) + - sizeof(unsigned int) * nr_ports, - GFP_KERNEL); + priv = kzalloc(struct_size(priv, line, nr_ports), GFP_KERNEL); if (!priv) { priv = ERR_PTR(-ENOMEM); goto err_deinit; @@ -4000,12 +3972,12 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board) uart.port.irq = 0; } else { if (pci_match_id(pci_use_msi, dev)) { - dev_dbg(&dev->dev, "Using MSI(-X) interrupts\n"); + pci_dbg(dev, "Using MSI(-X) interrupts\n"); pci_set_master(dev); uart.port.flags &= ~UPF_SHARE_IRQ; rc = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_ALL_TYPES); } else { - dev_dbg(&dev->dev, "Using legacy interrupts\n"); + pci_dbg(dev, "Using legacy interrupts\n"); rc = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_LEGACY); } if (rc < 0) { @@ -4023,12 +3995,12 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board) if (quirk->setup(priv, board, &uart, i)) break; - dev_dbg(&dev->dev, "Setup PCI port: port %lx, irq %d, type %d\n", + 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) { - dev_err(&dev->dev, + pci_err(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]); @@ -4124,8 +4096,7 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) } if (ent->driver_data >= ARRAY_SIZE(pci_boards)) { - dev_err(&dev->dev, "invalid driver_data: %ld\n", - ent->driver_data); + pci_err(dev, "invalid driver_data: %ld\n", ent->driver_data); return -EINVAL; } @@ -4208,7 +4179,7 @@ static int pciserial_resume_one(struct device *dev) err = pci_enable_device(pdev); /* FIXME: We cannot simply error out here */ if (err) - dev_err(dev, "Unable to re-enable ports, trying to continue.\n"); + pci_err(pdev, "Unable to re-enable ports, trying to continue.\n"); pciserial_resume_ports(priv); } return 0; diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c index 98e5ee4d0d08..1974bbadc975 100644 --- a/drivers/tty/serial/8250/8250_pnp.c +++ b/drivers/tty/serial/8250/8250_pnp.c @@ -56,10 +56,6 @@ static const struct pnp_device_id pnp_dev_table[] = { { "BRI1400", 0 }, /* Boca 33.6 Kbps Internal FD34FSVD */ { "BRI3400", 0 }, - /* Boca 33.6 Kbps Internal FD34FSVD */ - { "BRI0A49", 0 }, - /* Best Data Products Inc. Smart One 336F PnP Modem */ - { "BDP3336", 0 }, /* Computer Peripherals Inc */ /* EuroViVa CommCenter-33.6 SP PnP */ { "CPI4050", 0 }, diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 66374704747e..5775cbff8f6e 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1338,7 +1338,7 @@ static void autoconfig(struct uart_8250_port *up) up->tx_loadsz = uart_config[port->type].tx_loadsz; if (port->type == PORT_UNKNOWN) - goto out_lock; + goto out_unlock; /* * Reset the UART. @@ -1355,7 +1355,7 @@ static void autoconfig(struct uart_8250_port *up) else serial_out(up, UART_IER, 0); -out_lock: +out_unlock: spin_unlock_irqrestore(&port->lock, flags); /* @@ -2696,21 +2696,32 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port, void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk) { struct uart_8250_port *up = up_to_u8250p(port); + struct tty_port *tport = &port->state->port; unsigned int baud, quot, frac = 0; struct ktermios *termios; + struct tty_struct *tty; unsigned long flags; - mutex_lock(&port->state->port.mutex); + tty = tty_port_tty_get(tport); + if (!tty) { + mutex_lock(&tport->mutex); + port->uartclk = uartclk; + mutex_unlock(&tport->mutex); + return; + } + + down_write(&tty->termios_rwsem); + mutex_lock(&tport->mutex); if (port->uartclk == uartclk) - goto out_lock; + goto out_unlock; port->uartclk = uartclk; - if (!tty_port_initialized(&port->state->port)) - goto out_lock; + if (!tty_port_initialized(tport)) + goto out_unlock; - termios = &port->state->port.tty->termios; + termios = &tty->termios; baud = serial8250_get_baud_rate(port, termios, NULL); quot = serial8250_get_divisor(port, baud, &frac); @@ -2726,8 +2737,10 @@ void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk) spin_unlock_irqrestore(&port->lock, flags); serial8250_rpm_put(up); -out_lock: - mutex_unlock(&port->state->port.mutex); +out_unlock: + mutex_unlock(&tport->mutex); + up_write(&tty->termios_rwsem); + tty_kref_put(tty); } EXPORT_SYMBOL_GPL(serial8250_update_uartclk); diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index 71ae16de0f90..8cd11aa63ed5 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -361,9 +361,13 @@ config SERIAL_8250_BCM2835AUX If unsure, say N. config SERIAL_8250_FSL - bool + bool "Freescale 16550 UART support" if COMPILE_TEST && !(PPC || ARM || ARM64) depends on SERIAL_8250_CONSOLE - default PPC || ARM || ARM64 || COMPILE_TEST + default PPC || ARM || ARM64 + help + Selecting this option enables a workaround for a break-detection + erratum for Freescale 16550 UARTs in the 8250 driver. It also + enables support for ACPI enumeration. config SERIAL_8250_DW tristate "Support for Synopsys DesignWare 8250 quirks" @@ -376,7 +380,7 @@ config SERIAL_8250_DW config SERIAL_8250_EM tristate "Support for Emma Mobile integrated serial port" depends on SERIAL_8250 && HAVE_CLK - depends on ARM || COMPILE_TEST + depends on (ARM && ARCH_RENESAS) || COMPILE_TEST help Selecting this option will add support for the integrated serial port hardware found on the Emma Mobile line of processors. diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 131a6a587acd..6ff94cfcd9db 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -239,10 +239,11 @@ config SERIAL_SAMSUNG depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || ARCH_APPLE || COMPILE_TEST select SERIAL_CORE help - Support for the on-chip UARTs on the Samsung S3C24XX series CPUs, - providing /dev/ttySAC0, 1 and 2 (note, some machines may not - provide all of these ports, depending on how the serial port - pins are configured. + Support for the on-chip UARTs on the Samsung + S3C24xx/S3C64xx/S5Pv210/Exynos and Apple M1 SoCs, providing + /dev/ttySAC0, 1 and 2 (note, some machines may not provide all of + these ports, depending on how the serial port pins are configured. + Choose Y/M here only if you build for such SoC. config SERIAL_SAMSUNG_UARTS_4 bool diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 249ea35088d2..2c99a47a2535 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -2084,7 +2084,7 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state, struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); switch (state) { - case 0: + case UART_PM_STATE_ON: /* * Enable the peripheral clock for this serial port. * This is called on uart_open() or a resume event. @@ -2094,7 +2094,7 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state, /* re-enable interrupts if we disabled some on suspend */ atmel_uart_writel(port, ATMEL_US_IER, atmel_port->backup_imr); break; - case 3: + case UART_PM_STATE_OFF: /* Back up the interrupt mask and disable all interrupts */ atmel_port->backup_imr = atmel_uart_readl(port, ATMEL_US_IMR); atmel_uart_writel(port, ATMEL_US_IDR, -1); diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c index c719aa2b1832..d6d3db9c3b1f 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c @@ -1090,6 +1090,7 @@ static void cpm_put_poll_char(struct uart_port *port, cpm_uart_early_write(pinfo, ch, 1, false); } +#ifdef CONFIG_SERIAL_CPM_CONSOLE static struct uart_port *udbg_port; static void udbg_cpm_putc(char c) @@ -1114,6 +1115,7 @@ static int udbg_cpm_getc(void) cpu_relax(); return c; } +#endif /* CONFIG_SERIAL_CPM_CONSOLE */ #endif /* CONFIG_CONSOLE_POLL */ diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 8b121cd869e9..90f82e6c54e4 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -2017,7 +2017,7 @@ imx_uart_console_write(struct console *co, const char *s, unsigned int count) * If the port was already initialised (eg, by a boot loader), * try to determine the current setup. */ -static void __init +static void imx_uart_console_get_options(struct imx_port *sport, int *baud, int *parity, int *bits) { @@ -2076,7 +2076,7 @@ imx_uart_console_get_options(struct imx_port *sport, int *baud, } } -static int __init +static int imx_uart_console_setup(struct console *co, char *options) { struct imx_port *sport; @@ -2124,12 +2124,24 @@ error_console: return retval; } +static int +imx_uart_console_exit(struct console *co) +{ + struct imx_port *sport = imx_uart_ports[co->index]; + + clk_disable_unprepare(sport->clk_per); + clk_disable_unprepare(sport->clk_ipg); + + return 0; +} + static struct uart_driver imx_uart_uart_driver; static struct console imx_uart_console = { .name = DEV_NAME, .write = imx_uart_console_write, .device = uart_console_device, .setup = imx_uart_console_setup, + .exit = imx_uart_console_exit, .flags = CON_PRINTBUFFER, .index = -1, .data = &imx_uart_uart_driver, diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 3df0788ddeb0..dde0824b2fa5 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1426,7 +1426,7 @@ out_clk: return ret; } -static int max310x_remove(struct device *dev) +static void max310x_remove(struct device *dev) { struct max310x_port *s = dev_get_drvdata(dev); int i; @@ -1441,8 +1441,6 @@ static int max310x_remove(struct device *dev) } clk_disable_unprepare(s->clk); - - return 0; } static const struct of_device_id __maybe_unused max310x_dt_ids[] = { @@ -1491,7 +1489,8 @@ static int max310x_spi_probe(struct spi_device *spi) static int max310x_spi_remove(struct spi_device *spi) { - return max310x_remove(&spi->dev); + max310x_remove(&spi->dev); + return 0; } static const struct spi_device_id max310x_id_table[] = { diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c index 231de29a6452..ab226da75f7b 100644 --- a/drivers/tty/serial/mvebu-uart.c +++ b/drivers/tty/serial/mvebu-uart.c @@ -163,7 +163,7 @@ static unsigned int mvebu_uart_tx_empty(struct uart_port *port) st = readl(port->membase + UART_STAT); spin_unlock_irqrestore(&port->lock, flags); - return (st & STAT_TX_FIFO_EMP) ? TIOCSER_TEMT : 0; + return (st & STAT_TX_EMP) ? TIOCSER_TEMT : 0; } static unsigned int mvebu_uart_get_mctrl(struct uart_port *port) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index e2f49863e9c2..ca084c10d0bb 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -65,7 +65,7 @@ enum s3c24xx_port_type { struct s3c24xx_uart_info { char *name; enum s3c24xx_port_type type; - unsigned int has_usi; + bool has_usi; unsigned int port_type; unsigned int fifosize; unsigned long rx_fifomask; @@ -2780,7 +2780,7 @@ static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = { #endif #if defined(CONFIG_ARCH_EXYNOS) -#define EXYNOS_COMMON_SERIAL_DRV_DATA_USI(_has_usi) \ +#define EXYNOS_COMMON_SERIAL_DRV_DATA(_has_usi) \ .info = &(struct s3c24xx_uart_info) { \ .name = "Samsung Exynos UART", \ .type = TYPE_S3C6400, \ @@ -2804,21 +2804,18 @@ static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = { .has_fracval = 1, \ } \ -#define EXYNOS_COMMON_SERIAL_DRV_DATA \ - EXYNOS_COMMON_SERIAL_DRV_DATA_USI(0) - static struct s3c24xx_serial_drv_data exynos4210_serial_drv_data = { - EXYNOS_COMMON_SERIAL_DRV_DATA, + EXYNOS_COMMON_SERIAL_DRV_DATA(false), .fifosize = { 256, 64, 16, 16 }, }; static struct s3c24xx_serial_drv_data exynos5433_serial_drv_data = { - EXYNOS_COMMON_SERIAL_DRV_DATA, + EXYNOS_COMMON_SERIAL_DRV_DATA(false), .fifosize = { 64, 256, 16, 256 }, }; static struct s3c24xx_serial_drv_data exynos850_serial_drv_data = { - EXYNOS_COMMON_SERIAL_DRV_DATA_USI(1), + EXYNOS_COMMON_SERIAL_DRV_DATA(true), .fifosize = { 256, 64, 64, 64 }, }; diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index acbb615dd28f..64e7e6c8145f 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -1365,7 +1365,7 @@ out_clk: return ret; } -static int sc16is7xx_remove(struct device *dev) +static void sc16is7xx_remove(struct device *dev) { struct sc16is7xx_port *s = dev_get_drvdata(dev); int i; @@ -1385,8 +1385,6 @@ static int sc16is7xx_remove(struct device *dev) kthread_stop(s->kworker_task); clk_disable_unprepare(s->clk); - - return 0; } static const struct of_device_id __maybe_unused sc16is7xx_dt_ids[] = { @@ -1444,7 +1442,9 @@ static int sc16is7xx_spi_probe(struct spi_device *spi) static int sc16is7xx_spi_remove(struct spi_device *spi) { - return sc16is7xx_remove(&spi->dev); + sc16is7xx_remove(&spi->dev); + + return 0; } static const struct spi_device_id sc16is7xx_spi_id_table[] = { @@ -1497,7 +1497,9 @@ static int sc16is7xx_i2c_probe(struct i2c_client *i2c, static int sc16is7xx_i2c_remove(struct i2c_client *client) { - return sc16is7xx_remove(&client->dev); + sc16is7xx_remove(&client->dev); + + return 0; } static const struct i2c_device_id sc16is7xx_i2c_id_table[] = { diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 0e2e35ab64c7..1e738f265eea 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -222,7 +222,11 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, if (retval == 0) { if (uart_console(uport) && uport->cons->cflag) { tty->termios.c_cflag = uport->cons->cflag; + tty->termios.c_ispeed = uport->cons->ispeed; + tty->termios.c_ospeed = uport->cons->ospeed; uport->cons->cflag = 0; + uport->cons->ispeed = 0; + uport->cons->ospeed = 0; } /* * Initialise the hardware port settings. @@ -290,8 +294,11 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) /* * Turn off DTR and RTS early. */ - if (uport && uart_console(uport) && tty) + if (uport && uart_console(uport) && tty) { uport->cons->cflag = tty->termios.c_cflag; + uport->cons->ispeed = tty->termios.c_ispeed; + uport->cons->ospeed = tty->termios.c_ospeed; + } if (!tty || C_HUPCL(tty)) uart_port_dtr_rts(uport, 0); @@ -2094,8 +2101,11 @@ uart_set_options(struct uart_port *port, struct console *co, * Allow the setting of the UART parameters with a NULL console * too: */ - if (co) + if (co) { co->cflag = termios.c_cflag; + co->ispeed = termios.c_ispeed; + co->ospeed = termios.c_ospeed; + } return 0; } @@ -2229,6 +2239,8 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) */ memset(&termios, 0, sizeof(struct ktermios)); termios.c_cflag = uport->cons->cflag; + termios.c_ispeed = uport->cons->ispeed; + termios.c_ospeed = uport->cons->ospeed; /* * If that's unset, use the tty termios setting. diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c index 0ac0371f943b..b79900d0e91a 100644 --- a/drivers/tty/serial/sifive.c +++ b/drivers/tty/serial/sifive.c @@ -887,7 +887,7 @@ static void __ssp_add_console_port(struct sifive_serial_port *ssp) static void __ssp_remove_console_port(struct sifive_serial_port *ssp) { - sifive_serial_console_ports[ssp->port.line] = 0; + sifive_serial_console_ports[ssp->port.line] = NULL; } #define SIFIVE_SERIAL_CONSOLE (&sifive_serial_console) diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 8f032e77b954..3244e7f6818c 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -165,63 +165,61 @@ static int stm32_usart_init_rs485(struct uart_port *port, return uart_get_rs485_mode(port); } -static int stm32_usart_pending_rx(struct uart_port *port, u32 *sr, - int *last_res, bool threaded) +static bool stm32_usart_rx_dma_enabled(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - enum dma_status status; - struct dma_tx_state state; - *sr = readl_relaxed(port->membase + ofs->isr); + if (!stm32_port->rx_ch) + return false; - if (threaded && stm32_port->rx_ch) { - status = dmaengine_tx_status(stm32_port->rx_ch, - stm32_port->rx_ch->cookie, - &state); - if (status == DMA_IN_PROGRESS && (*last_res != state.residue)) - return 1; - else - return 0; - } else if (*sr & USART_SR_RXNE) { - return 1; + return !!(readl_relaxed(port->membase + ofs->cr3) & USART_CR3_DMAR); +} + +/* Return true when data is pending (in pio mode), and false when no data is pending. */ +static bool stm32_usart_pending_rx_pio(struct uart_port *port, u32 *sr) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + + *sr = readl_relaxed(port->membase + ofs->isr); + /* Get pending characters in RDR or FIFO */ + if (*sr & USART_SR_RXNE) { + /* Get all pending characters from the RDR or the FIFO when using interrupts */ + if (!stm32_usart_rx_dma_enabled(port)) + return true; + + /* Handle only RX data errors when using DMA */ + if (*sr & USART_SR_ERR_MASK) + return true; } - return 0; + + return false; } -static unsigned long stm32_usart_get_char(struct uart_port *port, u32 *sr, - int *last_res) +static unsigned long stm32_usart_get_char_pio(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; unsigned long c; - if (stm32_port->rx_ch) { - c = stm32_port->rx_buf[RX_BUF_L - (*last_res)--]; - if ((*last_res) == 0) - *last_res = RX_BUF_L; - } else { - c = readl_relaxed(port->membase + ofs->rdr); - /* apply RDR data mask */ - c &= stm32_port->rdr_mask; - } + c = readl_relaxed(port->membase + ofs->rdr); + /* Apply RDR data mask */ + c &= stm32_port->rdr_mask; return c; } -static void stm32_usart_receive_chars(struct uart_port *port, bool threaded) +static unsigned int stm32_usart_receive_chars_pio(struct uart_port *port) { - struct tty_port *tport = &port->state->port; struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; unsigned long c; + unsigned int size = 0; u32 sr; char flag; - spin_lock(&port->lock); - - while (stm32_usart_pending_rx(port, &sr, &stm32_port->last_res, - threaded)) { + while (stm32_usart_pending_rx_pio(port, &sr)) { sr |= USART_SR_DUMMY_RX; flag = TTY_NORMAL; @@ -240,8 +238,9 @@ static void stm32_usart_receive_chars(struct uart_port *port, bool threaded) writel_relaxed(sr & USART_SR_ERR_MASK, port->membase + ofs->icr); - c = stm32_usart_get_char(port, &sr, &stm32_port->last_res); + c = stm32_usart_get_char_pio(port); port->icount.rx++; + size++; if (sr & USART_SR_ERR_MASK) { if (sr & USART_SR_ORE) { port->icount.overrun++; @@ -275,9 +274,95 @@ static void stm32_usart_receive_chars(struct uart_port *port, bool threaded) uart_insert_char(port, sr, USART_SR_ORE, c, flag); } - uart_unlock_and_check_sysrq(port); + return size; +} + +static void stm32_usart_push_buffer_dma(struct uart_port *port, unsigned int dma_size) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + struct tty_port *ttyport = &stm32_port->port.state->port; + unsigned char *dma_start; + int dma_count, i; - tty_flip_buffer_push(tport); + dma_start = stm32_port->rx_buf + (RX_BUF_L - stm32_port->last_res); + + /* + * Apply rdr_mask on buffer in order to mask parity bit. + * This loop is useless in cs8 mode because DMA copies only + * 8 bits and already ignores parity bit. + */ + if (!(stm32_port->rdr_mask == (BIT(8) - 1))) + for (i = 0; i < dma_size; i++) + *(dma_start + i) &= stm32_port->rdr_mask; + + dma_count = tty_insert_flip_string(ttyport, dma_start, dma_size); + port->icount.rx += dma_count; + if (dma_count != dma_size) + port->icount.buf_overrun++; + stm32_port->last_res -= dma_count; + if (stm32_port->last_res == 0) + stm32_port->last_res = RX_BUF_L; +} + +static unsigned int stm32_usart_receive_chars_dma(struct uart_port *port) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + unsigned int dma_size, size = 0; + + /* DMA buffer is configured in cyclic mode and handles the rollback of the buffer. */ + if (stm32_port->rx_dma_state.residue > stm32_port->last_res) { + /* Conditional first part: from last_res to end of DMA buffer */ + dma_size = stm32_port->last_res; + stm32_usart_push_buffer_dma(port, dma_size); + size = dma_size; + } + + dma_size = stm32_port->last_res - stm32_port->rx_dma_state.residue; + stm32_usart_push_buffer_dma(port, dma_size); + size += dma_size; + + return size; +} + +static unsigned int stm32_usart_receive_chars(struct uart_port *port, bool force_dma_flush) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + enum dma_status rx_dma_status; + u32 sr; + unsigned int size = 0; + + if (stm32_usart_rx_dma_enabled(port) || force_dma_flush) { + rx_dma_status = dmaengine_tx_status(stm32_port->rx_ch, + stm32_port->rx_ch->cookie, + &stm32_port->rx_dma_state); + if (rx_dma_status == DMA_IN_PROGRESS) { + /* Empty DMA buffer */ + size = stm32_usart_receive_chars_dma(port); + sr = readl_relaxed(port->membase + ofs->isr); + if (sr & USART_SR_ERR_MASK) { + /* Disable DMA request line */ + stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); + + /* Switch to PIO mode to handle the errors */ + size += stm32_usart_receive_chars_pio(port); + + /* Switch back to DMA mode */ + stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAR); + } + } else { + /* Disable RX DMA */ + dmaengine_terminate_async(stm32_port->rx_ch); + stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); + /* Fall back to interrupt mode */ + dev_dbg(port->dev, "DMA error, fallback to irq mode\n"); + size = stm32_usart_receive_chars_pio(port); + } + } else { + size = stm32_usart_receive_chars_pio(port); + } + + return size; } static void stm32_usart_tx_dma_complete(void *arg) @@ -312,6 +397,20 @@ static void stm32_usart_tx_interrupt_enable(struct uart_port *port) stm32_usart_set_bits(port, ofs->cr1, USART_CR1_TXEIE); } +static void stm32_usart_rx_dma_complete(void *arg) +{ + struct uart_port *port = arg; + struct tty_port *tport = &port->state->port; + unsigned int size; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + size = stm32_usart_receive_chars(port, false); + uart_unlock_and_check_sysrq_irqrestore(port, flags); + if (size) + tty_flip_buffer_push(tport); +} + static void stm32_usart_tx_interrupt_disable(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); @@ -462,6 +561,7 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; u32 sr; + unsigned int size; sr = readl_relaxed(port->membase + ofs->isr); @@ -478,8 +578,20 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) pm_wakeup_event(tport->tty->dev, 0); } - if ((sr & USART_SR_RXNE) && !(stm32_port->rx_ch)) - stm32_usart_receive_chars(port, false); + /* + * rx errors in dma mode has to be handled ASAP to avoid overrun as the DMA request + * line has been masked by HW and rx data are stacking in FIFO. + */ + if (!stm32_port->throttled) { + if (((sr & USART_SR_RXNE) && !stm32_usart_rx_dma_enabled(port)) || + ((sr & USART_SR_ERR_MASK) && stm32_usart_rx_dma_enabled(port))) { + spin_lock(&port->lock); + size = stm32_usart_receive_chars(port, false); + uart_unlock_and_check_sysrq(port); + if (size) + tty_flip_buffer_push(tport); + } + } if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch)) { spin_lock(&port->lock); @@ -487,7 +599,7 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) spin_unlock(&port->lock); } - if (stm32_port->rx_ch) + if (stm32_usart_rx_dma_enabled(port)) return IRQ_WAKE_THREAD; else return IRQ_HANDLED; @@ -496,10 +608,19 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) static irqreturn_t stm32_usart_threaded_interrupt(int irq, void *ptr) { struct uart_port *port = ptr; + struct tty_port *tport = &port->state->port; struct stm32_port *stm32_port = to_stm32_port(port); + unsigned int size; + unsigned long flags; - if (stm32_port->rx_ch) - stm32_usart_receive_chars(port, true); + /* Receiver timeout irq for DMA RX */ + if (!stm32_port->throttled) { + spin_lock_irqsave(&port->lock, flags); + size = stm32_usart_receive_chars(port, false); + uart_unlock_and_check_sysrq_irqrestore(port, flags); + if (size) + tty_flip_buffer_push(tport); + } return IRQ_HANDLED; } @@ -612,10 +733,19 @@ static void stm32_usart_throttle(struct uart_port *port) unsigned long flags; spin_lock_irqsave(&port->lock, flags); + + /* + * Disable DMA request line if enabled, so the RX data gets queued into the FIFO. + * Hardware flow control is triggered when RX FIFO is full. + */ + if (stm32_usart_rx_dma_enabled(port)) + stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); + stm32_usart_clr_bits(port, ofs->cr1, stm32_port->cr1_irq); if (stm32_port->cr3_irq) stm32_usart_clr_bits(port, ofs->cr3, stm32_port->cr3_irq); + stm32_port->throttled = true; spin_unlock_irqrestore(&port->lock, flags); } @@ -631,6 +761,14 @@ static void stm32_usart_unthrottle(struct uart_port *port) if (stm32_port->cr3_irq) stm32_usart_set_bits(port, ofs->cr3, stm32_port->cr3_irq); + /* + * Switch back to DMA mode (re-enable DMA request line). + * Hardware flow control is stopped when FIFO is not full any more. + */ + if (stm32_port->rx_ch) + stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAR); + + stm32_port->throttled = false; spin_unlock_irqrestore(&port->lock, flags); } @@ -640,6 +778,10 @@ static void stm32_usart_stop_rx(struct uart_port *port) struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + /* Disable DMA request line. */ + if (stm32_port->rx_ch) + stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); + stm32_usart_clr_bits(port, ofs->cr1, stm32_port->cr1_irq); if (stm32_port->cr3_irq) stm32_usart_clr_bits(port, ofs->cr3, stm32_port->cr3_irq); @@ -650,6 +792,48 @@ static void stm32_usart_break_ctl(struct uart_port *port, int break_state) { } +static int stm32_usart_start_rx_dma_cyclic(struct uart_port *port) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + struct dma_async_tx_descriptor *desc; + int ret; + + stm32_port->last_res = RX_BUF_L; + /* Prepare a DMA cyclic transaction */ + desc = dmaengine_prep_dma_cyclic(stm32_port->rx_ch, + stm32_port->rx_dma_buf, + RX_BUF_L, RX_BUF_P, + DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT); + if (!desc) { + dev_err(port->dev, "rx dma prep cyclic failed\n"); + return -ENODEV; + } + + desc->callback = stm32_usart_rx_dma_complete; + desc->callback_param = port; + + /* Push current DMA transaction in the pending queue */ + ret = dma_submit_error(dmaengine_submit(desc)); + if (ret) { + dmaengine_terminate_sync(stm32_port->rx_ch); + return ret; + } + + /* Issue pending DMA requests */ + dma_async_issue_pending(stm32_port->rx_ch); + + /* + * DMA request line not re-enabled at resume when port is throttled. + * It will be re-enabled by unthrottle ops. + */ + if (!stm32_port->throttled) + stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAR); + + return 0; +} + static int stm32_usart_startup(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); @@ -676,6 +860,14 @@ static int stm32_usart_startup(struct uart_port *port) if (ofs->rqr != UNDEF_REG) writel_relaxed(USART_RQR_RXFRQ, port->membase + ofs->rqr); + if (stm32_port->rx_ch) { + ret = stm32_usart_start_rx_dma_cyclic(port); + if (ret) { + free_irq(port->irq, port); + return ret; + } + } + /* RX enabling */ val = stm32_port->cr1_irq | USART_CR1_RE | BIT(cfg->uart_enable_bit); stm32_usart_set_bits(port, ofs->cr1, val); @@ -708,6 +900,10 @@ static void stm32_usart_shutdown(struct uart_port *port) if (ret) dev_err(port->dev, "Transmission is not complete\n"); + /* Disable RX DMA. */ + if (stm32_port->rx_ch) + dmaengine_terminate_async(stm32_port->rx_ch); + /* flush RX & TX FIFO */ if (ofs->rqr != UNDEF_REG) writel_relaxed(USART_RQR_TXFRQ | USART_RQR_RXFRQ, @@ -810,9 +1006,11 @@ static void stm32_usart_set_termios(struct uart_port *port, stm32_port->cr1_irq = USART_CR1_RTOIE; writel_relaxed(bits, port->membase + ofs->rtor); cr2 |= USART_CR2_RTOEN; - /* Not using dma, enable fifo threshold irq */ - if (!stm32_port->rx_ch) - stm32_port->cr3_irq = USART_CR3_RXFTIE; + /* + * Enable fifo threshold irq in two cases, either when there is no DMA, or when + * wake up over usart, from low power until the DMA gets re-enabled by resume. + */ + stm32_port->cr3_irq = USART_CR3_RXFTIE; } cr1 |= stm32_port->cr1_irq; @@ -875,8 +1073,16 @@ static void stm32_usart_set_termios(struct uart_port *port, if ((termios->c_cflag & CREAD) == 0) port->ignore_status_mask |= USART_SR_DUMMY_RX; - if (stm32_port->rx_ch) + if (stm32_port->rx_ch) { + /* + * Setup DMA to collect only valid data and enable error irqs. + * This also enables break reception when using DMA. + */ + cr1 |= USART_CR1_PEIE; + cr3 |= USART_CR3_EIE; cr3 |= USART_CR3_DMAR; + cr3 |= USART_CR3_DDRE; + } if (rs485conf->flags & SER_RS485_ENABLED) { stm32_usart_config_reg_rs485(&cr1, &cr3, @@ -1166,7 +1372,6 @@ static int stm32_usart_of_dma_rx_probe(struct stm32_port *stm32port, struct uart_port *port = &stm32port->port; struct device *dev = &pdev->dev; struct dma_slave_config config; - struct dma_async_tx_descriptor *desc = NULL; int ret; /* @@ -1194,32 +1399,6 @@ static int stm32_usart_of_dma_rx_probe(struct stm32_port *stm32port, return ret; } - /* Prepare a DMA cyclic transaction */ - desc = dmaengine_prep_dma_cyclic(stm32port->rx_ch, - stm32port->rx_dma_buf, - RX_BUF_L, RX_BUF_P, DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT); - if (!desc) { - dev_err(dev, "rx dma prep cyclic failed\n"); - stm32_usart_of_dma_rx_remove(stm32port, pdev); - return -ENODEV; - } - - /* No callback as dma buffer is drained on usart interrupt */ - desc->callback = NULL; - desc->callback_param = NULL; - - /* Push current DMA transaction in the pending queue */ - ret = dma_submit_error(dmaengine_submit(desc)); - if (ret) { - dmaengine_terminate_sync(stm32port->rx_ch); - stm32_usart_of_dma_rx_remove(stm32port, pdev); - return ret; - } - - /* Issue pending DMA requests */ - dma_async_issue_pending(stm32port->rx_ch); - return 0; } @@ -1372,6 +1551,7 @@ static int stm32_usart_serial_remove(struct platform_device *pdev) struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; int err; + u32 cr3; pm_runtime_get_sync(&pdev->dev); err = uart_remove_one_port(&stm32_usart_driver, port); @@ -1382,7 +1562,12 @@ static int stm32_usart_serial_remove(struct platform_device *pdev) pm_runtime_set_suspended(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); - stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); + stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_PEIE); + cr3 = readl_relaxed(port->membase + ofs->cr3); + cr3 &= ~USART_CR3_EIE; + cr3 &= ~USART_CR3_DMAR; + cr3 &= ~USART_CR3_DDRE; + writel_relaxed(cr3, port->membase + ofs->cr3); if (stm32_port->tx_ch) { dmaengine_terminate_async(stm32_port->tx_ch); @@ -1391,7 +1576,6 @@ static int stm32_usart_serial_remove(struct platform_device *pdev) } if (stm32_port->rx_ch) { - dmaengine_terminate_async(stm32_port->rx_ch); stm32_usart_of_dma_rx_remove(stm32_port, pdev); dma_release_channel(stm32_port->rx_ch); } @@ -1504,14 +1688,18 @@ static struct uart_driver stm32_usart_driver = { .cons = STM32_SERIAL_CONSOLE, }; -static void __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port, - bool enable) +static int __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port, + bool enable) { struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + struct tty_port *tport = &port->state->port; + int ret; + unsigned int size; + unsigned long flags; - if (!stm32_port->wakeup_src) - return; + if (!stm32_port->wakeup_src || !tty_port_initialized(tport)) + return 0; /* * Enable low-power wake-up and wake-up irq if argument is set to @@ -1520,20 +1708,52 @@ static void __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port, if (enable) { stm32_usart_set_bits(port, ofs->cr1, USART_CR1_UESM); stm32_usart_set_bits(port, ofs->cr3, USART_CR3_WUFIE); + + /* + * When DMA is used for reception, it must be disabled before + * entering low-power mode and re-enabled when exiting from + * low-power mode. + */ + if (stm32_port->rx_ch) { + spin_lock_irqsave(&port->lock, flags); + /* Avoid race with RX IRQ when DMAR is cleared */ + stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); + /* Poll data from DMA RX buffer if any */ + size = stm32_usart_receive_chars(port, true); + dmaengine_terminate_async(stm32_port->rx_ch); + uart_unlock_and_check_sysrq_irqrestore(port, flags); + if (size) + tty_flip_buffer_push(tport); + } + + /* Poll data from RX FIFO if any */ + stm32_usart_receive_chars(port, false); } else { + if (stm32_port->rx_ch) { + ret = stm32_usart_start_rx_dma_cyclic(port); + if (ret) + return ret; + } + stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_UESM); stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_WUFIE); } + + return 0; } static int __maybe_unused stm32_usart_serial_suspend(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); + int ret; uart_suspend_port(&stm32_usart_driver, port); - if (device_may_wakeup(dev) || device_wakeup_path(dev)) - stm32_usart_serial_en_wakeup(port, true); + if (device_may_wakeup(dev) || device_wakeup_path(dev)) { + ret = stm32_usart_serial_en_wakeup(port, true); + if (ret) + return ret; + } /* * When "no_console_suspend" is enabled, keep the pinctrl default state @@ -1554,11 +1774,15 @@ static int __maybe_unused stm32_usart_serial_suspend(struct device *dev) static int __maybe_unused stm32_usart_serial_resume(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); + int ret; pinctrl_pm_select_default_state(dev); - if (device_may_wakeup(dev) || device_wakeup_path(dev)) - stm32_usart_serial_en_wakeup(port, false); + if (device_may_wakeup(dev) || device_wakeup_path(dev)) { + ret = stm32_usart_serial_en_wakeup(port, false); + if (ret) + return ret; + } return uart_resume_port(&stm32_usart_driver, port); } diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h index 07ac291328cd..e23916bfbb60 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -109,7 +109,7 @@ struct stm32_usart_info stm32h7_info = { /* USART_SR (F4) / USART_ISR (F7) */ #define USART_SR_PE BIT(0) #define USART_SR_FE BIT(1) -#define USART_SR_NF BIT(2) +#define USART_SR_NE BIT(2) /* F7 (NF for F4) */ #define USART_SR_ORE BIT(3) #define USART_SR_IDLE BIT(4) #define USART_SR_RXNE BIT(5) @@ -126,7 +126,8 @@ struct stm32_usart_info stm32h7_info = { #define USART_SR_SBKF BIT(18) /* F7 */ #define USART_SR_WUF BIT(20) /* H7 */ #define USART_SR_TEACK BIT(21) /* F7 */ -#define USART_SR_ERR_MASK (USART_SR_ORE | USART_SR_FE | USART_SR_PE) +#define USART_SR_ERR_MASK (USART_SR_ORE | USART_SR_NE | USART_SR_FE |\ + USART_SR_PE) /* Dummy bits */ #define USART_SR_DUMMY_RX BIT(16) @@ -246,9 +247,9 @@ struct stm32_usart_info stm32h7_info = { #define STM32_SERIAL_NAME "ttySTM" #define STM32_MAX_PORTS 8 -#define RX_BUF_L 200 /* dma rx buffer length */ -#define RX_BUF_P RX_BUF_L /* dma rx buffer period */ -#define TX_BUF_L 200 /* dma tx buffer length */ +#define RX_BUF_L 4096 /* dma rx buffer length */ +#define RX_BUF_P (RX_BUF_L / 2) /* dma rx buffer period */ +#define TX_BUF_L RX_BUF_L /* dma tx buffer length */ struct stm32_port { struct uart_port port; @@ -264,6 +265,7 @@ struct stm32_port { u32 cr3_irq; /* USART_CR3_RXFTIE */ int last_res; bool tx_dma_busy; /* dma tx busy */ + bool throttled; /* port throttled */ bool hw_flow_control; bool swap; /* swap RX & TX pins */ bool fifoen; @@ -272,6 +274,7 @@ struct stm32_port { bool wakeup_src; int rdr_mask; /* receive data register mask */ struct mctrl_gpios *gpios; /* modem control gpios */ + struct dma_tx_state rx_dma_state; }; static struct stm32_port stm32_ports[STM32_MAX_PORTS]; diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c index 1a54e3e52ed6..b714b00d2dad 100644 --- a/drivers/tty/serial/sunzilog.c +++ b/drivers/tty/serial/sunzilog.c @@ -1125,7 +1125,7 @@ static void sunzilog_free_tables(void) #define ZS_PUT_CHAR_MAX_DELAY 2000 /* 10 ms */ -static void sunzilog_putchar(struct uart_port *port, int ch) +static void __maybe_unused sunzilog_putchar(struct uart_port *port, int ch) { struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port); int loops = ZS_PUT_CHAR_MAX_DELAY; diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c index dfc1ba4e1572..d3d9566e5dbd 100644 --- a/drivers/tty/serial/uartlite.c +++ b/drivers/tty/serial/uartlite.c @@ -8,6 +8,7 @@ #include <linux/platform_device.h> #include <linux/module.h> +#include <linux/bitfield.h> #include <linux/console.h> #include <linux/serial.h> #include <linux/serial_core.h> @@ -63,9 +64,18 @@ static struct uart_port *console_port; #endif +/** + * struct uartlite_data: Driver private data + * reg_ops: Functions to read/write registers + * clk: Our parent clock, if present + * baud: The baud rate configured when this device was synthesized + * cflags: The cflags for parity and data bits + */ struct uartlite_data { const struct uartlite_reg_ops *reg_ops; struct clk *clk; + unsigned int baud; + tcflag_t cflags; }; struct uartlite_reg_ops { @@ -119,6 +129,8 @@ static inline void uart_out32(u32 val, u32 offset, struct uart_port *port) static struct uart_port ulite_ports[ULITE_NR_UARTS]; +static struct uart_driver ulite_uart_driver; + /* --------------------------------------------------------------------- * Core UART driver operations */ @@ -306,7 +318,12 @@ static void ulite_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { unsigned long flags; - unsigned int baud; + struct uartlite_data *pdata = port->private_data; + + /* Set termios to what the hardware supports */ + termios->c_cflag &= ~(BRKINT | CSTOPB | PARENB | PARODD | CSIZE); + termios->c_cflag |= pdata->cflags & (PARENB | PARODD | CSIZE); + tty_termios_encode_baud_rate(termios, pdata->baud, pdata->baud); spin_lock_irqsave(&port->lock, flags); @@ -329,8 +346,7 @@ static void ulite_set_termios(struct uart_port *port, struct ktermios *termios, | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN; /* update timeout */ - baud = uart_get_baud_rate(port, termios, old, 0, 460800); - uart_update_timeout(port, termios->c_cflag, baud); + uart_update_timeout(port, termios->c_cflag, pdata->baud); spin_unlock_irqrestore(&port->lock, flags); } @@ -532,8 +548,6 @@ static int ulite_console_setup(struct console *co, char *options) return uart_set_options(port, co, baud, parity, bits, flow); } -static struct uart_driver ulite_uart_driver; - static struct console ulite_console = { .name = ULITE_NAME, .write = ulite_console_write, @@ -765,18 +779,73 @@ static int ulite_probe(struct platform_device *pdev) struct uartlite_data *pdata; int irq, ret; int id = pdev->id; -#ifdef CONFIG_OF - const __be32 *prop; - prop = of_get_property(pdev->dev.of_node, "port-number", NULL); - if (prop) - id = be32_to_cpup(prop); -#endif pdata = devm_kzalloc(&pdev->dev, sizeof(struct uartlite_data), GFP_KERNEL); if (!pdata) return -ENOMEM; + if (IS_ENABLED(CONFIG_OF)) { + const char *prop; + struct device_node *np = pdev->dev.of_node; + u32 val = 0; + + prop = "port-number"; + ret = of_property_read_u32(np, prop, &id); + if (ret && ret != -EINVAL) +of_err: + return dev_err_probe(&pdev->dev, ret, + "could not read %s\n", prop); + + prop = "current-speed"; + ret = of_property_read_u32(np, prop, &pdata->baud); + if (ret) + goto of_err; + + prop = "xlnx,use-parity"; + ret = of_property_read_u32(np, prop, &val); + if (ret && ret != -EINVAL) + goto of_err; + + if (val) { + prop = "xlnx,odd-parity"; + ret = of_property_read_u32(np, prop, &val); + if (ret) + goto of_err; + + if (val) + pdata->cflags |= PARODD; + pdata->cflags |= PARENB; + } + + val = 8; + prop = "xlnx,data-bits"; + ret = of_property_read_u32(np, prop, &val); + if (ret && ret != -EINVAL) + goto of_err; + + switch (val) { + case 5: + pdata->cflags |= CS5; + break; + case 6: + pdata->cflags |= CS6; + break; + case 7: + pdata->cflags |= CS7; + break; + case 8: + pdata->cflags |= CS8; + break; + default: + return dev_err_probe(&pdev->dev, -EINVAL, + "bad data bits %d\n", val); + } + } else { + pdata->baud = 9600; + pdata->cflags = CS8; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENODEV; diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 962e522ccc45..d5e243908d9f 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -601,9 +601,10 @@ static void cdns_uart_start_tx(struct uart_port *port) if (uart_circ_empty(&port->state->xmit)) return; + writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_ISR); + cdns_uart_handle_tx(port); - writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_ISR); /* Enable the TX Empty interrupt */ writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IER); } |