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: Benjamin Herrenschmidt <benh@kernel.crashing.org>
This commit is contained in:
parent
d72944457b
commit
734796f123
|
@ -840,30 +840,68 @@ static void __devinit smp_core99_setup_cpu(int cpu_nr)
|
|||
|
||||
/* Setup openpic */
|
||||
mpic_setup_this_cpu();
|
||||
|
||||
if (cpu_nr == 0) {
|
||||
#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);
|
||||
pmac_tb_clock_chip_host = NULL;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
g5_phy_disable_cpu1();
|
||||
#endif /* CONFIG_PPC64 */
|
||||
|
||||
if (ppc_md.progress)
|
||||
ppc_md.progress("core99_setup_cpu 0 done", 0x349);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
static int smp_core99_cpu_notify(struct notifier_block *self,
|
||||
unsigned long action, void *hcpu)
|
||||
{
|
||||
int rc;
|
||||
|
||||
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) {
|
||||
rc = pmac_i2c_open(pmac_tb_clock_chip_host, 1);
|
||||
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;
|
||||
}
|
||||
|
||||
static struct notifier_block __cpuinitdata smp_core99_cpu_nb = {
|
||||
.notifier_call = smp_core99_cpu_notify,
|
||||
};
|
||||
#endif /* CONFIG_HOTPLUG_CPU */
|
||||
|
||||
static void __init smp_core99_bringup_done(void)
|
||||
{
|
||||
#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
|
||||
|
||||
|
@ -940,6 +978,7 @@ static void pmac_cpu_die(void)
|
|||
struct smp_ops_t core99_smp_ops = {
|
||||
.message_pass = smp_mpic_message_pass,
|
||||
.probe = smp_core99_probe,
|
||||
.bringup_done = smp_core99_bringup_done,
|
||||
.kick_cpu = smp_core99_kick_cpu,
|
||||
.setup_cpu = smp_core99_setup_cpu,
|
||||
.give_timebase = smp_core99_give_timebase,
|
||||
|
|
Loading…
Reference in New Issue