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 | |
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')
-rw-r--r-- | arch/powerpc/kernel/pci_64.c | 11 | ||||
-rw-r--r-- | arch/powerpc/kernel/prom_parse.c | 17 |
2 files changed, 22 insertions, 6 deletions
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index 2fce7738e9e2..138134c8c17d 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c | |||
@@ -1289,6 +1289,9 @@ int pci_read_irq_line(struct pci_dev *pci_dev) | |||
1289 | 1289 | ||
1290 | DBG("Try to map irq for %s...\n", pci_name(pci_dev)); | 1290 | DBG("Try to map irq for %s...\n", pci_name(pci_dev)); |
1291 | 1291 | ||
1292 | #ifdef DEBUG | ||
1293 | memset(&oirq, 0xff, sizeof(oirq)); | ||
1294 | #endif | ||
1292 | /* Try to get a mapping from the device-tree */ | 1295 | /* Try to get a mapping from the device-tree */ |
1293 | if (of_irq_map_pci(pci_dev, &oirq)) { | 1296 | if (of_irq_map_pci(pci_dev, &oirq)) { |
1294 | u8 line, pin; | 1297 | u8 line, pin; |
@@ -1314,8 +1317,9 @@ int pci_read_irq_line(struct pci_dev *pci_dev) | |||
1314 | if (virq != NO_IRQ) | 1317 | if (virq != NO_IRQ) |
1315 | set_irq_type(virq, IRQ_TYPE_LEVEL_LOW); | 1318 | set_irq_type(virq, IRQ_TYPE_LEVEL_LOW); |
1316 | } else { | 1319 | } else { |
1317 | DBG(" -> got one, spec %d cells (0x%08x...) on %s\n", | 1320 | DBG(" -> got one, spec %d cells (0x%08x 0x%08x...) on %s\n", |
1318 | oirq.size, oirq.specifier[0], oirq.controller->full_name); | 1321 | oirq.size, oirq.specifier[0], oirq.specifier[1], |
1322 | oirq.controller->full_name); | ||
1319 | 1323 | ||
1320 | virq = irq_create_of_mapping(oirq.controller, oirq.specifier, | 1324 | virq = irq_create_of_mapping(oirq.controller, oirq.specifier, |
1321 | oirq.size); | 1325 | oirq.size); |
@@ -1324,6 +1328,9 @@ int pci_read_irq_line(struct pci_dev *pci_dev) | |||
1324 | DBG(" -> failed to map !\n"); | 1328 | DBG(" -> failed to map !\n"); |
1325 | return -1; | 1329 | return -1; |
1326 | } | 1330 | } |
1331 | |||
1332 | DBG(" -> mapped to linux irq %d\n", virq); | ||
1333 | |||
1327 | pci_dev->irq = virq; | 1334 | pci_dev->irq = virq; |
1328 | pci_write_config_byte(pci_dev, PCI_INTERRUPT_LINE, virq); | 1335 | pci_write_config_byte(pci_dev, PCI_INTERRUPT_LINE, virq); |
1329 | 1336 | ||
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 */ |