powerpc/pmac/smp: Fix CPU hotplug crashes on some machines

On some machines that use i2c to synchronize the timebases (such
as PowerMac7,2/7,3 G5 machines), hotplug CPU would crash when
putting back a new CPU online due to the underlying i2c bus being
closed.

This uses the newly added bringup_done() callback to move the close
along with other housekeeping calls, and adds a CPU notifier to
re-open the i2c bus around subsequent hotplug operations
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent d7294445
...@@ -840,30 +840,68 @@ static void __devinit smp_core99_setup_cpu(int cpu_nr) ...@@ -840,30 +840,68 @@ static void __devinit smp_core99_setup_cpu(int cpu_nr)
/* Setup openpic */ /* Setup openpic */
mpic_setup_this_cpu(); mpic_setup_this_cpu();
}
if (cpu_nr == 0) { #ifdef CONFIG_HOTPLUG_CPU
#ifdef CONFIG_PPC64 static int smp_core99_cpu_notify(struct notifier_block *self,
extern void g5_phy_disable_cpu1(void); unsigned long action, void *hcpu)
{
int rc;
/* Close i2c bus if it was used for tb sync */ switch(action) {
case CPU_UP_PREPARE:
case CPU_UP_PREPARE_FROZEN:
/* Open i2c bus if it was used for tb sync */
if (pmac_tb_clock_chip_host) { if (pmac_tb_clock_chip_host) {
pmac_i2c_close(pmac_tb_clock_chip_host); rc = pmac_i2c_open(pmac_tb_clock_chip_host, 1);
pmac_tb_clock_chip_host = NULL; if (rc) {
pr_err("Failed to open i2c bus for time sync\n");
return notifier_from_errno(rc);
}
} }
break;
case CPU_ONLINE:
case CPU_UP_CANCELED:
/* Close i2c bus if it was used for tb sync */
if (pmac_tb_clock_chip_host)
pmac_i2c_close(pmac_tb_clock_chip_host);
break;
default:
break;
}
return NOTIFY_OK;
}
/* If we didn't start the second CPU, we must take static struct notifier_block __cpuinitdata smp_core99_cpu_nb = {
* it off the bus .notifier_call = smp_core99_cpu_notify,
*/ };
if (of_machine_is_compatible("MacRISC4") && #endif /* CONFIG_HOTPLUG_CPU */
num_online_cpus() < 2)
g5_phy_disable_cpu1();
#endif /* CONFIG_PPC64 */
if (ppc_md.progress) static void __init smp_core99_bringup_done(void)
ppc_md.progress("core99_setup_cpu 0 done", 0x349); {
#ifdef CONFIG_PPC64
extern void g5_phy_disable_cpu1(void);
/* Close i2c bus if it was used for tb sync */
if (pmac_tb_clock_chip_host)
pmac_i2c_close(pmac_tb_clock_chip_host);
/* If we didn't start the second CPU, we must take
* it off the bus.
*/
if (of_machine_is_compatible("MacRISC4") &&
num_online_cpus() < 2) {
set_cpu_present(1, false);
g5_phy_disable_cpu1();
} }
} #endif /* CONFIG_PPC64 */
#ifdef CONFIG_HOTPLUG_CPU
register_cpu_notifier(&smp_core99_cpu_nb);
#endif
if (ppc_md.progress)
ppc_md.progress("smp_core99_bringup_done", 0x349);
}
#ifdef CONFIG_HOTPLUG_CPU #ifdef CONFIG_HOTPLUG_CPU
...@@ -940,6 +978,7 @@ static void pmac_cpu_die(void) ...@@ -940,6 +978,7 @@ static void pmac_cpu_die(void)
struct smp_ops_t core99_smp_ops = { struct smp_ops_t core99_smp_ops = {
.message_pass = smp_mpic_message_pass, .message_pass = smp_mpic_message_pass,
.probe = smp_core99_probe, .probe = smp_core99_probe,
.bringup_done = smp_core99_bringup_done,
.kick_cpu = smp_core99_kick_cpu, .kick_cpu = smp_core99_kick_cpu,
.setup_cpu = smp_core99_setup_cpu, .setup_cpu = smp_core99_setup_cpu,
.give_timebase = smp_core99_give_timebase, .give_timebase = smp_core99_give_timebase,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment