diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2006-08-25 00:46:23 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2006-08-30 00:31:03 -0400 |
commit | 006b64de607f895de2ba1e21d3179cddf059128f (patch) | |
tree | c4eb38d1a3fcb42336475ae261c6624d179308ed /arch/powerpc/kernel/prom_parse.c | |
parent | 7233593b7844c2db930594ee9c0c872a6900bfcc (diff) |
[POWERPC] Make OF irq map code detect more error cases
Device-tree bugs on js20 with some versions of SLOF were causing the
interrupt for IDE to not be parsed correctly and fail to boot. This
patch adds a bit more sanity checking to the parser to detect some of
those errors and fail instead of returning bogus information. The
powerpc PCI code can then trigger a fallback that works on those
machines.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/kernel/prom_parse.c')
-rw-r--r-- | arch/powerpc/kernel/prom_parse.c | 17 |
1 files changed, 13 insertions, 4 deletions
diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c index 11052c212ad5..a10825a5dfe6 100644 --- a/arch/powerpc/kernel/prom_parse.c +++ b/arch/powerpc/kernel/prom_parse.c | |||
@@ -639,14 +639,17 @@ void of_irq_map_init(unsigned int flags) | |||
639 | 639 | ||
640 | } | 640 | } |
641 | 641 | ||
642 | int of_irq_map_raw(struct device_node *parent, u32 *intspec, u32 *addr, | 642 | int of_irq_map_raw(struct device_node *parent, u32 *intspec, u32 ointsize, |
643 | struct of_irq *out_irq) | 643 | u32 *addr, struct of_irq *out_irq) |
644 | { | 644 | { |
645 | struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL; | 645 | struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL; |
646 | u32 *tmp, *imap, *imask; | 646 | u32 *tmp, *imap, *imask; |
647 | u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0; | 647 | u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0; |
648 | int imaplen, match, i; | 648 | int imaplen, match, i; |
649 | 649 | ||
650 | DBG("of_irq_map_raw: par=%s,intspec=[0x%08x 0x%08x...],ointsize=%d\n", | ||
651 | parent->full_name, intspec[0], intspec[1], ointsize); | ||
652 | |||
650 | ipar = of_node_get(parent); | 653 | ipar = of_node_get(parent); |
651 | 654 | ||
652 | /* First get the #interrupt-cells property of the current cursor | 655 | /* First get the #interrupt-cells property of the current cursor |
@@ -670,6 +673,9 @@ int of_irq_map_raw(struct device_node *parent, u32 *intspec, u32 *addr, | |||
670 | 673 | ||
671 | DBG("of_irq_map_raw: ipar=%s, size=%d\n", ipar->full_name, intsize); | 674 | DBG("of_irq_map_raw: ipar=%s, size=%d\n", ipar->full_name, intsize); |
672 | 675 | ||
676 | if (ointsize != intsize) | ||
677 | return -EINVAL; | ||
678 | |||
673 | /* Look for this #address-cells. We have to implement the old linux | 679 | /* Look for this #address-cells. We have to implement the old linux |
674 | * trick of looking for the parent here as some device-trees rely on it | 680 | * trick of looking for the parent here as some device-trees rely on it |
675 | */ | 681 | */ |
@@ -875,12 +881,15 @@ int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq | |||
875 | } | 881 | } |
876 | intsize = *tmp; | 882 | intsize = *tmp; |
877 | 883 | ||
884 | DBG(" intsize=%d intlen=%d\n", intsize, intlen); | ||
885 | |||
878 | /* Check index */ | 886 | /* Check index */ |
879 | if ((index + 1) * intsize > intlen) | 887 | if ((index + 1) * intsize > intlen) |
880 | return -EINVAL; | 888 | return -EINVAL; |
881 | 889 | ||
882 | /* Get new specifier and map it */ | 890 | /* Get new specifier and map it */ |
883 | res = of_irq_map_raw(p, intspec + index * intsize, addr, out_irq); | 891 | res = of_irq_map_raw(p, intspec + index * intsize, intsize, |
892 | addr, out_irq); | ||
884 | of_node_put(p); | 893 | of_node_put(p); |
885 | return res; | 894 | return res; |
886 | } | 895 | } |
@@ -965,7 +974,7 @@ int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq) | |||
965 | laddr[0] = (pdev->bus->number << 16) | 974 | laddr[0] = (pdev->bus->number << 16) |
966 | | (pdev->devfn << 8); | 975 | | (pdev->devfn << 8); |
967 | laddr[1] = laddr[2] = 0; | 976 | laddr[1] = laddr[2] = 0; |
968 | return of_irq_map_raw(ppnode, &lspec, laddr, out_irq); | 977 | return of_irq_map_raw(ppnode, &lspec, 1, laddr, out_irq); |
969 | } | 978 | } |
970 | EXPORT_SYMBOL_GPL(of_irq_map_pci); | 979 | EXPORT_SYMBOL_GPL(of_irq_map_pci); |
971 | #endif /* CONFIG_PCI */ | 980 | #endif /* CONFIG_PCI */ |