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/platforms/powermac | |
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/platforms/powermac')
-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 837989e72ca..74a43c65204 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, |