Skip to content

Commit

Permalink
Merge tag 'tty-6.9-rc5' of git://git.kernel.org/pub/scm/linux/kernel/…
Browse files Browse the repository at this point in the history
…git/gregkh/tty

Pull tty/serial driver fixes from Greg KH:
 "Here are some small tty and serial driver fixes for 6.9-rc5 that
  resolve a bunch of reported problems. Included in here are:

   - MAINTAINERS and .mailmap update for Richard Genoud

   - serial core regression fixes from 6.9-rc1 changes

   - pci id cleanups

   - serial core crash fix

   - stm32 driver fixes

   - 8250 driver fixes

  All of these have been in linux-next for a while with no reported
  problems"

* tag 'tty-6.9-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
  serial: stm32: Reset .throttled state in .startup()
  serial: stm32: Return IRQ_NONE in the ISR if no handling happend
  serial: core: Fix missing shutdown and startup for serial base port
  serial: core: Clearing the circular buffer before NULLifying it
  MAINTAINERS: mailmap: update Richard Genoud's email address
  serial/pmac_zilog: Remove flawed mitigation for rx irq flood
  serial: 8250_pci: Remove redundant PCI IDs
  serial: core: Fix regression when runtime PM is not enabled
  serial: mxs-auart: add spinlock around changing cts state
  serial: 8250_dw: Revert: Do not reclock if already at correct rate
  serial: 8250_lpc18xx: disable clks on error in probe()
  • Loading branch information
torvalds committed Apr 21, 2024
2 parents 5fa0ab4 + ea2624b commit c0c6b5c
Show file tree
Hide file tree
Showing 12 changed files with 81 additions and 34 deletions.
1 change: 1 addition & 0 deletions .mailmap
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,7 @@ Rémi Denis-Courmont <[email protected]>
Ricardo Ribalda <[email protected]> <[email protected]>
Ricardo Ribalda <[email protected]> Ricardo Ribalda Delgado <[email protected]>
Ricardo Ribalda <[email protected]> <[email protected]>
Richard Genoud <[email protected]> <[email protected]>
Richard Leitner <[email protected]> <[email protected]>
Richard Leitner <[email protected]> <[email protected]>
Richard Leitner <[email protected]> <[email protected]>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Atmel Universal Synchronous Asynchronous Receiver/Transmitter (USART)

maintainers:
- Richard Genoud <richard.genoud@gmail.com>
- Richard Genoud <richard.genoud@bootlin.com>

properties:
compatible:
Expand Down
2 changes: 1 addition & 1 deletion MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -14356,7 +14356,7 @@ F: drivers/dma/at_xdmac.c
F: include/dt-bindings/dma/at91.h

MICROCHIP AT91 SERIAL DRIVER
M: Richard Genoud <richard.genoud@gmail.com>
M: Richard Genoud <richard.genoud@bootlin.com>
S: Maintained
F: Documentation/devicetree/bindings/serial/atmel,at91-usart.yaml
F: drivers/tty/serial/atmel_serial.c
Expand Down
6 changes: 3 additions & 3 deletions drivers/tty/serial/8250/8250_dw.c
Original file line number Diff line number Diff line change
Expand Up @@ -356,18 +356,18 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios,
long rate;
int ret;

clk_disable_unprepare(d->clk);
rate = clk_round_rate(d->clk, newrate);
if (rate > 0 && p->uartclk != rate) {
clk_disable_unprepare(d->clk);
if (rate > 0) {
/*
* Note that any clock-notifer worker will block in
* serial8250_update_uartclk() until we are done.
*/
ret = clk_set_rate(d->clk, newrate);
if (!ret)
p->uartclk = rate;
clk_prepare_enable(d->clk);
}
clk_prepare_enable(d->clk);

dw8250_do_set_termios(p, termios, old);
}
Expand Down
2 changes: 1 addition & 1 deletion drivers/tty/serial/8250/8250_lpc18xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ static int lpc18xx_serial_probe(struct platform_device *pdev)

ret = uart_read_port_properties(&uart.port);
if (ret)
return ret;
goto dis_uart_clk;

