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