diff options
| author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-03-21 12:08:21 -0500 |
|---|---|---|
| committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-03-21 12:08:21 -0500 |
| commit | ac58c9059da8886b5e8cde012a80266b18ca146e (patch) | |
| tree | 40bf486843a2cace6c3a959d73423e50e6aa0c00 /drivers/serial | |
| parent | df6db302cb236ac3a683d535a3e2073d9f4b2833 (diff) | |
| parent | c4a1745aa09fc110afdefea0e5d025043e348bae (diff) | |
Merge branch 'linus'
Diffstat (limited to 'drivers/serial')
| -rw-r--r-- | drivers/serial/Kconfig | 7 | ||||
| -rw-r--r-- | drivers/serial/Makefile | 1 | ||||
| -rw-r--r-- | drivers/serial/sunhv.c | 550 | ||||
| -rw-r--r-- | drivers/serial/sunsab.c | 19 | ||||
| -rw-r--r-- | drivers/serial/sunsu.c | 26 | ||||
| -rw-r--r-- | drivers/serial/sunzilog.c | 35 |
6 files changed, 612 insertions, 26 deletions
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index b3c561abe3f6..89e5413cc2a3 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig | |||
| @@ -582,6 +582,13 @@ config SERIAL_SUNSAB_CONSOLE | |||
| 582 | on your Sparc system as the console, you can do so by answering | 582 | on your Sparc system as the console, you can do so by answering |
| 583 | Y to this option. | 583 | Y to this option. |
| 584 | 584 | ||
| 585 | config SERIAL_SUNHV | ||
| 586 | bool "Sun4v Hypervisor Console support" | ||
| 587 | depends on SPARC64 | ||
| 588 | help | ||
| 589 | This driver supports the console device found on SUN4V Sparc | ||
| 590 | systems. Say Y if you want to be able to use this device. | ||
| 591 | |||
| 585 | config SERIAL_IP22_ZILOG | 592 | config SERIAL_IP22_ZILOG |
| 586 | tristate "IP22 Zilog8530 serial support" | 593 | tristate "IP22 Zilog8530 serial support" |
| 587 | depends on SGI_IP22 | 594 | depends on SGI_IP22 |
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index eaf8e01db198..50c221af9e6d 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile | |||
| @@ -30,6 +30,7 @@ obj-$(CONFIG_SERIAL_PXA) += pxa.o | |||
| 30 | obj-$(CONFIG_SERIAL_SA1100) += sa1100.o | 30 | obj-$(CONFIG_SERIAL_SA1100) += sa1100.o |
| 31 | obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o | 31 | obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o |
| 32 | obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o | 32 | obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o |
| 33 | obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o | ||
| 33 | obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o | 34 | obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o |
| 34 | obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o | 35 | obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o |
| 35 | obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o | 36 | obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o |
diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c new file mode 100644 index 000000000000..f137804b3133 --- /dev/null +++ b/drivers/serial/sunhv.c | |||
| @@ -0,0 +1,550 @@ | |||
| 1 | /* sunhv.c: Serial driver for SUN4V hypervisor console. | ||
| 2 | * | ||
| 3 | * Copyright (C) 2006 David S. Miller (davem@davemloft.net) | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <linux/module.h> | ||
| 7 | #include <linux/kernel.h> | ||
| 8 | #include <linux/errno.h> | ||
| 9 | #include <linux/tty.h> | ||
| 10 | #include <linux/tty_flip.h> | ||
| 11 | #include <linux/major.h> | ||
| 12 | #include <linux/circ_buf.h> | ||
| 13 | #include <linux/serial.h> | ||
| 14 | #include <linux/sysrq.h> | ||
| 15 | #include <linux/console.h> | ||
| 16 | #include <linux/spinlock.h> | ||
| 17 | #include <linux/slab.h> | ||
| 18 | #include <linux/delay.h> | ||
| 19 | #include <linux/init.h> | ||
| 20 | |||
| 21 | #include <asm/hypervisor.h> | ||
| 22 | #include <asm/spitfire.h> | ||
| 23 | #include <asm/vdev.h> | ||
| 24 | #include <asm/oplib.h> | ||
| 25 | #include <asm/irq.h> | ||
| 26 | |||
| 27 | #if defined(CONFIG_MAGIC_SYSRQ) | ||
| 28 | #define SUPPORT_SYSRQ | ||
| 29 | #endif | ||
| 30 | |||
| 31 | #include <linux/serial_core.h> | ||
| 32 | |||
| 33 | #include "suncore.h" | ||
| 34 | |||
| 35 | #define CON_BREAK ((long)-1) | ||
| 36 | #define CON_HUP ((long)-2) | ||
| 37 | |||
| 38 | static inline long hypervisor_con_getchar(long *status) | ||
| 39 | { | ||
| 40 | register unsigned long func asm("%o5"); | ||
| 41 | register unsigned long arg0 asm("%o0"); | ||
| 42 | register unsigned long arg1 asm("%o1"); | ||
| 43 | |||
| 44 | func = HV_FAST_CONS_GETCHAR; | ||
| 45 | arg0 = 0; | ||
| 46 | arg1 = 0; | ||
| 47 | __asm__ __volatile__("ta %6" | ||
| 48 | : "=&r" (func), "=&r" (arg0), "=&r" (arg1) | ||
| 49 | : "0" (func), "1" (arg0), "2" (arg1), | ||
| 50 | "i" (HV_FAST_TRAP)); | ||
| 51 | |||
| 52 | *status = arg0; | ||
| 53 | |||
| 54 | return (long) arg1; | ||
| 55 | } | ||
| 56 | |||
| 57 | static inline long hypervisor_con_putchar(long ch) | ||
| 58 | { | ||
| 59 | register unsigned long func asm("%o5"); | ||
| 60 | register unsigned long arg0 asm("%o0"); | ||
| 61 | |||
| 62 | func = HV_FAST_CONS_PUTCHAR; | ||
| 63 | arg0 = ch; | ||
| 64 | __asm__ __volatile__("ta %4" | ||
| 65 | : "=&r" (func), "=&r" (arg0) | ||
| 66 | : "0" (func), "1" (arg0), "i" (HV_FAST_TRAP)); | ||
| 67 | |||
| 68 | return (long) arg0; | ||
| 69 | } | ||
| 70 | |||
| 71 | #define IGNORE_BREAK 0x1 | ||
| 72 | #define IGNORE_ALL 0x2 | ||
| 73 | |||
| 74 | static int hung_up = 0; | ||
| 75 | |||
| 76 | static struct tty_struct *receive_chars(struct uart_port *port, struct pt_regs *regs) | ||
| 77 | { | ||
| 78 | struct tty_struct *tty = NULL; | ||
| 79 | int saw_console_brk = 0; | ||
| 80 | int limit = 10000; | ||
| 81 | |||
| 82 | if (port->info != NULL) /* Unopened serial console */ | ||
| 83 | tty = port->info->tty; | ||
| 84 | |||
| 85 | while (limit-- > 0) { | ||
| 86 | long status; | ||
| 87 | long c = hypervisor_con_getchar(&status); | ||
| 88 | unsigned char flag; | ||
| 89 | |||
| 90 | if (status == HV_EWOULDBLOCK) | ||
| 91 | break; | ||
| 92 | |||
| 93 | if (c == CON_BREAK) { | ||
| 94 | if (uart_handle_break(port)) | ||
| 95 | continue; | ||
| 96 | saw_console_brk = 1; | ||
| 97 | c = 0; | ||
| 98 | } | ||
| 99 | |||
| 100 | if (c == CON_HUP) { | ||
| 101 | hung_up = 1; | ||
| 102 | uart_handle_dcd_change(port, 0); | ||
| 103 | } else if (hung_up) { | ||
| 104 | hung_up = 0; | ||
| 105 | uart_handle_dcd_change(port, 1); | ||
| 106 | } | ||
| 107 | |||
| 108 | if (tty == NULL) { | ||
| 109 | uart_handle_sysrq_char(port, c, regs); | ||
| 110 | continue; | ||
| 111 | } | ||
| 112 | |||
| 113 | flag = TTY_NORMAL; | ||
| 114 | port->icount.rx++; | ||
| 115 | if (c == CON_BREAK) { | ||
| 116 | port->icount.brk++; | ||
| 117 | if (uart_handle_break(port)) | ||
| 118 | continue; | ||
| 119 | flag = TTY_BREAK; | ||
| 120 | } | ||
| 121 | |||
| 122 | if (uart_handle_sysrq_char(port, c, regs)) | ||
| 123 | continue; | ||
| 124 | |||
| 125 | if ((port->ignore_status_mask & IGNORE_ALL) || | ||
| 126 | ((port->ignore_status_mask & IGNORE_BREAK) && | ||
| 127 | (c == CON_BREAK))) | ||
| 128 | continue; | ||
| 129 | |||
| 130 | tty_insert_flip_char(tty, c, flag); | ||
| 131 | } | ||
| 132 | |||
| 133 | if (saw_console_brk) | ||
| 134 | sun_do_break(); | ||
| 135 | |||
| 136 | return tty; | ||
| 137 | } | ||
| 138 | |||
| 139 | static void transmit_chars(struct uart_port *port) | ||
| 140 | { | ||
| 141 | struct circ_buf *xmit; | ||
| 142 | |||
| 143 | if (!port->info) | ||
| 144 | return; | ||
| 145 | |||
| 146 | xmit = &port->info->xmit; | ||
| 147 | if (uart_circ_empty(xmit) || uart_tx_stopped(port)) | ||
| 148 | return; | ||
| 149 | |||
| 150 | while (!uart_circ_empty(xmit)) { | ||
| 151 | long status = hypervisor_con_putchar(xmit->buf[xmit->tail]); | ||
| 152 | |||
| 153 | if (status != HV_EOK) | ||
| 154 | break; | ||
| 155 | |||
| 156 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); | ||
| 157 | port->icount.tx++; | ||
| 158 | } | ||
| 159 | |||
| 160 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) | ||
| 161 | uart_write_wakeup(port); | ||
| 162 | } | ||
| 163 | |||
| 164 | static irqreturn_t sunhv_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
| 165 | { | ||
| 166 | struct uart_port *port = dev_id; | ||
| 167 | struct tty_struct *tty; | ||
| 168 | unsigned long flags; | ||
| 169 | |||
| 170 | spin_lock_irqsave(&port->lock, flags); | ||
| 171 | tty = receive_chars(port, regs); | ||
| 172 | transmit_chars(port); | ||
| 173 | spin_unlock_irqrestore(&port->lock, flags); | ||
| 174 | |||
| 175 | if (tty) | ||
| 176 | tty_flip_buffer_push(tty); | ||
| 177 | |||
| 178 | return IRQ_HANDLED; | ||
| 179 | } | ||
| 180 | |||
| 181 | /* port->lock is not held. */ | ||
| 182 | static unsigned int sunhv_tx_empty(struct uart_port *port) | ||
| 183 | { | ||
| 184 | /* Transmitter is always empty for us. If the circ buffer | ||
| 185 | * is non-empty or there is an x_char pending, our caller | ||
| 186 | * will do the right thing and ignore what we return here. | ||
| 187 | */ | ||
| 188 | return TIOCSER_TEMT; | ||
| 189 | } | ||
| 190 | |||
| 191 | /* port->lock held by caller. */ | ||
| 192 | static void sunhv_set_mctrl(struct uart_port *port, unsigned int mctrl) | ||
| 193 | { | ||
| 194 | return; | ||
| 195 | } | ||
| 196 | |||
| 197 | /* port->lock is held by caller and interrupts are disabled. */ | ||
| 198 | static unsigned int sunhv_get_mctrl(struct uart_port *port) | ||
| 199 | { | ||
| 200 | return TIOCM_DSR | TIOCM_CAR | TIOCM_CTS; | ||
| 201 | } | ||
| 202 | |||
| 203 | /* port->lock held by caller. */ | ||
| 204 | static void sunhv_stop_tx(struct uart_port *port) | ||
| 205 | { | ||
| 206 | return; | ||
| 207 | } | ||
| 208 | |||
| 209 | /* port->lock held by caller. */ | ||
| 210 | static void sunhv_start_tx(struct uart_port *port) | ||
| 211 | { | ||
| 212 | struct circ_buf *xmit = &port->info->xmit; | ||
| 213 | |||
| 214 | while (!uart_circ_empty(xmit)) { | ||
| 215 | long status = hypervisor_con_putchar(xmit->buf[xmit->tail]); | ||
| 216 | |||
| 217 | if (status != HV_EOK) | ||
| 218 | break; | ||
| 219 | |||
| 220 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); | ||
| 221 | port->icount.tx++; | ||
| 222 | } | ||
| 223 | } | ||
| 224 | |||
| 225 | /* port->lock is not held. */ | ||
| 226 | static void sunhv_send_xchar(struct uart_port *port, char ch) | ||
| 227 | { | ||
| 228 | unsigned long flags; | ||
| 229 | int limit = 10000; | ||
| 230 | |||
| 231 | spin_lock_irqsave(&port->lock, flags); | ||
| 232 | |||
| 233 | while (limit-- > 0) { | ||
| 234 | long status = hypervisor_con_putchar(ch); | ||
| 235 | if (status == HV_EOK) | ||
| 236 | break; | ||
| 237 | } | ||
| 238 | |||
| 239 | spin_unlock_irqrestore(&port->lock, flags); | ||
| 240 | } | ||
| 241 | |||
| 242 | /* port->lock held by caller. */ | ||
| 243 | static void sunhv_stop_rx(struct uart_port *port) | ||
| 244 | { | ||
| 245 | } | ||
| 246 | |||
| 247 | /* port->lock held by caller. */ | ||
| 248 | static void sunhv_enable_ms(struct uart_port *port) | ||
| 249 | { | ||
| 250 | } | ||
| 251 | |||
| 252 | /* port->lock is not held. */ | ||
| 253 | static void sunhv_break_ctl(struct uart_port *port, int break_state) | ||
| 254 | { | ||
| 255 | if (break_state) { | ||
| 256 | unsigned long flags; | ||
| 257 | int limit = 1000000; | ||
| 258 | |||
| 259 | spin_lock_irqsave(&port->lock, flags); | ||
| 260 | |||
| 261 | while (limit-- > 0) { | ||
| 262 | long status = hypervisor_con_putchar(CON_BREAK); | ||
| 263 | if (status == HV_EOK) | ||
| 264 | break; | ||
| 265 | udelay(2); | ||
| 266 | } | ||
| 267 | |||
| 268 | spin_unlock_irqrestore(&port->lock, flags); | ||
| 269 | } | ||
| 270 | } | ||
| 271 | |||
| 272 | /* port->lock is not held. */ | ||
| 273 | static int sunhv_startup(struct uart_port *port) | ||
| 274 | { | ||
| 275 | return 0; | ||
| 276 | } | ||
| 277 | |||
| 278 | /* port->lock is not held. */ | ||
| 279 | static void sunhv_shutdown(struct uart_port *port) | ||
| 280 | { | ||
| 281 | } | ||
| 282 | |||
| 283 | /* port->lock is not held. */ | ||
| 284 | static void sunhv_set_termios(struct uart_port *port, struct termios *termios, | ||
| 285 | struct termios *old) | ||
| 286 | { | ||
| 287 | unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000); | ||
| 288 | unsigned int quot = uart_get_divisor(port, baud); | ||
| 289 | unsigned int iflag, cflag; | ||
| 290 | unsigned long flags; | ||
| 291 | |||
| 292 | spin_lock_irqsave(&port->lock, flags); | ||
| 293 | |||
| 294 | iflag = termios->c_iflag; | ||
| 295 | cflag = termios->c_cflag; | ||
| 296 | |||
| 297 | port->ignore_status_mask = 0; | ||
| 298 | if (iflag & IGNBRK) | ||
| 299 | port->ignore_status_mask |= IGNORE_BREAK; | ||
| 300 | if ((cflag & CREAD) == 0) | ||
| 301 | port->ignore_status_mask |= IGNORE_ALL; | ||
| 302 | |||
| 303 | /* XXX */ | ||
| 304 | uart_update_timeout(port, cflag, | ||
| 305 | (port->uartclk / (16 * quot))); | ||
| 306 | |||
| 307 | spin_unlock_irqrestore(&port->lock, flags); | ||
| 308 | } | ||
| 309 | |||
| 310 | static const char *sunhv_type(struct uart_port *port) | ||
| 311 | { | ||
| 312 | return "SUN4V HCONS"; | ||
| 313 | } | ||
| 314 | |||
| 315 | static void sunhv_release_port(struct uart_port *port) | ||
| 316 | { | ||
| 317 | } | ||
| 318 | |||
| 319 | static int sunhv_request_port(struct uart_port *port) | ||
| 320 | { | ||
| 321 | return 0; | ||
| 322 | } | ||
| 323 | |||
| 324 | static void sunhv_config_port(struct uart_port *port, int flags) | ||
| 325 | { | ||
| 326 | } | ||
| 327 | |||
| 328 | static int sunhv_verify_port(struct uart_port *port, struct serial_struct *ser) | ||
| 329 | { | ||
| 330 | return -EINVAL; | ||
| 331 | } | ||
| 332 | |||
| 333 | static struct uart_ops sunhv_pops = { | ||
| 334 | .tx_empty = sunhv_tx_empty, | ||
| 335 | .set_mctrl = sunhv_set_mctrl, | ||
| 336 | .get_mctrl = sunhv_get_mctrl, | ||
| 337 | .stop_tx = sunhv_stop_tx, | ||
| 338 | .start_tx = sunhv_start_tx, | ||
| 339 | .send_xchar = sunhv_send_xchar, | ||
| 340 | .stop_rx = sunhv_stop_rx, | ||
| 341 | .enable_ms = sunhv_enable_ms, | ||
| 342 | .break_ctl = sunhv_break_ctl, | ||
| 343 | .startup = sunhv_startup, | ||
| 344 | .shutdown = sunhv_shutdown, | ||
| 345 | .set_termios = sunhv_set_termios, | ||
| 346 | .type = sunhv_type, | ||
| 347 | .release_port = sunhv_release_port, | ||
| 348 | .request_port = sunhv_request_port, | ||
| 349 | .config_port = sunhv_config_port, | ||
| 350 | .verify_port = sunhv_verify_port, | ||
| 351 | }; | ||
| 352 | |||
| 353 | static struct uart_driver sunhv_reg = { | ||
| 354 | .owner = THIS_MODULE, | ||
| 355 | .driver_name = "serial", | ||
| 356 | .devfs_name = "tts/", | ||
| 357 | .dev_name = "ttyS", | ||
| 358 | .major = TTY_MAJOR, | ||
| 359 | }; | ||
| 360 | |||
| 361 | static struct uart_port *sunhv_port; | ||
| 362 | |||
| 363 | static inline void sunhv_console_putchar(struct uart_port *port, char c) | ||
| 364 | { | ||
| 365 | unsigned long flags; | ||
| 366 | int limit = 1000000; | ||
| 367 | |||
| 368 | spin_lock_irqsave(&port->lock, flags); | ||
| 369 | |||
| 370 | while (limit-- > 0) { | ||
| 371 | long status = hypervisor_con_putchar(c); | ||
| 372 | if (status == HV_EOK) | ||
| 373 | break; | ||
| 374 | udelay(2); | ||
| 375 | } | ||
| 376 | |||
| 377 | spin_unlock_irqrestore(&port->lock, flags); | ||
| 378 | } | ||
| 379 | |||
| 380 | static void sunhv_console_write(struct console *con, const char *s, unsigned n) | ||
| 381 | { | ||
| 382 | struct uart_port *port = sunhv_port; | ||
| 383 | int i; | ||
| 384 | |||
| 385 | for (i = 0; i < n; i++) { | ||
| 386 | if (*s == '\n') | ||
| 387 | sunhv_console_putchar(port, '\r'); | ||
| 388 | sunhv_console_putchar(port, *s++); | ||
| 389 | } | ||
| 390 | } | ||
| 391 | |||
| 392 | static struct console sunhv_console = { | ||
| 393 | .name = "ttyHV", | ||
| 394 | .write = sunhv_console_write, | ||
| 395 | .device = uart_console_device, | ||
| 396 | .flags = CON_PRINTBUFFER, | ||
| 397 | .index = -1, | ||
| 398 | .data = &sunhv_reg, | ||
| 399 | }; | ||
| 400 | |||
| 401 | static inline struct console *SUNHV_CONSOLE(void) | ||
| 402 | { | ||
| 403 | if (con_is_present()) | ||
| 404 | return NULL; | ||
| 405 | |||
| 406 | sunhv_console.index = 0; | ||
| 407 | |||
| 408 | return &sunhv_console; | ||
| 409 | } | ||
| 410 | |||
| 411 | static int __init hv_console_compatible(char *buf, int len) | ||
| 412 | { | ||
| 413 | while (len) { | ||
| 414 | int this_len; | ||
| 415 | |||
| 416 | if (!strcmp(buf, "qcn")) | ||
| 417 | return 1; | ||
| 418 | |||
| 419 | this_len = strlen(buf) + 1; | ||
| 420 | |||
| 421 | buf += this_len; | ||
| 422 | len -= this_len; | ||
| 423 | } | ||
| 424 | |||
| 425 | return 0; | ||
| 426 | } | ||
| 427 | |||
| 428 | static unsigned int __init get_interrupt(void) | ||
| 429 | { | ||
| 430 | const char *cons_str = "console"; | ||
| 431 | const char *compat_str = "compatible"; | ||
| 432 | int node = prom_getchild(sun4v_vdev_root); | ||
| 433 | char buf[64]; | ||
| 434 | int err, len; | ||
| 435 | |||
| 436 | node = prom_searchsiblings(node, cons_str); | ||
| 437 | if (!node) | ||
| 438 | return 0; | ||
| 439 | |||
| 440 | len = prom_getproplen(node, compat_str); | ||
| 441 | if (len == 0 || len == -1) | ||
| 442 | return 0; | ||
| 443 | |||
| 444 | err = prom_getproperty(node, compat_str, buf, 64); | ||
| 445 | if (err == -1) | ||
| 446 | return 0; | ||
| 447 | |||
| 448 | if (!hv_console_compatible(buf, len)) | ||
| 449 | return 0; | ||
| 450 | |||
| 451 | /* Ok, the this is the OBP node for the sun4v hypervisor | ||
| 452 | * console device. Decode the interrupt. | ||
| 453 | */ | ||
| 454 | return sun4v_vdev_device_interrupt(node); | ||
| 455 | } | ||
| 456 | |||
| 457 | static int __init sunhv_init(void) | ||
| 458 | { | ||
| 459 | struct uart_port *port; | ||
| 460 | int ret; | ||
| 461 | |||
| 462 | if (tlb_type != hypervisor) | ||
| 463 | return -ENODEV; | ||
| 464 | |||
| 465 | port = kmalloc(sizeof(struct uart_port), GFP_KERNEL); | ||
| 466 | if (unlikely(!port)) | ||
| 467 | return -ENOMEM; | ||
| 468 | |||
| 469 | memset(port, 0, sizeof(struct uart_port)); | ||
| 470 | |||
| 471 | port->line = 0; | ||
| 472 | port->ops = &sunhv_pops; | ||
| 473 | port->type = PORT_SUNHV; | ||
| 474 | port->uartclk = ( 29491200 / 16 ); /* arbitrary */ | ||
| 475 | |||
| 476 | /* Set this just to make uart_configure_port() happy. */ | ||
| 477 | port->membase = (unsigned char __iomem *) __pa(port); | ||
| 478 | |||
| 479 | port->irq = get_interrupt(); | ||
| 480 | if (!port->irq) { | ||
| 481 | kfree(port); | ||
| 482 | return -ENODEV; | ||
| 483 | } | ||
| 484 | |||
| 485 | sunhv_reg.minor = sunserial_current_minor; | ||
| 486 | sunhv_reg.nr = 1; | ||
| 487 | |||
| 488 | ret = uart_register_driver(&sunhv_reg); | ||
| 489 | if (ret < 0) { | ||
| 490 | printk(KERN_ERR "SUNHV: uart_register_driver() failed %d\n", | ||
| 491 | ret); | ||
| 492 | kfree(port); | ||
| 493 | |||
| 494 | return ret; | ||
| 495 | } | ||
| 496 | |||
| 497 | sunhv_reg.tty_driver->name_base = sunhv_reg.minor - 64; | ||
| 498 | sunserial_current_minor += 1; | ||
| 499 | |||
| 500 | sunhv_reg.cons = SUNHV_CONSOLE(); | ||
| 501 | |||
| 502 | sunhv_port = port; | ||
| 503 | |||
| 504 | ret = uart_add_one_port(&sunhv_reg, port); | ||
| 505 | if (ret < 0) { | ||
| 506 | printk(KERN_ERR "SUNHV: uart_add_one_port() failed %d\n", ret); | ||
| 507 | sunserial_current_minor -= 1; | ||
| 508 | uart_unregister_driver(&sunhv_reg); | ||
| 509 | kfree(port); | ||
| 510 | sunhv_port = NULL; | ||
| 511 | return -ENODEV; | ||
| 512 | } | ||
| 513 | |||
| 514 | if (request_irq(port->irq, sunhv_interrupt, | ||
| 515 | SA_SHIRQ, "serial(sunhv)", port)) { | ||
| 516 | printk(KERN_ERR "sunhv: Cannot register IRQ\n"); | ||
| 517 | uart_remove_one_port(&sunhv_reg, port); | ||
| 518 | sunserial_current_minor -= 1; | ||
| 519 | uart_unregister_driver(&sunhv_reg); | ||
| 520 | kfree(port); | ||
| 521 | sunhv_port = NULL; | ||
| 522 | return -ENODEV; | ||
| 523 | } | ||
| 524 | |||
| 525 | return 0; | ||
| 526 | } | ||
| 527 | |||
| 528 | static void __exit sunhv_exit(void) | ||
| 529 | { | ||
| 530 | struct uart_port *port = sunhv_port; | ||
| 531 | |||
| 532 | BUG_ON(!port); | ||
| 533 | |||
| 534 | free_irq(port->irq, port); | ||
| 535 | |||
| 536 | uart_remove_one_port(&sunhv_reg, port); | ||
| 537 | sunserial_current_minor -= 1; | ||
| 538 | |||
| 539 | uart_unregister_driver(&sunhv_reg); | ||
| 540 | |||
| 541 | kfree(sunhv_port); | ||
| 542 | sunhv_port = NULL; | ||
| 543 | } | ||
| 544 | |||
| 545 | module_init(sunhv_init); | ||
| 546 | module_exit(sunhv_exit); | ||
| 547 | |||
| 548 | MODULE_AUTHOR("David S. Miller"); | ||
| 549 | MODULE_DESCRIPTION("SUN4V Hypervisor console driver") | ||
| 550 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c index 85664228a0b6..a2fb0c2fb121 100644 --- a/drivers/serial/sunsab.c +++ b/drivers/serial/sunsab.c | |||
| @@ -955,14 +955,13 @@ static struct console sunsab_console = { | |||
| 955 | .index = -1, | 955 | .index = -1, |
| 956 | .data = &sunsab_reg, | 956 | .data = &sunsab_reg, |
| 957 | }; | 957 | }; |
| 958 | #define SUNSAB_CONSOLE (&sunsab_console) | ||
| 959 | 958 | ||
| 960 | static void __init sunsab_console_init(void) | 959 | static inline struct console *SUNSAB_CONSOLE(void) |
| 961 | { | 960 | { |
| 962 | int i; | 961 | int i; |
| 963 | 962 | ||
| 964 | if (con_is_present()) | 963 | if (con_is_present()) |
| 965 | return; | 964 | return NULL; |
| 966 | 965 | ||
| 967 | for (i = 0; i < num_channels; i++) { | 966 | for (i = 0; i < num_channels; i++) { |
| 968 | int this_minor = sunsab_reg.minor + i; | 967 | int this_minor = sunsab_reg.minor + i; |
| @@ -971,13 +970,14 @@ static void __init sunsab_console_init(void) | |||
| 971 | break; | 970 | break; |
| 972 | } | 971 | } |
| 973 | if (i == num_channels) | 972 | if (i == num_channels) |
| 974 | return; | 973 | return NULL; |
| 975 | 974 | ||
| 976 | sunsab_console.index = i; | 975 | sunsab_console.index = i; |
| 977 | register_console(&sunsab_console); | 976 | |
| 977 | return &sunsab_console; | ||
| 978 | } | 978 | } |
| 979 | #else | 979 | #else |
| 980 | #define SUNSAB_CONSOLE (NULL) | 980 | #define SUNSAB_CONSOLE() (NULL) |
| 981 | #define sunsab_console_init() do { } while (0) | 981 | #define sunsab_console_init() do { } while (0) |
| 982 | #endif | 982 | #endif |
| 983 | 983 | ||
| @@ -1124,7 +1124,6 @@ static int __init sunsab_init(void) | |||
| 1124 | 1124 | ||
| 1125 | sunsab_reg.minor = sunserial_current_minor; | 1125 | sunsab_reg.minor = sunserial_current_minor; |
| 1126 | sunsab_reg.nr = num_channels; | 1126 | sunsab_reg.nr = num_channels; |
| 1127 | sunsab_reg.cons = SUNSAB_CONSOLE; | ||
| 1128 | 1127 | ||
| 1129 | ret = uart_register_driver(&sunsab_reg); | 1128 | ret = uart_register_driver(&sunsab_reg); |
| 1130 | if (ret < 0) { | 1129 | if (ret < 0) { |
| @@ -1143,10 +1142,12 @@ static int __init sunsab_init(void) | |||
| 1143 | return ret; | 1142 | return ret; |
| 1144 | } | 1143 | } |
| 1145 | 1144 | ||
| 1145 | sunsab_reg.tty_driver->name_base = sunsab_reg.minor - 64; | ||
| 1146 | |||
| 1147 | sunsab_reg.cons = SUNSAB_CONSOLE(); | ||
| 1148 | |||
| 1146 | sunserial_current_minor += num_channels; | 1149 | sunserial_current_minor += num_channels; |
| 1147 | 1150 | ||
| 1148 | sunsab_console_init(); | ||
| 1149 | |||
| 1150 | for (i = 0; i < num_channels; i++) { | 1151 | for (i = 0; i < num_channels; i++) { |
| 1151 | struct uart_sunsab_port *up = &sunsab_ports[i]; | 1152 | struct uart_sunsab_port *up = &sunsab_ports[i]; |
| 1152 | 1153 | ||
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index 4e453fa966ae..46c44b83f57c 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c | |||
| @@ -1280,6 +1280,7 @@ static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up, int channel) | |||
| 1280 | struct serio *serio; | 1280 | struct serio *serio; |
| 1281 | #endif | 1281 | #endif |
| 1282 | 1282 | ||
| 1283 | spin_lock_init(&up->port.lock); | ||
| 1283 | up->port.line = channel; | 1284 | up->port.line = channel; |
| 1284 | up->port.type = PORT_UNKNOWN; | 1285 | up->port.type = PORT_UNKNOWN; |
| 1285 | up->port.uartclk = (SU_BASE_BAUD * 16); | 1286 | up->port.uartclk = (SU_BASE_BAUD * 16); |
| @@ -1464,18 +1465,17 @@ static struct console sunsu_cons = { | |||
| 1464 | .index = -1, | 1465 | .index = -1, |
| 1465 | .data = &sunsu_reg, | 1466 | .data = &sunsu_reg, |
| 1466 | }; | 1467 | }; |
| 1467 | #define SUNSU_CONSOLE (&sunsu_cons) | ||
| 1468 | 1468 | ||
| 1469 | /* | 1469 | /* |
| 1470 | * Register console. | 1470 | * Register console. |
| 1471 | */ | 1471 | */ |
| 1472 | 1472 | ||
| 1473 | static int __init sunsu_serial_console_init(void) | 1473 | static inline struct console *SUNSU_CONSOLE(void) |
| 1474 | { | 1474 | { |
| 1475 | int i; | 1475 | int i; |
| 1476 | 1476 | ||
| 1477 | if (con_is_present()) | 1477 | if (con_is_present()) |
| 1478 | return 0; | 1478 | return NULL; |
| 1479 | 1479 | ||
| 1480 | for (i = 0; i < UART_NR; i++) { | 1480 | for (i = 0; i < UART_NR; i++) { |
| 1481 | int this_minor = sunsu_reg.minor + i; | 1481 | int this_minor = sunsu_reg.minor + i; |
| @@ -1484,16 +1484,16 @@ static int __init sunsu_serial_console_init(void) | |||
| 1484 | break; | 1484 | break; |
| 1485 | } | 1485 | } |
| 1486 | if (i == UART_NR) | 1486 | if (i == UART_NR) |
| 1487 | return 0; | 1487 | return NULL; |
| 1488 | if (sunsu_ports[i].port_node == 0) | 1488 | if (sunsu_ports[i].port_node == 0) |
| 1489 | return 0; | 1489 | return NULL; |
| 1490 | 1490 | ||
| 1491 | sunsu_cons.index = i; | 1491 | sunsu_cons.index = i; |
| 1492 | register_console(&sunsu_cons); | 1492 | |
| 1493 | return 0; | 1493 | return &sunsu_cons; |
| 1494 | } | 1494 | } |
| 1495 | #else | 1495 | #else |
| 1496 | #define SUNSU_CONSOLE (NULL) | 1496 | #define SUNSU_CONSOLE() (NULL) |
| 1497 | #define sunsu_serial_console_init() do { } while (0) | 1497 | #define sunsu_serial_console_init() do { } while (0) |
| 1498 | #endif | 1498 | #endif |
| 1499 | 1499 | ||
| @@ -1510,6 +1510,7 @@ static int __init sunsu_serial_init(void) | |||
| 1510 | up->su_type == SU_PORT_KBD) | 1510 | up->su_type == SU_PORT_KBD) |
| 1511 | continue; | 1511 | continue; |
| 1512 | 1512 | ||
| 1513 | spin_lock_init(&up->port.lock); | ||
| 1513 | up->port.flags |= UPF_BOOT_AUTOCONF; | 1514 | up->port.flags |= UPF_BOOT_AUTOCONF; |
| 1514 | up->port.type = PORT_UNKNOWN; | 1515 | up->port.type = PORT_UNKNOWN; |
| 1515 | up->port.uartclk = (SU_BASE_BAUD * 16); | 1516 | up->port.uartclk = (SU_BASE_BAUD * 16); |
| @@ -1523,16 +1524,19 @@ static int __init sunsu_serial_init(void) | |||
| 1523 | } | 1524 | } |
| 1524 | 1525 | ||
| 1525 | sunsu_reg.minor = sunserial_current_minor; | 1526 | sunsu_reg.minor = sunserial_current_minor; |
| 1526 | sunserial_current_minor += instance; | ||
| 1527 | 1527 | ||
| 1528 | sunsu_reg.nr = instance; | 1528 | sunsu_reg.nr = instance; |
| 1529 | sunsu_reg.cons = SUNSU_CONSOLE; | ||
| 1530 | 1529 | ||
| 1531 | ret = uart_register_driver(&sunsu_reg); | 1530 | ret = uart_register_driver(&sunsu_reg); |
| 1532 | if (ret < 0) | 1531 | if (ret < 0) |
| 1533 | return ret; | 1532 | return ret; |
| 1534 | 1533 | ||
| 1535 | sunsu_serial_console_init(); | 1534 | sunsu_reg.tty_driver->name_base = sunsu_reg.minor - 64; |
| 1535 | |||
| 1536 | sunserial_current_minor += instance; | ||
| 1537 | |||
| 1538 | sunsu_reg.cons = SUNSU_CONSOLE(); | ||
| 1539 | |||
| 1536 | for (i = 0; i < UART_NR; i++) { | 1540 | for (i = 0; i < UART_NR; i++) { |
| 1537 | struct uart_sunsu_port *up = &sunsu_ports[i]; | 1541 | struct uart_sunsu_port *up = &sunsu_ports[i]; |
| 1538 | 1542 | ||
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index 5cc4d4c2935c..10b35c6f287d 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c | |||
| @@ -1390,7 +1390,6 @@ static struct console sunzilog_console = { | |||
| 1390 | .index = -1, | 1390 | .index = -1, |
| 1391 | .data = &sunzilog_reg, | 1391 | .data = &sunzilog_reg, |
| 1392 | }; | 1392 | }; |
| 1393 | #define SUNZILOG_CONSOLE (&sunzilog_console) | ||
| 1394 | 1393 | ||
| 1395 | static int __init sunzilog_console_init(void) | 1394 | static int __init sunzilog_console_init(void) |
| 1396 | { | 1395 | { |
| @@ -1413,8 +1412,31 @@ static int __init sunzilog_console_init(void) | |||
| 1413 | register_console(&sunzilog_console); | 1412 | register_console(&sunzilog_console); |
| 1414 | return 0; | 1413 | return 0; |
| 1415 | } | 1414 | } |
| 1415 | |||
| 1416 | static inline struct console *SUNZILOG_CONSOLE(void) | ||
| 1417 | { | ||
| 1418 | int i; | ||
| 1419 | |||
| 1420 | if (con_is_present()) | ||
| 1421 | return NULL; | ||
| 1422 | |||
| 1423 | for (i = 0; i < NUM_CHANNELS; i++) { | ||
| 1424 | int this_minor = sunzilog_reg.minor + i; | ||
| 1425 | |||
| 1426 | if ((this_minor - 64) == (serial_console - 1)) | ||
| 1427 | break; | ||
| 1428 | } | ||
| 1429 | if (i == NUM_CHANNELS) | ||
| 1430 | return NULL; | ||
| 1431 | |||
| 1432 | sunzilog_console.index = i; | ||
| 1433 | sunzilog_port_table[i].flags |= SUNZILOG_FLAG_IS_CONS; | ||
| 1434 | |||
| 1435 | return &sunzilog_console; | ||
| 1436 | } | ||
| 1437 | |||
| 1416 | #else | 1438 | #else |
| 1417 | #define SUNZILOG_CONSOLE (NULL) | 1439 | #define SUNZILOG_CONSOLE() (NULL) |
| 1418 | #define sunzilog_console_init() do { } while (0) | 1440 | #define sunzilog_console_init() do { } while (0) |
| 1419 | #endif | 1441 | #endif |
| 1420 | 1442 | ||
| @@ -1666,14 +1688,15 @@ static int __init sunzilog_ports_init(void) | |||
| 1666 | } | 1688 | } |
| 1667 | 1689 | ||
| 1668 | sunzilog_reg.nr = uart_count; | 1690 | sunzilog_reg.nr = uart_count; |
| 1669 | sunzilog_reg.cons = SUNZILOG_CONSOLE; | ||
| 1670 | |||
| 1671 | sunzilog_reg.minor = sunserial_current_minor; | 1691 | sunzilog_reg.minor = sunserial_current_minor; |
| 1672 | sunserial_current_minor += uart_count; | ||
| 1673 | 1692 | ||
| 1674 | ret = uart_register_driver(&sunzilog_reg); | 1693 | ret = uart_register_driver(&sunzilog_reg); |
| 1675 | if (ret == 0) { | 1694 | if (ret == 0) { |
| 1676 | sunzilog_console_init(); | 1695 | sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64; |
| 1696 | sunzilog_reg.cons = SUNZILOG_CONSOLE(); | ||
| 1697 | |||
| 1698 | sunserial_current_minor += uart_count; | ||
| 1699 | |||
| 1677 | for (i = 0; i < NUM_CHANNELS; i++) { | 1700 | for (i = 0; i < NUM_CHANNELS; i++) { |
| 1678 | struct uart_sunzilog_port *up = &sunzilog_port_table[i]; | 1701 | struct uart_sunzilog_port *up = &sunzilog_port_table[i]; |
| 1679 | 1702 | ||
