aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/serial
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/serial')
-rw-r--r--drivers/serial/Kconfig9
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/s3c2410.c2
-rw-r--r--drivers/serial/serial_txx9.c77
-rw-r--r--drivers/serial/sunhv.c550
-rw-r--r--drivers/serial/sunsab.c19
-rw-r--r--drivers/serial/sunsu.c26
-rw-r--r--drivers/serial/sunzilog.c35
-rw-r--r--drivers/serial/vr41xx_siu.c24
9 files changed, 671 insertions, 72 deletions
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index b3c561abe3f6..c66ef96c71b4 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
585config 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
585config SERIAL_IP22_ZILOG 592config 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
@@ -859,7 +866,7 @@ config SERIAL_M32R_PLDSIO
859 866
860config SERIAL_TXX9 867config SERIAL_TXX9
861 bool "TMPTX39XX/49XX SIO support" 868 bool "TMPTX39XX/49XX SIO support"
862 depends HAS_TXX9_SERIAL && BROKEN 869 depends HAS_TXX9_SERIAL
863 select SERIAL_CORE 870 select SERIAL_CORE
864 default y 871 default y
865 872
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
30obj-$(CONFIG_SERIAL_SA1100) += sa1100.o 30obj-$(CONFIG_SERIAL_SA1100) += sa1100.o
31obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o 31obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o
32obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o 32obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o
33obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o
33obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o 34obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o
34obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o 35obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o
35obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o 36obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
index e4d701239702..f5aac92fb798 100644
--- a/drivers/serial/s3c2410.c
+++ b/drivers/serial/s3c2410.c
@@ -1066,6 +1066,8 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
1066 port->mapbase = res->start; 1066 port->mapbase = res->start;
1067 port->membase = S3C24XX_VA_UART + (res->start - S3C24XX_PA_UART); 1067 port->membase = S3C24XX_VA_UART + (res->start - S3C24XX_PA_UART);
1068 port->irq = platform_get_irq(platdev, 0); 1068 port->irq = platform_get_irq(platdev, 0);
1069 if (port->irq < 0)
1070 port->irq = 0;
1069 1071
1070 ourport->clk = clk_get(&platdev->dev, "uart"); 1072 ourport->clk = clk_get(&platdev->dev, "uart");
1071 1073
diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c
index 1a259cee1a98..b848b7d94412 100644
--- a/drivers/serial/serial_txx9.c
+++ b/drivers/serial/serial_txx9.c
@@ -33,6 +33,10 @@
33 * 1.02 Cleanup. (import 8250.c changes) 33 * 1.02 Cleanup. (import 8250.c changes)
34 * 1.03 Fix low-latency mode. (import 8250.c changes) 34 * 1.03 Fix low-latency mode. (import 8250.c changes)
35 * 1.04 Remove usage of deprecated functions, cleanup. 35 * 1.04 Remove usage of deprecated functions, cleanup.
36 * 1.05 More strict check in verify_port. Cleanup.
37 * 1.06 Do not insert a char caused previous overrun.
38 * Fix some spin_locks.
39 * Do not call uart_add_one_port for absent ports.
36 */ 40 */
37#include <linux/config.h> 41#include <linux/config.h>
38 42
@@ -57,7 +61,7 @@
57#include <asm/io.h> 61#include <asm/io.h>
58#include <asm/irq.h> 62#include <asm/irq.h>
59 63
60static char *serial_version = "1.04"; 64static char *serial_version = "1.06";
61static char *serial_name = "TX39/49 Serial driver"; 65static char *serial_name = "TX39/49 Serial driver";
62 66
63#define PASS_LIMIT 256 67#define PASS_LIMIT 256
@@ -94,6 +98,8 @@ static char *serial_name = "TX39/49 Serial driver";
94#define UART_NR 4 98#define UART_NR 4
95#endif 99#endif
96 100
101#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
102
97struct uart_txx9_port { 103struct uart_txx9_port {
98 struct uart_port port; 104 struct uart_port port;
99 105
@@ -210,7 +216,7 @@ static inline unsigned int sio_in(struct uart_txx9_port *up, int offset)
210{ 216{
211 switch (up->port.iotype) { 217 switch (up->port.iotype) {
212 default: 218 default:
213 return *(volatile u32 *)(up->port.membase + offset); 219 return __raw_readl(up->port.membase + offset);
214 case UPIO_PORT: 220 case UPIO_PORT:
215 return inl(up->port.iobase + offset); 221 return inl(up->port.iobase + offset);
216 } 222 }
@@ -221,7 +227,7 @@ sio_out(struct uart_txx9_port *up, int offset, int value)
221{ 227{
222 switch (up->port.iotype) { 228 switch (up->port.iotype) {
223 default: 229 default:
224 *(volatile u32 *)(up->port.membase + offset) = value; 230 __raw_writel(value, up->port.membase + offset);
225 break; 231 break;
226 case UPIO_PORT: 232 case UPIO_PORT:
227 outl(value, up->port.iobase + offset); 233 outl(value, up->port.iobase + offset);
@@ -259,34 +265,19 @@ sio_quot_set(struct uart_txx9_port *up, int quot)
259static void serial_txx9_stop_tx(struct uart_port *port) 265static void serial_txx9_stop_tx(struct uart_port *port)
260{ 266{
261 struct uart_txx9_port *up = (struct uart_txx9_port *)port; 267 struct uart_txx9_port *up = (struct uart_txx9_port *)port;
262 unsigned long flags;
263
264 spin_lock_irqsave(&up->port.lock, flags);
265 sio_mask(up, TXX9_SIDICR, TXX9_SIDICR_TIE); 268 sio_mask(up, TXX9_SIDICR, TXX9_SIDICR_TIE);
266 spin_unlock_irqrestore(&up->port.lock, flags);
267} 269}
268 270
269static void serial_txx9_start_tx(struct uart_port *port) 271static void serial_txx9_start_tx(struct uart_port *port)
270{ 272{
271 struct uart_txx9_port *up = (struct uart_txx9_port *)port; 273 struct uart_txx9_port *up = (struct uart_txx9_port *)port;
272 unsigned long flags;
273
274 spin_lock_irqsave(&up->port.lock, flags);
275 sio_set(up, TXX9_SIDICR, TXX9_SIDICR_TIE); 274 sio_set(up, TXX9_SIDICR, TXX9_SIDICR_TIE);
276 spin_unlock_irqrestore(&up->port.lock, flags);
277} 275}
278 276
279static void serial_txx9_stop_rx(struct uart_port *port) 277static void serial_txx9_stop_rx(struct uart_port *port)
280{ 278{
281 struct uart_txx9_port *up = (struct uart_txx9_port *)port; 279 struct uart_txx9_port *up = (struct uart_txx9_port *)port;
282 unsigned long flags;
283
284 spin_lock_irqsave(&up->port.lock, flags);
285 up->port.read_status_mask &= ~TXX9_SIDISR_RDIS; 280 up->port.read_status_mask &= ~TXX9_SIDISR_RDIS;
286#if 0
287 sio_mask(up, TXX9_SIDICR, TXX9_SIDICR_RIE);
288#endif
289 spin_unlock_irqrestore(&up->port.lock, flags);
290} 281}
291 282
292static void serial_txx9_enable_ms(struct uart_port *port) 283static void serial_txx9_enable_ms(struct uart_port *port)
@@ -302,12 +293,16 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status, struct pt_regs *r
302 unsigned int disr = *status; 293 unsigned int disr = *status;
303 int max_count = 256; 294 int max_count = 256;
304 char flag; 295 char flag;
296 unsigned int next_ignore_status_mask;
305 297
306 do { 298 do {
307 ch = sio_in(up, TXX9_SIRFIFO); 299 ch = sio_in(up, TXX9_SIRFIFO);
308 flag = TTY_NORMAL; 300 flag = TTY_NORMAL;
309 up->port.icount.rx++; 301 up->port.icount.rx++;
310 302
303 /* mask out RFDN_MASK bit added by previous overrun */
304 next_ignore_status_mask =
305 up->port.ignore_status_mask & ~TXX9_SIDISR_RFDN_MASK;
311 if (unlikely(disr & (TXX9_SIDISR_UBRK | TXX9_SIDISR_UPER | 306 if (unlikely(disr & (TXX9_SIDISR_UBRK | TXX9_SIDISR_UPER |
312 TXX9_SIDISR_UFER | TXX9_SIDISR_UOER))) { 307 TXX9_SIDISR_UFER | TXX9_SIDISR_UOER))) {
313 /* 308 /*
@@ -328,8 +323,17 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status, struct pt_regs *r
328 up->port.icount.parity++; 323 up->port.icount.parity++;
329 else if (disr & TXX9_SIDISR_UFER) 324 else if (disr & TXX9_SIDISR_UFER)
330 up->port.icount.frame++; 325 up->port.icount.frame++;
331 if (disr & TXX9_SIDISR_UOER) 326 if (disr & TXX9_SIDISR_UOER) {
332 up->port.icount.overrun++; 327 up->port.icount.overrun++;
328 /*
329 * The receiver read buffer still hold
330 * a char which caused overrun.
331 * Ignore next char by adding RFDN_MASK
332 * to ignore_status_mask temporarily.
333 */
334 next_ignore_status_mask |=
335 TXX9_SIDISR_RFDN_MASK;
336 }
333 337
334 /* 338 /*
335 * Mask off conditions which should be ingored. 339 * Mask off conditions which should be ingored.
@@ -349,6 +353,7 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status, struct pt_regs *r
349 uart_insert_char(&up->port, disr, TXX9_SIDISR_UOER, ch, flag); 353 uart_insert_char(&up->port, disr, TXX9_SIDISR_UOER, ch, flag);
350 354
351 ignore_char: 355 ignore_char:
356 up->port.ignore_status_mask = next_ignore_status_mask;
352 disr = sio_in(up, TXX9_SIDISR); 357 disr = sio_in(up, TXX9_SIDISR);
353 } while (!(disr & TXX9_SIDISR_UVALID) && (max_count-- > 0)); 358 } while (!(disr & TXX9_SIDISR_UVALID) && (max_count-- > 0));
354 spin_unlock(&up->port.lock); 359 spin_unlock(&up->port.lock);
@@ -450,14 +455,11 @@ static unsigned int serial_txx9_get_mctrl(struct uart_port *port)
450static void serial_txx9_set_mctrl(struct uart_port *port, unsigned int mctrl) 455static void serial_txx9_set_mctrl(struct uart_port *port, unsigned int mctrl)
451{ 456{
452 struct uart_txx9_port *up = (struct uart_txx9_port *)port; 457 struct uart_txx9_port *up = (struct uart_txx9_port *)port;
453 unsigned long flags;
454 458
455 spin_lock_irqsave(&up->port.lock, flags);
456 if (mctrl & TIOCM_RTS) 459 if (mctrl & TIOCM_RTS)
457 sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC); 460 sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC);
458 else 461 else
459 sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC); 462 sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC);
460 spin_unlock_irqrestore(&up->port.lock, flags);
461} 463}
462 464
463static void serial_txx9_break_ctl(struct uart_port *port, int break_state) 465static void serial_txx9_break_ctl(struct uart_port *port, int break_state)
@@ -784,8 +786,14 @@ static void serial_txx9_config_port(struct uart_port *port, int uflags)
784static int 786static int
785serial_txx9_verify_port(struct uart_port *port, struct serial_struct *ser) 787serial_txx9_verify_port(struct uart_port *port, struct serial_struct *ser)
786{ 788{
787 if (ser->irq < 0 || 789 unsigned long new_port = ser->port;
788 ser->baud_base < 9600 || ser->type != PORT_TXX9) 790 if (HIGH_BITS_OFFSET)
791 new_port += (unsigned long)ser->port_high << HIGH_BITS_OFFSET;
792 if (ser->type != port->type ||
793 ser->irq != port->irq ||
794 ser->io_type != port->iotype ||
795 new_port != port->iobase ||
796 (unsigned long)ser->iomem_base != port->mapbase)
789 return -EINVAL; 797 return -EINVAL;
790 return 0; 798 return 0;
791} 799}
@@ -827,7 +835,8 @@ static void __init serial_txx9_register_ports(struct uart_driver *drv)
827 835
828 up->port.line = i; 836 up->port.line = i;
829 up->port.ops = &serial_txx9_pops; 837 up->port.ops = &serial_txx9_pops;
830 uart_add_one_port(drv, &up->port); 838 if (up->port.iobase || up->port.mapbase)
839 uart_add_one_port(drv, &up->port);
831 } 840 }
832} 841}
833 842
@@ -919,11 +928,6 @@ static int serial_txx9_console_setup(struct console *co, char *options)
919 return -ENODEV; 928 return -ENODEV;
920 929
921 /* 930 /*
922 * Temporary fix.
923 */
924 spin_lock_init(&port->lock);
925
926 /*
927 * Disable UART interrupts, set DTR and RTS high 931 * Disable UART interrupts, set DTR and RTS high
928 * and set speed. 932 * and set speed.
929 */ 933 */
@@ -1033,11 +1037,10 @@ static int __devinit serial_txx9_register_port(struct uart_port *port)
1033 mutex_lock(&serial_txx9_mutex); 1037 mutex_lock(&serial_txx9_mutex);
1034 for (i = 0; i < UART_NR; i++) { 1038 for (i = 0; i < UART_NR; i++) {
1035 uart = &serial_txx9_ports[i]; 1039 uart = &serial_txx9_ports[i];
1036 if (uart->port.type == PORT_UNKNOWN) 1040 if (!(uart->port.iobase || uart->port.mapbase))
1037 break; 1041 break;
1038 } 1042 }
1039 if (i < UART_NR) { 1043 if (i < UART_NR) {
1040 uart_remove_one_port(&serial_txx9_reg, &uart->port);
1041 uart->port.iobase = port->iobase; 1044 uart->port.iobase = port->iobase;
1042 uart->port.membase = port->membase; 1045 uart->port.membase = port->membase;
1043 uart->port.irq = port->irq; 1046 uart->port.irq = port->irq;
@@ -1072,9 +1075,8 @@ static void __devexit serial_txx9_unregister_port(int line)
1072 uart->port.type = PORT_UNKNOWN; 1075 uart->port.type = PORT_UNKNOWN;
1073 uart->port.iobase = 0; 1076 uart->port.iobase = 0;
1074 uart->port.mapbase = 0; 1077 uart->port.mapbase = 0;
1075 uart->port.membase = 0; 1078 uart->port.membase = NULL;
1076 uart->port.dev = NULL; 1079 uart->port.dev = NULL;
1077 uart_add_one_port(&serial_txx9_reg, &uart->port);
1078 mutex_unlock(&serial_txx9_mutex); 1080 mutex_unlock(&serial_txx9_mutex);
1079} 1081}
1080 1082
@@ -1190,8 +1192,11 @@ static void __exit serial_txx9_exit(void)
1190#ifdef ENABLE_SERIAL_TXX9_PCI 1192#ifdef ENABLE_SERIAL_TXX9_PCI
1191 pci_unregister_driver(&serial_txx9_pci_driver); 1193 pci_unregister_driver(&serial_txx9_pci_driver);
1192#endif 1194#endif
1193 for (i = 0; i < UART_NR; i++) 1195 for (i = 0; i < UART_NR; i++) {
1194 uart_remove_one_port(&serial_txx9_reg, &serial_txx9_ports[i].port); 1196 struct uart_txx9_port *up = &serial_txx9_ports[i];
1197 if (up->port.iobase || up->port.mapbase)
1198 uart_remove_one_port(&serial_txx9_reg, &up->port);
1199 }
1195 1200
1196 uart_unregister_driver(&serial_txx9_reg); 1201 uart_unregister_driver(&serial_txx9_reg);
1197} 1202}
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
38static 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
57static 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
74static int hung_up = 0;
75
76static 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
139static 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
164static 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. */
182static 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. */
192static 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. */
198static 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. */
204static void sunhv_stop_tx(struct uart_port *port)
205{
206 return;
207}
208
209/* port->lock held by caller. */
210static 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. */
226static 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. */
243static void sunhv_stop_rx(struct uart_port *port)
244{
245}
246
247/* port->lock held by caller. */
248static void sunhv_enable_ms(struct uart_port *port)
249{
250}
251
252/* port->lock is not held. */
253static 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. */
273static int sunhv_startup(struct uart_port *port)
274{
275 return 0;
276}
277
278/* port->lock is not held. */
279static void sunhv_shutdown(struct uart_port *port)
280{
281}
282
283/* port->lock is not held. */
284static 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
310static const char *sunhv_type(struct uart_port *port)
311{
312 return "SUN4V HCONS";
313}
314
315static void sunhv_release_port(struct uart_port *port)
316{
317}
318
319static int sunhv_request_port(struct uart_port *port)
320{
321 return 0;
322}
323
324static void sunhv_config_port(struct uart_port *port, int flags)
325{
326}
327
328static int sunhv_verify_port(struct uart_port *port, struct serial_struct *ser)
329{
330 return -EINVAL;
331}
332
333static 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
353static 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
361static struct uart_port *sunhv_port;
362
363static 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
380static 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
392static 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
401static 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
411static 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
428static 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
457static 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
528static 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
545module_init(sunhv_init);
546module_exit(sunhv_exit);
547
548MODULE_AUTHOR("David S. Miller");
549MODULE_DESCRIPTION("SUN4V Hypervisor console driver")
550MODULE_LICENSE("GPL");
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c
index be95eabd0394..bfbe9dc90cca 100644
--- a/drivers/serial/sunsab.c
+++ b/drivers/serial/sunsab.c
@@ -951,14 +951,13 @@ static struct console sunsab_console = {
951 .index = -1, 951 .index = -1,
952 .data = &sunsab_reg, 952 .data = &sunsab_reg,
953}; 953};
954#define SUNSAB_CONSOLE (&sunsab_console)
955 954
956static void __init sunsab_console_init(void) 955static inline struct console *SUNSAB_CONSOLE(void)
957{ 956{
958 int i; 957 int i;
959 958
960 if (con_is_present()) 959 if (con_is_present())
961 return; 960 return NULL;
962 961
963 for (i = 0; i < num_channels; i++) { 962 for (i = 0; i < num_channels; i++) {
964 int this_minor = sunsab_reg.minor + i; 963 int this_minor = sunsab_reg.minor + i;
@@ -967,13 +966,14 @@ static void __init sunsab_console_init(void)
967 break; 966 break;
968 } 967 }
969 if (i == num_channels) 968 if (i == num_channels)
970 return; 969 return NULL;
971 970
972 sunsab_console.index = i; 971 sunsab_console.index = i;
973 register_console(&sunsab_console); 972
973 return &sunsab_console;
974} 974}
975#else 975#else
976#define SUNSAB_CONSOLE (NULL) 976#define SUNSAB_CONSOLE() (NULL)
977#define sunsab_console_init() do { } while (0) 977#define sunsab_console_init() do { } while (0)
978#endif 978#endif
979 979
@@ -1120,7 +1120,6 @@ static int __init sunsab_init(void)
1120 1120
1121 sunsab_reg.minor = sunserial_current_minor; 1121 sunsab_reg.minor = sunserial_current_minor;
1122 sunsab_reg.nr = num_channels; 1122 sunsab_reg.nr = num_channels;
1123 sunsab_reg.cons = SUNSAB_CONSOLE;
1124 1123
1125 ret = uart_register_driver(&sunsab_reg); 1124 ret = uart_register_driver(&sunsab_reg);
1126 if (ret < 0) { 1125 if (ret < 0) {
@@ -1139,10 +1138,12 @@ static int __init sunsab_init(void)
1139 return ret; 1138 return ret;
1140 } 1139 }
1141 1140
1141 sunsab_reg.tty_driver->name_base = sunsab_reg.minor - 64;
1142
1143 sunsab_reg.cons = SUNSAB_CONSOLE();
1144
1142 sunserial_current_minor += num_channels; 1145 sunserial_current_minor += num_channels;
1143 1146
1144 sunsab_console_init();
1145
1146 for (i = 0; i < num_channels; i++) { 1147 for (i = 0; i < num_channels; i++) {
1147 struct uart_sunsab_port *up = &sunsab_ports[i]; 1148 struct uart_sunsab_port *up = &sunsab_ports[i];
1148 1149
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index 9ca1d8b9364b..7fc3d3b41d18 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);
@@ -1456,18 +1457,17 @@ static struct console sunsu_cons = {
1456 .index = -1, 1457 .index = -1,
1457 .data = &sunsu_reg, 1458 .data = &sunsu_reg,
1458}; 1459};
1459#define SUNSU_CONSOLE (&sunsu_cons)
1460 1460
1461/* 1461/*
1462 * Register console. 1462 * Register console.
1463 */ 1463 */
1464 1464
1465static int __init sunsu_serial_console_init(void) 1465static inline struct console *SUNSU_CONSOLE(void)
1466{ 1466{
1467 int i; 1467 int i;
1468 1468
1469 if (con_is_present()) 1469 if (con_is_present())
1470 return 0; 1470 return NULL;
1471 1471
1472 for (i = 0; i < UART_NR; i++) { 1472 for (i = 0; i < UART_NR; i++) {
1473 int this_minor = sunsu_reg.minor + i; 1473 int this_minor = sunsu_reg.minor + i;
@@ -1476,16 +1476,16 @@ static int __init sunsu_serial_console_init(void)
1476 break; 1476 break;
1477 } 1477 }
1478 if (i == UART_NR) 1478 if (i == UART_NR)
1479 return 0; 1479 return NULL;
1480 if (sunsu_ports[i].port_node == 0) 1480 if (sunsu_ports[i].port_node == 0)
1481 return 0; 1481 return NULL;
1482 1482
1483 sunsu_cons.index = i; 1483 sunsu_cons.index = i;
1484 register_console(&sunsu_cons); 1484
1485 return 0; 1485 return &sunsu_cons;
1486} 1486}
1487#else 1487#else
1488#define SUNSU_CONSOLE (NULL) 1488#define SUNSU_CONSOLE() (NULL)
1489#define sunsu_serial_console_init() do { } while (0) 1489#define sunsu_serial_console_init() do { } while (0)
1490#endif 1490#endif
1491 1491
@@ -1502,6 +1502,7 @@ static int __init sunsu_serial_init(void)
1502 up->su_type == SU_PORT_KBD) 1502 up->su_type == SU_PORT_KBD)
1503 continue; 1503 continue;
1504 1504
1505 spin_lock_init(&up->port.lock);
1505 up->port.flags |= UPF_BOOT_AUTOCONF; 1506 up->port.flags |= UPF_BOOT_AUTOCONF;
1506 up->port.type = PORT_UNKNOWN; 1507 up->port.type = PORT_UNKNOWN;
1507 up->port.uartclk = (SU_BASE_BAUD * 16); 1508 up->port.uartclk = (SU_BASE_BAUD * 16);
@@ -1515,16 +1516,19 @@ static int __init sunsu_serial_init(void)
1515 } 1516 }
1516 1517
1517 sunsu_reg.minor = sunserial_current_minor; 1518 sunsu_reg.minor = sunserial_current_minor;
1518 sunserial_current_minor += instance;
1519 1519
1520 sunsu_reg.nr = instance; 1520 sunsu_reg.nr = instance;
1521 sunsu_reg.cons = SUNSU_CONSOLE;
1522 1521
1523 ret = uart_register_driver(&sunsu_reg); 1522 ret = uart_register_driver(&sunsu_reg);
1524 if (ret < 0) 1523 if (ret < 0)
1525 return ret; 1524 return ret;
1526 1525
1527 sunsu_serial_console_init(); 1526 sunsu_reg.tty_driver->name_base = sunsu_reg.minor - 64;
1527
1528 sunserial_current_minor += instance;
1529
1530 sunsu_reg.cons = SUNSU_CONSOLE();
1531
1528 for (i = 0; i < UART_NR; i++) { 1532 for (i = 0; i < UART_NR; i++) {
1529 struct uart_sunsu_port *up = &sunsu_ports[i]; 1533 struct uart_sunsu_port *up = &sunsu_ports[i];
1530 1534
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
index b0c46b9a5930..cd49ebbf4a45 100644
--- a/drivers/serial/sunzilog.c
+++ b/drivers/serial/sunzilog.c
@@ -1385,7 +1385,6 @@ static struct console sunzilog_console = {
1385 .index = -1, 1385 .index = -1,
1386 .data = &sunzilog_reg, 1386 .data = &sunzilog_reg,
1387}; 1387};
1388#define SUNZILOG_CONSOLE (&sunzilog_console)
1389 1388
1390static int __init sunzilog_console_init(void) 1389static int __init sunzilog_console_init(void)
1391{ 1390{
@@ -1408,8 +1407,31 @@ static int __init sunzilog_console_init(void)
1408 register_console(&sunzilog_console); 1407 register_console(&sunzilog_console);
1409 return 0; 1408 return 0;
1410} 1409}
1410
1411static inline struct console *SUNZILOG_CONSOLE(void)
1412{
1413 int i;
1414
1415 if (con_is_present())
1416 return NULL;
1417
1418 for (i = 0; i < NUM_CHANNELS; i++) {
1419 int this_minor = sunzilog_reg.minor + i;
1420
1421 if ((this_minor - 64) == (serial_console - 1))
1422 break;
1423 }
1424 if (i == NUM_CHANNELS)
1425 return NULL;
1426
1427 sunzilog_console.index = i;
1428 sunzilog_port_table[i].flags |= SUNZILOG_FLAG_IS_CONS;
1429
1430 return &sunzilog_console;
1431}
1432
1411#else 1433#else
1412#define SUNZILOG_CONSOLE (NULL) 1434#define SUNZILOG_CONSOLE() (NULL)
1413#define sunzilog_console_init() do { } while (0) 1435#define sunzilog_console_init() do { } while (0)
1414#endif 1436#endif
1415 1437
@@ -1661,14 +1683,15 @@ static int __init sunzilog_ports_init(void)
1661 } 1683 }
1662 1684
1663 sunzilog_reg.nr = uart_count; 1685 sunzilog_reg.nr = uart_count;
1664 sunzilog_reg.cons = SUNZILOG_CONSOLE;
1665
1666 sunzilog_reg.minor = sunserial_current_minor; 1686 sunzilog_reg.minor = sunserial_current_minor;
1667 sunserial_current_minor += uart_count;
1668 1687
1669 ret = uart_register_driver(&sunzilog_reg); 1688 ret = uart_register_driver(&sunzilog_reg);
1670 if (ret == 0) { 1689 if (ret == 0) {
1671 sunzilog_console_init(); 1690 sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64;
1691 sunzilog_reg.cons = SUNZILOG_CONSOLE();
1692
1693 sunserial_current_minor += uart_count;
1694
1672 for (i = 0; i < NUM_CHANNELS; i++) { 1695 for (i = 0; i < NUM_CHANNELS; i++) {
1673 struct uart_sunzilog_port *up = &sunzilog_port_table[i]; 1696 struct uart_sunzilog_port *up = &sunzilog_port_table[i];
1674 1697
diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c
index 3f88b8e81937..df5e8713fa31 100644
--- a/drivers/serial/vr41xx_siu.c
+++ b/drivers/serial/vr41xx_siu.c
@@ -917,7 +917,7 @@ static struct uart_driver siu_uart_driver = {
917 .cons = SERIAL_VR41XX_CONSOLE, 917 .cons = SERIAL_VR41XX_CONSOLE,
918}; 918};
919 919
920static int siu_probe(struct platform_device *dev) 920static int __devinit siu_probe(struct platform_device *dev)
921{ 921{
922 struct uart_port *port; 922 struct uart_port *port;
923 int num, i, retval; 923 int num, i, retval;
@@ -951,7 +951,7 @@ static int siu_probe(struct platform_device *dev)
951 return 0; 951 return 0;
952} 952}
953 953
954static int siu_remove(struct platform_device *dev) 954static int __devexit siu_remove(struct platform_device *dev)
955{ 955{
956 struct uart_port *port; 956 struct uart_port *port;
957 int i; 957 int i;
@@ -1004,21 +1004,28 @@ static struct platform_device *siu_platform_device;
1004 1004
1005static struct platform_driver siu_device_driver = { 1005static struct platform_driver siu_device_driver = {
1006 .probe = siu_probe, 1006 .probe = siu_probe,
1007 .remove = siu_remove, 1007 .remove = __devexit_p(siu_remove),
1008 .suspend = siu_suspend, 1008 .suspend = siu_suspend,
1009 .resume = siu_resume, 1009 .resume = siu_resume,
1010 .driver = { 1010 .driver = {
1011 .name = "SIU", 1011 .name = "SIU",
1012 .owner = THIS_MODULE,
1012 }, 1013 },
1013}; 1014};
1014 1015
1015static int __devinit vr41xx_siu_init(void) 1016static int __init vr41xx_siu_init(void)
1016{ 1017{
1017 int retval; 1018 int retval;
1018 1019
1019 siu_platform_device = platform_device_register_simple("SIU", -1, NULL, 0); 1020 siu_platform_device = platform_device_alloc("SIU", -1);
1020 if (IS_ERR(siu_platform_device)) 1021 if (!siu_platform_device)
1021 return PTR_ERR(siu_platform_device); 1022 return -ENOMEM;
1023
1024 retval = platform_device_add(siu_platform_device);
1025 if (retval < 0) {
1026 platform_device_put(siu_platform_device);
1027 return retval;
1028 }
1022 1029
1023 retval = platform_driver_register(&siu_device_driver); 1030 retval = platform_driver_register(&siu_device_driver);
1024 if (retval < 0) 1031 if (retval < 0)
@@ -1027,10 +1034,9 @@ static int __devinit vr41xx_siu_init(void)
1027 return retval; 1034 return retval;
1028} 1035}
1029 1036
1030static void __devexit vr41xx_siu_exit(void) 1037static void __exit vr41xx_siu_exit(void)
1031{ 1038{
1032 platform_driver_unregister(&siu_device_driver); 1039 platform_driver_unregister(&siu_device_driver);
1033
1034 platform_device_unregister(siu_platform_device); 1040 platform_device_unregister(siu_platform_device);
1035} 1041}
1036 1042