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 ddbe8cda06af..f8ef2f2b9b37 100644 --- a/arch/sparc64/kernel/devices.c +++ b/arch/sparc64/kernel/devices.c | |||
@@ -20,8 +20,6 @@ | |||
20 | #include <asm/spitfire.h> | 20 | #include <asm/spitfire.h> |
21 | #include <asm/timer.h> | 21 | #include <asm/timer.h> |
22 | #include <asm/cpudata.h> | 22 | #include <asm/cpudata.h> |
23 | #include <asm/vdev.h> | ||
24 | #include <asm/irq.h> | ||
25 | 23 | ||
26 | /* Used to synchronize acceses to NatSemi SUPER I/O chip configure | 24 | /* Used to synchronize acceses to NatSemi SUPER I/O chip configure |
27 | * operations in asm/ns87303.h | 25 | * operations in asm/ns87303.h |
@@ -31,100 +29,6 @@ DEFINE_SPINLOCK(ns87303_lock); | |||
31 | extern void cpu_probe(void); | 29 | extern void cpu_probe(void); |
32 | extern void central_probe(void); | 30 | extern void central_probe(void); |
33 | 31 | ||
34 | u32 sun4v_vdev_devhandle; | ||
35 | struct device_node *sun4v_vdev_root; | ||
36 | |||
37 | struct vdev_intmap { | ||
38 | unsigned int phys; | ||
39 | unsigned int irq; | ||
40 | unsigned int cnode; | ||
41 | unsigned int cinterrupt; | ||
42 | }; | ||
43 | |||
44 | struct vdev_intmask { | ||
45 | unsigned int phys; | ||
46 | unsigned int interrupt; | ||
47 | unsigned int __unused; | ||
48 | }; | ||
49 | |||
50 | static struct vdev_intmap *vdev_intmap; | ||
51 | static int vdev_num_intmap; | ||
52 | static struct vdev_intmask *vdev_intmask; | ||
53 | |||
54 | static void __init sun4v_virtual_device_probe(void) | ||
55 | { | ||
56 | struct linux_prom64_registers *regs; | ||
57 | struct property *prop; | ||
58 | struct device_node *dp; | ||
59 | int sz; | ||
60 | |||
61 | if (tlb_type != hypervisor) | ||
62 | return; | ||
63 | |||
64 | dp = of_find_node_by_name(NULL, "virtual-devices"); | ||
65 | if (!dp) { | ||
66 | prom_printf("SUN4V: Fatal error, no virtual-devices node.\n"); | ||
67 | prom_halt(); | ||
68 | } | ||
69 | |||
70 | sun4v_vdev_root = dp; | ||
71 | |||
72 | prop = of_find_property(dp, "reg", NULL); | ||
73 | regs = prop->value; | ||
74 | sun4v_vdev_devhandle = (regs[0].phys_addr >> 32UL) & 0x0fffffff; | ||
75 | |||
76 | prop = of_find_property(dp, "interrupt-map", &sz); | ||
77 | vdev_intmap = prop->value; | ||
78 | vdev_num_intmap = sz / sizeof(struct vdev_intmap); | ||
79 | |||
80 | prop = of_find_property(dp, "interrupt-map-mask", NULL); | ||
81 | vdev_intmask = prop->value; | ||
82 | |||
83 | printk("%s: Virtual Device Bus devhandle[%x]\n", | ||
84 | dp->full_name, sun4v_vdev_devhandle); | ||
85 | } | ||
86 | |||
87 | unsigned int sun4v_vdev_device_interrupt(struct device_node *dev_node) | ||
88 | { | ||
89 | struct property *prop; | ||
90 | unsigned int irq, reg; | ||
91 | int i; | ||
92 | |||
93 | prop = of_find_property(dev_node, "interrupts", NULL); | ||
94 | if (!prop) { | ||
95 | printk("VDEV: Cannot get \"interrupts\" " | ||
96 | "property for OBP node %s\n", | ||
97 | dev_node->full_name); | ||
98 | return 0; | ||
99 | } | ||
100 | irq = *(unsigned int *) prop->value; | ||
101 | |||
102 | prop = of_find_property(dev_node, "reg", NULL); | ||
103 | if (!prop) { | ||
104 | printk("VDEV: Cannot get \"reg\" " | ||
105 | "property for OBP node %s\n", | ||
106 | dev_node->full_name); | ||
107 | return 0; | ||
108 | } | ||
109 | reg = *(unsigned int *) prop->value; | ||
110 | |||
111 | for (i = 0; i < vdev_num_intmap; i++) { | ||
112 | if (vdev_intmap[i].phys == (reg & vdev_intmask->phys) && | ||
113 | vdev_intmap[i].irq == (irq & vdev_intmask->interrupt)) { | ||
114 | irq = vdev_intmap[i].cinterrupt; | ||
115 | break; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | if (i == vdev_num_intmap) { | ||
120 | printk("VDEV: No matching interrupt map entry " | ||
121 | "for OBP node %s\n", dev_node->full_name); | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | return sun4v_build_irq(sun4v_vdev_devhandle, irq); | ||
126 | } | ||
127 | |||
128 | static const char *cpu_mid_prop(void) | 32 | static const char *cpu_mid_prop(void) |
129 | { | 33 | { |
130 | if (tlb_type == spitfire) | 34 | if (tlb_type == spitfire) |
@@ -289,7 +193,6 @@ void __init device_scan(void) | |||
289 | } | 193 | } |
290 | #endif | 194 | #endif |
291 | 195 | ||
292 | sun4v_virtual_device_probe(); | ||
293 | central_probe(); | 196 | central_probe(); |
294 | 197 | ||
295 | cpu_probe(); | 198 | cpu_probe(); |
diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c index 3670dc8a7d5f..169b017eec0b 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, | |||
602 | build_res: | 602 | build_res: |
603 | memset(r, 0, sizeof(*r)); | 603 | memset(r, 0, sizeof(*r)); |
604 | if (result != OF_BAD_ADDR) { | 604 | if (result != OF_BAD_ADDR) { |
605 | if (tlb_type == hypervisor) | ||
606 | result &= 0x0fffffffffffffffUL; | ||
607 | |||
605 | r->start = result; | 608 | r->start = result; |
606 | r->end = result + size - 1; | 609 | r->end = result + size - 1; |
607 | r->flags = flags; | 610 | r->flags = flags; |
diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index 8a70c52c0447..fa484d4f241e 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[] = { | |||
1008 | }; | 1008 | }; |
1009 | #endif | 1009 | #endif |
1010 | 1010 | ||
1011 | static unsigned int sun4v_vdev_irq_build(struct device_node *dp, | ||
1012 | unsigned int devino, | ||
1013 | void *_data) | ||
1014 | { | ||
1015 | u32 devhandle = (u32) (unsigned long) _data; | ||
1016 | |||
1017 | return sun4v_build_irq(devhandle, devino); | ||
1018 | } | ||
1019 | |||
1020 | static void sun4v_vdev_irq_trans_init(struct device_node *dp) | ||
1021 | { | ||
1022 | struct linux_prom64_registers *regs; | ||
1023 | |||
1024 | dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); | ||
1025 | dp->irq_trans->irq_build = sun4v_vdev_irq_build; | ||
1026 | |||
1027 | regs = of_get_property(dp, "reg", NULL); | ||
1028 | dp->irq_trans->data = (void *) (unsigned long) | ||
1029 | ((regs->phys_addr >> 32UL) & 0x0fffffff); | ||
1030 | } | ||
1031 | |||
1011 | static void irq_trans_init(struct device_node *dp) | 1032 | static void irq_trans_init(struct device_node *dp) |
1012 | { | 1033 | { |
1013 | const char *model; | 1034 | const char *model; |
@@ -1034,6 +1055,8 @@ static void irq_trans_init(struct device_node *dp) | |||
1034 | #endif | 1055 | #endif |
1035 | if (!strcmp(dp->name, "central")) | 1056 | if (!strcmp(dp->name, "central")) |
1036 | return central_irq_trans_init(dp->child); | 1057 | return central_irq_trans_init(dp->child); |
1058 | if (!strcmp(dp->name, "virtual-devices")) | ||
1059 | return sun4v_vdev_irq_trans_init(dp); | ||
1037 | } | 1060 | } |
1038 | 1061 | ||
1039 | static int is_root_node(const struct device_node *dp) | 1062 | static int is_root_node(const struct device_node *dp) |
diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c index d36bc4003399..f851f0f44f9b 100644 --- a/drivers/serial/sunhv.c +++ b/drivers/serial/sunhv.c | |||
@@ -20,8 +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> | 23 | #include <asm/prom.h> |
24 | #include <asm/oplib.h> | 24 | #include <asm/of_device.h> |
25 | #include <asm/irq.h> | 25 | #include <asm/irq.h> |
26 | 26 | ||
27 | #if defined(CONFIG_MAGIC_SYSRQ) | 27 | #if defined(CONFIG_MAGIC_SYSRQ) |
@@ -407,144 +407,120 @@ static inline struct console *SUNHV_CONSOLE(void) | |||
407 | return &sunhv_console; | 407 | return &sunhv_console; |
408 | } | 408 | } |
409 | 409 | ||
410 | static int __init hv_console_compatible(char *buf, int len) | 410 | static int __devinit hv_probe(struct of_device *op, const struct of_device_id *match) |
411 | { | ||
412 | while (len) { | ||
413 | int this_len; | ||
414 | |||
415 | if (!strcmp(buf, "qcn")) | ||
416 | return 1; | ||
417 | |||
418 | this_len = strlen(buf) + 1; | ||
419 | |||
420 | buf += this_len; | ||
421 | len -= this_len; | ||
422 | } | ||
423 | |||
424 | return 0; | ||
425 | } | ||
426 | |||
427 | static unsigned int __init get_interrupt(void) | ||
428 | { | ||
429 | struct device_node *dev_node; | ||
430 | |||
431 | dev_node = sun4v_vdev_root->child; | ||
432 | while (dev_node != NULL) { | ||
433 | struct property *prop; | ||
434 | |||
435 | if (strcmp(dev_node->name, "console")) | ||
436 | goto next_sibling; | ||
437 | |||
438 | prop = of_find_property(dev_node, "compatible", NULL); | ||
439 | if (!prop) | ||
440 | goto next_sibling; | ||
441 | |||
442 | if (hv_console_compatible(prop->value, prop->length)) | ||
443 | break; | ||
444 | |||
445 | next_sibling: | ||
446 | dev_node = dev_node->sibling; | ||
447 | } | ||
448 | if (!dev_node) | ||
449 | return 0; | ||
450 | |||
451 | /* Ok, the this is the OBP node for the sun4v hypervisor | ||
452 | * console device. Decode the interrupt. | ||
453 | */ | ||
454 | return sun4v_vdev_device_interrupt(dev_node); | ||
455 | } | ||
456 | |||
457 | static int __init sunhv_init(void) | ||
458 | { | 411 | { |
459 | struct uart_port *port; | 412 | struct uart_port *port; |
460 | int ret; | 413 | int err; |
461 | 414 | ||
462 | if (tlb_type != hypervisor) | 415 | if (op->irqs[0] == 0xffffffff) |
463 | return -ENODEV; | 416 | return -ENODEV; |
464 | 417 | ||
465 | port = kmalloc(sizeof(struct uart_port), GFP_KERNEL); | 418 | port = kzalloc(sizeof(struct uart_port), GFP_KERNEL); |
466 | if (unlikely(!port)) | 419 | if (unlikely(!port)) |
467 | return -ENOMEM; | 420 | return -ENOMEM; |
468 | 421 | ||
469 | memset(port, 0, sizeof(struct uart_port)); | 422 | sunhv_port = port; |
470 | 423 | ||
471 | port->line = 0; | 424 | port->line = 0; |
472 | port->ops = &sunhv_pops; | 425 | port->ops = &sunhv_pops; |
473 | port->type = PORT_SUNHV; | 426 | port->type = PORT_SUNHV; |
474 | port->uartclk = ( 29491200 / 16 ); /* arbitrary */ | 427 | port->uartclk = ( 29491200 / 16 ); /* arbitrary */ |
475 | 428 | ||
476 | /* Set this just to make uart_configure_port() happy. */ | ||
477 | port->membase = (unsigned char __iomem *) __pa(port); | 429 | port->membase = (unsigned char __iomem *) __pa(port); |
478 | 430 | ||
479 | port->irq = get_interrupt(); | 431 | port->irq = op->irqs[0]; |
480 | if (!port->irq) { | 432 | |
481 | kfree(port); | 433 | port->dev = &op->dev; |
482 | return -ENODEV; | ||
483 | } | ||
484 | 434 | ||
485 | sunhv_reg.minor = sunserial_current_minor; | 435 | sunhv_reg.minor = sunserial_current_minor; |
486 | sunhv_reg.nr = 1; | 436 | sunhv_reg.nr = 1; |
487 | 437 | ||
488 | ret = uart_register_driver(&sunhv_reg); | 438 | err = uart_register_driver(&sunhv_reg); |
489 | if (ret < 0) { | 439 | if (err) |
490 | printk(KERN_ERR "SUNHV: uart_register_driver() failed %d\n", | 440 | goto out_free_port; |
491 | ret); | ||
492 | kfree(port); | ||
493 | |||
494 | return ret; | ||
495 | } | ||
496 | 441 | ||
497 | sunhv_reg.tty_driver->name_base = sunhv_reg.minor - 64; | 442 | sunhv_reg.tty_driver->name_base = sunhv_reg.minor - 64; |
498 | sunserial_current_minor += 1; | 443 | sunserial_current_minor += 1; |
499 | 444 | ||
500 | sunhv_reg.cons = SUNHV_CONSOLE(); | 445 | sunhv_reg.cons = SUNHV_CONSOLE(); |
501 | 446 | ||
502 | sunhv_port = port; | 447 | err = uart_add_one_port(&sunhv_reg, port); |
448 | if (err) | ||
449 | goto out_unregister_driver; | ||
503 | 450 | ||
504 | ret = uart_add_one_port(&sunhv_reg, port); | 451 | err = request_irq(port->irq, sunhv_interrupt, 0, "hvcons", port); |
505 | if (ret < 0) { | 452 | if (err) |
506 | printk(KERN_ERR "SUNHV: uart_add_one_port() failed %d\n", ret); | 453 | goto out_remove_port; |
507 | sunserial_current_minor -= 1; | ||
508 | uart_unregister_driver(&sunhv_reg); | ||
509 | kfree(port); | ||
510 | sunhv_port = NULL; | ||
511 | return -ENODEV; | ||
512 | } | ||
513 | 454 | ||
514 | if (request_irq(port->irq, sunhv_interrupt, | 455 | dev_set_drvdata(&op->dev, port); |
515 | SA_SHIRQ, "serial(sunhv)", port)) { | ||
516 | printk(KERN_ERR "sunhv: Cannot register IRQ\n"); | ||
517 | uart_remove_one_port(&sunhv_reg, port); | ||
518 | sunserial_current_minor -= 1; | ||
519 | uart_unregister_driver(&sunhv_reg); | ||
520 | kfree(port); | ||
521 | sunhv_port = NULL; | ||
522 | return -ENODEV; | ||
523 | } | ||
524 | 456 | ||
525 | return 0; | 457 | return 0; |
458 | |||
459 | out_remove_port: | ||
460 | uart_remove_one_port(&sunhv_reg, port); | ||
461 | |||
462 | out_unregister_driver: | ||
463 | sunserial_current_minor -= 1; | ||
464 | uart_unregister_driver(&sunhv_reg); | ||
465 | |||
466 | out_free_port: | ||
467 | kfree(port); | ||
468 | sunhv_port = NULL; | ||
469 | return err; | ||
526 | } | 470 | } |
527 | 471 | ||
528 | static void __exit sunhv_exit(void) | 472 | static int __devexit hv_remove(struct of_device *dev) |
529 | { | 473 | { |
530 | struct uart_port *port = sunhv_port; | 474 | struct uart_port *port = dev_get_drvdata(&dev->dev); |
531 | |||
532 | BUG_ON(!port); | ||
533 | 475 | ||
534 | free_irq(port->irq, port); | 476 | free_irq(port->irq, port); |
535 | 477 | ||
536 | uart_remove_one_port(&sunhv_reg, port); | 478 | uart_remove_one_port(&sunhv_reg, port); |
537 | sunserial_current_minor -= 1; | ||
538 | 479 | ||
480 | sunserial_current_minor -= 1; | ||
539 | uart_unregister_driver(&sunhv_reg); | 481 | uart_unregister_driver(&sunhv_reg); |
540 | 482 | ||
541 | kfree(sunhv_port); | 483 | kfree(port); |
542 | sunhv_port = NULL; | 484 | sunhv_port = NULL; |
485 | |||
486 | dev_set_drvdata(&dev->dev, NULL); | ||
487 | |||
488 | return 0; | ||
489 | } | ||
490 | |||
491 | static struct of_device_id hv_match[] = { | ||
492 | { | ||
493 | .name = "console", | ||
494 | .compatible = "qcn", | ||
495 | }, | ||
496 | {}, | ||
497 | }; | ||
498 | MODULE_DEVICE_TABLE(of, hv_match); | ||
499 | |||
500 | static struct of_platform_driver hv_driver = { | ||
501 | .name = "hv", | ||
502 | .match_table = hv_match, | ||
503 | .probe = hv_probe, | ||
504 | .remove = __devexit_p(hv_remove), | ||
505 | }; | ||
506 | |||
507 | static int __init sunhv_init(void) | ||
508 | { | ||
509 | if (tlb_type != hypervisor) | ||
510 | return -ENODEV; | ||
511 | |||
512 | return of_register_driver(&hv_driver, &of_bus_type); | ||
513 | } | ||
514 | |||
515 | static void __exit sunhv_exit(void) | ||
516 | { | ||
517 | of_unregister_driver(&hv_driver); | ||
543 | } | 518 | } |
544 | 519 | ||
545 | module_init(sunhv_init); | 520 | module_init(sunhv_init); |
546 | module_exit(sunhv_exit); | 521 | module_exit(sunhv_exit); |
547 | 522 | ||
548 | MODULE_AUTHOR("David S. Miller"); | 523 | MODULE_AUTHOR("David S. Miller"); |
549 | MODULE_DESCRIPTION("SUN4V Hypervisor console driver") | 524 | MODULE_DESCRIPTION("SUN4V Hypervisor console driver"); |
525 | MODULE_VERSION("2.0"); | ||
550 | MODULE_LICENSE("GPL"); | 526 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index 72c86d0017f5..eabf477fee95 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 | |||
1438 | err = sunsu_kbd_ms_init(up); | 1438 | err = sunsu_kbd_ms_init(up); |
1439 | if (err) | 1439 | if (err) |
1440 | goto out_unmap; | 1440 | goto out_unmap; |
1441 | |||
1442 | return 0; | ||
1441 | } | 1443 | } |
1442 | 1444 | ||
1443 | up->port.flags |= UPF_BOOT_AUTOCONF; | 1445 | 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 25637c57675d..000000000000 --- a/include/asm-sparc64/vdev.h +++ /dev/null | |||
@@ -1,17 +0,0 @@ | |||
1 | /* vdev.h: SUN4V virtual device interfaces and defines. | ||
2 | * | ||
3 | * Copyright (C) 2006 David S. Miller <davem@davemloft.net> | ||
4 | */ | ||
5 | |||
6 | #ifndef _SPARC64_VDEV_H | ||
7 | #define _SPARC64_VDEV_H | ||
8 | |||
9 | #include <linux/types.h> | ||
10 | #include <asm/prom.h> | ||
11 | |||
12 | extern u32 sun4v_vdev_devhandle; | ||
13 | extern struct device_node *sun4v_vdev_root; | ||
14 | |||
15 | extern unsigned int sun4v_vdev_device_interrupt(struct device_node *dev_node); | ||
16 | |||
17 | #endif /* !(_SPARC64_VDEV_H) */ | ||