diff options
Diffstat (limited to 'arch/powerpc/platforms/85xx/smp.c')
| -rw-r--r-- | arch/powerpc/platforms/85xx/smp.c | 53 |
1 files changed, 43 insertions, 10 deletions
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index 148c2f2d978..ba093f55367 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -15,6 +15,7 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/of.h> +#include <linux/of_address.h> #include <linux/kexec.h> #include <linux/highmem.h> #include <linux/cpu.h> @@ -26,6 +27,7 @@ #include <asm/cacheflush.h> #include <asm/dbell.h> #include <asm/fsl_guts.h> +#include <asm/code-patching.h> #include <sysdev/fsl_soc.h> #include <sysdev/mpic.h> @@ -69,7 +71,32 @@ static void mpc85xx_give_timebase(void) tb_req = 0; mpc85xx_timebase_freeze(1); +#ifdef CONFIG_PPC64 + /* + * e5500/e6500 have a workaround for erratum A-006958 in place + * that will reread the timebase until TBL is non-zero. + * That would be a bad thing when the timebase is frozen. + * + * Thus, we read it manually, and instead of checking that + * TBL is non-zero, we ensure that TB does not change. We don't + * do that for the main mftb implementation, because it requires + * a scratch register + */ + { + u64 prev; + + asm volatile("mfspr %0, %1" : "=r" (timebase) : + "i" (SPRN_TBRL)); + + do { + prev = timebase; + asm volatile("mfspr %0, %1" : "=r" (timebase) : + "i" (SPRN_TBRL)); + } while (prev != timebase); + } +#else timebase = get_tb(); +#endif mb(); tb_valid = 1; @@ -99,7 +126,7 @@ static void mpc85xx_take_timebase(void) } #ifdef CONFIG_HOTPLUG_CPU -static void __cpuinit smp_85xx_mach_cpu_die(void) +static void smp_85xx_mach_cpu_die(void) { unsigned int cpu = smp_processor_id(); u32 tmp; @@ -141,7 +168,7 @@ static inline u32 read_spin_table_addr_l(void *spin_table) return in_be32(&((struct epapr_spin_table *)spin_table)->addr_l); } -static int __cpuinit smp_85xx_kick_cpu(int nr) +static int smp_85xx_kick_cpu(int nr) { unsigned long flags; const u64 *cpu_rel_addr; @@ -201,7 +228,7 @@ static int __cpuinit smp_85xx_kick_cpu(int nr) * We don't set the BPTR register here since it already points * to the boot page properly. */ - mpic_reset_core(hw_cpu); + mpic_reset_core(nr); /* * wait until core is ready... @@ -241,7 +268,7 @@ out: flush_spin_table(spin_table); out_be32(&spin_table->pir, hw_cpu); out_be64((u64 *)(&spin_table->addr_h), - __pa((u64)*((unsigned long long *)generic_secondary_smp_init))); + __pa(ppc_function_entry(generic_secondary_smp_init))); flush_spin_table(spin_table); #endif @@ -255,6 +282,7 @@ out: struct smp_ops_t smp_85xx_ops = { .kick_cpu = smp_85xx_kick_cpu, + .cpu_bootable = smp_generic_cpu_bootable, #ifdef CONFIG_HOTPLUG_CPU .cpu_disable = generic_cpu_disable, .cpu_die = generic_cpu_die, @@ -362,15 +390,18 @@ static void mpc85xx_smp_machine_kexec(struct kimage *image) } #endif /* CONFIG_KEXEC */ -static void __cpuinit smp_85xx_setup_cpu(int cpu_nr) +static void smp_85xx_basic_setup(int cpu_nr) { - if (smp_85xx_ops.probe == smp_mpic_probe) - mpic_setup_this_cpu(); - if (cpu_has_feature(CPU_FTR_DBELL)) doorbell_setup_this_cpu(); } +static void smp_85xx_setup_cpu(int cpu_nr) +{ + mpic_setup_this_cpu(); + smp_85xx_basic_setup(cpu_nr); +} + static const struct of_device_id mpc85xx_smp_guts_ids[] = { { .compatible = "fsl,mpc8572-guts", }, { .compatible = "fsl,p1020-guts", }, @@ -385,13 +416,14 @@ void __init mpc85xx_smp_init(void) { struct device_node *np; - smp_85xx_ops.setup_cpu = smp_85xx_setup_cpu; np = of_find_node_by_type(NULL, "open-pic"); if (np) { smp_85xx_ops.probe = smp_mpic_probe; + smp_85xx_ops.setup_cpu = smp_85xx_setup_cpu; smp_85xx_ops.message_pass = smp_mpic_message_pass; - } + } else + smp_85xx_ops.setup_cpu = smp_85xx_basic_setup; if (cpu_has_feature(CPU_FTR_DBELL)) { /* @@ -400,6 +432,7 @@ void __init mpc85xx_smp_init(void) */ smp_85xx_ops.message_pass = NULL; smp_85xx_ops.cause_ipi = doorbell_cause_ipi; + smp_85xx_ops.probe = NULL; } np = of_find_matching_node(NULL, mpc85xx_smp_guts_ids); |
