aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/ebus.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64/kernel/ebus.c')
-rw-r--r--arch/sparc64/kernel/ebus.c150
1 files changed, 33 insertions, 117 deletions
diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
index 98e0a8cbeecd..aac014d15ad3 100644
--- a/arch/sparc64/kernel/ebus.c
+++ b/arch/sparc64/kernel/ebus.c
@@ -20,6 +20,8 @@
20#include <asm/pbm.h> 20#include <asm/pbm.h>
21#include <asm/ebus.h> 21#include <asm/ebus.h>
22#include <asm/oplib.h> 22#include <asm/oplib.h>
23#include <asm/prom.h>
24#include <asm/of_device.h>
23#include <asm/bpp.h> 25#include <asm/bpp.h>
24#include <asm/irq.h> 26#include <asm/irq.h>
25 27
@@ -279,45 +281,12 @@ static inline void *ebus_alloc(size_t size)
279 return mem; 281 return mem;
280} 282}
281 283
282int __init ebus_intmap_match(struct linux_ebus *ebus, 284static void __init fill_ebus_child(struct device_node *dp,
283 struct linux_prom_registers *reg, 285 struct linux_ebus_child *dev,
284 int *interrupt) 286 int non_standard_regs)
285{
286 struct linux_prom_ebus_intmap *imap;
287 struct linux_prom_ebus_intmask *imask;
288 unsigned int hi, lo, irq;
289 int i, len, n_imap;
290
291 imap = of_get_property(ebus->prom_node, "interrupt-map", &len);
292 if (!imap)
293 return 0;
294 n_imap = len / sizeof(imap[0]);
295
296 imask = of_get_property(ebus->prom_node, "interrupt-map-mask", NULL);
297 if (!imask)
298 return 0;
299
300 hi = reg->which_io & imask->phys_hi;
301 lo = reg->phys_addr & imask->phys_lo;
302 irq = *interrupt & imask->interrupt;
303 for (i = 0; i < n_imap; i++) {
304 if ((imap[i].phys_hi == hi) &&
305 (imap[i].phys_lo == lo) &&
306 (imap[i].interrupt == irq)) {
307 *interrupt = imap[i].cinterrupt;
308 return 0;
309 }
310 }
311 return -1;
312}
313
314void __init fill_ebus_child(struct device_node *dp,
315 struct linux_prom_registers *preg,
316 struct linux_ebus_child *dev,
317 int non_standard_regs)
318{ 287{
288 struct of_device *op;
319 int *regs; 289 int *regs;
320 int *irqs;
321 int i, len; 290 int i, len;
322 291
323 dev->prom_node = dp; 292 dev->prom_node = dp;
@@ -354,12 +323,16 @@ void __init fill_ebus_child(struct device_node *dp,
354 } 323 }
355 } 324 }
356 325
357 for (i = 0; i < PROMINTR_MAX; i++) 326 op = of_find_device_by_node(dp);
358 dev->irqs[i] = PCI_IRQ_NONE; 327 if (!op) {
359
360 irqs = of_get_property(dp, "interrupts", &len);
361 if (!irqs) {
362 dev->num_irqs = 0; 328 dev->num_irqs = 0;
329 } else {
330 dev->num_irqs = op->num_irqs;
331 for (i = 0; i < dev->num_irqs; i++)
332 dev->irqs[i] = op->irqs[i];
333 }
334
335 if (!dev->num_irqs) {
363 /* 336 /*
364 * Oh, well, some PROMs don't export interrupts 337 * Oh, well, some PROMs don't export interrupts
365 * property to children of EBus devices... 338 * property to children of EBus devices...
@@ -375,23 +348,6 @@ void __init fill_ebus_child(struct device_node *dp,
375 dev->irqs[0] = dev->parent->irqs[1]; 348 dev->irqs[0] = dev->parent->irqs[1];
376 } 349 }
377 } 350 }
378 } else {
379 dev->num_irqs = len / sizeof(irqs[0]);
380 for (i = 0; i < dev->num_irqs; i++) {
381 struct pci_pbm_info *pbm = dev->bus->parent;
382 struct pci_controller_info *p = pbm->parent;
383
384 if (ebus_intmap_match(dev->bus, preg, &irqs[i]) != -1) {
385 dev->irqs[i] = p->irq_build(pbm,
386 dev->bus->self,
387 irqs[i]);
388 } else {
389 /* If we get a bogus interrupt property, just
390 * record the raw value instead of punting.
391 */
392 dev->irqs[i] = irqs[i];
393 }
394 }
395 } 351 }
396} 352}
397 353
@@ -403,72 +359,32 @@ static int __init child_regs_nonstandard(struct linux_ebus_device *dev)
403 return 0; 359 return 0;
404} 360}
405 361
406void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev) 362static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev)
407{ 363{
408 struct linux_prom_registers *regs;
409 struct linux_ebus_child *child; 364 struct linux_ebus_child *child;
410 int *irqs; 365 struct of_device *op;
411 int i, n, len; 366 int i, len;
412 367
413 dev->prom_node = dp; 368 dev->prom_node = dp;
414 369
415 printk(" [%s", dp->name); 370 printk(" [%s", dp->name);
416 371
417 regs = of_get_property(dp, "reg", &len); 372 op = of_find_device_by_node(dp);
418 if (!regs) { 373 if (!op) {
419 dev->num_addrs = 0; 374 dev->num_addrs = 0;
420 goto probe_interrupts;
421 }
422
423 if (len % sizeof(struct linux_prom_registers)) {
424 prom_printf("UGH: proplen for %s was %d, need multiple of %d\n",
425 dev->prom_node->name, len,
426 (int)sizeof(struct linux_prom_registers));
427 prom_halt();
428 }
429 dev->num_addrs = len / sizeof(struct linux_prom_registers);
430
431 for (i = 0; i < dev->num_addrs; i++) {
432 /* XXX Learn how to interpret ebus ranges... -DaveM */
433 if (regs[i].which_io >= 0x10)
434 n = (regs[i].which_io - 0x10) >> 2;
435 else
436 n = regs[i].which_io;
437
438 dev->resource[i].start = dev->bus->self->resource[n].start;
439 dev->resource[i].start += (unsigned long)regs[i].phys_addr;
440 dev->resource[i].end =
441 (dev->resource[i].start + (unsigned long)regs[i].reg_size - 1UL);
442 dev->resource[i].flags = IORESOURCE_MEM;
443 dev->resource[i].name = dev->prom_node->name;
444 request_resource(&dev->bus->self->resource[n],
445 &dev->resource[i]);
446 }
447
448probe_interrupts:
449 for (i = 0; i < PROMINTR_MAX; i++)
450 dev->irqs[i] = PCI_IRQ_NONE;
451
452 irqs = of_get_property(dp, "interrupts", &len);
453 if (!irqs) {
454 dev->num_irqs = 0; 375 dev->num_irqs = 0;
455 } else { 376 } else {
456 dev->num_irqs = len / sizeof(irqs[0]); 377 (void) of_get_property(dp, "reg", &len);
457 for (i = 0; i < dev->num_irqs; i++) { 378 dev->num_addrs = len / sizeof(struct linux_prom_registers);
458 struct pci_pbm_info *pbm = dev->bus->parent; 379
459 struct pci_controller_info *p = pbm->parent; 380 for (i = 0; i < dev->num_addrs; i++)
460 381 memcpy(&dev->resource[i],
461 if (ebus_intmap_match(dev->bus, &regs[0], &irqs[i]) != -1) { 382 &op->resource[i],
462 dev->irqs[i] = p->irq_build(pbm, 383 sizeof(struct resource));
463 dev->bus->self, 384
464 irqs[i]); 385 dev->num_irqs = op->num_irqs;
465 } else { 386 for (i = 0; i < dev->num_irqs; i++)
466 /* If we get a bogus interrupt property, just 387 dev->irqs[i] = op->irqs[i];
467 * record the raw value instead of punting.
468 */
469 dev->irqs[i] = irqs[i];
470 }
471 }
472 } 388 }
473 389
474 dev->ofdev.node = dp; 390 dev->ofdev.node = dp;
@@ -490,7 +406,7 @@ probe_interrupts:
490 child->next = NULL; 406 child->next = NULL;
491 child->parent = dev; 407 child->parent = dev;
492 child->bus = dev->bus; 408 child->bus = dev->bus;
493 fill_ebus_child(dp, regs, child, 409 fill_ebus_child(dp, child,
494 child_regs_nonstandard(dev)); 410 child_regs_nonstandard(dev));
495 411
496 while ((dp = dp->sibling) != NULL) { 412 while ((dp = dp->sibling) != NULL) {
@@ -500,7 +416,7 @@ probe_interrupts:
500 child->next = NULL; 416 child->next = NULL;
501 child->parent = dev; 417 child->parent = dev;
502 child->bus = dev->bus; 418 child->bus = dev->bus;
503 fill_ebus_child(dp, regs, child, 419 fill_ebus_child(dp, child,
504 child_regs_nonstandard(dev)); 420 child_regs_nonstandard(dev));
505 } 421 }
506 } 422 }