]> git.neil.brown.name Git - history.git/commitdiff
ppc64: Fix break handling in pmac_zilog driver, fixes for 64 bits kernel
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Fri, 13 Feb 2004 02:50:52 +0000 (13:50 +1100)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Fri, 13 Feb 2004 02:50:52 +0000 (13:50 +1100)
drivers/serial/pmac_zilog.c

index 43c13e34dcd570af828a32361f8c46938745d5c9..8be44af13e538f3243448b44dc6e2f7fbf7670fa 100644 (file)
 
 #include "pmac_zilog.h"
 
+#if defined(CONFIG_SERIAL_PMACZILOG_CONSOLE) && defined(CONFIG_PPC64)
+#define HAS_SCCDBG
+extern int sccdbg;
+#endif
 
 /* Not yet implemented */
 #undef HAS_DBDMA
@@ -170,7 +174,6 @@ static void pmz_load_zsregs(struct uart_pmac_port *up, u8 *regs)
  */
 static void pmz_maybe_update_regs(struct uart_pmac_port *up)
 {
-#if 1
                if (!ZS_REGS_HELD(up)) {
                if (ZS_TX_ACTIVE(up)) {
                        up->flags |= PMACZILOG_FLAG_REGS_HELD;
@@ -179,10 +182,6 @@ static void pmz_maybe_update_regs(struct uart_pmac_port *up)
                        pmz_load_zsregs(up, up->curregs);
                }
        }
-#else
-               pr_debug("pmz: maybe_update_regs: updating\n");
-        pmz_load_zsregs(up, up->curregs);
-#endif
 }
 
 static void pmz_receive_chars(struct uart_pmac_port *up, struct pt_regs *regs)
@@ -205,22 +204,18 @@ static void pmz_receive_chars(struct uart_pmac_port *up, struct pt_regs *regs)
                        zssync(up);
                }
 
-               ch = read_zsreg(up, R0);
-
-               /* This funny hack depends upon BRK_ABRT not interfering
-                * with the other bits we care about in R1.
-                */
-               if (ch & BRK_ABRT)
-                       r1 |= BRK_ABRT;
-
                ch = read_zsdata(up);
                ch &= up->parity_mask;
+               if (ch == 0 && up->prev_status & BRK_ABRT) {
+                       r1 |= BRK_ABRT;
+                       printk("rx break\n");
+               }
 
                /* A real serial line, record the character and status.  */
                *tty->flip.char_buf_ptr = ch;
                *tty->flip.flag_buf_ptr = TTY_NORMAL;
                up->port.icount.rx++;
