155190f88SBenjamin Herrenschmidt /*
255190f88SBenjamin Herrenschmidt  * SMP support for PowerNV machines.
355190f88SBenjamin Herrenschmidt  *
455190f88SBenjamin Herrenschmidt  * Copyright 2011 IBM Corp.
555190f88SBenjamin Herrenschmidt  *
655190f88SBenjamin Herrenschmidt  * This program is free software; you can redistribute it and/or
755190f88SBenjamin Herrenschmidt  * modify it under the terms of the GNU General Public License
855190f88SBenjamin Herrenschmidt  * as published by the Free Software Foundation; either version
955190f88SBenjamin Herrenschmidt  * 2 of the License, or (at your option) any later version.
1055190f88SBenjamin Herrenschmidt  */
1155190f88SBenjamin Herrenschmidt 
1255190f88SBenjamin Herrenschmidt #include <linux/kernel.h>
1355190f88SBenjamin Herrenschmidt #include <linux/module.h>
1455190f88SBenjamin Herrenschmidt #include <linux/sched.h>
1555190f88SBenjamin Herrenschmidt #include <linux/smp.h>
1655190f88SBenjamin Herrenschmidt #include <linux/interrupt.h>
1755190f88SBenjamin Herrenschmidt #include <linux/delay.h>
1855190f88SBenjamin Herrenschmidt #include <linux/init.h>
1955190f88SBenjamin Herrenschmidt #include <linux/spinlock.h>
2055190f88SBenjamin Herrenschmidt #include <linux/cpu.h>
2155190f88SBenjamin Herrenschmidt 
2255190f88SBenjamin Herrenschmidt #include <asm/irq.h>
2355190f88SBenjamin Herrenschmidt #include <asm/smp.h>
2455190f88SBenjamin Herrenschmidt #include <asm/paca.h>
2555190f88SBenjamin Herrenschmidt #include <asm/machdep.h>
2655190f88SBenjamin Herrenschmidt #include <asm/cputable.h>
2755190f88SBenjamin Herrenschmidt #include <asm/firmware.h>
2855190f88SBenjamin Herrenschmidt #include <asm/system.h>
2955190f88SBenjamin Herrenschmidt #include <asm/rtas.h>
3055190f88SBenjamin Herrenschmidt #include <asm/vdso_datapage.h>
3155190f88SBenjamin Herrenschmidt #include <asm/cputhreads.h>
3255190f88SBenjamin Herrenschmidt #include <asm/xics.h>
3355190f88SBenjamin Herrenschmidt 
3455190f88SBenjamin Herrenschmidt #include "powernv.h"
3555190f88SBenjamin Herrenschmidt 
3655190f88SBenjamin Herrenschmidt static void __devinit pnv_smp_setup_cpu(int cpu)
3755190f88SBenjamin Herrenschmidt {
3855190f88SBenjamin Herrenschmidt 	if (cpu != boot_cpuid)
3955190f88SBenjamin Herrenschmidt 		xics_setup_cpu();
4055190f88SBenjamin Herrenschmidt }
4155190f88SBenjamin Herrenschmidt 
4255190f88SBenjamin Herrenschmidt static int pnv_smp_cpu_bootable(unsigned int nr)
4355190f88SBenjamin Herrenschmidt {
4455190f88SBenjamin Herrenschmidt 	/* Special case - we inhibit secondary thread startup
4555190f88SBenjamin Herrenschmidt 	 * during boot if the user requests it.
4655190f88SBenjamin Herrenschmidt 	 */
4755190f88SBenjamin Herrenschmidt 	if (system_state < SYSTEM_RUNNING && cpu_has_feature(CPU_FTR_SMT)) {
4855190f88SBenjamin Herrenschmidt 		if (!smt_enabled_at_boot && cpu_thread_in_core(nr) != 0)
4955190f88SBenjamin Herrenschmidt 			return 0;
5055190f88SBenjamin Herrenschmidt 		if (smt_enabled_at_boot
5155190f88SBenjamin Herrenschmidt 		    && cpu_thread_in_core(nr) >= smt_enabled_at_boot)
5255190f88SBenjamin Herrenschmidt 			return 0;
5355190f88SBenjamin Herrenschmidt 	}
5455190f88SBenjamin Herrenschmidt 
5555190f88SBenjamin Herrenschmidt 	return 1;
5655190f88SBenjamin Herrenschmidt }
5755190f88SBenjamin Herrenschmidt 
5855190f88SBenjamin Herrenschmidt static struct smp_ops_t pnv_smp_ops = {
5955190f88SBenjamin Herrenschmidt 	.message_pass	= smp_muxed_ipi_message_pass,
6055190f88SBenjamin Herrenschmidt 	.cause_ipi	= NULL,	/* Filled at runtime by xics_smp_probe() */
6155190f88SBenjamin Herrenschmidt 	.probe		= xics_smp_probe,
6255190f88SBenjamin Herrenschmidt 	.kick_cpu	= smp_generic_kick_cpu,
6355190f88SBenjamin Herrenschmidt 	.setup_cpu	= pnv_smp_setup_cpu,
6455190f88SBenjamin Herrenschmidt 	.cpu_bootable	= pnv_smp_cpu_bootable,
6555190f88SBenjamin Herrenschmidt };
6655190f88SBenjamin Herrenschmidt 
6755190f88SBenjamin Herrenschmidt /* This is called very early during platform setup_arch */
6855190f88SBenjamin Herrenschmidt void __init pnv_smp_init(void)
6955190f88SBenjamin Herrenschmidt {
7055190f88SBenjamin Herrenschmidt 	smp_ops = &pnv_smp_ops;
7155190f88SBenjamin Herrenschmidt 
7255190f88SBenjamin Herrenschmidt 	/* XXX We don't yet have a proper entry point from HAL, for
7355190f88SBenjamin Herrenschmidt 	 * now we rely on kexec-style entry from BML
7455190f88SBenjamin Herrenschmidt 	 */
7555190f88SBenjamin Herrenschmidt 
7655190f88SBenjamin Herrenschmidt #ifdef CONFIG_PPC_RTAS
7755190f88SBenjamin Herrenschmidt 	/* Non-lpar has additional take/give timebase */
7855190f88SBenjamin Herrenschmidt 	if (rtas_token("freeze-time-base") != RTAS_UNKNOWN_SERVICE) {
7955190f88SBenjamin Herrenschmidt 		smp_ops->give_timebase = rtas_give_timebase;
8055190f88SBenjamin Herrenschmidt 		smp_ops->take_timebase = rtas_take_timebase;
8155190f88SBenjamin Herrenschmidt 	}
8255190f88SBenjamin Herrenschmidt #endif /* CONFIG_PPC_RTAS */
8355190f88SBenjamin Herrenschmidt }
84