[PATCH] ppc64: Fix booting on latest G5 models
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Mon, 23 May 2005 00:03:52 +0000 (10:03 +1000)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Mon, 23 May 2005 00:34:42 +0000 (17:34 -0700)
The latest speedbumped Apple G5 models have a "bug" in the Open Firmware
device tree that lacks the proper interrupt routing information for the
northbridge i2c controller.  Apple's driver silently falls back into a
sub-optimal "polled" mode (heh, maybe they didn't even notice the bug
because of that :), our driver didn't properly check and crashes :(

This patch fixes our driver to not crash, and adds code to the
prom_init() OF trampoline code that detects the "bug" and adds the
missing information back for this chipset revision.  This fixes booting
and thermal control on these models.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
arch/ppc64/kernel/prom_init.c
drivers/i2c/busses/i2c-keywest.c

index 35ec42de962e2f42d331e72f3a09cac678e6486a..6f79b7b9b445e8669411e34b48c1ea8ce5135965 100644 (file)
@@ -1750,7 +1750,44 @@ static void __init flatten_device_tree(void)
        prom_printf("Device tree struct  0x%x -> 0x%x\n",
                    RELOC(dt_struct_start), RELOC(dt_struct_end));
 
- }
+}
+
+
+static void __init fixup_device_tree(void)
+{
+       unsigned long offset = reloc_offset();
+       phandle u3, i2c, mpic;
+       u32 u3_rev;
+       u32 interrupts[2];
+       u32 parent;
+
+       /* Some G5s have a missing interrupt definition, fix it up here */
+       u3 = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000"));
+       if ((long)u3 <= 0)
+               return;
+       i2c = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/i2c@f8001000"));
+       if ((long)i2c <= 0)
+               return;
+       mpic = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/mpic@f8040000"));
+       if ((long)mpic <= 0)
+               return;
+
+       /* check if proper rev of u3 */
+       if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev)) <= 0)
+               return;
+       if (u3_rev != 0x35)
+               return;
+       /* does it need fixup ? */
+       if (prom_getproplen(i2c, "interrupts") > 0)
+               return;
+       /* interrupt on this revision of u3 is number 0 and level */
+       interrupts[0] = 0;
+       interrupts[1] = 1;
+       prom_setprop(i2c, "interrupts", &interrupts, sizeof(interrupts));
+       parent = (u32)mpic;
+       prom_setprop(i2c, "interrupt-parent", &parent, sizeof(parent));
+}
+
 
 static void __init prom_find_boot_cpu(void)
 {
@@ -1919,6 +1956,11 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, unsigned long
                        PTRRELOC(&prom_tce_alloc_end), sizeof(RELOC(prom_tce_alloc_end)));
        }
 
+       /*
+        * Fixup any known bugs in the device-tree
+        */
+       fixup_device_tree();
+
        /*
         * Now finally create the flattened device-tree
         */
index dd0d4c463146be33d9469c2f434ddbed4d96d615..867d443e7133f03c1f8999e4fe25e38f76f9419f 100644 (file)
@@ -516,6 +516,11 @@ create_iface(struct device_node *np, struct device *dev)
        u32 *psteps, *prate;
        int rc;
 
+       if (np->n_intrs < 1 || np->n_addrs < 1) {
+               printk(KERN_ERR "%s: Missing interrupt or address !\n",
+                      np->full_name);
+               return -ENODEV;
+       }
        if (pmac_low_i2c_lock(np))
                return -ENODEV;