diff options
-rw-r--r-- | arch/sparc64/kernel/devices.c | 97 | ||||
-rw-r--r-- | arch/sparc64/kernel/of_device.c | 3 | ||||
-rw-r--r-- | arch/sparc64/kernel/prom.c | 23 | ||||
-rw-r--r-- | drivers/serial/sunhv.c | 166 | ||||
-rw-r--r-- | drivers/serial/sunsu.c | 2 | ||||
-rw-r--r-- | include/asm-sparc64/vdev.h | 17 |
6 files changed, 99 insertions, 209 deletions
diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c index ddbe8cda06a..f8ef2f2b9b3 100644 --- a/arch/sparc64/kernel/devices.c +++ b/arch/sparc64/kernel/devices.c @@ -20,8 +20,6 @@ #include <asm/spitfire.h> #include <asm/timer.h> #include <asm/cpudata.h> -#include <asm/vdev.h> -#include <asm/irq.h> /* Used to synchronize acceses to NatSemi SUPER I/O chip configure * operations in asm/ns87303.h @@ -31,100 +29,6 @@ DEFINE_SPINLOCK(ns87303_lock); extern void cpu_probe(void); extern void central_probe(void); -u32 sun4v_vdev_devhandle; -struct device_node *sun4v_vdev_root; - -struct vdev_intmap { - unsigned int phys; - unsigned int irq; - unsigned int cnode; - unsigned int cinterrupt; -}; - -struct vdev_intmask { - unsigned int phys; - unsigned int interrupt; - unsigned int __unused; -}; - -static struct vdev_intmap *vdev_intmap; -static int vdev_num_intmap; -static struct vdev_intmask *vdev_intmask; - -static void __init sun4v_virtual_device_probe(void) -{ - struct linux_prom64_registers *regs; - struct property *prop; - struct device_node *dp; - int sz; - - if (tlb_type != hypervisor) - return; - - dp = of_find_node_by_name(NULL, "virtual-devices"); - if (!dp) { - prom_printf("SUN4V: Fatal error, no virtual-devices node.\n"); - prom_halt(); - } - - sun4v_vdev_root = dp; - - prop = of_find_property(dp, "reg", NULL); - regs = prop->value; - sun4v_vdev_devhandle = (regs[0].phys_addr >> 32UL) & 0x0fffffff; - - prop = of_find_property(dp, "interrupt-map", &sz); - vdev_intmap = prop->value; - vdev_num_intmap = sz / sizeof(struct vdev_intmap); - - prop = of_find_property(dp, "interrupt-map-mask", NULL); - vdev_intmask = prop->value; - - printk("%s: Virtual Device Bus devhandle[%x]\n", - dp->full_name, sun4v_vdev_devhandle); -} - -unsigned int sun4v_vdev_device_interrupt(struct device_node *dev_node) -{ - struct property *prop; - unsigned int irq, reg; - int i; - - prop = of_find_property(dev_node, "interrupts", NULL); - if (!prop) { - printk("VDEV: Cannot get \"interrupts\" " - "property for OBP node %s\n", - dev_node->full_name); - return 0; - } - irq = *(unsigned int *) prop->value; - - prop = of_find_property(dev_node, "reg", NULL); - if (!prop) { - printk("VDEV: Cannot get \"reg\" " - "property for OBP node %s\n", - dev_node->full_name); - return 0; - } - reg = *(unsigned int *) prop->value; - - for (i = 0; i < vdev_num_intmap; i++) { - if (vdev_intmap[i].phys == (reg & vdev_intmask->phys) && - vdev_intmap[i].irq == (irq & vdev_intmask->interrupt)) { - irq = vdev_intmap[i].cinterrupt; - break; - } - } - - if (i == vdev_num_intmap) { - printk("VDEV: No matching interrupt map entry " - "for OBP node %s\n", dev_node->full_name); - return 0; - } - - return sun4v_build_irq(sun4v_vdev_devhandle, irq); -} - static const char *cpu_mid_prop(void) { if (tlb_type == spitfire) @@ -289,7 +193,6 @@ void __init device_scan(void) } #endif - sun4v_virtual_device_probe(); central_probe(); cpu_probe(); diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c index 3670dc8a7d5..169b017eec0 100644 --- a/arch/sparc64/kernel/of_device.c +++ b/arch/sparc64/kernel/of_device.c @@ -602,6 +602,9 @@ static void __init build_device_resources(struct of_device *op, build_res: memset(r, 0, sizeof(*r)); if (result != OF_BAD_ADDR) { + if (tlb_type == hypervisor) + result &= 0x0fffffffffffffffUL; + r->start = result; r->end = result + size - 1; r->flags = flags; diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index 8a70c52c044..fa484d4f241 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c @@ -1008,6 +1008,27 @@ static struct irq_trans pci_irq_trans_table[] = { }; #endif +static unsigned int sun4v_vdev_irq_build(struct device_node *dp, + unsigned int devino, + void *_data) +{ + u32 devhandle = (u32) (unsigned long) _data; + + return sun4v_build_irq(devhandle, devino); +} + +static void sun4v_vdev_irq_trans_init(struct device_node *dp) +{ + struct linux_prom64_registers *regs; + + dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); + dp->irq_trans->irq_build = sun4v_vdev_irq_build; + + regs = of_get_property(dp, "reg", NULL); + dp->irq_trans->data = (void *) (unsigned long) + ((regs->phys_addr >> 32UL) & 0x0fffffff); +} + static void irq_trans_init(struct device_node *dp) { const char *model; @@ -1034,6 +1055,8 @@ static void irq_trans_init(struct device_node *dp) #endif if (!strcmp(dp->name, "central")) return central_irq_trans_init(dp->child); + if (!strcmp(dp->name, "virtual-devices")) + return sun4v_vdev_irq_trans_init(dp); } static int is_root_node(const struct device_node *dp) diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c index d36bc400339..f851f0f44f9 100644 --- a/drivers/serial/sunhv.c +++ b/drivers/serial/sunhv.c @@ -20,8 +20,8 @@ #include <asm/hypervisor.h> #include <asm/spitfire.h> -#include <asm/vdev.h> -#include <asm/oplib.h> +#include <asm/prom.h> +#include <asm/of_device.h> #include <asm/irq.h> #if defined(CONFIG_MAGIC_SYSRQ) @@ -407,144 +407,120 @@ static inline struct console *SUNHV_CONSOLE(void) return &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) -{ - struct device_node *dev_node; - - dev_node = sun4v_vdev_root->child; - while (dev_node != NULL) { - struct property *prop; - - if (strcmp(dev_node->name, "console")) - goto next_sibling; - - prop = of_find_property(dev_node, "compatible", NULL); - if (!prop) - goto next_sibling; - - if (hv_console_compatible(prop->value, prop->length)) - break; - - next_sibling: - dev_node = dev_node->sibling; - } - if (!dev_node) - return 0; - - /* Ok, the this is the OBP node for the sun4v hypervisor - * console device. Decode the interrupt. - */ - return sun4v_vdev_device_interrupt(dev_node); -} - -static int __init sunhv_init(void) +static int __devinit hv_probe(struct of_device *op, const struct of_device_id *match) { struct uart_port *port; - int ret; + int err; - if (tlb_type != hypervisor) + if (op->irqs[0] == 0xffffffff) return -ENODEV; - port = kmalloc(sizeof(struct uart_port), GFP_KERNEL); + port = kzalloc(sizeof(struct uart_port), GFP_KERNEL); if (unlikely(!port)) return -ENOMEM; - memset(port, 0, sizeof(struct uart_port)); + sunhv_port = port; port->line = 0; port->ops = &sunhv_pops; port->type = PORT_SUNHV; port->uartclk = ( 29491200 / 16 ); /* arbitrary */ - /* Set this just to make uart_configure_port() happy. */ port->membase = (unsigned char __iomem *) __pa(port); - port->irq = get_interrupt(); - if (!port->irq) { - kfree(port); - return -ENODEV; - } + port->irq = op->irqs[0]; + + port->dev = &op->dev; sunhv_reg.minor = sunserial_current_minor; sunhv_reg.nr = 1; - ret = uart_register_driver(&sunhv_reg); - if (ret < 0) { - printk(KERN_ERR "SUNHV: uart_register_driver() failed %d\n", - ret); - kfree(port); - - return ret; - } + err = uart_register_driver(&sunhv_reg); + if (err) + goto out_free_port; sunhv_reg.tty_driver->name_base = sunhv_reg.minor - 64; sunserial_current_minor += 1; sunhv_reg.cons = SUNHV_CONSOLE(); - sunhv_port = port; + err = uart_add_one_port(&sunhv_reg, port); + if (err) + goto out_unregister_driver; - ret = uart_add_one_port(&sunhv_reg, port); - if (ret < 0) { - printk(KERN_ERR "SUNHV: uart_add_one_port() failed %d\n", ret); - sunserial_current_minor -= 1; - uart_unregister_driver(&sunhv_reg); - kfree(port); - sunhv_port = NULL; - return -ENODEV; - } + err = request_irq(port->irq, sunhv_interrupt, 0, "hvcons", port); + if (err) + goto out_remove_port; - if (request_irq(port->irq, sunhv_interrupt, - SA_SHIRQ, "serial(sunhv)", port)) { - printk(KERN_ERR "sunhv: Cannot register IRQ\n"); - uart_remove_one_port(&sunhv_reg, port); - sunserial_current_minor -= 1; - uart_unregister_driver(&sunhv_reg); - kfree(port); - sunhv_port = NULL; - return -ENODEV; - } + dev_set_drvdata(&op->dev, port); return 0; + +out_remove_port: + uart_remove_one_port(&sunhv_reg, port); + +out_unregister_driver: + sunserial_current_minor -= 1; + uart_unregister_driver(&sunhv_reg); + +out_free_port: + kfree(port); + sunhv_port = NULL; + return err; } -static void __exit sunhv_exit(void) +static int __devexit hv_remove(struct of_device *dev) { - struct uart_port *port = sunhv_port; - - BUG_ON(!port); + struct uart_port *port = dev_get_drvdata(&dev->dev); free_irq(port->irq, port); uart_remove_one_port(&sunhv_reg, port); - sunserial_current_minor -= 1; + sunserial_current_minor -= 1; uart_unregister_driver(&sunhv_reg); - kfree(sunhv_port); + kfree(port); sunhv_port = NULL; + + dev_set_drvdata(&dev->dev, NULL); + + return 0; +} + +static struct of_device_id hv_match[] = { + { + .name = "console", + .compatible = "qcn", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, hv_match); + +static struct of_platform_driver hv_driver = { + .name = "hv", + .match_table = hv_match, + .probe = hv_probe, + .remove = __devexit_p(hv_remove), +}; + +static int __init sunhv_init(void) +{ + if (tlb_type != hypervisor) + return -ENODEV; + + return of_register_driver(&hv_driver, &of_bus_type); +} + +static void __exit sunhv_exit(void) +{ + of_unregister_driver(&hv_driver); } module_init(sunhv_init); module_exit(sunhv_exit); MODULE_AUTHOR("David S. Miller"); -MODULE_DESCRIPTION("SUN4V Hypervisor console driver") +MODULE_DESCRIPTION("SUN4V Hypervisor console driver"); +MODULE_VERSION("2.0"); MODULE_LICENSE("GPL"); diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index 72c86d0017f..eabf477fee9 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c @@ -1438,6 +1438,8 @@ static int __devinit su_probe(struct of_device *op, const struct of_device_id *m err = sunsu_kbd_ms_init(up); if (err) goto out_unmap; + + return 0; } up->port.flags |= UPF_BOOT_AUTOCONF; diff --git a/include/asm-sparc64/vdev.h b/include/asm-sparc64/vdev.h deleted file mode 100644 index 25637c57675..00000000000 --- a/include/asm-sparc64/vdev.h +++ /dev/null @@ -1,17 +0,0 @@ -/* vdev.h: SUN4V virtual device interfaces and defines. - * - * Copyright (C) 2006 David S. Miller <davem@davemloft.net> - */ - -#ifndef _SPARC64_VDEV_H -#define _SPARC64_VDEV_H - -#include <linux/types.h> -#include <asm/prom.h> - -extern u32 sun4v_vdev_devhandle; -extern struct device_node *sun4v_vdev_root; - -extern unsigned int sun4v_vdev_device_interrupt(struct device_node *dev_node); - -#endif /* !(_SPARC64_VDEV_H) */ |