aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc')
-rw-r--r--arch/sparc/kernel/of_device.c167
1 files changed, 109 insertions, 58 deletions
diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c
index bbd3203b86af..5a2faad5d043 100644
--- a/arch/sparc/kernel/of_device.c
+++ b/arch/sparc/kernel/of_device.c
@@ -183,7 +183,7 @@ struct bus_type of_bus_type = {
183}; 183};
184EXPORT_SYMBOL(of_bus_type); 184EXPORT_SYMBOL(of_bus_type);
185 185
186static inline u64 of_read_addr(u32 *cell, int size) 186static inline u64 of_read_addr(const u32 *cell, int size)
187{ 187{
188 u64 r = 0; 188 u64 r = 0;
189 while (size--) 189 while (size--)
@@ -209,8 +209,8 @@ struct of_bus {
209 int (*match)(struct device_node *parent); 209 int (*match)(struct device_node *parent);
210 void (*count_cells)(struct device_node *child, 210 void (*count_cells)(struct device_node *child,
211 int *addrc, int *sizec); 211 int *addrc, int *sizec);
212 u64 (*map)(u32 *addr, u32 *range, int na, int ns, int pna); 212 int (*map)(u32 *addr, const u32 *range,
213 int (*translate)(u32 *addr, u64 offset, int na); 213 int na, int ns, int pna);
214 unsigned int (*get_flags)(u32 *addr); 214 unsigned int (*get_flags)(u32 *addr);
215}; 215};
216 216
@@ -224,27 +224,49 @@ static void of_bus_default_count_cells(struct device_node *dev,
224 get_cells(dev, addrc, sizec); 224 get_cells(dev, addrc, sizec);
225} 225}
226 226
227static u64 of_bus_default_map(u32 *addr, u32 *range, int na, int ns, int pna) 227/* Make sure the least significant 64-bits are in-range. Even
228 * for 3 or 4 cell values it is a good enough approximation.
229 */
230static int of_out_of_range(const u32 *addr, const u32 *base,
231 const u32 *size, int na, int ns)
228{ 232{
229 u64 cp, s, da; 233 u64 a = of_read_addr(addr, na);
234 u64 b = of_read_addr(base, na);
235
236 if (a < b)
237 return 1;
230 238
231 cp = of_read_addr(range, na); 239 b += of_read_addr(size, ns);
232 s = of_read_addr(range + na + pna, ns); 240 if (a >= b)
233 da = of_read_addr(addr, na); 241 return 1;
234 242
235 if (da < cp || da >= (cp + s)) 243 return 0;
236 return OF_BAD_ADDR;
237 return da - cp;
238} 244}
239 245
240static int of_bus_default_translate(u32 *addr, u64 offset, int na) 246static int of_bus_default_map(u32 *addr, const u32 *range,
247 int na, int ns, int pna)
241{ 248{
242 u64 a = of_read_addr(addr, na); 249 u32 result[OF_MAX_ADDR_CELLS];
243 memset(addr, 0, na * 4); 250 int i;
244 a += offset; 251
245 if (na > 1) 252 if (ns > 2) {
246 addr[na - 2] = a >> 32; 253 printk("of_device: Cannot handle size cells (%d) > 2.", ns);
247 addr[na - 1] = a & 0xffffffffu; 254 return -EINVAL;
255 }
256
257 if (of_out_of_range(addr, range, range + na + pna, na, ns))
258 return -EINVAL;
259
260 /* Start with the parent range base. */
261 memcpy(result, range + na, pna * 4);
262
263 /* Add in the child address offset. */
264 for (i = 0; i < na; i++)
265 result[pna - 1 - i] +=
266 (addr[na - 1 - i] -
267 range[na - 1 - i]);
268
269 memcpy(addr, result, pna * 4);
248 270
249 return 0; 271 return 0;
250} 272}
@@ -254,14 +276,26 @@ static unsigned int of_bus_default_get_flags(u32 *addr)
254 return IORESOURCE_MEM; 276 return IORESOURCE_MEM;
255} 277}
256 278
257
258/* 279/*
259 * PCI bus specific translator 280 * PCI bus specific translator
260 */ 281 */
261 282
262static int of_bus_pci_match(struct device_node *np) 283static int of_bus_pci_match(struct device_node *np)
263{ 284{
264 return !strcmp(np->type, "pci") || !strcmp(np->type, "pciex"); 285 if (!strcmp(np->type, "pci") || !strcmp(np->type, "pciex")) {
286 /* Do not do PCI specific frobbing if the
287 * PCI bridge lacks a ranges property. We
288 * want to pass it through up to the next
289 * parent as-is, not with the PCI translate
290 * method which chops off the top address cell.
291 */
292 if (!of_find_property(np, "ranges", NULL))
293 return 0;
294
295 return 1;
296 }
297
298 return 0;
265} 299}
266 300
267static void of_bus_pci_count_cells(struct device_node *np, 301static void of_bus_pci_count_cells(struct device_node *np,
@@ -273,27 +307,32 @@ static void of_bus_pci_count_cells(struct device_node *np,
273 *sizec = 2; 307 *sizec = 2;
274} 308}
275 309
276static u64 of_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna) 310static int of_bus_pci_map(u32 *addr, const u32 *range,
311 int na, int ns, int pna)
277{ 312{
278 u64 cp, s, da; 313 u32 result[OF_MAX_ADDR_CELLS];
314 int i;
279 315
280 /* Check address type match */ 316 /* Check address type match */
281 if ((addr[0] ^ range[0]) & 0x03000000) 317 if ((addr[0] ^ range[0]) & 0x03000000)
282 return OF_BAD_ADDR; 318 return -EINVAL;
283 319
284 /* Read address values, skipping high cell */ 320 if (of_out_of_range(addr + 1, range + 1, range + na + pna,
285 cp = of_read_addr(range + 1, na - 1); 321 na - 1, ns))
286 s = of_read_addr(range + na + pna, ns); 322 return -EINVAL;
287 da = of_read_addr(addr + 1, na - 1);
288 323
289 if (da < cp || da >= (cp + s)) 324 /* Start with the parent range base. */
290 return OF_BAD_ADDR; 325 memcpy(result, range + na, pna * 4);
291 return da - cp;
292}
293 326
294static int of_bus_pci_translate(u32 *addr, u64 offset, int na) 327 /* Add in the child address offset, skipping high cell. */
295{ 328 for (i = 0; i < na - 1; i++)
296 return of_bus_default_translate(addr + 1, offset, na - 1); 329 result[pna - 1 - i] +=
330 (addr[na - 1 - i] -
331 range[na - 1 - i]);
332
333 memcpy(addr, result, pna * 4);
334
335 return 0;
297} 336}
298 337
299static unsigned int of_bus_pci_get_flags(u32 *addr) 338static unsigned int of_bus_pci_get_flags(u32 *addr)
@@ -332,16 +371,11 @@ static void of_bus_sbus_count_cells(struct device_node *child,
332 *sizec = 1; 371 *sizec = 1;
333} 372}
334 373
335static u64 of_bus_sbus_map(u32 *addr, u32 *range, int na, int ns, int pna) 374static int of_bus_sbus_map(u32 *addr, const u32 *range, int na, int ns, int pna)
336{ 375{
337 return of_bus_default_map(addr, range, na, ns, pna); 376 return of_bus_default_map(addr, range, na, ns, pna);
338} 377}
339 378
340static int of_bus_sbus_translate(u32 *addr, u64 offset, int na)
341{
342 return of_bus_default_translate(addr, offset, na);
343}
344
345static unsigned int of_bus_sbus_get_flags(u32 *addr) 379static unsigned int of_bus_sbus_get_flags(u32 *addr)
346{ 380{
347 return IORESOURCE_MEM; 381 return IORESOURCE_MEM;
@@ -360,7 +394,6 @@ static struct of_bus of_busses[] = {
360 .match = of_bus_pci_match, 394 .match = of_bus_pci_match,
361 .count_cells = of_bus_pci_count_cells, 395 .count_cells = of_bus_pci_count_cells,
362 .map = of_bus_pci_map, 396 .map = of_bus_pci_map,
363 .translate = of_bus_pci_translate,
364 .get_flags = of_bus_pci_get_flags, 397 .get_flags = of_bus_pci_get_flags,
365 }, 398 },
366 /* SBUS */ 399 /* SBUS */
@@ -370,7 +403,6 @@ static struct of_bus of_busses[] = {
370 .match = of_bus_sbus_match, 403 .match = of_bus_sbus_match,
371 .count_cells = of_bus_sbus_count_cells, 404 .count_cells = of_bus_sbus_count_cells,
372 .map = of_bus_sbus_map, 405 .map = of_bus_sbus_map,
373 .translate = of_bus_sbus_translate,
374 .get_flags = of_bus_sbus_get_flags, 406 .get_flags = of_bus_sbus_get_flags,
375 }, 407 },
376 /* Default */ 408 /* Default */
@@ -380,7 +412,6 @@ static struct of_bus of_busses[] = {
380 .match = NULL, 412 .match = NULL,
381 .count_cells = of_bus_default_count_cells, 413 .count_cells = of_bus_default_count_cells,
382 .map = of_bus_default_map, 414 .map = of_bus_default_map,
383 .translate = of_bus_default_translate,
384 .get_flags = of_bus_default_get_flags, 415 .get_flags = of_bus_default_get_flags,
385 }, 416 },
386}; 417};
@@ -405,33 +436,34 @@ static int __init build_one_resource(struct device_node *parent,
405 u32 *ranges; 436 u32 *ranges;
406 unsigned int rlen; 437 unsigned int rlen;
407 int rone; 438 int rone;
408 u64 offset = OF_BAD_ADDR;
409 439
410 ranges = of_get_property(parent, "ranges", &rlen); 440 ranges = of_get_property(parent, "ranges", &rlen);
411 if (ranges == NULL || rlen == 0) { 441 if (ranges == NULL || rlen == 0) {
412 offset = of_read_addr(addr, na); 442 u32 result[OF_MAX_ADDR_CELLS];
413 memset(addr, 0, pna * 4); 443 int i;
414 goto finish; 444
445 memset(result, 0, pna * 4);
446 for (i = 0; i < na; i++)
447 result[pna - 1 - i] =
448 addr[na - 1 - i];
449
450 memcpy(addr, result, pna * 4);
451 return 0;
415 } 452 }
416 453
417 /* Now walk through the ranges */ 454 /* Now walk through the ranges */
418 rlen /= 4; 455 rlen /= 4;
419 rone = na + pna + ns; 456 rone = na + pna + ns;
420 for (; rlen >= rone; rlen -= rone, ranges += rone) { 457 for (; rlen >= rone; rlen -= rone, ranges += rone) {
421 offset = bus->map(addr, ranges, na, ns, pna); 458 if (!bus->map(addr, ranges, na, ns, pna))
422 if (offset != OF_BAD_ADDR) 459 return 0;
423 break;
424 } 460 }
425 if (offset == OF_BAD_ADDR)
426 return 1;
427
428 memcpy(addr, ranges + na, 4 * pna);
429 461
430finish: 462 return 1;
431 /* Translate it into parent bus space */
432 return pbus->translate(addr, offset, pna);
433} 463}
434 464
465static int of_resource_verbose;
466
435static void __init build_device_resources(struct of_device *op, 467static void __init build_device_resources(struct of_device *op,
436 struct device *parent) 468 struct device *parent)
437{ 469{
@@ -497,7 +529,8 @@ static void __init build_device_resources(struct of_device *op,
497 pbus = of_match_bus(pp); 529 pbus = of_match_bus(pp);
498 pbus->count_cells(dp, &pna, &pns); 530 pbus->count_cells(dp, &pna, &pns);
499 531
500 if (build_one_resource(dp, bus, pbus, addr, dna, dns, pna)) 532 if (build_one_resource(dp, bus, pbus, addr,
533 dna, dns, pna))
501 break; 534 break;
502 535
503 dna = pna; 536 dna = pna;
@@ -507,6 +540,12 @@ static void __init build_device_resources(struct of_device *op,
507 540
508 build_res: 541 build_res:
509 memset(r, 0, sizeof(*r)); 542 memset(r, 0, sizeof(*r));
543
544 if (of_resource_verbose)
545 printk("%s reg[%d] -> %llx\n",
546 op->node->full_name, index,
547 result);
548
510 if (result != OF_BAD_ADDR) { 549 if (result != OF_BAD_ADDR) {
511 r->start = result & 0xffffffff; 550 r->start = result & 0xffffffff;
512 r->end = result + size - 1; 551 r->end = result + size - 1;
@@ -643,6 +682,18 @@ static int __init of_bus_driver_init(void)
643 682
644postcore_initcall(of_bus_driver_init); 683postcore_initcall(of_bus_driver_init);
645 684
685static int __init of_debug(char *str)
686{
687 int val = 0;
688
689 get_option(&str, &val);
690 if (val & 1)
691 of_resource_verbose = 1;
692 return 1;
693}
694
695__setup("of_debug=", of_debug);
696
646int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus) 697int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus)
647{ 698{
648 /* initialize common driver fields */ 699 /* initialize common driver fields */