aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2006-08-25 00:46:23 -0400
committerPaul Mackerras <paulus@samba.org>2006-08-30 00:31:03 -0400
commit006b64de607f895de2ba1e21d3179cddf059128f (patch)
treec4eb38d1a3fcb42336475ae261c6624d179308ed
parent7233593b7844c2db930594ee9c0c872a6900bfcc (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>
-rw-r--r--arch/powerpc/kernel/pci_64.c11
-rw-r--r--arch/powerpc/kernel/prom_parse.c17
-rw-r--r--include/asm-powerpc/prom.h4
3 files changed, 25 insertions, 7 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
642int of_irq_map_raw(struct device_node *parent, u32 *intspec, u32 *addr, 642int 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}
970EXPORT_SYMBOL_GPL(of_irq_map_pci); 979EXPORT_SYMBOL_GPL(of_irq_map_pci);
971#endif /* CONFIG_PCI */ 980#endif /* CONFIG_PCI */
diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h
index b095a285c84b..d0fa1b9aed35 100644
--- a/include/asm-powerpc/prom.h
+++ b/include/asm-powerpc/prom.h
@@ -276,6 +276,7 @@ extern void of_irq_map_init(unsigned int flags);
276 * of_irq_map_raw - Low level interrupt tree parsing 276 * of_irq_map_raw - Low level interrupt tree parsing
277 * @parent: the device interrupt parent 277 * @parent: the device interrupt parent
278 * @intspec: interrupt specifier ("interrupts" property of the device) 278 * @intspec: interrupt specifier ("interrupts" property of the device)
279 * @ointsize: size of the passed in interrupt specifier
279 * @addr: address specifier (start of "reg" property of the device) 280 * @addr: address specifier (start of "reg" property of the device)
280 * @out_irq: structure of_irq filled by this function 281 * @out_irq: structure of_irq filled by this function
281 * 282 *
@@ -288,7 +289,8 @@ extern void of_irq_map_init(unsigned int flags);
288 * 289 *
289 */ 290 */
290 291
291extern int of_irq_map_raw(struct device_node *parent, u32 *intspec, u32 *addr, 292extern int of_irq_map_raw(struct device_node *parent, u32 *intspec,
293 u32 ointsize, u32 *addr,
292 struct of_irq *out_irq); 294 struct of_irq *out_irq);
293 295
294 296