Skip to content

Commit

Permalink
[SERIAL]: Fix console write locking in sparc drivers.
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
David S. Miller committed Jul 16, 2007
1 parent 9918cc2 commit f3c681c
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 12 deletions.
30 changes: 26 additions & 4 deletions drivers/serial/sunhv.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand All @@ -488,15 +499,26 @@ 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++) {
if (*s == '\n')
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 = {
Expand Down
19 changes: 14 additions & 5 deletions drivers/serial/sunsab.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
14 changes: 14 additions & 0 deletions drivers/serial/sunsu.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
}

/*
Expand Down
17 changes: 14 additions & 3 deletions drivers/serial/sunzilog.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 ([email protected])
* Copyright (C) 2002, 2006, 2007 David S. Miller ([email protected])
*/

#include <linux/module.h>
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit f3c681c

Please sign in to comment.