diff options
Diffstat (limited to 'arch/sparc64/kernel/of_device.c')
| -rw-r--r-- | arch/sparc64/kernel/of_device.c | 692 |
1 files changed, 690 insertions, 2 deletions
diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c index 768475bbce82..169b017eec0b 100644 --- a/arch/sparc64/kernel/of_device.c +++ b/arch/sparc64/kernel/of_device.c | |||
| @@ -129,6 +129,43 @@ static int of_device_resume(struct device * dev) | |||
| 129 | return error; | 129 | return error; |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name) | ||
| 133 | { | ||
| 134 | unsigned long ret = res->start + offset; | ||
| 135 | |||
| 136 | if (!request_region(ret, size, name)) | ||
| 137 | ret = 0; | ||
| 138 | |||
| 139 | return (void __iomem *) ret; | ||
| 140 | } | ||
| 141 | EXPORT_SYMBOL(of_ioremap); | ||
| 142 | |||
| 143 | void of_iounmap(void __iomem *base, unsigned long size) | ||
| 144 | { | ||
| 145 | release_region((unsigned long) base, size); | ||
| 146 | } | ||
| 147 | EXPORT_SYMBOL(of_iounmap); | ||
| 148 | |||
| 149 | static int node_match(struct device *dev, void *data) | ||
| 150 | { | ||
| 151 | struct of_device *op = to_of_device(dev); | ||
| 152 | struct device_node *dp = data; | ||
| 153 | |||
| 154 | return (op->node == dp); | ||
| 155 | } | ||
| 156 | |||
| 157 | struct of_device *of_find_device_by_node(struct device_node *dp) | ||
| 158 | { | ||
| 159 | struct device *dev = bus_find_device(&of_bus_type, NULL, | ||
| 160 | dp, node_match); | ||
| 161 | |||
| 162 | if (dev) | ||
| 163 | return to_of_device(dev); | ||
| 164 | |||
| 165 | return NULL; | ||
| 166 | } | ||
| 167 | EXPORT_SYMBOL(of_find_device_by_node); | ||
| 168 | |||
| 132 | #ifdef CONFIG_PCI | 169 | #ifdef CONFIG_PCI |
| 133 | struct bus_type isa_bus_type = { | 170 | struct bus_type isa_bus_type = { |
| 134 | .name = "isa", | 171 | .name = "isa", |
| @@ -163,10 +200,657 @@ struct bus_type sbus_bus_type = { | |||
| 163 | EXPORT_SYMBOL(sbus_bus_type); | 200 | EXPORT_SYMBOL(sbus_bus_type); |
| 164 | #endif | 201 | #endif |
| 165 | 202 | ||
| 203 | struct bus_type of_bus_type = { | ||
| 204 | .name = "of", | ||
| 205 | .match = of_platform_bus_match, | ||
| 206 | .probe = of_device_probe, | ||
| 207 | .remove = of_device_remove, | ||
| 208 | .suspend = of_device_suspend, | ||
| 209 | .resume = of_device_resume, | ||
| 210 | }; | ||
| 211 | EXPORT_SYMBOL(of_bus_type); | ||
| 212 | |||
| 213 | static inline u64 of_read_addr(u32 *cell, int size) | ||
| 214 | { | ||
| 215 | u64 r = 0; | ||
| 216 | while (size--) | ||
| 217 | r = (r << 32) | *(cell++); | ||
| 218 | return r; | ||
| 219 | } | ||
| 220 | |||
| 221 | static void __init get_cells(struct device_node *dp, | ||
| 222 | int *addrc, int *sizec) | ||
| 223 | { | ||
| 224 | if (addrc) | ||
| 225 | *addrc = of_n_addr_cells(dp); | ||
| 226 | if (sizec) | ||
| 227 | *sizec = of_n_size_cells(dp); | ||
| 228 | } | ||
| 229 | |||
| 230 | /* Max address size we deal with */ | ||
| 231 | #define OF_MAX_ADDR_CELLS 4 | ||
| 232 | |||
| 233 | struct of_bus { | ||
| 234 | const char *name; | ||
| 235 | const char *addr_prop_name; | ||
| 236 | int (*match)(struct device_node *parent); | ||
| 237 | void (*count_cells)(struct device_node *child, | ||
| 238 | int *addrc, int *sizec); | ||
| 239 | u64 (*map)(u32 *addr, u32 *range, int na, int ns, int pna); | ||
| 240 | int (*translate)(u32 *addr, u64 offset, int na); | ||
| 241 | unsigned int (*get_flags)(u32 *addr); | ||
| 242 | }; | ||
| 243 | |||
| 244 | /* | ||
| 245 | * Default translator (generic bus) | ||
| 246 | */ | ||
| 247 | |||
| 248 | static void of_bus_default_count_cells(struct device_node *dev, | ||
| 249 | int *addrc, int *sizec) | ||
| 250 | { | ||
| 251 | get_cells(dev, addrc, sizec); | ||
| 252 | } | ||
| 253 | |||
| 254 | static u64 of_bus_default_map(u32 *addr, u32 *range, int na, int ns, int pna) | ||
| 255 | { | ||
| 256 | u64 cp, s, da; | ||
| 257 | |||
| 258 | cp = of_read_addr(range, na); | ||
| 259 | s = of_read_addr(range + na + pna, ns); | ||
| 260 | da = of_read_addr(addr, na); | ||
| 261 | |||
| 262 | if (da < cp || da >= (cp + s)) | ||
| 263 | return OF_BAD_ADDR; | ||
| 264 | return da - cp; | ||
| 265 | } | ||
| 266 | |||
| 267 | static int of_bus_default_translate(u32 *addr, u64 offset, int na) | ||
| 268 | { | ||
| 269 | u64 a = of_read_addr(addr, na); | ||
| 270 | memset(addr, 0, na * 4); | ||
| 271 | a += offset; | ||
| 272 | if (na > 1) | ||
| 273 | addr[na - 2] = a >> 32; | ||
| 274 | addr[na - 1] = a & 0xffffffffu; | ||
| 275 | |||
| 276 | return 0; | ||
| 277 | } | ||
| 278 | |||
| 279 | static unsigned int of_bus_default_get_flags(u32 *addr) | ||
| 280 | { | ||
| 281 | return IORESOURCE_MEM; | ||
| 282 | } | ||
| 283 | |||
| 284 | /* | ||
| 285 | * PCI bus specific translator | ||
| 286 | */ | ||
| 287 | |||
| 288 | static int of_bus_pci_match(struct device_node *np) | ||
| 289 | { | ||
| 290 | return !strcmp(np->type, "pci") || !strcmp(np->type, "pciex"); | ||
| 291 | } | ||
| 292 | |||
| 293 | static void of_bus_pci_count_cells(struct device_node *np, | ||
| 294 | int *addrc, int *sizec) | ||
| 295 | { | ||
| 296 | if (addrc) | ||
| 297 | *addrc = 3; | ||
| 298 | if (sizec) | ||
| 299 | *sizec = 2; | ||
| 300 | } | ||
| 301 | |||
| 302 | static u64 of_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna) | ||
| 303 | { | ||
| 304 | u64 cp, s, da; | ||
| 305 | |||
| 306 | /* Check address type match */ | ||
| 307 | if ((addr[0] ^ range[0]) & 0x03000000) | ||
| 308 | return OF_BAD_ADDR; | ||
| 309 | |||
| 310 | /* Read address values, skipping high cell */ | ||
| 311 | cp = of_read_addr(range + 1, na - 1); | ||
| 312 | s = of_read_addr(range + na + pna, ns); | ||
| 313 | da = of_read_addr(addr + 1, na - 1); | ||
| 314 | |||
| 315 | if (da < cp || da >= (cp + s)) | ||
| 316 | return OF_BAD_ADDR; | ||
| 317 | return da - cp; | ||
| 318 | } | ||
| 319 | |||
| 320 | static int of_bus_pci_translate(u32 *addr, u64 offset, int na) | ||
| 321 | { | ||
| 322 | return of_bus_default_translate(addr + 1, offset, na - 1); | ||
| 323 | } | ||
| 324 | |||
| 325 | static unsigned int of_bus_pci_get_flags(u32 *addr) | ||
| 326 | { | ||
| 327 | unsigned int flags = 0; | ||
| 328 | u32 w = addr[0]; | ||
| 329 | |||
| 330 | switch((w >> 24) & 0x03) { | ||
| 331 | case 0x01: | ||
| 332 | flags |= IORESOURCE_IO; | ||
| 333 | case 0x02: /* 32 bits */ | ||
| 334 | case 0x03: /* 64 bits */ | ||
| 335 | flags |= IORESOURCE_MEM; | ||
| 336 | } | ||
| 337 | if (w & 0x40000000) | ||
| 338 | flags |= IORESOURCE_PREFETCH; | ||
| 339 | return flags; | ||
| 340 | } | ||
| 341 | |||
| 342 | /* | ||
| 343 | * ISA bus specific translator | ||
| 344 | */ | ||
| 345 | |||
| 346 | static int of_bus_isa_match(struct device_node *np) | ||
| 347 | { | ||
| 348 | return !strcmp(np->name, "isa"); | ||
| 349 | } | ||
| 350 | |||
| 351 | static void of_bus_isa_count_cells(struct device_node *child, | ||
| 352 | int *addrc, int *sizec) | ||
| 353 | { | ||
| 354 | if (addrc) | ||
| 355 | *addrc = 2; | ||
| 356 | if (sizec) | ||
| 357 | *sizec = 1; | ||
| 358 | } | ||
| 359 | |||
| 360 | static u64 of_bus_isa_map(u32 *addr, u32 *range, int na, int ns, int pna) | ||
| 361 | { | ||
| 362 | u64 cp, s, da; | ||
| 363 | |||
| 364 | /* Check address type match */ | ||
| 365 | if ((addr[0] ^ range[0]) & 0x00000001) | ||
| 366 | return OF_BAD_ADDR; | ||
| 367 | |||
| 368 | /* Read address values, skipping high cell */ | ||
| 369 | cp = of_read_addr(range + 1, na - 1); | ||
| 370 | s = of_read_addr(range + na + pna, ns); | ||
| 371 | da = of_read_addr(addr + 1, na - 1); | ||
| 372 | |||
| 373 | if (da < cp || da >= (cp + s)) | ||
| 374 | return OF_BAD_ADDR; | ||
| 375 | return da - cp; | ||
| 376 | } | ||
| 377 | |||
| 378 | static int of_bus_isa_translate(u32 *addr, u64 offset, int na) | ||
| 379 | { | ||
| 380 | return of_bus_default_translate(addr + 1, offset, na - 1); | ||
| 381 | } | ||
| 382 | |||
| 383 | static unsigned int of_bus_isa_get_flags(u32 *addr) | ||
| 384 | { | ||
| 385 | unsigned int flags = 0; | ||
| 386 | u32 w = addr[0]; | ||
| 387 | |||
| 388 | if (w & 1) | ||
| 389 | flags |= IORESOURCE_IO; | ||
| 390 | else | ||
| 391 | flags |= IORESOURCE_MEM; | ||
| 392 | return flags; | ||
| 393 | } | ||
| 394 | |||
| 395 | /* | ||
| 396 | * SBUS bus specific translator | ||
| 397 | */ | ||
| 398 | |||
| 399 | static int of_bus_sbus_match(struct device_node *np) | ||
| 400 | { | ||
| 401 | return !strcmp(np->name, "sbus") || | ||
| 402 | !strcmp(np->name, "sbi"); | ||
| 403 | } | ||
| 404 | |||
| 405 | static void of_bus_sbus_count_cells(struct device_node *child, | ||
| 406 | int *addrc, int *sizec) | ||
| 407 | { | ||
| 408 | if (addrc) | ||
| 409 | *addrc = 2; | ||
| 410 | if (sizec) | ||
| 411 | *sizec = 1; | ||
| 412 | } | ||
| 413 | |||
| 414 | static u64 of_bus_sbus_map(u32 *addr, u32 *range, int na, int ns, int pna) | ||
| 415 | { | ||
| 416 | return of_bus_default_map(addr, range, na, ns, pna); | ||
| 417 | } | ||
| 418 | |||
| 419 | static int of_bus_sbus_translate(u32 *addr, u64 offset, int na) | ||
| 420 | { | ||
| 421 | return of_bus_default_translate(addr, offset, na); | ||
| 422 | } | ||
| 423 | |||
| 424 | static unsigned int of_bus_sbus_get_flags(u32 *addr) | ||
| 425 | { | ||
| 426 | return IORESOURCE_MEM; | ||
| 427 | } | ||
| 428 | |||
| 429 | |||
| 430 | /* | ||
| 431 | * Array of bus specific translators | ||
| 432 | */ | ||
| 433 | |||
| 434 | static struct of_bus of_busses[] = { | ||
| 435 | /* PCI */ | ||
| 436 | { | ||
| 437 | .name = "pci", | ||
| 438 | .addr_prop_name = "assigned-addresses", | ||
| 439 | .match = of_bus_pci_match, | ||
| 440 | .count_cells = of_bus_pci_count_cells, | ||
| 441 | .map = of_bus_pci_map, | ||
| 442 | .translate = of_bus_pci_translate, | ||
| 443 | .get_flags = of_bus_pci_get_flags, | ||
| 444 | }, | ||
| 445 | /* ISA */ | ||
| 446 | { | ||
| 447 | .name = "isa", | ||
| 448 | .addr_prop_name = "reg", | ||
| 449 | .match = of_bus_isa_match, | ||
| 450 | .count_cells = of_bus_isa_count_cells, | ||
| 451 | .map = of_bus_isa_map, | ||
| 452 | .translate = of_bus_isa_translate, | ||
| 453 | .get_flags = of_bus_isa_get_flags, | ||
| 454 | }, | ||
| 455 | /* SBUS */ | ||
| 456 | { | ||
| 457 | .name = "sbus", | ||
| 458 | .addr_prop_name = "reg", | ||
| 459 | .match = of_bus_sbus_match, | ||
| 460 | .count_cells = of_bus_sbus_count_cells, | ||
| 461 | .map = of_bus_sbus_map, | ||
| 462 | .translate = of_bus_sbus_translate, | ||
| 463 | .get_flags = of_bus_sbus_get_flags, | ||
| 464 | }, | ||
| 465 | /* Default */ | ||
| 466 | { | ||
| 467 | .name = "default", | ||
| 468 | .addr_prop_name = "reg", | ||
| 469 | .match = NULL, | ||
| 470 | .count_cells = of_bus_default_count_cells, | ||
| 471 | .map = of_bus_default_map, | ||
| 472 | .translate = of_bus_default_translate, | ||
| 473 | .get_flags = of_bus_default_get_flags, | ||
| 474 | }, | ||
| 475 | }; | ||
| 476 | |||
| 477 | static struct of_bus *of_match_bus(struct device_node *np) | ||
| 478 | { | ||
| 479 | int i; | ||
| 480 | |||
| 481 | for (i = 0; i < ARRAY_SIZE(of_busses); i ++) | ||
| 482 | if (!of_busses[i].match || of_busses[i].match(np)) | ||
| 483 | return &of_busses[i]; | ||
| 484 | BUG(); | ||
| 485 | return NULL; | ||
| 486 | } | ||
| 487 | |||
| 488 | static int __init build_one_resource(struct device_node *parent, | ||
| 489 | struct of_bus *bus, | ||
| 490 | struct of_bus *pbus, | ||
| 491 | u32 *addr, | ||
| 492 | int na, int ns, int pna) | ||
| 493 | { | ||
| 494 | u32 *ranges; | ||
| 495 | unsigned int rlen; | ||
| 496 | int rone; | ||
| 497 | u64 offset = OF_BAD_ADDR; | ||
| 498 | |||
| 499 | ranges = of_get_property(parent, "ranges", &rlen); | ||
| 500 | if (ranges == NULL || rlen == 0) { | ||
| 501 | offset = of_read_addr(addr, na); | ||
| 502 | memset(addr, 0, pna * 4); | ||
| 503 | goto finish; | ||
| 504 | } | ||
| 505 | |||
| 506 | /* Now walk through the ranges */ | ||
| 507 | rlen /= 4; | ||
| 508 | rone = na + pna + ns; | ||
| 509 | for (; rlen >= rone; rlen -= rone, ranges += rone) { | ||
| 510 | offset = bus->map(addr, ranges, na, ns, pna); | ||
| 511 | if (offset != OF_BAD_ADDR) | ||
| 512 | break; | ||
| 513 | } | ||
| 514 | if (offset == OF_BAD_ADDR) | ||
| 515 | return 1; | ||
| 516 | |||
| 517 | memcpy(addr, ranges + na, 4 * pna); | ||
| 518 | |||
| 519 | finish: | ||
| 520 | /* Translate it into parent bus space */ | ||
| 521 | return pbus->translate(addr, offset, pna); | ||
| 522 | } | ||
| 523 | |||
| 524 | static void __init build_device_resources(struct of_device *op, | ||
| 525 | struct device *parent) | ||
| 526 | { | ||
| 527 | struct of_device *p_op; | ||
| 528 | struct of_bus *bus; | ||
| 529 | int na, ns; | ||
| 530 | int index, num_reg; | ||
| 531 | void *preg; | ||
| 532 | |||
| 533 | if (!parent) | ||
| 534 | return; | ||
| 535 | |||
| 536 | p_op = to_of_device(parent); | ||
| 537 | bus = of_match_bus(p_op->node); | ||
| 538 | bus->count_cells(op->node, &na, &ns); | ||
| 539 | |||
| 540 | preg = of_get_property(op->node, bus->addr_prop_name, &num_reg); | ||
| 541 | if (!preg || num_reg == 0) | ||
| 542 | return; | ||
| 543 | |||
| 544 | /* Convert to num-cells. */ | ||
| 545 | num_reg /= 4; | ||
| 546 | |||
| 547 | /* Conver to num-entries. */ | ||
| 548 | num_reg /= na + ns; | ||
| 549 | |||
| 550 | for (index = 0; index < num_reg; index++) { | ||
| 551 | struct resource *r = &op->resource[index]; | ||
| 552 | u32 addr[OF_MAX_ADDR_CELLS]; | ||
| 553 | u32 *reg = (preg + (index * ((na + ns) * 4))); | ||
| 554 | struct device_node *dp = op->node; | ||
| 555 | struct device_node *pp = p_op->node; | ||
| 556 | struct of_bus *pbus; | ||
| 557 | u64 size, result = OF_BAD_ADDR; | ||
| 558 | unsigned long flags; | ||
| 559 | int dna, dns; | ||
| 560 | int pna, pns; | ||
| 561 | |||
| 562 | size = of_read_addr(reg + na, ns); | ||
| 563 | flags = bus->get_flags(reg); | ||
| 564 | |||
| 565 | memcpy(addr, reg, na * 4); | ||
| 566 | |||
| 567 | /* If the immediate parent has no ranges property to apply, | ||
| 568 | * just use a 1<->1 mapping. Unless it is the 'dma' child | ||
| 569 | * of an isa bus, which must be passed up towards the root. | ||
| 570 | * | ||
| 571 | * Also, don't try to translate PMU bus device registers. | ||
| 572 | */ | ||
| 573 | if ((of_find_property(pp, "ranges", NULL) == NULL && | ||
| 574 | strcmp(pp->name, "dma") != 0) || | ||
| 575 | !strcmp(pp->name, "pmu")) { | ||
| 576 | result = of_read_addr(addr, na); | ||
| 577 | goto build_res; | ||
| 578 | } | ||
| 579 | |||
| 580 | dna = na; | ||
| 581 | dns = ns; | ||
| 582 | |||
| 583 | while (1) { | ||
| 584 | dp = pp; | ||
| 585 | pp = dp->parent; | ||
| 586 | if (!pp) { | ||
| 587 | result = of_read_addr(addr, dna); | ||
| 588 | break; | ||
| 589 | } | ||
| 590 | |||
| 591 | pbus = of_match_bus(pp); | ||
| 592 | pbus->count_cells(dp, &pna, &pns); | ||
| 593 | |||
| 594 | if (build_one_resource(dp, bus, pbus, addr, dna, dns, pna)) | ||
| 595 | break; | ||
| 596 | |||
| 597 | dna = pna; | ||
| 598 | dns = pns; | ||
| 599 | bus = pbus; | ||
| 600 | } | ||
| 601 | |||
| 602 | build_res: | ||
| 603 | memset(r, 0, sizeof(*r)); | ||
| 604 | if (result != OF_BAD_ADDR) { | ||
| 605 | if (tlb_type == hypervisor) | ||
| 606 | result &= 0x0fffffffffffffffUL; | ||
| 607 | |||
| 608 | r->start = result; | ||
| 609 | r->end = result + size - 1; | ||
| 610 | r->flags = flags; | ||
| 611 | } else { | ||
| 612 | r->start = ~0UL; | ||
| 613 | r->end = ~0UL; | ||
| 614 | } | ||
| 615 | r->name = op->node->name; | ||
| 616 | } | ||
| 617 | } | ||
| 618 | |||
| 619 | static struct device_node * __init | ||
| 620 | apply_interrupt_map(struct device_node *dp, struct device_node *pp, | ||
| 621 | u32 *imap, int imlen, u32 *imask, | ||
| 622 | unsigned int *irq_p) | ||
| 623 | { | ||
| 624 | struct device_node *cp; | ||
| 625 | unsigned int irq = *irq_p; | ||
| 626 | struct of_bus *bus; | ||
| 627 | phandle handle; | ||
| 628 | u32 *reg; | ||
| 629 | int na, num_reg, i; | ||
| 630 | |||
| 631 | bus = of_match_bus(pp); | ||
| 632 | bus->count_cells(dp, &na, NULL); | ||
| 633 | |||
| 634 | reg = of_get_property(dp, "reg", &num_reg); | ||
| 635 | if (!reg || !num_reg) | ||
| 636 | return NULL; | ||
| 637 | |||
| 638 | imlen /= ((na + 3) * 4); | ||
| 639 | handle = 0; | ||
| 640 | for (i = 0; i < imlen; i++) { | ||
| 641 | int j; | ||
| 642 | |||
| 643 | for (j = 0; j < na; j++) { | ||
| 644 | if ((reg[j] & imask[j]) != imap[j]) | ||
| 645 | goto next; | ||
| 646 | } | ||
| 647 | if (imap[na] == irq) { | ||
| 648 | handle = imap[na + 1]; | ||
| 649 | irq = imap[na + 2]; | ||
| 650 | break; | ||
| 651 | } | ||
| 652 | |||
| 653 | next: | ||
| 654 | imap += (na + 3); | ||
| 655 | } | ||
| 656 | if (i == imlen) | ||
| 657 | return NULL; | ||
| 658 | |||
| 659 | *irq_p = irq; | ||
| 660 | cp = of_find_node_by_phandle(handle); | ||
| 661 | |||
| 662 | return cp; | ||
| 663 | } | ||
| 664 | |||
| 665 | static unsigned int __init pci_irq_swizzle(struct device_node *dp, | ||
| 666 | struct device_node *pp, | ||
| 667 | unsigned int irq) | ||
| 668 | { | ||
| 669 | struct linux_prom_pci_registers *regs; | ||
| 670 | unsigned int devfn, slot, ret; | ||
| 671 | |||
| 672 | if (irq < 1 || irq > 4) | ||
| 673 | return irq; | ||
| 674 | |||
| 675 | regs = of_get_property(dp, "reg", NULL); | ||
| 676 | if (!regs) | ||
| 677 | return irq; | ||
| 678 | |||
| 679 | devfn = (regs->phys_hi >> 8) & 0xff; | ||
| 680 | slot = (devfn >> 3) & 0x1f; | ||
| 681 | |||
| 682 | ret = ((irq - 1 + (slot & 3)) & 3) + 1; | ||
| 683 | |||
| 684 | return ret; | ||
| 685 | } | ||
| 686 | |||
| 687 | static unsigned int __init build_one_device_irq(struct of_device *op, | ||
| 688 | struct device *parent, | ||
| 689 | unsigned int irq) | ||
| 690 | { | ||
| 691 | struct device_node *dp = op->node; | ||
| 692 | struct device_node *pp, *ip; | ||
| 693 | unsigned int orig_irq = irq; | ||
| 694 | |||
| 695 | if (irq == 0xffffffff) | ||
| 696 | return irq; | ||
| 697 | |||
| 698 | if (dp->irq_trans) { | ||
| 699 | irq = dp->irq_trans->irq_build(dp, irq, | ||
| 700 | dp->irq_trans->data); | ||
| 701 | #if 1 | ||
| 702 | printk("%s: direct translate %x --> %x\n", | ||
| 703 | dp->full_name, orig_irq, irq); | ||
| 704 | #endif | ||
| 705 | return irq; | ||
| 706 | } | ||
| 707 | |||
| 708 | /* Something more complicated. Walk up to the root, applying | ||
| 709 | * interrupt-map or bus specific translations, until we hit | ||
| 710 | * an IRQ translator. | ||
| 711 | * | ||
| 712 | * If we hit a bus type or situation we cannot handle, we | ||
| 713 | * stop and assume that the original IRQ number was in a | ||
| 714 | * format which has special meaning to it's immediate parent. | ||
| 715 | */ | ||
| 716 | pp = dp->parent; | ||
| 717 | ip = NULL; | ||
| 718 | while (pp) { | ||
| 719 | void *imap, *imsk; | ||
| 720 | int imlen; | ||
| 721 | |||
| 722 | imap = of_get_property(pp, "interrupt-map", &imlen); | ||
| 723 | imsk = of_get_property(pp, "interrupt-map-mask", NULL); | ||
| 724 | if (imap && imsk) { | ||
| 725 | struct device_node *iret; | ||
| 726 | int this_orig_irq = irq; | ||
| 727 | |||
| 728 | iret = apply_interrupt_map(dp, pp, | ||
| 729 | imap, imlen, imsk, | ||
| 730 | &irq); | ||
| 731 | #if 1 | ||
| 732 | printk("%s: Apply [%s:%x] imap --> [%s:%x]\n", | ||
| 733 | op->node->full_name, | ||
| 734 | pp->full_name, this_orig_irq, | ||
| 735 | (iret ? iret->full_name : "NULL"), irq); | ||
| 736 | #endif | ||
| 737 | if (!iret) | ||
| 738 | break; | ||
| 739 | |||
| 740 | if (iret->irq_trans) { | ||
| 741 | ip = iret; | ||
| 742 | break; | ||
| 743 | } | ||
| 744 | } else { | ||
| 745 | if (!strcmp(pp->type, "pci") || | ||
| 746 | !strcmp(pp->type, "pciex")) { | ||
| 747 | unsigned int this_orig_irq = irq; | ||
| 748 | |||
| 749 | irq = pci_irq_swizzle(dp, pp, irq); | ||
| 750 | #if 1 | ||
| 751 | printk("%s: PCI swizzle [%s] %x --> %x\n", | ||
| 752 | op->node->full_name, | ||
| 753 | pp->full_name, this_orig_irq, irq); | ||
| 754 | #endif | ||
| 755 | } | ||
| 756 | |||
| 757 | if (pp->irq_trans) { | ||
| 758 | ip = pp; | ||
| 759 | break; | ||
| 760 | } | ||
| 761 | } | ||
| 762 | dp = pp; | ||
| 763 | pp = pp->parent; | ||
| 764 | } | ||
| 765 | if (!ip) | ||
| 766 | return orig_irq; | ||
| 767 | |||
| 768 | irq = ip->irq_trans->irq_build(op->node, irq, | ||
| 769 | ip->irq_trans->data); | ||
| 770 | #if 1 | ||
| 771 | printk("%s: Apply IRQ trans [%s] %x --> %x\n", | ||
| 772 | op->node->full_name, ip->full_name, orig_irq, irq); | ||
| 773 | #endif | ||
| 774 | |||
| 775 | return irq; | ||
| 776 | } | ||
| 777 | |||
| 778 | static struct of_device * __init scan_one_device(struct device_node *dp, | ||
| 779 | struct device *parent) | ||
| 780 | { | ||
| 781 | struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL); | ||
| 782 | unsigned int *irq; | ||
| 783 | int len, i; | ||
| 784 | |||
| 785 | if (!op) | ||
| 786 | return NULL; | ||
| 787 | |||
| 788 | op->node = dp; | ||
| 789 | |||
| 790 | op->clock_freq = of_getintprop_default(dp, "clock-frequency", | ||
| 791 | (25*1000*1000)); | ||
| 792 | op->portid = of_getintprop_default(dp, "upa-portid", -1); | ||
| 793 | if (op->portid == -1) | ||
| 794 | op->portid = of_getintprop_default(dp, "portid", -1); | ||
| 795 | |||
| 796 | irq = of_get_property(dp, "interrupts", &len); | ||
| 797 | if (irq) { | ||
| 798 | memcpy(op->irqs, irq, len); | ||
| 799 | op->num_irqs = len / 4; | ||
| 800 | } else { | ||
| 801 | op->num_irqs = 0; | ||
| 802 | } | ||
| 803 | |||
| 804 | build_device_resources(op, parent); | ||
| 805 | for (i = 0; i < op->num_irqs; i++) | ||
| 806 | op->irqs[i] = build_one_device_irq(op, parent, op->irqs[i]); | ||
| 807 | |||
| 808 | op->dev.parent = parent; | ||
| 809 | op->dev.bus = &of_bus_type; | ||
| 810 | if (!parent) | ||
| 811 | strcpy(op->dev.bus_id, "root"); | ||
| 812 | else | ||
| 813 | strcpy(op->dev.bus_id, dp->path_component_name); | ||
| 814 | |||
| 815 | if (of_device_register(op)) { | ||
| 816 | printk("%s: Could not register of device.\n", | ||
| 817 | dp->full_name); | ||
| 818 | kfree(op); | ||
| 819 | op = NULL; | ||
| 820 | } | ||
| 821 | |||
| 822 | return op; | ||
| 823 | } | ||
| 824 | |||
| 825 | static void __init scan_tree(struct device_node *dp, struct device *parent) | ||
| 826 | { | ||
| 827 | while (dp) { | ||
| 828 | struct of_device *op = scan_one_device(dp, parent); | ||
| 829 | |||
| 830 | if (op) | ||
| 831 | scan_tree(dp->child, &op->dev); | ||
| 832 | |||
| 833 | dp = dp->sibling; | ||
| 834 | } | ||
| 835 | } | ||
| 836 | |||
| 837 | static void __init scan_of_devices(void) | ||
| 838 | { | ||
| 839 | struct device_node *root = of_find_node_by_path("/"); | ||
| 840 | struct of_device *parent; | ||
| 841 | |||
| 842 | parent = scan_one_device(root, NULL); | ||
| 843 | if (!parent) | ||
| 844 | return; | ||
| 845 | |||
| 846 | scan_tree(root->child, &parent->dev); | ||
| 847 | } | ||
| 848 | |||
| 166 | static int __init of_bus_driver_init(void) | 849 | static int __init of_bus_driver_init(void) |
| 167 | { | 850 | { |
| 168 | int err = 0; | 851 | int err; |
| 169 | 852 | ||
| 853 | err = bus_register(&of_bus_type); | ||
| 170 | #ifdef CONFIG_PCI | 854 | #ifdef CONFIG_PCI |
| 171 | if (!err) | 855 | if (!err) |
| 172 | err = bus_register(&isa_bus_type); | 856 | err = bus_register(&isa_bus_type); |
| @@ -177,7 +861,11 @@ static int __init of_bus_driver_init(void) | |||
| 177 | if (!err) | 861 | if (!err) |
| 178 | err = bus_register(&sbus_bus_type); | 862 | err = bus_register(&sbus_bus_type); |
| 179 | #endif | 863 | #endif |
| 180 | return 0; | 864 | |
| 865 | if (!err) | ||
| 866 | scan_of_devices(); | ||
| 867 | |||
| 868 | return err; | ||
| 181 | } | 869 | } |
| 182 | 870 | ||
| 183 | postcore_initcall(of_bus_driver_init); | 871 | postcore_initcall(of_bus_driver_init); |
