Commit b1e16506 authored by Paul Mackerras's avatar Paul Mackerras Committed by Linus Torvalds

[PATCH] SMP-safe macserial driver

The patch below removes the uses of save_flags/restore_flags/cli
etc. from the macserial driver and replaces them with a spinlock.
parent c2970ed3
...@@ -441,12 +441,8 @@ static _INLINE_ void receive_chars(struct mac_serial *info, ...@@ -441,12 +441,8 @@ static _INLINE_ void receive_chars(struct mac_serial *info,
static void transmit_chars(struct mac_serial *info) static void transmit_chars(struct mac_serial *info)
{ {
unsigned long flags;
save_flags(flags);
cli();
if ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) == 0) if ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) == 0)
goto out; return;
info->tx_active = 0; info->tx_active = 0;
if (info->x_char && !info->power_wait) { if (info->x_char && !info->power_wait) {
...@@ -454,13 +450,13 @@ static void transmit_chars(struct mac_serial *info) ...@@ -454,13 +450,13 @@ static void transmit_chars(struct mac_serial *info)
write_zsdata(info->zs_channel, info->x_char); write_zsdata(info->zs_channel, info->x_char);
info->x_char = 0; info->x_char = 0;
info->tx_active = 1; info->tx_active = 1;
goto out; return;
} }
if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tx_stopped if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tx_stopped
|| info->power_wait) { || info->power_wait) {
write_zsreg(info->zs_channel, 0, RES_Tx_P); write_zsreg(info->zs_channel, 0, RES_Tx_P);
goto out; return;
} }
/* Send char */ /* Send char */
...@@ -471,17 +467,17 @@ static void transmit_chars(struct mac_serial *info) ...@@ -471,17 +467,17 @@ static void transmit_chars(struct mac_serial *info)
if (info->xmit_cnt < WAKEUP_CHARS) if (info->xmit_cnt < WAKEUP_CHARS)
rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
out:
restore_flags(flags);
} }
static void powerup_done(unsigned long data) static void powerup_done(unsigned long data)
{ {
struct mac_serial *info = (struct mac_serial *) data; struct mac_serial *info = (struct mac_serial *) data;
unsigned long flags;
spin_lock_irqsave(&info->lock, flags);
info->power_wait = 0; info->power_wait = 0;
transmit_chars(info); transmit_chars(info);
spin_unlock_irqrestore(&info->lock, flags);
} }
static _INLINE_ void status_handle(struct mac_serial *info) static _INLINE_ void status_handle(struct mac_serial *info)
...@@ -567,6 +563,7 @@ static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs) ...@@ -567,6 +563,7 @@ static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
struct mac_serial *info = (struct mac_serial *) dev_id; struct mac_serial *info = (struct mac_serial *) dev_id;
unsigned char zs_intreg; unsigned char zs_intreg;
int shift; int shift;
unsigned long flags;
if (!(info->flags & ZILOG_INITIALIZED)) { if (!(info->flags & ZILOG_INITIALIZED)) {
printk(KERN_WARNING "rs_interrupt: irq %d, port not " printk(KERN_WARNING "rs_interrupt: irq %d, port not "
...@@ -588,6 +585,7 @@ static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs) ...@@ -588,6 +585,7 @@ static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
else else
shift = 0; /* Channel B */ shift = 0; /* Channel B */
spin_lock_irqsave(&info->lock, flags);
for (;;) { for (;;) {
zs_intreg = read_zsreg(info->zs_chan_a, 3) >> shift; zs_intreg = read_zsreg(info->zs_chan_a, 3) >> shift;
#ifdef SERIAL_DEBUG_INTR #ifdef SERIAL_DEBUG_INTR
...@@ -611,6 +609,7 @@ static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs) ...@@ -611,6 +609,7 @@ static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
if (zs_intreg & CHBEXT) if (zs_intreg & CHBEXT)
status_handle(info); status_handle(info);
} }
spin_unlock_irqrestore(&info->lock, flags);
} }
/* Transmit DMA interrupt - not used at present */ /* Transmit DMA interrupt - not used at present */
...@@ -672,13 +671,13 @@ static void rs_stop(struct tty_struct *tty) ...@@ -672,13 +671,13 @@ static void rs_stop(struct tty_struct *tty)
return; return;
#if 0 #if 0
save_flags(flags); cli(); spin_lock_irqsave(&info->lock, flags);
if (info->curregs[5] & TxENAB) { if (info->curregs[5] & TxENAB) {
info->curregs[5] &= ~TxENAB; info->curregs[5] &= ~TxENAB;
info->pendregs[5] &= ~TxENAB; info->pendregs[5] &= ~TxENAB;
write_zsreg(info->zs_channel, 5, info->curregs[5]); write_zsreg(info->zs_channel, 5, info->curregs[5]);
} }
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
#endif #endif
} }
...@@ -695,7 +694,7 @@ static void rs_start(struct tty_struct *tty) ...@@ -695,7 +694,7 @@ static void rs_start(struct tty_struct *tty)
if (serial_paranoia_check(info, tty->device, "rs_start")) if (serial_paranoia_check(info, tty->device, "rs_start"))
return; return;
save_flags(flags); cli(); spin_lock_irqsave(&info->lock, flags);
#if 0 #if 0
if (info->xmit_cnt && info->xmit_buf && !(info->curregs[5] & TxENAB)) { if (info->xmit_cnt && info->xmit_buf && !(info->curregs[5] & TxENAB)) {
info->curregs[5] |= TxENAB; info->curregs[5] |= TxENAB;
...@@ -707,7 +706,7 @@ static void rs_start(struct tty_struct *tty) ...@@ -707,7 +706,7 @@ static void rs_start(struct tty_struct *tty)
transmit_chars(info); transmit_chars(info);
} }
#endif #endif
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
} }
static void do_softint(void *private_) static void do_softint(void *private_)
...@@ -754,12 +753,11 @@ static int startup(struct mac_serial * info) ...@@ -754,12 +753,11 @@ static int startup(struct mac_serial * info)
unsigned long flags; unsigned long flags;
/* delay is in ms */ /* delay is in ms */
save_flags(flags); spin_lock_irqsave(&info->lock, flags);
cli();
info->power_wait = 1; info->power_wait = 1;
mod_timer(&info->powerup_timer, mod_timer(&info->powerup_timer,
jiffies + (delay * HZ + 999) / 1000); jiffies + (delay * HZ + 999) / 1000);
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
} }
OPNDBG("enabling IRQ on ttyS%d (irq %d)...\n", info->line, info->irq); OPNDBG("enabling IRQ on ttyS%d (irq %d)...\n", info->line, info->irq);
...@@ -1019,7 +1017,7 @@ static int setup_scc(struct mac_serial * info) ...@@ -1019,7 +1017,7 @@ static int setup_scc(struct mac_serial * info)
OPNDBG("setting up ttyS%d SCC...\n", info->line); OPNDBG("setting up ttyS%d SCC...\n", info->line);
save_flags(flags); cli(); /* Disable interrupts */ spin_lock_irqsave(&info->lock, flags);
/* Nice buggy HW ... */ /* Nice buggy HW ... */
fix_zero_bug_scc(info); fix_zero_bug_scc(info);
...@@ -1091,6 +1089,8 @@ static int setup_scc(struct mac_serial * info) ...@@ -1091,6 +1089,8 @@ static int setup_scc(struct mac_serial * info)
clear_bit(TTY_IO_ERROR, &info->tty->flags); clear_bit(TTY_IO_ERROR, &info->tty->flags);
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
spin_unlock_irqrestore(&info->lock, flags);
/* /*
* Set the speed of the serial port * Set the speed of the serial port
*/ */
...@@ -1099,8 +1099,6 @@ static int setup_scc(struct mac_serial * info) ...@@ -1099,8 +1099,6 @@ static int setup_scc(struct mac_serial * info)
/* Save the current value of RR0 */ /* Save the current value of RR0 */
info->read_reg_zero = read_zsreg(info->zs_channel, 0); info->read_reg_zero = read_zsreg(info->zs_channel, 0);
restore_flags(flags);
if (info->dma_initted) { if (info->dma_initted) {
spin_lock_irqsave(&info->rx_dma_lock, flags); spin_lock_irqsave(&info->rx_dma_lock, flags);
rxdma_start(info, 0); rxdma_start(info, 0);
...@@ -1214,10 +1212,7 @@ static int set_scc_power(struct mac_serial * info, int state) ...@@ -1214,10 +1212,7 @@ static int set_scc_power(struct mac_serial * info, int state)
static void irda_rts_pulses(struct mac_serial *info, int w) static void irda_rts_pulses(struct mac_serial *info, int w)
{ {
unsigned long flags;
udelay(w); udelay(w);
save_flags(flags); cli();
write_zsreg(info->zs_channel, 5, Tx8 | TxENAB); write_zsreg(info->zs_channel, 5, Tx8 | TxENAB);
udelay(2); udelay(2);
write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS); write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);
...@@ -1225,7 +1220,6 @@ static void irda_rts_pulses(struct mac_serial *info, int w) ...@@ -1225,7 +1220,6 @@ static void irda_rts_pulses(struct mac_serial *info, int w)
write_zsreg(info->zs_channel, 5, Tx8 | TxENAB); write_zsreg(info->zs_channel, 5, Tx8 | TxENAB);
udelay(4); udelay(4);
write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS); write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);
restore_flags(flags);
} }
/* /*
...@@ -1234,7 +1228,6 @@ static void irda_rts_pulses(struct mac_serial *info, int w) ...@@ -1234,7 +1228,6 @@ static void irda_rts_pulses(struct mac_serial *info, int w)
static void irda_setup(struct mac_serial *info) static void irda_setup(struct mac_serial *info)
{ {
int code, speed, t; int code, speed, t;
unsigned long flags;
speed = info->tty->termios->c_cflag & CBAUD; speed = info->tty->termios->c_cflag & CBAUD;
if (speed < B2400 || speed > B115200) if (speed < B2400 || speed > B115200)
...@@ -1268,10 +1261,8 @@ static void irda_setup(struct mac_serial *info) ...@@ -1268,10 +1261,8 @@ static void irda_setup(struct mac_serial *info)
/* set TxD low for ~104us and pulse RTS */ /* set TxD low for ~104us and pulse RTS */
udelay(1000); udelay(1000);
save_flags(flags); cli();
write_zsdata(info->zs_channel, 0xfe); write_zsdata(info->zs_channel, 0xfe);
irda_rts_pulses(info, 150); irda_rts_pulses(info, 150);
restore_flags(flags);
irda_rts_pulses(info, 180); irda_rts_pulses(info, 180);
irda_rts_pulses(info, 50); irda_rts_pulses(info, 50);
udelay(100); udelay(100);
...@@ -1351,7 +1342,7 @@ static void change_speed(struct mac_serial *info, struct termios *old_termios) ...@@ -1351,7 +1342,7 @@ static void change_speed(struct mac_serial *info, struct termios *old_termios)
else if (baud == 0) else if (baud == 0)
baud = 38400; baud = 38400;
save_flags(flags); cli(); spin_lock_irqsave(&info->lock, flags);
info->zs_baud = baud; info->zs_baud = baud;
info->clk_divisor = 16; info->clk_divisor = 16;
...@@ -1460,22 +1451,23 @@ static void change_speed(struct mac_serial *info, struct termios *old_termios) ...@@ -1460,22 +1451,23 @@ static void change_speed(struct mac_serial *info, struct termios *old_termios)
/* Load up the new values */ /* Load up the new values */
load_zsregs(info->zs_channel, info->curregs); load_zsregs(info->zs_channel, info->curregs);
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
} }
static void rs_flush_chars(struct tty_struct *tty) static void rs_flush_chars(struct tty_struct *tty)
{ {
struct mac_serial *info = (struct mac_serial *)tty->driver_data; struct mac_serial *info = (struct mac_serial *)tty->driver_data;
unsigned long flags;
if (serial_paranoia_check(info, tty->device, "rs_flush_chars")) if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
return; return;
if (info->xmit_cnt <= 0 || tty->stopped || info->tx_stopped || spin_lock_irqsave(&info->lock, flags);
!info->xmit_buf) if (!(info->xmit_cnt <= 0 || tty->stopped || info->tx_stopped ||
return; !info->xmit_buf))
/* Enable transmitter */
/* Enable transmitter */ transmit_chars(info);
transmit_chars(info); spin_unlock_irqrestore(&info->lock, flags);
} }
static int rs_write(struct tty_struct * tty, int from_user, static int rs_write(struct tty_struct * tty, int from_user,
...@@ -1506,15 +1498,14 @@ static int rs_write(struct tty_struct * tty, int from_user, ...@@ -1506,15 +1498,14 @@ static int rs_write(struct tty_struct * tty, int from_user,
ret = -EFAULT; ret = -EFAULT;
break; break;
} }
save_flags(flags); spin_lock_irqsave(&info->lock, flags);
cli();
c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
SERIAL_XMIT_SIZE - info->xmit_head)); SERIAL_XMIT_SIZE - info->xmit_head));
memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
info->xmit_head = ((info->xmit_head + c) & info->xmit_head = ((info->xmit_head + c) &
(SERIAL_XMIT_SIZE-1)); (SERIAL_XMIT_SIZE-1));
info->xmit_cnt += c; info->xmit_cnt += c;
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
buf += c; buf += c;
count -= c; count -= c;
ret += c; ret += c;
...@@ -1522,28 +1513,29 @@ static int rs_write(struct tty_struct * tty, int from_user, ...@@ -1522,28 +1513,29 @@ static int rs_write(struct tty_struct * tty, int from_user,
up(&tmp_buf_sem); up(&tmp_buf_sem);
} else { } else {
while (1) { while (1) {
save_flags(flags); spin_lock_irqsave(&info->lock, flags);
cli();
c = MIN(count, c = MIN(count,
MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
SERIAL_XMIT_SIZE - info->xmit_head)); SERIAL_XMIT_SIZE - info->xmit_head));
if (c <= 0) { if (c <= 0) {
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
break; break;
} }
memcpy(info->xmit_buf + info->xmit_head, buf, c); memcpy(info->xmit_buf + info->xmit_head, buf, c);
info->xmit_head = ((info->xmit_head + c) & info->xmit_head = ((info->xmit_head + c) &
(SERIAL_XMIT_SIZE-1)); (SERIAL_XMIT_SIZE-1));
info->xmit_cnt += c; info->xmit_cnt += c;
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
buf += c; buf += c;
count -= c; count -= c;
ret += c; ret += c;
} }
} }
spin_lock_irqsave(&info->lock, flags);
if (info->xmit_cnt && !tty->stopped && !info->tx_stopped if (info->xmit_cnt && !tty->stopped && !info->tx_stopped
&& !info->tx_active) && !info->tx_active)
transmit_chars(info); transmit_chars(info);
spin_unlock_irqrestore(&info->lock, flags);
return ret; return ret;
} }
...@@ -1576,9 +1568,9 @@ static void rs_flush_buffer(struct tty_struct *tty) ...@@ -1576,9 +1568,9 @@ static void rs_flush_buffer(struct tty_struct *tty)
if (serial_paranoia_check(info, tty->device, "rs_flush_buffer")) if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
return; return;
save_flags(flags); cli(); spin_lock_irqsave(&info->lock, flags);
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
wake_up_interruptible(&tty->write_wait); wake_up_interruptible(&tty->write_wait);
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
tty->ldisc.write_wakeup) tty->ldisc.write_wakeup)
...@@ -1605,11 +1597,11 @@ static void rs_throttle(struct tty_struct * tty) ...@@ -1605,11 +1597,11 @@ static void rs_throttle(struct tty_struct * tty)
return; return;
if (I_IXOFF(tty)) { if (I_IXOFF(tty)) {
save_flags(flags); cli(); spin_lock_irqsave(&info->lock, flags);
info->x_char = STOP_CHAR(tty); info->x_char = STOP_CHAR(tty);
if (!info->tx_active) if (!info->tx_active)
transmit_chars(info); transmit_chars(info);
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
} }
if (C_CRTSCTS(tty)) { if (C_CRTSCTS(tty)) {
...@@ -1627,21 +1619,21 @@ static void rs_throttle(struct tty_struct * tty) ...@@ -1627,21 +1619,21 @@ static void rs_throttle(struct tty_struct * tty)
* drop RTS. * drop RTS.
*/ */
if (info->is_internal_modem) { if (info->is_internal_modem) {
save_flags(flags); cli(); spin_lock_irqsave(&info->lock, flags);
info->curregs[5] &= ~RTS; info->curregs[5] &= ~RTS;
info->pendregs[5] &= ~RTS; info->pendregs[5] &= ~RTS;
write_zsreg(info->zs_channel, 5, info->curregs[5]); write_zsreg(info->zs_channel, 5, info->curregs[5]);
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
} }
} }
#ifdef CDTRCTS #ifdef CDTRCTS
if (tty->termios->c_cflag & CDTRCTS) { if (tty->termios->c_cflag & CDTRCTS) {
save_flags(flags); cli(); spin_lock_irqsave(&info->lock, flags);
info->curregs[5] &= ~DTR; info->curregs[5] &= ~DTR;
info->pendregs[5] &= ~DTR; info->pendregs[5] &= ~DTR;
write_zsreg(info->zs_channel, 5, info->curregs[5]); write_zsreg(info->zs_channel, 5, info->curregs[5]);
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
} }
#endif /* CDTRCTS */ #endif /* CDTRCTS */
} }
...@@ -1659,7 +1651,7 @@ static void rs_unthrottle(struct tty_struct * tty) ...@@ -1659,7 +1651,7 @@ static void rs_unthrottle(struct tty_struct * tty)
return; return;
if (I_IXOFF(tty)) { if (I_IXOFF(tty)) {
save_flags(flags); cli(); spin_lock_irqsave(&info->lock, flags);
if (info->x_char) if (info->x_char)
info->x_char = 0; info->x_char = 0;
else { else {
...@@ -1667,26 +1659,26 @@ static void rs_unthrottle(struct tty_struct * tty) ...@@ -1667,26 +1659,26 @@ static void rs_unthrottle(struct tty_struct * tty)
if (!info->tx_active) if (!info->tx_active)
transmit_chars(info); transmit_chars(info);
} }
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
} }
if (C_CRTSCTS(tty) && info->is_internal_modem) { if (C_CRTSCTS(tty) && info->is_internal_modem) {
/* Assert RTS line */ /* Assert RTS line */
save_flags(flags); cli(); spin_lock_irqsave(&info->lock, flags);
info->curregs[5] |= RTS; info->curregs[5] |= RTS;
info->pendregs[5] |= RTS; info->pendregs[5] |= RTS;
write_zsreg(info->zs_channel, 5, info->curregs[5]); write_zsreg(info->zs_channel, 5, info->curregs[5]);
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
} }
#ifdef CDTRCTS #ifdef CDTRCTS
if (tty->termios->c_cflag & CDTRCTS) { if (tty->termios->c_cflag & CDTRCTS) {
/* Assert DTR line */ /* Assert DTR line */
save_flags(flags); cli(); spin_lock_irqsave(&info->lock, flags);
info->curregs[5] |= DTR; info->curregs[5] |= DTR;
info->pendregs[5] |= DTR; info->pendregs[5] |= DTR;
write_zsreg(info->zs_channel, 5, info->curregs[5]); write_zsreg(info->zs_channel, 5, info->curregs[5]);
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
} }
#endif #endif
} }
...@@ -1779,9 +1771,9 @@ static int get_lsr_info(struct mac_serial * info, unsigned int *value) ...@@ -1779,9 +1771,9 @@ static int get_lsr_info(struct mac_serial * info, unsigned int *value)
unsigned char status; unsigned char status;
unsigned long flags; unsigned long flags;
save_flags(flags); cli(); spin_lock_irqsave(&info->lock, flags);
status = read_zsreg(info->zs_channel, 0); status = read_zsreg(info->zs_channel, 0);
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
status = (status & Tx_BUF_EMP)? TIOCSER_TEMT: 0; status = (status & Tx_BUF_EMP)? TIOCSER_TEMT: 0;
return put_user(status,value); return put_user(status,value);
} }
...@@ -1792,10 +1784,10 @@ static int get_modem_info(struct mac_serial *info, unsigned int *value) ...@@ -1792,10 +1784,10 @@ static int get_modem_info(struct mac_serial *info, unsigned int *value)
unsigned int result; unsigned int result;
unsigned long flags; unsigned long flags;
save_flags(flags); cli(); spin_lock_irqsave(&info->lock, flags);
control = info->curregs[5]; control = info->curregs[5];
status = read_zsreg(info->zs_channel, 0); status = read_zsreg(info->zs_channel, 0);
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
result = ((control & RTS) ? TIOCM_RTS: 0) result = ((control & RTS) ? TIOCM_RTS: 0)
| ((control & DTR) ? TIOCM_DTR: 0) | ((control & DTR) ? TIOCM_DTR: 0)
| ((status & DCD) ? TIOCM_CAR: 0) | ((status & DCD) ? TIOCM_CAR: 0)
...@@ -1812,7 +1804,7 @@ static int set_modem_info(struct mac_serial *info, unsigned int cmd, ...@@ -1812,7 +1804,7 @@ static int set_modem_info(struct mac_serial *info, unsigned int cmd,
if (get_user(arg, value)) if (get_user(arg, value))
return -EFAULT; return -EFAULT;
bits = (arg & TIOCM_RTS? RTS: 0) + (arg & TIOCM_DTR? DTR: 0); bits = (arg & TIOCM_RTS? RTS: 0) + (arg & TIOCM_DTR? DTR: 0);
save_flags(flags); cli(); spin_lock_irqsave(&info->lock, flags);
switch (cmd) { switch (cmd) {
case TIOCMBIS: case TIOCMBIS:
info->curregs[5] |= bits; info->curregs[5] |= bits;
...@@ -1824,12 +1816,12 @@ static int set_modem_info(struct mac_serial *info, unsigned int cmd, ...@@ -1824,12 +1816,12 @@ static int set_modem_info(struct mac_serial *info, unsigned int cmd,
info->curregs[5] = (info->curregs[5] & ~(DTR | RTS)) | bits; info->curregs[5] = (info->curregs[5] & ~(DTR | RTS)) | bits;
break; break;
default: default:
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
return -EINVAL; return -EINVAL;
} }
info->pendregs[5] = info->curregs[5]; info->pendregs[5] = info->curregs[5];
write_zsreg(info->zs_channel, 5, info->curregs[5]); write_zsreg(info->zs_channel, 5, info->curregs[5]);
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
return 0; return 0;
} }
...@@ -1844,13 +1836,13 @@ static void rs_break(struct tty_struct *tty, int break_state) ...@@ -1844,13 +1836,13 @@ static void rs_break(struct tty_struct *tty, int break_state)
if (serial_paranoia_check(info, tty->device, "rs_break")) if (serial_paranoia_check(info, tty->device, "rs_break"))
return; return;
save_flags(flags); cli(); spin_lock_irqsave(&info->lock, flags);
if (break_state == -1) if (break_state == -1)
info->curregs[5] |= SND_BRK; info->curregs[5] |= SND_BRK;
else else
info->curregs[5] &= ~SND_BRK; info->curregs[5] &= ~SND_BRK;
write_zsreg(info->zs_channel, 5, info->curregs[5]); write_zsreg(info->zs_channel, 5, info->curregs[5]);
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
} }
static int rs_ioctl(struct tty_struct *tty, struct file * file, static int rs_ioctl(struct tty_struct *tty, struct file * file,
...@@ -1932,11 +1924,11 @@ static void rs_close(struct tty_struct *tty, struct file * filp) ...@@ -1932,11 +1924,11 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
if (!info || serial_paranoia_check(info, tty->device, "rs_close")) if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
return; return;
save_flags(flags); cli(); spin_lock_irqsave(&info->lock, flags);
if (tty_hung_up_p(filp)) { if (tty_hung_up_p(filp)) {
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
return; return;
} }
...@@ -1960,7 +1952,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) ...@@ -1960,7 +1952,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
} }
if (info->count) { if (info->count) {
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
return; return;
} }
info->flags |= ZILOG_CLOSING; info->flags |= ZILOG_CLOSING;
...@@ -1979,9 +1971,9 @@ static void rs_close(struct tty_struct *tty, struct file * filp) ...@@ -1979,9 +1971,9 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
OPNDBG("waiting end of Tx... (timeout:%d)\n", info->closing_wait); OPNDBG("waiting end of Tx... (timeout:%d)\n", info->closing_wait);
tty->closing = 1; tty->closing = 1;
if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE) { if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE) {
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
tty_wait_until_sent(tty, info->closing_wait); tty_wait_until_sent(tty, info->closing_wait);
save_flags(flags); cli(); spin_lock_irqsave(&info->lock, flags);
} }
/* /*
...@@ -2001,15 +1993,15 @@ static void rs_close(struct tty_struct *tty, struct file * filp) ...@@ -2001,15 +1993,15 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
* has completely drained. * has completely drained.
*/ */
OPNDBG("waiting end of Rx...\n"); OPNDBG("waiting end of Rx...\n");
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
rs_wait_until_sent(tty, info->timeout); rs_wait_until_sent(tty, info->timeout);
save_flags(flags); cli(); spin_lock_irqsave(&info->lock, flags);
} }
shutdown(info); shutdown(info);
/* restore flags now since shutdown() will have disabled this port's /* restore flags now since shutdown() will have disabled this port's
specific irqs */ specific irqs */
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
if (tty->driver.flush_buffer) if (tty->driver.flush_buffer)
tty->driver.flush_buffer(tty); tty->driver.flush_buffer(tty);
...@@ -2174,18 +2166,18 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, ...@@ -2174,18 +2166,18 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
add_wait_queue(&info->open_wait, &wait); add_wait_queue(&info->open_wait, &wait);
OPNDBG("block_til_ready before block: ttyS%d, count = %d\n", OPNDBG("block_til_ready before block: ttyS%d, count = %d\n",
info->line, info->count); info->line, info->count);
cli(); spin_lock_irq(&info->lock);
if (!tty_hung_up_p(filp)) if (!tty_hung_up_p(filp))
info->count--; info->count--;
sti(); spin_unlock_irq(&info->lock);
info->blocked_open++; info->blocked_open++;
while (1) { while (1) {
cli(); spin_lock_irq(&info->lock);
if (!(info->flags & ZILOG_CALLOUT_ACTIVE) && if (!(info->flags & ZILOG_CALLOUT_ACTIVE) &&
(tty->termios->c_cflag & CBAUD) && (tty->termios->c_cflag & CBAUD) &&
!info->is_irda) !info->is_irda)
zs_rtsdtr(info, 1); zs_rtsdtr(info, 1);
sti(); spin_unlock_irq(&info->lock);
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) || if (tty_hung_up_p(filp) ||
!(info->flags & ZILOG_INITIALIZED)) { !(info->flags & ZILOG_INITIALIZED)) {
...@@ -2553,7 +2545,6 @@ probe_sccs() ...@@ -2553,7 +2545,6 @@ probe_sccs()
int macserial_init(void) int macserial_init(void)
{ {
int channel, i; int channel, i;
unsigned long flags;
struct mac_serial *info; struct mac_serial *info;
/* Find out how many Z8530 SCCs we have */ /* Find out how many Z8530 SCCs we have */
...@@ -2570,7 +2561,6 @@ int macserial_init(void) ...@@ -2570,7 +2561,6 @@ int macserial_init(void)
* We also request the OF resources here as probe_sccs() * We also request the OF resources here as probe_sccs()
* might be called too early for that * might be called too early for that
*/ */
save_flags(flags); cli();
for (i = 0; i < zs_channels_found; ++i) { for (i = 0; i < zs_channels_found; ++i) {
struct device_node* ch = zs_soft[i].dev_node; struct device_node* ch = zs_soft[i].dev_node;
if (!request_OF_resource(ch, 0, NULL)) { if (!request_OF_resource(ch, 0, NULL)) {
...@@ -2607,7 +2597,6 @@ int macserial_init(void) ...@@ -2607,7 +2597,6 @@ int macserial_init(void)
zs_soft[i].irq); zs_soft[i].irq);
disable_irq(zs_soft[i].irq); disable_irq(zs_soft[i].irq);
} }
restore_flags(flags);
show_serial_version(); show_serial_version();
...@@ -2723,6 +2712,7 @@ int macserial_init(void) ...@@ -2723,6 +2712,7 @@ int macserial_init(void)
info->count = 0; info->count = 0;
info->blocked_open = 0; info->blocked_open = 0;
INIT_WORK(&info->tqueue, do_softint, info); INIT_WORK(&info->tqueue, do_softint, info);
spin_lock_init(&info->lock);
info->callout_termios = callout_driver.init_termios; info->callout_termios = callout_driver.init_termios;
info->normal_termios = serial_driver.init_termios; info->normal_termios = serial_driver.init_termios;
init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->open_wait);
...@@ -2753,7 +2743,7 @@ void macserial_cleanup(void) ...@@ -2753,7 +2743,7 @@ void macserial_cleanup(void)
for (info = zs_chain, i = 0; info; info = info->zs_next, i++) for (info = zs_chain, i = 0; info; info = info->zs_next, i++)
set_scc_power(info, 0); set_scc_power(info, 0);
save_flags(flags); cli(); spin_lock_irqsave(&info->lock, flags);
for (i = 0; i < zs_channels_found; ++i) { for (i = 0; i < zs_channels_found; ++i) {
free_irq(zs_soft[i].irq, &zs_soft[i]); free_irq(zs_soft[i].irq, &zs_soft[i]);
if (zs_soft[i].has_dma) { if (zs_soft[i].has_dma) {
...@@ -2767,7 +2757,7 @@ void macserial_cleanup(void) ...@@ -2767,7 +2757,7 @@ void macserial_cleanup(void)
release_OF_resource(ch, ch->n_addrs - 1); release_OF_resource(ch, ch->n_addrs - 1);
} }
} }
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
tty_unregister_driver(&callout_driver); tty_unregister_driver(&callout_driver);
tty_unregister_driver(&serial_driver); tty_unregister_driver(&serial_driver);
...@@ -2944,7 +2934,7 @@ static int __init serial_console_setup(struct console *co, char *options) ...@@ -2944,7 +2934,7 @@ static int __init serial_console_setup(struct console *co, char *options)
} }
co->cflag = cflag; co->cflag = cflag;
save_flags(flags); cli(); spin_lock_irqsave(&info->lock, flags);
memset(info->curregs, 0, sizeof(info->curregs)); memset(info->curregs, 0, sizeof(info->curregs));
info->zs_baud = baud; info->zs_baud = baud;
...@@ -3026,7 +3016,7 @@ static int __init serial_console_setup(struct console *co, char *options) ...@@ -3026,7 +3016,7 @@ static int __init serial_console_setup(struct console *co, char *options)
/* Load up the new values */ /* Load up the new values */
load_zsregs(info->zs_channel, info->curregs); load_zsregs(info->zs_channel, info->curregs);
restore_flags(flags); spin_unlock_irqrestore(&info->lock, flags);
return 0; return 0;
} }
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
#ifndef _MACSERIAL_H #ifndef _MACSERIAL_H
#define _MACSERIAL_H #define _MACSERIAL_H
#include <linux/spinlock.h>
#define NUM_ZSREGS 16 #define NUM_ZSREGS 16
struct serial_struct { struct serial_struct {
...@@ -105,6 +107,7 @@ struct mac_serial { ...@@ -105,6 +107,7 @@ struct mac_serial {
struct mac_zschannel *zs_chan_a; /* A side registers */ struct mac_zschannel *zs_chan_a; /* A side registers */
unsigned char read_reg_zero; unsigned char read_reg_zero;
struct device_node* dev_node; struct device_node* dev_node;
spinlock_t lock;
char soft_carrier; /* Use soft carrier on this channel */ char soft_carrier; /* Use soft carrier on this channel */
char break_abort; /* Is serial console in, so process brk/abrt */ char break_abort; /* Is serial console in, so process brk/abrt */
......
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