Commit 4aaa098f authored by David S. Miller's avatar David S. Miller

[SPARC]: Do tty_flip_buffer_push outside of port lock.

parent c6d6857c
...@@ -97,9 +97,10 @@ static __inline__ void sunsab_cec_wait(struct uart_sunsab_port *up) ...@@ -97,9 +97,10 @@ static __inline__ void sunsab_cec_wait(struct uart_sunsab_port *up)
udelay(1); udelay(1);
} }
static void receive_chars(struct uart_sunsab_port *up, static struct tty_struct *
union sab82532_irq_status *stat, receive_chars(struct uart_sunsab_port *up,
struct pt_regs *regs) union sab82532_irq_status *stat,
struct pt_regs *regs)
{ {
struct tty_struct *tty = NULL; struct tty_struct *tty = NULL;
unsigned char buf[32]; unsigned char buf[32];
...@@ -126,7 +127,7 @@ static void receive_chars(struct uart_sunsab_port *up, ...@@ -126,7 +127,7 @@ static void receive_chars(struct uart_sunsab_port *up,
if (stat->sreg.isr0 & SAB82532_ISR0_TIME) { if (stat->sreg.isr0 & SAB82532_ISR0_TIME) {
sunsab_cec_wait(up); sunsab_cec_wait(up);
writeb(SAB82532_CMDR_RFRD, &up->regs->w.cmdr); writeb(SAB82532_CMDR_RFRD, &up->regs->w.cmdr);
return; return tty;
} }
if (stat->sreg.isr0 & SAB82532_ISR0_RFO) if (stat->sreg.isr0 & SAB82532_ISR0_RFO)
...@@ -153,7 +154,7 @@ static void receive_chars(struct uart_sunsab_port *up, ...@@ -153,7 +154,7 @@ static void receive_chars(struct uart_sunsab_port *up,
if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) { if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
tty->flip.work.func((void *)tty); tty->flip.work.func((void *)tty);
if (tty->flip.count >= TTY_FLIPBUF_SIZE) if (tty->flip.count >= TTY_FLIPBUF_SIZE)
return; // if TTY_DONT_FLIP is set return tty; // if TTY_DONT_FLIP is set
} }
*tty->flip.char_buf_ptr = ch; *tty->flip.char_buf_ptr = ch;
...@@ -225,11 +226,10 @@ static void receive_chars(struct uart_sunsab_port *up, ...@@ -225,11 +226,10 @@ static void receive_chars(struct uart_sunsab_port *up,
} }
} }
if (tty)
tty_flip_buffer_push(tty);
if (saw_console_brk) if (saw_console_brk)
sun_do_break(); sun_do_break();
return tty;
} }
static void sunsab_stop_tx(struct uart_port *, unsigned int); static void sunsab_stop_tx(struct uart_port *, unsigned int);
...@@ -311,6 +311,7 @@ static void check_status(struct uart_sunsab_port *up, ...@@ -311,6 +311,7 @@ static void check_status(struct uart_sunsab_port *up,
static irqreturn_t sunsab_interrupt(int irq, void *dev_id, struct pt_regs *regs) static irqreturn_t sunsab_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{ {
struct uart_sunsab_port *up = dev_id; struct uart_sunsab_port *up = dev_id;
struct tty_struct *tty;
union sab82532_irq_status status; union sab82532_irq_status status;
unsigned long flags; unsigned long flags;
...@@ -322,10 +323,11 @@ static irqreturn_t sunsab_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -322,10 +323,11 @@ static irqreturn_t sunsab_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (readb(&up->regs->r.gis) & SAB82532_GIS_ISA1) if (readb(&up->regs->r.gis) & SAB82532_GIS_ISA1)
status.sreg.isr1 = readb(&up->regs->r.isr1); status.sreg.isr1 = readb(&up->regs->r.isr1);
tty = NULL;
if (status.stat) { if (status.stat) {
if (status.sreg.isr0 & (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME | if (status.sreg.isr0 & (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME |
SAB82532_ISR0_RFO | SAB82532_ISR0_RPF)) SAB82532_ISR0_RFO | SAB82532_ISR0_RPF))
receive_chars(up, &status, regs); tty = receive_chars(up, &status, regs);
if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) || if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) ||
(status.sreg.isr1 & SAB82532_ISR1_CSC)) (status.sreg.isr1 & SAB82532_ISR1_CSC))
check_status(up, &status); check_status(up, &status);
...@@ -335,6 +337,9 @@ static irqreturn_t sunsab_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -335,6 +337,9 @@ static irqreturn_t sunsab_interrupt(int irq, void *dev_id, struct pt_regs *regs)
spin_unlock(&up->port.lock); spin_unlock(&up->port.lock);
if (tty)
tty_flip_buffer_push(tty);
up++; up++;
spin_lock(&up->port.lock); spin_lock(&up->port.lock);
...@@ -345,10 +350,11 @@ static irqreturn_t sunsab_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -345,10 +350,11 @@ static irqreturn_t sunsab_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (readb(&up->regs->r.gis) & SAB82532_GIS_ISB1) if (readb(&up->regs->r.gis) & SAB82532_GIS_ISB1)
status.sreg.isr1 = readb(&up->regs->r.isr1); status.sreg.isr1 = readb(&up->regs->r.isr1);
tty = NULL;
if (status.stat) { if (status.stat) {
if (status.sreg.isr0 & (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME | if (status.sreg.isr0 & (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME |
SAB82532_ISR0_RFO | SAB82532_ISR0_RPF)) SAB82532_ISR0_RFO | SAB82532_ISR0_RPF))
receive_chars(up, &status, regs); tty = receive_chars(up, &status, regs);
if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) || if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) ||
(status.sreg.isr1 & (SAB82532_ISR1_BRK | SAB82532_ISR1_CSC))) (status.sreg.isr1 & (SAB82532_ISR1_BRK | SAB82532_ISR1_CSC)))
check_status(up, &status); check_status(up, &status);
...@@ -358,6 +364,9 @@ static irqreturn_t sunsab_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -358,6 +364,9 @@ static irqreturn_t sunsab_interrupt(int irq, void *dev_id, struct pt_regs *regs)
spin_unlock_irqrestore(&up->port.lock, flags); spin_unlock_irqrestore(&up->port.lock, flags);
if (tty)
tty_flip_buffer_push(tty);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
......
...@@ -310,7 +310,7 @@ static void sunsu_enable_ms(struct uart_port *port) ...@@ -310,7 +310,7 @@ static void sunsu_enable_ms(struct uart_port *port)
spin_unlock_irqrestore(&up->port.lock, flags); spin_unlock_irqrestore(&up->port.lock, flags);
} }
static _INLINE_ void static _INLINE_ struct tty_struct *
receive_chars(struct uart_sunsu_port *up, unsigned char *status, struct pt_regs *regs) receive_chars(struct uart_sunsu_port *up, unsigned char *status, struct pt_regs *regs)
{ {
struct tty_struct *tty = up->port.info->tty; struct tty_struct *tty = up->port.info->tty;
...@@ -322,7 +322,7 @@ receive_chars(struct uart_sunsu_port *up, unsigned char *status, struct pt_regs ...@@ -322,7 +322,7 @@ receive_chars(struct uart_sunsu_port *up, unsigned char *status, struct pt_regs
if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) { if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
tty->flip.work.func((void *)tty); tty->flip.work.func((void *)tty);
if (tty->flip.count >= TTY_FLIPBUF_SIZE) if (tty->flip.count >= TTY_FLIPBUF_SIZE)
return; // if TTY_DONT_FLIP is set return tty; // if TTY_DONT_FLIP is set
} }
ch = serial_inp(up, UART_RX); ch = serial_inp(up, UART_RX);
*tty->flip.char_buf_ptr = ch; *tty->flip.char_buf_ptr = ch;
...@@ -396,10 +396,11 @@ receive_chars(struct uart_sunsu_port *up, unsigned char *status, struct pt_regs ...@@ -396,10 +396,11 @@ receive_chars(struct uart_sunsu_port *up, unsigned char *status, struct pt_regs
ignore_char: ignore_char:
*status = serial_inp(up, UART_LSR); *status = serial_inp(up, UART_LSR);
} while ((*status & UART_LSR_DR) && (max_count-- > 0)); } while ((*status & UART_LSR_DR) && (max_count-- > 0));
tty_flip_buffer_push(tty);
if (saw_console_brk) if (saw_console_brk)
sun_do_break(); sun_do_break();
return tty;
} }
static _INLINE_ void transmit_chars(struct uart_sunsu_port *up) static _INLINE_ void transmit_chars(struct uart_sunsu_port *up)
...@@ -464,12 +465,23 @@ static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id, struct pt_regs ...@@ -464,12 +465,23 @@ static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id, struct pt_regs
spin_lock_irqsave(&up->port.lock, flags); spin_lock_irqsave(&up->port.lock, flags);
do { do {
struct tty_struct *tty;
status = serial_inp(up, UART_LSR); status = serial_inp(up, UART_LSR);
tty = NULL;
if (status & UART_LSR_DR) if (status & UART_LSR_DR)
receive_chars(up, &status, regs); tty = receive_chars(up, &status, regs);
check_modem_status(up); check_modem_status(up);
if (status & UART_LSR_THRE) if (status & UART_LSR_THRE)
transmit_chars(up); transmit_chars(up);
spin_unlock_irqrestore(&up->port.lock, flags);
if (tty)
tty_flip_buffer_push(tty);
spin_lock_irqsave(&up->port.lock, flags);
} while (!(serial_in(up, UART_IIR) & UART_IIR_NO_INT)); } while (!(serial_in(up, UART_IIR) & UART_IIR_NO_INT));
spin_unlock_irqrestore(&up->port.lock, flags); spin_unlock_irqrestore(&up->port.lock, flags);
......
...@@ -313,9 +313,10 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up, ...@@ -313,9 +313,10 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up,
} }
} }
static void sunzilog_receive_chars(struct uart_sunzilog_port *up, static struct tty_struct *
struct zilog_channel *channel, sunzilog_receive_chars(struct uart_sunzilog_port *up,
struct pt_regs *regs) struct zilog_channel *channel,
struct pt_regs *regs)
{ {
struct tty_struct *tty; struct tty_struct *tty;
unsigned char ch, r1; unsigned char ch, r1;
...@@ -414,8 +415,7 @@ static void sunzilog_receive_chars(struct uart_sunzilog_port *up, ...@@ -414,8 +415,7 @@ static void sunzilog_receive_chars(struct uart_sunzilog_port *up,
} }
} }
if (tty) return tty;
tty_flip_buffer_push(tty);
} }
static void sunzilog_status_handle(struct uart_sunzilog_port *up, static void sunzilog_status_handle(struct uart_sunzilog_port *up,
...@@ -550,19 +550,21 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *reg ...@@ -550,19 +550,21 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *reg
while (up) { while (up) {
struct zilog_channel *channel struct zilog_channel *channel
= ZILOG_CHANNEL_FROM_PORT(&up->port); = ZILOG_CHANNEL_FROM_PORT(&up->port);
struct tty_struct *tty;
unsigned char r3; unsigned char r3;
spin_lock(&up->port.lock); spin_lock(&up->port.lock);
r3 = read_zsreg(channel, R3); r3 = read_zsreg(channel, R3);
/* Channel A */ /* Channel A */
tty = NULL;
if (r3 & (CHAEXT | CHATxIP | CHARxIP)) { if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
sbus_writeb(RES_H_IUS, &channel->control); sbus_writeb(RES_H_IUS, &channel->control);
ZSDELAY(); ZSDELAY();
ZS_WSYNC(channel); ZS_WSYNC(channel);
if (r3 & CHARxIP) if (r3 & CHARxIP)
sunzilog_receive_chars(up, channel, regs); tty = sunzilog_receive_chars(up, channel, regs);
if (r3 & CHAEXT) if (r3 & CHAEXT)
sunzilog_status_handle(up, channel, regs); sunzilog_status_handle(up, channel, regs);
if (r3 & CHATxIP) if (r3 & CHATxIP)
...@@ -570,18 +572,22 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *reg ...@@ -570,18 +572,22 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *reg
} }
spin_unlock(&up->port.lock); spin_unlock(&up->port.lock);
if (tty)
tty_flip_buffer_push(tty);
/* Channel B */ /* Channel B */
up = up->next; up = up->next;
channel = ZILOG_CHANNEL_FROM_PORT(&up->port); channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
spin_lock(&up->port.lock); spin_lock(&up->port.lock);
tty = NULL;
if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
sbus_writeb(RES_H_IUS, &channel->control); sbus_writeb(RES_H_IUS, &channel->control);
ZSDELAY(); ZSDELAY();
ZS_WSYNC(channel); ZS_WSYNC(channel);
if (r3 & CHBRxIP) if (r3 & CHBRxIP)
sunzilog_receive_chars(up, channel, regs); tty = sunzilog_receive_chars(up, channel, regs);
if (r3 & CHBEXT) if (r3 & CHBEXT)
sunzilog_status_handle(up, channel, regs); sunzilog_status_handle(up, channel, regs);
if (r3 & CHBTxIP) if (r3 & CHBTxIP)
...@@ -589,6 +595,9 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *reg ...@@ -589,6 +595,9 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *reg
} }
spin_unlock(&up->port.lock); spin_unlock(&up->port.lock);
if (tty)
tty_flip_buffer_push(tty);
up = up->next; up = up->next;
} }
......
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