Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1263cc67 authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Linus Torvalds
Browse files

[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: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent b5c44c21
Loading
Loading
Loading
Loading
+43 −1
Original line number Original line Diff line number Diff line
@@ -1752,6 +1752,43 @@ static void __init flatten_device_tree(void)


}
}



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)
static void __init prom_find_boot_cpu(void)
{
{
	unsigned long offset = reloc_offset();
	unsigned long offset = reloc_offset();
@@ -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)));
			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
	 * Now finally create the flattened device-tree
	 */
	 */
+5 −0
Original line number Original line Diff line number Diff line
@@ -516,6 +516,11 @@ create_iface(struct device_node *np, struct device *dev)
	u32 *psteps, *prate;
	u32 *psteps, *prate;
	int rc;
	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))
	if (pmac_low_i2c_lock(np))
		return -ENODEV;
		return -ENODEV;