-               if (r1 & (BRK_ABRT | PAR_ERR | Rx_OVR | CRC_ERR)) {
+               if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | BRK_ABRT)) {
                        if (r1 & BRK_ABRT) {
                                r1 &= ~(PAR_ERR | CRC_ERR);
                                up->port.icount.brk++;
@@ -274,6 +269,15 @@ static void pmz_status_handle(struct uart_pmac_port *up, struct pt_regs *regs)
        write_zsreg(up, R0, RES_EXT_INT);
        zssync(up);
 
+#ifdef HAS_SCCDBG
+       if (sccdbg && (status & BRK_ABRT) && !(up->prev_status & BRK_ABRT)) {
+#ifdef CONFIG_XMON
+               extern void xmon(struct pt_regs *);
+               xmon(regs);
+#endif
+       }
+#endif /* HAS_SCCDBG */
+
        if (ZS_WANTS_MODEM_STATUS(up)) {
                if (status & SYNC_HUNT)
                        up->port.icount.dsr++;
@@ -383,10 +387,10 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                write_zsreg(up_a, R0, RES_H_IUS);
                zssync(up_a);           
                pr_debug("pmz: irq channel A: %x\n", r3);
-               if (r3 & CHARxIP)
-                       pmz_receive_chars(up_a, regs);
                        if (r3 & CHAEXT)
                                pmz_status_handle(up_a, regs);
+               if (r3 & CHARxIP)
+                       pmz_receive_chars(up_a, regs);
                        if (r3 & CHATxIP)
                                pmz_transmit_chars(up_a);
                rc = IRQ_HANDLED;
@@ -398,10 +402,10 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                write_zsreg(up_b, R0, RES_H_IUS);
                zssync(up_b);
                pr_debug("pmz: irq channel B: %x\n", r3);
-                       if (r3 & CHBRxIP)
-                               pmz_receive_chars(up_b, regs);
                        if (r3 & CHBEXT)
                                pmz_status_handle(up_b, regs);
+                       if (r3 & CHBRxIP)
+                               pmz_receive_chars(up_b, regs);
                        if (r3 & CHBTxIP)
                                pmz_transmit_chars(up_b);
                rc = IRQ_HANDLED;
@@ -575,15 +579,12 @@ static void pmz_stop_rx(struct uart_port *port)
 
 /* 
  * Enable modem status change interrupts
- * The port lock is not held.
+ * The port lock is held.
  */
 static void pmz_enable_ms(struct uart_port *port)
 {
        struct uart_pmac_port *up = to_pmz(port);
        unsigned char new_reg;
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
 
        new_reg = up->curregs[R15] | (DCDIE | SYNCIE | CTSIE);
        if (new_reg != up->curregs[R15]) {
@@ -592,8 +593,6 @@ static void pmz_enable_ms(struct uart_port *port)
                /* NOTE: Not subject to 'transmitter active' rule.  */ 
                write_zsreg(up, R15, up->curregs[R15]);
        }
-
-       spin_unlock_irqrestore(&port->lock, flags);
 }
 
 /* 
@@ -765,7 +764,7 @@ static int __pmz_startup(struct uart_pmac_port *up)
        up->curregs[R9] |= NV | MIE;
 
        up->curregs[R1] |= EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
-       //      pmz_maybe_update_regs(up);
+               pmz_maybe_update_regs(up);
 
        return pwr_delay;
 }
@@ -1051,10 +1050,13 @@ pmz_set_termios(struct uart_port *port, struct termios *termios,
 
        pmz_convert_to_zs(up, termios->c_cflag, termios->c_iflag, baud);
 
-       if (UART_ENABLE_MS(&up->port, termios->c_cflag))
+       if (UART_ENABLE_MS(&up->port, termios->c_cflag)) {
+               up->curregs[R15] |= DCDIE | SYNCIE | CTSIE;
                up->flags |= PMACZILOG_FLAG_MODEM_STATUS;
-       else
+       } else {
+               up->curregs[R15] &= ~(DCDIE | SYNCIE | CTSIE);
                up->flags &= ~PMACZILOG_FLAG_MODEM_STATUS;
+       }
 
        /* set the irda codec to the right rate */
        if (ZS_IS_IRDA(up))
@@ -1120,7 +1122,7 @@ static struct uart_ops pmz_pops = {
  * Unlike sunzilog, we don't need to pre-init the spinlock as we don't
  * register our console before uart_add_one_port() is called
  */
-static int __init pmz_setup_port(struct uart_pmac_port *up)
+static int __init pmz_init_port(struct uart_pmac_port *up)
 {
        struct device_node *np = up->node;
        char *conn;
@@ -1225,13 +1227,6 @@ static void pmz_dispose_port(struct uart_pmac_port *up)
 {
        struct device_node *np;
 
-       if (up->flags & PMACZILOG_FLAG_RSRC_REQUESTED) {
-               release_OF_resource(up->node, 0);
-               if (ZS_HAS_DMA(up)) {
-                       release_OF_resource(up->node, up->node->n_addrs - 2);
-                       release_OF_resource(up->node, up->node->n_addrs - 1);
-               }
-       }
        iounmap((void *)up->control_reg);
        np = up->node;
        up->node = NULL;
@@ -1335,9 +1330,9 @@ static int __init pmz_probe(void)
                /*
                 * Setup the ports for real
                 */
-               rc = pmz_setup_port(&pmz_ports[count]);
+               rc = pmz_init_port(&pmz_ports[count]);
                if (rc == 0)
-                       rc = pmz_setup_port(&pmz_ports[count+1]);
+                       rc = pmz_init_port(&pmz_ports[count+1]);
                if (rc != 0) {
                        of_node_put(node_a);
                        of_node_put(node_b);
@@ -1581,6 +1576,8 @@ static int __init pmz_console_init(void)
        /* Probe ports */
        pmz_probe();
 
+#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE
+#endif
        /* TODO: Autoprobe console based on OF */
        /* pmz_console.index = i; */
        register_console(&pmz_console);