[SPARC64] sunhv: Bug fixes.
[pandora-kernel.git] / drivers / serial / sunhv.c
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/irq.h>
25
26 #if defined(CONFIG_MAGIC_SYSRQ)
27 #define SUPPORT_SYSRQ
28 #endif
29
30 #include <linux/serial_core.h>
31
32 #include "suncore.h"
33
34 #define CON_BREAK       ((long)-1)
35 #define CON_HUP         ((long)-2)
36
37 static inline long hypervisor_con_getchar(long *status)
38 {
39         register unsigned long func asm("%o5");
40         register unsigned long arg0 asm("%o0");
41         register unsigned long arg1 asm("%o1");
42
43         func = HV_FAST_CONS_GETCHAR;
44         arg0 = 0;
45         arg1 = 0;
46         __asm__ __volatile__("ta        %6"
47                              : "=&r" (func), "=&r" (arg0), "=&r" (arg1)
48                              : "0" (func), "1" (arg0), "2" (arg1),
49                                "i" (HV_FAST_TRAP));
50
51         *status = arg0;
52
53         return (long) arg1;
54 }
55
56 static inline long hypervisor_con_putchar(long ch)
57 {
58         register unsigned long func asm("%o5");
59         register unsigned long arg0 asm("%o0");
60
61         func = HV_FAST_CONS_PUTCHAR;
62         arg0 = ch;
63         __asm__ __volatile__("ta        %4"
64                              : "=&r" (func), "=&r" (arg0)
65                              : "0" (func), "1" (arg0), "i" (HV_FAST_TRAP));
66
67         return (long) arg0;
68 }
69
70 #define IGNORE_BREAK    0x1
71 #define IGNORE_ALL      0x2
72
73 static int hung_up = 0;
74
75 static struct tty_struct *receive_chars(struct uart_port *port, struct pt_regs *regs)
76 {
77         struct tty_struct *tty = NULL;
78         int saw_console_brk = 0;
79         int limit = 10000;
80
81         if (port->info != NULL)         /* Unopened serial console */
82                 tty = port->info->tty;
83
84         while (limit-- > 0) {
85                 long status;
86                 long c = hypervisor_con_getchar(&status);
87                 unsigned char flag;
88
89                 if (status == HV_EWOULDBLOCK)
90                         break;
91
92                 if (c == CON_BREAK) {
93                         saw_console_brk = 1;
94                         c = 0;
95                 }
96
97                 if (c == CON_HUP) {
98                         hung_up = 1;
99                         uart_handle_dcd_change(port, 0);
100                 } else if (hung_up) {
101                         hung_up = 0;
102                         uart_handle_dcd_change(port, 1);
103                 }
104
105                 if (tty == NULL) {
106                         uart_handle_sysrq_char(port, c, regs);
107                         continue;
108                 }
109
110                 flag = TTY_NORMAL;
111                 port->icount.rx++;
112                 if (c == CON_BREAK) {
113                         port->icount.brk++;
114                         if (uart_handle_break(port))
115                                 continue;
116                         flag = TTY_BREAK;
117                 }
118
119                 if (uart_handle_sysrq_char(port, c, regs))
120                         continue;
121
122                 if ((port->ignore_status_mask & IGNORE_ALL) ||
123                     ((port->ignore_status_mask & IGNORE_BREAK) &&
124                      (c == CON_BREAK)))
125                         continue;
126
127                 tty_insert_flip_char(tty, c, flag);
128         }
129
130         if (saw_console_brk)
131                 sun_do_break();
132
133         return tty;
134 }
135
136 static void transmit_chars(struct uart_port *port)
137 {
138         struct circ_buf *xmit = &port->info->xmit;
139
140         if (uart_circ_empty(xmit) || uart_tx_stopped(port))
141                 return;
142
143         while (!uart_circ_empty(xmit)) {
144                 long status = hypervisor_con_putchar(xmit->buf[xmit->tail]);
145
146                 if (status != HV_EOK)
147                         break;
148
149                 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
150                 port->icount.tx++;
151         }
152
153         if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
154                 uart_write_wakeup(port);
155 }
156
157 static irqreturn_t sunhv_interrupt(int irq, void *dev_id, struct pt_regs *regs)
158 {
159         struct uart_port *port = dev_id;
160         struct tty_struct *tty;
161         unsigned long flags;
162
163         spin_lock_irqsave(&port->lock, flags);
164         tty = receive_chars(port, regs);
165         transmit_chars(port);
166         spin_unlock_irqrestore(&port->lock, flags);
167
168         if (tty)
169                 tty_flip_buffer_push(tty);
170
171         return IRQ_HANDLED;
172 }
173
174 /* port->lock is not held.  */
175 static unsigned int sunhv_tx_empty(struct uart_port *port)
176 {
177         /* Transmitter is always empty for us.  If the circ buffer
178          * is non-empty or there is an x_char pending, our caller
179          * will do the right thing and ignore what we return here.
180          */
181         return TIOCSER_TEMT;
182 }
183
184 /* port->lock held by caller.  */
185 static void sunhv_set_mctrl(struct uart_port *port, unsigned int mctrl)
186 {
187         return;
188 }
189
190 /* port->lock is held by caller and interrupts are disabled.  */
191 static unsigned int sunhv_get_mctrl(struct uart_port *port)
192 {
193         return TIOCM_DSR | TIOCM_CAR | TIOCM_CTS;
194 }
195
196 /* port->lock held by caller.  */
197 static void sunhv_stop_tx(struct uart_port *port)
198 {
199         return;
200 }
201
202 /* port->lock held by caller.  */
203 static void sunhv_start_tx(struct uart_port *port)
204 {
205         struct circ_buf *xmit = &port->info->xmit;
206         unsigned long flags;
207
208         spin_lock_irqsave(&port->lock, flags);
209
210         while (!uart_circ_empty(xmit)) {
211                 long status = hypervisor_con_putchar(xmit->buf[xmit->tail]);
212
213                 if (status != HV_EOK)
214                         break;
215
216                 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
217                 port->icount.tx++;
218         }
219
220         spin_unlock_irqrestore(&port->lock, flags);
221 }
222
223 /* port->lock is not held.  */
224 static void sunhv_send_xchar(struct uart_port *port, char ch)
225 {
226         unsigned long flags;
227         int limit = 10000;
228
229         spin_lock_irqsave(&port->lock, flags);
230
231         while (limit-- > 0) {
232                 long status = hypervisor_con_putchar(ch);
233                 if (status == HV_EOK)
234                         break;
235         }
236
237         spin_unlock_irqrestore(&port->lock, flags);
238 }
239
240 /* port->lock held by caller.  */
241 static void sunhv_stop_rx(struct uart_port *port)
242 {
243 }
244
245 /* port->lock held by caller.  */
246 static void sunhv_enable_ms(struct uart_port *port)
247 {
248 }
249
250 /* port->lock is not held.  */
251 static void sunhv_break_ctl(struct uart_port *port, int break_state)
252 {
253         if (break_state) {
254                 unsigned long flags;
255                 int limit = 10000;
256
257                 spin_lock_irqsave(&port->lock, flags);
258
259                 while (limit-- > 0) {
260                         long status = hypervisor_con_putchar(CON_BREAK);
261                         if (status == HV_EOK)
262                                 break;
263                 }
264
265                 spin_unlock_irqrestore(&port->lock, flags);
266         }
267 }
268
269 /* port->lock is not held.  */
270 static int sunhv_startup(struct uart_port *port)
271 {
272         return 0;
273 }
274
275 /* port->lock is not held.  */
276 static void sunhv_shutdown(struct uart_port *port)
277 {
278 }
279
280 /* port->lock is not held.  */
281 static void sunhv_set_termios(struct uart_port *port, struct termios *termios,
282                               struct termios *old)
283 {
284         unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
285         unsigned int quot = uart_get_divisor(port, baud);
286         unsigned int iflag, cflag;
287         unsigned long flags;
288
289         spin_lock_irqsave(&port->lock, flags);
290
291         iflag = termios->c_iflag;
292         cflag = termios->c_cflag;
293
294         port->ignore_status_mask = 0;
295         if (iflag & IGNBRK)
296                 port->ignore_status_mask |= IGNORE_BREAK;
297         if ((cflag & CREAD) == 0)
298                 port->ignore_status_mask |= IGNORE_ALL;
299
300         /* XXX */
301         uart_update_timeout(port, cflag,
302                             (port->uartclk / (16 * quot)));
303
304         spin_unlock_irqrestore(&port->lock, flags);
305 }
306
307 static const char *sunhv_type(struct uart_port *port)
308 {
309         return "SUN4V HCONS";
310 }
311
312 static void sunhv_release_port(struct uart_port *port)
313 {
314 }
315
316 static int sunhv_request_port(struct uart_port *port)
317 {
318         return 0;
319 }
320
321 static void sunhv_config_port(struct uart_port *port, int flags)
322 {
323 }
324
325 static int sunhv_verify_port(struct uart_port *port, struct serial_struct *ser)
326 {
327         return -EINVAL;
328 }
329
330 static struct uart_ops sunhv_pops = {
331         .tx_empty       = sunhv_tx_empty,
332         .set_mctrl      = sunhv_set_mctrl,
333         .get_mctrl      = sunhv_get_mctrl,
334         .stop_tx        = sunhv_stop_tx,
335         .start_tx       = sunhv_start_tx,
336         .send_xchar     = sunhv_send_xchar,
337         .stop_rx        = sunhv_stop_rx,
338         .enable_ms      = sunhv_enable_ms,
339         .break_ctl      = sunhv_break_ctl,
340         .startup        = sunhv_startup,
341         .shutdown       = sunhv_shutdown,
342         .set_termios    = sunhv_set_termios,
343         .type           = sunhv_type,
344         .release_port   = sunhv_release_port,
345         .request_port   = sunhv_request_port,
346         .config_port    = sunhv_config_port,
347         .verify_port    = sunhv_verify_port,
348 };
349
350 static struct uart_driver sunhv_reg = {
351         .owner                  = THIS_MODULE,
352         .driver_name            = "serial",
353         .devfs_name             = "tts/",
354         .dev_name               = "ttyS",
355         .major                  = TTY_MAJOR,
356 };
357
358 static struct uart_port *sunhv_port;
359
360 static inline void sunhv_console_putchar(struct uart_port *port, char c)
361 {
362         unsigned long flags;
363         int limit = 1000000;
364
365         spin_lock_irqsave(&port->lock, flags);
366
367         while (limit-- > 0) {
368                 long status = hypervisor_con_putchar(c);
369                 if (status == HV_EOK)
370                         break;
371                 udelay(2);
372         }
373
374         spin_unlock_irqrestore(&port->lock, flags);
375 }
376
377 static void sunhv_console_write(struct console *con, const char *s, unsigned n)
378 {
379         struct uart_port *port = sunhv_port;
380         int i;
381
382         for (i = 0; i < n; i++) {
383                 if (*s == '\n')
384                         sunhv_console_putchar(port, '\r');
385                 sunhv_console_putchar(port, *s++);
386         }
387 }
388
389 static struct console sunhv_console = {
390         .name   =       "ttyHV",
391         .write  =       sunhv_console_write,
392         .device =       uart_console_device,
393         .flags  =       CON_PRINTBUFFER,
394         .index  =       -1,
395         .data   =       &sunhv_reg,
396 };
397
398 static inline struct console *SUNHV_CONSOLE(void)
399 {
400         if (con_is_present())
401                 return NULL;
402
403         sunhv_console.index = 0;
404
405         return &sunhv_console;
406 }
407
408 static int __init hv_console_compatible(char *buf, int len)
409 {
410         while (len) {
411                 int this_len;
412
413                 if (!strcmp(buf, "qcn"))
414                         return 1;
415
416                 this_len = strlen(buf) + 1;
417
418                 buf += this_len;
419                 len -= this_len;
420         }
421
422         return 0;
423 }
424
425 static unsigned int __init get_interrupt(void)
426 {
427         const char *cons_str = "console";
428         const char *compat_str = "compatible";
429         int node = prom_getchild(sun4v_vdev_root);
430         unsigned int irq;
431         char buf[64];
432         int err, len;
433
434         node = prom_searchsiblings(node, cons_str);
435         if (!node)
436                 return 0;
437
438         len = prom_getproplen(node, compat_str);
439         if (len == 0 || len == -1)
440                 return 0;
441
442         err = prom_getproperty(node, compat_str, buf, 64);
443         if (err == -1)
444                 return 0;
445
446         if (!hv_console_compatible(buf, len))
447                 return 0;
448
449         /* Ok, the this is the OBP node for the sun4v hypervisor
450          * console device.  Decode the interrupt.
451          */
452         err = prom_getproperty(node, "interrupts",
453                                (char *) &irq, sizeof(irq));
454         if (err == -1)
455                 return 0;
456
457         return sun4v_build_irq(sun4v_vdev_devhandle, irq, 4, 0);
458 }
459
460 static u32 sunhv_irq;
461
462 static int __init sunhv_init(void)
463 {
464         struct uart_port *port;
465         int ret;
466
467         if (tlb_type != hypervisor)
468                 return -ENODEV;
469
470         sunhv_irq = get_interrupt();
471         if (!sunhv_irq)
472                 return -ENODEV;
473
474         port = kmalloc(sizeof(struct uart_port), GFP_KERNEL);
475         if (unlikely(!port))
476                 return -ENOMEM;
477
478         port->line = 0;
479         port->ops = &sunhv_pops;
480         port->type = PORT_SUNHV;
481         port->uartclk = ( 29491200 / 16 ); /* arbitrary */
482
483         if (request_irq(sunhv_irq, sunhv_interrupt,
484                         SA_SHIRQ, "serial(sunhv)", port)) {
485                 printk("sunhv: Cannot get IRQ %x\n", sunhv_irq);
486                 kfree(port);
487                 return -ENODEV;
488         }
489
490         printk("SUNHV: SUN4V virtual console, IRQ[%08x]\n",
491                sunhv_irq);
492
493         sunhv_reg.minor = sunserial_current_minor;
494         sunhv_reg.nr = 1;
495
496         ret = uart_register_driver(&sunhv_reg);
497         if (ret < 0) {
498                 free_irq(sunhv_irq, up);
499                 kfree(port);
500
501                 return ret;
502         }
503
504         sunserial_current_minor += 1;
505
506         sunhv_reg.cons = SUNHV_CONSOLE();
507
508         sunhv_port = port;
509
510         uart_add_one_port(&sunhv_reg, port);
511
512         return 0;
513 }
514
515 static void __exit sunhv_exit(void)
516 {
517         struct uart_port *port = sunhv_port;
518
519         BUG_ON(!port);
520
521         uart_remove_one_port(&sunhv_reg, port);
522         free_irq(sunhv_irq, port);
523
524         sunserial_current_minor -= 1;
525
526         uart_unregister_driver(&sunhv_reg);
527
528         kfree(sunhv_port);
529         sunhv_port = NULL;
530 }
531
532 module_init(sunhv_init);
533 module_exit(sunhv_exit);
534
535 MODULE_AUTHOR("David S. Miller");
536 MODULE_DESCRIPTION("SUN4V Hypervisor console driver")
537 MODULE_LICENSE("GPL");