Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=f3c681c028846bd5d39f563909409832a295ca69
Commit:     f3c681c028846bd5d39f563909409832a295ca69
Parent:     9918cc2e3275bf7f3561e4de1d5a3314183e71dc
Author:     David S. Miller <[EMAIL PROTECTED]>
AuthorDate: Sun Jul 15 23:53:32 2007 -0700
Committer:  David S. Miller <[EMAIL PROTECTED]>
CommitDate: Mon Jul 16 04:05:28 2007 -0700

    [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 <[EMAIL PROTECTED]>
---
 drivers/serial/sunhv.c    |   30 ++++++++++++++++++++++++++----
 drivers/serial/sunsab.c   |   19 ++++++++++++++-----
 drivers/serial/sunsu.c    |   14 ++++++++++++++
 drivers/serial/sunzilog.c |   17 ++++++++++++++---
 4 files changed, 68 insertions(+), 12 deletions(-)

diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c
index 96557e6..17bcca5 100644
--- a/drivers/serial/sunhv.c
+++ b/drivers/serial/sunhv.c
@@ -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 = {
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c
index deb9ab4..8a0f9e4 100644
--- a/drivers/serial/sunsab.c
+++ b/drivers/serial/sunsab.c
@@ -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)
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index 2a63cdb..26d720b 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -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);
 }
 
 /*
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
index 15b6e1c..0a3e10a 100644
--- a/drivers/serial/sunzilog.c
+++ b/drivers/serial/sunzilog.c
@@ -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>
@@ -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)
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to