mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 19:00:25 +00:00
[SERIAL]: Fix console write locking in sparc drivers.
Mirror the logic in 8250 for proper console write locking when SYSRQ is triggered or an OOPS is in progress. Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
9918cc2e32
commit
f3c681c028
4 changed files with 68 additions and 12 deletions
|
@ -440,8 +440,16 @@ static void sunhv_console_write_paged(struct console *con, const char *s, unsign
|
|||
{
|
||||
struct uart_port *port = sunhv_port;
|
||||
unsigned long flags;
|
||||
int locked = 1;
|
||||
|
||||
local_irq_save(flags);
|
||||
if (port->sysrq) {
|
||||
locked = 0;
|
||||
} else if (oops_in_progress) {
|
||||
locked = spin_trylock(&port->lock);
|
||||
} else
|
||||
spin_lock(&port->lock);
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
while (n > 0) {
|
||||
unsigned long ra = __pa(con_write_page);
|
||||
unsigned long page_bytes;
|
||||
|
@ -469,7 +477,10 @@ static void sunhv_console_write_paged(struct console *con, const char *s, unsign
|
|||
ra += written;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
if (locked)
|
||||
spin_unlock(&port->lock);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static inline void sunhv_console_putchar(struct uart_port *port, char c)
|
||||
|
@ -488,7 +499,15 @@ static void sunhv_console_write_bychar(struct console *con, const char *s, unsig
|
|||
{
|
||||
struct uart_port *port = sunhv_port;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
int i, locked = 1;
|
||||
|
||||
local_irq_save(flags);
|
||||
if (port->sysrq) {
|
||||
locked = 0;
|
||||
} else if (oops_in_progress) {
|
||||
locked = spin_trylock(&port->lock);
|
||||
} else
|
||||
spin_lock(&port->lock);
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
for (i = 0; i < n; i++) {
|
||||
|
@ -496,7 +515,10 @@ static void sunhv_console_write_bychar(struct console *con, const char *s, unsig
|
|||
sunhv_console_putchar(port, '\r');
|
||||
sunhv_console_putchar(port, *s++);
|
||||
}
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
if (locked)
|
||||
spin_unlock(&port->lock);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static struct console sunhv_console = {
|
||||
|
|
|
@ -860,22 +860,31 @@ static int num_channels;
|
|||
static void sunsab_console_putchar(struct uart_port *port, int c)
|
||||
{
|
||||
struct uart_sunsab_port *up = (struct uart_sunsab_port *)port;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&up->port.lock, flags);
|
||||
|
||||
sunsab_tec_wait(up);
|
||||
writeb(c, &up->regs->w.tic);
|
||||
|
||||
spin_unlock_irqrestore(&up->port.lock, flags);
|
||||
}
|
||||
|
||||
static void sunsab_console_write(struct console *con, const char *s, unsigned n)
|
||||
{
|
||||
struct uart_sunsab_port *up = &sunsab_ports[con->index];
|
||||
unsigned long flags;
|
||||
int locked = 1;
|
||||
|
||||
local_irq_save(flags);
|
||||
if (up->port.sysrq) {
|
||||
locked = 0;
|
||||
} else if (oops_in_progress) {
|
||||
locked = spin_trylock(&up->port.lock);
|
||||
} else
|
||||
spin_lock(&up->port.lock);
|
||||
|
||||
uart_console_write(&up->port, s, n, sunsab_console_putchar);
|
||||
sunsab_tec_wait(up);
|
||||
|
||||
if (locked)
|
||||
spin_unlock(&up->port.lock);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static int sunsab_console_setup(struct console *con, char *options)
|
||||
|
|
|
@ -1288,7 +1288,17 @@ static void sunsu_console_write(struct console *co, const char *s,
|
|||
unsigned int count)
|
||||
{
|
||||
struct uart_sunsu_port *up = &sunsu_ports[co->index];
|
||||
unsigned long flags;
|
||||
unsigned int ier;
|
||||
int locked = 1;
|
||||
|
||||
local_irq_save(flags);
|
||||
if (up->port.sysrq) {
|
||||
locked = 0;
|
||||
} else if (oops_in_progress) {
|
||||
locked = spin_trylock(&up->port.lock);
|
||||
} else
|
||||
spin_lock(&up->port.lock);
|
||||
|
||||
/*
|
||||
* First save the UER then disable the interrupts
|
||||
|
@ -1304,6 +1314,10 @@ static void sunsu_console_write(struct console *co, const char *s,
|
|||
*/
|
||||
wait_for_xmitr(up);
|
||||
serial_out(up, UART_IER, ier);
|
||||
|
||||
if (locked)
|
||||
spin_unlock(&up->port.lock);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
* C. Dost, Pete Zaitcev, Ted Ts'o and Alex Buell for their
|
||||
* work there.
|
||||
*
|
||||
* Copyright (C) 2002, 2006 David S. Miller (davem@davemloft.net)
|
||||
* Copyright (C) 2002, 2006, 2007 David S. Miller (davem@davemloft.net)
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
@ -1151,11 +1151,22 @@ sunzilog_console_write(struct console *con, const char *s, unsigned int count)
|
|||
{
|
||||
struct uart_sunzilog_port *up = &sunzilog_port_table[con->index];
|
||||
unsigned long flags;
|
||||
int locked = 1;
|
||||
|
||||
local_irq_save(flags);
|
||||
if (up->port.sysrq) {
|
||||
locked = 0;
|
||||
} else if (oops_in_progress) {
|
||||
locked = spin_trylock(&up->port.lock);
|
||||
} else
|
||||
spin_lock(&up->port.lock);
|
||||
|
||||
spin_lock_irqsave(&up->port.lock, flags);
|
||||
uart_console_write(&up->port, s, count, sunzilog_putchar);
|
||||
udelay(2);
|
||||
spin_unlock_irqrestore(&up->port.lock, flags);
|
||||
|
||||
if (locked)
|
||||
spin_unlock(&up->port.lock);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static int __init sunzilog_console_setup(struct console *con, char *options)
|
||||
|
|
Loading…
Reference in a new issue