aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/serial/sunhv.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/serial/sunhv.c')
-rw-r--r--drivers/serial/sunhv.c73
1 files changed, 67 insertions, 6 deletions
diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c
index 2ba716eeb0bf..d3a9dd739da3 100644
--- a/drivers/serial/sunhv.c
+++ b/drivers/serial/sunhv.c
@@ -20,6 +20,8 @@
20 20
21#include <asm/hypervisor.h> 21#include <asm/hypervisor.h>
22#include <asm/spitfire.h> 22#include <asm/spitfire.h>
23#include <asm/vdev.h>
24#include <asm/irq.h>
23 25
24#if defined(CONFIG_MAGIC_SYSRQ) 26#if defined(CONFIG_MAGIC_SYSRQ)
25#define SUPPORT_SYSRQ 27#define SUPPORT_SYSRQ
@@ -407,6 +409,60 @@ static void __init sunhv_console_init(void)
407 register_console(&sunhv_console); 409 register_console(&sunhv_console);
408} 410}
409 411
412static int __init hv_console_compatible(char *buf, int len)
413{
414 while (len) {
415 int this_len;
416
417 if (!strcmp(buf, "qcn"))
418 return 1;
419
420 this_len = strlen(buf) + 1;
421
422 buf += this_len;
423 len -= this_len;
424 }
425
426 return 0;
427}
428
429static unsigned int __init get_interrupt(void)
430{
431 const char *cons_str = "console";
432 const char *compat_str = "compatible";
433 int node = prom_getchild(sun4v_vdev_root);
434 unsigned int irq;
435 char buf[64];
436 int err, len;
437
438 node = prom_searchsiblings(node, cons_str);
439 if (!node)
440 return 0;
441
442 len = prom_getproplen(node, compat_str);
443 if (len == 0 || len == -1)
444 return 0;
445
446 err = prom_getproperty(node, compat_str, buf, 64);
447 if (err == -1)
448 return 0;
449
450 if (!hv_console_compatible(buf, len))
451 return 0;
452
453 /* Ok, the this is the OBP node for the sun4v hypervisor
454 * console device. Decode the interrupt.
455 */
456 err = prom_getproperty(node, "interrupts",
457 (char *) &irq, sizeof(irq));
458 if (err == -1)
459 return 0;
460
461 return sun4v_build_irq(sun4v_vdev_devhandle, irq, 4, 0);
462}
463
464static u32 sunhv_irq;
465
410static int __init sunhv_init(void) 466static int __init sunhv_init(void)
411{ 467{
412 struct uart_port *port; 468 struct uart_port *port;
@@ -415,6 +471,10 @@ static int __init sunhv_init(void)
415 if (tlb_type != hypervisor) 471 if (tlb_type != hypervisor)
416 return -ENODEV; 472 return -ENODEV;
417 473
474 sunhv_irq = get_interrupt();
475 if (!sunhv_irq)
476 return -ENODEV;
477
418 port = kmalloc(sizeof(struct uart_port), GFP_KERNEL); 478 port = kmalloc(sizeof(struct uart_port), GFP_KERNEL);
419 if (unlikely(!port)) 479 if (unlikely(!port))
420 return -ENOMEM; 480 return -ENOMEM;
@@ -424,22 +484,23 @@ static int __init sunhv_init(void)
424 port->type = PORT_SUNHV; 484 port->type = PORT_SUNHV;
425 port->uartclk = ( 29491200 / 16 ); /* arbitrary */ 485 port->uartclk = ( 29491200 / 16 ); /* arbitrary */
426 486
427 /* XXX Get interrupt. XXX */ 487 if (request_irq(sunhv_irq, sunhv_interrupt,
428 if (request_irq(0 /* XXX */, sunhv_interrupt,
429 SA_SHIRQ, "serial(sunhv)", port)) { 488 SA_SHIRQ, "serial(sunhv)", port)) {
430 printk("sunhv: Cannot get IRQ %x\n", 489 printk("sunhv: Cannot get IRQ %x\n", sunhv_irq);
431 0 /* XXX */);
432 kfree(port); 490 kfree(port);
433 return -ENODEV; 491 return -ENODEV;
434 } 492 }
435 493
494 printk("SUNHV: SUN4V virtual console, IRQ[%08x]\n",
495 sunhv_irq);
496
436 sunhv_reg.minor = sunserial_current_minor; 497 sunhv_reg.minor = sunserial_current_minor;
437 sunhv_reg.nr = 1; 498 sunhv_reg.nr = 1;
438 sunhv_reg.cons = &sunhv_console; 499 sunhv_reg.cons = &sunhv_console;
439 500
440 ret = uart_register_driver(&sunhv_reg); 501 ret = uart_register_driver(&sunhv_reg);
441 if (ret < 0) { 502 if (ret < 0) {
442 free_irq(0 /* XXX */, up); 503 free_irq(sunhv_irq, up);
443 kfree(port); 504 kfree(port);
444 505
445 return ret; 506 return ret;
@@ -463,7 +524,7 @@ static void __exit sunhv_exit(void)
463 BUG_ON(!port); 524 BUG_ON(!port);
464 525
465 uart_remove_one_port(&sunhv_reg, port); 526 uart_remove_one_port(&sunhv_reg, port);
466 free_irq(0 /* XXX */, port); 527 free_irq(sunhv_irq, port);
467 528
468 sunserial_current_minor -= 1; 529 sunserial_current_minor -= 1;
469 530