aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFinn Thain <fthain@telegraphics.com.au>2011-12-06 12:49:36 -0500
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2011-12-07 22:22:53 -0500
commit7cf82b1b65833f207f55bb6dea32488f558b200b (patch)
treec5554bf1e9eca5d6b4a3af215795e1a20b9c6abd
parent2fde6d20bb75b53f1ead383b4713f95d0d6d9f59 (diff)
pmac_zilog: Fix unexpected irq
On most 68k Macs the SCC IRQ is an autovector interrupt and cannot be masked. This can be a problem when pmac_zilog starts up. For example, the serial debugging code in arch/m68k/kernel/head.S may be used beforehand. It disables the SCC interrupts at the chip but doesn't ack them. Then when a pmac_zilog port is used, the machine locks up with "unexpected interrupt". This can happen in pmz_shutdown() since the irq is freed before the channel interrupts are disabled. Fix this by clearing interrupt enable bits before the handler is uninstalled. Also move the interrupt control bit flipping into a separate pmz_interrupt_control() routine. Replace all instances of these operations with calls to this routine. Omit the zssync() calls that seem to serve no purpose. Signed-off-by: Finn Thain <fthain@telegraphics.com.au> Acked-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r--drivers/tty/serial/pmac_zilog.c102
1 files changed, 52 insertions, 50 deletions
diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c
index 5acd24a27d08..51941f02e936 100644
--- a/drivers/tty/serial/pmac_zilog.c
+++ b/drivers/tty/serial/pmac_zilog.c
@@ -216,6 +216,18 @@ static void pmz_maybe_update_regs(struct uart_pmac_port *uap)
216 } 216 }
217} 217}
218 218
219static void pmz_interrupt_control(struct uart_pmac_port *uap, int enable)
220{
221 if (enable) {
222 uap->curregs[1] |= INT_ALL_Rx | TxINT_ENAB;
223 if (!ZS_IS_EXTCLK(uap))
224 uap->curregs[1] |= EXT_INT_ENAB;
225 } else {
226 uap->curregs[1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
227 }
228 write_zsreg(uap, R1, uap->curregs[1]);
229}
230
219static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap) 231static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap)
220{ 232{
221 struct tty_struct *tty = NULL; 233 struct tty_struct *tty = NULL;
@@ -339,9 +351,7 @@ static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap)
339 351
340 return tty; 352 return tty;
341 flood: 353 flood:
342 uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK); 354 pmz_interrupt_control(uap, 0);
343 write_zsreg(uap, R1, uap->curregs[R1]);
344 zssync(uap);
345 pmz_error("pmz: rx irq flood !\n"); 355 pmz_error("pmz: rx irq flood !\n");
346 return tty; 356 return tty;
347} 357}
@@ -990,12 +1000,9 @@ static int pmz_startup(struct uart_port *port)
990 if (ZS_IS_IRDA(uap)) 1000 if (ZS_IS_IRDA(uap))
991 pmz_irda_reset(uap); 1001 pmz_irda_reset(uap);
992 1002
993 /* Enable interrupts emission from the chip */ 1003 /* Enable interrupt requests for the channel */
994 spin_lock_irqsave(&port->lock, flags); 1004 spin_lock_irqsave(&port->lock, flags);
995 uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB; 1005 pmz_interrupt_control(uap, 1);
996 if (!ZS_IS_EXTCLK(uap))
997 uap->curregs[R1] |= EXT_INT_ENAB;
998 write_zsreg(uap, R1, uap->curregs[R1]);
999 spin_unlock_irqrestore(&port->lock, flags); 1006 spin_unlock_irqrestore(&port->lock, flags);
1000 1007
1001 pmz_debug("pmz: startup() done.\n"); 1008 pmz_debug("pmz: startup() done.\n");
@@ -1015,6 +1022,25 @@ static void pmz_shutdown(struct uart_port *port)
1015 1022
1016 mutex_lock(&pmz_irq_mutex); 1023 mutex_lock(&pmz_irq_mutex);
1017 1024
1025 spin_lock_irqsave(&port->lock, flags);
1026
1027 if (!ZS_IS_ASLEEP(uap)) {
1028 /* Disable interrupt requests for the channel */
1029 pmz_interrupt_control(uap, 0);
1030
1031 if (!ZS_IS_CONS(uap)) {
1032 /* Disable receiver and transmitter */
1033 uap->curregs[R3] &= ~RxENABLE;
1034 uap->curregs[R5] &= ~TxENABLE;
1035
1036 /* Disable break assertion */
1037 uap->curregs[R5] &= ~SND_BRK;
1038 pmz_maybe_update_regs(uap);
1039 }
1040 }
1041
1042 spin_unlock_irqrestore(&port->lock, flags);
1043
1018 /* Release interrupt handler */ 1044 /* Release interrupt handler */
1019 free_irq(uap->port.irq, uap); 1045 free_irq(uap->port.irq, uap);
1020 1046
@@ -1025,29 +1051,8 @@ static void pmz_shutdown(struct uart_port *port)
1025 if (!ZS_IS_OPEN(uap->mate)) 1051 if (!ZS_IS_OPEN(uap->mate))
1026 pmz_get_port_A(uap)->flags &= ~PMACZILOG_FLAG_IS_IRQ_ON; 1052 pmz_get_port_A(uap)->flags &= ~PMACZILOG_FLAG_IS_IRQ_ON;
1027 1053
1028 /* Disable interrupts */ 1054 if (!ZS_IS_ASLEEP(uap) && !ZS_IS_CONS(uap))
1029 if (!ZS_IS_ASLEEP(uap)) { 1055 pmz_set_scc_power(uap, 0); /* Shut the chip down */
1030 uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
1031 write_zsreg(uap, R1, uap->curregs[R1]);
1032 zssync(uap);
1033 }
1034
1035 if (ZS_IS_CONS(uap) || ZS_IS_ASLEEP(uap)) {
1036 spin_unlock_irqrestore(&port->lock, flags);
1037 mutex_unlock(&pmz_irq_mutex);
1038 return;
1039 }
1040
1041 /* Disable receiver and transmitter. */
1042 uap->curregs[R3] &= ~RxENABLE;
1043 uap->curregs[R5] &= ~TxENABLE;
1044
1045 /* Disable all interrupts and BRK assertion. */
1046 uap->curregs[R5] &= ~SND_BRK;
1047 pmz_maybe_update_regs(uap);
1048
1049 /* Shut the chip down */
1050 pmz_set_scc_power(uap, 0);
1051 1056
1052 spin_unlock_irqrestore(&port->lock, flags); 1057 spin_unlock_irqrestore(&port->lock, flags);
1053 1058
@@ -1352,19 +1357,15 @@ static void pmz_set_termios(struct uart_port *port, struct ktermios *termios,
1352 spin_lock_irqsave(&port->lock, flags); 1357 spin_lock_irqsave(&port->lock, flags);
1353 1358
1354 /* Disable IRQs on the port */ 1359 /* Disable IRQs on the port */
1355 uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK); 1360 pmz_interrupt_control(uap, 0);
1356 write_zsreg(uap, R1, uap->curregs[R1]);
1357 1361
1358 /* Setup new port configuration */ 1362 /* Setup new port configuration */
1359 __pmz_set_termios(port, termios, old); 1363 __pmz_set_termios(port, termios, old);
1360 1364
1361 /* Re-enable IRQs on the port */ 1365 /* Re-enable IRQs on the port */
1362 if (ZS_IS_OPEN(uap)) { 1366 if (ZS_IS_OPEN(uap))
1363 uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB; 1367 pmz_interrupt_control(uap, 1);
1364 if (!ZS_IS_EXTCLK(uap)) 1368
1365 uap->curregs[R1] |= EXT_INT_ENAB;
1366 write_zsreg(uap, R1, uap->curregs[R1]);
1367 }
1368 spin_unlock_irqrestore(&port->lock, flags); 1369 spin_unlock_irqrestore(&port->lock, flags);
1369} 1370}
1370 1371
@@ -1671,14 +1672,17 @@ static int pmz_suspend(struct macio_dev *mdev, pm_message_t pm_state)
1671 spin_lock_irqsave(&uap->port.lock, flags); 1672 spin_lock_irqsave(&uap->port.lock, flags);
1672 1673
1673 if (ZS_IS_OPEN(uap) || ZS_IS_CONS(uap)) { 1674 if (ZS_IS_OPEN(uap) || ZS_IS_CONS(uap)) {
1674 /* Disable receiver and transmitter. */ 1675 /* Disable interrupt requests for the channel */
1676 pmz_interrupt_control(uap, 0);
1677
1678 /* Disable receiver and transmitter */
1675 uap->curregs[R3] &= ~RxENABLE; 1679 uap->curregs[R3] &= ~RxENABLE;
1676 uap->curregs[R5] &= ~TxENABLE; 1680 uap->curregs[R5] &= ~TxENABLE;
1677 1681
1678 /* Disable all interrupts and BRK assertion. */ 1682 /* Disable break assertion */
1679 uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
1680 uap->curregs[R5] &= ~SND_BRK; 1683 uap->curregs[R5] &= ~SND_BRK;
1681 pmz_load_zsregs(uap, uap->curregs); 1684 pmz_load_zsregs(uap, uap->curregs);
1685
1682 uap->flags |= PMACZILOG_FLAG_IS_ASLEEP; 1686 uap->flags |= PMACZILOG_FLAG_IS_ASLEEP;
1683 mb(); 1687 mb();
1684 } 1688 }
@@ -1738,14 +1742,6 @@ static int pmz_resume(struct macio_dev *mdev)
1738 /* Take care of config that may have changed while asleep */ 1742 /* Take care of config that may have changed while asleep */
1739 __pmz_set_termios(&uap->port, &uap->termios_cache, NULL); 1743 __pmz_set_termios(&uap->port, &uap->termios_cache, NULL);
1740 1744
1741 if (ZS_IS_OPEN(uap)) {
1742 /* Enable interrupts */
1743 uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB;
1744 if (!ZS_IS_EXTCLK(uap))
1745 uap->curregs[R1] |= EXT_INT_ENAB;
1746 write_zsreg(uap, R1, uap->curregs[R1]);
1747 }
1748
1749 spin_unlock_irqrestore(&uap->port.lock, flags); 1745 spin_unlock_irqrestore(&uap->port.lock, flags);
1750 1746
1751 if (ZS_IS_CONS(uap)) 1747 if (ZS_IS_CONS(uap))
@@ -1757,6 +1753,12 @@ static int pmz_resume(struct macio_dev *mdev)
1757 enable_irq(uap->port.irq); 1753 enable_irq(uap->port.irq);
1758 } 1754 }
1759 1755
1756 if (ZS_IS_OPEN(uap)) {
1757 spin_lock_irqsave(&uap->port.lock, flags);
1758 pmz_interrupt_control(uap, 1);
1759 spin_unlock_irqrestore(&uap->port.lock, flags);
1760 }
1761
1760 bail: 1762 bail:
1761 mutex_unlock(&state->port.mutex); 1763 mutex_unlock(&state->port.mutex);
1762 mutex_unlock(&pmz_irq_mutex); 1764 mutex_unlock(&pmz_irq_mutex);