lkml.org 
[lkml]   [2023]   [Mar]   [2]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH printk v1 00/18] serial: 8250: implement non-BKL console
    Date
    Implement the necessary callbacks to allow the 8250 console driver
    to perform as a non-BKL console. Remove the implementation for the
    legacy console callback (write) and add implementations for the
    non-BKL consoles (write_atomic, write_thread, port_lock) and add
    CON_NO_BKL to the initial flags.

    This is an all-in-one commit meant only for testing the new printk
    non-BKL infrastructure. It is not meant to be included mainline in
    this form. In particular, it includes mainline driver fixes that
    need to be submitted individually.

    Although non-BKL consoles can coexist with legacy consoles, you
    will only receive all the benefits of the non-BKL consoles, if
    this console driver is the only console. That means no netconsole,
    no tty1, no earlyprintk, no earlycon. Just the uart8250.

    For example: console=ttyS0,115200

    Signed-off-by: John Ogness <john.ogness@linutronix.de>
    diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
    index 287153d32536..d8da34bb9ae3 100644
    --- a/drivers/tty/serial/8250/8250.h
    +++ b/drivers/tty/serial/8250/8250.h
    @@ -177,12 +177,154 @@ static inline void serial_dl_write(struct uart_8250_port *up, int value)
    up->dl_write(up, value);
    }

    +static inline bool serial8250_is_console(struct uart_port *port)
    +{
    + return uart_console(port) && !hlist_unhashed_lockless(&port->cons->node);
    +}
    +
    +static inline void serial8250_init_wctxt(struct cons_write_context *wctxt,
    + struct console *cons)
    +{
    + struct cons_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
    +
    + memset(wctxt, 0, sizeof(*wctxt));
    + ctxt->console = cons;
    + ctxt->prio = CONS_PRIO_NORMAL;
    + /* Both require the port lock, so they cannot clobber each other. */
    + ctxt->thread = 1;
    +}
    +
    +static inline void serial8250_console_acquire(struct cons_write_context *wctxt,
    + struct console *cons)
    +{
    + serial8250_init_wctxt(wctxt, cons);
    + while (!console_try_acquire(wctxt)) {
    + cpu_relax();
    + serial8250_init_wctxt(wctxt, cons);
    + }
    +}
    +
    +static inline void serial8250_enter_unsafe(struct uart_8250_port *up)
    +{
    + struct uart_port *port = &up->port;
    +
    + lockdep_assert_held_once(&port->lock);
    +
    + for (;;) {
    + up->cookie = console_srcu_read_lock();
    +
    + serial8250_console_acquire(&up->wctxt, port->cons);
    +
    + if (console_enter_unsafe(&up->wctxt))
    + break;
    +
    + console_srcu_read_unlock(up->cookie);
    + cpu_relax();
    + }
    +}
    +
    +static inline void serial8250_exit_unsafe(struct uart_8250_port *up)
    +{
    + struct uart_port *port = &up->port;
    +
    + lockdep_assert_held_once(&port->lock);
    +
    + /*
    + * FIXME: The 8250 driver does not support hostile takeovers
    + * in the unsafe section.
    + */
    + if (!WARN_ON_ONCE(!console_exit_unsafe(&up->wctxt)))
    + WARN_ON_ONCE(!console_release(&up->wctxt));
    +
    + console_srcu_read_unlock(up->cookie);
    +}
    +
    +static inline int serial8250_in_IER(struct uart_8250_port *up)
    +{
    + struct uart_port *port = &up->port;
    + bool is_console;
    + int ier;
    +
    + is_console = serial8250_is_console(port);
    +
    + if (is_console)
    + serial8250_enter_unsafe(up);
    +
    + ier = serial_in(up, UART_IER);
    +
    + if (is_console)
    + serial8250_exit_unsafe(up);
    +
    + return ier;
    +}
    +
    +static inline bool __serial8250_set_IER(struct uart_8250_port *up,
    + struct cons_write_context *wctxt,
    + int ier)
    +{
    + if (wctxt && !console_can_proceed(wctxt))
    + return false;
    + serial_out(up, UART_IER, ier);
    + return true;
    +}
    +
    +static inline void serial8250_set_IER(struct uart_8250_port *up, int ier)
    +{
    + struct uart_port *port = &up->port;
    + bool is_console;
    +
    + is_console = serial8250_is_console(port);
    +
    + if (is_console) {
    + serial8250_enter_unsafe(up);
    + __serial8250_set_IER(up, &up->wctxt, ier);
    + serial8250_exit_unsafe(up);
    + } else {
    + __serial8250_set_IER(up, NULL, ier);
    + }
    +}
    +
    +static inline bool __serial8250_clear_IER(struct uart_8250_port *up,
    + struct cons_write_context *wctxt,
    + int *prior)
    +{
    + unsigned int clearval = 0;
    +
    + if (up->capabilities & UART_CAP_UUE)
    + clearval = UART_IER_UUE;
    +
    + *prior = serial_in(up, UART_IER);
    + if (wctxt && !console_can_proceed(wctxt))
    + return false;
    + serial_out(up, UART_IER, clearval);
    + return true;
    +}
    +
    +static inline int serial8250_clear_IER(struct uart_8250_port *up)
    +{
    + struct uart_port *port = &up->port;
    + bool is_console;
    + int prior;
    +
    + is_console = serial8250_is_console(port);
    +
    + if (is_console) {
    + serial8250_enter_unsafe(up);
    + __serial8250_clear_IER(up, &up->wctxt, &prior);
    + serial8250_exit_unsafe(up);
    + } else {
    + __serial8250_clear_IER(up, NULL, &prior);
    + }
    +
    + return prior;
    +}
    +
    static inline bool serial8250_set_THRI(struct uart_8250_port *up)
    {
    if (up->ier & UART_IER_THRI)
    return false;
    up->ier |= UART_IER_THRI;
    - serial_out(up, UART_IER, up->ier);
    + serial8250_set_IER(up, up->ier);
    return true;
    }

    @@ -191,7 +333,7 @@ static inline bool serial8250_clear_THRI(struct uart_8250_port *up)
    if (!(up->ier & UART_IER_THRI))
    return false;
    up->ier &= ~UART_IER_THRI;
    - serial_out(up, UART_IER, up->ier);
    + serial8250_set_IER(up, up->ier);
    return true;
    }

    diff --git a/drivers/tty/serial/8250/8250_aspeed_vuart.c b/drivers/tty/serial/8250/8250_aspeed_vuart.c
    index 9d2a7856784f..7cc6b527c088 100644
    --- a/drivers/tty/serial/8250/8250_aspeed_vuart.c
    +++ b/drivers/tty/serial/8250/8250_aspeed_vuart.c
    @@ -278,7 +278,7 @@ static void __aspeed_vuart_set_throttle(struct uart_8250_port *up,
    up->ier &= ~irqs;
    if (!throttle)
    up->ier |= irqs;
    - serial_out(up, UART_IER, up->ier);
    + serial8250_set_IER(up, up->ier);
    }
    static void aspeed_vuart_set_throttle(struct uart_port *port, bool throttle)
    {
    diff --git a/drivers/tty/serial/8250/8250_bcm7271.c b/drivers/tty/serial/8250/8250_bcm7271.c
    index ed5a94747692..adb1a3247807 100644
    --- a/drivers/tty/serial/8250/8250_bcm7271.c
    +++ b/drivers/tty/serial/8250/8250_bcm7271.c
    @@ -606,8 +606,10 @@ static int brcmuart_startup(struct uart_port *port)
    * Disable the Receive Data Interrupt because the DMA engine
    * will handle this.
    */
    + spin_lock_irq(&port->lock);
    up->ier &= ~UART_IER_RDI;
    - serial_port_out(port, UART_IER, up->ier);
    + serial8250_set_IER(up, up->ier);
    + spin_unlock_irq(&port->lock);

    priv->tx_running = false;
    priv->dma.rx_dma = NULL;
    @@ -787,6 +789,12 @@ static int brcmuart_handle_irq(struct uart_port *p)
    spin_lock_irqsave(&p->lock, flags);
    status = serial_port_in(p, UART_LSR);
    if ((status & UART_LSR_DR) == 0) {
    + bool is_console;
    +
    + is_console = serial8250_is_console(port);
    +
    + if (is_console)
    + serial8250_enter_unsafe(p);

    ier = serial_port_in(p, UART_IER);
    /*
    @@ -807,6 +815,9 @@ static int brcmuart_handle_irq(struct uart_port *p)
    serial_port_in(p, UART_RX);
    }

    + if (is_console)
    + serial8250_exit_unsafe(p);
    +
    handled = 1;
    }
    spin_unlock_irqrestore(&p->lock, flags);
    @@ -844,12 +855,22 @@ static enum hrtimer_restart brcmuart_hrtimer_func(struct hrtimer *t)
    /* re-enable receive unless upper layer has disabled it */
    if ((up->ier & (UART_IER_RLSI | UART_IER_RDI)) ==
    (UART_IER_RLSI | UART_IER_RDI)) {
    + bool is_console;
    +
    + is_console = serial8250_is_console(port);
    +
    + if (is_console)
    + serial8250_enter_unsafe(p);
    +
    status = serial_port_in(p, UART_IER);
    status |= (UART_IER_RLSI | UART_IER_RDI);
    serial_port_out(p, UART_IER, status);
    status = serial_port_in(p, UART_MCR);
    status |= UART_MCR_RTS;
    serial_port_out(p, UART_MCR, status);
    +
    + if (is_console)
    + serial8250_exit_unsafe(p);
    }
    spin_unlock_irqrestore(&p->lock, flags);
    return HRTIMER_NORESTART;
    diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
    index ab63c308be0a..688ecfc6e1d5 100644
    --- a/drivers/tty/serial/8250/8250_core.c
    +++ b/drivers/tty/serial/8250/8250_core.c
    @@ -256,6 +256,7 @@ static void serial8250_timeout(struct timer_list *t)
    static void serial8250_backup_timeout(struct timer_list *t)
    {
    struct uart_8250_port *up = from_timer(up, t, timer);
    + struct uart_port *port = &up->port;
    unsigned int iir, ier = 0, lsr;
    unsigned long flags;

    @@ -266,8 +267,18 @@ static void serial8250_backup_timeout(struct timer_list *t)
    * based handler.
    */
    if (up->port.irq) {
    + bool is_console;
    +
    + is_console = serial8250_is_console(port);
    +
    + if (is_console)
    + serial8250_enter_unsafe(up);
    +
    ier = serial_in(up, UART_IER);
    serial_out(up, UART_IER, 0);
    +
    + if (is_console)
    + serial8250_exit_unsafe(up);
    }

    iir = serial_in(up, UART_IIR);
    @@ -290,7 +301,7 @@ static void serial8250_backup_timeout(struct timer_list *t)
    serial8250_tx_chars(up);

    if (up->port.irq)
    - serial_out(up, UART_IER, ier);
    + serial8250_set_IER(up, ier);

    spin_unlock_irqrestore(&up->port.lock, flags);

    @@ -576,12 +587,30 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)

    #ifdef CONFIG_SERIAL_8250_CONSOLE

    -static void univ8250_console_write(struct console *co, const char *s,
    - unsigned int count)
    +static void univ8250_console_port_lock(struct console *con, bool do_lock, unsigned long *flags)
    +{
    + struct uart_8250_port *up = &serial8250_ports[con->index];
    +
    + if (do_lock)
    + spin_lock_irqsave(&up->port.lock, *flags);
    + else
    + spin_unlock_irqrestore(&up->port.lock, *flags);
    +}
    +
    +static bool univ8250_console_write_atomic(struct console *co,
    + struct cons_write_context *wctxt)
    +{
    + struct uart_8250_port *up = &serial8250_ports[co->index];
    +
    + return serial8250_console_write_atomic(up, wctxt);
    +}
    +
    +static bool univ8250_console_write_thread(struct console *co,
    + struct cons_write_context *wctxt)
    {
    struct uart_8250_port *up = &serial8250_ports[co->index];

    - serial8250_console_write(up, s, count);
    + return serial8250_console_write_thread(up, wctxt);
    }

    static int univ8250_console_setup(struct console *co, char *options)
    @@ -669,12 +698,14 @@ static int univ8250_console_match(struct console *co, char *name, int idx,

    static struct console univ8250_console = {
    .name = "ttyS",
    - .write = univ8250_console_write,
    + .write_atomic = univ8250_console_write_atomic,
    + .write_thread = univ8250_console_write_thread,
    + .port_lock = univ8250_console_port_lock,
    .device = uart_console_device,
    .setup = univ8250_console_setup,
    .exit = univ8250_console_exit,
    .match = univ8250_console_match,
    - .flags = CON_PRINTBUFFER | CON_ANYTIME,
    + .flags = CON_PRINTBUFFER | CON_ANYTIME | CON_NO_BKL,
    .index = -1,
    .data = &serial8250_reg,
    };
    @@ -962,7 +993,7 @@ static void serial_8250_overrun_backoff_work(struct work_struct *work)
    spin_lock_irqsave(&port->lock, flags);
    up->ier |= UART_IER_RLSI | UART_IER_RDI;
    up->port.read_status_mask |= UART_LSR_DR;
    - serial_out(up, UART_IER, up->ier);
    + serial8250_set_IER(up, up->ier);
    spin_unlock_irqrestore(&port->lock, flags);
    }

    diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c
    index 64770c62bbec..ccb70b20b1f4 100644
    --- a/drivers/tty/serial/8250/8250_exar.c
    +++ b/drivers/tty/serial/8250/8250_exar.c
    @@ -185,6 +185,10 @@ static void xr17v35x_set_divisor(struct uart_port *p, unsigned int baud,

    static int xr17v35x_startup(struct uart_port *port)
    {
    + struct uart_8250_port *up = up_to_u8250p(port);
    +
    + spin_lock_irq(&port->lock);
    +
    /*
    * First enable access to IER [7:5], ISR [5:4], FCR [5:4],
    * MCR [7:5] and MSR [7:0]
    @@ -195,7 +199,9 @@ static int xr17v35x_startup(struct uart_port *port)
    * Make sure all interrups are masked until initialization is
    * complete and the FIFOs are cleared
    */
    - serial_port_out(port, UART_IER, 0);
    + serial8250_set_IER(up, 0);
    +
    + spin_unlock_irq(&port->lock);

    return serial8250_do_startup(port);
    }
    diff --git a/drivers/tty/serial/8250/8250_fsl.c b/drivers/tty/serial/8250/8250_fsl.c
    index 8aad15622a2e..74bb85b705e7 100644
    --- a/drivers/tty/serial/8250/8250_fsl.c
    +++ b/drivers/tty/serial/8250/8250_fsl.c
    @@ -58,7 +58,8 @@ int fsl8250_handle_irq(struct uart_port *port)
    if ((orig_lsr & UART_LSR_OE) && (up->overrun_backoff_time_ms > 0)) {
    unsigned long delay;

    - up->ier = port->serial_in(port, UART_IER);
    + up->ier = serial8250_in_IER(up);
    +
    if (up->ier & (UART_IER_RLSI | UART_IER_RDI)) {
    port->ops->stop_rx(port);
    } else {
    diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c
    index 617b8ce60d6b..548904c3d11b 100644
    --- a/drivers/tty/serial/8250/8250_ingenic.c
    +++ b/drivers/tty/serial/8250/8250_ingenic.c
    @@ -171,6 +171,7 @@ OF_EARLYCON_DECLARE(x1000_uart, "ingenic,x1000-uart",

    static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value)
    {
    + struct uart_8250_port *up = up_to_u8250p(p);
    int ier;

    switch (offset) {
    @@ -192,7 +193,7 @@ static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value)
    * If we have enabled modem status IRQs we should enable
    * modem mode.
    */
    - ier = p->serial_in(p, UART_IER);
    + ier = serial8250_in_IER(up);

    if (ier & UART_IER_MSI)
    value |= UART_MCR_MDCE | UART_MCR_FCM;
    diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c
    index fb1d5ec0940e..bf7ab55c8923 100644
    --- a/drivers/tty/serial/8250/8250_mtk.c
    +++ b/drivers/tty/serial/8250/8250_mtk.c
    @@ -222,12 +222,38 @@ static void mtk8250_shutdown(struct uart_port *port)

    static void mtk8250_disable_intrs(struct uart_8250_port *up, int mask)
    {
    - serial_out(up, UART_IER, serial_in(up, UART_IER) & (~mask));
    + struct uart_port *port = &up->port;
    + bool is_console;
    + int ier;
    +
    + is_console = serial8250_is_console(port);
    +
    + if (is_console)
    + serial8250_enter_unsafe(up);
    +
    + ier = serial_in(up, UART_IER);
    + serial_out(up, UART_IER, ier & (~mask));
    +
    + if (is_console)
    + serial8250_exit_unsafe(up);
    }

    static void mtk8250_enable_intrs(struct uart_8250_port *up, int mask)
    {
    - serial_out(up, UART_IER, serial_in(up, UART_IER) | mask);
    + struct uart_port *port = &up->port;
    + bool is_console;
    + int ier;
    +
    + is_console = serial8250_is_console(port);
    +
    + if (is_console)
    + serial8250_enter_unsafe(up);
    +
    + ier = serial_in(up, UART_IER);
    + serial_out(up, UART_IER, ier | mask);
    +
    + if (is_console)
    + serial8250_exit_unsafe(up);
    }

    static void mtk8250_set_flow_ctrl(struct uart_8250_port *up, int mode)
    diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
    index 734f092ef839..bfa50a26349d 100644
    --- a/drivers/tty/serial/8250/8250_omap.c
    +++ b/drivers/tty/serial/8250/8250_omap.c
    @@ -334,8 +334,7 @@ static void omap8250_restore_regs(struct uart_8250_port *up)

    /* drop TCR + TLR access, we setup XON/XOFF later */
    serial8250_out_MCR(up, mcr);
    -
    - serial_out(up, UART_IER, up->ier);
    + serial8250_set_IER(up, up->ier);

    serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
    serial_dl_write(up, priv->quot);
    @@ -523,16 +522,21 @@ static void omap_8250_pm(struct uart_port *port, unsigned int state,
    u8 efr;

    pm_runtime_get_sync(port->dev);
    +
    + spin_lock_irq(&port->lock);
    +
    serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
    efr = serial_in(up, UART_EFR);
    serial_out(up, UART_EFR, efr | UART_EFR_ECB);
    serial_out(up, UART_LCR, 0);

    - serial_out(up, UART_IER, (state != 0) ? UART_IERX_SLEEP : 0);
    + serial8250_set_IER(up, (state != 0) ? UART_IERX_SLEEP : 0);
    serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
    serial_out(up, UART_EFR, efr);
    serial_out(up, UART_LCR, 0);

    + spin_unlock_irq(&port->lock);
    +
    pm_runtime_mark_last_busy(port->dev);
    pm_runtime_put_autosuspend(port->dev);
    }
    @@ -649,7 +653,8 @@ static irqreturn_t omap8250_irq(int irq, void *dev_id)
    if ((lsr & UART_LSR_OE) && up->overrun_backoff_time_ms > 0) {
    unsigned long delay;

    - up->ier = port->serial_in(port, UART_IER);
    + spin_lock(&port->lock);
    + up->ier = serial8250_in_IER(up);
    if (up->ier & (UART_IER_RLSI | UART_IER_RDI)) {
    port->ops->stop_rx(port);
    } else {
    @@ -658,6 +663,7 @@ static irqreturn_t omap8250_irq(int irq, void *dev_id)
    */
    cancel_delayed_work(&up->overrun_backoff);
    }
    + spin_unlock(&port->lock);

    delay = msecs_to_jiffies(up->overrun_backoff_time_ms);
    schedule_delayed_work(&up->overrun_backoff, delay);
    @@ -707,8 +713,10 @@ static int omap_8250_startup(struct uart_port *port)
    if (ret < 0)
    goto err;

    + spin_lock_irq(&port->lock);
    up->ier = UART_IER_RLSI | UART_IER_RDI;
    - serial_out(up, UART_IER, up->ier);
    + serial8250_set_IER(up, up->ier);
    + spin_unlock_irq(&port->lock);

    #ifdef CONFIG_PM
    up->capabilities |= UART_CAP_RPM;
    @@ -748,8 +756,10 @@ static void omap_8250_shutdown(struct uart_port *port)
    if (priv->habit & UART_HAS_EFR2)
    serial_out(up, UART_OMAP_EFR2, 0x0);

    + spin_lock_irq(&port->lock);
    up->ier = 0;
    - serial_out(up, UART_IER, 0);
    + serial8250_set_IER(up, 0);
    + spin_unlock_irq(&port->lock);

    if (up->dma)
    serial8250_release_dma(up);
    @@ -797,7 +807,7 @@ static void omap_8250_unthrottle(struct uart_port *port)
    up->dma->rx_dma(up);
    up->ier |= UART_IER_RLSI | UART_IER_RDI;
    port->read_status_mask |= UART_LSR_DR;
    - serial_out(up, UART_IER, up->ier);
    + serial8250_set_IER(up, up->ier);
    spin_unlock_irqrestore(&port->lock, flags);

    pm_runtime_mark_last_busy(port->dev);
    @@ -956,7 +966,7 @@ static void __dma_rx_complete(void *param)
    __dma_rx_do_complete(p);
    if (!priv->throttled) {
    p->ier |= UART_IER_RLSI | UART_IER_RDI;
    - serial_out(p, UART_IER, p->ier);
    + serial8250_set_IER(p, p->ier);
    if (!(priv->habit & UART_HAS_EFR2))
    omap_8250_rx_dma(p);
    }
    @@ -1013,7 +1023,7 @@ static int omap_8250_rx_dma(struct uart_8250_port *p)
    * callback to run.
    */
    p->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
    - serial_out(p, UART_IER, p->ier);
    + serial8250_set_IER(p, p->ier);
    }
    goto out;
    }
    @@ -1226,12 +1236,12 @@ static void am654_8250_handle_rx_dma(struct uart_8250_port *up, u8 iir,
    * periodic timeouts, re-enable interrupts.
    */
    up->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
    - serial_out(up, UART_IER, up->ier);
    + serial8250_set_IER(up, up->ier);
    omap_8250_rx_dma_flush(up);
    serial_in(up, UART_IIR);
    serial_out(up, UART_OMAP_EFR2, 0x0);
    up->ier |= UART_IER_RLSI | UART_IER_RDI;
    - serial_out(up, UART_IER, up->ier);
    + serial8250_set_IER(up, up->ier);
    }
    }

    @@ -1717,12 +1727,16 @@ static int omap8250_runtime_resume(struct device *dev)

    up = serial8250_get_port(priv->line);

    + spin_lock_irq(&up->port.lock);
    +
    if (omap8250_lost_context(up))
    omap8250_restore_regs(up);

    if (up->dma && up->dma->rxchan && !(priv->habit & UART_HAS_EFR2))
    omap_8250_rx_dma(up);

    + spin_unlock_irq(&up->port.lock);
    +
    priv->latency = priv->calc_latency;
    schedule_work(&priv->qos_work);
    return 0;
    diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
    index fa43df05342b..f1976d9a8a38 100644
    --- a/drivers/tty/serial/8250/8250_port.c
    +++ b/drivers/tty/serial/8250/8250_port.c
    @@ -744,6 +744,7 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
    serial8250_rpm_get(p);

    if (p->capabilities & UART_CAP_SLEEP) {
    + spin_lock_irq(&p->port.lock);
    if (p->capabilities & UART_CAP_EFR) {
    lcr = serial_in(p, UART_LCR);
    efr = serial_in(p, UART_EFR);
    @@ -751,25 +752,18 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
    serial_out(p, UART_EFR, UART_EFR_ECB);
    serial_out(p, UART_LCR, 0);
    }
    - serial_out(p, UART_IER, sleep ? UART_IERX_SLEEP : 0);
    + serial8250_set_IER(p, sleep ? UART_IERX_SLEEP : 0);
    if (p->capabilities & UART_CAP_EFR) {
    serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B);
    serial_out(p, UART_EFR, efr);
    serial_out(p, UART_LCR, lcr);
    }
    + spin_unlock_irq(&p->port.lock);
    }

    serial8250_rpm_put(p);
    }

    -static void serial8250_clear_IER(struct uart_8250_port *up)
    -{
    - if (up->capabilities & UART_CAP_UUE)
    - serial_out(up, UART_IER, UART_IER_UUE);
    - else
    - serial_out(up, UART_IER, 0);
    -}
    -
    #ifdef CONFIG_SERIAL_8250_RSA
    /*
    * Attempts to turn on the RSA FIFO. Returns zero on failure.
    @@ -1033,8 +1027,10 @@ static int broken_efr(struct uart_8250_port *up)
    */
    static void autoconfig_16550a(struct uart_8250_port *up)
    {
    + struct uart_port *port = &up->port;
    unsigned char status1, status2;
    unsigned int iersave;
    + bool is_console;

    up->port.type = PORT_16550A;
    up->capabilities |= UART_CAP_FIFO;
    @@ -1150,6 +1146,11 @@ static void autoconfig_16550a(struct uart_8250_port *up)
    return;
    }

    + is_console = serial8250_is_console(port);
    +
    + if (is_console)
    + serial8250_enter_unsafe(up);
    +
    /*
    * Try writing and reading the UART_IER_UUE bit (b6).
    * If it works, this is probably one of the Xscale platform's
    @@ -1185,6 +1186,9 @@ static void autoconfig_16550a(struct uart_8250_port *up)
    }
    serial_out(up, UART_IER, iersave);

    + if (is_console)
    + serial8250_exit_unsafe(up);
    +
    /*
    * We distinguish between 16550A and U6 16550A by counting
    * how many bytes are in the FIFO.
    @@ -1226,6 +1230,13 @@ static void autoconfig(struct uart_8250_port *up)
    up->bugs = 0;

    if (!(port->flags & UPF_BUGGY_UART)) {
    + bool is_console;
    +
    + is_console = serial8250_is_console(port);
    +
    + if (is_console)
    + serial8250_enter_unsafe(up);
    +
    /*
    * Do a simple existence test first; if we fail this,
    * there's no point trying anything else.
    @@ -1255,6 +1266,10 @@ static void autoconfig(struct uart_8250_port *up)
    #endif
    scratch3 = serial_in(up, UART_IER) & UART_IER_ALL_INTR;
    serial_out(up, UART_IER, scratch);
    +
    + if (is_console)
    + serial8250_exit_unsafe(up);
    +
    if (scratch2 != 0 || scratch3 != UART_IER_ALL_INTR) {
    /*
    * We failed; there's nothing here
    @@ -1376,6 +1391,7 @@ static void autoconfig_irq(struct uart_8250_port *up)
    unsigned char save_ICP = 0;
    unsigned int ICP = 0;
    unsigned long irqs;
    + bool is_console;
    int irq;

    if (port->flags & UPF_FOURPORT) {
    @@ -1385,8 +1401,12 @@ static void autoconfig_irq(struct uart_8250_port *up)
    inb_p(ICP);
    }

    - if (uart_console(port))
    + is_console = serial8250_is_console(port);
    +
    + if (is_console) {
    console_lock();
    + serial8250_enter_unsafe(up);
    + }

    /* forget possible initially masked and pending IRQ */
    probe_irq_off(probe_irq_on());
    @@ -1418,8 +1438,10 @@ static void autoconfig_irq(struct uart_8250_port *up)
    if (port->flags & UPF_FOURPORT)
    outb_p(save_ICP, ICP);

    - if (uart_console(port))
    + if (is_console) {
    + serial8250_exit_unsafe(up);
    console_unlock();
    + }

    port->irq = (irq > 0) ? irq : 0;
    }
    @@ -1432,7 +1454,7 @@ static void serial8250_stop_rx(struct uart_port *port)

    up->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
    up->port.read_status_mask &= ~UART_LSR_DR;
    - serial_port_out(port, UART_IER, up->ier);
    + serial8250_set_IER(up, up->ier);

    serial8250_rpm_put(up);
    }
    @@ -1462,7 +1484,7 @@ void serial8250_em485_stop_tx(struct uart_8250_port *p)
    serial8250_clear_and_reinit_fifos(p);

    p->ier |= UART_IER_RLSI | UART_IER_RDI;
    - serial_port_out(&p->port, UART_IER, p->ier);
    + serial8250_set_IER(p, p->ier);
    }
    }
    EXPORT_SYMBOL_GPL(serial8250_em485_stop_tx);
    @@ -1709,7 +1731,7 @@ static void serial8250_disable_ms(struct uart_port *port)
    mctrl_gpio_disable_ms(up->gpios);

    up->ier &= ~UART_IER_MSI;
    - serial_port_out(port, UART_IER, up->ier);
    + serial8250_set_IER(up, up->ier);
    }

    static void serial8250_enable_ms(struct uart_port *port)
    @@ -1725,7 +1747,7 @@ static void serial8250_enable_ms(struct uart_port *port)
    up->ier |= UART_IER_MSI;

    serial8250_rpm_get(up);
    - serial_port_out(port, UART_IER, up->ier);
    + serial8250_set_IER(up, up->ier);
    serial8250_rpm_put(up);
    }

    @@ -2160,9 +2182,10 @@ static void serial8250_put_poll_char(struct uart_port *port,
    serial8250_rpm_get(up);
    /*
    * First save the IER then disable the interrupts
    + *
    + * Best-effort IER access because other CPUs are quiesced.
    */
    - ier = serial_port_in(port, UART_IER);
    - serial8250_clear_IER(up);
    + __serial8250_clear_IER(up, NULL, &ier);

    wait_for_xmitr(up, UART_LSR_BOTH_EMPTY);
    /*
    @@ -2175,7 +2198,7 @@ static void serial8250_put_poll_char(struct uart_port *port,
    * and restore the IER
    */
    wait_for_xmitr(up, UART_LSR_BOTH_EMPTY);
    - serial_port_out(port, UART_IER, ier);
    + __serial8250_set_IER(up, NULL, ier);
    serial8250_rpm_put(up);
    }

    @@ -2186,6 +2209,7 @@ int serial8250_do_startup(struct uart_port *port)
    struct uart_8250_port *up = up_to_u8250p(port);
    unsigned long flags;
    unsigned char iir;
    + bool is_console;
    int retval;
    u16 lsr;

    @@ -2203,21 +2227,25 @@ int serial8250_do_startup(struct uart_port *port)
    serial8250_rpm_get(up);
    if (port->type == PORT_16C950) {
    /* Wake up and initialize UART */
    + spin_lock_irqsave(&port->lock, flags);
    up->acr = 0;
    serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B);
    serial_port_out(port, UART_EFR, UART_EFR_ECB);
    - serial_port_out(port, UART_IER, 0);
    + serial8250_set_IER(up, 0);
    serial_port_out(port, UART_LCR, 0);
    serial_icr_write(up, UART_CSR, 0); /* Reset the UART */
    serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B);
    serial_port_out(port, UART_EFR, UART_EFR_ECB);
    serial_port_out(port, UART_LCR, 0);
    + spin_unlock_irqrestore(&port->lock, flags);
    }

    if (port->type == PORT_DA830) {
    /* Reset the port */
    - serial_port_out(port, UART_IER, 0);
    + spin_lock_irqsave(&port->lock, flags);
    + serial8250_set_IER(up, 0);
    serial_port_out(port, UART_DA830_PWREMU_MGMT, 0);
    + spin_unlock_irqrestore(&port->lock, flags);
    mdelay(10);

    /* Enable Tx, Rx and free run mode */
    @@ -2315,6 +2343,8 @@ int serial8250_do_startup(struct uart_port *port)
    if (retval)
    goto out;

    + is_console = serial8250_is_console(port);
    +
    if (port->irq && !(up->port.flags & UPF_NO_THRE_TEST)) {
    unsigned char iir1;

    @@ -2331,6 +2361,9 @@ int serial8250_do_startup(struct uart_port *port)
    */
    spin_lock_irqsave(&port->lock, flags);

    + if (is_console)
    + serial8250_enter_unsafe(up);
    +
    wait_for_xmitr(up, UART_LSR_THRE);
    serial_port_out_sync(port, UART_IER, UART_IER_THRI);
    udelay(1); /* allow THRE to set */
    @@ -2341,6 +2374,9 @@ int serial8250_do_startup(struct uart_port *port)
    iir = serial_port_in(port, UART_IIR);
    serial_port_out(port, UART_IER, 0);

    + if (is_console)
    + serial8250_exit_unsafe(up);
    +
    spin_unlock_irqrestore(&port->lock, flags);

    if (port->irqflags & IRQF_SHARED)
    @@ -2395,10 +2431,14 @@ int serial8250_do_startup(struct uart_port *port)
    * Do a quick test to see if we receive an interrupt when we enable
    * the TX irq.
    */
    + if (is_console)
    + serial8250_enter_unsafe(up);
    serial_port_out(port, UART_IER, UART_IER_THRI);
    lsr = serial_port_in(port, UART_LSR);
    iir = serial_port_in(port, UART_IIR);
    serial_port_out(port, UART_IER, 0);
    + if (is_console)
    + serial8250_exit_unsafe(up);

    if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) {
    if (!(up->bugs & UART_BUG_TXEN)) {
    @@ -2430,7 +2470,7 @@ int serial8250_do_startup(struct uart_port *port)
    if (up->dma) {
    const char *msg = NULL;

    - if (uart_console(port))
    + if (is_console)
    msg = "forbid DMA for kernel console";
    else if (serial8250_request_dma(up))
    msg = "failed to request DMA";
    @@ -2481,7 +2521,7 @@ void serial8250_do_shutdown(struct uart_port *port)
    */
    spin_lock_irqsave(&port->lock, flags);
    up->ier = 0;
    - serial_port_out(port, UART_IER, 0);
    + serial8250_set_IER(up, 0);
    spin_unlock_irqrestore(&port->lock, flags);

    synchronize_irq(port->irq);
    @@ -2847,7 +2887,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
    if (up->capabilities & UART_CAP_RTOIE)
    up->ier |= UART_IER_RTOIE;

    - serial_port_out(port, UART_IER, up->ier);
    + serial8250_set_IER(up, up->ier);

    if (up->capabilities & UART_CAP_EFR) {
    unsigned char efr = 0;
    @@ -3312,12 +3352,21 @@ EXPORT_SYMBOL_GPL(serial8250_set_defaults);

    #ifdef CONFIG_SERIAL_8250_CONSOLE

    -static void serial8250_console_putchar(struct uart_port *port, unsigned char ch)
    +static bool serial8250_console_putchar(struct uart_port *port, unsigned char ch,
    + struct cons_write_context *wctxt)
    {
    struct uart_8250_port *up = up_to_u8250p(port);

    wait_for_xmitr(up, UART_LSR_THRE);
    + if (!console_can_proceed(wctxt))
    + return false;
    serial_port_out(port, UART_TX, ch);
    + if (ch == '\n')
    + up->console_newline_needed = false;
    + else
    + up->console_newline_needed = true;
    +
    + return true;
    }

    /*
    @@ -3346,33 +3395,134 @@ static void serial8250_console_restore(struct uart_8250_port *up)
    serial8250_out_MCR(up, up->mcr | UART_MCR_DTR | UART_MCR_RTS);
    }

    +static bool __serial8250_console_write(struct uart_port *port, struct cons_write_context *wctxt,
    + const char *s, unsigned int count,
    + bool (*putchar)(struct uart_port *, unsigned char, struct cons_write_context *))
    +{
    + bool finished = false;
    + unsigned int i;
    +
    + for (i = 0; i < count; i++, s++) {
    + if (*s == '\n') {
    + if (!putchar(port, '\r', wctxt))
    + goto out;
    + }
    + if (!putchar(port, *s, wctxt))
    + goto out;
    + }
    + finished = true;
    +out:
    + return finished;
    +}
    +
    +static bool serial8250_console_write(struct uart_port *port, struct cons_write_context *wctxt,
    + const char *s, unsigned int count,
    + bool (*putchar)(struct uart_port *, unsigned char, struct cons_write_context *))
    +{
    + return __serial8250_console_write(port, wctxt, s, count, putchar);
    +}
    +
    +static bool atomic_print_line(struct uart_8250_port *up,
    + struct cons_write_context *wctxt)
    +{
    + struct uart_port *port = &up->port;
    + char buf[4];
    +
    + if (up->console_newline_needed &&
    + !__serial8250_console_write(port, wctxt, "\n", 1, serial8250_console_putchar)) {
    + return false;
    + }
    +
    + sprintf(buf, "A%d", raw_smp_processor_id());
    + if (!__serial8250_console_write(port, wctxt, buf, strlen(buf), serial8250_console_putchar))
    + return false;
    +
    + return __serial8250_console_write(port, wctxt, wctxt->outbuf, wctxt->len,
    + serial8250_console_putchar);
    +}
    +
    +static void atomic_console_reacquire(struct cons_write_context *wctxt,
    + struct cons_write_context *wctxt_init)
    +{
    + memcpy(wctxt, wctxt_init, sizeof(*wctxt));
    + while (!console_try_acquire(wctxt)) {
    + cpu_relax();
    + memcpy(wctxt, wctxt_init, sizeof(*wctxt));
    + }
    +}
    +
    /*
    - * Print a string to the serial port using the device FIFO
    - *
    - * It sends fifosize bytes and then waits for the fifo
    - * to get empty.
    + * It should be possible to support a hostile takeover in an unsafe
    + * section if it is write_atomic() that is being taken over. But where
    + * to put this policy?
    */
    -static void serial8250_console_fifo_write(struct uart_8250_port *up,
    - const char *s, unsigned int count)
    +bool serial8250_console_write_atomic(struct uart_8250_port *up,
    + struct cons_write_context *wctxt)
    {
    - int i;
    - const char *end = s + count;
    - unsigned int fifosize = up->tx_loadsz;
    - bool cr_sent = false;
    -
    - while (s != end) {
    - wait_for_lsr(up, UART_LSR_THRE);
    -
    - for (i = 0; i < fifosize && s != end; ++i) {
    - if (*s == '\n' && !cr_sent) {
    - serial_out(up, UART_TX, '\r');
    - cr_sent = true;
    - } else {
    - serial_out(up, UART_TX, *s++);
    - cr_sent = false;
    - }
    + struct cons_write_context wctxt_init = {};
    + struct cons_context *ctxt_init = &ACCESS_PRIVATE(&wctxt_init, ctxt);
    + struct cons_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
    + bool can_print = true;
    + unsigned int ier;
    +
    + /* With write_atomic, another context may hold the port->lock. */
    +
    + ctxt_init->console = ctxt->console;
    + ctxt_init->prio = ctxt->prio;
    + ctxt_init->thread = ctxt->thread;
    +
    + touch_nmi_watchdog();
    +
    + /*
    + * Enter unsafe in order to disable interrupts. If the console is
    + * lost before the interrupts are disabled, bail out because another
    + * context took over the printing. If the console is lost after the
    + * interrutps are disabled, the console must be reacquired in order
    + * to re-enable the interrupts. However in that case no printing is
    + * allowed because another context took over the printing.
    + */
    +
    + if (!console_enter_unsafe(wctxt))
    + return false;
    +
    + if (!__serial8250_clear_IER(up, wctxt, &ier))
    + return false;
    +
    + if (console_exit_unsafe(wctxt)) {
    + can_print = atomic_print_line(up, wctxt);
    + if (!can_print)
    + atomic_console_reacquire(wctxt, &wctxt_init);
    +
    + if (can_print) {
    + can_print = console_can_proceed(wctxt);
    + if (can_print)
    + wait_for_xmitr(up, UART_LSR_BOTH_EMPTY);
    + else
    + atomic_console_reacquire(wctxt, &wctxt_init);
    + }
    + } else {
    + atomic_console_reacquire(wctxt, &wctxt_init);
    + }
    +
    + /*
    + * Enter unsafe in order to enable interrupts. If the console is
    + * lost before the interrupts are enabled, the console must be
    + * reacquired in order to re-enable the interrupts.
    + */
    +
    + for (;;) {
    + if (console_enter_unsafe(wctxt) &&
    + __serial8250_set_IER(up, wctxt, ier)) {
    + break;
    }
    +
    + /* HW-IRQs still disabled. Reacquire to enable them. */
    + atomic_console_reacquire(wctxt, &wctxt_init);
    }
    +
    + console_exit_unsafe(wctxt);
    +
    + return can_print;
    }

    /*
    @@ -3384,64 +3534,54 @@ static void serial8250_console_fifo_write(struct uart_8250_port *up,
    * Doing runtime PM is really a bad idea for the kernel console.
    * Thus, we assume the function is called when device is powered up.
    */
    -void serial8250_console_write(struct uart_8250_port *up, const char *s,
    - unsigned int count)
    +bool serial8250_console_write_thread(struct uart_8250_port *up,
    + struct cons_write_context *wctxt)
    {
    struct uart_8250_em485 *em485 = up->em485;
    struct uart_port *port = &up->port;
    - unsigned long flags;
    - unsigned int ier, use_fifo;
    - int locked = 1;
    -
    - touch_nmi_watchdog();
    -
    - if (oops_in_progress)
    - locked = spin_trylock_irqsave(&port->lock, flags);
    - else
    - spin_lock_irqsave(&port->lock, flags);
    + unsigned int count = wctxt->len;
    + const char *s = wctxt->outbuf;
    + bool finished = false;
    + unsigned int ier;
    + char buf[4];

    /*
    * First save the IER then disable the interrupts
    */
    - ier = serial_port_in(port, UART_IER);
    - serial8250_clear_IER(up);
    + if (!console_enter_unsafe(wctxt) ||
    + !__serial8250_clear_IER(up, wctxt, &ier)) {
    + goto out;
    + }
    + if (!console_exit_unsafe(wctxt))
    + goto out;

    /* check scratch reg to see if port powered off during system sleep */
    if (up->canary && (up->canary != serial_port_in(port, UART_SCR))) {
    + if (!console_enter_unsafe(wctxt))
    + goto out;
    serial8250_console_restore(up);
    + if (!console_exit_unsafe(wctxt))
    + goto out;
    up->canary = 0;
    }

    if (em485) {
    - if (em485->tx_stopped)
    + if (em485->tx_stopped) {
    + if (!console_enter_unsafe(wctxt))
    + goto out;
    up->rs485_start_tx(up);
    - mdelay(port->rs485.delay_rts_before_send);
    + if (!console_exit_unsafe(wctxt))
    + goto out;
    + }
    + mdelay(port->rs485.delay_rts_before_send); /* WTF?! Seriously?! */
    }

    - use_fifo = (up->capabilities & UART_CAP_FIFO) &&
    - /*
    - * BCM283x requires to check the fifo
    - * after each byte.
    - */
    - !(up->capabilities & UART_CAP_MINI) &&
    - /*
    - * tx_loadsz contains the transmit fifo size
    - */
    - up->tx_loadsz > 1 &&
    - (up->fcr & UART_FCR_ENABLE_FIFO) &&
    - port->state &&
    - test_bit(TTY_PORT_INITIALIZED, &port->state->port.iflags) &&
    - /*
    - * After we put a data in the fifo, the controller will send
    - * it regardless of the CTS state. Therefore, only use fifo
    - * if we don't use control flow.
    - */
    - !(up->port.flags & UPF_CONS_FLOW);
    + sprintf(buf, "T%d", raw_smp_processor_id());
    + if (serial8250_console_write(port, wctxt, buf, strlen(buf), serial8250_console_putchar))
    + finished = serial8250_console_write(port, wctxt, s, count, serial8250_console_putchar);

    - if (likely(use_fifo))
    - serial8250_console_fifo_write(up, s, count);
    - else
    - uart_console_write(port, s, count, serial8250_console_putchar);
    + if (!finished)
    + goto out;

    /*
    * Finally, wait for transmitter to become empty
    @@ -3450,12 +3590,20 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
    wait_for_xmitr(up, UART_LSR_BOTH_EMPTY);

    if (em485) {
    - mdelay(port->rs485.delay_rts_after_send);
    - if (em485->tx_stopped)
    + mdelay(port->rs485.delay_rts_after_send); /* WTF?! Seriously?! */
    + if (em485->tx_stopped) {
    + if (!console_enter_unsafe(wctxt))
    + goto out;
    up->rs485_stop_tx(up);
    + if (!console_exit_unsafe(wctxt))
    + goto out;
    + }
    }
    -
    - serial_port_out(port, UART_IER, ier);
    + if (!console_enter_unsafe(wctxt))
    + goto out;
    + WARN_ON_ONCE(!__serial8250_set_IER(up, wctxt, ier));
    + if (!console_exit_unsafe(wctxt))
    + goto out;

    /*
    * The receive handling will happen properly because the
    @@ -3464,11 +3612,15 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
    * call it if we have saved something in the saved flags
    * while processing with interrupts off.
    */
    - if (up->msr_saved_flags)
    + if (up->msr_saved_flags) {
    + if (!console_enter_unsafe(wctxt))
    + goto out;
    serial8250_modem_status(up);
    -
    - if (locked)
    - spin_unlock_irqrestore(&port->lock, flags);
    + if (!console_exit_unsafe(wctxt))
    + goto out;
    + }
    +out:
    + return finished;
    }

    static unsigned int probe_baud(struct uart_port *port)
    @@ -3488,6 +3640,7 @@ static unsigned int probe_baud(struct uart_port *port)

    int serial8250_console_setup(struct uart_port *port, char *options, bool probe)
    {
    + struct uart_8250_port *up = up_to_u8250p(port);
    int baud = 9600;
    int bits = 8;
    int parity = 'n';
    @@ -3497,6 +3650,8 @@ int serial8250_console_setup(struct uart_port *port, char *options, bool probe)
    if (!port->iobase && !port->membase)
    return -ENODEV;

    + up->console_newline_needed = false;
    +
    if (options)
    uart_parse_options(options, &baud, &parity, &bits, &flow);
    else if (probe)
    diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
    index 978dc196c29b..22656e8370ea 100644
    --- a/drivers/tty/serial/8250/Kconfig
    +++ b/drivers/tty/serial/8250/Kconfig
    @@ -9,6 +9,7 @@ config SERIAL_8250
    depends on !S390
    select SERIAL_CORE
    select SERIAL_MCTRL_GPIO if GPIOLIB
    + select HAVE_ATOMIC_CONSOLE
    help
    This selects whether you want to include the driver for the standard
    serial ports. The standard answer is Y. People who might say N
    diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
    index 2bd32c8ece39..9901f916dc1a 100644
    --- a/drivers/tty/serial/serial_core.c
    +++ b/drivers/tty/serial/serial_core.c
    @@ -2336,8 +2336,11 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
    * able to Re-start_rx later.
    */
    if (!console_suspend_enabled && uart_console(uport)) {
    - if (uport->ops->start_rx)
    + if (uport->ops->start_rx) {
    + spin_lock_irq(&uport->lock);
    uport->ops->stop_rx(uport);
    + spin_unlock_irq(&uport->lock);
    + }
    goto unlock;
    }

    @@ -2430,8 +2433,11 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
    if (console_suspend_enabled)
    uart_change_pm(state, UART_PM_STATE_ON);
    uport->ops->set_termios(uport, &termios, NULL);
    - if (!console_suspend_enabled && uport->ops->start_rx)
    + if (!console_suspend_enabled && uport->ops->start_rx) {
    + spin_lock_irq(&uport->lock);
    uport->ops->start_rx(uport);
    + spin_unlock_irq(&uport->lock);
    + }
    if (console_suspend_enabled)
    console_start(uport->cons);
    }
    diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
    index 19376bee9667..9055a22992ed 100644
    --- a/include/linux/serial_8250.h
    +++ b/include/linux/serial_8250.h
    @@ -125,6 +125,8 @@ struct uart_8250_port {
    #define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
    unsigned char msr_saved_flags;

    + bool console_newline_needed;
    +
    struct uart_8250_dma *dma;
    const struct uart_8250_ops *ops;

    @@ -139,6 +141,9 @@ struct uart_8250_port {
    /* Serial port overrun backoff */
    struct delayed_work overrun_backoff;
    u32 overrun_backoff_time_ms;
    +
    + struct cons_write_context wctxt;
    + int cookie;
    };

    static inline struct uart_8250_port *up_to_u8250p(struct uart_port *up)
    @@ -178,8 +183,10 @@ void serial8250_tx_chars(struct uart_8250_port *up);
    unsigned int serial8250_modem_status(struct uart_8250_port *up);
    void serial8250_init_port(struct uart_8250_port *up);
    void serial8250_set_defaults(struct uart_8250_port *up);
    -void serial8250_console_write(struct uart_8250_port *up, const char *s,
    - unsigned int count);
    +bool serial8250_console_write_atomic(struct uart_8250_port *up,
    + struct cons_write_context *wctxt);
    +bool serial8250_console_write_thread(struct uart_8250_port *up,
    + struct cons_write_context *wctxt);
    int serial8250_console_setup(struct uart_port *port, char *options, bool probe);
    int serial8250_console_exit(struct uart_port *port);

    \
     
     \ /
      Last update: 2023-03-27 00:42    [W:4.492 / U:0.008 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site