diff options
Diffstat (limited to 'arch/powerpc/kernel/prom.c')
| -rw-r--r-- | arch/powerpc/kernel/prom.c | 454 |
1 files changed, 3 insertions, 451 deletions
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 4c524cb52184..a1787ffb6319 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | #include <linux/module.h> | 30 | #include <linux/module.h> |
| 31 | #include <linux/kexec.h> | 31 | #include <linux/kexec.h> |
| 32 | #include <linux/debugfs.h> | 32 | #include <linux/debugfs.h> |
| 33 | #include <linux/irq.h> | ||
| 33 | 34 | ||
| 34 | #include <asm/prom.h> | 35 | #include <asm/prom.h> |
| 35 | #include <asm/rtas.h> | 36 | #include <asm/rtas.h> |
| @@ -86,424 +87,6 @@ static DEFINE_RWLOCK(devtree_lock); | |||
| 86 | /* export that to outside world */ | 87 | /* export that to outside world */ |
| 87 | struct device_node *of_chosen; | 88 | struct device_node *of_chosen; |
| 88 | 89 | ||
| 89 | struct device_node *dflt_interrupt_controller; | ||
| 90 | int num_interrupt_controllers; | ||
| 91 | |||
| 92 | /* | ||
| 93 | * Wrapper for allocating memory for various data that needs to be | ||
| 94 | * attached to device nodes as they are processed at boot or when | ||
| 95 | * added to the device tree later (e.g. DLPAR). At boot there is | ||
| 96 | * already a region reserved so we just increment *mem_start by size; | ||
| 97 | * otherwise we call kmalloc. | ||
| 98 | */ | ||
| 99 | static void * prom_alloc(unsigned long size, unsigned long *mem_start) | ||
| 100 | { | ||
| 101 | unsigned long tmp; | ||
| 102 | |||
| 103 | if (!mem_start) | ||
| 104 | return kmalloc(size, GFP_KERNEL); | ||
| 105 | |||
| 106 | tmp = *mem_start; | ||
| 107 | *mem_start += size; | ||
| 108 | return (void *)tmp; | ||
| 109 | } | ||
| 110 | |||
| 111 | /* | ||
| 112 | * Find the device_node with a given phandle. | ||
| 113 | */ | ||
| 114 | static struct device_node * find_phandle(phandle ph) | ||
| 115 | { | ||
| 116 | struct device_node *np; | ||
| 117 | |||
| 118 | for (np = allnodes; np != 0; np = np->allnext) | ||
| 119 | if (np->linux_phandle == ph) | ||
| 120 | return np; | ||
| 121 | return NULL; | ||
| 122 | } | ||
| 123 | |||
| 124 | /* | ||
| 125 | * Find the interrupt parent of a node. | ||
| 126 | */ | ||
| 127 | static struct device_node * __devinit intr_parent(struct device_node *p) | ||
| 128 | { | ||
| 129 | phandle *parp; | ||
| 130 | |||
| 131 | parp = (phandle *) get_property(p, "interrupt-parent", NULL); | ||
| 132 | if (parp == NULL) | ||
| 133 | return p->parent; | ||
| 134 | p = find_phandle(*parp); | ||
| 135 | if (p != NULL) | ||
| 136 | return p; | ||
| 137 | /* | ||
| 138 | * On a powermac booted with BootX, we don't get to know the | ||
| 139 | * phandles for any nodes, so find_phandle will return NULL. | ||
| 140 | * Fortunately these machines only have one interrupt controller | ||
| 141 | * so there isn't in fact any ambiguity. -- paulus | ||
| 142 | */ | ||
| 143 | if (num_interrupt_controllers == 1) | ||
| 144 | p = dflt_interrupt_controller; | ||
| 145 | return p; | ||
| 146 | } | ||
| 147 | |||
| 148 | /* | ||
| 149 | * Find out the size of each entry of the interrupts property | ||
| 150 | * for a node. | ||
| 151 | */ | ||
| 152 | int __devinit prom_n_intr_cells(struct device_node *np) | ||
| 153 | { | ||
| 154 | struct device_node *p; | ||
| 155 | unsigned int *icp; | ||
| 156 | |||
| 157 | for (p = np; (p = intr_parent(p)) != NULL; ) { | ||
| 158 | icp = (unsigned int *) | ||
| 159 | get_property(p, "#interrupt-cells", NULL); | ||
| 160 | if (icp != NULL) | ||
| 161 | return *icp; | ||
| 162 | if (get_property(p, "interrupt-controller", NULL) != NULL | ||
| 163 | || get_property(p, "interrupt-map", NULL) != NULL) { | ||
| 164 | printk("oops, node %s doesn't have #interrupt-cells\n", | ||
| 165 | p->full_name); | ||
| 166 | return 1; | ||
| 167 | } | ||
| 168 | } | ||
| 169 | #ifdef DEBUG_IRQ | ||
| 170 | printk("prom_n_intr_cells failed for %s\n", np->full_name); | ||
| 171 | #endif | ||
| 172 | return 1; | ||
| 173 | } | ||
| 174 | |||
| 175 | /* | ||
| 176 | * Map an interrupt from a device up to the platform interrupt | ||
| 177 | * descriptor. | ||
| 178 | */ | ||
| 179 | static int __devinit map_interrupt(unsigned int **irq, struct device_node **ictrler, | ||
| 180 | struct device_node *np, unsigned int *ints, | ||
| 181 | int nintrc) | ||
| 182 | { | ||
| 183 | struct device_node *p, *ipar; | ||
| 184 | unsigned int *imap, *imask, *ip; | ||
| 185 | int i, imaplen, match; | ||
| 186 | int newintrc = 0, newaddrc = 0; | ||
| 187 | unsigned int *reg; | ||
| 188 | int naddrc; | ||
| 189 | |||
| 190 | reg = (unsigned int *) get_property(np, "reg", NULL); | ||
| 191 | naddrc = prom_n_addr_cells(np); | ||
| 192 | p = intr_parent(np); | ||
| 193 | while (p != NULL) { | ||
| 194 | if (get_property(p, "interrupt-controller", NULL) != NULL) | ||
| 195 | /* this node is an interrupt controller, stop here */ | ||
| 196 | break; | ||
| 197 | imap = (unsigned int *) | ||
| 198 | get_property(p, "interrupt-map", &imaplen); | ||
| 199 | if (imap == NULL) { | ||
| 200 | p = intr_parent(p); | ||
| 201 | continue; | ||
| 202 | } | ||
| 203 | imask = (unsigned int *) | ||
| 204 | get_property(p, "interrupt-map-mask", NULL); | ||
| 205 | if (imask == NULL) { | ||
| 206 | printk("oops, %s has interrupt-map but no mask\n", | ||
| 207 | p->full_name); | ||
| 208 | return 0; | ||
| 209 | } | ||
| 210 | imaplen /= sizeof(unsigned int); | ||
| 211 | match = 0; | ||
| 212 | ipar = NULL; | ||
| 213 | while (imaplen > 0 && !match) { | ||
| 214 | /* check the child-interrupt field */ | ||
| 215 | match = 1; | ||
| 216 | for (i = 0; i < naddrc && match; ++i) | ||
| 217 | match = ((reg[i] ^ imap[i]) & imask[i]) == 0; | ||
| 218 | for (; i < naddrc + nintrc && match; ++i) | ||
| 219 | match = ((ints[i-naddrc] ^ imap[i]) & imask[i]) == 0; | ||
| 220 | imap += naddrc + nintrc; | ||
| 221 | imaplen -= naddrc + nintrc; | ||
| 222 | /* grab the interrupt parent */ | ||
| 223 | ipar = find_phandle((phandle) *imap++); | ||
| 224 | --imaplen; | ||
| 225 | if (ipar == NULL && num_interrupt_controllers == 1) | ||
| 226 | /* cope with BootX not giving us phandles */ | ||
| 227 | ipar = dflt_interrupt_controller; | ||
| 228 | if (ipar == NULL) { | ||
| 229 | printk("oops, no int parent %x in map of %s\n", | ||
| 230 | imap[-1], p->full_name); | ||
| 231 | return 0; | ||
| 232 | } | ||
| 233 | /* find the parent's # addr and intr cells */ | ||
| 234 | ip = (unsigned int *) | ||
| 235 | get_property(ipar, "#interrupt-cells", NULL); | ||
| 236 | if (ip == NULL) { | ||
| 237 | printk("oops, no #interrupt-cells on %s\n", | ||
| 238 | ipar->full_name); | ||
| 239 | return 0; | ||
| 240 | } | ||
| 241 | newintrc = *ip; | ||
| 242 | ip = (unsigned int *) | ||
| 243 | get_property(ipar, "#address-cells", NULL); | ||
| 244 | newaddrc = (ip == NULL)? 0: *ip; | ||
| 245 | imap += newaddrc + newintrc; | ||
| 246 | imaplen -= newaddrc + newintrc; | ||
| 247 | } | ||
| 248 | if (imaplen < 0) { | ||
| 249 | printk("oops, error decoding int-map on %s, len=%d\n", | ||
| 250 | p->full_name, imaplen); | ||
| 251 | return 0; | ||
| 252 | } | ||
| 253 | if (!match) { | ||
| 254 | #ifdef DEBUG_IRQ | ||
| 255 | printk("oops, no match in %s int-map for %s\n", | ||
| 256 | p->full_name, np->full_name); | ||
| 257 | #endif | ||
| 258 | return 0; | ||
| 259 | } | ||
| 260 | p = ipar; | ||
| 261 | naddrc = newaddrc; | ||
| 262 | nintrc = newintrc; | ||
| 263 | ints = imap - nintrc; | ||
| 264 | reg = ints - naddrc; | ||
| 265 | } | ||
| 266 | if (p == NULL) { | ||
| 267 | #ifdef DEBUG_IRQ | ||
| 268 | printk("hmmm, int tree for %s doesn't have ctrler\n", | ||
| 269 | np->full_name); | ||
| 270 | #endif | ||
| 271 | return 0; | ||
| 272 | } | ||
| 273 | *irq = ints; | ||
| 274 | *ictrler = p; | ||
| 275 | return nintrc; | ||
| 276 | } | ||
| 277 | |||
| 278 | static unsigned char map_isa_senses[4] = { | ||
| 279 | IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE, | ||
| 280 | IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE, | ||
| 281 | IRQ_SENSE_EDGE | IRQ_POLARITY_NEGATIVE, | ||
| 282 | IRQ_SENSE_EDGE | IRQ_POLARITY_POSITIVE | ||
| 283 | }; | ||
| 284 | |||
| 285 | static unsigned char map_mpic_senses[4] = { | ||
| 286 | IRQ_SENSE_EDGE | IRQ_POLARITY_POSITIVE, | ||
| 287 | IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE, | ||
| 288 | /* 2 seems to be used for the 8259 cascade... */ | ||
| 289 | IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE, | ||
| 290 | IRQ_SENSE_EDGE | IRQ_POLARITY_NEGATIVE, | ||
| 291 | }; | ||
| 292 | |||
| 293 | static int __devinit finish_node_interrupts(struct device_node *np, | ||
| 294 | unsigned long *mem_start, | ||
| 295 | int measure_only) | ||
| 296 | { | ||
| 297 | unsigned int *ints; | ||
| 298 | int intlen, intrcells, intrcount; | ||
| 299 | int i, j, n, sense; | ||
| 300 | unsigned int *irq, virq; | ||
| 301 | struct device_node *ic; | ||
| 302 | int trace = 0; | ||
| 303 | |||
| 304 | //#define TRACE(fmt...) do { if (trace) { printk(fmt); mdelay(1000); } } while(0) | ||
| 305 | #define TRACE(fmt...) | ||
| 306 | |||
| 307 | if (!strcmp(np->name, "smu-doorbell")) | ||
| 308 | trace = 1; | ||
| 309 | |||
| 310 | TRACE("Finishing SMU doorbell ! num_interrupt_controllers = %d\n", | ||
| 311 | num_interrupt_controllers); | ||
| 312 | |||
| 313 | if (num_interrupt_controllers == 0) { | ||
| 314 | /* | ||
| 315 | * Old machines just have a list of interrupt numbers | ||
| 316 | * and no interrupt-controller nodes. | ||
| 317 | */ | ||
| 318 | ints = (unsigned int *) get_property(np, "AAPL,interrupts", | ||
| 319 | &intlen); | ||
| 320 | /* XXX old interpret_pci_props looked in parent too */ | ||
| 321 | /* XXX old interpret_macio_props looked for interrupts | ||
| 322 | before AAPL,interrupts */ | ||
| 323 | if (ints == NULL) | ||
| 324 | ints = (unsigned int *) get_property(np, "interrupts", | ||
| 325 | &intlen); | ||
| 326 | if (ints == NULL) | ||
| 327 | return 0; | ||
| 328 | |||
| 329 | np->n_intrs = intlen / sizeof(unsigned int); | ||
| 330 | np->intrs = prom_alloc(np->n_intrs * sizeof(np->intrs[0]), | ||
| 331 | mem_start); | ||
| 332 | if (!np->intrs) | ||
| 333 | return -ENOMEM; | ||
| 334 | if (measure_only) | ||
| 335 | return 0; | ||
| 336 | |||
| 337 | for (i = 0; i < np->n_intrs; ++i) { | ||
| 338 | np->intrs[i].line = *ints++; | ||
| 339 | np->intrs[i].sense = IRQ_SENSE_LEVEL | ||
| 340 | | IRQ_POLARITY_NEGATIVE; | ||
| 341 | } | ||
| 342 | return 0; | ||
| 343 | } | ||
| 344 | |||
| 345 | ints = (unsigned int *) get_property(np, "interrupts", &intlen); | ||
| 346 | TRACE("ints=%p, intlen=%d\n", ints, intlen); | ||
| 347 | if (ints == NULL) | ||
| 348 | return 0; | ||
| 349 | intrcells = prom_n_intr_cells(np); | ||
| 350 | intlen /= intrcells * sizeof(unsigned int); | ||
| 351 | TRACE("intrcells=%d, new intlen=%d\n", intrcells, intlen); | ||
| 352 | np->intrs = prom_alloc(intlen * sizeof(*(np->intrs)), mem_start); | ||
| 353 | if (!np->intrs) | ||
| 354 | return -ENOMEM; | ||
| 355 | |||
| 356 | if (measure_only) | ||
| 357 | return 0; | ||
| 358 | |||
| 359 | intrcount = 0; | ||
| 360 | for (i = 0; i < intlen; ++i, ints += intrcells) { | ||
| 361 | n = map_interrupt(&irq, &ic, np, ints, intrcells); | ||
| 362 | TRACE("map, irq=%d, ic=%p, n=%d\n", irq, ic, n); | ||
| 363 | if (n <= 0) | ||
| 364 | continue; | ||
| 365 | |||
| 366 | /* don't map IRQ numbers under a cascaded 8259 controller */ | ||
| 367 | if (ic && device_is_compatible(ic, "chrp,iic")) { | ||
| 368 | np->intrs[intrcount].line = irq[0]; | ||
| 369 | sense = (n > 1)? (irq[1] & 3): 3; | ||
| 370 | np->intrs[intrcount].sense = map_isa_senses[sense]; | ||
| 371 | } else { | ||
| 372 | virq = virt_irq_create_mapping(irq[0]); | ||
| 373 | TRACE("virq=%d\n", virq); | ||
| 374 | #ifdef CONFIG_PPC64 | ||
| 375 | if (virq == NO_IRQ) { | ||
| 376 | printk(KERN_CRIT "Could not allocate interrupt" | ||
| 377 | " number for %s\n", np->full_name); | ||
| 378 | continue; | ||
| 379 | } | ||
| 380 | #endif | ||
| 381 | np->intrs[intrcount].line = irq_offset_up(virq); | ||
| 382 | sense = (n > 1)? (irq[1] & 3): 1; | ||
| 383 | |||
| 384 | /* Apple uses bits in there in a different way, let's | ||
| 385 | * only keep the real sense bit on macs | ||
| 386 | */ | ||
| 387 | if (machine_is(powermac)) | ||
| 388 | sense &= 0x1; | ||
| 389 | np->intrs[intrcount].sense = map_mpic_senses[sense]; | ||
| 390 | } | ||
| 391 | |||
| 392 | #ifdef CONFIG_PPC64 | ||
| 393 | /* We offset irq numbers for the u3 MPIC by 128 in PowerMac */ | ||
| 394 | if (machine_is(powermac) && ic && ic->parent) { | ||
| 395 | char *name = get_property(ic->parent, "name", NULL); | ||
| 396 | if (name && !strcmp(name, "u3")) | ||
| 397 | np->intrs[intrcount].line += 128; | ||
| 398 | else if (!(name && (!strcmp(name, "mac-io") || | ||
| 399 | !strcmp(name, "u4")))) | ||
| 400 | /* ignore other cascaded controllers, such as | ||
| 401 | the k2-sata-root */ | ||
| 402 | break; | ||
| 403 | } | ||
| 404 | #endif /* CONFIG_PPC64 */ | ||
| 405 | if (n > 2) { | ||
| 406 | printk("hmmm, got %d intr cells for %s:", n, | ||
| 407 | np->full_name); | ||
| 408 | for (j = 0; j < n; ++j) | ||
| 409 | printk(" %d", irq[j]); | ||
| 410 | printk("\n"); | ||
| 411 | } | ||
| 412 | ++intrcount; | ||
| 413 | } | ||
| 414 | np->n_intrs = intrcount; | ||
| 415 | |||
| 416 | return 0; | ||
| 417 | } | ||
| 418 | |||
| 419 | static int __devinit finish_node(struct device_node *np, | ||
| 420 | unsigned long *mem_start, | ||
| 421 | int measure_only) | ||
| 422 | { | ||
| 423 | struct device_node *child; | ||
| 424 | int rc = 0; | ||
| 425 | |||
| 426 | rc = finish_node_interrupts(np, mem_start, measure_only); | ||
| 427 | if (rc) | ||
| 428 | goto out; | ||
| 429 | |||
| 430 | for (child = np->child; child != NULL; child = child->sibling) { | ||
| 431 | rc = finish_node(child, mem_start, measure_only); | ||
| 432 | if (rc) | ||
| 433 | goto out; | ||
| 434 | } | ||
| 435 | out: | ||
| 436 | return rc; | ||
| 437 | } | ||
| 438 | |||
| 439 | static void __init scan_interrupt_controllers(void) | ||
| 440 | { | ||
| 441 | struct device_node *np; | ||
| 442 | int n = 0; | ||
| 443 | char *name, *ic; | ||
| 444 | int iclen; | ||
| 445 | |||
| 446 | for (np = allnodes; np != NULL; np = np->allnext) { | ||
| 447 | ic = get_property(np, "interrupt-controller", &iclen); | ||
| 448 | name = get_property(np, "name", NULL); | ||
| 449 | /* checking iclen makes sure we don't get a false | ||
| 450 | match on /chosen.interrupt_controller */ | ||
| 451 | if ((name != NULL | ||
| 452 | && strcmp(name, "interrupt-controller") == 0) | ||
| 453 | || (ic != NULL && iclen == 0 | ||
| 454 | && strcmp(name, "AppleKiwi"))) { | ||
| 455 | if (n == 0) | ||
| 456 | dflt_interrupt_controller = np; | ||
| 457 | ++n; | ||
| 458 | } | ||
| 459 | } | ||
| 460 | num_interrupt_controllers = n; | ||
| 461 | } | ||
| 462 | |||
| 463 | /** | ||
| 464 | * finish_device_tree is called once things are running normally | ||
| 465 | * (i.e. with text and data mapped to the address they were linked at). | ||
| 466 | * It traverses the device tree and fills in some of the additional, | ||
| 467 | * fields in each node like {n_}addrs and {n_}intrs, the virt interrupt | ||
| 468 | * mapping is also initialized at this point. | ||
| 469 | */ | ||
| 470 | void __init finish_device_tree(void) | ||
| 471 | { | ||
| 472 | unsigned long start, end, size = 0; | ||
| 473 | |||
| 474 | DBG(" -> finish_device_tree\n"); | ||
| 475 | |||
| 476 | #ifdef CONFIG_PPC64 | ||
| 477 | /* Initialize virtual IRQ map */ | ||
| 478 | virt_irq_init(); | ||
| 479 | #endif | ||
| 480 | scan_interrupt_controllers(); | ||
| 481 | |||
| 482 | /* | ||
| 483 | * Finish device-tree (pre-parsing some properties etc...) | ||
| 484 | * We do this in 2 passes. One with "measure_only" set, which | ||
| 485 | * will only measure the amount of memory needed, then we can | ||
| 486 | * allocate that memory, and call finish_node again. However, | ||
| 487 | * we must be careful as most routines will fail nowadays when | ||
| 488 | * prom_alloc() returns 0, so we must make sure our first pass | ||
| 489 | * doesn't start at 0. We pre-initialize size to 16 for that | ||
| 490 | * reason and then remove those additional 16 bytes | ||
| 491 | */ | ||
| 492 | size = 16; | ||
| 493 | finish_node(allnodes, &size, 1); | ||
| 494 | size -= 16; | ||
| 495 | |||
| 496 | if (0 == size) | ||
| 497 | end = start = 0; | ||
| 498 | else | ||
| 499 | end = start = (unsigned long)__va(lmb_alloc(size, 128)); | ||
| 500 | |||
| 501 | finish_node(allnodes, &end, 0); | ||
| 502 | BUG_ON(end != start + size); | ||
| 503 | |||
| 504 | DBG(" <- finish_device_tree\n"); | ||
| 505 | } | ||
| 506 | |||
| 507 | static inline char *find_flat_dt_string(u32 offset) | 90 | static inline char *find_flat_dt_string(u32 offset) |
| 508 | { | 91 | { |
| 509 | return ((char *)initial_boot_params) + | 92 | return ((char *)initial_boot_params) + |
| @@ -1389,27 +972,6 @@ prom_n_size_cells(struct device_node* np) | |||
| 1389 | EXPORT_SYMBOL(prom_n_size_cells); | 972 | EXPORT_SYMBOL(prom_n_size_cells); |
| 1390 | 973 | ||
| 1391 | /** | 974 | /** |
| 1392 | * Work out the sense (active-low level / active-high edge) | ||
| 1393 | * of each interrupt from the device tree. | ||
| 1394 | */ | ||
| 1395 | void __init prom_get_irq_senses(unsigned char *senses, int off, int max) | ||
| 1396 | { | ||
| 1397 | struct device_node *np; | ||
| 1398 | int i, j; | ||
| 1399 | |||
| 1400 | /* default to level-triggered */ | ||
| 1401 | memset(senses, IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE, max - off); | ||
| 1402 | |||
| 1403 | for (np = allnodes; np != 0; np = np->allnext) { | ||
| 1404 | for (j = 0; j < np->n_intrs; j++) { | ||
| 1405 | i = np->intrs[j].line; | ||
| 1406 | if (i >= off && i < max) | ||
| 1407 | senses[i-off] = np->intrs[j].sense; | ||
| 1408 | } | ||
| 1409 | } | ||
| 1410 | } | ||
| 1411 | |||
| 1412 | /** | ||
| 1413 | * Construct and return a list of the device_nodes with a given name. | 975 | * Construct and return a list of the device_nodes with a given name. |
| 1414 | */ | 976 | */ |
| 1415 | struct device_node *find_devices(const char *name) | 977 | struct device_node *find_devices(const char *name) |
| @@ -1808,7 +1370,6 @@ static void of_node_release(struct kref *kref) | |||
| 1808 | node->deadprops = NULL; | 1370 | node->deadprops = NULL; |
| 1809 | } | 1371 | } |
| 1810 | } | 1372 | } |
| 1811 | kfree(node->intrs); | ||
| 1812 | kfree(node->full_name); | 1373 | kfree(node->full_name); |
| 1813 | kfree(node->data); | 1374 | kfree(node->data); |
| 1814 | kfree(node); | 1375 | kfree(node); |
| @@ -1881,13 +1442,7 @@ void of_detach_node(const struct device_node *np) | |||
| 1881 | #ifdef CONFIG_PPC_PSERIES | 1442 | #ifdef CONFIG_PPC_PSERIES |
| 1882 | /* | 1443 | /* |
| 1883 | * Fix up the uninitialized fields in a new device node: | 1444 | * Fix up the uninitialized fields in a new device node: |
| 1884 | * name, type, n_addrs, addrs, n_intrs, intrs, and pci-specific fields | 1445 | * name, type and pci-specific fields |
| 1885 | * | ||
| 1886 | * A lot of boot-time code is duplicated here, because functions such | ||
| 1887 | * as finish_node_interrupts, interpret_pci_props, etc. cannot use the | ||
| 1888 | * slab allocator. | ||
| 1889 | * | ||
| 1890 | * This should probably be split up into smaller chunks. | ||
| 1891 | */ | 1446 | */ |
| 1892 | 1447 | ||
| 1893 | static int of_finish_dynamic_node(struct device_node *node) | 1448 | static int of_finish_dynamic_node(struct device_node *node) |
| @@ -1928,8 +1483,6 @@ static int prom_reconfig_notifier(struct notifier_block *nb, | |||
| 1928 | switch (action) { | 1483 | switch (action) { |
| 1929 | case PSERIES_RECONFIG_ADD: | 1484 | case PSERIES_RECONFIG_ADD: |
| 1930 | err = of_finish_dynamic_node(node); | 1485 | err = of_finish_dynamic_node(node); |
| 1931 | if (!err) | ||
| 1932 | finish_node(node, NULL, 0); | ||
| 1933 | if (err < 0) { | 1486 | if (err < 0) { |
| 1934 | printk(KERN_ERR "finish_node returned %d\n", err); | 1487 | printk(KERN_ERR "finish_node returned %d\n", err); |
| 1935 | err = NOTIFY_BAD; | 1488 | err = NOTIFY_BAD; |
| @@ -1975,8 +1528,7 @@ struct property *of_find_property(struct device_node *np, const char *name, | |||
| 1975 | * Find a property with a given name for a given node | 1528 | * Find a property with a given name for a given node |
| 1976 | * and return the value. | 1529 | * and return the value. |
| 1977 | */ | 1530 | */ |
| 1978 | unsigned char *get_property(struct device_node *np, const char *name, | 1531 | void *get_property(struct device_node *np, const char *name, int *lenp) |
| 1979 | int *lenp) | ||
| 1980 | { | 1532 | { |
| 1981 | struct property *pp = of_find_property(np,name,lenp); | 1533 | struct property *pp = of_find_property(np,name,lenp); |
| 1982 | return pp ? pp->value : NULL; | 1534 | return pp ? pp->value : NULL; |