uart.port.iotype = UPIO_MEM32;
uart.port.regshift = 2;
Expand Down
6 changes: 0 additions & 6 deletions drivers/tty/serial/8250/8250_pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -5010,12 +5010,6 @@ static const struct pci_device_id serial_pci_tbl[] = {
{ PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_bt_2_115200 },
{ PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATTRO_A,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_bt_2_115200 },
{ PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATTRO_B,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_bt_2_115200 },
{ PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_A,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_bt_4_460800 },
Expand Down
8 changes: 6 additions & 2 deletions drivers/tty/serial/mxs-auart.c
Original file line number Diff line number Diff line change
Expand Up @@ -1086,11 +1086,13 @@ static void mxs_auart_set_ldisc(struct uart_port *port,

static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
{
u32 istat;
u32 istat, stat;
struct mxs_auart_port *s = context;
u32 mctrl_temp = s->mctrl_prev;
u32 stat = mxs_read(s, REG_STAT);

uart_port_lock(&s->port);

stat = mxs_read(s, REG_STAT);
istat = mxs_read(s, REG_INTR);

/* ack irq */
Expand Down Expand Up @@ -1126,6 +1128,8 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
istat &= ~AUART_INTR_TXIS;
}

uart_port_unlock(&s->port);

return IRQ_HANDLED;
}

Expand Down
14 changes: 0 additions & 14 deletions drivers/tty/serial/pmac_zilog.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,6 @@ static bool pmz_receive_chars(struct uart_pmac_port *uap)
{
struct tty_port *port;
unsigned char ch, r1, drop, flag;
int loops = 0;

/* Sanity check, make sure the old bug is no longer happening */
if (uap->port.state == NULL) {
Expand Down Expand Up @@ -291,24 +290,11 @@ static bool pmz_receive_chars(struct uart_pmac_port *uap)
if (r1 & Rx_OVR)
tty_insert_flip_char(port, 0, TTY_OVERRUN);
next_char:
/* We can get stuck in an infinite loop getting char 0 when the
* line is in a wrong HW state, we break that here.
* When that happens, I disable the receive side of the driver.
* Note that what I've been experiencing is a real irq loop where
* I'm getting flooded regardless of the actual port speed.
* Something strange is going on with the HW
*/
if ((++loops) > 1000)
goto flood;
ch = read_zsreg(uap, R0);
if (!(ch & Rx_CH_AV))
break;
}

return true;
flood:
pmz_interrupt_control(uap, 0);
pmz_error("pmz: rx irq flood !\n");
return true;
}

Expand Down
4 changes: 4 additions & 0 deletions drivers/tty/serial/serial_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ struct serial_ctrl_device {
struct serial_port_device {
struct device dev;
struct uart_port *port;
unsigned int tx_enabled:1;
};

int serial_base_ctrl_init(void);
Expand All @@ -30,6 +31,9 @@ void serial_base_ctrl_exit(void);
int serial_base_port_init(void);
void serial_base_port_exit(void);

void serial_base_port_startup(struct uart_port *port);
void serial_base_port_shutdown(struct uart_port *port);

int serial_base_driver_register(struct device_driver *driver);
void serial_base_driver_unregister(struct device_driver *driver);

Expand Down
23 changes: 19 additions & 4 deletions drivers/tty/serial/serial_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ static void __uart_start(struct uart_state *state)
* enabled, serial_port_runtime_resume() calls start_tx() again
* after enabling the device.
*/
if (pm_runtime_active(&port_dev->dev))
if (!pm_runtime_enabled(port->dev) || pm_runtime_active(&port_dev->dev))
port->ops->start_tx(port);
pm_runtime_mark_last_busy(&port_dev->dev);
pm_runtime_put_autosuspend(&port_dev->dev);
Expand Down Expand Up @@ -323,16 +323,26 @@ static int uart_startup(struct tty_struct *tty, struct uart_state *state,
bool init_hw)
{
struct tty_port *port = &state->port;
struct uart_port *uport;
int retval;

if (tty_port_initialized(port))
return 0;
goto out_base_port_startup;

retval = uart_port_startup(tty, state, init_hw);
if (retval)
if (retval) {
set_bit(TTY_IO_ERROR, &tty->flags);
return retval;
}

return retval;
out_base_port_startup:
uport = uart_port_check(state);
if (!uport)
return -EIO;

serial_base_port_startup(uport);

return 0;
}

/*
Expand All @@ -355,6 +365,9 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
if (tty)
set_bit(TTY_IO_ERROR, &tty->flags);

if (uport)
serial_base_port_shutdown(uport);

if (tty_port_initialized(port)) {
tty_port_set_initialized(port, false);

Expand Down Expand Up @@ -1775,6 +1788,7 @@ static void uart_tty_port_shutdown(struct tty_port *port)
uport->ops->stop_rx(uport);
uart_port_unlock_irq(uport);

serial_base_port_shutdown(uport);
uart_port_shutdown(port);

/*
Expand All @@ -1788,6 +1802,7 @@ static void uart_tty_port_shutdown(struct tty_port *port)
* Free the transmit buffer.
*/
uart_port_lock_irq(uport);
uart_circ_clear(&state->xmit);
buf = state->xmit.buf;
state->xmit.buf = NULL;
uart_port_unlock_irq(uport);
Expand Down
34 changes: 34 additions & 0 deletions drivers/tty/serial/serial_port.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,12 @@ static int serial_port_runtime_resume(struct device *dev)

/* Flush any pending TX for the port */
uart_port_lock_irqsave(port, &flags);
if (!port_dev->tx_enabled)
goto unlock;
if (__serial_port_busy(port))
port->ops->start_tx(port);

unlock:
uart_port_unlock_irqrestore(port, flags);

out:
Expand All @@ -60,6 +64,11 @@ static int serial_port_runtime_suspend(struct device *dev)
return 0;

uart_port_lock_irqsave(port, &flags);
if (!port_dev->tx_enabled) {
uart_port_unlock_irqrestore(port, flags);
return 0;
}

busy = __serial_port_busy(port);
if (busy)
port->ops->start_tx(port);
Expand All @@ -71,6 +80,31 @@ static int serial_port_runtime_suspend(struct device *dev)
return busy ? -EBUSY : 0;
}

static void serial_base_port_set_tx(struct uart_port *port,
struct serial_port_device *port_dev,
bool enabled)
{
unsigned long flags;

uart_port_lock_irqsave(port, &flags);
port_dev->tx_enabled = enabled;
uart_port_unlock_irqrestore(port, flags);
}

void serial_base_port_startup(struct uart_port *port)
{
struct serial_port_device *port_dev = port->port_dev;

serial_base_port_set_tx(port, port_dev, true);
}

void serial_base_port_shutdown(struct uart_port *port)
{
struct serial_port_device *port_dev = port->port_dev;

serial_base_port_set_tx(port, port_dev, false);
}

static DEFINE_RUNTIME_DEV_PM_OPS(serial_port_pm,
serial_port_runtime_suspend,
serial_port_runtime_resume, NULL);
Expand Down
13 changes: 11 additions & 2 deletions drivers/tty/serial/stm32-usart.c
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,7 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr)
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
u32 sr;
unsigned int size;
irqreturn_t ret = IRQ_NONE;

