aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/prom.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/prom.c')
-rw-r--r--arch/powerpc/kernel/prom.c468
1 files changed, 52 insertions, 416 deletions
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 3bf968e74095..977ee3adaf2d 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -29,6 +29,7 @@
29#include <linux/initrd.h> 29#include <linux/initrd.h>
30#include <linux/bitops.h> 30#include <linux/bitops.h>
31#include <linux/module.h> 31#include <linux/module.h>
32#include <linux/kexec.h>
32 33
33#include <asm/prom.h> 34#include <asm/prom.h>
34#include <asm/rtas.h> 35#include <asm/rtas.h>
@@ -37,6 +38,7 @@
37#include <asm/processor.h> 38#include <asm/processor.h>
38#include <asm/irq.h> 39#include <asm/irq.h>
39#include <asm/io.h> 40#include <asm/io.h>
41#include <asm/kdump.h>
40#include <asm/smp.h> 42#include <asm/smp.h>
41#include <asm/system.h> 43#include <asm/system.h>
42#include <asm/mmu.h> 44#include <asm/mmu.h>
@@ -55,21 +57,6 @@
55#define DBG(fmt...) 57#define DBG(fmt...)
56#endif 58#endif
57 59
58struct pci_reg_property {
59 struct pci_address addr;
60 u32 size_hi;
61 u32 size_lo;
62};
63
64struct isa_reg_property {
65 u32 space;
66 u32 address;
67 u32 size;
68};
69
70
71typedef int interpret_func(struct device_node *, unsigned long *,
72 int, int, int);
73 60
74static int __initdata dt_root_addr_cells; 61static int __initdata dt_root_addr_cells;
75static int __initdata dt_root_size_cells; 62static int __initdata dt_root_size_cells;
@@ -311,6 +298,16 @@ static int __devinit finish_node_interrupts(struct device_node *np,
311 int i, j, n, sense; 298 int i, j, n, sense;
312 unsigned int *irq, virq; 299 unsigned int *irq, virq;
313 struct device_node *ic; 300 struct device_node *ic;
301 int trace = 0;
302
303 //#define TRACE(fmt...) do { if (trace) { printk(fmt); mdelay(1000); } } while(0)
304#define TRACE(fmt...)
305
306 if (!strcmp(np->name, "smu-doorbell"))
307 trace = 1;
308
309 TRACE("Finishing SMU doorbell ! num_interrupt_controllers = %d\n",
310 num_interrupt_controllers);
314 311
315 if (num_interrupt_controllers == 0) { 312 if (num_interrupt_controllers == 0) {
316 /* 313 /*
@@ -345,11 +342,12 @@ static int __devinit finish_node_interrupts(struct device_node *np,
345 } 342 }
346 343
347 ints = (unsigned int *) get_property(np, "interrupts", &intlen); 344 ints = (unsigned int *) get_property(np, "interrupts", &intlen);
345 TRACE("ints=%p, intlen=%d\n", ints, intlen);
348 if (ints == NULL) 346 if (ints == NULL)
349 return 0; 347 return 0;
350 intrcells = prom_n_intr_cells(np); 348 intrcells = prom_n_intr_cells(np);
351 intlen /= intrcells * sizeof(unsigned int); 349 intlen /= intrcells * sizeof(unsigned int);
352 350 TRACE("intrcells=%d, new intlen=%d\n", intrcells, intlen);
353 np->intrs = prom_alloc(intlen * sizeof(*(np->intrs)), mem_start); 351 np->intrs = prom_alloc(intlen * sizeof(*(np->intrs)), mem_start);
354 if (!np->intrs) 352 if (!np->intrs)
355 return -ENOMEM; 353 return -ENOMEM;
@@ -360,6 +358,7 @@ static int __devinit finish_node_interrupts(struct device_node *np,
360 intrcount = 0; 358 intrcount = 0;
361 for (i = 0; i < intlen; ++i, ints += intrcells) { 359 for (i = 0; i < intlen; ++i, ints += intrcells) {
362 n = map_interrupt(&irq, &ic, np, ints, intrcells); 360 n = map_interrupt(&irq, &ic, np, ints, intrcells);
361 TRACE("map, irq=%d, ic=%p, n=%d\n", irq, ic, n);
363 if (n <= 0) 362 if (n <= 0)
364 continue; 363 continue;
365 364
@@ -370,6 +369,7 @@ static int __devinit finish_node_interrupts(struct device_node *np,
370 np->intrs[intrcount].sense = map_isa_senses[sense]; 369 np->intrs[intrcount].sense = map_isa_senses[sense];
371 } else { 370 } else {
372 virq = virt_irq_create_mapping(irq[0]); 371 virq = virt_irq_create_mapping(irq[0]);
372 TRACE("virq=%d\n", virq);
373#ifdef CONFIG_PPC64 373#ifdef CONFIG_PPC64
374 if (virq == NO_IRQ) { 374 if (virq == NO_IRQ) {
375 printk(KERN_CRIT "Could not allocate interrupt" 375 printk(KERN_CRIT "Could not allocate interrupt"
@@ -379,6 +379,12 @@ static int __devinit finish_node_interrupts(struct device_node *np,
379#endif 379#endif
380 np->intrs[intrcount].line = irq_offset_up(virq); 380 np->intrs[intrcount].line = irq_offset_up(virq);
381 sense = (n > 1)? (irq[1] & 3): 1; 381 sense = (n > 1)? (irq[1] & 3): 1;
382
383 /* Apple uses bits in there in a different way, let's
384 * only keep the real sense bit on macs
385 */
386 if (_machine == PLATFORM_POWERMAC)
387 sense &= 0x1;
382 np->intrs[intrcount].sense = map_mpic_senses[sense]; 388 np->intrs[intrcount].sense = map_mpic_senses[sense];
383 } 389 }
384 390
@@ -388,12 +394,13 @@ static int __devinit finish_node_interrupts(struct device_node *np,
388 char *name = get_property(ic->parent, "name", NULL); 394 char *name = get_property(ic->parent, "name", NULL);
389 if (name && !strcmp(name, "u3")) 395 if (name && !strcmp(name, "u3"))
390 np->intrs[intrcount].line += 128; 396 np->intrs[intrcount].line += 128;
391 else if (!(name && !strcmp(name, "mac-io"))) 397 else if (!(name && (!strcmp(name, "mac-io") ||
398 !strcmp(name, "u4"))))
392 /* ignore other cascaded controllers, such as 399 /* ignore other cascaded controllers, such as
393 the k2-sata-root */ 400 the k2-sata-root */
394 break; 401 break;
395 } 402 }
396#endif 403#endif /* CONFIG_PPC64 */
397 if (n > 2) { 404 if (n > 2) {
398 printk("hmmm, got %d intr cells for %s:", n, 405 printk("hmmm, got %d intr cells for %s:", n,
399 np->full_name); 406 np->full_name);
@@ -408,234 +415,19 @@ static int __devinit finish_node_interrupts(struct device_node *np,
408 return 0; 415 return 0;
409} 416}
410 417
411static int __devinit interpret_pci_props(struct device_node *np,
412 unsigned long *mem_start,
413 int naddrc, int nsizec,
414 int measure_only)
415{
416 struct address_range *adr;
417 struct pci_reg_property *pci_addrs;
418 int i, l, n_addrs;
419
420 pci_addrs = (struct pci_reg_property *)
421 get_property(np, "assigned-addresses", &l);
422 if (!pci_addrs)
423 return 0;
424
425 n_addrs = l / sizeof(*pci_addrs);
426
427 adr = prom_alloc(n_addrs * sizeof(*adr), mem_start);
428 if (!adr)
429 return -ENOMEM;
430
431 if (measure_only)
432 return 0;
433
434 np->addrs = adr;
435 np->n_addrs = n_addrs;
436
437 for (i = 0; i < n_addrs; i++) {
438 adr[i].space = pci_addrs[i].addr.a_hi;
439 adr[i].address = pci_addrs[i].addr.a_lo |
440 ((u64)pci_addrs[i].addr.a_mid << 32);
441 adr[i].size = pci_addrs[i].size_lo;
442 }
443
444 return 0;
445}
446
447static int __init interpret_dbdma_props(struct device_node *np,
448 unsigned long *mem_start,
449 int naddrc, int nsizec,
450 int measure_only)
451{
452 struct reg_property32 *rp;
453 struct address_range *adr;
454 unsigned long base_address;
455 int i, l;
456 struct device_node *db;
457
458 base_address = 0;
459 if (!measure_only) {
460 for (db = np->parent; db != NULL; db = db->parent) {
461 if (!strcmp(db->type, "dbdma") && db->n_addrs != 0) {
462 base_address = db->addrs[0].address;
463 break;
464 }
465 }
466 }
467
468 rp = (struct reg_property32 *) get_property(np, "reg", &l);
469 if (rp != 0 && l >= sizeof(struct reg_property32)) {
470 i = 0;
471 adr = (struct address_range *) (*mem_start);
472 while ((l -= sizeof(struct reg_property32)) >= 0) {
473 if (!measure_only) {
474 adr[i].space = 2;
475 adr[i].address = rp[i].address + base_address;
476 adr[i].size = rp[i].size;
477 }
478 ++i;
479 }
480 np->addrs = adr;
481 np->n_addrs = i;
482 (*mem_start) += i * sizeof(struct address_range);
483 }
484
485 return 0;
486}
487
488static int __init interpret_macio_props(struct device_node *np,
489 unsigned long *mem_start,
490 int naddrc, int nsizec,
491 int measure_only)
492{
493 struct reg_property32 *rp;
494 struct address_range *adr;
495 unsigned long base_address;
496 int i, l;
497 struct device_node *db;
498
499 base_address = 0;
500 if (!measure_only) {
501 for (db = np->parent; db != NULL; db = db->parent) {
502 if (!strcmp(db->type, "mac-io") && db->n_addrs != 0) {
503 base_address = db->addrs[0].address;
504 break;
505 }
506 }
507 }
508
509 rp = (struct reg_property32 *) get_property(np, "reg", &l);
510 if (rp != 0 && l >= sizeof(struct reg_property32)) {
511 i = 0;
512 adr = (struct address_range *) (*mem_start);
513 while ((l -= sizeof(struct reg_property32)) >= 0) {
514 if (!measure_only) {
515 adr[i].space = 2;
516 adr[i].address = rp[i].address + base_address;
517 adr[i].size = rp[i].size;
518 }
519 ++i;
520 }
521 np->addrs = adr;
522 np->n_addrs = i;
523 (*mem_start) += i * sizeof(struct address_range);
524 }
525
526 return 0;
527}
528
529static int __init interpret_isa_props(struct device_node *np,
530 unsigned long *mem_start,
531 int naddrc, int nsizec,
532 int measure_only)
533{
534 struct isa_reg_property *rp;
535 struct address_range *adr;
536 int i, l;
537
538 rp = (struct isa_reg_property *) get_property(np, "reg", &l);
539 if (rp != 0 && l >= sizeof(struct isa_reg_property)) {
540 i = 0;
541 adr = (struct address_range *) (*mem_start);
542 while ((l -= sizeof(struct isa_reg_property)) >= 0) {
543 if (!measure_only) {
544 adr[i].space = rp[i].space;
545 adr[i].address = rp[i].address;
546 adr[i].size = rp[i].size;
547 }
548 ++i;
549 }
550 np->addrs = adr;
551 np->n_addrs = i;
552 (*mem_start) += i * sizeof(struct address_range);
553 }
554
555 return 0;
556}
557
558static int __init interpret_root_props(struct device_node *np,
559 unsigned long *mem_start,
560 int naddrc, int nsizec,
561 int measure_only)
562{
563 struct address_range *adr;
564 int i, l;
565 unsigned int *rp;
566 int rpsize = (naddrc + nsizec) * sizeof(unsigned int);
567
568 rp = (unsigned int *) get_property(np, "reg", &l);
569 if (rp != 0 && l >= rpsize) {
570 i = 0;
571 adr = (struct address_range *) (*mem_start);
572 while ((l -= rpsize) >= 0) {
573 if (!measure_only) {
574 adr[i].space = 0;
575 adr[i].address = rp[naddrc - 1];
576 adr[i].size = rp[naddrc + nsizec - 1];
577 }
578 ++i;
579 rp += naddrc + nsizec;
580 }
581 np->addrs = adr;
582 np->n_addrs = i;
583 (*mem_start) += i * sizeof(struct address_range);
584 }
585
586 return 0;
587}
588
589static int __devinit finish_node(struct device_node *np, 418static int __devinit finish_node(struct device_node *np,
590 unsigned long *mem_start, 419 unsigned long *mem_start,
591 interpret_func *ifunc,
592 int naddrc, int nsizec,
593 int measure_only) 420 int measure_only)
594{ 421{
595 struct device_node *child; 422 struct device_node *child;
596 int *ip, rc = 0; 423 int rc = 0;
597
598 /* get the device addresses and interrupts */
599 if (ifunc != NULL)
600 rc = ifunc(np, mem_start, naddrc, nsizec, measure_only);
601 if (rc)
602 goto out;
603 424
604 rc = finish_node_interrupts(np, mem_start, measure_only); 425 rc = finish_node_interrupts(np, mem_start, measure_only);
605 if (rc) 426 if (rc)
606 goto out; 427 goto out;
607 428
608 /* Look for #address-cells and #size-cells properties. */
609 ip = (int *) get_property(np, "#address-cells", NULL);
610 if (ip != NULL)
611 naddrc = *ip;
612 ip = (int *) get_property(np, "#size-cells", NULL);
613 if (ip != NULL)
614 nsizec = *ip;
615
616 if (!strcmp(np->name, "device-tree") || np->parent == NULL)
617 ifunc = interpret_root_props;
618 else if (np->type == 0)
619 ifunc = NULL;
620 else if (!strcmp(np->type, "pci") || !strcmp(np->type, "vci"))
621 ifunc = interpret_pci_props;
622 else if (!strcmp(np->type, "dbdma"))
623 ifunc = interpret_dbdma_props;
624 else if (!strcmp(np->type, "mac-io") || ifunc == interpret_macio_props)
625 ifunc = interpret_macio_props;
626 else if (!strcmp(np->type, "isa"))
627 ifunc = interpret_isa_props;
628 else if (!strcmp(np->name, "uni-n") || !strcmp(np->name, "u3"))
629 ifunc = interpret_root_props;
630 else if (!((ifunc == interpret_dbdma_props
631 || ifunc == interpret_macio_props)
632 && (!strcmp(np->type, "escc")
633 || !strcmp(np->type, "media-bay"))))
634 ifunc = NULL;
635
636 for (child = np->child; child != NULL; child = child->sibling) { 429 for (child = np->child; child != NULL; child = child->sibling) {
637 rc = finish_node(child, mem_start, ifunc, 430 rc = finish_node(child, mem_start, measure_only);
638 naddrc, nsizec, measure_only);
639 if (rc) 431 if (rc)
640 goto out; 432 goto out;
641 } 433 }
@@ -697,10 +489,10 @@ void __init finish_device_tree(void)
697 * reason and then remove those additional 16 bytes 489 * reason and then remove those additional 16 bytes
698 */ 490 */
699 size = 16; 491 size = 16;
700 finish_node(allnodes, &size, NULL, 0, 0, 1); 492 finish_node(allnodes, &size, 1);
701 size -= 16; 493 size -= 16;
702 end = start = (unsigned long) __va(lmb_alloc(size, 128)); 494 end = start = (unsigned long) __va(lmb_alloc(size, 128));
703 finish_node(allnodes, &end, NULL, 0, 0, 0); 495 finish_node(allnodes, &end, 0);
704 BUG_ON(end != start + size); 496 BUG_ON(end != start + size);
705 497
706 DBG(" <- finish_device_tree\n"); 498 DBG(" <- finish_device_tree\n");
@@ -1197,6 +989,16 @@ static int __init early_init_dt_scan_chosen(unsigned long node,
1197 } 989 }
1198#endif /* CONFIG_PPC_RTAS */ 990#endif /* CONFIG_PPC_RTAS */
1199 991
992#ifdef CONFIG_KEXEC
993 lprop = (u64*)of_get_flat_dt_prop(node, "linux,crashkernel-base", NULL);
994 if (lprop)
995 crashk_res.start = *lprop;
996
997 lprop = (u64*)of_get_flat_dt_prop(node, "linux,crashkernel-size", NULL);
998 if (lprop)
999 crashk_res.end = crashk_res.start + *lprop - 1;
1000#endif
1001
1200 /* break now */ 1002 /* break now */
1201 return 1; 1003 return 1;
1202} 1004}
@@ -1263,7 +1065,9 @@ static int __init early_init_dt_scan_memory(unsigned long node,
1263 } else if (strcmp(type, "memory") != 0) 1065 } else if (strcmp(type, "memory") != 0)
1264 return 0; 1066 return 0;
1265 1067
1266 reg = (cell_t *)of_get_flat_dt_prop(node, "reg", &l); 1068 reg = (cell_t *)of_get_flat_dt_prop(node, "linux,usable-memory", &l);
1069 if (reg == NULL)
1070 reg = (cell_t *)of_get_flat_dt_prop(node, "reg", &l);
1267 if (reg == NULL) 1071 if (reg == NULL)
1268 return 0; 1072 return 0;
1269 1073
@@ -1335,11 +1139,14 @@ void __init early_init_devtree(void *params)
1335 of_scan_flat_dt(early_init_dt_scan_memory, NULL); 1139 of_scan_flat_dt(early_init_dt_scan_memory, NULL);
1336 lmb_enforce_memory_limit(memory_limit); 1140 lmb_enforce_memory_limit(memory_limit);
1337 lmb_analyze(); 1141 lmb_analyze();
1338 lmb_reserve(0, __pa(klimit));
1339 1142
1340 DBG("Phys. mem: %lx\n", lmb_phys_mem_size()); 1143 DBG("Phys. mem: %lx\n", lmb_phys_mem_size());
1341 1144
1342 /* Reserve LMB regions used by kernel, initrd, dt, etc... */ 1145 /* Reserve LMB regions used by kernel, initrd, dt, etc... */
1146 lmb_reserve(PHYSICAL_START, __pa(klimit) - PHYSICAL_START);
1147#ifdef CONFIG_CRASH_DUMP
1148 lmb_reserve(0, KDUMP_RESERVE_LIMIT);
1149#endif
1343 early_reserve_mem(); 1150 early_reserve_mem();
1344 1151
1345 DBG("Scanning CPUs ...\n"); 1152 DBG("Scanning CPUs ...\n");
@@ -1802,7 +1609,6 @@ static void of_node_release(struct kref *kref)
1802 prop = next; 1609 prop = next;
1803 } 1610 }
1804 kfree(node->intrs); 1611 kfree(node->intrs);
1805 kfree(node->addrs);
1806 kfree(node->full_name); 1612 kfree(node->full_name);
1807 kfree(node->data); 1613 kfree(node->data);
1808 kfree(node); 1614 kfree(node);
@@ -1884,9 +1690,7 @@ void of_detach_node(const struct device_node *np)
1884 * This should probably be split up into smaller chunks. 1690 * This should probably be split up into smaller chunks.
1885 */ 1691 */
1886 1692
1887static int of_finish_dynamic_node(struct device_node *node, 1693static int of_finish_dynamic_node(struct device_node *node)
1888 unsigned long *unused1, int unused2,
1889 int unused3, int unused4)
1890{ 1694{
1891 struct device_node *parent = of_get_parent(node); 1695 struct device_node *parent = of_get_parent(node);
1892 int err = 0; 1696 int err = 0;
@@ -1907,7 +1711,8 @@ static int of_finish_dynamic_node(struct device_node *node,
1907 return -ENODEV; 1711 return -ENODEV;
1908 1712
1909 /* fix up new node's linux_phandle field */ 1713 /* fix up new node's linux_phandle field */
1910 if ((ibm_phandle = (unsigned int *)get_property(node, "ibm,phandle", NULL))) 1714 if ((ibm_phandle = (unsigned int *)get_property(node,
1715 "ibm,phandle", NULL)))
1911 node->linux_phandle = *ibm_phandle; 1716 node->linux_phandle = *ibm_phandle;
1912 1717
1913out: 1718out:
@@ -1922,7 +1727,9 @@ static int prom_reconfig_notifier(struct notifier_block *nb,
1922 1727
1923 switch (action) { 1728 switch (action) {
1924 case PSERIES_RECONFIG_ADD: 1729 case PSERIES_RECONFIG_ADD:
1925 err = finish_node(node, NULL, of_finish_dynamic_node, 0, 0, 0); 1730 err = of_finish_dynamic_node(node);
1731 if (!err)
1732 finish_node(node, NULL, 0);
1926 if (err < 0) { 1733 if (err < 0) {
1927 printk(KERN_ERR "finish_node returned %d\n", err); 1734 printk(KERN_ERR "finish_node returned %d\n", err);
1928 err = NOTIFY_BAD; 1735 err = NOTIFY_BAD;
@@ -1996,175 +1803,4 @@ int prom_add_property(struct device_node* np, struct property* prop)
1996 return 0; 1803 return 0;
1997} 1804}
1998 1805
1999/* I quickly hacked that one, check against spec ! */
2000static inline unsigned long
2001bus_space_to_resource_flags(unsigned int bus_space)
2002{
2003 u8 space = (bus_space >> 24) & 0xf;
2004 if (space == 0)
2005 space = 0x02;
2006 if (space == 0x02)
2007 return IORESOURCE_MEM;
2008 else if (space == 0x01)
2009 return IORESOURCE_IO;
2010 else {
2011 printk(KERN_WARNING "prom.c: bus_space_to_resource_flags(), space: %x\n",
2012 bus_space);
2013 return 0;
2014 }
2015}
2016
2017#ifdef CONFIG_PCI
2018static struct resource *find_parent_pci_resource(struct pci_dev* pdev,
2019 struct address_range *range)
2020{
2021 unsigned long mask;
2022 int i;
2023
2024 /* Check this one */
2025 mask = bus_space_to_resource_flags(range->space);
2026 for (i=0; i<DEVICE_COUNT_RESOURCE; i++) {
2027 if ((pdev->resource[i].flags & mask) == mask &&
2028 pdev->resource[i].start <= range->address &&
2029 pdev->resource[i].end > range->address) {
2030 if ((range->address + range->size - 1) > pdev->resource[i].end) {
2031 /* Add better message */
2032 printk(KERN_WARNING "PCI/OF resource overlap !\n");
2033 return NULL;
2034 }
2035 break;
2036 }
2037 }
2038 if (i == DEVICE_COUNT_RESOURCE)
2039 return NULL;
2040 return &pdev->resource[i];
2041}
2042
2043/*
2044 * Request an OF device resource. Currently handles child of PCI devices,
2045 * or other nodes attached to the root node. Ultimately, put some
2046 * link to resources in the OF node.
2047 */
2048struct resource *request_OF_resource(struct device_node* node, int index,
2049 const char* name_postfix)
2050{
2051 struct pci_dev* pcidev;
2052 u8 pci_bus, pci_devfn;
2053 unsigned long iomask;
2054 struct device_node* nd;
2055 struct resource* parent;
2056 struct resource *res = NULL;
2057 int nlen, plen;
2058
2059 if (index >= node->n_addrs)
2060 goto fail;
2061
2062 /* Sanity check on bus space */
2063 iomask = bus_space_to_resource_flags(node->addrs[index].space);
2064 if (iomask & IORESOURCE_MEM)
2065 parent = &iomem_resource;
2066 else if (iomask & IORESOURCE_IO)
2067 parent = &ioport_resource;
2068 else
2069 goto fail;
2070
2071 /* Find a PCI parent if any */
2072 nd = node;
2073 pcidev = NULL;
2074 while (nd) {
2075 if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn))
2076 pcidev = pci_find_slot(pci_bus, pci_devfn);
2077 if (pcidev) break;
2078 nd = nd->parent;
2079 }
2080 if (pcidev)
2081 parent = find_parent_pci_resource(pcidev, &node->addrs[index]);
2082 if (!parent) {
2083 printk(KERN_WARNING "request_OF_resource(%s), parent not found\n",
2084 node->name);
2085 goto fail;
2086 }
2087 1806
2088 res = __request_region(parent, node->addrs[index].address,
2089 node->addrs[index].size, NULL);
2090 if (!res)
2091 goto fail;
2092 nlen = strlen(node->name);
2093 plen = name_postfix ? strlen(name_postfix) : 0;
2094 res->name = (const char *)kmalloc(nlen+plen+1, GFP_KERNEL);
2095 if (res->name) {
2096 strcpy((char *)res->name, node->name);
2097 if (plen)
2098 strcpy((char *)res->name+nlen, name_postfix);
2099 }
2100 return res;
2101fail:
2102 return NULL;
2103}
2104EXPORT_SYMBOL(request_OF_resource);
2105
2106int release_OF_resource(struct device_node *node, int index)
2107{
2108 struct pci_dev* pcidev;
2109 u8 pci_bus, pci_devfn;
2110 unsigned long iomask, start, end;
2111 struct device_node* nd;
2112 struct resource* parent;
2113 struct resource *res = NULL;
2114
2115 if (index >= node->n_addrs)
2116 return -EINVAL;
2117
2118 /* Sanity check on bus space */
2119 iomask = bus_space_to_resource_flags(node->addrs[index].space);
2120 if (iomask & IORESOURCE_MEM)
2121 parent = &iomem_resource;
2122 else if (iomask & IORESOURCE_IO)
2123 parent = &ioport_resource;
2124 else
2125 return -EINVAL;
2126
2127 /* Find a PCI parent if any */
2128 nd = node;
2129 pcidev = NULL;
2130 while(nd) {
2131 if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn))
2132 pcidev = pci_find_slot(pci_bus, pci_devfn);
2133 if (pcidev) break;
2134 nd = nd->parent;
2135 }
2136 if (pcidev)
2137 parent = find_parent_pci_resource(pcidev, &node->addrs[index]);
2138 if (!parent) {
2139 printk(KERN_WARNING "release_OF_resource(%s), parent not found\n",
2140 node->name);
2141 return -ENODEV;
2142 }
2143
2144 /* Find us in the parent and its childs */
2145 res = parent->child;
2146 start = node->addrs[index].address;
2147 end = start + node->addrs[index].size - 1;
2148 while (res) {
2149 if (res->start == start && res->end == end &&
2150 (res->flags & IORESOURCE_BUSY))
2151 break;
2152 if (res->start <= start && res->end >= end)
2153 res = res->child;
2154 else
2155 res = res->sibling;
2156 }
2157 if (!res)
2158 return -ENODEV;
2159
2160 if (res->name) {
2161 kfree(res->name);
2162 res->name = NULL;
2163 }
2164 release_resource(res);
2165 kfree(res);
2166
2167 return 0;
2168}
2169EXPORT_SYMBOL(release_OF_resource);
2170#endif /* CONFIG_PCI */