From e0a599251d8ea8d02424ce52b52cbae739a8fda2 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 13 Feb 2006 20:43:02 -0800 Subject: [PATCH] --- yaml --- r: 21439 b: refs/heads/master c: f4266ab45a3f08bd76c2d414a2d7a1a9dc2501c0 h: refs/heads/master i: 21437: 5239faa080a34364987c5aca2ddbbd92357cdc36 21435: 2d8389c05197d5924ba655e9a70004275de69e38 21431: 5fc6df2336d62a920f44044897949d8d209b5eb8 21423: 5f9c22c63fde18b3fe93b1fc2866af330334500e 21407: bcdc1b91016c2c5c6940a0df802944923e5b455a 21375: d3aa8891740bd11d0da79b039ad226f06550cd1f v: v3 --- [refs] | 2 +- trunk/drivers/serial/sunhv.c | 73 +++++++++++++++++++++++++++++++++--- 2 files changed, 68 insertions(+), 7 deletions(-) diff --git a/[refs] b/[refs] index 0caa1e8f4773..e9fdf6d483fb 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: e77227eb4e17591a6a511b9c0ff6e8ad7350c575 +refs/heads/master: f4266ab45a3f08bd76c2d414a2d7a1a9dc2501c0 diff --git a/trunk/drivers/serial/sunhv.c b/trunk/drivers/serial/sunhv.c index 2ba716eeb0bf..d3a9dd739da3 100644 --- a/trunk/drivers/serial/sunhv.c +++ b/trunk/drivers/serial/sunhv.c @@ -20,6 +20,8 @@ #include #include +#include +#include #if defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ @@ -407,6 +409,60 @@ static void __init sunhv_console_init(void) register_console(&sunhv_console); } +static int __init hv_console_compatible(char *buf, int len) +{ + while (len) { + int this_len; + + if (!strcmp(buf, "qcn")) + return 1; + + this_len = strlen(buf) + 1; + + buf += this_len; + len -= this_len; + } + + return 0; +} + +static unsigned int __init get_interrupt(void) +{ + const char *cons_str = "console"; + const char *compat_str = "compatible"; + int node = prom_getchild(sun4v_vdev_root); + unsigned int irq; + char buf[64]; + int err, len; + + node = prom_searchsiblings(node, cons_str); + if (!node) + return 0; + + len = prom_getproplen(node, compat_str); + if (len == 0 || len == -1) + return 0; + + err = prom_getproperty(node, compat_str, buf, 64); + if (err == -1) + return 0; + + if (!hv_console_compatible(buf, len)) + return 0; + + /* Ok, the this is the OBP node for the sun4v hypervisor + * console device. Decode the interrupt. + */ + err = prom_getproperty(node, "interrupts", + (char *) &irq, sizeof(irq)); + if (err == -1) + return 0; + + return sun4v_build_irq(sun4v_vdev_devhandle, irq, 4, 0); +} + +static u32 sunhv_irq; + static int __init sunhv_init(void) { struct uart_port *port; @@ -415,6 +471,10 @@ static int __init sunhv_init(void) if (tlb_type != hypervisor) return -ENODEV; + sunhv_irq = get_interrupt(); + if (!sunhv_irq) + return -ENODEV; + port = kmalloc(sizeof(struct uart_port), GFP_KERNEL); if (unlikely(!port)) return -ENOMEM; @@ -424,22 +484,23 @@ static int __init sunhv_init(void) port->type = PORT_SUNHV; port->uartclk = ( 29491200 / 16 ); /* arbitrary */ - /* XXX Get interrupt. XXX */ - if (request_irq(0 /* XXX */, sunhv_interrupt, + if (request_irq(sunhv_irq, sunhv_interrupt, SA_SHIRQ, "serial(sunhv)", port)) { - printk("sunhv: Cannot get IRQ %x\n", - 0 /* XXX */); + printk("sunhv: Cannot get IRQ %x\n", sunhv_irq); kfree(port); return -ENODEV; } + printk("SUNHV: SUN4V virtual console, IRQ[%08x]\n", + sunhv_irq); + sunhv_reg.minor = sunserial_current_minor; sunhv_reg.nr = 1; sunhv_reg.cons = &sunhv_console; ret = uart_register_driver(&sunhv_reg); if (ret < 0) { - free_irq(0 /* XXX */, up); + free_irq(sunhv_irq, up); kfree(port); return ret; @@ -463,7 +524,7 @@ static void __exit sunhv_exit(void) BUG_ON(!port); uart_remove_one_port(&sunhv_reg, port); - free_irq(0 /* XXX */, port); + free_irq(sunhv_irq, port); sunserial_current_minor -= 1;