aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/ebus.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2006-06-29 18:07:37 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-06-29 19:37:38 -0400
commit2b1e59787198e75fb2ffb3bb4fb247da1c55ac12 (patch)
tree96d74048849b310135e0c79f663b16c52186caa5 /arch/sparc64/kernel/ebus.c
parentc3a8b85f5ac2c21f4ef75e87bfe55ee7a753ffcf (diff)
[SPARC64]: of_device layer IRQ resolution
Do IRQ determination generically by parsing the PROM properties, and using IRQ controller drivers for final resolution. One immediate positive effect is that all of the IRQ frobbing in the EBUS, ISA, and PCI controller layers has been eliminated. We just look up the of_device and use the properly computed value. The PCI controller irq_build() routines are gone and no longer used. Unfortunately sbus_build_irq() has to remain as there is a direct reference to this in the sunzilog driver. That can be killed off once the sparc32 side of this is written and the sunzilog driver is transformed into an "of" bus driver. Signed-off-by: David S. Miller <davem@davemloft.net>
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 }