aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2006-02-15 22:48:54 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2006-03-20 04:13:05 -0500
commit9d29a3fafd06534ad73427fee3c968c094d05b9b (patch)
tree4afd7455d6249d9143acea6c4704f69aa98d311a
parent7890f794e0e6f7dce2a5f4a03ba64b0b3fe306bd (diff)
[SPARC64]: Decode virtual-devices interrupts correctly.
Need to translate through the interrupt-map{,-mask] properties. Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--arch/sparc64/kernel/devices.c98
-rw-r--r--drivers/serial/sunhv.c14
-rw-r--r--include/asm-sparc64/vdev.h6
3 files changed, 92 insertions, 26 deletions
diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c
index 71eee392e141..1341b99ca7aa 100644
--- a/arch/sparc64/kernel/devices.c
+++ b/arch/sparc64/kernel/devices.c
@@ -22,6 +22,7 @@
22#include <asm/timer.h> 22#include <asm/timer.h>
23#include <asm/cpudata.h> 23#include <asm/cpudata.h>
24#include <asm/vdev.h> 24#include <asm/vdev.h>
25#include <asm/irq.h>
25 26
26/* Used to synchronize acceses to NatSemi SUPER I/O chip configure 27/* Used to synchronize acceses to NatSemi SUPER I/O chip configure
27 * operations in asm/ns87303.h 28 * operations in asm/ns87303.h
@@ -33,14 +34,28 @@ extern void central_probe(void);
33 34
34u32 sun4v_vdev_devhandle; 35u32 sun4v_vdev_devhandle;
35int sun4v_vdev_root; 36int sun4v_vdev_root;
36struct linux_prom_pci_intmap *sun4v_vdev_intmap; 37
37int sun4v_vdev_num_intmap; 38struct vdev_intmap {
38struct linux_prom_pci_intmap sun4v_vdev_intmask; 39 unsigned int phys;
40 unsigned int irq;
41 unsigned int cnode;
42 unsigned int cinterrupt;
43};
44
45struct vdev_intmask {
46 unsigned int phys;
47 unsigned int interrupt;
48 unsigned int __unused;
49};
50
51static struct vdev_intmap *vdev_intmap;
52static int vdev_num_intmap;
53static struct vdev_intmask vdev_intmask;
39 54
40static void __init sun4v_virtual_device_probe(void) 55static void __init sun4v_virtual_device_probe(void)
41{ 56{
42 struct linux_prom64_registers regs; 57 struct linux_prom64_registers regs;
43 struct linux_prom_pci_intmap *ip; 58 struct vdev_intmap *ip;
44 int node, sz, err; 59 int node, sz, err;
45 60
46 if (tlb_type != hypervisor) 61 if (tlb_type != hypervisor)
@@ -58,10 +73,21 @@ static void __init sun4v_virtual_device_probe(void)
58 prom_getproperty(node, "reg", (char *)&regs, sizeof(regs)); 73 prom_getproperty(node, "reg", (char *)&regs, sizeof(regs));
59 sun4v_vdev_devhandle = (regs.phys_addr >> 32UL) & 0x0fffffff; 74 sun4v_vdev_devhandle = (regs.phys_addr >> 32UL) & 0x0fffffff;
60 75
61 sz = sizeof(*ip) * 64; 76 sz = prom_getproplen(node, "interrupt-map");
62 sun4v_vdev_intmap = ip = alloc_bootmem_low_pages(sz); 77 if (sz <= 0) {
63 if (!sun4v_vdev_intmap) { 78 prom_printf("SUN4V: Error, no vdev interrupt-map.\n");
64 prom_printf("SUN4V: Error, cannot allocate vdev intmap.\n"); 79 prom_halt();
80 }
81
82 if ((sz % sizeof(*ip)) != 0) {
83 prom_printf("SUN4V: Bogus interrupt-map property size %d\n",
84 sz);
85 prom_halt();
86 }
87
88 vdev_intmap = ip = alloc_bootmem_low_pages(sz);
89 if (!vdev_intmap) {
90 prom_printf("SUN4V: Error, cannot allocate vdev_intmap.\n");
65 prom_halt(); 91 prom_halt();
66 } 92 }
67 93
@@ -70,22 +96,70 @@ static void __init sun4v_virtual_device_probe(void)
70 prom_printf("SUN4V: Fatal error, no vdev interrupt-map.\n"); 96 prom_printf("SUN4V: Fatal error, no vdev interrupt-map.\n");
71 prom_halt(); 97 prom_halt();
72 } 98 }
99 if (err != sz) {
100 prom_printf("SUN4V: Inconsistent interrupt-map size, "
101 "proplen(%d) vs getprop(%d).\n", sz,err);
102 prom_halt();
103 }
73 104
74 sun4v_vdev_num_intmap = err / sizeof(*ip); 105 vdev_num_intmap = err / sizeof(*ip);
75 106
76 err = prom_getproperty(node, "interrupt-map-mask", 107 err = prom_getproperty(node, "interrupt-map-mask",
77 (char *) &sun4v_vdev_intmask, 108 (char *) &vdev_intmask,
78 sizeof(sun4v_vdev_intmask)); 109 sizeof(vdev_intmask));
79 if (err == -1) { 110 if (err <= 0) {
80 prom_printf("SUN4V: Fatal error, no vdev " 111 prom_printf("SUN4V: Fatal error, no vdev "
81 "interrupt-map-mask.\n"); 112 "interrupt-map-mask.\n");
82 prom_halt(); 113 prom_halt();
83 } 114 }
115 if (err % sizeof(vdev_intmask)) {
116 prom_printf("SUN4V: Bogus interrupt-map-mask "
117 "property size %d\n", err);
118 prom_halt();
119 }
84 120
85 printk("SUN4V: virtual-devices devhandle[%x]\n", 121 printk("SUN4V: virtual-devices devhandle[%x]\n",
86 sun4v_vdev_devhandle); 122 sun4v_vdev_devhandle);
87} 123}
88 124
125unsigned int sun4v_vdev_device_interrupt(unsigned int dev_node)
126{
127 unsigned int irq, reg;
128 int err, i;
129
130 err = prom_getproperty(dev_node, "interrupts",
131 (char *) &irq, sizeof(irq));
132 if (err <= 0) {
133 printk("VDEV: Cannot get \"interrupts\" "
134 "property for OBP node %x\n", dev_node);
135 return 0;
136 }
137
138 err = prom_getproperty(dev_node, "reg",
139 (char *) &reg, sizeof(reg));
140 if (err <= 0) {
141 printk("VDEV: Cannot get \"reg\" "
142 "property for OBP node %x\n", dev_node);
143 return 0;
144 }
145
146 for (i = 0; i < vdev_num_intmap; i++) {
147 if (vdev_intmap[i].phys == (reg & vdev_intmask.phys) &&
148 vdev_intmap[i].irq == (irq & vdev_intmask.interrupt)) {
149 irq = vdev_intmap[i].cinterrupt;
150 break;
151 }
152 }
153
154 if (i == vdev_num_intmap) {
155 printk("VDEV: No matching interrupt map entry "
156 "for OBP node %x\n", dev_node);
157 return 0;
158 }
159
160 return sun4v_build_irq(sun4v_vdev_devhandle, irq, 4, 0);
161}
162
89static const char *cpu_mid_prop(void) 163static const char *cpu_mid_prop(void)
90{ 164{
91 if (tlb_type == spitfire) 165 if (tlb_type == spitfire)
diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c
index 71c70d7a998c..cc46206a1065 100644
--- a/drivers/serial/sunhv.c
+++ b/drivers/serial/sunhv.c
@@ -21,6 +21,7 @@
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/vdev.h>
24#include <asm/oplib.h>
24#include <asm/irq.h> 25#include <asm/irq.h>
25 26
26#if defined(CONFIG_MAGIC_SYSRQ) 27#if defined(CONFIG_MAGIC_SYSRQ)
@@ -427,7 +428,6 @@ static unsigned int __init get_interrupt(void)
427 const char *cons_str = "console"; 428 const char *cons_str = "console";
428 const char *compat_str = "compatible"; 429 const char *compat_str = "compatible";
429 int node = prom_getchild(sun4v_vdev_root); 430 int node = prom_getchild(sun4v_vdev_root);
430 unsigned int irq;
431 char buf[64]; 431 char buf[64];
432 int err, len; 432 int err, len;
433 433
@@ -449,12 +449,7 @@ static unsigned int __init get_interrupt(void)
449 /* Ok, the this is the OBP node for the sun4v hypervisor 449 /* Ok, the this is the OBP node for the sun4v hypervisor
450 * console device. Decode the interrupt. 450 * console device. Decode the interrupt.
451 */ 451 */
452 err = prom_getproperty(node, "interrupts", 452 return sun4v_vdev_device_interrupt(node);
453 (char *) &irq, sizeof(irq));
454 if (err == -1)
455 return 0;
456
457 return sun4v_build_irq(sun4v_vdev_devhandle, irq, 4, 0);
458} 453}
459 454
460static u32 sunhv_irq; 455static u32 sunhv_irq;
@@ -487,8 +482,8 @@ static int __init sunhv_init(void)
487 return -ENODEV; 482 return -ENODEV;
488 } 483 }
489 484
490 printk("SUNHV: SUN4V virtual console, IRQ[%08x]\n", 485 printk("SUNHV: SUN4V virtual console, IRQ %s\n",
491 sunhv_irq); 486 __irq_itoa(sunhv_irq));
492 487
493 sunhv_reg.minor = sunserial_current_minor; 488 sunhv_reg.minor = sunserial_current_minor;
494 sunhv_reg.nr = 1; 489 sunhv_reg.nr = 1;
@@ -520,7 +515,6 @@ static void __exit sunhv_exit(void)
520 515
521 uart_remove_one_port(&sunhv_reg, port); 516 uart_remove_one_port(&sunhv_reg, port);
522 free_irq(sunhv_irq, port); 517 free_irq(sunhv_irq, port);
523
524 sunserial_current_minor -= 1; 518 sunserial_current_minor -= 1;
525 519
526 uart_unregister_driver(&sunhv_reg); 520 uart_unregister_driver(&sunhv_reg);
diff --git a/include/asm-sparc64/vdev.h b/include/asm-sparc64/vdev.h
index ebaac41a6e1a..996e6be7b976 100644
--- a/include/asm-sparc64/vdev.h
+++ b/include/asm-sparc64/vdev.h
@@ -7,12 +7,10 @@
7#define _SPARC64_VDEV_H 7#define _SPARC64_VDEV_H
8 8
9#include <linux/types.h> 9#include <linux/types.h>
10#include <asm/oplib.h>
11 10
12extern u32 sun4v_vdev_devhandle; 11extern u32 sun4v_vdev_devhandle;
13extern int sun4v_vdev_root; 12extern int sun4v_vdev_root;
14extern struct linux_prom_pci_intmap *sun4v_vdev_intmap; 13
15extern int sun4v_vdev_num_intmap; 14extern unsigned int sun4v_vdev_device_interrupt(unsigned int);
16extern struct linux_prom_pci_intmap sun4v_vdev_intmask;
17 15
18#endif /* !(_SPARC64_VDEV_H) */ 16#endif /* !(_SPARC64_VDEV_H) */