diff options
Diffstat (limited to 'drivers/tty/serial/sunzilog.c')
| -rw-r--r-- | drivers/tty/serial/sunzilog.c | 151 |
1 files changed, 75 insertions, 76 deletions
diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c index 135a15203532..0551c24c06f5 100644 --- a/drivers/tty/serial/sunzilog.c +++ b/drivers/tty/serial/sunzilog.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* sunzilog.c: Zilog serial driver for Sparc systems. * * Driver for Zilog serial chips found on Sun workstations and @@ -32,17 +33,13 @@ #include <linux/serio.h> #endif #include <linux/init.h> -#include <linux/of_device.h> +#include <linux/of.h> +#include <linux/platform_device.h> -#include <asm/io.h> +#include <linux/io.h> #include <asm/irq.h> -#include <asm/prom.h> #include <asm/setup.h> -#if defined(CONFIG_SERIAL_SUNZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - #include <linux/serial_core.h> #include <linux/sunserialcore.h> @@ -103,7 +100,7 @@ struct uart_sunzilog_port { #endif }; -static void sunzilog_putchar(struct uart_port *port, int ch); +static void sunzilog_putchar(struct uart_port *port, unsigned char ch); #define ZILOG_CHANNEL_FROM_PORT(PORT) ((struct zilog_channel __iomem *)((PORT)->membase)) #define UART_ZILOG(PORT) ((struct uart_sunzilog_port *)(PORT)) @@ -309,7 +306,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up, switch (ret) { case 2: sunzilog_change_mouse_baud(up); - /* fallthru */ + fallthrough; case 1: break; @@ -319,7 +316,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up, serio_interrupt(&up->serio, ch, 0); #endif break; - }; + } } } @@ -456,7 +453,8 @@ static void sunzilog_status_handle(struct uart_sunzilog_port *up, static void sunzilog_transmit_chars(struct uart_sunzilog_port *up, struct zilog_channel __iomem *channel) { - struct circ_buf *xmit; + struct tty_port *tport; + unsigned char ch; if (ZS_IS_CONS(up)) { unsigned char status = readb(&channel->control); @@ -499,22 +497,20 @@ static void sunzilog_transmit_chars(struct uart_sunzilog_port *up, if (up->port.state == NULL) goto ack_tx_int; - xmit = &up->port.state->xmit; - if (uart_circ_empty(xmit)) - goto ack_tx_int; + tport = &up->port.state->port; if (uart_tx_stopped(&up->port)) goto ack_tx_int; + if (!uart_fifo_get(&up->port, &ch)) + goto ack_tx_int; + up->flags |= SUNZILOG_FLAG_TX_ACTIVE; - writeb(xmit->buf[xmit->tail], &channel->data); + writeb(ch, &channel->data); ZSDELAY(); ZS_WSYNC(channel); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - up->port.icount.tx++; - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&up->port); return; @@ -535,7 +531,7 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id) struct tty_port *port; unsigned char r3; - spin_lock(&up->port.lock); + uart_port_lock(&up->port); r3 = read_zsreg(channel, R3); /* Channel A */ @@ -552,7 +548,7 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id) if (r3 & CHATxIP) sunzilog_transmit_chars(up, channel); } - spin_unlock(&up->port.lock); + uart_port_unlock(&up->port); if (port) tty_flip_buffer_push(port); @@ -561,7 +557,7 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id) up = up->next; channel = ZILOG_CHANNEL_FROM_PORT(&up->port); - spin_lock(&up->port.lock); + uart_port_lock(&up->port); port = NULL; if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { writeb(RES_H_IUS, &channel->control); @@ -575,7 +571,7 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id) if (r3 & CHBTxIP) sunzilog_transmit_chars(up, channel); } - spin_unlock(&up->port.lock); + uart_port_unlock(&up->port); if (port) tty_flip_buffer_push(port); @@ -608,11 +604,11 @@ static unsigned int sunzilog_tx_empty(struct uart_port *port) unsigned char status; unsigned int ret; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); status = sunzilog_read_channel_status(port); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); if (status & Tx_BUF_EMP) ret = TIOCSER_TEMT; @@ -644,7 +640,8 @@ static unsigned int sunzilog_get_mctrl(struct uart_port *port) /* The port lock is held and interrupts are disabled. */ static void sunzilog_set_mctrl(struct uart_port *port, unsigned int mctrl) { - struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; + struct uart_sunzilog_port *up = + container_of(port, struct uart_sunzilog_port, port); struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port); unsigned char set_bits, clear_bits; @@ -668,7 +665,8 @@ static void sunzilog_set_mctrl(struct uart_port *port, unsigned int mctrl) /* The port lock is held and interrupts are disabled. */ static void sunzilog_stop_tx(struct uart_port *port) { - struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; + struct uart_sunzilog_port *up = + container_of(port, struct uart_sunzilog_port, port); up->flags |= SUNZILOG_FLAG_TX_STOPPED; } @@ -676,7 +674,8 @@ static void sunzilog_stop_tx(struct uart_port *port) /* The port lock is held and interrupts are disabled. */ static void sunzilog_start_tx(struct uart_port *port) { - struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; + struct uart_sunzilog_port *up = + container_of(port, struct uart_sunzilog_port, port); struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port); unsigned char status; @@ -701,16 +700,16 @@ static void sunzilog_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; - writeb(xmit->buf[xmit->tail], &channel->data); + if (!uart_fifo_get(&up->port, &ch)) + return; + writeb(ch, &channel->data); ZSDELAY(); ZS_WSYNC(channel); - 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(&up->port); } } @@ -734,7 +733,8 @@ static void sunzilog_stop_rx(struct uart_port *port) /* The port lock is held. */ static void sunzilog_enable_ms(struct uart_port *port) { - struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; + struct uart_sunzilog_port *up = + container_of(port, struct uart_sunzilog_port, port); struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port); unsigned char new_reg; @@ -750,7 +750,8 @@ static void sunzilog_enable_ms(struct uart_port *port) /* The port lock is not held. */ static void sunzilog_break_ctl(struct uart_port *port, int break_state) { - struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; + struct uart_sunzilog_port *up = + container_of(port, struct uart_sunzilog_port, port); struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port); unsigned char set_bits, clear_bits, new_reg; unsigned long flags; @@ -762,7 +763,7 @@ static void sunzilog_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 = (up->curregs[R5] | set_bits) & ~clear_bits; if (new_reg != up->curregs[R5]) { @@ -772,7 +773,7 @@ static void sunzilog_break_ctl(struct uart_port *port, int break_state) write_zsreg(channel, R5, up->curregs[R5]); } - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static void __sunzilog_startup(struct uart_sunzilog_port *up) @@ -798,9 +799,9 @@ static int sunzilog_startup(struct uart_port *port) if (ZS_IS_CONS(up)) return 0; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); __sunzilog_startup(up); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); return 0; } @@ -838,7 +839,7 @@ static void sunzilog_shutdown(struct uart_port *port) if (ZS_IS_CONS(up)) return; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); channel = ZILOG_CHANNEL_FROM_PORT(port); @@ -851,7 +852,7 @@ static void sunzilog_shutdown(struct uart_port *port) up->curregs[R5] &= ~SND_BRK; sunzilog_maybe_update_regs(up, channel); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } /* Shared by TTY driver and serial console setup. The port lock is held @@ -897,7 +898,7 @@ sunzilog_convert_to_zs(struct uart_sunzilog_port *up, unsigned int cflag, up->curregs[R5] |= Tx8; up->parity_mask = 0xff; break; - }; + } up->curregs[R4] &= ~0x0c; if (cflag & CSTOPB) up->curregs[R4] |= SB2; @@ -915,7 +916,7 @@ sunzilog_convert_to_zs(struct uart_sunzilog_port *up, unsigned int cflag, up->port.read_status_mask = Rx_OVR; if (iflag & INPCK) up->port.read_status_mask |= CRC_ERR | PAR_ERR; - if (iflag & (BRKINT | PARMRK)) + if (iflag & (IGNBRK | BRKINT | PARMRK)) up->port.read_status_mask |= BRK_ABRT; up->port.ignore_status_mask = 0; @@ -934,15 +935,16 @@ sunzilog_convert_to_zs(struct uart_sunzilog_port *up, unsigned int cflag, /* The port lock is not held. */ static void sunzilog_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { - struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; + struct uart_sunzilog_port *up = + container_of(port, struct uart_sunzilog_port, port); unsigned long flags; int baud, brg; baud = uart_get_baud_rate(port, termios, old, 1200, 76800); - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); @@ -959,7 +961,7 @@ sunzilog_set_termios(struct uart_port *port, struct ktermios *termios, uart_update_timeout(port, termios->c_cflag, baud); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); } static const char *sunzilog_type(struct uart_port *port) @@ -996,7 +998,8 @@ static int sunzilog_verify_port(struct uart_port *port, struct serial_struct *se static int sunzilog_get_poll_char(struct uart_port *port) { unsigned char ch, r1; - struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; + struct uart_sunzilog_port *up = + container_of(port, struct uart_sunzilog_port, port); struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(&up->port); @@ -1030,13 +1033,14 @@ static int sunzilog_get_poll_char(struct uart_port *port) static void sunzilog_put_poll_char(struct uart_port *port, unsigned char ch) { - struct uart_sunzilog_port *up = (struct uart_sunzilog_port *)port; + struct uart_sunzilog_port *up = + container_of(port, struct uart_sunzilog_port, port); sunzilog_putchar(&up->port, ch); } #endif /* CONFIG_CONSOLE_POLL */ -static struct uart_ops sunzilog_pops = { +static const struct uart_ops sunzilog_pops = { .tx_empty = sunzilog_tx_empty, .set_mctrl = sunzilog_set_mctrl, .get_mctrl = sunzilog_get_mctrl, @@ -1118,7 +1122,7 @@ static void sunzilog_free_tables(void) #define ZS_PUT_CHAR_MAX_DELAY 2000 /* 10 ms */ -static void sunzilog_putchar(struct uart_port *port, int ch) +static void __maybe_unused sunzilog_putchar(struct uart_port *port, unsigned char ch) { struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port); int loops = ZS_PUT_CHAR_MAX_DELAY; @@ -1195,20 +1199,16 @@ sunzilog_console_write(struct console *con, const char *s, unsigned int count) unsigned long flags; int locked = 1; - local_irq_save(flags); - if (up->port.sysrq) { - locked = 0; - } else if (oops_in_progress) { - locked = spin_trylock(&up->port.lock); - } else - spin_lock(&up->port.lock); + if (up->port.sysrq || oops_in_progress) + locked = uart_port_trylock_irqsave(&up->port, &flags); + else + uart_port_lock_irqsave(&up->port, &flags); uart_console_write(&up->port, s, count, sunzilog_putchar); udelay(2); if (locked) - spin_unlock(&up->port.lock); - local_irq_restore(flags); + uart_port_unlock_irqrestore(&up->port, flags); } static int __init sunzilog_console_setup(struct console *con, char *options) @@ -1218,7 +1218,7 @@ static int __init sunzilog_console_setup(struct console *con, char *options) int baud, brg; if (up->port.type != PORT_SUNZILOG) - return -1; + return -EINVAL; printk(KERN_INFO "Console: ttyS%d (SunZilog zs%d)\n", (sunzilog_reg.minor - 64) + con->index, con->index); @@ -1239,11 +1239,11 @@ static int __init sunzilog_console_setup(struct console *con, char *options) default: case B9600: baud = 9600; break; case B19200: baud = 19200; break; case B38400: baud = 38400; break; - }; + } brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); up->curregs[R15] |= BRKIE; sunzilog_convert_to_zs(up, con->cflag, 0, brg); @@ -1251,7 +1251,7 @@ static int __init sunzilog_console_setup(struct console *con, char *options) sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS); __sunzilog_startup(up); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); return 0; } @@ -1304,13 +1304,13 @@ static void sunzilog_register_serio(struct uart_sunzilog_port *up) serio->id.type = SERIO_RS232; if (up->flags & SUNZILOG_FLAG_CONS_KEYB) { serio->id.proto = SERIO_SUNKBD; - strlcpy(serio->name, "zskbd", sizeof(serio->name)); + strscpy(serio->name, "zskbd", sizeof(serio->name)); } else { serio->id.proto = SERIO_SUN; serio->id.extra = 1; - strlcpy(serio->name, "zsms", sizeof(serio->name)); + strscpy(serio->name, "zsms", sizeof(serio->name)); } - strlcpy(serio->phys, + strscpy(serio->phys, ((up->flags & SUNZILOG_FLAG_CONS_KEYB) ? "zs/serio0" : "zs/serio1"), sizeof(serio->phys)); @@ -1332,7 +1332,7 @@ static void sunzilog_init_hw(struct uart_sunzilog_port *up) channel = ZILOG_CHANNEL_FROM_PORT(&up->port); - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); if (ZS_IS_CHANNEL_A(up)) { write_zsreg(channel, R9, FHWRES); ZSDELAY_LONG(); @@ -1382,7 +1382,7 @@ static void sunzilog_init_hw(struct uart_sunzilog_port *up) write_zsreg(channel, R9, up->curregs[R9]); } - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); #ifdef CONFIG_SERIO if (up->flags & (SUNZILOG_FLAG_CONS_KEYB | @@ -1402,7 +1402,7 @@ static int zs_probe(struct platform_device *op) int keyboard_mouse = 0; int err; - if (of_find_property(op->dev.of_node, "keyboard", NULL)) + if (of_property_present(op->dev.of_node, "keyboard")) keyboard_mouse = 1; /* uarts must come before keyboards/mice */ @@ -1437,6 +1437,7 @@ static int zs_probe(struct platform_device *op) up[0].port.line = (inst * 2) + 0; up[0].port.dev = &op->dev; up[0].flags |= SUNZILOG_FLAG_IS_CHANNEL_A; + up[0].port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_SUNZILOG_CONSOLE); if (keyboard_mouse) up[0].flags |= SUNZILOG_FLAG_CONS_KEYB; sunzilog_init_hw(&up[0]); @@ -1454,6 +1455,7 @@ static int zs_probe(struct platform_device *op) up[1].port.line = (inst * 2) + 1; up[1].port.dev = &op->dev; up[1].flags |= 0; + up[1].port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_SUNZILOG_CONSOLE); if (keyboard_mouse) up[1].flags |= SUNZILOG_FLAG_CONS_MOUSE; sunzilog_init_hw(&up[1]); @@ -1510,7 +1512,7 @@ static void zs_remove_one(struct uart_sunzilog_port *up) uart_remove_one_port(&sunzilog_reg, &up->port); } -static int zs_remove(struct platform_device *op) +static void zs_remove(struct platform_device *op) { struct uart_sunzilog_port *up = platform_get_drvdata(op); struct zilog_layout __iomem *regs; @@ -1520,8 +1522,6 @@ static int zs_remove(struct platform_device *op) regs = sunzilog_chip_regs[up[0].port.line / 2]; of_iounmap(&op->resource[0], regs, sizeof(struct zilog_layout)); - - return 0; } static const struct of_device_id zs_match[] = { @@ -1535,7 +1535,6 @@ MODULE_DEVICE_TABLE(of, zs_match); static struct platform_driver zs_driver = { .driver = { .name = "zs", - .owner = THIS_MODULE, .of_match_table = zs_match, }, .probe = zs_probe, @@ -1551,7 +1550,7 @@ static int __init sunzilog_init(void) for_each_node_by_name(dp, "zs") { num_sunzilog++; - if (of_find_property(dp, "keyboard", NULL)) + if (of_property_present(dp, "keyboard")) num_keybms++; } |
