diff options
Diffstat (limited to 'drivers/serial/sunhv.c')
-rw-r--r-- | drivers/serial/sunhv.c | 73 |
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 | ||
412 | static 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 | |||
429 | static 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 | |||
464 | static u32 sunhv_irq; | ||
465 | |||
410 | static int __init sunhv_init(void) | 466 | static 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 | ||