12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 25ad57078SPaul Mackerras /* 35ad57078SPaul Mackerras * SMP support for ppc. 45ad57078SPaul Mackerras * 55ad57078SPaul Mackerras * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great 65ad57078SPaul Mackerras * deal of code from the sparc and intel versions. 75ad57078SPaul Mackerras * 85ad57078SPaul Mackerras * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu> 95ad57078SPaul Mackerras * 105ad57078SPaul Mackerras * PowerPC-64 Support added by Dave Engebretsen, Peter Bergner, and 115ad57078SPaul Mackerras * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com 125ad57078SPaul Mackerras */ 135ad57078SPaul Mackerras 145ad57078SPaul Mackerras #undef DEBUG 155ad57078SPaul Mackerras 165ad57078SPaul Mackerras #include <linux/kernel.h> 174b16f8e2SPaul Gortmaker #include <linux/export.h> 1868e21be2SIngo Molnar #include <linux/sched/mm.h> 19678c668aSChristophe Leroy #include <linux/sched/task_stack.h> 20105ab3d8SIngo Molnar #include <linux/sched/topology.h> 215ad57078SPaul Mackerras #include <linux/smp.h> 225ad57078SPaul Mackerras #include <linux/interrupt.h> 235ad57078SPaul Mackerras #include <linux/delay.h> 245ad57078SPaul Mackerras #include <linux/init.h> 255ad57078SPaul Mackerras #include <linux/spinlock.h> 265ad57078SPaul Mackerras #include <linux/cache.h> 275ad57078SPaul Mackerras #include <linux/err.h> 288a25a2fdSKay Sievers #include <linux/device.h> 295ad57078SPaul Mackerras #include <linux/cpu.h> 305ad57078SPaul Mackerras #include <linux/notifier.h> 314b703a23SAnton Blanchard #include <linux/topology.h> 32665e87ffSDaniel Axtens #include <linux/profile.h> 334e287e65SNicholas Piggin #include <linux/processor.h> 347241d26eSChristophe Leroy #include <linux/random.h> 35b6aeddeaSMichael Ellerman #include <linux/stackprotector.h> 3665fddcfcSMike Rapoport #include <linux/pgtable.h> 37cd7aa5d2SCédric Le Goater #include <linux/clockchips.h> 385ad57078SPaul Mackerras 395ad57078SPaul Mackerras #include <asm/ptrace.h> 4060063497SArun Sharma #include <linux/atomic.h> 415ad57078SPaul Mackerras #include <asm/irq.h> 421b67bee1SSrivatsa S. Bhat #include <asm/hw_irq.h> 43441c19c8SMichael Ellerman #include <asm/kvm_ppc.h> 44b866cc21SNicholas Piggin #include <asm/dbell.h> 455ad57078SPaul Mackerras #include <asm/page.h> 465ad57078SPaul Mackerras #include <asm/prom.h> 475ad57078SPaul Mackerras #include <asm/smp.h> 485ad57078SPaul Mackerras #include <asm/time.h> 495ad57078SPaul Mackerras #include <asm/machdep.h> 50e2075f79SNathan Lynch #include <asm/cputhreads.h> 515ad57078SPaul Mackerras #include <asm/cputable.h> 525ad57078SPaul Mackerras #include <asm/mpic.h> 53a7f290daSBenjamin Herrenschmidt #include <asm/vdso_datapage.h> 545ad57078SPaul Mackerras #ifdef CONFIG_PPC64 555ad57078SPaul Mackerras #include <asm/paca.h> 565ad57078SPaul Mackerras #endif 5718ad51ddSAnton Blanchard #include <asm/vdso.h> 58ae3a197eSDavid Howells #include <asm/debug.h> 591217d34bSAnton Blanchard #include <asm/kexec.h> 6042f5b4caSDaniel Axtens #include <asm/asm-prototypes.h> 61b92a226eSKevin Hao #include <asm/cpu_has_feature.h> 62d1039786SNaveen N. Rao #include <asm/ftrace.h> 63e0d8e991SAneesh Kumar K.V #include <asm/kup.h> 645ad57078SPaul Mackerras 655ad57078SPaul Mackerras #ifdef DEBUG 66f9e4ec57SMichael Ellerman #include <asm/udbg.h> 675ad57078SPaul Mackerras #define DBG(fmt...) udbg_printf(fmt) 685ad57078SPaul Mackerras #else 695ad57078SPaul Mackerras #define DBG(fmt...) 705ad57078SPaul Mackerras #endif 715ad57078SPaul Mackerras 72c56e5853SBenjamin Herrenschmidt #ifdef CONFIG_HOTPLUG_CPU 73fb82b839SBenjamin Herrenschmidt /* State of each CPU during hotplug phases */ 74fb82b839SBenjamin Herrenschmidt static DEFINE_PER_CPU(int, cpu_state) = { 0 }; 75c56e5853SBenjamin Herrenschmidt #endif 76c56e5853SBenjamin Herrenschmidt 777c19c2e5SChristophe Leroy struct task_struct *secondary_current; 78425752c6SGautham R. Shenoy bool has_big_cores; 79f9f130ffSSrikar Dronamraju bool coregroup_enabled; 809538abeeSGautham R. Shenoy bool thread_group_shares_l2; 81e9ef81e1SParth Shah bool thread_group_shares_l3; 82f9e4ec57SMichael Ellerman 83cc1ba8eaSAnton Blanchard DEFINE_PER_CPU(cpumask_var_t, cpu_sibling_map); 84425752c6SGautham R. Shenoy DEFINE_PER_CPU(cpumask_var_t, cpu_smallcore_map); 852a636a56SOliver O'Halloran DEFINE_PER_CPU(cpumask_var_t, cpu_l2_cache_map); 86cc1ba8eaSAnton Blanchard DEFINE_PER_CPU(cpumask_var_t, cpu_core_map); 87078277acSYu Kuai static DEFINE_PER_CPU(cpumask_var_t, cpu_coregroup_map); 885ad57078SPaul Mackerras 89d5a7430dSMike Travis EXPORT_PER_CPU_SYMBOL(cpu_sibling_map); 902a636a56SOliver O'Halloran EXPORT_PER_CPU_SYMBOL(cpu_l2_cache_map); 91440a0857SNathan Lynch EXPORT_PER_CPU_SYMBOL(cpu_core_map); 92425752c6SGautham R. Shenoy EXPORT_SYMBOL_GPL(has_big_cores); 93425752c6SGautham R. Shenoy 9472730bfcSSrikar Dronamraju enum { 9572730bfcSSrikar Dronamraju #ifdef CONFIG_SCHED_SMT 9672730bfcSSrikar Dronamraju smt_idx, 9772730bfcSSrikar Dronamraju #endif 9872730bfcSSrikar Dronamraju cache_idx, 9972730bfcSSrikar Dronamraju mc_idx, 10072730bfcSSrikar Dronamraju die_idx, 10172730bfcSSrikar Dronamraju }; 10272730bfcSSrikar Dronamraju 103425752c6SGautham R. Shenoy #define MAX_THREAD_LIST_SIZE 8 104425752c6SGautham R. Shenoy #define THREAD_GROUP_SHARE_L1 1 105e9ef81e1SParth Shah #define THREAD_GROUP_SHARE_L2_L3 2 106425752c6SGautham R. Shenoy struct thread_groups { 107425752c6SGautham R. Shenoy unsigned int property; 108425752c6SGautham R. Shenoy unsigned int nr_groups; 109425752c6SGautham R. Shenoy unsigned int threads_per_group; 110425752c6SGautham R. Shenoy unsigned int thread_list[MAX_THREAD_LIST_SIZE]; 111425752c6SGautham R. Shenoy }; 112425752c6SGautham R. Shenoy 113790a1662SGautham R. Shenoy /* Maximum number of properties that groups of threads within a core can share */ 1149538abeeSGautham R. Shenoy #define MAX_THREAD_GROUP_PROPERTIES 2 115790a1662SGautham R. Shenoy 116790a1662SGautham R. Shenoy struct thread_groups_list { 117790a1662SGautham R. Shenoy unsigned int nr_properties; 118790a1662SGautham R. Shenoy struct thread_groups property_tgs[MAX_THREAD_GROUP_PROPERTIES]; 119790a1662SGautham R. Shenoy }; 120790a1662SGautham R. Shenoy 121790a1662SGautham R. Shenoy static struct thread_groups_list tgl[NR_CPUS] __initdata; 122425752c6SGautham R. Shenoy /* 1231fdc1d66SGautham R. Shenoy * On big-cores system, thread_group_l1_cache_map for each CPU corresponds to 124425752c6SGautham R. Shenoy * the set its siblings that share the L1-cache. 125425752c6SGautham R. Shenoy */ 126a4bec516SGautham R. Shenoy DEFINE_PER_CPU(cpumask_var_t, thread_group_l1_cache_map); 1275ad57078SPaul Mackerras 1289538abeeSGautham R. Shenoy /* 1299538abeeSGautham R. Shenoy * On some big-cores system, thread_group_l2_cache_map for each CPU 1309538abeeSGautham R. Shenoy * corresponds to the set its siblings within the core that share the 1319538abeeSGautham R. Shenoy * L2-cache. 1329538abeeSGautham R. Shenoy */ 133a4bec516SGautham R. Shenoy DEFINE_PER_CPU(cpumask_var_t, thread_group_l2_cache_map); 1349538abeeSGautham R. Shenoy 135e9ef81e1SParth Shah /* 136e9ef81e1SParth Shah * On P10, thread_group_l3_cache_map for each CPU is equal to the 137e9ef81e1SParth Shah * thread_group_l2_cache_map 138e9ef81e1SParth Shah */ 139e9ef81e1SParth Shah DEFINE_PER_CPU(cpumask_var_t, thread_group_l3_cache_map); 140e9ef81e1SParth Shah 1415ad57078SPaul Mackerras /* SMP operations for this machine */ 1425ad57078SPaul Mackerras struct smp_ops_t *smp_ops; 1435ad57078SPaul Mackerras 1447ccbe504SBenjamin Herrenschmidt /* Can't be static due to PowerMac hackery */ 1457ccbe504SBenjamin Herrenschmidt volatile unsigned int cpu_callin_map[NR_CPUS]; 1465ad57078SPaul Mackerras 1475ad57078SPaul Mackerras int smt_enabled_at_boot = 1; 1485ad57078SPaul Mackerras 1493cd85250SAndy Fleming /* 1503cd85250SAndy Fleming * Returns 1 if the specified cpu should be brought up during boot. 1513cd85250SAndy Fleming * Used to inhibit booting threads if they've been disabled or 1523cd85250SAndy Fleming * limited on the command line 1533cd85250SAndy Fleming */ 1543cd85250SAndy Fleming int smp_generic_cpu_bootable(unsigned int nr) 1553cd85250SAndy Fleming { 1563cd85250SAndy Fleming /* Special case - we inhibit secondary thread startup 1573cd85250SAndy Fleming * during boot if the user requests it. 1583cd85250SAndy Fleming */ 159a8fcfc19SThomas Gleixner if (system_state < SYSTEM_RUNNING && cpu_has_feature(CPU_FTR_SMT)) { 1603cd85250SAndy Fleming if (!smt_enabled_at_boot && cpu_thread_in_core(nr) != 0) 1613cd85250SAndy Fleming return 0; 1623cd85250SAndy Fleming if (smt_enabled_at_boot 1633cd85250SAndy Fleming && cpu_thread_in_core(nr) >= smt_enabled_at_boot) 1643cd85250SAndy Fleming return 0; 1653cd85250SAndy Fleming } 1663cd85250SAndy Fleming 1673cd85250SAndy Fleming return 1; 1683cd85250SAndy Fleming } 1693cd85250SAndy Fleming 1703cd85250SAndy Fleming 1715ad57078SPaul Mackerras #ifdef CONFIG_PPC64 172cad5cef6SGreg Kroah-Hartman int smp_generic_kick_cpu(int nr) 1735ad57078SPaul Mackerras { 174c642af9cSSantosh Sivaraj if (nr < 0 || nr >= nr_cpu_ids) 175f8d0d5dcSSantosh Sivaraj return -EINVAL; 1765ad57078SPaul Mackerras 1775ad57078SPaul Mackerras /* 1785ad57078SPaul Mackerras * The processor is currently spinning, waiting for the 1795ad57078SPaul Mackerras * cpu_start field to become non-zero After we set cpu_start, 1805ad57078SPaul Mackerras * the processor will continue on to secondary_start 1815ad57078SPaul Mackerras */ 182d2e60075SNicholas Piggin if (!paca_ptrs[nr]->cpu_start) { 183d2e60075SNicholas Piggin paca_ptrs[nr]->cpu_start = 1; 1845ad57078SPaul Mackerras smp_mb(); 185fb82b839SBenjamin Herrenschmidt return 0; 186fb82b839SBenjamin Herrenschmidt } 187fb82b839SBenjamin Herrenschmidt 188fb82b839SBenjamin Herrenschmidt #ifdef CONFIG_HOTPLUG_CPU 189fb82b839SBenjamin Herrenschmidt /* 190fb82b839SBenjamin Herrenschmidt * Ok it's not there, so it might be soft-unplugged, let's 191fb82b839SBenjamin Herrenschmidt * try to bring it back 192fb82b839SBenjamin Herrenschmidt */ 193ae5cab47SZhao Chenhui generic_set_cpu_up(nr); 194fb82b839SBenjamin Herrenschmidt smp_wmb(); 195fb82b839SBenjamin Herrenschmidt smp_send_reschedule(nr); 196fb82b839SBenjamin Herrenschmidt #endif /* CONFIG_HOTPLUG_CPU */ 197de300974SMichael Ellerman 198de300974SMichael Ellerman return 0; 1995ad57078SPaul Mackerras } 200fb82b839SBenjamin Herrenschmidt #endif /* CONFIG_PPC64 */ 2015ad57078SPaul Mackerras 20225ddd738SMilton Miller static irqreturn_t call_function_action(int irq, void *data) 20325ddd738SMilton Miller { 20425ddd738SMilton Miller generic_smp_call_function_interrupt(); 20525ddd738SMilton Miller return IRQ_HANDLED; 20625ddd738SMilton Miller } 20725ddd738SMilton Miller 20825ddd738SMilton Miller static irqreturn_t reschedule_action(int irq, void *data) 20925ddd738SMilton Miller { 210184748ccSPeter Zijlstra scheduler_ipi(); 21125ddd738SMilton Miller return IRQ_HANDLED; 21225ddd738SMilton Miller } 21325ddd738SMilton Miller 214bc907113SNicholas Piggin #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST 2151b67bee1SSrivatsa S. Bhat static irqreturn_t tick_broadcast_ipi_action(int irq, void *data) 21625ddd738SMilton Miller { 2173f984620SNicholas Piggin timer_broadcast_interrupt(); 21825ddd738SMilton Miller return IRQ_HANDLED; 21925ddd738SMilton Miller } 220bc907113SNicholas Piggin #endif 22125ddd738SMilton Miller 222ddd703caSNicholas Piggin #ifdef CONFIG_NMI_IPI 223ddd703caSNicholas Piggin static irqreturn_t nmi_ipi_action(int irq, void *data) 22425ddd738SMilton Miller { 225ddd703caSNicholas Piggin smp_handle_nmi_ipi(get_irq_regs()); 22623d72bfdSMilton Miller return IRQ_HANDLED; 22723d72bfdSMilton Miller } 228ddd703caSNicholas Piggin #endif 22925ddd738SMilton Miller 23025ddd738SMilton Miller static irq_handler_t smp_ipi_action[] = { 23125ddd738SMilton Miller [PPC_MSG_CALL_FUNCTION] = call_function_action, 23225ddd738SMilton Miller [PPC_MSG_RESCHEDULE] = reschedule_action, 233bc907113SNicholas Piggin #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST 2341b67bee1SSrivatsa S. Bhat [PPC_MSG_TICK_BROADCAST] = tick_broadcast_ipi_action, 235bc907113SNicholas Piggin #endif 236ddd703caSNicholas Piggin #ifdef CONFIG_NMI_IPI 237ddd703caSNicholas Piggin [PPC_MSG_NMI_IPI] = nmi_ipi_action, 238ddd703caSNicholas Piggin #endif 23925ddd738SMilton Miller }; 24025ddd738SMilton Miller 241ddd703caSNicholas Piggin /* 242ddd703caSNicholas Piggin * The NMI IPI is a fallback and not truly non-maskable. It is simpler 243ddd703caSNicholas Piggin * than going through the call function infrastructure, and strongly 244ddd703caSNicholas Piggin * serialized, so it is more appropriate for debugging. 245ddd703caSNicholas Piggin */ 24625ddd738SMilton Miller const char *smp_ipi_name[] = { 24725ddd738SMilton Miller [PPC_MSG_CALL_FUNCTION] = "ipi call function", 24825ddd738SMilton Miller [PPC_MSG_RESCHEDULE] = "ipi reschedule", 249bc907113SNicholas Piggin #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST 2501b67bee1SSrivatsa S. Bhat [PPC_MSG_TICK_BROADCAST] = "ipi tick-broadcast", 251bc907113SNicholas Piggin #endif 25221bfd6a8SNicholas Piggin #ifdef CONFIG_NMI_IPI 253ddd703caSNicholas Piggin [PPC_MSG_NMI_IPI] = "nmi ipi", 25421bfd6a8SNicholas Piggin #endif 25525ddd738SMilton Miller }; 25625ddd738SMilton Miller 25725ddd738SMilton Miller /* optional function to request ipi, for controllers with >= 4 ipis */ 25825ddd738SMilton Miller int smp_request_message_ipi(int virq, int msg) 25925ddd738SMilton Miller { 26025ddd738SMilton Miller int err; 26125ddd738SMilton Miller 262ddd703caSNicholas Piggin if (msg < 0 || msg > PPC_MSG_NMI_IPI) 26325ddd738SMilton Miller return -EINVAL; 264ddd703caSNicholas Piggin #ifndef CONFIG_NMI_IPI 265ddd703caSNicholas Piggin if (msg == PPC_MSG_NMI_IPI) 26625ddd738SMilton Miller return 1; 26725ddd738SMilton Miller #endif 268ddd703caSNicholas Piggin 2693b5e16d7SThomas Gleixner err = request_irq(virq, smp_ipi_action[msg], 270e6651de9SZhao Chenhui IRQF_PERCPU | IRQF_NO_THREAD | IRQF_NO_SUSPEND, 271b0d436c7SAnton Blanchard smp_ipi_name[msg], NULL); 27225ddd738SMilton Miller WARN(err < 0, "unable to request_irq %d for %s (rc %d)\n", 27325ddd738SMilton Miller virq, smp_ipi_name[msg], err); 27425ddd738SMilton Miller 27525ddd738SMilton Miller return err; 27625ddd738SMilton Miller } 27725ddd738SMilton Miller 2781ece355bSMilton Miller #ifdef CONFIG_PPC_SMP_MUXED_IPI 27923d72bfdSMilton Miller struct cpu_messages { 280bd7f561fSSuresh Warrier long messages; /* current messages */ 28123d72bfdSMilton Miller }; 28223d72bfdSMilton Miller static DEFINE_PER_CPU_SHARED_ALIGNED(struct cpu_messages, ipi_message); 28323d72bfdSMilton Miller 28431639c77SSuresh Warrier void smp_muxed_ipi_set_message(int cpu, int msg) 28523d72bfdSMilton Miller { 28623d72bfdSMilton Miller struct cpu_messages *info = &per_cpu(ipi_message, cpu); 28771454272SMilton Miller char *message = (char *)&info->messages; 28823d72bfdSMilton Miller 2899fb1b36cSPaul Mackerras /* 2909fb1b36cSPaul Mackerras * Order previous accesses before accesses in the IPI handler. 2919fb1b36cSPaul Mackerras */ 2929fb1b36cSPaul Mackerras smp_mb(); 29371454272SMilton Miller message[msg] = 1; 29431639c77SSuresh Warrier } 29531639c77SSuresh Warrier 29631639c77SSuresh Warrier void smp_muxed_ipi_message_pass(int cpu, int msg) 29731639c77SSuresh Warrier { 29831639c77SSuresh Warrier smp_muxed_ipi_set_message(cpu, msg); 299b866cc21SNicholas Piggin 3009fb1b36cSPaul Mackerras /* 3019fb1b36cSPaul Mackerras * cause_ipi functions are required to include a full barrier 3029fb1b36cSPaul Mackerras * before doing whatever causes the IPI. 3039fb1b36cSPaul Mackerras */ 304b866cc21SNicholas Piggin smp_ops->cause_ipi(cpu); 30523d72bfdSMilton Miller } 30623d72bfdSMilton Miller 3070654de1cSAnton Blanchard #ifdef __BIG_ENDIAN__ 308bd7f561fSSuresh Warrier #define IPI_MESSAGE(A) (1uL << ((BITS_PER_LONG - 8) - 8 * (A))) 3090654de1cSAnton Blanchard #else 310bd7f561fSSuresh Warrier #define IPI_MESSAGE(A) (1uL << (8 * (A))) 3110654de1cSAnton Blanchard #endif 3120654de1cSAnton Blanchard 31323d72bfdSMilton Miller irqreturn_t smp_ipi_demux(void) 31423d72bfdSMilton Miller { 31523d72bfdSMilton Miller mb(); /* order any irq clear */ 31671454272SMilton Miller 317b87ac021SNicholas Piggin return smp_ipi_demux_relaxed(); 318b87ac021SNicholas Piggin } 319b87ac021SNicholas Piggin 320b87ac021SNicholas Piggin /* sync-free variant. Callers should ensure synchronization */ 321b87ac021SNicholas Piggin irqreturn_t smp_ipi_demux_relaxed(void) 322b87ac021SNicholas Piggin { 323b866cc21SNicholas Piggin struct cpu_messages *info; 32423d72bfdSMilton Miller unsigned long all; 32523d72bfdSMilton Miller 326b866cc21SNicholas Piggin info = this_cpu_ptr(&ipi_message); 32771454272SMilton Miller do { 3289fb1b36cSPaul Mackerras all = xchg(&info->messages, 0); 329e17769ebSSuresh E. Warrier #if defined(CONFIG_KVM_XICS) && defined(CONFIG_KVM_BOOK3S_HV_POSSIBLE) 330e17769ebSSuresh E. Warrier /* 331e17769ebSSuresh E. Warrier * Must check for PPC_MSG_RM_HOST_ACTION messages 332e17769ebSSuresh E. Warrier * before PPC_MSG_CALL_FUNCTION messages because when 333e17769ebSSuresh E. Warrier * a VM is destroyed, we call kick_all_cpus_sync() 334e17769ebSSuresh E. Warrier * to ensure that any pending PPC_MSG_RM_HOST_ACTION 335e17769ebSSuresh E. Warrier * messages have completed before we free any VCPUs. 336e17769ebSSuresh E. Warrier */ 337e17769ebSSuresh E. Warrier if (all & IPI_MESSAGE(PPC_MSG_RM_HOST_ACTION)) 338e17769ebSSuresh E. Warrier kvmppc_xics_ipi_action(); 339e17769ebSSuresh E. Warrier #endif 3400654de1cSAnton Blanchard if (all & IPI_MESSAGE(PPC_MSG_CALL_FUNCTION)) 34123d72bfdSMilton Miller generic_smp_call_function_interrupt(); 3420654de1cSAnton Blanchard if (all & IPI_MESSAGE(PPC_MSG_RESCHEDULE)) 343880102e7SBenjamin Herrenschmidt scheduler_ipi(); 344bc907113SNicholas Piggin #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST 3451b67bee1SSrivatsa S. Bhat if (all & IPI_MESSAGE(PPC_MSG_TICK_BROADCAST)) 3463f984620SNicholas Piggin timer_broadcast_interrupt(); 347bc907113SNicholas Piggin #endif 348ddd703caSNicholas Piggin #ifdef CONFIG_NMI_IPI 349ddd703caSNicholas Piggin if (all & IPI_MESSAGE(PPC_MSG_NMI_IPI)) 350ddd703caSNicholas Piggin nmi_ipi_action(0, NULL); 351ddd703caSNicholas Piggin #endif 35271454272SMilton Miller } while (info->messages); 35371454272SMilton Miller 35423d72bfdSMilton Miller return IRQ_HANDLED; 35523d72bfdSMilton Miller } 3561ece355bSMilton Miller #endif /* CONFIG_PPC_SMP_MUXED_IPI */ 35723d72bfdSMilton Miller 3589ca980dcSPaul Mackerras static inline void do_message_pass(int cpu, int msg) 3599ca980dcSPaul Mackerras { 3609ca980dcSPaul Mackerras if (smp_ops->message_pass) 3619ca980dcSPaul Mackerras smp_ops->message_pass(cpu, msg); 3629ca980dcSPaul Mackerras #ifdef CONFIG_PPC_SMP_MUXED_IPI 3639ca980dcSPaul Mackerras else 3649ca980dcSPaul Mackerras smp_muxed_ipi_message_pass(cpu, msg); 3659ca980dcSPaul Mackerras #endif 3669ca980dcSPaul Mackerras } 3679ca980dcSPaul Mackerras 3685ad57078SPaul Mackerras void smp_send_reschedule(int cpu) 3695ad57078SPaul Mackerras { 3708cffc6acSBenjamin Herrenschmidt if (likely(smp_ops)) 3719ca980dcSPaul Mackerras do_message_pass(cpu, PPC_MSG_RESCHEDULE); 3725ad57078SPaul Mackerras } 373de56a948SPaul Mackerras EXPORT_SYMBOL_GPL(smp_send_reschedule); 3745ad57078SPaul Mackerras 375b7d7a240SJens Axboe void arch_send_call_function_single_ipi(int cpu) 376b7d7a240SJens Axboe { 377402d9a1eSSrivatsa S. Bhat do_message_pass(cpu, PPC_MSG_CALL_FUNCTION); 378b7d7a240SJens Axboe } 379b7d7a240SJens Axboe 380f063ea02SRusty Russell void arch_send_call_function_ipi_mask(const struct cpumask *mask) 381b7d7a240SJens Axboe { 382b7d7a240SJens Axboe unsigned int cpu; 383b7d7a240SJens Axboe 384f063ea02SRusty Russell for_each_cpu(cpu, mask) 3859ca980dcSPaul Mackerras do_message_pass(cpu, PPC_MSG_CALL_FUNCTION); 386b7d7a240SJens Axboe } 387b7d7a240SJens Axboe 388ddd703caSNicholas Piggin #ifdef CONFIG_NMI_IPI 389ddd703caSNicholas Piggin 390ddd703caSNicholas Piggin /* 391ddd703caSNicholas Piggin * "NMI IPI" system. 392ddd703caSNicholas Piggin * 393ddd703caSNicholas Piggin * NMI IPIs may not be recoverable, so should not be used as ongoing part of 394ddd703caSNicholas Piggin * a running system. They can be used for crash, debug, halt/reboot, etc. 395ddd703caSNicholas Piggin * 396ddd703caSNicholas Piggin * The IPI call waits with interrupts disabled until all targets enter the 39788b9a3d1SNicholas Piggin * NMI handler, then returns. Subsequent IPIs can be issued before targets 39888b9a3d1SNicholas Piggin * have returned from their handlers, so there is no guarantee about 39988b9a3d1SNicholas Piggin * concurrency or re-entrancy. 400ddd703caSNicholas Piggin * 40188b9a3d1SNicholas Piggin * A new NMI can be issued before all targets exit the handler. 402ddd703caSNicholas Piggin * 403ddd703caSNicholas Piggin * The IPI call may time out without all targets entering the NMI handler. 404ddd703caSNicholas Piggin * In that case, there is some logic to recover (and ignore subsequent 405ddd703caSNicholas Piggin * NMI interrupts that may eventually be raised), but the platform interrupt 406ddd703caSNicholas Piggin * handler may not be able to distinguish this from other exception causes, 407ddd703caSNicholas Piggin * which may cause a crash. 408ddd703caSNicholas Piggin */ 409ddd703caSNicholas Piggin 410ddd703caSNicholas Piggin static atomic_t __nmi_ipi_lock = ATOMIC_INIT(0); 411ddd703caSNicholas Piggin static struct cpumask nmi_ipi_pending_mask; 41288b9a3d1SNicholas Piggin static bool nmi_ipi_busy = false; 413ddd703caSNicholas Piggin static void (*nmi_ipi_function)(struct pt_regs *) = NULL; 414ddd703caSNicholas Piggin 415ddd703caSNicholas Piggin static void nmi_ipi_lock_start(unsigned long *flags) 416ddd703caSNicholas Piggin { 417ddd703caSNicholas Piggin raw_local_irq_save(*flags); 418ddd703caSNicholas Piggin hard_irq_disable(); 419ddd703caSNicholas Piggin while (atomic_cmpxchg(&__nmi_ipi_lock, 0, 1) == 1) { 420ddd703caSNicholas Piggin raw_local_irq_restore(*flags); 4210459ddfdSNicholas Piggin spin_until_cond(atomic_read(&__nmi_ipi_lock) == 0); 422ddd703caSNicholas Piggin raw_local_irq_save(*flags); 423ddd703caSNicholas Piggin hard_irq_disable(); 424ddd703caSNicholas Piggin } 425ddd703caSNicholas Piggin } 426ddd703caSNicholas Piggin 427ddd703caSNicholas Piggin static void nmi_ipi_lock(void) 428ddd703caSNicholas Piggin { 429ddd703caSNicholas Piggin while (atomic_cmpxchg(&__nmi_ipi_lock, 0, 1) == 1) 4300459ddfdSNicholas Piggin spin_until_cond(atomic_read(&__nmi_ipi_lock) == 0); 431ddd703caSNicholas Piggin } 432ddd703caSNicholas Piggin 433ddd703caSNicholas Piggin static void nmi_ipi_unlock(void) 434ddd703caSNicholas Piggin { 435ddd703caSNicholas Piggin smp_mb(); 436ddd703caSNicholas Piggin WARN_ON(atomic_read(&__nmi_ipi_lock) != 1); 437ddd703caSNicholas Piggin atomic_set(&__nmi_ipi_lock, 0); 438ddd703caSNicholas Piggin } 439ddd703caSNicholas Piggin 440ddd703caSNicholas Piggin static void nmi_ipi_unlock_end(unsigned long *flags) 441ddd703caSNicholas Piggin { 442ddd703caSNicholas Piggin nmi_ipi_unlock(); 443ddd703caSNicholas Piggin raw_local_irq_restore(*flags); 444ddd703caSNicholas Piggin } 445ddd703caSNicholas Piggin 446ddd703caSNicholas Piggin /* 447ddd703caSNicholas Piggin * Platform NMI handler calls this to ack 448ddd703caSNicholas Piggin */ 449ddd703caSNicholas Piggin int smp_handle_nmi_ipi(struct pt_regs *regs) 450ddd703caSNicholas Piggin { 45188b9a3d1SNicholas Piggin void (*fn)(struct pt_regs *) = NULL; 452ddd703caSNicholas Piggin unsigned long flags; 453ddd703caSNicholas Piggin int me = raw_smp_processor_id(); 454ddd703caSNicholas Piggin int ret = 0; 455ddd703caSNicholas Piggin 456ddd703caSNicholas Piggin /* 457ddd703caSNicholas Piggin * Unexpected NMIs are possible here because the interrupt may not 458ddd703caSNicholas Piggin * be able to distinguish NMI IPIs from other types of NMIs, or 459ddd703caSNicholas Piggin * because the caller may have timed out. 460ddd703caSNicholas Piggin */ 461ddd703caSNicholas Piggin nmi_ipi_lock_start(&flags); 46288b9a3d1SNicholas Piggin if (cpumask_test_cpu(me, &nmi_ipi_pending_mask)) { 463ddd703caSNicholas Piggin cpumask_clear_cpu(me, &nmi_ipi_pending_mask); 46488b9a3d1SNicholas Piggin fn = READ_ONCE(nmi_ipi_function); 46588b9a3d1SNicholas Piggin WARN_ON_ONCE(!fn); 466ddd703caSNicholas Piggin ret = 1; 46788b9a3d1SNicholas Piggin } 468ddd703caSNicholas Piggin nmi_ipi_unlock_end(&flags); 469ddd703caSNicholas Piggin 47088b9a3d1SNicholas Piggin if (fn) 47188b9a3d1SNicholas Piggin fn(regs); 47288b9a3d1SNicholas Piggin 473ddd703caSNicholas Piggin return ret; 474ddd703caSNicholas Piggin } 475ddd703caSNicholas Piggin 4766ba55716SMichael Ellerman static void do_smp_send_nmi_ipi(int cpu, bool safe) 477ddd703caSNicholas Piggin { 4786ba55716SMichael Ellerman if (!safe && smp_ops->cause_nmi_ipi && smp_ops->cause_nmi_ipi(cpu)) 479c64af645SNicholas Piggin return; 480c64af645SNicholas Piggin 481ddd703caSNicholas Piggin if (cpu >= 0) { 482ddd703caSNicholas Piggin do_message_pass(cpu, PPC_MSG_NMI_IPI); 483ddd703caSNicholas Piggin } else { 484ddd703caSNicholas Piggin int c; 485ddd703caSNicholas Piggin 486ddd703caSNicholas Piggin for_each_online_cpu(c) { 487ddd703caSNicholas Piggin if (c == raw_smp_processor_id()) 488ddd703caSNicholas Piggin continue; 489ddd703caSNicholas Piggin do_message_pass(c, PPC_MSG_NMI_IPI); 490ddd703caSNicholas Piggin } 491ddd703caSNicholas Piggin } 492ddd703caSNicholas Piggin } 493ddd703caSNicholas Piggin 494ddd703caSNicholas Piggin /* 495ddd703caSNicholas Piggin * - cpu is the target CPU (must not be this CPU), or NMI_IPI_ALL_OTHERS. 496ddd703caSNicholas Piggin * - fn is the target callback function. 497ddd703caSNicholas Piggin * - delay_us > 0 is the delay before giving up waiting for targets to 49888b9a3d1SNicholas Piggin * begin executing the handler, == 0 specifies indefinite delay. 499ddd703caSNicholas Piggin */ 5006fe243feSNicholas Piggin static int __smp_send_nmi_ipi(int cpu, void (*fn)(struct pt_regs *), 5016fe243feSNicholas Piggin u64 delay_us, bool safe) 502ddd703caSNicholas Piggin { 503ddd703caSNicholas Piggin unsigned long flags; 504ddd703caSNicholas Piggin int me = raw_smp_processor_id(); 505ddd703caSNicholas Piggin int ret = 1; 506ddd703caSNicholas Piggin 507ddd703caSNicholas Piggin BUG_ON(cpu == me); 508ddd703caSNicholas Piggin BUG_ON(cpu < 0 && cpu != NMI_IPI_ALL_OTHERS); 509ddd703caSNicholas Piggin 510ddd703caSNicholas Piggin if (unlikely(!smp_ops)) 511ddd703caSNicholas Piggin return 0; 512ddd703caSNicholas Piggin 513ddd703caSNicholas Piggin nmi_ipi_lock_start(&flags); 51488b9a3d1SNicholas Piggin while (nmi_ipi_busy) { 515ddd703caSNicholas Piggin nmi_ipi_unlock_end(&flags); 51688b9a3d1SNicholas Piggin spin_until_cond(!nmi_ipi_busy); 517ddd703caSNicholas Piggin nmi_ipi_lock_start(&flags); 518ddd703caSNicholas Piggin } 51988b9a3d1SNicholas Piggin nmi_ipi_busy = true; 520ddd703caSNicholas Piggin nmi_ipi_function = fn; 521ddd703caSNicholas Piggin 52288b9a3d1SNicholas Piggin WARN_ON_ONCE(!cpumask_empty(&nmi_ipi_pending_mask)); 52388b9a3d1SNicholas Piggin 524ddd703caSNicholas Piggin if (cpu < 0) { 525ddd703caSNicholas Piggin /* ALL_OTHERS */ 526ddd703caSNicholas Piggin cpumask_copy(&nmi_ipi_pending_mask, cpu_online_mask); 527ddd703caSNicholas Piggin cpumask_clear_cpu(me, &nmi_ipi_pending_mask); 528ddd703caSNicholas Piggin } else { 529ddd703caSNicholas Piggin cpumask_set_cpu(cpu, &nmi_ipi_pending_mask); 530ddd703caSNicholas Piggin } 53188b9a3d1SNicholas Piggin 532ddd703caSNicholas Piggin nmi_ipi_unlock(); 533ddd703caSNicholas Piggin 53488b9a3d1SNicholas Piggin /* Interrupts remain hard disabled */ 53588b9a3d1SNicholas Piggin 5366ba55716SMichael Ellerman do_smp_send_nmi_ipi(cpu, safe); 537ddd703caSNicholas Piggin 5385b73151fSNicholas Piggin nmi_ipi_lock(); 53988b9a3d1SNicholas Piggin /* nmi_ipi_busy is set here, so unlock/lock is okay */ 540ddd703caSNicholas Piggin while (!cpumask_empty(&nmi_ipi_pending_mask)) { 5415b73151fSNicholas Piggin nmi_ipi_unlock(); 542ddd703caSNicholas Piggin udelay(1); 5435b73151fSNicholas Piggin nmi_ipi_lock(); 544ddd703caSNicholas Piggin if (delay_us) { 545ddd703caSNicholas Piggin delay_us--; 546ddd703caSNicholas Piggin if (!delay_us) 54788b9a3d1SNicholas Piggin break; 548ddd703caSNicholas Piggin } 549ddd703caSNicholas Piggin } 550ddd703caSNicholas Piggin 551ddd703caSNicholas Piggin if (!cpumask_empty(&nmi_ipi_pending_mask)) { 5525b73151fSNicholas Piggin /* Timeout waiting for CPUs to call smp_handle_nmi_ipi */ 553ddd703caSNicholas Piggin ret = 0; 554ddd703caSNicholas Piggin cpumask_clear(&nmi_ipi_pending_mask); 555ddd703caSNicholas Piggin } 5565b73151fSNicholas Piggin 55788b9a3d1SNicholas Piggin nmi_ipi_function = NULL; 55888b9a3d1SNicholas Piggin nmi_ipi_busy = false; 55988b9a3d1SNicholas Piggin 560ddd703caSNicholas Piggin nmi_ipi_unlock_end(&flags); 561ddd703caSNicholas Piggin 562ddd703caSNicholas Piggin return ret; 563ddd703caSNicholas Piggin } 5646ba55716SMichael Ellerman 5656ba55716SMichael Ellerman int smp_send_nmi_ipi(int cpu, void (*fn)(struct pt_regs *), u64 delay_us) 5666ba55716SMichael Ellerman { 5676ba55716SMichael Ellerman return __smp_send_nmi_ipi(cpu, fn, delay_us, false); 5686ba55716SMichael Ellerman } 5696ba55716SMichael Ellerman 5706ba55716SMichael Ellerman int smp_send_safe_nmi_ipi(int cpu, void (*fn)(struct pt_regs *), u64 delay_us) 5716ba55716SMichael Ellerman { 5726ba55716SMichael Ellerman return __smp_send_nmi_ipi(cpu, fn, delay_us, true); 5736ba55716SMichael Ellerman } 574ddd703caSNicholas Piggin #endif /* CONFIG_NMI_IPI */ 575ddd703caSNicholas Piggin 5761b67bee1SSrivatsa S. Bhat #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST 5771b67bee1SSrivatsa S. Bhat void tick_broadcast(const struct cpumask *mask) 5781b67bee1SSrivatsa S. Bhat { 5791b67bee1SSrivatsa S. Bhat unsigned int cpu; 5801b67bee1SSrivatsa S. Bhat 5811b67bee1SSrivatsa S. Bhat for_each_cpu(cpu, mask) 5821b67bee1SSrivatsa S. Bhat do_message_pass(cpu, PPC_MSG_TICK_BROADCAST); 5831b67bee1SSrivatsa S. Bhat } 5841b67bee1SSrivatsa S. Bhat #endif 5851b67bee1SSrivatsa S. Bhat 586ddd703caSNicholas Piggin #ifdef CONFIG_DEBUGGER 587157c9f40SCédric Le Goater static void debugger_ipi_callback(struct pt_regs *regs) 588ddd703caSNicholas Piggin { 589ddd703caSNicholas Piggin debugger_ipi(regs); 590ddd703caSNicholas Piggin } 591ddd703caSNicholas Piggin 592e0476371SMilton Miller void smp_send_debugger_break(void) 5935ad57078SPaul Mackerras { 594ddd703caSNicholas Piggin smp_send_nmi_ipi(NMI_IPI_ALL_OTHERS, debugger_ipi_callback, 1000000); 5955ad57078SPaul Mackerras } 5965ad57078SPaul Mackerras #endif 5975ad57078SPaul Mackerras 598da665885SThiago Jung Bauermann #ifdef CONFIG_KEXEC_CORE 599cc532915SMichael Ellerman void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *)) 600cc532915SMichael Ellerman { 6014145f358SBalbir Singh int cpu; 6024145f358SBalbir Singh 603ddd703caSNicholas Piggin smp_send_nmi_ipi(NMI_IPI_ALL_OTHERS, crash_ipi_callback, 1000000); 6044145f358SBalbir Singh if (kdump_in_progress() && crash_wake_offline) { 6054145f358SBalbir Singh for_each_present_cpu(cpu) { 6064145f358SBalbir Singh if (cpu_online(cpu)) 6074145f358SBalbir Singh continue; 6084145f358SBalbir Singh /* 6094145f358SBalbir Singh * crash_ipi_callback will wait for 6104145f358SBalbir Singh * all cpus, including offline CPUs. 6114145f358SBalbir Singh * We don't care about nmi_ipi_function. 6124145f358SBalbir Singh * Offline cpus will jump straight into 6134145f358SBalbir Singh * crash_ipi_callback, we can skip the 6144145f358SBalbir Singh * entire NMI dance and waiting for 6154145f358SBalbir Singh * cpus to clear pending mask, etc. 6164145f358SBalbir Singh */ 6176ba55716SMichael Ellerman do_smp_send_nmi_ipi(cpu, false); 6184145f358SBalbir Singh } 6194145f358SBalbir Singh } 620cc532915SMichael Ellerman } 621cc532915SMichael Ellerman #endif 622cc532915SMichael Ellerman 6236029755eSNicholas Piggin #ifdef CONFIG_NMI_IPI 6246029755eSNicholas Piggin static void nmi_stop_this_cpu(struct pt_regs *regs) 6256029755eSNicholas Piggin { 6266029755eSNicholas Piggin /* 6276029755eSNicholas Piggin * IRQs are already hard disabled by the smp_handle_nmi_ipi. 6286029755eSNicholas Piggin */ 629bab26238SNicholas Piggin set_cpu_online(smp_processor_id(), false); 630bab26238SNicholas Piggin 6316029755eSNicholas Piggin spin_begin(); 6326029755eSNicholas Piggin while (1) 6336029755eSNicholas Piggin spin_cpu_relax(); 6346029755eSNicholas Piggin } 6356029755eSNicholas Piggin 6366029755eSNicholas Piggin void smp_send_stop(void) 6376029755eSNicholas Piggin { 6386029755eSNicholas Piggin smp_send_nmi_ipi(NMI_IPI_ALL_OTHERS, nmi_stop_this_cpu, 1000000); 6396029755eSNicholas Piggin } 6406029755eSNicholas Piggin 6416029755eSNicholas Piggin #else /* CONFIG_NMI_IPI */ 6426029755eSNicholas Piggin 6435ad57078SPaul Mackerras static void stop_this_cpu(void *dummy) 6445ad57078SPaul Mackerras { 645855bfe0dSNicholas Piggin hard_irq_disable(); 646bab26238SNicholas Piggin 647bab26238SNicholas Piggin /* 648bab26238SNicholas Piggin * Offlining CPUs in stop_this_cpu can result in scheduler warnings, 649bab26238SNicholas Piggin * (see commit de6e5d38417e), but printk_safe_flush_on_panic() wants 650bab26238SNicholas Piggin * to know other CPUs are offline before it breaks locks to flush 651bab26238SNicholas Piggin * printk buffers, in case we panic()ed while holding the lock. 652bab26238SNicholas Piggin */ 653bab26238SNicholas Piggin set_cpu_online(smp_processor_id(), false); 654bab26238SNicholas Piggin 655855bfe0dSNicholas Piggin spin_begin(); 6565ad57078SPaul Mackerras while (1) 657855bfe0dSNicholas Piggin spin_cpu_relax(); 6585ad57078SPaul Mackerras } 6595ad57078SPaul Mackerras 6608fd7675cSSatyam Sharma void smp_send_stop(void) 6618fd7675cSSatyam Sharma { 6626029755eSNicholas Piggin static bool stopped = false; 6636029755eSNicholas Piggin 6646029755eSNicholas Piggin /* 6656029755eSNicholas Piggin * Prevent waiting on csd lock from a previous smp_send_stop. 6666029755eSNicholas Piggin * This is racy, but in general callers try to do the right 6676029755eSNicholas Piggin * thing and only fire off one smp_send_stop (e.g., see 6686029755eSNicholas Piggin * kernel/panic.c) 6696029755eSNicholas Piggin */ 6706029755eSNicholas Piggin if (stopped) 6716029755eSNicholas Piggin return; 6726029755eSNicholas Piggin 6736029755eSNicholas Piggin stopped = true; 6746029755eSNicholas Piggin 6758691e5a8SJens Axboe smp_call_function(stop_this_cpu, NULL, 0); 6765ad57078SPaul Mackerras } 6776029755eSNicholas Piggin #endif /* CONFIG_NMI_IPI */ 6785ad57078SPaul Mackerras 6797c19c2e5SChristophe Leroy struct task_struct *current_set[NR_CPUS]; 6805ad57078SPaul Mackerras 681cad5cef6SGreg Kroah-Hartman static void smp_store_cpu_info(int id) 6825ad57078SPaul Mackerras { 6836b7487fcSTejun Heo per_cpu(cpu_pvr, id) = mfspr(SPRN_PVR); 6843160b097SBecky Bruce #ifdef CONFIG_PPC_FSL_BOOK3E 6853160b097SBecky Bruce per_cpu(next_tlbcam_idx, id) 6863160b097SBecky Bruce = (mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY) - 1; 6873160b097SBecky Bruce #endif 6885ad57078SPaul Mackerras } 6895ad57078SPaul Mackerras 690df52f671SOliver O'Halloran /* 691df52f671SOliver O'Halloran * Relationships between CPUs are maintained in a set of per-cpu cpumasks so 692df52f671SOliver O'Halloran * rather than just passing around the cpumask we pass around a function that 693df52f671SOliver O'Halloran * returns the that cpumask for the given CPU. 694df52f671SOliver O'Halloran */ 695df52f671SOliver O'Halloran static void set_cpus_related(int i, int j, struct cpumask *(*get_cpumask)(int)) 696df52f671SOliver O'Halloran { 697df52f671SOliver O'Halloran cpumask_set_cpu(i, get_cpumask(j)); 698df52f671SOliver O'Halloran cpumask_set_cpu(j, get_cpumask(i)); 699df52f671SOliver O'Halloran } 700df52f671SOliver O'Halloran 701df52f671SOliver O'Halloran #ifdef CONFIG_HOTPLUG_CPU 702df52f671SOliver O'Halloran static void set_cpus_unrelated(int i, int j, 703df52f671SOliver O'Halloran struct cpumask *(*get_cpumask)(int)) 704df52f671SOliver O'Halloran { 705df52f671SOliver O'Halloran cpumask_clear_cpu(i, get_cpumask(j)); 706df52f671SOliver O'Halloran cpumask_clear_cpu(j, get_cpumask(i)); 707df52f671SOliver O'Halloran } 708df52f671SOliver O'Halloran #endif 709df52f671SOliver O'Halloran 710425752c6SGautham R. Shenoy /* 7113ab33d6dSSrikar Dronamraju * Extends set_cpus_related. Instead of setting one CPU at a time in 7123ab33d6dSSrikar Dronamraju * dstmask, set srcmask at oneshot. dstmask should be super set of srcmask. 7133ab33d6dSSrikar Dronamraju */ 7143ab33d6dSSrikar Dronamraju static void or_cpumasks_related(int i, int j, struct cpumask *(*srcmask)(int), 7153ab33d6dSSrikar Dronamraju struct cpumask *(*dstmask)(int)) 7163ab33d6dSSrikar Dronamraju { 7173ab33d6dSSrikar Dronamraju struct cpumask *mask; 7183ab33d6dSSrikar Dronamraju int k; 7193ab33d6dSSrikar Dronamraju 7203ab33d6dSSrikar Dronamraju mask = srcmask(j); 7213ab33d6dSSrikar Dronamraju for_each_cpu(k, srcmask(i)) 7223ab33d6dSSrikar Dronamraju cpumask_or(dstmask(k), dstmask(k), mask); 7233ab33d6dSSrikar Dronamraju 7243ab33d6dSSrikar Dronamraju if (i == j) 7253ab33d6dSSrikar Dronamraju return; 7263ab33d6dSSrikar Dronamraju 7273ab33d6dSSrikar Dronamraju mask = srcmask(i); 7283ab33d6dSSrikar Dronamraju for_each_cpu(k, srcmask(j)) 7293ab33d6dSSrikar Dronamraju cpumask_or(dstmask(k), dstmask(k), mask); 7303ab33d6dSSrikar Dronamraju } 7313ab33d6dSSrikar Dronamraju 7323ab33d6dSSrikar Dronamraju /* 733425752c6SGautham R. Shenoy * parse_thread_groups: Parses the "ibm,thread-groups" device tree 734425752c6SGautham R. Shenoy * property for the CPU device node @dn and stores 735790a1662SGautham R. Shenoy * the parsed output in the thread_groups_list 736790a1662SGautham R. Shenoy * structure @tglp. 737425752c6SGautham R. Shenoy * 738425752c6SGautham R. Shenoy * @dn: The device node of the CPU device. 739790a1662SGautham R. Shenoy * @tglp: Pointer to a thread group list structure into which the parsed 740425752c6SGautham R. Shenoy * output of "ibm,thread-groups" is stored. 741425752c6SGautham R. Shenoy * 742425752c6SGautham R. Shenoy * ibm,thread-groups[0..N-1] array defines which group of threads in 743425752c6SGautham R. Shenoy * the CPU-device node can be grouped together based on the property. 744425752c6SGautham R. Shenoy * 745790a1662SGautham R. Shenoy * This array can represent thread groupings for multiple properties. 746790a1662SGautham R. Shenoy * 747790a1662SGautham R. Shenoy * ibm,thread-groups[i + 0] tells us the property based on which the 748425752c6SGautham R. Shenoy * threads are being grouped together. If this value is 1, it implies 7499538abeeSGautham R. Shenoy * that the threads in the same group share L1, translation cache. If 7509538abeeSGautham R. Shenoy * the value is 2, it implies that the threads in the same group share 7519538abeeSGautham R. Shenoy * the same L2 cache. 752425752c6SGautham R. Shenoy * 753790a1662SGautham R. Shenoy * ibm,thread-groups[i+1] tells us how many such thread groups exist for the 754790a1662SGautham R. Shenoy * property ibm,thread-groups[i] 755425752c6SGautham R. Shenoy * 756790a1662SGautham R. Shenoy * ibm,thread-groups[i+2] tells us the number of threads in each such 757425752c6SGautham R. Shenoy * group. 758790a1662SGautham R. Shenoy * Suppose k = (ibm,thread-groups[i+1] * ibm,thread-groups[i+2]), then, 759425752c6SGautham R. Shenoy * 760790a1662SGautham R. Shenoy * ibm,thread-groups[i+3..i+k+2] (is the list of threads identified by 761425752c6SGautham R. Shenoy * "ibm,ppc-interrupt-server#s" arranged as per their membership in 762425752c6SGautham R. Shenoy * the grouping. 763425752c6SGautham R. Shenoy * 764790a1662SGautham R. Shenoy * Example: 765790a1662SGautham R. Shenoy * If "ibm,thread-groups" = [1,2,4,8,10,12,14,9,11,13,15,2,2,4,8,10,12,14,9,11,13,15] 766790a1662SGautham R. Shenoy * This can be decomposed up into two consecutive arrays: 767790a1662SGautham R. Shenoy * a) [1,2,4,8,10,12,14,9,11,13,15] 768790a1662SGautham R. Shenoy * b) [2,2,4,8,10,12,14,9,11,13,15] 769425752c6SGautham R. Shenoy * 770790a1662SGautham R. Shenoy * where in, 771790a1662SGautham R. Shenoy * 772790a1662SGautham R. Shenoy * a) provides information of Property "1" being shared by "2" groups, 773790a1662SGautham R. Shenoy * each with "4" threads each. The "ibm,ppc-interrupt-server#s" of 774790a1662SGautham R. Shenoy * the first group is {8,10,12,14} and the 775790a1662SGautham R. Shenoy * "ibm,ppc-interrupt-server#s" of the second group is 776790a1662SGautham R. Shenoy * {9,11,13,15}. Property "1" is indicative of the thread in the 777790a1662SGautham R. Shenoy * group sharing L1 cache, translation cache and Instruction Data 778790a1662SGautham R. Shenoy * flow. 779790a1662SGautham R. Shenoy * 780790a1662SGautham R. Shenoy * b) provides information of Property "2" being shared by "2" groups, 781790a1662SGautham R. Shenoy * each group with "4" threads. The "ibm,ppc-interrupt-server#s" of 782790a1662SGautham R. Shenoy * the first group is {8,10,12,14} and the 783790a1662SGautham R. Shenoy * "ibm,ppc-interrupt-server#s" of the second group is 784790a1662SGautham R. Shenoy * {9,11,13,15}. Property "2" indicates that the threads in each 785790a1662SGautham R. Shenoy * group share the L2-cache. 786425752c6SGautham R. Shenoy * 787425752c6SGautham R. Shenoy * Returns 0 on success, -EINVAL if the property does not exist, 788425752c6SGautham R. Shenoy * -ENODATA if property does not have a value, and -EOVERFLOW if the 789425752c6SGautham R. Shenoy * property data isn't large enough. 790425752c6SGautham R. Shenoy */ 791425752c6SGautham R. Shenoy static int parse_thread_groups(struct device_node *dn, 792790a1662SGautham R. Shenoy struct thread_groups_list *tglp) 793425752c6SGautham R. Shenoy { 794790a1662SGautham R. Shenoy unsigned int property_idx = 0; 795790a1662SGautham R. Shenoy u32 *thread_group_array; 796425752c6SGautham R. Shenoy size_t total_threads; 797790a1662SGautham R. Shenoy int ret = 0, count; 798790a1662SGautham R. Shenoy u32 *thread_list; 799790a1662SGautham R. Shenoy int i = 0; 800425752c6SGautham R. Shenoy 801790a1662SGautham R. Shenoy count = of_property_count_u32_elems(dn, "ibm,thread-groups"); 802790a1662SGautham R. Shenoy thread_group_array = kcalloc(count, sizeof(u32), GFP_KERNEL); 803425752c6SGautham R. Shenoy ret = of_property_read_u32_array(dn, "ibm,thread-groups", 804790a1662SGautham R. Shenoy thread_group_array, count); 805425752c6SGautham R. Shenoy if (ret) 806790a1662SGautham R. Shenoy goto out_free; 807425752c6SGautham R. Shenoy 808790a1662SGautham R. Shenoy while (i < count && property_idx < MAX_THREAD_GROUP_PROPERTIES) { 809790a1662SGautham R. Shenoy int j; 810790a1662SGautham R. Shenoy struct thread_groups *tg = &tglp->property_tgs[property_idx++]; 811425752c6SGautham R. Shenoy 812790a1662SGautham R. Shenoy tg->property = thread_group_array[i]; 813790a1662SGautham R. Shenoy tg->nr_groups = thread_group_array[i + 1]; 814790a1662SGautham R. Shenoy tg->threads_per_group = thread_group_array[i + 2]; 815425752c6SGautham R. Shenoy total_threads = tg->nr_groups * tg->threads_per_group; 816425752c6SGautham R. Shenoy 817790a1662SGautham R. Shenoy thread_list = &thread_group_array[i + 3]; 818790a1662SGautham R. Shenoy 819790a1662SGautham R. Shenoy for (j = 0; j < total_threads; j++) 820790a1662SGautham R. Shenoy tg->thread_list[j] = thread_list[j]; 821790a1662SGautham R. Shenoy i = i + 3 + total_threads; 822790a1662SGautham R. Shenoy } 823790a1662SGautham R. Shenoy 824790a1662SGautham R. Shenoy tglp->nr_properties = property_idx; 825790a1662SGautham R. Shenoy 826790a1662SGautham R. Shenoy out_free: 827790a1662SGautham R. Shenoy kfree(thread_group_array); 828425752c6SGautham R. Shenoy return ret; 829425752c6SGautham R. Shenoy } 830425752c6SGautham R. Shenoy 831425752c6SGautham R. Shenoy /* 832425752c6SGautham R. Shenoy * get_cpu_thread_group_start : Searches the thread group in tg->thread_list 833425752c6SGautham R. Shenoy * that @cpu belongs to. 834425752c6SGautham R. Shenoy * 835425752c6SGautham R. Shenoy * @cpu : The logical CPU whose thread group is being searched. 836425752c6SGautham R. Shenoy * @tg : The thread-group structure of the CPU node which @cpu belongs 837425752c6SGautham R. Shenoy * to. 838425752c6SGautham R. Shenoy * 839425752c6SGautham R. Shenoy * Returns the index to tg->thread_list that points to the the start 840425752c6SGautham R. Shenoy * of the thread_group that @cpu belongs to. 841425752c6SGautham R. Shenoy * 842425752c6SGautham R. Shenoy * Returns -1 if cpu doesn't belong to any of the groups pointed to by 843425752c6SGautham R. Shenoy * tg->thread_list. 844425752c6SGautham R. Shenoy */ 845425752c6SGautham R. Shenoy static int get_cpu_thread_group_start(int cpu, struct thread_groups *tg) 846425752c6SGautham R. Shenoy { 847425752c6SGautham R. Shenoy int hw_cpu_id = get_hard_smp_processor_id(cpu); 848425752c6SGautham R. Shenoy int i, j; 849425752c6SGautham R. Shenoy 850425752c6SGautham R. Shenoy for (i = 0; i < tg->nr_groups; i++) { 851425752c6SGautham R. Shenoy int group_start = i * tg->threads_per_group; 852425752c6SGautham R. Shenoy 853425752c6SGautham R. Shenoy for (j = 0; j < tg->threads_per_group; j++) { 854425752c6SGautham R. Shenoy int idx = group_start + j; 855425752c6SGautham R. Shenoy 856425752c6SGautham R. Shenoy if (tg->thread_list[idx] == hw_cpu_id) 857425752c6SGautham R. Shenoy return group_start; 858425752c6SGautham R. Shenoy } 859425752c6SGautham R. Shenoy } 860425752c6SGautham R. Shenoy 861425752c6SGautham R. Shenoy return -1; 862425752c6SGautham R. Shenoy } 863425752c6SGautham R. Shenoy 864790a1662SGautham R. Shenoy static struct thread_groups *__init get_thread_groups(int cpu, 865790a1662SGautham R. Shenoy int group_property, 866790a1662SGautham R. Shenoy int *err) 867790a1662SGautham R. Shenoy { 868790a1662SGautham R. Shenoy struct device_node *dn = of_get_cpu_node(cpu, NULL); 869790a1662SGautham R. Shenoy struct thread_groups_list *cpu_tgl = &tgl[cpu]; 870790a1662SGautham R. Shenoy struct thread_groups *tg = NULL; 871790a1662SGautham R. Shenoy int i; 872790a1662SGautham R. Shenoy *err = 0; 873790a1662SGautham R. Shenoy 874790a1662SGautham R. Shenoy if (!dn) { 875790a1662SGautham R. Shenoy *err = -ENODATA; 876790a1662SGautham R. Shenoy return NULL; 877790a1662SGautham R. Shenoy } 878790a1662SGautham R. Shenoy 879790a1662SGautham R. Shenoy if (!cpu_tgl->nr_properties) { 880790a1662SGautham R. Shenoy *err = parse_thread_groups(dn, cpu_tgl); 881790a1662SGautham R. Shenoy if (*err) 882790a1662SGautham R. Shenoy goto out; 883790a1662SGautham R. Shenoy } 884790a1662SGautham R. Shenoy 885790a1662SGautham R. Shenoy for (i = 0; i < cpu_tgl->nr_properties; i++) { 886790a1662SGautham R. Shenoy if (cpu_tgl->property_tgs[i].property == group_property) { 887790a1662SGautham R. Shenoy tg = &cpu_tgl->property_tgs[i]; 888790a1662SGautham R. Shenoy break; 889790a1662SGautham R. Shenoy } 890790a1662SGautham R. Shenoy } 891790a1662SGautham R. Shenoy 892790a1662SGautham R. Shenoy if (!tg) 893790a1662SGautham R. Shenoy *err = -EINVAL; 894790a1662SGautham R. Shenoy out: 895790a1662SGautham R. Shenoy of_node_put(dn); 896790a1662SGautham R. Shenoy return tg; 897790a1662SGautham R. Shenoy } 898790a1662SGautham R. Shenoy 899e9ef81e1SParth Shah static int update_mask_from_threadgroup(cpumask_var_t *mask, struct thread_groups *tg, int cpu, int cpu_group_start) 900425752c6SGautham R. Shenoy { 901425752c6SGautham R. Shenoy int first_thread = cpu_first_thread_sibling(cpu); 902e9ef81e1SParth Shah int i; 9039538abeeSGautham R. Shenoy 904fbd2b672SGautham R. Shenoy zalloc_cpumask_var_node(mask, GFP_KERNEL, cpu_to_node(cpu)); 9056e086302SSrikar Dronamraju 906425752c6SGautham R. Shenoy for (i = first_thread; i < first_thread + threads_per_core; i++) { 907790a1662SGautham R. Shenoy int i_group_start = get_cpu_thread_group_start(i, tg); 908425752c6SGautham R. Shenoy 909425752c6SGautham R. Shenoy if (unlikely(i_group_start == -1)) { 910425752c6SGautham R. Shenoy WARN_ON_ONCE(1); 911790a1662SGautham R. Shenoy return -ENODATA; 912425752c6SGautham R. Shenoy } 913425752c6SGautham R. Shenoy 914425752c6SGautham R. Shenoy if (i_group_start == cpu_group_start) 915fbd2b672SGautham R. Shenoy cpumask_set_cpu(i, *mask); 916425752c6SGautham R. Shenoy } 917425752c6SGautham R. Shenoy 918790a1662SGautham R. Shenoy return 0; 919425752c6SGautham R. Shenoy } 920425752c6SGautham R. Shenoy 921e9ef81e1SParth Shah static int __init init_thread_group_cache_map(int cpu, int cache_property) 922e9ef81e1SParth Shah 923e9ef81e1SParth Shah { 924e9ef81e1SParth Shah int cpu_group_start = -1, err = 0; 925e9ef81e1SParth Shah struct thread_groups *tg = NULL; 926e9ef81e1SParth Shah cpumask_var_t *mask = NULL; 927e9ef81e1SParth Shah 928e9ef81e1SParth Shah if (cache_property != THREAD_GROUP_SHARE_L1 && 929e9ef81e1SParth Shah cache_property != THREAD_GROUP_SHARE_L2_L3) 930e9ef81e1SParth Shah return -EINVAL; 931e9ef81e1SParth Shah 932e9ef81e1SParth Shah tg = get_thread_groups(cpu, cache_property, &err); 933e9ef81e1SParth Shah 934e9ef81e1SParth Shah if (!tg) 935e9ef81e1SParth Shah return err; 936e9ef81e1SParth Shah 937e9ef81e1SParth Shah cpu_group_start = get_cpu_thread_group_start(cpu, tg); 938e9ef81e1SParth Shah 939e9ef81e1SParth Shah if (unlikely(cpu_group_start == -1)) { 940e9ef81e1SParth Shah WARN_ON_ONCE(1); 941e9ef81e1SParth Shah return -ENODATA; 942e9ef81e1SParth Shah } 943e9ef81e1SParth Shah 944e9ef81e1SParth Shah if (cache_property == THREAD_GROUP_SHARE_L1) { 945e9ef81e1SParth Shah mask = &per_cpu(thread_group_l1_cache_map, cpu); 946e9ef81e1SParth Shah update_mask_from_threadgroup(mask, tg, cpu, cpu_group_start); 947e9ef81e1SParth Shah } 948e9ef81e1SParth Shah else if (cache_property == THREAD_GROUP_SHARE_L2_L3) { 949e9ef81e1SParth Shah mask = &per_cpu(thread_group_l2_cache_map, cpu); 950e9ef81e1SParth Shah update_mask_from_threadgroup(mask, tg, cpu, cpu_group_start); 951e9ef81e1SParth Shah mask = &per_cpu(thread_group_l3_cache_map, cpu); 952e9ef81e1SParth Shah update_mask_from_threadgroup(mask, tg, cpu, cpu_group_start); 953e9ef81e1SParth Shah } 954e9ef81e1SParth Shah 955e9ef81e1SParth Shah 956e9ef81e1SParth Shah return 0; 957e9ef81e1SParth Shah } 958e9ef81e1SParth Shah 9595e93f16aSSrikar Dronamraju static bool shared_caches; 9605e93f16aSSrikar Dronamraju 9615e93f16aSSrikar Dronamraju #ifdef CONFIG_SCHED_SMT 9625e93f16aSSrikar Dronamraju /* cpumask of CPUs with asymmetric SMT dependency */ 9635e93f16aSSrikar Dronamraju static int powerpc_smt_flags(void) 9645e93f16aSSrikar Dronamraju { 9655e93f16aSSrikar Dronamraju int flags = SD_SHARE_CPUCAPACITY | SD_SHARE_PKG_RESOURCES; 9665e93f16aSSrikar Dronamraju 9675e93f16aSSrikar Dronamraju if (cpu_has_feature(CPU_FTR_ASYM_SMT)) { 9685e93f16aSSrikar Dronamraju printk_once(KERN_INFO "Enabling Asymmetric SMT scheduling\n"); 9695e93f16aSSrikar Dronamraju flags |= SD_ASYM_PACKING; 9705e93f16aSSrikar Dronamraju } 9715e93f16aSSrikar Dronamraju return flags; 9725e93f16aSSrikar Dronamraju } 9735e93f16aSSrikar Dronamraju #endif 9745e93f16aSSrikar Dronamraju 9755e93f16aSSrikar Dronamraju /* 9765e93f16aSSrikar Dronamraju * P9 has a slightly odd architecture where pairs of cores share an L2 cache. 9775e93f16aSSrikar Dronamraju * This topology makes it *much* cheaper to migrate tasks between adjacent cores 9785e93f16aSSrikar Dronamraju * since the migrated task remains cache hot. We want to take advantage of this 9795e93f16aSSrikar Dronamraju * at the scheduler level so an extra topology level is required. 9805e93f16aSSrikar Dronamraju */ 9815e93f16aSSrikar Dronamraju static int powerpc_shared_cache_flags(void) 9825e93f16aSSrikar Dronamraju { 9835e93f16aSSrikar Dronamraju return SD_SHARE_PKG_RESOURCES; 9845e93f16aSSrikar Dronamraju } 9855e93f16aSSrikar Dronamraju 9865e93f16aSSrikar Dronamraju /* 9875e93f16aSSrikar Dronamraju * We can't just pass cpu_l2_cache_mask() directly because 9885e93f16aSSrikar Dronamraju * returns a non-const pointer and the compiler barfs on that. 9895e93f16aSSrikar Dronamraju */ 9905e93f16aSSrikar Dronamraju static const struct cpumask *shared_cache_mask(int cpu) 9915e93f16aSSrikar Dronamraju { 992caa8e29dSSrikar Dronamraju return per_cpu(cpu_l2_cache_map, cpu); 9935e93f16aSSrikar Dronamraju } 9945e93f16aSSrikar Dronamraju 9955e93f16aSSrikar Dronamraju #ifdef CONFIG_SCHED_SMT 9965e93f16aSSrikar Dronamraju static const struct cpumask *smallcore_smt_mask(int cpu) 9975e93f16aSSrikar Dronamraju { 9985e93f16aSSrikar Dronamraju return cpu_smallcore_mask(cpu); 9995e93f16aSSrikar Dronamraju } 10005e93f16aSSrikar Dronamraju #endif 10015e93f16aSSrikar Dronamraju 100272730bfcSSrikar Dronamraju static struct cpumask *cpu_coregroup_mask(int cpu) 100372730bfcSSrikar Dronamraju { 100472730bfcSSrikar Dronamraju return per_cpu(cpu_coregroup_map, cpu); 100572730bfcSSrikar Dronamraju } 100672730bfcSSrikar Dronamraju 100772730bfcSSrikar Dronamraju static bool has_coregroup_support(void) 100872730bfcSSrikar Dronamraju { 100972730bfcSSrikar Dronamraju return coregroup_enabled; 101072730bfcSSrikar Dronamraju } 101172730bfcSSrikar Dronamraju 101272730bfcSSrikar Dronamraju static const struct cpumask *cpu_mc_mask(int cpu) 101372730bfcSSrikar Dronamraju { 101472730bfcSSrikar Dronamraju return cpu_coregroup_mask(cpu); 101572730bfcSSrikar Dronamraju } 101672730bfcSSrikar Dronamraju 10175e93f16aSSrikar Dronamraju static struct sched_domain_topology_level powerpc_topology[] = { 10185e93f16aSSrikar Dronamraju #ifdef CONFIG_SCHED_SMT 10195e93f16aSSrikar Dronamraju { cpu_smt_mask, powerpc_smt_flags, SD_INIT_NAME(SMT) }, 10205e93f16aSSrikar Dronamraju #endif 10215e93f16aSSrikar Dronamraju { shared_cache_mask, powerpc_shared_cache_flags, SD_INIT_NAME(CACHE) }, 102272730bfcSSrikar Dronamraju { cpu_mc_mask, SD_INIT_NAME(MC) }, 10235e93f16aSSrikar Dronamraju { cpu_cpu_mask, SD_INIT_NAME(DIE) }, 10245e93f16aSSrikar Dronamraju { NULL, }, 10255e93f16aSSrikar Dronamraju }; 10265e93f16aSSrikar Dronamraju 10279014eab6SCédric Le Goater static int __init init_big_cores(void) 1028425752c6SGautham R. Shenoy { 1029425752c6SGautham R. Shenoy int cpu; 1030425752c6SGautham R. Shenoy 1031425752c6SGautham R. Shenoy for_each_possible_cpu(cpu) { 1032fbd2b672SGautham R. Shenoy int err = init_thread_group_cache_map(cpu, THREAD_GROUP_SHARE_L1); 1033425752c6SGautham R. Shenoy 1034425752c6SGautham R. Shenoy if (err) 1035425752c6SGautham R. Shenoy return err; 1036425752c6SGautham R. Shenoy 1037425752c6SGautham R. Shenoy zalloc_cpumask_var_node(&per_cpu(cpu_smallcore_map, cpu), 1038425752c6SGautham R. Shenoy GFP_KERNEL, 1039425752c6SGautham R. Shenoy cpu_to_node(cpu)); 1040425752c6SGautham R. Shenoy } 1041425752c6SGautham R. Shenoy 1042425752c6SGautham R. Shenoy has_big_cores = true; 10439538abeeSGautham R. Shenoy 10449538abeeSGautham R. Shenoy for_each_possible_cpu(cpu) { 1045e9ef81e1SParth Shah int err = init_thread_group_cache_map(cpu, THREAD_GROUP_SHARE_L2_L3); 10469538abeeSGautham R. Shenoy 10479538abeeSGautham R. Shenoy if (err) 10489538abeeSGautham R. Shenoy return err; 10499538abeeSGautham R. Shenoy } 10509538abeeSGautham R. Shenoy 10519538abeeSGautham R. Shenoy thread_group_shares_l2 = true; 1052e9ef81e1SParth Shah thread_group_shares_l3 = true; 1053e9ef81e1SParth Shah pr_debug("L2/L3 cache only shared by the threads in the small core\n"); 1054e9ef81e1SParth Shah 1055425752c6SGautham R. Shenoy return 0; 1056425752c6SGautham R. Shenoy } 1057425752c6SGautham R. Shenoy 10585ad57078SPaul Mackerras void __init smp_prepare_cpus(unsigned int max_cpus) 10595ad57078SPaul Mackerras { 10605ad57078SPaul Mackerras unsigned int cpu; 10615ad57078SPaul Mackerras 10625ad57078SPaul Mackerras DBG("smp_prepare_cpus\n"); 10635ad57078SPaul Mackerras 10645ad57078SPaul Mackerras /* 10655ad57078SPaul Mackerras * setup_cpu may need to be called on the boot cpu. We havent 10665ad57078SPaul Mackerras * spun any cpus up but lets be paranoid. 10675ad57078SPaul Mackerras */ 10685ad57078SPaul Mackerras BUG_ON(boot_cpuid != smp_processor_id()); 10695ad57078SPaul Mackerras 10705ad57078SPaul Mackerras /* Fixup boot cpu */ 10715ad57078SPaul Mackerras smp_store_cpu_info(boot_cpuid); 10725ad57078SPaul Mackerras cpu_callin_map[boot_cpuid] = 1; 10735ad57078SPaul Mackerras 1074cc1ba8eaSAnton Blanchard for_each_possible_cpu(cpu) { 1075cc1ba8eaSAnton Blanchard zalloc_cpumask_var_node(&per_cpu(cpu_sibling_map, cpu), 1076cc1ba8eaSAnton Blanchard GFP_KERNEL, cpu_to_node(cpu)); 10772a636a56SOliver O'Halloran zalloc_cpumask_var_node(&per_cpu(cpu_l2_cache_map, cpu), 10782a636a56SOliver O'Halloran GFP_KERNEL, cpu_to_node(cpu)); 1079cc1ba8eaSAnton Blanchard zalloc_cpumask_var_node(&per_cpu(cpu_core_map, cpu), 1080cc1ba8eaSAnton Blanchard GFP_KERNEL, cpu_to_node(cpu)); 108172730bfcSSrikar Dronamraju if (has_coregroup_support()) 108272730bfcSSrikar Dronamraju zalloc_cpumask_var_node(&per_cpu(cpu_coregroup_map, cpu), 108372730bfcSSrikar Dronamraju GFP_KERNEL, cpu_to_node(cpu)); 108472730bfcSSrikar Dronamraju 1085a9ee6cf5SMike Rapoport #ifdef CONFIG_NUMA 10862fabf084SNishanth Aravamudan /* 10872fabf084SNishanth Aravamudan * numa_node_id() works after this. 10882fabf084SNishanth Aravamudan */ 1089bc3c4327SLi Zhong if (cpu_present(cpu)) { 10902fabf084SNishanth Aravamudan set_cpu_numa_node(cpu, numa_cpu_lookup_table[cpu]); 1091bc3c4327SLi Zhong set_cpu_numa_mem(cpu, 1092bc3c4327SLi Zhong local_memory_node(numa_cpu_lookup_table[cpu])); 1093bc3c4327SLi Zhong } 1094d0fd24bbSSrikar Dronamraju #endif 1095cc1ba8eaSAnton Blanchard } 1096cc1ba8eaSAnton Blanchard 1097df52f671SOliver O'Halloran /* Init the cpumasks so the boot CPU is related to itself */ 1098cc1ba8eaSAnton Blanchard cpumask_set_cpu(boot_cpuid, cpu_sibling_mask(boot_cpuid)); 10992a636a56SOliver O'Halloran cpumask_set_cpu(boot_cpuid, cpu_l2_cache_mask(boot_cpuid)); 1100c47f892dSSrikar Dronamraju cpumask_set_cpu(boot_cpuid, cpu_core_mask(boot_cpuid)); 1101cc1ba8eaSAnton Blanchard 110272730bfcSSrikar Dronamraju if (has_coregroup_support()) 110372730bfcSSrikar Dronamraju cpumask_set_cpu(boot_cpuid, cpu_coregroup_mask(boot_cpuid)); 110472730bfcSSrikar Dronamraju 1105425752c6SGautham R. Shenoy init_big_cores(); 1106425752c6SGautham R. Shenoy if (has_big_cores) { 1107425752c6SGautham R. Shenoy cpumask_set_cpu(boot_cpuid, 1108425752c6SGautham R. Shenoy cpu_smallcore_mask(boot_cpuid)); 1109425752c6SGautham R. Shenoy } 1110425752c6SGautham R. Shenoy 1111c1e53367SSrikar Dronamraju if (cpu_to_chip_id(boot_cpuid) != -1) { 11128efd249bSSrikar Dronamraju int idx = DIV_ROUND_UP(num_possible_cpus(), threads_per_core); 1113c1e53367SSrikar Dronamraju 1114c1e53367SSrikar Dronamraju /* 1115c1e53367SSrikar Dronamraju * All threads of a core will all belong to the same core, 1116c1e53367SSrikar Dronamraju * chip_id_lookup_table will have one entry per core. 1117c1e53367SSrikar Dronamraju * Assumption: if boot_cpuid doesn't have a chip-id, then no 1118c1e53367SSrikar Dronamraju * other CPUs, will also not have chip-id. 1119c1e53367SSrikar Dronamraju */ 1120c1e53367SSrikar Dronamraju chip_id_lookup_table = kcalloc(idx, sizeof(int), GFP_KERNEL); 1121c1e53367SSrikar Dronamraju if (chip_id_lookup_table) 1122c1e53367SSrikar Dronamraju memset(chip_id_lookup_table, -1, sizeof(int) * idx); 1123c1e53367SSrikar Dronamraju } 1124c1e53367SSrikar Dronamraju 1125dfee0efeSChen Gang if (smp_ops && smp_ops->probe) 1126dfee0efeSChen Gang smp_ops->probe(); 11275ad57078SPaul Mackerras } 11285ad57078SPaul Mackerras 1129cad5cef6SGreg Kroah-Hartman void smp_prepare_boot_cpu(void) 11305ad57078SPaul Mackerras { 11315ad57078SPaul Mackerras BUG_ON(smp_processor_id() != boot_cpuid); 11325ad57078SPaul Mackerras #ifdef CONFIG_PPC64 1133d2e60075SNicholas Piggin paca_ptrs[boot_cpuid]->__current = current; 11345ad57078SPaul Mackerras #endif 11358c272261SNishanth Aravamudan set_numa_node(numa_cpu_lookup_table[boot_cpuid]); 11367c19c2e5SChristophe Leroy current_set[boot_cpuid] = current; 11375ad57078SPaul Mackerras } 11385ad57078SPaul Mackerras 11395ad57078SPaul Mackerras #ifdef CONFIG_HOTPLUG_CPU 11405ad57078SPaul Mackerras 11415ad57078SPaul Mackerras int generic_cpu_disable(void) 11425ad57078SPaul Mackerras { 11435ad57078SPaul Mackerras unsigned int cpu = smp_processor_id(); 11445ad57078SPaul Mackerras 11455ad57078SPaul Mackerras if (cpu == boot_cpuid) 11465ad57078SPaul Mackerras return -EBUSY; 11475ad57078SPaul Mackerras 1148ea0f1cabSRusty Russell set_cpu_online(cpu, false); 1149799d6046SPaul Mackerras #ifdef CONFIG_PPC64 1150a7f290daSBenjamin Herrenschmidt vdso_data->processorCount--; 1151094fe2e7SPaul Mackerras #endif 1152a978e139SBenjamin Herrenschmidt /* Update affinity of all IRQs previously aimed at this CPU */ 1153a978e139SBenjamin Herrenschmidt irq_migrate_all_off_this_cpu(); 1154a978e139SBenjamin Herrenschmidt 1155687b8f24SMichael Ellerman /* 1156687b8f24SMichael Ellerman * Depending on the details of the interrupt controller, it's possible 1157687b8f24SMichael Ellerman * that one of the interrupts we just migrated away from this CPU is 1158687b8f24SMichael Ellerman * actually already pending on this CPU. If we leave it in that state 1159687b8f24SMichael Ellerman * the interrupt will never be EOI'ed, and will never fire again. So 1160687b8f24SMichael Ellerman * temporarily enable interrupts here, to allow any pending interrupt to 1161687b8f24SMichael Ellerman * be received (and EOI'ed), before we take this CPU offline. 1162687b8f24SMichael Ellerman */ 1163a978e139SBenjamin Herrenschmidt local_irq_enable(); 1164a978e139SBenjamin Herrenschmidt mdelay(1); 1165a978e139SBenjamin Herrenschmidt local_irq_disable(); 1166a978e139SBenjamin Herrenschmidt 11675ad57078SPaul Mackerras return 0; 11685ad57078SPaul Mackerras } 11695ad57078SPaul Mackerras 11705ad57078SPaul Mackerras void generic_cpu_die(unsigned int cpu) 11715ad57078SPaul Mackerras { 11725ad57078SPaul Mackerras int i; 11735ad57078SPaul Mackerras 11745ad57078SPaul Mackerras for (i = 0; i < 100; i++) { 11755ad57078SPaul Mackerras smp_rmb(); 11762f4f1f81Schenhui zhao if (is_cpu_dead(cpu)) 11775ad57078SPaul Mackerras return; 11785ad57078SPaul Mackerras msleep(100); 11795ad57078SPaul Mackerras } 11805ad57078SPaul Mackerras printk(KERN_ERR "CPU%d didn't die...\n", cpu); 11815ad57078SPaul Mackerras } 11825ad57078SPaul Mackerras 1183105765f4SBenjamin Herrenschmidt void generic_set_cpu_dead(unsigned int cpu) 1184105765f4SBenjamin Herrenschmidt { 1185105765f4SBenjamin Herrenschmidt per_cpu(cpu_state, cpu) = CPU_DEAD; 1186105765f4SBenjamin Herrenschmidt } 1187fb82b839SBenjamin Herrenschmidt 1188ae5cab47SZhao Chenhui /* 1189ae5cab47SZhao Chenhui * The cpu_state should be set to CPU_UP_PREPARE in kick_cpu(), otherwise 1190ae5cab47SZhao Chenhui * the cpu_state is always CPU_DEAD after calling generic_set_cpu_dead(), 1191ae5cab47SZhao Chenhui * which makes the delay in generic_cpu_die() not happen. 1192ae5cab47SZhao Chenhui */ 1193ae5cab47SZhao Chenhui void generic_set_cpu_up(unsigned int cpu) 1194ae5cab47SZhao Chenhui { 1195ae5cab47SZhao Chenhui per_cpu(cpu_state, cpu) = CPU_UP_PREPARE; 1196ae5cab47SZhao Chenhui } 1197ae5cab47SZhao Chenhui 1198fb82b839SBenjamin Herrenschmidt int generic_check_cpu_restart(unsigned int cpu) 1199fb82b839SBenjamin Herrenschmidt { 1200fb82b839SBenjamin Herrenschmidt return per_cpu(cpu_state, cpu) == CPU_UP_PREPARE; 1201fb82b839SBenjamin Herrenschmidt } 1202512691d4SPaul Mackerras 12032f4f1f81Schenhui zhao int is_cpu_dead(unsigned int cpu) 12042f4f1f81Schenhui zhao { 12052f4f1f81Schenhui zhao return per_cpu(cpu_state, cpu) == CPU_DEAD; 12062f4f1f81Schenhui zhao } 12072f4f1f81Schenhui zhao 1208441c19c8SMichael Ellerman static bool secondaries_inhibited(void) 1209512691d4SPaul Mackerras { 1210441c19c8SMichael Ellerman return kvm_hv_mode_active(); 1211512691d4SPaul Mackerras } 1212512691d4SPaul Mackerras 1213512691d4SPaul Mackerras #else /* HOTPLUG_CPU */ 1214512691d4SPaul Mackerras 1215512691d4SPaul Mackerras #define secondaries_inhibited() 0 1216512691d4SPaul Mackerras 12175ad57078SPaul Mackerras #endif 12185ad57078SPaul Mackerras 121917e32eacSThomas Gleixner static void cpu_idle_thread_init(unsigned int cpu, struct task_struct *idle) 1220c56e5853SBenjamin Herrenschmidt { 1221c56e5853SBenjamin Herrenschmidt #ifdef CONFIG_PPC64 1222d2e60075SNicholas Piggin paca_ptrs[cpu]->__current = idle; 1223678c668aSChristophe Leroy paca_ptrs[cpu]->kstack = (unsigned long)task_stack_page(idle) + 1224678c668aSChristophe Leroy THREAD_SIZE - STACK_FRAME_OVERHEAD; 1225c56e5853SBenjamin Herrenschmidt #endif 1226ed1cd6deSChristophe Leroy idle->cpu = cpu; 12277c19c2e5SChristophe Leroy secondary_current = current_set[cpu] = idle; 1228c56e5853SBenjamin Herrenschmidt } 1229c56e5853SBenjamin Herrenschmidt 1230061d19f2SPaul Gortmaker int __cpu_up(unsigned int cpu, struct task_struct *tidle) 12315ad57078SPaul Mackerras { 1232c56e5853SBenjamin Herrenschmidt int rc, c; 12335ad57078SPaul Mackerras 1234512691d4SPaul Mackerras /* 1235512691d4SPaul Mackerras * Don't allow secondary threads to come online if inhibited 1236512691d4SPaul Mackerras */ 1237512691d4SPaul Mackerras if (threads_per_core > 1 && secondaries_inhibited() && 12386f5e40a3SMichael Ellerman cpu_thread_in_subcore(cpu)) 1239512691d4SPaul Mackerras return -EBUSY; 1240512691d4SPaul Mackerras 12418cffc6acSBenjamin Herrenschmidt if (smp_ops == NULL || 12428cffc6acSBenjamin Herrenschmidt (smp_ops->cpu_bootable && !smp_ops->cpu_bootable(cpu))) 12435ad57078SPaul Mackerras return -EINVAL; 12445ad57078SPaul Mackerras 124517e32eacSThomas Gleixner cpu_idle_thread_init(cpu, tidle); 1246c560bbceSkerstin jonsson 124714d4ae5cSBenjamin Herrenschmidt /* 124814d4ae5cSBenjamin Herrenschmidt * The platform might need to allocate resources prior to bringing 124914d4ae5cSBenjamin Herrenschmidt * up the CPU 125014d4ae5cSBenjamin Herrenschmidt */ 125114d4ae5cSBenjamin Herrenschmidt if (smp_ops->prepare_cpu) { 125214d4ae5cSBenjamin Herrenschmidt rc = smp_ops->prepare_cpu(cpu); 125314d4ae5cSBenjamin Herrenschmidt if (rc) 125414d4ae5cSBenjamin Herrenschmidt return rc; 125514d4ae5cSBenjamin Herrenschmidt } 125614d4ae5cSBenjamin Herrenschmidt 12575ad57078SPaul Mackerras /* Make sure callin-map entry is 0 (can be leftover a CPU 12585ad57078SPaul Mackerras * hotplug 12595ad57078SPaul Mackerras */ 12605ad57078SPaul Mackerras cpu_callin_map[cpu] = 0; 12615ad57078SPaul Mackerras 12625ad57078SPaul Mackerras /* The information for processor bringup must 12635ad57078SPaul Mackerras * be written out to main store before we release 12645ad57078SPaul Mackerras * the processor. 12655ad57078SPaul Mackerras */ 12665ad57078SPaul Mackerras smp_mb(); 12675ad57078SPaul Mackerras 12685ad57078SPaul Mackerras /* wake up cpus */ 12695ad57078SPaul Mackerras DBG("smp: kicking cpu %d\n", cpu); 1270de300974SMichael Ellerman rc = smp_ops->kick_cpu(cpu); 1271de300974SMichael Ellerman if (rc) { 1272de300974SMichael Ellerman pr_err("smp: failed starting cpu %d (rc %d)\n", cpu, rc); 1273de300974SMichael Ellerman return rc; 1274de300974SMichael Ellerman } 12755ad57078SPaul Mackerras 12765ad57078SPaul Mackerras /* 12775ad57078SPaul Mackerras * wait to see if the cpu made a callin (is actually up). 12785ad57078SPaul Mackerras * use this value that I found through experimentation. 12795ad57078SPaul Mackerras * -- Cort 12805ad57078SPaul Mackerras */ 12815ad57078SPaul Mackerras if (system_state < SYSTEM_RUNNING) 1282ee0339f2SJon Loeliger for (c = 50000; c && !cpu_callin_map[cpu]; c--) 12835ad57078SPaul Mackerras udelay(100); 12845ad57078SPaul Mackerras #ifdef CONFIG_HOTPLUG_CPU 12855ad57078SPaul Mackerras else 12865ad57078SPaul Mackerras /* 12875ad57078SPaul Mackerras * CPUs can take much longer to come up in the 12885ad57078SPaul Mackerras * hotplug case. Wait five seconds. 12895ad57078SPaul Mackerras */ 129067764263SGautham R Shenoy for (c = 5000; c && !cpu_callin_map[cpu]; c--) 129167764263SGautham R Shenoy msleep(1); 12925ad57078SPaul Mackerras #endif 12935ad57078SPaul Mackerras 12945ad57078SPaul Mackerras if (!cpu_callin_map[cpu]) { 12956685a477SSigned-off-by: Darren Hart printk(KERN_ERR "Processor %u is stuck.\n", cpu); 12965ad57078SPaul Mackerras return -ENOENT; 12975ad57078SPaul Mackerras } 12985ad57078SPaul Mackerras 12996685a477SSigned-off-by: Darren Hart DBG("Processor %u found.\n", cpu); 13005ad57078SPaul Mackerras 13015ad57078SPaul Mackerras if (smp_ops->give_timebase) 13025ad57078SPaul Mackerras smp_ops->give_timebase(); 13035ad57078SPaul Mackerras 1304875ebe94SMichael Ellerman /* Wait until cpu puts itself in the online & active maps */ 13054e287e65SNicholas Piggin spin_until_cond(cpu_online(cpu)); 13065ad57078SPaul Mackerras 13075ad57078SPaul Mackerras return 0; 13085ad57078SPaul Mackerras } 13095ad57078SPaul Mackerras 1310e9efed3bSNathan Lynch /* Return the value of the reg property corresponding to the given 1311e9efed3bSNathan Lynch * logical cpu. 1312e9efed3bSNathan Lynch */ 1313e9efed3bSNathan Lynch int cpu_to_core_id(int cpu) 1314e9efed3bSNathan Lynch { 1315e9efed3bSNathan Lynch struct device_node *np; 1316f8a1883aSAnton Blanchard const __be32 *reg; 1317e9efed3bSNathan Lynch int id = -1; 1318e9efed3bSNathan Lynch 1319e9efed3bSNathan Lynch np = of_get_cpu_node(cpu, NULL); 1320e9efed3bSNathan Lynch if (!np) 1321e9efed3bSNathan Lynch goto out; 1322e9efed3bSNathan Lynch 1323e9efed3bSNathan Lynch reg = of_get_property(np, "reg", NULL); 1324e9efed3bSNathan Lynch if (!reg) 1325e9efed3bSNathan Lynch goto out; 1326e9efed3bSNathan Lynch 1327f8a1883aSAnton Blanchard id = be32_to_cpup(reg); 1328e9efed3bSNathan Lynch out: 1329e9efed3bSNathan Lynch of_node_put(np); 1330e9efed3bSNathan Lynch return id; 1331e9efed3bSNathan Lynch } 1332f8ab4810SMauricio Faria de Oliveira EXPORT_SYMBOL_GPL(cpu_to_core_id); 1333e9efed3bSNathan Lynch 133499d86705SVaidyanathan Srinivasan /* Helper routines for cpu to core mapping */ 133599d86705SVaidyanathan Srinivasan int cpu_core_index_of_thread(int cpu) 133699d86705SVaidyanathan Srinivasan { 133799d86705SVaidyanathan Srinivasan return cpu >> threads_shift; 133899d86705SVaidyanathan Srinivasan } 133999d86705SVaidyanathan Srinivasan EXPORT_SYMBOL_GPL(cpu_core_index_of_thread); 134099d86705SVaidyanathan Srinivasan 134199d86705SVaidyanathan Srinivasan int cpu_first_thread_of_core(int core) 134299d86705SVaidyanathan Srinivasan { 134399d86705SVaidyanathan Srinivasan return core << threads_shift; 134499d86705SVaidyanathan Srinivasan } 134599d86705SVaidyanathan Srinivasan EXPORT_SYMBOL_GPL(cpu_first_thread_of_core); 134699d86705SVaidyanathan Srinivasan 1347104699c0SKOSAKI Motohiro /* Must be called when no change can occur to cpu_present_mask, 1348440a0857SNathan Lynch * i.e. during cpu online or offline. 1349440a0857SNathan Lynch */ 1350440a0857SNathan Lynch static struct device_node *cpu_to_l2cache(int cpu) 1351440a0857SNathan Lynch { 1352440a0857SNathan Lynch struct device_node *np; 1353b2ea25b9SNathan Lynch struct device_node *cache; 1354440a0857SNathan Lynch 1355440a0857SNathan Lynch if (!cpu_present(cpu)) 1356440a0857SNathan Lynch return NULL; 1357440a0857SNathan Lynch 1358440a0857SNathan Lynch np = of_get_cpu_node(cpu, NULL); 1359440a0857SNathan Lynch if (np == NULL) 1360440a0857SNathan Lynch return NULL; 1361440a0857SNathan Lynch 1362b2ea25b9SNathan Lynch cache = of_find_next_cache_node(np); 1363b2ea25b9SNathan Lynch 1364440a0857SNathan Lynch of_node_put(np); 1365440a0857SNathan Lynch 1366b2ea25b9SNathan Lynch return cache; 1367440a0857SNathan Lynch } 13685ad57078SPaul Mackerras 136984dbf66cSSrikar Dronamraju static bool update_mask_by_l2(int cpu, cpumask_var_t *mask) 1370a8a5356cSPaul Mackerras { 13713ab33d6dSSrikar Dronamraju struct cpumask *(*submask_fn)(int) = cpu_sibling_mask; 1372256f2d4bSPaul Mackerras struct device_node *l2_cache, *np; 1373e3d8b67eSOliver O'Halloran int i; 1374256f2d4bSPaul Mackerras 1375966730a6SSrikar Dronamraju if (has_big_cores) 1376966730a6SSrikar Dronamraju submask_fn = cpu_smallcore_mask; 1377966730a6SSrikar Dronamraju 13789538abeeSGautham R. Shenoy /* 13799538abeeSGautham R. Shenoy * If the threads in a thread-group share L2 cache, then the 13809538abeeSGautham R. Shenoy * L2-mask can be obtained from thread_group_l2_cache_map. 13819538abeeSGautham R. Shenoy */ 13829538abeeSGautham R. Shenoy if (thread_group_shares_l2) { 13839538abeeSGautham R. Shenoy cpumask_set_cpu(cpu, cpu_l2_cache_mask(cpu)); 13849538abeeSGautham R. Shenoy 13859538abeeSGautham R. Shenoy for_each_cpu(i, per_cpu(thread_group_l2_cache_map, cpu)) { 13869538abeeSGautham R. Shenoy if (cpu_online(i)) 13879538abeeSGautham R. Shenoy set_cpus_related(i, cpu, cpu_l2_cache_mask); 13889538abeeSGautham R. Shenoy } 13899538abeeSGautham R. Shenoy 13909538abeeSGautham R. Shenoy /* Verify that L1-cache siblings are a subset of L2 cache-siblings */ 13919538abeeSGautham R. Shenoy if (!cpumask_equal(submask_fn(cpu), cpu_l2_cache_mask(cpu)) && 13929538abeeSGautham R. Shenoy !cpumask_subset(submask_fn(cpu), cpu_l2_cache_mask(cpu))) { 13939538abeeSGautham R. Shenoy pr_warn_once("CPU %d : Inconsistent L1 and L2 cache siblings\n", 13949538abeeSGautham R. Shenoy cpu); 13959538abeeSGautham R. Shenoy } 13969538abeeSGautham R. Shenoy 13979538abeeSGautham R. Shenoy return true; 13989538abeeSGautham R. Shenoy } 13999538abeeSGautham R. Shenoy 1400a8a5356cSPaul Mackerras l2_cache = cpu_to_l2cache(cpu); 140184dbf66cSSrikar Dronamraju if (!l2_cache || !*mask) { 140284dbf66cSSrikar Dronamraju /* Assume only core siblings share cache with this CPU */ 1403966730a6SSrikar Dronamraju for_each_cpu(i, submask_fn(cpu)) 1404f6606cfdSSrikar Dronamraju set_cpus_related(cpu, i, cpu_l2_cache_mask); 1405f6606cfdSSrikar Dronamraju 1406f6606cfdSSrikar Dronamraju return false; 1407f6606cfdSSrikar Dronamraju } 1408f6606cfdSSrikar Dronamraju 140984dbf66cSSrikar Dronamraju cpumask_and(*mask, cpu_online_mask, cpu_cpu_mask(cpu)); 14103ab33d6dSSrikar Dronamraju 14113ab33d6dSSrikar Dronamraju /* Update l2-cache mask with all the CPUs that are part of submask */ 14123ab33d6dSSrikar Dronamraju or_cpumasks_related(cpu, cpu, submask_fn, cpu_l2_cache_mask); 14133ab33d6dSSrikar Dronamraju 14143ab33d6dSSrikar Dronamraju /* Skip all CPUs already part of current CPU l2-cache mask */ 141584dbf66cSSrikar Dronamraju cpumask_andnot(*mask, *mask, cpu_l2_cache_mask(cpu)); 14163ab33d6dSSrikar Dronamraju 141784dbf66cSSrikar Dronamraju for_each_cpu(i, *mask) { 1418df52f671SOliver O'Halloran /* 1419df52f671SOliver O'Halloran * when updating the marks the current CPU has not been marked 1420df52f671SOliver O'Halloran * online, but we need to update the cache masks 1421df52f671SOliver O'Halloran */ 1422256f2d4bSPaul Mackerras np = cpu_to_l2cache(i); 1423df52f671SOliver O'Halloran 14243ab33d6dSSrikar Dronamraju /* Skip all CPUs already part of current CPU l2-cache */ 14253ab33d6dSSrikar Dronamraju if (np == l2_cache) { 14263ab33d6dSSrikar Dronamraju or_cpumasks_related(cpu, i, submask_fn, cpu_l2_cache_mask); 142784dbf66cSSrikar Dronamraju cpumask_andnot(*mask, *mask, submask_fn(i)); 14283ab33d6dSSrikar Dronamraju } else { 142984dbf66cSSrikar Dronamraju cpumask_andnot(*mask, *mask, cpu_l2_cache_mask(i)); 14303ab33d6dSSrikar Dronamraju } 1431df52f671SOliver O'Halloran 1432a8a5356cSPaul Mackerras of_node_put(np); 1433a8a5356cSPaul Mackerras } 1434a8a5356cSPaul Mackerras of_node_put(l2_cache); 1435df52f671SOliver O'Halloran 1436df52f671SOliver O'Halloran return true; 1437df52f671SOliver O'Halloran } 1438df52f671SOliver O'Halloran 1439df52f671SOliver O'Halloran #ifdef CONFIG_HOTPLUG_CPU 1440df52f671SOliver O'Halloran static void remove_cpu_from_masks(int cpu) 1441df52f671SOliver O'Halloran { 144270edd4a7SSrikar Dronamraju struct cpumask *(*mask_fn)(int) = cpu_sibling_mask; 1443df52f671SOliver O'Halloran int i; 1444df52f671SOliver O'Halloran 144570edd4a7SSrikar Dronamraju if (shared_caches) 144670edd4a7SSrikar Dronamraju mask_fn = cpu_l2_cache_mask; 144770edd4a7SSrikar Dronamraju 144870edd4a7SSrikar Dronamraju for_each_cpu(i, mask_fn(cpu)) { 14492a636a56SOliver O'Halloran set_cpus_unrelated(cpu, i, cpu_l2_cache_mask); 1450df52f671SOliver O'Halloran set_cpus_unrelated(cpu, i, cpu_sibling_mask); 1451425752c6SGautham R. Shenoy if (has_big_cores) 1452425752c6SGautham R. Shenoy set_cpus_unrelated(cpu, i, cpu_smallcore_mask); 145370edd4a7SSrikar Dronamraju } 145470edd4a7SSrikar Dronamraju 1455c47f892dSSrikar Dronamraju for_each_cpu(i, cpu_core_mask(cpu)) 1456c47f892dSSrikar Dronamraju set_cpus_unrelated(cpu, i, cpu_core_mask); 1457c47f892dSSrikar Dronamraju 145870edd4a7SSrikar Dronamraju if (has_coregroup_support()) { 145970edd4a7SSrikar Dronamraju for_each_cpu(i, cpu_coregroup_mask(cpu)) 146072730bfcSSrikar Dronamraju set_cpus_unrelated(cpu, i, cpu_coregroup_mask); 1461df52f671SOliver O'Halloran } 1462df52f671SOliver O'Halloran } 1463df52f671SOliver O'Halloran #endif 1464df52f671SOliver O'Halloran 1465425752c6SGautham R. Shenoy static inline void add_cpu_to_smallcore_masks(int cpu) 1466425752c6SGautham R. Shenoy { 1467661e3d42SSrikar Dronamraju int i; 1468425752c6SGautham R. Shenoy 1469425752c6SGautham R. Shenoy if (!has_big_cores) 1470425752c6SGautham R. Shenoy return; 1471425752c6SGautham R. Shenoy 1472425752c6SGautham R. Shenoy cpumask_set_cpu(cpu, cpu_smallcore_mask(cpu)); 1473425752c6SGautham R. Shenoy 14741fdc1d66SGautham R. Shenoy for_each_cpu(i, per_cpu(thread_group_l1_cache_map, cpu)) { 1475661e3d42SSrikar Dronamraju if (cpu_online(i)) 1476425752c6SGautham R. Shenoy set_cpus_related(i, cpu, cpu_smallcore_mask); 1477425752c6SGautham R. Shenoy } 1478425752c6SGautham R. Shenoy } 1479425752c6SGautham R. Shenoy 148084dbf66cSSrikar Dronamraju static void update_coregroup_mask(int cpu, cpumask_var_t *mask) 1481b8a97cb4SSrikar Dronamraju { 148270a94089SSrikar Dronamraju struct cpumask *(*submask_fn)(int) = cpu_sibling_mask; 1483b8a97cb4SSrikar Dronamraju int coregroup_id = cpu_to_coregroup_id(cpu); 1484b8a97cb4SSrikar Dronamraju int i; 1485b8a97cb4SSrikar Dronamraju 148670a94089SSrikar Dronamraju if (shared_caches) 148770a94089SSrikar Dronamraju submask_fn = cpu_l2_cache_mask; 148870a94089SSrikar Dronamraju 148984dbf66cSSrikar Dronamraju if (!*mask) { 149084dbf66cSSrikar Dronamraju /* Assume only siblings are part of this CPU's coregroup */ 149184dbf66cSSrikar Dronamraju for_each_cpu(i, submask_fn(cpu)) 149284dbf66cSSrikar Dronamraju set_cpus_related(cpu, i, cpu_coregroup_mask); 149384dbf66cSSrikar Dronamraju 149484dbf66cSSrikar Dronamraju return; 149584dbf66cSSrikar Dronamraju } 149684dbf66cSSrikar Dronamraju 149784dbf66cSSrikar Dronamraju cpumask_and(*mask, cpu_online_mask, cpu_cpu_mask(cpu)); 149884dbf66cSSrikar Dronamraju 149970a94089SSrikar Dronamraju /* Update coregroup mask with all the CPUs that are part of submask */ 150070a94089SSrikar Dronamraju or_cpumasks_related(cpu, cpu, submask_fn, cpu_coregroup_mask); 150170a94089SSrikar Dronamraju 150270a94089SSrikar Dronamraju /* Skip all CPUs already part of coregroup mask */ 150384dbf66cSSrikar Dronamraju cpumask_andnot(*mask, *mask, cpu_coregroup_mask(cpu)); 150470a94089SSrikar Dronamraju 150584dbf66cSSrikar Dronamraju for_each_cpu(i, *mask) { 150670a94089SSrikar Dronamraju /* Skip all CPUs not part of this coregroup */ 150770a94089SSrikar Dronamraju if (coregroup_id == cpu_to_coregroup_id(i)) { 150870a94089SSrikar Dronamraju or_cpumasks_related(cpu, i, submask_fn, cpu_coregroup_mask); 150984dbf66cSSrikar Dronamraju cpumask_andnot(*mask, *mask, submask_fn(i)); 151070a94089SSrikar Dronamraju } else { 151184dbf66cSSrikar Dronamraju cpumask_andnot(*mask, *mask, cpu_coregroup_mask(i)); 1512b8a97cb4SSrikar Dronamraju } 1513b8a97cb4SSrikar Dronamraju } 151470a94089SSrikar Dronamraju } 1515b8a97cb4SSrikar Dronamraju 1516df52f671SOliver O'Halloran static void add_cpu_to_masks(int cpu) 1517df52f671SOliver O'Halloran { 1518c47f892dSSrikar Dronamraju struct cpumask *(*submask_fn)(int) = cpu_sibling_mask; 1519df52f671SOliver O'Halloran int first_thread = cpu_first_thread_sibling(cpu); 152084dbf66cSSrikar Dronamraju cpumask_var_t mask; 1521c1e53367SSrikar Dronamraju int chip_id = -1; 1522c47f892dSSrikar Dronamraju bool ret; 1523df52f671SOliver O'Halloran int i; 1524df52f671SOliver O'Halloran 1525df52f671SOliver O'Halloran /* 1526df52f671SOliver O'Halloran * This CPU will not be in the online mask yet so we need to manually 1527df52f671SOliver O'Halloran * add it to it's own thread sibling mask. 1528df52f671SOliver O'Halloran */ 1529df52f671SOliver O'Halloran cpumask_set_cpu(cpu, cpu_sibling_mask(cpu)); 1530*b8b92803SSrikar Dronamraju cpumask_set_cpu(cpu, cpu_core_mask(cpu)); 1531df52f671SOliver O'Halloran 1532df52f671SOliver O'Halloran for (i = first_thread; i < first_thread + threads_per_core; i++) 1533df52f671SOliver O'Halloran if (cpu_online(i)) 1534df52f671SOliver O'Halloran set_cpus_related(i, cpu, cpu_sibling_mask); 1535df52f671SOliver O'Halloran 1536425752c6SGautham R. Shenoy add_cpu_to_smallcore_masks(cpu); 153784dbf66cSSrikar Dronamraju 153884dbf66cSSrikar Dronamraju /* In CPU-hotplug path, hence use GFP_ATOMIC */ 1539c47f892dSSrikar Dronamraju ret = alloc_cpumask_var_node(&mask, GFP_ATOMIC, cpu_to_node(cpu)); 154084dbf66cSSrikar Dronamraju update_mask_by_l2(cpu, &mask); 15412a636a56SOliver O'Halloran 1542b8a97cb4SSrikar Dronamraju if (has_coregroup_support()) 154384dbf66cSSrikar Dronamraju update_coregroup_mask(cpu, &mask); 154484dbf66cSSrikar Dronamraju 1545c1e53367SSrikar Dronamraju if (chip_id_lookup_table && ret) 1546c1e53367SSrikar Dronamraju chip_id = cpu_to_chip_id(cpu); 1547c1e53367SSrikar Dronamraju 1548c47f892dSSrikar Dronamraju if (shared_caches) 1549c47f892dSSrikar Dronamraju submask_fn = cpu_l2_cache_mask; 1550c47f892dSSrikar Dronamraju 1551c47f892dSSrikar Dronamraju /* Update core_mask with all the CPUs that are part of submask */ 1552c47f892dSSrikar Dronamraju or_cpumasks_related(cpu, cpu, submask_fn, cpu_core_mask); 1553c47f892dSSrikar Dronamraju 1554c47f892dSSrikar Dronamraju /* Skip all CPUs already part of current CPU core mask */ 1555c47f892dSSrikar Dronamraju cpumask_andnot(mask, cpu_online_mask, cpu_core_mask(cpu)); 1556c47f892dSSrikar Dronamraju 1557*b8b92803SSrikar Dronamraju /* If chip_id is -1; limit the cpu_core_mask to within DIE*/ 1558*b8b92803SSrikar Dronamraju if (chip_id == -1) 1559*b8b92803SSrikar Dronamraju cpumask_and(mask, mask, cpu_cpu_mask(cpu)); 1560*b8b92803SSrikar Dronamraju 1561c47f892dSSrikar Dronamraju for_each_cpu(i, mask) { 1562c47f892dSSrikar Dronamraju if (chip_id == cpu_to_chip_id(i)) { 1563c47f892dSSrikar Dronamraju or_cpumasks_related(cpu, i, submask_fn, cpu_core_mask); 1564c47f892dSSrikar Dronamraju cpumask_andnot(mask, mask, submask_fn(i)); 1565c47f892dSSrikar Dronamraju } else { 1566c47f892dSSrikar Dronamraju cpumask_andnot(mask, mask, cpu_core_mask(i)); 1567c47f892dSSrikar Dronamraju } 1568c47f892dSSrikar Dronamraju } 1569c47f892dSSrikar Dronamraju 157084dbf66cSSrikar Dronamraju free_cpumask_var(mask); 1571a8a5356cSPaul Mackerras } 1572a8a5356cSPaul Mackerras 15735ad57078SPaul Mackerras /* Activate a secondary processor. */ 1574061d19f2SPaul Gortmaker void start_secondary(void *unused) 15755ad57078SPaul Mackerras { 157699f070b6SQian Cai unsigned int cpu = raw_smp_processor_id(); 15775ad57078SPaul Mackerras 157886f46f34SChristophe Leroy /* PPC64 calls setup_kup() in early_setup_secondary() */ 157986f46f34SChristophe Leroy if (IS_ENABLED(CONFIG_PPC32)) 158086f46f34SChristophe Leroy setup_kup(); 158186f46f34SChristophe Leroy 1582f1f10076SVegard Nossum mmgrab(&init_mm); 15835ad57078SPaul Mackerras current->active_mm = &init_mm; 15845ad57078SPaul Mackerras 15855ad57078SPaul Mackerras smp_store_cpu_info(cpu); 15865ad57078SPaul Mackerras set_dec(tb_ticks_per_jiffy); 158799f070b6SQian Cai rcu_cpu_starting(cpu); 15881be6f10fSMichael Ellerman cpu_callin_map[cpu] = 1; 15895ad57078SPaul Mackerras 1590757cbd46SKumar Gala if (smp_ops->setup_cpu) 15915ad57078SPaul Mackerras smp_ops->setup_cpu(cpu); 15925ad57078SPaul Mackerras if (smp_ops->take_timebase) 15935ad57078SPaul Mackerras smp_ops->take_timebase(); 15945ad57078SPaul Mackerras 1595d831d0b8STony Breeds secondary_cpu_time_init(); 1596d831d0b8STony Breeds 1597aeeafbfaSBenjamin Herrenschmidt #ifdef CONFIG_PPC64 1598aeeafbfaSBenjamin Herrenschmidt if (system_state == SYSTEM_RUNNING) 1599aeeafbfaSBenjamin Herrenschmidt vdso_data->processorCount++; 160018ad51ddSAnton Blanchard 160118ad51ddSAnton Blanchard vdso_getcpu_init(); 1602aeeafbfaSBenjamin Herrenschmidt #endif 16036980d13fSSrikar Dronamraju set_numa_node(numa_cpu_lookup_table[cpu]); 16046980d13fSSrikar Dronamraju set_numa_mem(local_memory_node(numa_cpu_lookup_table[cpu])); 16056980d13fSSrikar Dronamraju 1606df52f671SOliver O'Halloran /* Update topology CPU masks */ 1607df52f671SOliver O'Halloran add_cpu_to_masks(cpu); 16085ad57078SPaul Mackerras 160996d91431SOliver O'Halloran /* 161096d91431SOliver O'Halloran * Check for any shared caches. Note that this must be done on a 161196d91431SOliver O'Halloran * per-core basis because one core in the pair might be disabled. 161296d91431SOliver O'Halloran */ 1613caa8e29dSSrikar Dronamraju if (!shared_caches) { 1614caa8e29dSSrikar Dronamraju struct cpumask *(*sibling_mask)(int) = cpu_sibling_mask; 1615caa8e29dSSrikar Dronamraju struct cpumask *mask = cpu_l2_cache_mask(cpu); 1616caa8e29dSSrikar Dronamraju 1617caa8e29dSSrikar Dronamraju if (has_big_cores) 1618caa8e29dSSrikar Dronamraju sibling_mask = cpu_smallcore_mask; 1619caa8e29dSSrikar Dronamraju 1620caa8e29dSSrikar Dronamraju if (cpumask_weight(mask) > cpumask_weight(sibling_mask(cpu))) 162196d91431SOliver O'Halloran shared_caches = true; 1622caa8e29dSSrikar Dronamraju } 162396d91431SOliver O'Halloran 1624cce606feSLi Zhong smp_wmb(); 1625cce606feSLi Zhong notify_cpu_starting(cpu); 1626cce606feSLi Zhong set_cpu_online(cpu, true); 1627cce606feSLi Zhong 1628b6aeddeaSMichael Ellerman boot_init_stack_canary(); 1629b6aeddeaSMichael Ellerman 16305ad57078SPaul Mackerras local_irq_enable(); 16315ad57078SPaul Mackerras 1632d1039786SNaveen N. Rao /* We can enable ftrace for secondary cpus now */ 1633d1039786SNaveen N. Rao this_cpu_enable_ftrace(); 1634d1039786SNaveen N. Rao 1635fc6d73d6SThomas Gleixner cpu_startup_entry(CPUHP_AP_ONLINE_IDLE); 1636fa3f82c8SBenjamin Herrenschmidt 1637fa3f82c8SBenjamin Herrenschmidt BUG(); 16385ad57078SPaul Mackerras } 16395ad57078SPaul Mackerras 16405ad57078SPaul Mackerras int setup_profiling_timer(unsigned int multiplier) 16415ad57078SPaul Mackerras { 16425ad57078SPaul Mackerras return 0; 16435ad57078SPaul Mackerras } 16445ad57078SPaul Mackerras 16453c6032a8SSrikar Dronamraju static void fixup_topology(void) 16463c6032a8SSrikar Dronamraju { 1647375370a1SSrikar Dronamraju int i; 1648375370a1SSrikar Dronamraju 16493c6032a8SSrikar Dronamraju #ifdef CONFIG_SCHED_SMT 16503c6032a8SSrikar Dronamraju if (has_big_cores) { 16513c6032a8SSrikar Dronamraju pr_info("Big cores detected but using small core scheduling\n"); 165272730bfcSSrikar Dronamraju powerpc_topology[smt_idx].mask = smallcore_smt_mask; 16533c6032a8SSrikar Dronamraju } 16543c6032a8SSrikar Dronamraju #endif 165572730bfcSSrikar Dronamraju 165672730bfcSSrikar Dronamraju if (!has_coregroup_support()) 165772730bfcSSrikar Dronamraju powerpc_topology[mc_idx].mask = powerpc_topology[cache_idx].mask; 1658375370a1SSrikar Dronamraju 1659375370a1SSrikar Dronamraju /* 1660375370a1SSrikar Dronamraju * Try to consolidate topology levels here instead of 1661375370a1SSrikar Dronamraju * allowing scheduler to degenerate. 1662375370a1SSrikar Dronamraju * - Dont consolidate if masks are different. 1663375370a1SSrikar Dronamraju * - Dont consolidate if sd_flags exists and are different. 1664375370a1SSrikar Dronamraju */ 1665375370a1SSrikar Dronamraju for (i = 1; i <= die_idx; i++) { 1666375370a1SSrikar Dronamraju if (powerpc_topology[i].mask != powerpc_topology[i - 1].mask) 1667375370a1SSrikar Dronamraju continue; 1668375370a1SSrikar Dronamraju 1669375370a1SSrikar Dronamraju if (powerpc_topology[i].sd_flags && powerpc_topology[i - 1].sd_flags && 1670375370a1SSrikar Dronamraju powerpc_topology[i].sd_flags != powerpc_topology[i - 1].sd_flags) 1671375370a1SSrikar Dronamraju continue; 1672375370a1SSrikar Dronamraju 1673375370a1SSrikar Dronamraju if (!powerpc_topology[i - 1].sd_flags) 1674375370a1SSrikar Dronamraju powerpc_topology[i - 1].sd_flags = powerpc_topology[i].sd_flags; 1675375370a1SSrikar Dronamraju 1676375370a1SSrikar Dronamraju powerpc_topology[i].mask = powerpc_topology[i + 1].mask; 1677375370a1SSrikar Dronamraju powerpc_topology[i].sd_flags = powerpc_topology[i + 1].sd_flags; 1678375370a1SSrikar Dronamraju #ifdef CONFIG_SCHED_DEBUG 1679375370a1SSrikar Dronamraju powerpc_topology[i].name = powerpc_topology[i + 1].name; 1680375370a1SSrikar Dronamraju #endif 1681375370a1SSrikar Dronamraju } 16823c6032a8SSrikar Dronamraju } 16833c6032a8SSrikar Dronamraju 16845ad57078SPaul Mackerras void __init smp_cpus_done(unsigned int max_cpus) 16855ad57078SPaul Mackerras { 16866d11b87dSThomas Gleixner /* 16877b7622bbSMichael Ellerman * We are running pinned to the boot CPU, see rest_init(). 16885ad57078SPaul Mackerras */ 1689757cbd46SKumar Gala if (smp_ops && smp_ops->setup_cpu) 16907b7622bbSMichael Ellerman smp_ops->setup_cpu(boot_cpuid); 16914b703a23SAnton Blanchard 1692d7294445SBenjamin Herrenschmidt if (smp_ops && smp_ops->bringup_done) 1693d7294445SBenjamin Herrenschmidt smp_ops->bringup_done(); 1694d7294445SBenjamin Herrenschmidt 16954b703a23SAnton Blanchard dump_numa_cpu_topology(); 1696d7294445SBenjamin Herrenschmidt 16973c6032a8SSrikar Dronamraju fixup_topology(); 1698607b45e9SVincent Guittot set_sched_topology(powerpc_topology); 1699e1f0ece1SMichael Neuling } 1700e1f0ece1SMichael Neuling 17015ad57078SPaul Mackerras #ifdef CONFIG_HOTPLUG_CPU 17025ad57078SPaul Mackerras int __cpu_disable(void) 17035ad57078SPaul Mackerras { 1704e2075f79SNathan Lynch int cpu = smp_processor_id(); 1705e2075f79SNathan Lynch int err; 17065ad57078SPaul Mackerras 1707e2075f79SNathan Lynch if (!smp_ops->cpu_disable) 17085ad57078SPaul Mackerras return -ENOSYS; 1709e2075f79SNathan Lynch 1710424ef016SNaveen N. Rao this_cpu_disable_ftrace(); 1711424ef016SNaveen N. Rao 1712e2075f79SNathan Lynch err = smp_ops->cpu_disable(); 1713e2075f79SNathan Lynch if (err) 1714e2075f79SNathan Lynch return err; 1715e2075f79SNathan Lynch 1716e2075f79SNathan Lynch /* Update sibling maps */ 1717df52f671SOliver O'Halloran remove_cpu_from_masks(cpu); 1718440a0857SNathan Lynch 1719e2075f79SNathan Lynch return 0; 17205ad57078SPaul Mackerras } 17215ad57078SPaul Mackerras 17225ad57078SPaul Mackerras void __cpu_die(unsigned int cpu) 17235ad57078SPaul Mackerras { 17245ad57078SPaul Mackerras if (smp_ops->cpu_die) 17255ad57078SPaul Mackerras smp_ops->cpu_die(cpu); 17265ad57078SPaul Mackerras } 1727d0174c72SNathan Fontenot 17281ea21ba2SMichael Ellerman void arch_cpu_idle_dead(void) 17291ea21ba2SMichael Ellerman { 17301ea21ba2SMichael Ellerman sched_preempt_enable_no_resched(); 17311ea21ba2SMichael Ellerman 1732424ef016SNaveen N. Rao /* 1733424ef016SNaveen N. Rao * Disable on the down path. This will be re-enabled by 1734424ef016SNaveen N. Rao * start_secondary() via start_secondary_resume() below 1735424ef016SNaveen N. Rao */ 1736424ef016SNaveen N. Rao this_cpu_disable_ftrace(); 1737424ef016SNaveen N. Rao 173839f87561SMichael Ellerman if (smp_ops->cpu_offline_self) 173939f87561SMichael Ellerman smp_ops->cpu_offline_self(); 1740fa3f82c8SBenjamin Herrenschmidt 1741fa3f82c8SBenjamin Herrenschmidt /* If we return, we re-enter start_secondary */ 1742fa3f82c8SBenjamin Herrenschmidt start_secondary_resume(); 1743abb17f9cSMilton Miller } 1744fa3f82c8SBenjamin Herrenschmidt 17455ad57078SPaul Mackerras #endif 1746