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