diff options
Diffstat (limited to 'drivers/tty/serial/pmac_zilog.c')
| -rw-r--r-- | drivers/tty/serial/pmac_zilog.c | 206 |
1 files changed, 63 insertions, 143 deletions
diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index ba65a3bbd72a..e3a919328695 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -24,7 +24,6 @@ */ #undef DEBUG -#undef DEBUG_HARD #undef USE_CTRL_O_SYSRQ #include <linux/module.h> @@ -47,14 +46,12 @@ #include <linux/of_address.h> #include <linux/of_irq.h> #include <asm/sections.h> -#include <asm/io.h> +#include <linux/io.h> #include <asm/irq.h> #ifdef CONFIG_PPC_PMAC -#include <asm/prom.h> #include <asm/machdep.h> #include <asm/pmac_feature.h> -#include <asm/dbdma.h> #include <asm/macio.h> #else #include <linux/platform_device.h> @@ -66,10 +63,6 @@ #include "pmac_zilog.h" -/* Not yet implemented */ -#undef HAS_DBDMA - -static char version[] __initdata = "pmac_zilog: 0.6 (Benjamin Herrenschmidt <benh@kernel.crashing.org>)"; MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); MODULE_DESCRIPTION("Driver for the Mac and PowerMac serial ports."); MODULE_LICENSE("GPL"); @@ -213,10 +206,10 @@ static void pmz_interrupt_control(struct uart_pmac_port *uap, int enable) } static bool pmz_receive_chars(struct uart_pmac_port *uap) + __must_hold(&uap->port.lock) { struct tty_port *port; unsigned char ch, r1, drop, flag; - int loops = 0; /* Sanity check, make sure the old bug is no longer happening */ if (uap->port.state == NULL) { @@ -252,9 +245,9 @@ static bool pmz_receive_chars(struct uart_pmac_port *uap) #endif /* USE_CTRL_O_SYSRQ */ if (uap->port.sysrq) { int swallow; - spin_unlock(&uap->port.lock); + uart_port_unlock(&uap->port); swallow = uart_handle_sysrq_char(&uap->port, ch); - spin_lock(&uap->port.lock); + uart_port_lock(&uap->port); if (swallow) goto next_char; } @@ -297,25 +290,12 @@ static bool pmz_receive_chars(struct uart_pmac_port *uap) if (r1 & Rx_OVR) tty_insert_flip_char(port, 0, TTY_OVERRUN); next_char: - /* We can get stuck in an infinite loop getting char 0 when the - * line is in a wrong HW state, we break that here. - * When that happens, I disable the receive side of the driver. - * Note that what I've been experiencing is a real irq loop where - * I'm getting flooded regardless of the actual port speed. - * Something strange is going on with the HW - */ - if ((++loops) > 1000) - goto flood; ch = read_zsreg(uap, R0); if (!(ch & Rx_CH_AV)) break; } return true; - flood: - pmz_interrupt_control(uap, 0); - pmz_error("pmz: rx irq flood !\n"); - return true; } static void pmz_status_handle(struct uart_pmac_port *uap) @@ -353,7 +333,8 @@ static void pmz_status_handle(struct uart_pmac_port *uap) static void pmz_transmit_chars(struct uart_pmac_port *uap) { - struct circ_buf *xmit; + struct tty_port *tport; + unsigned char ch; if (ZS_IS_CONS(uap)) { unsigned char status = read_zsreg(uap, R0); @@ -404,8 +385,8 @@ static void pmz_transmit_chars(struct uart_pmac_port *uap) if (uap->port.state == NULL) goto ack_tx_int; - xmit = &uap->port.state->xmit; - if (uart_circ_empty(xmit)) { + tport = &uap->port.state->port; + if (kfifo_is_empty(&tport->xmit_fifo)) { uart_write_wakeup(&uap->port); goto ack_tx_int; } @@ -413,13 +394,11 @@ static void pmz_transmit_chars(struct uart_pmac_port *uap) goto ack_tx_int; uap->flags |= PMACZILOG_FLAG_TX_ACTIVE; - write_zsdata(uap, xmit->buf[xmit->tail]); + WARN_ON(!uart_fifo_get(&uap->port, &ch)); + write_zsdata(uap, ch); zssync(uap); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - uap->port.icount.tx++; - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&uap->port); return; @@ -442,12 +421,9 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id) uap_a = pmz_get_port_A(uap); uap_b = uap_a->mate; - spin_lock(&uap_a->port.lock); + uart_port_lock(&uap_a->port); r3 = read_zsreg(uap_a, R3); -#ifdef DEBUG_HARD - pmz_debug("irq, r3: %x\n", r3); -#endif /* Channel A */ push = false; if (r3 & (CHAEXT | CHATxIP | CHARxIP)) { @@ -466,14 +442,14 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id) rc = IRQ_HANDLED; } skip_a: - spin_unlock(&uap_a->port.lock); + uart_port_unlock(&uap_a->port); if (push) tty_flip_buffer_push(&uap->port.state->port); if (!uap_b) goto out; - spin_lock(&uap_b->port.lock); + uart_port_lock(&uap_b->port); push = false; if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { if (!ZS_IS_OPEN(uap_b)) { @@ -491,7 +467,7 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id) rc = IRQ_HANDLED; } skip_b: - spin_unlock(&uap_b->port.lock); + uart_port_unlock(&uap_b->port); if (push) tty_flip_buffer_push(&uap->port.state->port); @@ -507,9 +483,9 @@ static inline u8 pmz_peek_status(struct uart_pmac_port *uap) unsigned long flags; u8 status; - spin_lock_irqsave(&uap->port.lock, flags); + uart_port_lock_irqsave(&uap->port, &flags); status = read_zsreg(uap, R0); - spin_unlock_irqrestore(&uap->port.lock, flags); + uart_port_unlock_irqrestore(&uap->port, flags); return status; } @@ -612,8 +588,6 @@ static void pmz_start_tx(struct uart_port *port) struct uart_pmac_port *uap = to_pmz(port); unsigned char status; - pmz_debug("pmz: start_tx()\n"); - uap->flags |= PMACZILOG_FLAG_TX_ACTIVE; uap->flags &= ~PMACZILOG_FLAG_TX_STOPPED; @@ -632,20 +606,17 @@ static void pmz_start_tx(struct uart_port *port) port->icount.tx++; port->x_char = 0; } else { - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; + unsigned char ch; - if (uart_circ_empty(xmit)) - goto out; - write_zsdata(uap, xmit->buf[xmit->tail]); + if (!uart_fifo_get(&uap->port, &ch)) + return; + write_zsdata(uap, ch); zssync(uap); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&uap->port); } - out: - pmz_debug("pmz: start_tx() done.\n"); } /* @@ -658,13 +629,9 @@ static void pmz_stop_rx(struct uart_port *port) { struct uart_pmac_port *uap = to_pmz(port); - pmz_debug("pmz: stop_rx()()\n"); - /* Disable all RX interrupts. */ uap->curregs[R1] &= ~RxINT_MASK; pmz_maybe_update_regs(uap); - - pmz_debug("pmz: stop_rx() done.\n"); } /* @@ -704,7 +671,7 @@ static void pmz_break_ctl(struct uart_port *port, int break_state) else clear_bits |= SND_BRK; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); new_reg = (uap->curregs[R5] | set_bits) & ~clear_bits; if (new_reg != uap->curregs[R5]) { @@ -712,7 +679,7 @@ static void pmz_break_ctl(struct uart_port *port, int break_state) write_zsreg(uap, R5, uap->curregs[R5]); } - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } #ifdef CONFIG_PPC_PMAC @@ -884,18 +851,18 @@ static void pmz_irda_reset(struct uart_pmac_port *uap) { unsigned long flags; - spin_lock_irqsave(&uap->port.lock, flags); + uart_port_lock_irqsave(&uap->port, &flags); uap->curregs[R5] |= DTR; write_zsreg(uap, R5, uap->curregs[R5]); zssync(uap); - spin_unlock_irqrestore(&uap->port.lock, flags); + uart_port_unlock_irqrestore(&uap->port, flags); msleep(110); - spin_lock_irqsave(&uap->port.lock, flags); + uart_port_lock_irqsave(&uap->port, &flags); uap->curregs[R5] &= ~DTR; write_zsreg(uap, R5, uap->curregs[R5]); zssync(uap); - spin_unlock_irqrestore(&uap->port.lock, flags); + uart_port_unlock_irqrestore(&uap->port, flags); msleep(10); } @@ -909,17 +876,15 @@ static int pmz_startup(struct uart_port *port) unsigned long flags; int pwr_delay = 0; - pmz_debug("pmz: startup()\n"); - uap->flags |= PMACZILOG_FLAG_IS_OPEN; /* A console is never powered down. Else, power up and * initialize the chip */ if (!ZS_IS_CONS(uap)) { - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); pwr_delay = __pmz_startup(uap); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } sprintf(uap->irq_name, PMACZILOG_NAME"%d", uap->port.line); if (request_irq(uap->port.irq, pmz_interrupt, IRQF_SHARED, @@ -942,11 +907,9 @@ static int pmz_startup(struct uart_port *port) pmz_irda_reset(uap); /* Enable interrupt requests for the channel */ - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); pmz_interrupt_control(uap, 1); - spin_unlock_irqrestore(&port->lock, flags); - - pmz_debug("pmz: startup() done.\n"); + uart_port_unlock_irqrestore(port, flags); return 0; } @@ -956,9 +919,7 @@ static void pmz_shutdown(struct uart_port *port) struct uart_pmac_port *uap = to_pmz(port); unsigned long flags; - pmz_debug("pmz: shutdown()\n"); - - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* Disable interrupt requests for the channel */ pmz_interrupt_control(uap, 0); @@ -973,21 +934,19 @@ static void pmz_shutdown(struct uart_port *port) pmz_maybe_update_regs(uap); } - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); /* Release interrupt handler */ free_irq(uap->port.irq, uap); - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); uap->flags &= ~PMACZILOG_FLAG_IS_OPEN; if (!ZS_IS_CONS(uap)) pmz_set_scc_power(uap, 0); /* Shut the chip down */ - spin_unlock_irqrestore(&port->lock, flags); - - pmz_debug("pmz: shutdown() done.\n"); + uart_port_unlock_irqrestore(port, flags); } /* Shared by TTY driver and serial console setup. The port lock is held @@ -1227,15 +1186,11 @@ static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud) static void __pmz_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct uart_pmac_port *uap = to_pmz(port); unsigned long baud; - pmz_debug("pmz: set_termios()\n"); - - memcpy(&uap->termios_cache, termios, sizeof(struct ktermios)); - /* XXX Check which revs of machines actually allow 1 and 4Mb speeds * on the IR dongle. Note that the IRTTY driver currently doesn't know * about the FIR mode and high speed modes. So these are unused. For @@ -1269,18 +1224,16 @@ static void __pmz_set_termios(struct uart_port *port, struct ktermios *termios, pmz_maybe_update_regs(uap); } uart_update_timeout(port, termios->c_cflag, baud); - - pmz_debug("pmz: set_termios() done.\n"); } /* The port lock is not held. */ static void pmz_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct uart_pmac_port *uap = to_pmz(port); unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* Disable IRQs on the port */ pmz_interrupt_control(uap, 0); @@ -1292,7 +1245,7 @@ static void pmz_set_termios(struct uart_port *port, struct ktermios *termios, if (ZS_IS_OPEN(uap)) pmz_interrupt_control(uap, 1); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static const char *pmz_type(struct uart_port *port) @@ -1399,7 +1352,7 @@ static int __init pmz_init_port(struct uart_pmac_port *uap) char name[1]; } *slots; int len; - struct resource r_ports, r_rxdma, r_txdma; + struct resource r_ports; /* * Request & map chip registers @@ -1411,35 +1364,6 @@ static int __init pmz_init_port(struct uart_pmac_port *uap) uap->control_reg = uap->port.membase; uap->data_reg = uap->control_reg + 0x10; - - /* - * Request & map DBDMA registers - */ -#ifdef HAS_DBDMA - if (of_address_to_resource(np, 1, &r_txdma) == 0 && - of_address_to_resource(np, 2, &r_rxdma) == 0) - uap->flags |= PMACZILOG_FLAG_HAS_DMA; -#else - memset(&r_txdma, 0, sizeof(struct resource)); - memset(&r_rxdma, 0, sizeof(struct resource)); -#endif - if (ZS_HAS_DMA(uap)) { - uap->tx_dma_regs = ioremap(r_txdma.start, 0x100); - if (uap->tx_dma_regs == NULL) { - uap->flags &= ~PMACZILOG_FLAG_HAS_DMA; - goto no_dma; - } - uap->rx_dma_regs = ioremap(r_rxdma.start, 0x100); - if (uap->rx_dma_regs == NULL) { - iounmap(uap->tx_dma_regs); - uap->tx_dma_regs = NULL; - uap->flags &= ~PMACZILOG_FLAG_HAS_DMA; - goto no_dma; - } - uap->tx_dma_irq = irq_of_parse_and_map(np, 1); - uap->rx_dma_irq = irq_of_parse_and_map(np, 2); - } -no_dma: /* * Detect port type @@ -1505,8 +1429,6 @@ no_dma: of_device_is_compatible(np->parent->parent, "gatwick")) { /* IRQs on gatwick are offset by 64 */ uap->port.irq = irq_create_mapping(NULL, 64 + 15); - uap->tx_dma_irq = irq_create_mapping(NULL, 64 + 4); - uap->rx_dma_irq = irq_create_mapping(NULL, 64 + 5); } /* Setup some valid baud rate information in the register @@ -1526,8 +1448,6 @@ static void pmz_dispose_port(struct uart_pmac_port *uap) struct device_node *np; np = uap->node; - iounmap(uap->rx_dma_regs); - iounmap(uap->tx_dma_regs); iounmap(uap->control_reg); uap->node = NULL; of_node_put(np); @@ -1573,12 +1493,12 @@ static int pmz_attach(struct macio_dev *mdev, const struct of_device_id *match) * That one should not be called, macio isn't really a hotswap device, * we don't expect one of those serial ports to go away... */ -static int pmz_detach(struct macio_dev *mdev) +static void pmz_detach(struct macio_dev *mdev) { struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev); if (!uap) - return -ENODEV; + return; uart_remove_one_port(&pmz_uart_reg, &uap->port); @@ -1589,11 +1509,8 @@ static int pmz_detach(struct macio_dev *mdev) dev_set_drvdata(&mdev->ofdev.dev, NULL); uap->dev = NULL; uap->port.dev = NULL; - - return 0; } - static int pmz_suspend(struct macio_dev *mdev, pm_message_t pm_state) { struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev); @@ -1643,7 +1560,7 @@ static int __init pmz_probe(void) * TODO: Add routines with proper locking to do that... */ node_a = node_b = NULL; - for (np = NULL; (np = of_get_next_child(node_p, np)) != NULL;) { + for_each_child_of_node(node_p, np) { if (of_node_name_prefix(np, "ch-a")) node_a = of_node_get(np); else if (of_node_name_prefix(np, "ch-b")) @@ -1692,6 +1609,11 @@ static int __init pmz_probe(void) #else +/* On PCI PowerMacs, pmz_probe() does an explicit search of the OpenFirmware + * tree to obtain the device_nodes needed to start the console before the + * macio driver. On Macs without OpenFirmware, global platform_devices take + * the place of those device_nodes. + */ extern struct platform_device scc_a_pdev, scc_b_pdev; static int __init pmz_init_port(struct uart_pmac_port *uap) @@ -1700,10 +1622,13 @@ static int __init pmz_init_port(struct uart_pmac_port *uap) int irq; r_ports = platform_get_resource(uap->pdev, IORESOURCE_MEM, 0); - irq = platform_get_irq(uap->pdev, 0); - if (!r_ports || irq <= 0) + if (!r_ports) return -ENODEV; + irq = platform_get_irq(uap->pdev, 0); + if (irq < 0) + return irq; + uap->port.mapbase = r_ports->start; uap->port.membase = (unsigned char __iomem *) r_ports->start; uap->port.iotype = UPIO_MEM; @@ -1756,7 +1681,7 @@ static void pmz_dispose_port(struct uart_pmac_port *uap) memset(uap, 0, sizeof(struct uart_pmac_port)); } -static int __init pmz_attach(struct platform_device *pdev) +static int pmz_attach(struct platform_device *pdev) { struct uart_pmac_port *uap; int i; @@ -1775,18 +1700,13 @@ static int __init pmz_attach(struct platform_device *pdev) return uart_add_one_port(&pmz_uart_reg, &uap->port); } -static int __exit pmz_detach(struct platform_device *pdev) +static void pmz_detach(struct platform_device *pdev) { struct uart_pmac_port *uap = platform_get_drvdata(pdev); - if (!uap) - return -ENODEV; - uart_remove_one_port(&pmz_uart_reg, &uap->port); uap->port.dev = NULL; - - return 0; } #endif /* !CONFIG_PPC_PMAC */ @@ -1855,7 +1775,8 @@ static struct macio_driver pmz_driver = { #else static struct platform_driver pmz_driver = { - .remove = __exit_p(pmz_detach), + .probe = pmz_attach, + .remove = pmz_detach, .driver = { .name = "scc", }, @@ -1866,7 +1787,6 @@ static struct platform_driver pmz_driver = { static int __init init_pmz(void) { int rc, i; - printk(KERN_INFO "%s\n", version); /* * First, we need to do a direct OF-based probe pass. We @@ -1904,7 +1824,7 @@ static int __init init_pmz(void) #ifdef CONFIG_PPC_PMAC return macio_register_driver(&pmz_driver); #else - return platform_driver_probe(&pmz_driver, pmz_attach); + return platform_driver_register(&pmz_driver); #endif } @@ -1935,7 +1855,7 @@ static void __exit exit_pmz(void) #ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE -static void pmz_console_putchar(struct uart_port *port, int ch) +static void pmz_console_putchar(struct uart_port *port, unsigned char ch) { struct uart_pmac_port *uap = container_of(port, struct uart_pmac_port, port); @@ -1955,7 +1875,7 @@ static void pmz_console_write(struct console *con, const char *s, unsigned int c struct uart_pmac_port *uap = &pmz_ports[con->index]; unsigned long flags; - spin_lock_irqsave(&uap->port.lock, flags); + uart_port_lock_irqsave(&uap->port, &flags); /* Turn of interrupts and enable the transmitter. */ write_zsreg(uap, R1, uap->curregs[1] & ~TxINT_ENAB); @@ -1967,7 +1887,7 @@ static void pmz_console_write(struct console *con, const char *s, unsigned int c write_zsreg(uap, R1, uap->curregs[1]); /* Don't disable the transmitter. */ - spin_unlock_irqrestore(&uap->port.lock, flags); + uart_port_unlock_irqrestore(&uap->port, flags); } /* |
