Commit f3c681c0 authored by David S. Miller's avatar David S. Miller

[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: default avatarDavid S. Miller <davem@davemloft.net>
parent 9918cc2e
...@@ -440,8 +440,16 @@ static void sunhv_console_write_paged(struct console *con, const char *s, unsign ...@@ -440,8 +440,16 @@ static void sunhv_console_write_paged(struct console *con, const char *s, unsign
{ {
struct uart_port *port = sunhv_port; struct uart_port *port = sunhv_port;
unsigned long flags; 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) { while (n > 0) {
unsigned long ra = __pa(con_write_page); unsigned long ra = __pa(con_write_page);
unsigned long page_bytes; unsigned long page_bytes;
...@@ -469,7 +477,10 @@ static void sunhv_console_write_paged(struct console *con, const char *s, unsign ...@@ -469,7 +477,10 @@ static void sunhv_console_write_paged(struct console *con, const char *s, unsign
ra += written; 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) 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 ...@@ -488,7 +499,15 @@ static void sunhv_console_write_bychar(struct console *con, const char *s, unsig
{ {
struct uart_port *port = sunhv_port; struct uart_port *port = sunhv_port;
unsigned long flags; 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); spin_lock_irqsave(&port->lock, flags);
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
...@@ -496,7 +515,10 @@ static void sunhv_console_write_bychar(struct console *con, const char *s, unsig ...@@ -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, '\r');
sunhv_console_putchar(port, *s++); 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 = { static struct console sunhv_console = {
......
...@@ -860,22 +860,31 @@ static int num_channels; ...@@ -860,22 +860,31 @@ static int num_channels;
static void sunsab_console_putchar(struct uart_port *port, int c) static void sunsab_console_putchar(struct uart_port *port, int c)
{ {
struct uart_sunsab_port *up = (struct uart_sunsab_port *)port; struct uart_sunsab_port *up = (struct uart_sunsab_port *)port;
unsigned long flags;
spin_lock_irqsave(&up->port.lock, flags);
sunsab_tec_wait(up); sunsab_tec_wait(up);
writeb(c, &up->regs->w.tic); 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) static void sunsab_console_write(struct console *con, const char *s, unsigned n)
{ {
struct uart_sunsab_port *up = &sunsab_ports[con->index]; 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); uart_console_write(&up->port, s, n, sunsab_console_putchar);
sunsab_tec_wait(up); 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) 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, ...@@ -1288,7 +1288,17 @@ static void sunsu_console_write(struct console *co, const char *s,
unsigned int count) unsigned int count)
{ {
struct uart_sunsu_port *up = &sunsu_ports[co->index]; struct uart_sunsu_port *up = &sunsu_ports[co->index];
unsigned long flags;
unsigned int ier; 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 * First save the UER then disable the interrupts
...@@ -1304,6 +1314,10 @@ static void sunsu_console_write(struct console *co, const char *s, ...@@ -1304,6 +1314,10 @@ static void sunsu_console_write(struct console *co, const char *s,
*/ */
wait_for_xmitr(up); wait_for_xmitr(up);
serial_out(up, UART_IER, ier); serial_out(up, UART_IER, ier);
if (locked)
spin_unlock(&up->port.lock);
local_irq_restore(flags);
} }
/* /*
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* C. Dost, Pete Zaitcev, Ted Ts'o and Alex Buell for their * C. Dost, Pete Zaitcev, Ted Ts'o and Alex Buell for their
* work there. * 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> #include <linux/module.h>
...@@ -1151,11 +1151,22 @@ sunzilog_console_write(struct console *con, const char *s, unsigned int count) ...@@ -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]; struct uart_sunzilog_port *up = &sunzilog_port_table[con->index];
unsigned long flags; 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); uart_console_write(&up->port, s, count, sunzilog_putchar);
udelay(2); 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) static int __init sunzilog_console_setup(struct console *con, char *options)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment