diff options
| author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2011-03-07 21:54:50 -0500 |
|---|---|---|
| committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2011-04-01 00:37:31 -0400 |
| commit | 734796f12351f9a0f38c47b981414f82d852f222 (patch) | |
| tree | 6a159233b7ab08b420a59e518ce2b99bb2002b07 /arch/powerpc | |
| parent | d72944457bb7d5c4be43aa1b741cb93c69484c20 (diff) | |
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>
Diffstat (limited to 'arch/powerpc')
| -rw-r--r-- | arch/powerpc/platforms/powermac/smp.c | 71 |
1 files changed, 55 insertions, 16 deletions
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index 837989e72ca1..74a43c652041 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c | |||
| @@ -840,30 +840,68 @@ static void __devinit smp_core99_setup_cpu(int cpu_nr) | |||
| 840 | 840 | ||
| 841 | /* Setup openpic */ | 841 | /* Setup openpic */ |
| 842 | mpic_setup_this_cpu(); | 842 | mpic_setup_this_cpu(); |
| 843 | } | ||
| 843 | 844 | ||
| 844 | if (cpu_nr == 0) { | 845 | #ifdef CONFIG_HOTPLUG_CPU |
| 845 | #ifdef CONFIG_PPC64 | 846 | static int smp_core99_cpu_notify(struct notifier_block *self, |
| 846 | extern void g5_phy_disable_cpu1(void); | 847 | unsigned long action, void *hcpu) |
| 848 | { | ||
| 849 | int rc; | ||
| 847 | 850 | ||
| 848 | /* Close i2c bus if it was used for tb sync */ | 851 | switch(action) { |
| 852 | case CPU_UP_PREPARE: | ||
| 853 | case CPU_UP_PREPARE_FROZEN: | ||
| 854 | /* Open i2c bus if it was used for tb sync */ | ||
| 849 | if (pmac_tb_clock_chip_host) { | 855 | if (pmac_tb_clock_chip_host) { |
| 850 | pmac_i2c_close(pmac_tb_clock_chip_host); | 856 | rc = pmac_i2c_open(pmac_tb_clock_chip_host, 1); |
| 851 | pmac_tb_clock_chip_host = NULL; | 857 | if (rc) { |
| 858 | pr_err("Failed to open i2c bus for time sync\n"); | ||
| 859 | return notifier_from_errno(rc); | ||
| 860 | } | ||
| 852 | } | 861 | } |
| 862 | break; | ||
| 863 | case CPU_ONLINE: | ||
| 864 | case CPU_UP_CANCELED: | ||
| 865 | /* Close i2c bus if it was used for tb sync */ | ||
| 866 | if (pmac_tb_clock_chip_host) | ||
| 867 | pmac_i2c_close(pmac_tb_clock_chip_host); | ||
| 868 | break; | ||
| 869 | default: | ||
| 870 | break; | ||
| 871 | } | ||
| 872 | return NOTIFY_OK; | ||
| 873 | } | ||
| 853 | 874 | ||
| 854 | /* If we didn't start the second CPU, we must take | 875 | static struct notifier_block __cpuinitdata smp_core99_cpu_nb = { |
| 855 | * it off the bus | 876 | .notifier_call = smp_core99_cpu_notify, |
| 856 | */ | 877 | }; |
| 857 | if (of_machine_is_compatible("MacRISC4") && | 878 | #endif /* CONFIG_HOTPLUG_CPU */ |
| 858 | num_online_cpus() < 2) | ||
| 859 | g5_phy_disable_cpu1(); | ||
| 860 | #endif /* CONFIG_PPC64 */ | ||
| 861 | 879 | ||
| 862 | if (ppc_md.progress) | 880 | static void __init smp_core99_bringup_done(void) |
| 863 | ppc_md.progress("core99_setup_cpu 0 done", 0x349); | 881 | { |
| 882 | #ifdef CONFIG_PPC64 | ||
| 883 | extern void g5_phy_disable_cpu1(void); | ||
| 884 | |||
| 885 | /* Close i2c bus if it was used for tb sync */ | ||
| 886 | if (pmac_tb_clock_chip_host) | ||
| 887 | pmac_i2c_close(pmac_tb_clock_chip_host); | ||
| 888 | |||
| 889 | /* If we didn't start the second CPU, we must take | ||
| 890 | * it off the bus. | ||
| 891 | */ | ||
| 892 | if (of_machine_is_compatible("MacRISC4") && | ||
| 893 | num_online_cpus() < 2) { | ||
| 894 | set_cpu_present(1, false); | ||
| 895 | g5_phy_disable_cpu1(); | ||
| 864 | } | 896 | } |
| 865 | } | 897 | #endif /* CONFIG_PPC64 */ |
| 866 | 898 | ||
| 899 | #ifdef CONFIG_HOTPLUG_CPU | ||
| 900 | register_cpu_notifier(&smp_core99_cpu_nb); | ||
| 901 | #endif | ||
| 902 | if (ppc_md.progress) | ||
| 903 | ppc_md.progress("smp_core99_bringup_done", 0x349); | ||
| 904 | } | ||
| 867 | 905 | ||
| 868 | #ifdef CONFIG_HOTPLUG_CPU | 906 | #ifdef CONFIG_HOTPLUG_CPU |
| 869 | 907 | ||
| @@ -940,6 +978,7 @@ static void pmac_cpu_die(void) | |||
| 940 | struct smp_ops_t core99_smp_ops = { | 978 | struct smp_ops_t core99_smp_ops = { |
| 941 | .message_pass = smp_mpic_message_pass, | 979 | .message_pass = smp_mpic_message_pass, |
| 942 | .probe = smp_core99_probe, | 980 | .probe = smp_core99_probe, |
| 981 | .bringup_done = smp_core99_bringup_done, | ||
| 943 | .kick_cpu = smp_core99_kick_cpu, | 982 | .kick_cpu = smp_core99_kick_cpu, |
| 944 | .setup_cpu = smp_core99_setup_cpu, | 983 | .setup_cpu = smp_core99_setup_cpu, |
| 945 | .give_timebase = smp_core99_give_timebase, | 984 | .give_timebase = smp_core99_give_timebase, |
