[PATCH] ppc64: Fix g5 hw timebase sync

The hardware sync of the timebase on SMP G5s uses a black magic
incantation to the i2c clock chip that was inspired from what Darwin
does.

However, this was an earlier version of Darwin that was ... buggy !
heh. This causes the latest models to break though when starting SMP,
so it's worth fixing.

Here's a new version of the incantation based on careful transcription
of the said incantations as found in the latest version of apple's
temple.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by Benjamin Herrenschmidt and committed by Linus Torvalds f10d20c1 e16fa6b9

+21 -7
+21 -7
arch/ppc64/kernel/pmac_smp.c
··· 68 68 69 69 static void (*pmac_tb_freeze)(int freeze); 70 70 static struct device_node *pmac_tb_clock_chip_host; 71 + static u8 pmac_tb_pulsar_addr; 71 72 static DEFINE_SPINLOCK(timebase_lock); 72 73 static unsigned long timebase; 73 74 ··· 107 106 u8 data; 108 107 int rc; 109 108 110 - /* Strangely, the device-tree says address is 0xd2, but darwin 111 - * accesses 0xd0 ... 112 - */ 113 109 pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_combined); 114 110 rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, 115 - 0xd4 | pmac_low_i2c_read, 111 + pmac_tb_pulsar_addr | pmac_low_i2c_read, 116 112 0x2e, &data, 1); 117 113 if (rc != 0) 118 114 goto bail; ··· 118 120 119 121 pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_stdsub); 120 122 rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, 121 - 0xd4 | pmac_low_i2c_write, 123 + pmac_tb_pulsar_addr | pmac_low_i2c_write, 122 124 0x2e, &data, 1); 123 125 bail: 124 126 if (rc != 0) { ··· 183 185 if (ncpus <= 1) 184 186 return 1; 185 187 188 + /* HW sync only on these platforms */ 189 + if (!machine_is_compatible("PowerMac7,2") && 190 + !machine_is_compatible("PowerMac7,3") && 191 + !machine_is_compatible("RackMac3,1")) 192 + goto nohwsync; 193 + 186 194 /* Look for the clock chip */ 187 195 for (cc = NULL; (cc = of_find_node_by_name(cc, "i2c-hwclock")) != NULL;) { 188 196 struct device_node *p = of_get_parent(cc); ··· 202 198 goto next; 203 199 switch (*reg) { 204 200 case 0xd2: 205 - pmac_tb_freeze = smp_core99_cypress_tb_freeze; 206 - printk(KERN_INFO "Timebase clock is Cypress chip\n"); 201 + if (device_is_compatible(cc, "pulsar-legacy-slewing")) { 202 + pmac_tb_freeze = smp_core99_pulsar_tb_freeze; 203 + pmac_tb_pulsar_addr = 0xd2; 204 + printk(KERN_INFO "Timebase clock is Pulsar chip\n"); 205 + } else if (device_is_compatible(cc, "cy28508")) { 206 + pmac_tb_freeze = smp_core99_cypress_tb_freeze; 207 + printk(KERN_INFO "Timebase clock is Cypress chip\n"); 208 + } 207 209 break; 208 210 case 0xd4: 209 211 pmac_tb_freeze = smp_core99_pulsar_tb_freeze; 212 + pmac_tb_pulsar_addr = 0xd4; 210 213 printk(KERN_INFO "Timebase clock is Pulsar chip\n"); 211 214 break; 212 215 } ··· 221 210 pmac_tb_clock_chip_host = p; 222 211 smp_ops->give_timebase = smp_core99_give_timebase; 223 212 smp_ops->take_timebase = smp_core99_take_timebase; 213 + of_node_put(cc); 214 + of_node_put(p); 224 215 break; 225 216 } 226 217 next: 227 218 of_node_put(p); 228 219 } 229 220 221 + nohwsync: 230 222 mpic_request_ipis(); 231 223 232 224 return ncpus;