diff options
Diffstat (limited to 'arch/sparc64/kernel/devices.c')
-rw-r--r-- | arch/sparc64/kernel/devices.c | 222 |
1 files changed, 92 insertions, 130 deletions
diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c index 0dd95ae50e12..389301c95cb2 100644 --- a/arch/sparc64/kernel/devices.c +++ b/arch/sparc64/kernel/devices.c | |||
@@ -33,7 +33,7 @@ extern void cpu_probe(void); | |||
33 | extern void central_probe(void); | 33 | extern void central_probe(void); |
34 | 34 | ||
35 | u32 sun4v_vdev_devhandle; | 35 | u32 sun4v_vdev_devhandle; |
36 | int sun4v_vdev_root; | 36 | struct device_node *sun4v_vdev_root; |
37 | 37 | ||
38 | struct vdev_intmap { | 38 | struct vdev_intmap { |
39 | unsigned int phys; | 39 | unsigned int phys; |
@@ -50,102 +50,68 @@ struct vdev_intmask { | |||
50 | 50 | ||
51 | static struct vdev_intmap *vdev_intmap; | 51 | static struct vdev_intmap *vdev_intmap; |
52 | static int vdev_num_intmap; | 52 | static int vdev_num_intmap; |
53 | static struct vdev_intmask vdev_intmask; | 53 | static struct vdev_intmask *vdev_intmask; |
54 | 54 | ||
55 | static void __init sun4v_virtual_device_probe(void) | 55 | static void __init sun4v_virtual_device_probe(void) |
56 | { | 56 | { |
57 | struct linux_prom64_registers regs; | 57 | struct linux_prom64_registers *regs; |
58 | struct vdev_intmap *ip; | 58 | struct property *prop; |
59 | int node, sz, err; | 59 | struct device_node *dp; |
60 | int sz; | ||
60 | 61 | ||
61 | if (tlb_type != hypervisor) | 62 | if (tlb_type != hypervisor) |
62 | return; | 63 | return; |
63 | 64 | ||
64 | node = prom_getchild(prom_root_node); | 65 | dp = of_find_node_by_name(NULL, "virtual-devices"); |
65 | node = prom_searchsiblings(node, "virtual-devices"); | 66 | if (!dp) { |
66 | if (!node) { | ||
67 | prom_printf("SUN4V: Fatal error, no virtual-devices node.\n"); | 67 | prom_printf("SUN4V: Fatal error, no virtual-devices node.\n"); |
68 | prom_halt(); | 68 | prom_halt(); |
69 | } | 69 | } |
70 | 70 | ||
71 | sun4v_vdev_root = node; | 71 | sun4v_vdev_root = dp; |
72 | 72 | ||
73 | prom_getproperty(node, "reg", (char *)®s, sizeof(regs)); | 73 | prop = of_find_property(dp, "reg", NULL); |
74 | sun4v_vdev_devhandle = (regs.phys_addr >> 32UL) & 0x0fffffff; | 74 | regs = prop->value; |
75 | sun4v_vdev_devhandle = (regs[0].phys_addr >> 32UL) & 0x0fffffff; | ||
75 | 76 | ||
76 | sz = prom_getproplen(node, "interrupt-map"); | 77 | prop = of_find_property(dp, "interrupt-map", &sz); |
77 | if (sz <= 0) { | 78 | vdev_intmap = prop->value; |
78 | prom_printf("SUN4V: Error, no vdev interrupt-map.\n"); | 79 | vdev_num_intmap = sz / sizeof(struct vdev_intmap); |
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"); | ||
91 | prom_halt(); | ||
92 | } | ||
93 | |||
94 | err = prom_getproperty(node, "interrupt-map", (char *) ip, sz); | ||
95 | if (err == -1) { | ||
96 | prom_printf("SUN4V: Fatal error, no vdev interrupt-map.\n"); | ||
97 | prom_halt(); | ||
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 | } | ||
104 | |||
105 | vdev_num_intmap = err / sizeof(*ip); | ||
106 | 80 | ||
107 | err = prom_getproperty(node, "interrupt-map-mask", | 81 | prop = of_find_property(dp, "interrupt-map-mask", NULL); |
108 | (char *) &vdev_intmask, | 82 | vdev_intmask = prop->value; |
109 | sizeof(vdev_intmask)); | ||
110 | if (err <= 0) { | ||
111 | prom_printf("SUN4V: Fatal error, no vdev " | ||
112 | "interrupt-map-mask.\n"); | ||
113 | prom_halt(); | ||
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 | } | ||
120 | 83 | ||
121 | printk("SUN4V: virtual-devices devhandle[%x]\n", | 84 | printk("%s: Virtual Device Bus devhandle[%x]\n", |
122 | sun4v_vdev_devhandle); | 85 | dp->full_name, sun4v_vdev_devhandle); |
123 | } | 86 | } |
124 | 87 | ||
125 | unsigned int sun4v_vdev_device_interrupt(unsigned int dev_node) | 88 | unsigned int sun4v_vdev_device_interrupt(struct device_node *dev_node) |
126 | { | 89 | { |
90 | struct property *prop; | ||
127 | unsigned int irq, reg; | 91 | unsigned int irq, reg; |
128 | int err, i; | 92 | int i; |
129 | 93 | ||
130 | err = prom_getproperty(dev_node, "interrupts", | 94 | prop = of_find_property(dev_node, "interrupts", NULL); |
131 | (char *) &irq, sizeof(irq)); | 95 | if (!prop) { |
132 | if (err <= 0) { | ||
133 | printk("VDEV: Cannot get \"interrupts\" " | 96 | printk("VDEV: Cannot get \"interrupts\" " |
134 | "property for OBP node %x\n", dev_node); | 97 | "property for OBP node %s\n", |
98 | dev_node->full_name); | ||
135 | return 0; | 99 | return 0; |
136 | } | 100 | } |
101 | irq = *(unsigned int *) prop->value; | ||
137 | 102 | ||
138 | err = prom_getproperty(dev_node, "reg", | 103 | prop = of_find_property(dev_node, "reg", NULL); |
139 | (char *) ®, sizeof(reg)); | 104 | if (!prop) { |
140 | if (err <= 0) { | ||
141 | printk("VDEV: Cannot get \"reg\" " | 105 | printk("VDEV: Cannot get \"reg\" " |
142 | "property for OBP node %x\n", dev_node); | 106 | "property for OBP node %s\n", |
107 | dev_node->full_name); | ||
143 | return 0; | 108 | return 0; |
144 | } | 109 | } |
110 | reg = *(unsigned int *) prop->value; | ||
145 | 111 | ||
146 | for (i = 0; i < vdev_num_intmap; i++) { | 112 | for (i = 0; i < vdev_num_intmap; i++) { |
147 | if (vdev_intmap[i].phys == (reg & vdev_intmask.phys) && | 113 | if (vdev_intmap[i].phys == (reg & vdev_intmask->phys) && |
148 | vdev_intmap[i].irq == (irq & vdev_intmask.interrupt)) { | 114 | vdev_intmap[i].irq == (irq & vdev_intmask->interrupt)) { |
149 | irq = vdev_intmap[i].cinterrupt; | 115 | irq = vdev_intmap[i].cinterrupt; |
150 | break; | 116 | break; |
151 | } | 117 | } |
@@ -153,7 +119,7 @@ unsigned int sun4v_vdev_device_interrupt(unsigned int dev_node) | |||
153 | 119 | ||
154 | if (i == vdev_num_intmap) { | 120 | if (i == vdev_num_intmap) { |
155 | printk("VDEV: No matching interrupt map entry " | 121 | printk("VDEV: No matching interrupt map entry " |
156 | "for OBP node %x\n", dev_node); | 122 | "for OBP node %s\n", dev_node->full_name); |
157 | return 0; | 123 | return 0; |
158 | } | 124 | } |
159 | 125 | ||
@@ -167,38 +133,44 @@ static const char *cpu_mid_prop(void) | |||
167 | return "portid"; | 133 | return "portid"; |
168 | } | 134 | } |
169 | 135 | ||
170 | static int get_cpu_mid(int prom_node) | 136 | static int get_cpu_mid(struct device_node *dp) |
171 | { | 137 | { |
138 | struct property *prop; | ||
139 | |||
172 | if (tlb_type == hypervisor) { | 140 | if (tlb_type == hypervisor) { |
173 | struct linux_prom64_registers reg; | 141 | struct linux_prom64_registers *reg; |
142 | int len; | ||
174 | 143 | ||
175 | if (prom_getproplen(prom_node, "cpuid") == 4) | 144 | prop = of_find_property(dp, "cpuid", &len); |
176 | return prom_getintdefault(prom_node, "cpuid", 0); | 145 | if (prop && len == 4) |
146 | return *(int *) prop->value; | ||
177 | 147 | ||
178 | prom_getproperty(prom_node, "reg", (char *) ®, sizeof(reg)); | 148 | prop = of_find_property(dp, "reg", NULL); |
179 | return (reg.phys_addr >> 32) & 0x0fffffffUL; | 149 | reg = prop->value; |
150 | return (reg[0].phys_addr >> 32) & 0x0fffffffUL; | ||
180 | } else { | 151 | } else { |
181 | const char *prop_name = cpu_mid_prop(); | 152 | const char *prop_name = cpu_mid_prop(); |
182 | 153 | ||
183 | return prom_getintdefault(prom_node, prop_name, 0); | 154 | prop = of_find_property(dp, prop_name, NULL); |
155 | if (prop) | ||
156 | return *(int *) prop->value; | ||
157 | return 0; | ||
184 | } | 158 | } |
185 | } | 159 | } |
186 | 160 | ||
187 | static int check_cpu_node(int nd, int *cur_inst, | 161 | static int check_cpu_node(struct device_node *dp, int *cur_inst, |
188 | int (*compare)(int, int, void *), void *compare_arg, | 162 | int (*compare)(struct device_node *, int, void *), |
189 | int *prom_node, int *mid) | 163 | void *compare_arg, |
164 | struct device_node **dev_node, int *mid) | ||
190 | { | 165 | { |
191 | char node_str[128]; | 166 | if (strcmp(dp->type, "cpu")) |
192 | |||
193 | prom_getstring(nd, "device_type", node_str, sizeof(node_str)); | ||
194 | if (strcmp(node_str, "cpu")) | ||
195 | return -ENODEV; | 167 | return -ENODEV; |
196 | 168 | ||
197 | if (!compare(nd, *cur_inst, compare_arg)) { | 169 | if (!compare(dp, *cur_inst, compare_arg)) { |
198 | if (prom_node) | 170 | if (dev_node) |
199 | *prom_node = nd; | 171 | *dev_node = dp; |
200 | if (mid) | 172 | if (mid) |
201 | *mid = get_cpu_mid(nd); | 173 | *mid = get_cpu_mid(dp); |
202 | return 0; | 174 | return 0; |
203 | } | 175 | } |
204 | 176 | ||
@@ -207,25 +179,18 @@ static int check_cpu_node(int nd, int *cur_inst, | |||
207 | return -ENODEV; | 179 | return -ENODEV; |
208 | } | 180 | } |
209 | 181 | ||
210 | static int __cpu_find_by(int (*compare)(int, int, void *), void *compare_arg, | 182 | static int __cpu_find_by(int (*compare)(struct device_node *, int, void *), |
211 | int *prom_node, int *mid) | 183 | void *compare_arg, |
184 | struct device_node **dev_node, int *mid) | ||
212 | { | 185 | { |
213 | int nd, cur_inst, err; | 186 | struct device_node *dp; |
187 | int cur_inst; | ||
214 | 188 | ||
215 | nd = prom_root_node; | ||
216 | cur_inst = 0; | 189 | cur_inst = 0; |
217 | 190 | for_each_node_by_type(dp, "cpu") { | |
218 | err = check_cpu_node(nd, &cur_inst, | 191 | int err = check_cpu_node(dp, &cur_inst, |
219 | compare, compare_arg, | 192 | compare, compare_arg, |
220 | prom_node, mid); | 193 | dev_node, mid); |
221 | if (err == 0) | ||
222 | return 0; | ||
223 | |||
224 | nd = prom_getchild(nd); | ||
225 | while ((nd = prom_getsibling(nd)) != 0) { | ||
226 | err = check_cpu_node(nd, &cur_inst, | ||
227 | compare, compare_arg, | ||
228 | prom_node, mid); | ||
229 | if (err == 0) | 194 | if (err == 0) |
230 | return 0; | 195 | return 0; |
231 | } | 196 | } |
@@ -233,7 +198,7 @@ static int __cpu_find_by(int (*compare)(int, int, void *), void *compare_arg, | |||
233 | return -ENODEV; | 198 | return -ENODEV; |
234 | } | 199 | } |
235 | 200 | ||
236 | static int cpu_instance_compare(int nd, int instance, void *_arg) | 201 | static int cpu_instance_compare(struct device_node *dp, int instance, void *_arg) |
237 | { | 202 | { |
238 | int desired_instance = (int) (long) _arg; | 203 | int desired_instance = (int) (long) _arg; |
239 | 204 | ||
@@ -242,27 +207,27 @@ static int cpu_instance_compare(int nd, int instance, void *_arg) | |||
242 | return -ENODEV; | 207 | return -ENODEV; |
243 | } | 208 | } |
244 | 209 | ||
245 | int cpu_find_by_instance(int instance, int *prom_node, int *mid) | 210 | int cpu_find_by_instance(int instance, struct device_node **dev_node, int *mid) |
246 | { | 211 | { |
247 | return __cpu_find_by(cpu_instance_compare, (void *)(long)instance, | 212 | return __cpu_find_by(cpu_instance_compare, (void *)(long)instance, |
248 | prom_node, mid); | 213 | dev_node, mid); |
249 | } | 214 | } |
250 | 215 | ||
251 | static int cpu_mid_compare(int nd, int instance, void *_arg) | 216 | static int cpu_mid_compare(struct device_node *dp, int instance, void *_arg) |
252 | { | 217 | { |
253 | int desired_mid = (int) (long) _arg; | 218 | int desired_mid = (int) (long) _arg; |
254 | int this_mid; | 219 | int this_mid; |
255 | 220 | ||
256 | this_mid = get_cpu_mid(nd); | 221 | this_mid = get_cpu_mid(dp); |
257 | if (this_mid == desired_mid) | 222 | if (this_mid == desired_mid) |
258 | return 0; | 223 | return 0; |
259 | return -ENODEV; | 224 | return -ENODEV; |
260 | } | 225 | } |
261 | 226 | ||
262 | int cpu_find_by_mid(int mid, int *prom_node) | 227 | int cpu_find_by_mid(int mid, struct device_node **dev_node) |
263 | { | 228 | { |
264 | return __cpu_find_by(cpu_mid_compare, (void *)(long)mid, | 229 | return __cpu_find_by(cpu_mid_compare, (void *)(long)mid, |
265 | prom_node, NULL); | 230 | dev_node, NULL); |
266 | } | 231 | } |
267 | 232 | ||
268 | void __init device_scan(void) | 233 | void __init device_scan(void) |
@@ -274,50 +239,47 @@ void __init device_scan(void) | |||
274 | 239 | ||
275 | #ifndef CONFIG_SMP | 240 | #ifndef CONFIG_SMP |
276 | { | 241 | { |
277 | int err, cpu_node, def; | 242 | struct device_node *dp; |
243 | int err, def; | ||
278 | 244 | ||
279 | err = cpu_find_by_instance(0, &cpu_node, NULL); | 245 | err = cpu_find_by_instance(0, &dp, NULL); |
280 | if (err) { | 246 | if (err) { |
281 | prom_printf("No cpu nodes, cannot continue\n"); | 247 | prom_printf("No cpu nodes, cannot continue\n"); |
282 | prom_halt(); | 248 | prom_halt(); |
283 | } | 249 | } |
284 | cpu_data(0).clock_tick = prom_getintdefault(cpu_node, | 250 | cpu_data(0).clock_tick = |
285 | "clock-frequency", | 251 | of_getintprop_default(dp, "clock-frequency", 0); |
286 | 0); | ||
287 | 252 | ||
288 | def = ((tlb_type == hypervisor) ? | 253 | def = ((tlb_type == hypervisor) ? |
289 | (8 * 1024) : | 254 | (8 * 1024) : |
290 | (16 * 1024)); | 255 | (16 * 1024)); |
291 | cpu_data(0).dcache_size = prom_getintdefault(cpu_node, | 256 | cpu_data(0).dcache_size = of_getintprop_default(dp, |
292 | "dcache-size", | 257 | "dcache-size", |
293 | def); | 258 | def); |
294 | 259 | ||
295 | def = 32; | 260 | def = 32; |
296 | cpu_data(0).dcache_line_size = | 261 | cpu_data(0).dcache_line_size = |
297 | prom_getintdefault(cpu_node, "dcache-line-size", | 262 | of_getintprop_default(dp, "dcache-line-size", def); |
298 | def); | ||
299 | 263 | ||
300 | def = 16 * 1024; | 264 | def = 16 * 1024; |
301 | cpu_data(0).icache_size = prom_getintdefault(cpu_node, | 265 | cpu_data(0).icache_size = of_getintprop_default(dp, |
302 | "icache-size", | 266 | "icache-size", |
303 | def); | 267 | def); |
304 | 268 | ||
305 | def = 32; | 269 | def = 32; |
306 | cpu_data(0).icache_line_size = | 270 | cpu_data(0).icache_line_size = |
307 | prom_getintdefault(cpu_node, "icache-line-size", | 271 | of_getintprop_default(dp, "icache-line-size", def); |
308 | def); | ||
309 | 272 | ||
310 | def = ((tlb_type == hypervisor) ? | 273 | def = ((tlb_type == hypervisor) ? |
311 | (3 * 1024 * 1024) : | 274 | (3 * 1024 * 1024) : |
312 | (4 * 1024 * 1024)); | 275 | (4 * 1024 * 1024)); |
313 | cpu_data(0).ecache_size = prom_getintdefault(cpu_node, | 276 | cpu_data(0).ecache_size = of_getintprop_default(dp, |
314 | "ecache-size", | 277 | "ecache-size", |
315 | def); | 278 | def); |
316 | 279 | ||
317 | def = 64; | 280 | def = 64; |
318 | cpu_data(0).ecache_line_size = | 281 | cpu_data(0).ecache_line_size = |
319 | prom_getintdefault(cpu_node, "ecache-line-size", | 282 | of_getintprop_default(dp, "ecache-line-size", def); |
320 | def); | ||
321 | printk("CPU[0]: Caches " | 283 | printk("CPU[0]: Caches " |
322 | "D[sz(%d):line_sz(%d)] " | 284 | "D[sz(%d):line_sz(%d)] " |
323 | "I[sz(%d):line_sz(%d)] " | 285 | "I[sz(%d):line_sz(%d)] " |