aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64')
-rw-r--r--arch/sparc64/kernel/devices.c98
1 files changed, 86 insertions, 12 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)