diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2005-05-22 20:03:52 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-05-22 20:34:42 -0400 |
commit | 1263cc67c09bc7f913a6877f3ba0427f0b76617e (patch) | |
tree | 5b713315560487f8c288820b17061fe27016c2cc | |
parent | b5c44c2147a447f77e07fecdb087ae288e1f4e40 (diff) |
[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>
-rw-r--r-- | arch/ppc64/kernel/prom_init.c | 44 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-keywest.c | 5 |
2 files changed, 48 insertions, 1 deletions
diff --git a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c index 35ec42de962e..6f79b7b9b445 100644 --- a/arch/ppc64/kernel/prom_init.c +++ b/arch/ppc64/kernel/prom_init.c | |||
@@ -1750,7 +1750,44 @@ static void __init flatten_device_tree(void) | |||
1750 | prom_printf("Device tree struct 0x%x -> 0x%x\n", | 1750 | prom_printf("Device tree struct 0x%x -> 0x%x\n", |
1751 | RELOC(dt_struct_start), RELOC(dt_struct_end)); | 1751 | RELOC(dt_struct_start), RELOC(dt_struct_end)); |
1752 | 1752 | ||
1753 | } | 1753 | } |
1754 | |||
1755 | |||
1756 | static void __init fixup_device_tree(void) | ||
1757 | { | ||
1758 | unsigned long offset = reloc_offset(); | ||
1759 | phandle u3, i2c, mpic; | ||
1760 | u32 u3_rev; | ||
1761 | u32 interrupts[2]; | ||
1762 | u32 parent; | ||
1763 | |||
1764 | /* Some G5s have a missing interrupt definition, fix it up here */ | ||
1765 | u3 = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000")); | ||
1766 | if ((long)u3 <= 0) | ||
1767 | return; | ||
1768 | i2c = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/i2c@f8001000")); | ||
1769 | if ((long)i2c <= 0) | ||
1770 | return; | ||
1771 | mpic = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/mpic@f8040000")); | ||
1772 | if ((long)mpic <= 0) | ||
1773 | return; | ||
1774 | |||
1775 | /* check if proper rev of u3 */ | ||
1776 | if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev)) <= 0) | ||
1777 | return; | ||
1778 | if (u3_rev != 0x35) | ||
1779 | return; | ||
1780 | /* does it need fixup ? */ | ||
1781 | if (prom_getproplen(i2c, "interrupts") > 0) | ||
1782 | return; | ||
1783 | /* interrupt on this revision of u3 is number 0 and level */ | ||
1784 | interrupts[0] = 0; | ||
1785 | interrupts[1] = 1; | ||
1786 | prom_setprop(i2c, "interrupts", &interrupts, sizeof(interrupts)); | ||
1787 | parent = (u32)mpic; | ||
1788 | prom_setprop(i2c, "interrupt-parent", &parent, sizeof(parent)); | ||
1789 | } | ||
1790 | |||
1754 | 1791 | ||
1755 | static void __init prom_find_boot_cpu(void) | 1792 | static void __init prom_find_boot_cpu(void) |
1756 | { | 1793 | { |
@@ -1920,6 +1957,11 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, unsigned long | |||
1920 | } | 1957 | } |
1921 | 1958 | ||
1922 | /* | 1959 | /* |
1960 | * Fixup any known bugs in the device-tree | ||
1961 | */ | ||
1962 | fixup_device_tree(); | ||
1963 | |||
1964 | /* | ||
1923 | * Now finally create the flattened device-tree | 1965 | * Now finally create the flattened device-tree |
1924 | */ | 1966 | */ |
1925 | prom_printf("copying OF device tree ...\n"); | 1967 | prom_printf("copying OF device tree ...\n"); |
diff --git a/drivers/i2c/busses/i2c-keywest.c b/drivers/i2c/busses/i2c-keywest.c index dd0d4c463146..867d443e7133 100644 --- a/drivers/i2c/busses/i2c-keywest.c +++ b/drivers/i2c/busses/i2c-keywest.c | |||
@@ -516,6 +516,11 @@ create_iface(struct device_node *np, struct device *dev) | |||
516 | u32 *psteps, *prate; | 516 | u32 *psteps, *prate; |
517 | int rc; | 517 | int rc; |
518 | 518 | ||
519 | if (np->n_intrs < 1 || np->n_addrs < 1) { | ||
520 | printk(KERN_ERR "%s: Missing interrupt or address !\n", | ||
521 | np->full_name); | ||
522 | return -ENODEV; | ||
523 | } | ||
519 | if (pmac_low_i2c_lock(np)) | 524 | if (pmac_low_i2c_lock(np)) |
520 | return -ENODEV; | 525 | return -ENODEV; |
521 | 526 | ||