sr = readl_relaxed(port->membase + ofs->isr);

Expand All @@ -869,11 +870,14 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr)
(sr & USART_SR_TC)) {
stm32_usart_tc_interrupt_disable(port);
stm32_usart_rs485_rts_disable(port);
ret = IRQ_HANDLED;
}

if ((sr & USART_SR_RTOF) && ofs->icr != UNDEF_REG)
if ((sr & USART_SR_RTOF) && ofs->icr != UNDEF_REG) {
writel_relaxed(USART_ICR_RTOCF,
port->membase + ofs->icr);
ret = IRQ_HANDLED;
}

if ((sr & USART_SR_WUF) && ofs->icr != UNDEF_REG) {
/* Clear wake up flag and disable wake up interrupt */
Expand All @@ -882,6 +886,7 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr)
stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_WUFIE);
if (irqd_is_wakeup_set(irq_get_irq_data(port->irq)))
pm_wakeup_event(tport->tty->dev, 0);
ret = IRQ_HANDLED;
}

/*
Expand All @@ -896,13 +901,15 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr)
uart_unlock_and_check_sysrq(port);
if (size)
tty_flip_buffer_push(tport);
ret = IRQ_HANDLED;
}
}

if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch)) {
uart_port_lock(port);
stm32_usart_transmit_chars(port);
uart_port_unlock(port);
ret = IRQ_HANDLED;
}

/* Receiver timeout irq for DMA RX */
Expand All @@ -912,9 +919,10 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr)
uart_unlock_and_check_sysrq(port);
if (size)
tty_flip_buffer_push(tport);
ret = IRQ_HANDLED;
}

return IRQ_HANDLED;
return ret;
}

static void stm32_usart_set_mctrl(struct uart_port *port, unsigned int mctrl)
Expand Down Expand Up @@ -1084,6 +1092,7 @@ static int stm32_usart_startup(struct uart_port *port)
val |= USART_CR2_SWAP;
writel_relaxed(val, port->membase + ofs->cr2);
}
stm32_port->throttled = false;

/* RX FIFO Flush */
if (ofs->rqr != UNDEF_REG)
Expand Down

0 comments on commit c0c6b5c

Please sign in to comment.