aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/of_device.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/of_device.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/of_device.c')
-rw-r--r--arch/sparc64/kernel/of_device.c194
1 files changed, 188 insertions, 6 deletions
diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c
index 9812cfa6dd36..3670dc8a7d5f 100644
--- a/arch/sparc64/kernel/of_device.c
+++ b/arch/sparc64/kernel/of_device.c
@@ -146,6 +146,26 @@ void of_iounmap(void __iomem *base, unsigned long size)
146} 146}
147EXPORT_SYMBOL(of_iounmap); 147EXPORT_SYMBOL(of_iounmap);
148 148
149static 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
157struct 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}
167EXPORT_SYMBOL(of_find_device_by_node);
168
149#ifdef CONFIG_PCI 169#ifdef CONFIG_PCI
150struct bus_type isa_bus_type = { 170struct bus_type isa_bus_type = {
151 .name = "isa", 171 .name = "isa",
@@ -261,7 +281,6 @@ static unsigned int of_bus_default_get_flags(u32 *addr)
261 return IORESOURCE_MEM; 281 return IORESOURCE_MEM;
262} 282}
263 283
264
265/* 284/*
266 * PCI bus specific translator 285 * PCI bus specific translator
267 */ 286 */
@@ -594,12 +613,171 @@ static void __init build_device_resources(struct of_device *op,
594 } 613 }
595} 614}
596 615
616static struct device_node * __init
617apply_interrupt_map(struct device_node *dp, struct device_node *pp,
618 u32 *imap, int imlen, u32 *imask,
619 unsigned int *irq_p)
620{
621 struct device_node *cp;
622 unsigned int irq = *irq_p;
623 struct of_bus *bus;
624 phandle handle;
625 u32 *reg;
626 int na, num_reg, i;
627
628 bus = of_match_bus(pp);
629 bus->count_cells(dp, &na, NULL);
630
631 reg = of_get_property(dp, "reg", &num_reg);
632 if (!reg || !num_reg)
633 return NULL;
634
635 imlen /= ((na + 3) * 4);
636 handle = 0;
637 for (i = 0; i < imlen; i++) {
638 int j;
639
640 for (j = 0; j < na; j++) {
641 if ((reg[j] & imask[j]) != imap[j])
642 goto next;
643 }
644 if (imap[na] == irq) {
645 handle = imap[na + 1];
646 irq = imap[na + 2];
647 break;
648 }
649
650 next:
651 imap += (na + 3);
652 }
653 if (i == imlen)
654 return NULL;
655
656 *irq_p = irq;
657 cp = of_find_node_by_phandle(handle);
658
659 return cp;
660}
661
662static unsigned int __init pci_irq_swizzle(struct device_node *dp,
663 struct device_node *pp,
664 unsigned int irq)
665{
666 struct linux_prom_pci_registers *regs;
667 unsigned int devfn, slot, ret;
668
669 if (irq < 1 || irq > 4)
670 return irq;
671
672 regs = of_get_property(dp, "reg", NULL);
673 if (!regs)
674 return irq;
675
676 devfn = (regs->phys_hi >> 8) & 0xff;
677 slot = (devfn >> 3) & 0x1f;
678
679 ret = ((irq - 1 + (slot & 3)) & 3) + 1;
680
681 return ret;
682}
683
684static unsigned int __init build_one_device_irq(struct of_device *op,
685 struct device *parent,
686 unsigned int irq)
687{
688 struct device_node *dp = op->node;
689 struct device_node *pp, *ip;
690 unsigned int orig_irq = irq;
691
692 if (irq == 0xffffffff)
693 return irq;
694
695 if (dp->irq_trans) {
696 irq = dp->irq_trans->irq_build(dp, irq,
697 dp->irq_trans->data);
698#if 1
699 printk("%s: direct translate %x --> %x\n",
700 dp->full_name, orig_irq, irq);
701#endif
702 return irq;
703 }
704
705 /* Something more complicated. Walk up to the root, applying
706 * interrupt-map or bus specific translations, until we hit
707 * an IRQ translator.
708 *
709 * If we hit a bus type or situation we cannot handle, we
710 * stop and assume that the original IRQ number was in a
711 * format which has special meaning to it's immediate parent.
712 */
713 pp = dp->parent;
714 ip = NULL;
715 while (pp) {
716 void *imap, *imsk;
717 int imlen;
718
719 imap = of_get_property(pp, "interrupt-map", &imlen);
720 imsk = of_get_property(pp, "interrupt-map-mask", NULL);
721 if (imap && imsk) {
722 struct device_node *iret;
723 int this_orig_irq = irq;
724
725 iret = apply_interrupt_map(dp, pp,
726 imap, imlen, imsk,
727 &irq);
728#if 1
729 printk("%s: Apply [%s:%x] imap --> [%s:%x]\n",
730 op->node->full_name,
731 pp->full_name, this_orig_irq,
732 (iret ? iret->full_name : "NULL"), irq);
733#endif
734 if (!iret)
735 break;
736
737 if (iret->irq_trans) {
738 ip = iret;
739 break;
740 }
741 } else {
742 if (!strcmp(pp->type, "pci") ||
743 !strcmp(pp->type, "pciex")) {
744 unsigned int this_orig_irq = irq;
745
746 irq = pci_irq_swizzle(dp, pp, irq);
747#if 1
748 printk("%s: PCI swizzle [%s] %x --> %x\n",
749 op->node->full_name,
750 pp->full_name, this_orig_irq, irq);
751#endif
752 }
753
754 if (pp->irq_trans) {
755 ip = pp;
756 break;
757 }
758 }
759 dp = pp;
760 pp = pp->parent;
761 }
762 if (!ip)
763 return orig_irq;
764
765 irq = ip->irq_trans->irq_build(op->node, irq,
766 ip->irq_trans->data);
767#if 1
768 printk("%s: Apply IRQ trans [%s] %x --> %x\n",
769 op->node->full_name, ip->full_name, orig_irq, irq);
770#endif
771
772 return irq;
773}
774
597static struct of_device * __init scan_one_device(struct device_node *dp, 775static struct of_device * __init scan_one_device(struct device_node *dp,
598 struct device *parent) 776 struct device *parent)
599{ 777{
600 struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL); 778 struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL);
601 unsigned int *irq; 779 unsigned int *irq;
602 int len; 780 int len, i;
603 781
604 if (!op) 782 if (!op)
605 return NULL; 783 return NULL;
@@ -613,12 +791,16 @@ static struct of_device * __init scan_one_device(struct device_node *dp,
613 op->portid = of_getintprop_default(dp, "portid", -1); 791 op->portid = of_getintprop_default(dp, "portid", -1);
614 792
615 irq = of_get_property(dp, "interrupts", &len); 793 irq = of_get_property(dp, "interrupts", &len);
616 if (irq) 794 if (irq) {
617 op->irq = *irq; 795 memcpy(op->irqs, irq, len);
618 else 796 op->num_irqs = len / 4;
619 op->irq = 0xffffffff; 797 } else {
798 op->num_irqs = 0;
799 }
620 800
621 build_device_resources(op, parent); 801 build_device_resources(op, parent);
802 for (i = 0; i < op->num_irqs; i++)
803 op->irqs[i] = build_one_device_irq(op, parent, op->irqs[i]);
622 804
623 op->dev.parent = parent; 805 op->dev.parent = parent;
624 op->dev.bus = &of_bus_type; 806 op->dev.bus = &of_bus_type;