[PATCH] ppc64: Fix booting on latest G5 models
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>
This commit is contained in:
parent
b5c44c2147
commit
1263cc67c0
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue