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> 6406e629c2SHari Bathini #include <asm/fadump.h> 655ad57078SPaul Mackerras 665ad57078SPaul Mackerras #ifdef DEBUG 67f9e4ec57SMichael Ellerman #include <asm/udbg.h> 685ad57078SPaul Mackerras #define DBG(fmt...) udbg_printf(fmt) 695ad57078SPaul Mackerras #else 705ad57078SPaul Mackerras #define DBG(fmt...) 715ad57078SPaul Mackerras #endif 725ad57078SPaul Mackerras 73c56e5853SBenjamin Herrenschmidt #ifdef CONFIG_HOTPLUG_CPU 74fb82b839SBenjamin Herrenschmidt /* State of each CPU during hotplug phases */ 75fb82b839SBenjamin Herrenschmidt static DEFINE_PER_CPU(int, cpu_state) = { 0 }; 76c56e5853SBenjamin Herrenschmidt #endif 77c56e5853SBenjamin Herrenschmidt 787c19c2e5SChristophe Leroy struct task_struct *secondary_current; 79425752c6SGautham R. Shenoy bool has_big_cores; 80f9f130ffSSrikar Dronamraju bool coregroup_enabled; 819538abeeSGautham R. Shenoy bool thread_group_shares_l2; 82e9ef81e1SParth Shah bool thread_group_shares_l3; 83f9e4ec57SMichael Ellerman 84cc1ba8eaSAnton Blanchard DEFINE_PER_CPU(cpumask_var_t, cpu_sibling_map); 85425752c6SGautham R. Shenoy DEFINE_PER_CPU(cpumask_var_t, cpu_smallcore_map); 862a636a56SOliver O'Halloran DEFINE_PER_CPU(cpumask_var_t, cpu_l2_cache_map); 87cc1ba8eaSAnton Blanchard DEFINE_PER_CPU(cpumask_var_t, cpu_core_map); 88078277acSYu Kuai static DEFINE_PER_CPU(cpumask_var_t, cpu_coregroup_map); 895ad57078SPaul Mackerras 90d5a7430dSMike Travis EXPORT_PER_CPU_SYMBOL(cpu_sibling_map); 912a636a56SOliver O'Halloran EXPORT_PER_CPU_SYMBOL(cpu_l2_cache_map); 92440a0857SNathan Lynch EXPORT_PER_CPU_SYMBOL(cpu_core_map); 93425752c6SGautham R. Shenoy EXPORT_SYMBOL_GPL(has_big_cores); 94425752c6SGautham R. Shenoy 9572730bfcSSrikar Dronamraju enum { 9672730bfcSSrikar Dronamraju #ifdef CONFIG_SCHED_SMT 9772730bfcSSrikar Dronamraju smt_idx, 9872730bfcSSrikar Dronamraju #endif 9972730bfcSSrikar Dronamraju cache_idx, 10072730bfcSSrikar Dronamraju mc_idx, 10172730bfcSSrikar Dronamraju die_idx, 10272730bfcSSrikar Dronamraju }; 10372730bfcSSrikar Dronamraju 104425752c6SGautham R. Shenoy #define MAX_THREAD_LIST_SIZE 8 105425752c6SGautham R. Shenoy #define THREAD_GROUP_SHARE_L1 1 106e9ef81e1SParth Shah #define THREAD_GROUP_SHARE_L2_L3 2 107425752c6SGautham R. Shenoy struct thread_groups { 108425752c6SGautham R. Shenoy unsigned int property; 109425752c6SGautham R. Shenoy unsigned int nr_groups; 110425752c6SGautham R. Shenoy unsigned int threads_per_group; 111425752c6SGautham R. Shenoy unsigned int thread_list[MAX_THREAD_LIST_SIZE]; 112425752c6SGautham R. Shenoy }; 113425752c6SGautham R. Shenoy 114790a1662SGautham R. Shenoy /* Maximum number of properties that groups of threads within a core can share */ 1159538abeeSGautham R. Shenoy #define MAX_THREAD_GROUP_PROPERTIES 2 116790a1662SGautham R. Shenoy 117790a1662SGautham R. Shenoy struct thread_groups_list { 118790a1662SGautham R. Shenoy unsigned int nr_properties; 119790a1662SGautham R. Shenoy struct thread_groups property_tgs[MAX_THREAD_GROUP_PROPERTIES]; 120790a1662SGautham R. Shenoy }; 121790a1662SGautham R. Shenoy 122790a1662SGautham R. Shenoy static struct thread_groups_list tgl[NR_CPUS] __initdata; 123425752c6SGautham R. Shenoy /* 1241fdc1d66SGautham R. Shenoy * On big-cores system, thread_group_l1_cache_map for each CPU corresponds to 125425752c6SGautham R. Shenoy * the set its siblings that share the L1-cache. 126425752c6SGautham R. Shenoy */ 127a4bec516SGautham R. Shenoy DEFINE_PER_CPU(cpumask_var_t, thread_group_l1_cache_map); 1285ad57078SPaul Mackerras 1299538abeeSGautham R. Shenoy /* 1309538abeeSGautham R. Shenoy * On some big-cores system, thread_group_l2_cache_map for each CPU 1319538abeeSGautham R. Shenoy * corresponds to the set its siblings within the core that share the 1329538abeeSGautham R. Shenoy * L2-cache. 1339538abeeSGautham R. Shenoy */ 134a4bec516SGautham R. Shenoy DEFINE_PER_CPU(cpumask_var_t, thread_group_l2_cache_map); 1359538abeeSGautham R. Shenoy 136e9ef81e1SParth Shah /* 137e9ef81e1SParth Shah * On P10, thread_group_l3_cache_map for each CPU is equal to the 138e9ef81e1SParth Shah * thread_group_l2_cache_map 139e9ef81e1SParth Shah */ 140e9ef81e1SParth Shah DEFINE_PER_CPU(cpumask_var_t, thread_group_l3_cache_map); 141e9ef81e1SParth Shah 1425ad57078SPaul Mackerras /* SMP operations for this machine */ 1435ad57078SPaul Mackerras struct smp_ops_t *smp_ops; 1445ad57078SPaul Mackerras 1457ccbe504SBenjamin Herrenschmidt /* Can't be static due to PowerMac hackery */ 1467ccbe504SBenjamin Herrenschmidt volatile unsigned int cpu_callin_map[NR_CPUS]; 1475ad57078SPaul Mackerras 1485ad57078SPaul Mackerras int smt_enabled_at_boot = 1; 1495ad57078SPaul Mackerras 1503cd85250SAndy Fleming /* 1513cd85250SAndy Fleming * Returns 1 if the specified cpu should be brought up during boot. 1523cd85250SAndy Fleming * Used to inhibit booting threads if they've been disabled or 1533cd85250SAndy Fleming * limited on the command line 1543cd85250SAndy Fleming */ 1553cd85250SAndy Fleming int smp_generic_cpu_bootable(unsigned int nr) 1563cd85250SAndy Fleming { 1573cd85250SAndy Fleming /* Special case - we inhibit secondary thread startup 1583cd85250SAndy Fleming * during boot if the user requests it. 1593cd85250SAndy Fleming */ 160a8fcfc19SThomas Gleixner if (system_state < SYSTEM_RUNNING && cpu_has_feature(CPU_FTR_SMT)) { 1613cd85250SAndy Fleming if (!smt_enabled_at_boot && cpu_thread_in_core(nr) != 0) 1623cd85250SAndy Fleming return 0; 1633cd85250SAndy Fleming if (smt_enabled_at_boot 1643cd85250SAndy Fleming && cpu_thread_in_core(nr) >= smt_enabled_at_boot) 1653cd85250SAndy Fleming return 0; 1663cd85250SAndy Fleming } 1673cd85250SAndy Fleming 1683cd85250SAndy Fleming return 1; 1693cd85250SAndy Fleming } 1703cd85250SAndy Fleming 1713cd85250SAndy Fleming 1725ad57078SPaul Mackerras #ifdef CONFIG_PPC64 173cad5cef6SGreg Kroah-Hartman int smp_generic_kick_cpu(int nr) 1745ad57078SPaul Mackerras { 175c642af9cSSantosh Sivaraj if (nr < 0 || nr >= nr_cpu_ids) 176f8d0d5dcSSantosh Sivaraj return -EINVAL; 1775ad57078SPaul Mackerras 1785ad57078SPaul Mackerras /* 1795ad57078SPaul Mackerras * The processor is currently spinning, waiting for the 1805ad57078SPaul Mackerras * cpu_start field to become non-zero After we set cpu_start, 1815ad57078SPaul Mackerras * the processor will continue on to secondary_start 1825ad57078SPaul Mackerras */ 183d2e60075SNicholas Piggin if (!paca_ptrs[nr]->cpu_start) { 184d2e60075SNicholas Piggin paca_ptrs[nr]->cpu_start = 1; 1855ad57078SPaul Mackerras smp_mb(); 186fb82b839SBenjamin Herrenschmidt return 0; 187fb82b839SBenjamin Herrenschmidt } 188fb82b839SBenjamin Herrenschmidt 189fb82b839SBenjamin Herrenschmidt #ifdef CONFIG_HOTPLUG_CPU 190fb82b839SBenjamin Herrenschmidt /* 191fb82b839SBenjamin Herrenschmidt * Ok it's not there, so it might be soft-unplugged, let's 192fb82b839SBenjamin Herrenschmidt * try to bring it back 193fb82b839SBenjamin Herrenschmidt */ 194ae5cab47SZhao Chenhui generic_set_cpu_up(nr); 195fb82b839SBenjamin Herrenschmidt smp_wmb(); 196fb82b839SBenjamin Herrenschmidt smp_send_reschedule(nr); 197fb82b839SBenjamin Herrenschmidt #endif /* CONFIG_HOTPLUG_CPU */ 198de300974SMichael Ellerman 199de300974SMichael Ellerman return 0; 2005ad57078SPaul Mackerras } 201fb82b839SBenjamin Herrenschmidt #endif /* CONFIG_PPC64 */ 2025ad57078SPaul Mackerras 20325ddd738SMilton Miller static irqreturn_t call_function_action(int irq, void *data) 20425ddd738SMilton Miller { 20525ddd738SMilton Miller generic_smp_call_function_interrupt(); 20625ddd738SMilton Miller return IRQ_HANDLED; 20725ddd738SMilton Miller } 20825ddd738SMilton Miller 20925ddd738SMilton Miller static irqreturn_t reschedule_action(int irq, void *data) 21025ddd738SMilton Miller { 211184748ccSPeter Zijlstra scheduler_ipi(); 21225ddd738SMilton Miller return IRQ_HANDLED; 21325ddd738SMilton Miller } 21425ddd738SMilton Miller 215bc907113SNicholas Piggin #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST 2161b67bee1SSrivatsa S. Bhat static irqreturn_t tick_broadcast_ipi_action(int irq, void *data) 21725ddd738SMilton Miller { 2183f984620SNicholas Piggin timer_broadcast_interrupt(); 21925ddd738SMilton Miller return IRQ_HANDLED; 22025ddd738SMilton Miller } 221bc907113SNicholas Piggin #endif 22225ddd738SMilton Miller 223ddd703caSNicholas Piggin #ifdef CONFIG_NMI_IPI 224ddd703caSNicholas Piggin static irqreturn_t nmi_ipi_action(int irq, void *data) 22525ddd738SMilton Miller { 226ddd703caSNicholas Piggin smp_handle_nmi_ipi(get_irq_regs()); 22723d72bfdSMilton Miller return IRQ_HANDLED; 22823d72bfdSMilton Miller } 229ddd703caSNicholas Piggin #endif 23025ddd738SMilton Miller 23125ddd738SMilton Miller static irq_handler_t smp_ipi_action[] = { 23225ddd738SMilton Miller [PPC_MSG_CALL_FUNCTION] = call_function_action, 23325ddd738SMilton Miller [PPC_MSG_RESCHEDULE] = reschedule_action, 234bc907113SNicholas Piggin #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST 2351b67bee1SSrivatsa S. Bhat [PPC_MSG_TICK_BROADCAST] = tick_broadcast_ipi_action, 236bc907113SNicholas Piggin #endif 237ddd703caSNicholas Piggin #ifdef CONFIG_NMI_IPI 238ddd703caSNicholas Piggin [PPC_MSG_NMI_IPI] = nmi_ipi_action, 239ddd703caSNicholas Piggin #endif 24025ddd738SMilton Miller }; 24125ddd738SMilton Miller 242ddd703caSNicholas Piggin /* 243ddd703caSNicholas Piggin * The NMI IPI is a fallback and not truly non-maskable. It is simpler 244ddd703caSNicholas Piggin * than going through the call function infrastructure, and strongly 245ddd703caSNicholas Piggin * serialized, so it is more appropriate for debugging. 246ddd703caSNicholas Piggin */ 24725ddd738SMilton Miller const char *smp_ipi_name[] = { 24825ddd738SMilton Miller [PPC_MSG_CALL_FUNCTION] = "ipi call function", 24925ddd738SMilton Miller [PPC_MSG_RESCHEDULE] = "ipi reschedule", 250bc907113SNicholas Piggin #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST 2511b67bee1SSrivatsa S. Bhat [PPC_MSG_TICK_BROADCAST] = "ipi tick-broadcast", 252bc907113SNicholas Piggin #endif 25321bfd6a8SNicholas Piggin #ifdef CONFIG_NMI_IPI 254ddd703caSNicholas Piggin [PPC_MSG_NMI_IPI] = "nmi ipi", 25521bfd6a8SNicholas Piggin #endif 25625ddd738SMilton Miller }; 25725ddd738SMilton Miller 25825ddd738SMilton Miller /* optional function to request ipi, for controllers with >= 4 ipis */ 25925ddd738SMilton Miller int smp_request_message_ipi(int virq, int msg) 26025ddd738SMilton Miller { 26125ddd738SMilton Miller int err; 26225ddd738SMilton Miller 263ddd703caSNicholas Piggin if (msg < 0 || msg > PPC_MSG_NMI_IPI) 26425ddd738SMilton Miller return -EINVAL; 265ddd703caSNicholas Piggin #ifndef CONFIG_NMI_IPI 266ddd703caSNicholas Piggin if (msg == PPC_MSG_NMI_IPI) 26725ddd738SMilton Miller return 1; 26825ddd738SMilton Miller #endif 269ddd703caSNicholas Piggin 2703b5e16d7SThomas Gleixner err = request_irq(virq, smp_ipi_action[msg], 271e6651de9SZhao Chenhui IRQF_PERCPU | IRQF_NO_THREAD | IRQF_NO_SUSPEND, 272b0d436c7SAnton Blanchard smp_ipi_name[msg], NULL); 27325ddd738SMilton Miller WARN(err < 0, "unable to request_irq %d for %s (rc %d)\n", 27425ddd738SMilton Miller virq, smp_ipi_name[msg], err); 27525ddd738SMilton Miller 27625ddd738SMilton Miller return err; 27725ddd738SMilton Miller } 27825ddd738SMilton Miller 2791ece355bSMilton Miller #ifdef CONFIG_PPC_SMP_MUXED_IPI 28023d72bfdSMilton Miller struct cpu_messages { 281bd7f561fSSuresh Warrier long messages; /* current messages */ 28223d72bfdSMilton Miller }; 28323d72bfdSMilton Miller static DEFINE_PER_CPU_SHARED_ALIGNED(struct cpu_messages, ipi_message); 28423d72bfdSMilton Miller 28531639c77SSuresh Warrier void smp_muxed_ipi_set_message(int cpu, int msg) 28623d72bfdSMilton Miller { 28723d72bfdSMilton Miller struct cpu_messages *info = &per_cpu(ipi_message, cpu); 28871454272SMilton Miller char *message = (char *)&info->messages; 28923d72bfdSMilton Miller 2909fb1b36cSPaul Mackerras /* 2919fb1b36cSPaul Mackerras * Order previous accesses before accesses in the IPI handler. 2929fb1b36cSPaul Mackerras */ 2939fb1b36cSPaul Mackerras smp_mb(); 29471454272SMilton Miller message[msg] = 1; 29531639c77SSuresh Warrier } 29631639c77SSuresh Warrier 29731639c77SSuresh Warrier void smp_muxed_ipi_message_pass(int cpu, int msg) 29831639c77SSuresh Warrier { 29931639c77SSuresh Warrier smp_muxed_ipi_set_message(cpu, msg); 300b866cc21SNicholas Piggin 3019fb1b36cSPaul Mackerras /* 3029fb1b36cSPaul Mackerras * cause_ipi functions are required to include a full barrier 3039fb1b36cSPaul Mackerras * before doing whatever causes the IPI. 3049fb1b36cSPaul Mackerras */ 305b866cc21SNicholas Piggin smp_ops->cause_ipi(cpu); 30623d72bfdSMilton Miller } 30723d72bfdSMilton Miller 3080654de1cSAnton Blanchard #ifdef __BIG_ENDIAN__ 309bd7f561fSSuresh Warrier #define IPI_MESSAGE(A) (1uL << ((BITS_PER_LONG - 8) - 8 * (A))) 3100654de1cSAnton Blanchard #else 311bd7f561fSSuresh Warrier #define IPI_MESSAGE(A) (1uL << (8 * (A))) 3120654de1cSAnton Blanchard #endif 3130654de1cSAnton Blanchard 31423d72bfdSMilton Miller irqreturn_t smp_ipi_demux(void) 31523d72bfdSMilton Miller { 31623d72bfdSMilton Miller mb(); /* order any irq clear */ 31771454272SMilton Miller 318b87ac021SNicholas Piggin return smp_ipi_demux_relaxed(); 319b87ac021SNicholas Piggin } 320b87ac021SNicholas Piggin 321b87ac021SNicholas Piggin /* sync-free variant. Callers should ensure synchronization */ 322b87ac021SNicholas Piggin irqreturn_t smp_ipi_demux_relaxed(void) 323b87ac021SNicholas Piggin { 324b866cc21SNicholas Piggin struct cpu_messages *info; 32523d72bfdSMilton Miller unsigned long all; 32623d72bfdSMilton Miller 327b866cc21SNicholas Piggin info = this_cpu_ptr(&ipi_message); 32871454272SMilton Miller do { 3299fb1b36cSPaul Mackerras all = xchg(&info->messages, 0); 330e17769ebSSuresh E. Warrier #if defined(CONFIG_KVM_XICS) && defined(CONFIG_KVM_BOOK3S_HV_POSSIBLE) 331e17769ebSSuresh E. Warrier /* 332e17769ebSSuresh E. Warrier * Must check for PPC_MSG_RM_HOST_ACTION messages 333e17769ebSSuresh E. Warrier * before PPC_MSG_CALL_FUNCTION messages because when 334e17769ebSSuresh E. Warrier * a VM is destroyed, we call kick_all_cpus_sync() 335e17769ebSSuresh E. Warrier * to ensure that any pending PPC_MSG_RM_HOST_ACTION 336e17769ebSSuresh E. Warrier * messages have completed before we free any VCPUs. 337e17769ebSSuresh E. Warrier */ 338e17769ebSSuresh E. Warrier if (all & IPI_MESSAGE(PPC_MSG_RM_HOST_ACTION)) 339e17769ebSSuresh E. Warrier kvmppc_xics_ipi_action(); 340e17769ebSSuresh E. Warrier #endif 3410654de1cSAnton Blanchard if (all & IPI_MESSAGE(PPC_MSG_CALL_FUNCTION)) 34223d72bfdSMilton Miller generic_smp_call_function_interrupt(); 3430654de1cSAnton Blanchard if (all & IPI_MESSAGE(PPC_MSG_RESCHEDULE)) 344880102e7SBenjamin Herrenschmidt scheduler_ipi(); 345bc907113SNicholas Piggin #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST 3461b67bee1SSrivatsa S. Bhat if (all & IPI_MESSAGE(PPC_MSG_TICK_BROADCAST)) 3473f984620SNicholas Piggin timer_broadcast_interrupt(); 348bc907113SNicholas Piggin #endif 349ddd703caSNicholas Piggin #ifdef CONFIG_NMI_IPI 350ddd703caSNicholas Piggin if (all & IPI_MESSAGE(PPC_MSG_NMI_IPI)) 351ddd703caSNicholas Piggin nmi_ipi_action(0, NULL); 352ddd703caSNicholas Piggin #endif 35371454272SMilton Miller } while (info->messages); 35471454272SMilton Miller 35523d72bfdSMilton Miller return IRQ_HANDLED; 35623d72bfdSMilton Miller } 3571ece355bSMilton Miller #endif /* CONFIG_PPC_SMP_MUXED_IPI */ 35823d72bfdSMilton Miller 3599ca980dcSPaul Mackerras static inline void do_message_pass(int cpu, int msg) 3609ca980dcSPaul Mackerras { 3619ca980dcSPaul Mackerras if (smp_ops->message_pass) 3629ca980dcSPaul Mackerras smp_ops->message_pass(cpu, msg); 3639ca980dcSPaul Mackerras #ifdef CONFIG_PPC_SMP_MUXED_IPI 3649ca980dcSPaul Mackerras else 3659ca980dcSPaul Mackerras smp_muxed_ipi_message_pass(cpu, msg); 3669ca980dcSPaul Mackerras #endif 3679ca980dcSPaul Mackerras } 3689ca980dcSPaul Mackerras 3695ad57078SPaul Mackerras void smp_send_reschedule(int cpu) 3705ad57078SPaul Mackerras { 3718cffc6acSBenjamin Herrenschmidt if (likely(smp_ops)) 3729ca980dcSPaul Mackerras do_message_pass(cpu, PPC_MSG_RESCHEDULE); 3735ad57078SPaul Mackerras } 374de56a948SPaul Mackerras EXPORT_SYMBOL_GPL(smp_send_reschedule); 3755ad57078SPaul Mackerras 376b7d7a240SJens Axboe void arch_send_call_function_single_ipi(int cpu) 377b7d7a240SJens Axboe { 378402d9a1eSSrivatsa S. Bhat do_message_pass(cpu, PPC_MSG_CALL_FUNCTION); 379b7d7a240SJens Axboe } 380b7d7a240SJens Axboe 381f063ea02SRusty Russell void arch_send_call_function_ipi_mask(const struct cpumask *mask) 382b7d7a240SJens Axboe { 383b7d7a240SJens Axboe unsigned int cpu; 384b7d7a240SJens Axboe 385f063ea02SRusty Russell for_each_cpu(cpu, mask) 3869ca980dcSPaul Mackerras do_message_pass(cpu, PPC_MSG_CALL_FUNCTION); 387b7d7a240SJens Axboe } 388b7d7a240SJens Axboe 389ddd703caSNicholas Piggin #ifdef CONFIG_NMI_IPI 390ddd703caSNicholas Piggin 391ddd703caSNicholas Piggin /* 392ddd703caSNicholas Piggin * "NMI IPI" system. 393ddd703caSNicholas Piggin * 394ddd703caSNicholas Piggin * NMI IPIs may not be recoverable, so should not be used as ongoing part of 395ddd703caSNicholas Piggin * a running system. They can be used for crash, debug, halt/reboot, etc. 396ddd703caSNicholas Piggin * 397ddd703caSNicholas Piggin * The IPI call waits with interrupts disabled until all targets enter the 39888b9a3d1SNicholas Piggin * NMI handler, then returns. Subsequent IPIs can be issued before targets 39988b9a3d1SNicholas Piggin * have returned from their handlers, so there is no guarantee about 40088b9a3d1SNicholas Piggin * concurrency or re-entrancy. 401ddd703caSNicholas Piggin * 40288b9a3d1SNicholas Piggin * A new NMI can be issued before all targets exit the handler. 403ddd703caSNicholas Piggin * 404ddd703caSNicholas Piggin * The IPI call may time out without all targets entering the NMI handler. 405ddd703caSNicholas Piggin * In that case, there is some logic to recover (and ignore subsequent 406ddd703caSNicholas Piggin * NMI interrupts that may eventually be raised), but the platform interrupt 407ddd703caSNicholas Piggin * handler may not be able to distinguish this from other exception causes, 408ddd703caSNicholas Piggin * which may cause a crash. 409ddd703caSNicholas Piggin */ 410ddd703caSNicholas Piggin 411ddd703caSNicholas Piggin static atomic_t __nmi_ipi_lock = ATOMIC_INIT(0); 412ddd703caSNicholas Piggin static struct cpumask nmi_ipi_pending_mask; 41388b9a3d1SNicholas Piggin static bool nmi_ipi_busy = false; 414ddd703caSNicholas Piggin static void (*nmi_ipi_function)(struct pt_regs *) = NULL; 415ddd703caSNicholas Piggin 416ddd703caSNicholas Piggin static void nmi_ipi_lock_start(unsigned long *flags) 417ddd703caSNicholas Piggin { 418ddd703caSNicholas Piggin raw_local_irq_save(*flags); 419ddd703caSNicholas Piggin hard_irq_disable(); 420ddd703caSNicholas Piggin while (atomic_cmpxchg(&__nmi_ipi_lock, 0, 1) == 1) { 421ddd703caSNicholas Piggin raw_local_irq_restore(*flags); 4220459ddfdSNicholas Piggin spin_until_cond(atomic_read(&__nmi_ipi_lock) == 0); 423ddd703caSNicholas Piggin raw_local_irq_save(*flags); 424ddd703caSNicholas Piggin hard_irq_disable(); 425ddd703caSNicholas Piggin } 426ddd703caSNicholas Piggin } 427ddd703caSNicholas Piggin 428ddd703caSNicholas Piggin static void nmi_ipi_lock(void) 429ddd703caSNicholas Piggin { 430ddd703caSNicholas Piggin while (atomic_cmpxchg(&__nmi_ipi_lock, 0, 1) == 1) 4310459ddfdSNicholas Piggin spin_until_cond(atomic_read(&__nmi_ipi_lock) == 0); 432ddd703caSNicholas Piggin } 433ddd703caSNicholas Piggin 434ddd703caSNicholas Piggin static void nmi_ipi_unlock(void) 435ddd703caSNicholas Piggin { 436ddd703caSNicholas Piggin smp_mb(); 437ddd703caSNicholas Piggin WARN_ON(atomic_read(&__nmi_ipi_lock) != 1); 438ddd703caSNicholas Piggin atomic_set(&__nmi_ipi_lock, 0); 439ddd703caSNicholas Piggin } 440ddd703caSNicholas Piggin 441ddd703caSNicholas Piggin static void nmi_ipi_unlock_end(unsigned long *flags) 442ddd703caSNicholas Piggin { 443ddd703caSNicholas Piggin nmi_ipi_unlock(); 444ddd703caSNicholas Piggin raw_local_irq_restore(*flags); 445ddd703caSNicholas Piggin } 446ddd703caSNicholas Piggin 447ddd703caSNicholas Piggin /* 448ddd703caSNicholas Piggin * Platform NMI handler calls this to ack 449ddd703caSNicholas Piggin */ 450ddd703caSNicholas Piggin int smp_handle_nmi_ipi(struct pt_regs *regs) 451ddd703caSNicholas Piggin { 45288b9a3d1SNicholas Piggin void (*fn)(struct pt_regs *) = NULL; 453ddd703caSNicholas Piggin unsigned long flags; 454ddd703caSNicholas Piggin int me = raw_smp_processor_id(); 455ddd703caSNicholas Piggin int ret = 0; 456ddd703caSNicholas Piggin 457ddd703caSNicholas Piggin /* 458ddd703caSNicholas Piggin * Unexpected NMIs are possible here because the interrupt may not 459ddd703caSNicholas Piggin * be able to distinguish NMI IPIs from other types of NMIs, or 460ddd703caSNicholas Piggin * because the caller may have timed out. 461ddd703caSNicholas Piggin */ 462ddd703caSNicholas Piggin nmi_ipi_lock_start(&flags); 46388b9a3d1SNicholas Piggin if (cpumask_test_cpu(me, &nmi_ipi_pending_mask)) { 464ddd703caSNicholas Piggin cpumask_clear_cpu(me, &nmi_ipi_pending_mask); 46588b9a3d1SNicholas Piggin fn = READ_ONCE(nmi_ipi_function); 46688b9a3d1SNicholas Piggin WARN_ON_ONCE(!fn); 467ddd703caSNicholas Piggin ret = 1; 46888b9a3d1SNicholas Piggin } 469ddd703caSNicholas Piggin nmi_ipi_unlock_end(&flags); 470ddd703caSNicholas Piggin 47188b9a3d1SNicholas Piggin if (fn) 47288b9a3d1SNicholas Piggin fn(regs); 47388b9a3d1SNicholas Piggin 474ddd703caSNicholas Piggin return ret; 475ddd703caSNicholas Piggin } 476ddd703caSNicholas Piggin 4776ba55716SMichael Ellerman static void do_smp_send_nmi_ipi(int cpu, bool safe) 478ddd703caSNicholas Piggin { 4796ba55716SMichael Ellerman if (!safe && smp_ops->cause_nmi_ipi && smp_ops->cause_nmi_ipi(cpu)) 480c64af645SNicholas Piggin return; 481c64af645SNicholas Piggin 482ddd703caSNicholas Piggin if (cpu >= 0) { 483ddd703caSNicholas Piggin do_message_pass(cpu, PPC_MSG_NMI_IPI); 484ddd703caSNicholas Piggin } else { 485ddd703caSNicholas Piggin int c; 486ddd703caSNicholas Piggin 487ddd703caSNicholas Piggin for_each_online_cpu(c) { 488ddd703caSNicholas Piggin if (c == raw_smp_processor_id()) 489ddd703caSNicholas Piggin continue; 490ddd703caSNicholas Piggin do_message_pass(c, PPC_MSG_NMI_IPI); 491ddd703caSNicholas Piggin } 492ddd703caSNicholas Piggin } 493ddd703caSNicholas Piggin } 494ddd703caSNicholas Piggin 495ddd703caSNicholas Piggin /* 496ddd703caSNicholas Piggin * - cpu is the target CPU (must not be this CPU), or NMI_IPI_ALL_OTHERS. 497ddd703caSNicholas Piggin * - fn is the target callback function. 498ddd703caSNicholas Piggin * - delay_us > 0 is the delay before giving up waiting for targets to 49988b9a3d1SNicholas Piggin * begin executing the handler, == 0 specifies indefinite delay. 500ddd703caSNicholas Piggin */ 5016fe243feSNicholas Piggin static int __smp_send_nmi_ipi(int cpu, void (*fn)(struct pt_regs *), 5026fe243feSNicholas Piggin u64 delay_us, bool safe) 503ddd703caSNicholas Piggin { 504ddd703caSNicholas Piggin unsigned long flags; 505ddd703caSNicholas Piggin int me = raw_smp_processor_id(); 506ddd703caSNicholas Piggin int ret = 1; 507ddd703caSNicholas Piggin 508ddd703caSNicholas Piggin BUG_ON(cpu == me); 509ddd703caSNicholas Piggin BUG_ON(cpu < 0 && cpu != NMI_IPI_ALL_OTHERS); 510ddd703caSNicholas Piggin 511ddd703caSNicholas Piggin if (unlikely(!smp_ops)) 512ddd703caSNicholas Piggin return 0; 513ddd703caSNicholas Piggin 514ddd703caSNicholas Piggin nmi_ipi_lock_start(&flags); 51588b9a3d1SNicholas Piggin while (nmi_ipi_busy) { 516ddd703caSNicholas Piggin nmi_ipi_unlock_end(&flags); 51788b9a3d1SNicholas Piggin spin_until_cond(!nmi_ipi_busy); 518ddd703caSNicholas Piggin nmi_ipi_lock_start(&flags); 519ddd703caSNicholas Piggin } 52088b9a3d1SNicholas Piggin nmi_ipi_busy = true; 521ddd703caSNicholas Piggin nmi_ipi_function = fn; 522ddd703caSNicholas Piggin 52388b9a3d1SNicholas Piggin WARN_ON_ONCE(!cpumask_empty(&nmi_ipi_pending_mask)); 52488b9a3d1SNicholas Piggin 525ddd703caSNicholas Piggin if (cpu < 0) { 526ddd703caSNicholas Piggin /* ALL_OTHERS */ 527ddd703caSNicholas Piggin cpumask_copy(&nmi_ipi_pending_mask, cpu_online_mask); 528ddd703caSNicholas Piggin cpumask_clear_cpu(me, &nmi_ipi_pending_mask); 529ddd703caSNicholas Piggin } else { 530ddd703caSNicholas Piggin cpumask_set_cpu(cpu, &nmi_ipi_pending_mask); 531ddd703caSNicholas Piggin } 53288b9a3d1SNicholas Piggin 533ddd703caSNicholas Piggin nmi_ipi_unlock(); 534ddd703caSNicholas Piggin 53588b9a3d1SNicholas Piggin /* Interrupts remain hard disabled */ 53688b9a3d1SNicholas Piggin 5376ba55716SMichael Ellerman do_smp_send_nmi_ipi(cpu, safe); 538ddd703caSNicholas Piggin 5395b73151fSNicholas Piggin nmi_ipi_lock(); 54088b9a3d1SNicholas Piggin /* nmi_ipi_busy is set here, so unlock/lock is okay */ 541ddd703caSNicholas Piggin while (!cpumask_empty(&nmi_ipi_pending_mask)) { 5425b73151fSNicholas Piggin nmi_ipi_unlock(); 543ddd703caSNicholas Piggin udelay(1); 5445b73151fSNicholas Piggin nmi_ipi_lock(); 545ddd703caSNicholas Piggin if (delay_us) { 546ddd703caSNicholas Piggin delay_us--; 547ddd703caSNicholas Piggin if (!delay_us) 54888b9a3d1SNicholas Piggin break; 549ddd703caSNicholas Piggin } 550ddd703caSNicholas Piggin } 551ddd703caSNicholas Piggin 552ddd703caSNicholas Piggin if (!cpumask_empty(&nmi_ipi_pending_mask)) { 5535b73151fSNicholas Piggin /* Timeout waiting for CPUs to call smp_handle_nmi_ipi */ 554ddd703caSNicholas Piggin ret = 0; 555ddd703caSNicholas Piggin cpumask_clear(&nmi_ipi_pending_mask); 556ddd703caSNicholas Piggin } 5575b73151fSNicholas Piggin 55888b9a3d1SNicholas Piggin nmi_ipi_function = NULL; 55988b9a3d1SNicholas Piggin nmi_ipi_busy = false; 56088b9a3d1SNicholas Piggin 561ddd703caSNicholas Piggin nmi_ipi_unlock_end(&flags); 562ddd703caSNicholas Piggin 563ddd703caSNicholas Piggin return ret; 564ddd703caSNicholas Piggin } 5656ba55716SMichael Ellerman 5666ba55716SMichael Ellerman int smp_send_nmi_ipi(int cpu, void (*fn)(struct pt_regs *), u64 delay_us) 5676ba55716SMichael Ellerman { 5686ba55716SMichael Ellerman return __smp_send_nmi_ipi(cpu, fn, delay_us, false); 5696ba55716SMichael Ellerman } 5706ba55716SMichael Ellerman 5716ba55716SMichael Ellerman int smp_send_safe_nmi_ipi(int cpu, void (*fn)(struct pt_regs *), u64 delay_us) 5726ba55716SMichael Ellerman { 5736ba55716SMichael Ellerman return __smp_send_nmi_ipi(cpu, fn, delay_us, true); 5746ba55716SMichael Ellerman } 575ddd703caSNicholas Piggin #endif /* CONFIG_NMI_IPI */ 576ddd703caSNicholas Piggin 5771b67bee1SSrivatsa S. Bhat #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST 5781b67bee1SSrivatsa S. Bhat void tick_broadcast(const struct cpumask *mask) 5791b67bee1SSrivatsa S. Bhat { 5801b67bee1SSrivatsa S. Bhat unsigned int cpu; 5811b67bee1SSrivatsa S. Bhat 5821b67bee1SSrivatsa S. Bhat for_each_cpu(cpu, mask) 5831b67bee1SSrivatsa S. Bhat do_message_pass(cpu, PPC_MSG_TICK_BROADCAST); 5841b67bee1SSrivatsa S. Bhat } 5851b67bee1SSrivatsa S. Bhat #endif 5861b67bee1SSrivatsa S. Bhat 587ddd703caSNicholas Piggin #ifdef CONFIG_DEBUGGER 588157c9f40SCédric Le Goater static void debugger_ipi_callback(struct pt_regs *regs) 589ddd703caSNicholas Piggin { 590ddd703caSNicholas Piggin debugger_ipi(regs); 591ddd703caSNicholas Piggin } 592ddd703caSNicholas Piggin 593e0476371SMilton Miller void smp_send_debugger_break(void) 5945ad57078SPaul Mackerras { 595ddd703caSNicholas Piggin smp_send_nmi_ipi(NMI_IPI_ALL_OTHERS, debugger_ipi_callback, 1000000); 5965ad57078SPaul Mackerras } 5975ad57078SPaul Mackerras #endif 5985ad57078SPaul Mackerras 599da665885SThiago Jung Bauermann #ifdef CONFIG_KEXEC_CORE 600cc532915SMichael Ellerman void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *)) 601cc532915SMichael Ellerman { 6024145f358SBalbir Singh int cpu; 6034145f358SBalbir Singh 604ddd703caSNicholas Piggin smp_send_nmi_ipi(NMI_IPI_ALL_OTHERS, crash_ipi_callback, 1000000); 6054145f358SBalbir Singh if (kdump_in_progress() && crash_wake_offline) { 6064145f358SBalbir Singh for_each_present_cpu(cpu) { 6074145f358SBalbir Singh if (cpu_online(cpu)) 6084145f358SBalbir Singh continue; 6094145f358SBalbir Singh /* 6104145f358SBalbir Singh * crash_ipi_callback will wait for 6114145f358SBalbir Singh * all cpus, including offline CPUs. 6124145f358SBalbir Singh * We don't care about nmi_ipi_function. 6134145f358SBalbir Singh * Offline cpus will jump straight into 6144145f358SBalbir Singh * crash_ipi_callback, we can skip the 6154145f358SBalbir Singh * entire NMI dance and waiting for 6164145f358SBalbir Singh * cpus to clear pending mask, etc. 6174145f358SBalbir Singh */ 6186ba55716SMichael Ellerman do_smp_send_nmi_ipi(cpu, false); 6194145f358SBalbir Singh } 6204145f358SBalbir Singh } 621cc532915SMichael Ellerman } 622cc532915SMichael Ellerman #endif 623cc532915SMichael Ellerman 6246029755eSNicholas Piggin #ifdef CONFIG_NMI_IPI 625219572d2SHari Bathini static void crash_stop_this_cpu(struct pt_regs *regs) 626219572d2SHari Bathini #else 627219572d2SHari Bathini static void crash_stop_this_cpu(void *dummy) 628219572d2SHari Bathini #endif 629219572d2SHari Bathini { 630219572d2SHari Bathini /* 631219572d2SHari Bathini * Just busy wait here and avoid marking CPU as offline to ensure 632219572d2SHari Bathini * register data is captured appropriately. 633219572d2SHari Bathini */ 634219572d2SHari Bathini while (1) 635219572d2SHari Bathini cpu_relax(); 636219572d2SHari Bathini } 637219572d2SHari Bathini 638219572d2SHari Bathini void crash_smp_send_stop(void) 639219572d2SHari Bathini { 640219572d2SHari Bathini static bool stopped = false; 641219572d2SHari Bathini 64206e629c2SHari Bathini /* 64306e629c2SHari Bathini * In case of fadump, register data for all CPUs is captured by f/w 64406e629c2SHari Bathini * on ibm,os-term rtas call. Skip IPI callbacks to other CPUs before 64506e629c2SHari Bathini * this rtas call to avoid tricky post processing of those CPUs' 64606e629c2SHari Bathini * backtraces. 64706e629c2SHari Bathini */ 64806e629c2SHari Bathini if (should_fadump_crash()) 64906e629c2SHari Bathini return; 65006e629c2SHari Bathini 651219572d2SHari Bathini if (stopped) 652219572d2SHari Bathini return; 653219572d2SHari Bathini 654219572d2SHari Bathini stopped = true; 655219572d2SHari Bathini 656219572d2SHari Bathini #ifdef CONFIG_NMI_IPI 657219572d2SHari Bathini smp_send_nmi_ipi(NMI_IPI_ALL_OTHERS, crash_stop_this_cpu, 1000000); 658219572d2SHari Bathini #else 659219572d2SHari Bathini smp_call_function(crash_stop_this_cpu, NULL, 0); 660219572d2SHari Bathini #endif /* CONFIG_NMI_IPI */ 661219572d2SHari Bathini } 662219572d2SHari Bathini 663219572d2SHari Bathini #ifdef CONFIG_NMI_IPI 6646029755eSNicholas Piggin static void nmi_stop_this_cpu(struct pt_regs *regs) 6656029755eSNicholas Piggin { 6666029755eSNicholas Piggin /* 6676029755eSNicholas Piggin * IRQs are already hard disabled by the smp_handle_nmi_ipi. 6686029755eSNicholas Piggin */ 669bab26238SNicholas Piggin set_cpu_online(smp_processor_id(), false); 670bab26238SNicholas Piggin 6716029755eSNicholas Piggin spin_begin(); 6726029755eSNicholas Piggin while (1) 6736029755eSNicholas Piggin spin_cpu_relax(); 6746029755eSNicholas Piggin } 6756029755eSNicholas Piggin 6766029755eSNicholas Piggin void smp_send_stop(void) 6776029755eSNicholas Piggin { 6786029755eSNicholas Piggin smp_send_nmi_ipi(NMI_IPI_ALL_OTHERS, nmi_stop_this_cpu, 1000000); 6796029755eSNicholas Piggin } 6806029755eSNicholas Piggin 6816029755eSNicholas Piggin #else /* CONFIG_NMI_IPI */ 6826029755eSNicholas Piggin 6835ad57078SPaul Mackerras static void stop_this_cpu(void *dummy) 6845ad57078SPaul Mackerras { 685855bfe0dSNicholas Piggin hard_irq_disable(); 686bab26238SNicholas Piggin 687bab26238SNicholas Piggin /* 688bab26238SNicholas Piggin * Offlining CPUs in stop_this_cpu can result in scheduler warnings, 689bab26238SNicholas Piggin * (see commit de6e5d38417e), but printk_safe_flush_on_panic() wants 690bab26238SNicholas Piggin * to know other CPUs are offline before it breaks locks to flush 691bab26238SNicholas Piggin * printk buffers, in case we panic()ed while holding the lock. 692bab26238SNicholas Piggin */ 693bab26238SNicholas Piggin set_cpu_online(smp_processor_id(), false); 694bab26238SNicholas Piggin 695855bfe0dSNicholas Piggin spin_begin(); 6965ad57078SPaul Mackerras while (1) 697855bfe0dSNicholas Piggin spin_cpu_relax(); 6985ad57078SPaul Mackerras } 6995ad57078SPaul Mackerras 7008fd7675cSSatyam Sharma void smp_send_stop(void) 7018fd7675cSSatyam Sharma { 7026029755eSNicholas Piggin static bool stopped = false; 7036029755eSNicholas Piggin 7046029755eSNicholas Piggin /* 7056029755eSNicholas Piggin * Prevent waiting on csd lock from a previous smp_send_stop. 7066029755eSNicholas Piggin * This is racy, but in general callers try to do the right 7076029755eSNicholas Piggin * thing and only fire off one smp_send_stop (e.g., see 7086029755eSNicholas Piggin * kernel/panic.c) 7096029755eSNicholas Piggin */ 7106029755eSNicholas Piggin if (stopped) 7116029755eSNicholas Piggin return; 7126029755eSNicholas Piggin 7136029755eSNicholas Piggin stopped = true; 7146029755eSNicholas Piggin 7158691e5a8SJens Axboe smp_call_function(stop_this_cpu, NULL, 0); 7165ad57078SPaul Mackerras } 7176029755eSNicholas Piggin #endif /* CONFIG_NMI_IPI */ 7185ad57078SPaul Mackerras 7197c19c2e5SChristophe Leroy struct task_struct *current_set[NR_CPUS]; 7205ad57078SPaul Mackerras 721cad5cef6SGreg Kroah-Hartman static void smp_store_cpu_info(int id) 7225ad57078SPaul Mackerras { 7236b7487fcSTejun Heo per_cpu(cpu_pvr, id) = mfspr(SPRN_PVR); 7243160b097SBecky Bruce #ifdef CONFIG_PPC_FSL_BOOK3E 7253160b097SBecky Bruce per_cpu(next_tlbcam_idx, id) 7263160b097SBecky Bruce = (mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY) - 1; 7273160b097SBecky Bruce #endif 7285ad57078SPaul Mackerras } 7295ad57078SPaul Mackerras 730df52f671SOliver O'Halloran /* 731df52f671SOliver O'Halloran * Relationships between CPUs are maintained in a set of per-cpu cpumasks so 732df52f671SOliver O'Halloran * rather than just passing around the cpumask we pass around a function that 733df52f671SOliver O'Halloran * returns the that cpumask for the given CPU. 734df52f671SOliver O'Halloran */ 735df52f671SOliver O'Halloran static void set_cpus_related(int i, int j, struct cpumask *(*get_cpumask)(int)) 736df52f671SOliver O'Halloran { 737df52f671SOliver O'Halloran cpumask_set_cpu(i, get_cpumask(j)); 738df52f671SOliver O'Halloran cpumask_set_cpu(j, get_cpumask(i)); 739df52f671SOliver O'Halloran } 740df52f671SOliver O'Halloran 741df52f671SOliver O'Halloran #ifdef CONFIG_HOTPLUG_CPU 742df52f671SOliver O'Halloran static void set_cpus_unrelated(int i, int j, 743df52f671SOliver O'Halloran struct cpumask *(*get_cpumask)(int)) 744df52f671SOliver O'Halloran { 745df52f671SOliver O'Halloran cpumask_clear_cpu(i, get_cpumask(j)); 746df52f671SOliver O'Halloran cpumask_clear_cpu(j, get_cpumask(i)); 747df52f671SOliver O'Halloran } 748df52f671SOliver O'Halloran #endif 749df52f671SOliver O'Halloran 750425752c6SGautham R. Shenoy /* 7513ab33d6dSSrikar Dronamraju * Extends set_cpus_related. Instead of setting one CPU at a time in 7523ab33d6dSSrikar Dronamraju * dstmask, set srcmask at oneshot. dstmask should be super set of srcmask. 7533ab33d6dSSrikar Dronamraju */ 7543ab33d6dSSrikar Dronamraju static void or_cpumasks_related(int i, int j, struct cpumask *(*srcmask)(int), 7553ab33d6dSSrikar Dronamraju struct cpumask *(*dstmask)(int)) 7563ab33d6dSSrikar Dronamraju { 7573ab33d6dSSrikar Dronamraju struct cpumask *mask; 7583ab33d6dSSrikar Dronamraju int k; 7593ab33d6dSSrikar Dronamraju 7603ab33d6dSSrikar Dronamraju mask = srcmask(j); 7613ab33d6dSSrikar Dronamraju for_each_cpu(k, srcmask(i)) 7623ab33d6dSSrikar Dronamraju cpumask_or(dstmask(k), dstmask(k), mask); 7633ab33d6dSSrikar Dronamraju 7643ab33d6dSSrikar Dronamraju if (i == j) 7653ab33d6dSSrikar Dronamraju return; 7663ab33d6dSSrikar Dronamraju 7673ab33d6dSSrikar Dronamraju mask = srcmask(i); 7683ab33d6dSSrikar Dronamraju for_each_cpu(k, srcmask(j)) 7693ab33d6dSSrikar Dronamraju cpumask_or(dstmask(k), dstmask(k), mask); 7703ab33d6dSSrikar Dronamraju } 7713ab33d6dSSrikar Dronamraju 7723ab33d6dSSrikar Dronamraju /* 773425752c6SGautham R. Shenoy * parse_thread_groups: Parses the "ibm,thread-groups" device tree 774425752c6SGautham R. Shenoy * property for the CPU device node @dn and stores 775790a1662SGautham R. Shenoy * the parsed output in the thread_groups_list 776790a1662SGautham R. Shenoy * structure @tglp. 777425752c6SGautham R. Shenoy * 778425752c6SGautham R. Shenoy * @dn: The device node of the CPU device. 779790a1662SGautham R. Shenoy * @tglp: Pointer to a thread group list structure into which the parsed 780425752c6SGautham R. Shenoy * output of "ibm,thread-groups" is stored. 781425752c6SGautham R. Shenoy * 782425752c6SGautham R. Shenoy * ibm,thread-groups[0..N-1] array defines which group of threads in 783425752c6SGautham R. Shenoy * the CPU-device node can be grouped together based on the property. 784425752c6SGautham R. Shenoy * 785790a1662SGautham R. Shenoy * This array can represent thread groupings for multiple properties. 786790a1662SGautham R. Shenoy * 787790a1662SGautham R. Shenoy * ibm,thread-groups[i + 0] tells us the property based on which the 788425752c6SGautham R. Shenoy * threads are being grouped together. If this value is 1, it implies 7899538abeeSGautham R. Shenoy * that the threads in the same group share L1, translation cache. If 7909538abeeSGautham R. Shenoy * the value is 2, it implies that the threads in the same group share 7919538abeeSGautham R. Shenoy * the same L2 cache. 792425752c6SGautham R. Shenoy * 793790a1662SGautham R. Shenoy * ibm,thread-groups[i+1] tells us how many such thread groups exist for the 794790a1662SGautham R. Shenoy * property ibm,thread-groups[i] 795425752c6SGautham R. Shenoy * 796790a1662SGautham R. Shenoy * ibm,thread-groups[i+2] tells us the number of threads in each such 797425752c6SGautham R. Shenoy * group. 798790a1662SGautham R. Shenoy * Suppose k = (ibm,thread-groups[i+1] * ibm,thread-groups[i+2]), then, 799425752c6SGautham R. Shenoy * 800790a1662SGautham R. Shenoy * ibm,thread-groups[i+3..i+k+2] (is the list of threads identified by 801425752c6SGautham R. Shenoy * "ibm,ppc-interrupt-server#s" arranged as per their membership in 802425752c6SGautham R. Shenoy * the grouping. 803425752c6SGautham R. Shenoy * 804790a1662SGautham R. Shenoy * Example: 805790a1662SGautham 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] 806790a1662SGautham R. Shenoy * This can be decomposed up into two consecutive arrays: 807790a1662SGautham R. Shenoy * a) [1,2,4,8,10,12,14,9,11,13,15] 808790a1662SGautham R. Shenoy * b) [2,2,4,8,10,12,14,9,11,13,15] 809425752c6SGautham R. Shenoy * 810790a1662SGautham R. Shenoy * where in, 811790a1662SGautham R. Shenoy * 812790a1662SGautham R. Shenoy * a) provides information of Property "1" being shared by "2" groups, 813790a1662SGautham R. Shenoy * each with "4" threads each. The "ibm,ppc-interrupt-server#s" of 814790a1662SGautham R. Shenoy * the first group is {8,10,12,14} and the 815790a1662SGautham R. Shenoy * "ibm,ppc-interrupt-server#s" of the second group is 816790a1662SGautham R. Shenoy * {9,11,13,15}. Property "1" is indicative of the thread in the 817790a1662SGautham R. Shenoy * group sharing L1 cache, translation cache and Instruction Data 818790a1662SGautham R. Shenoy * flow. 819790a1662SGautham R. Shenoy * 820790a1662SGautham R. Shenoy * b) provides information of Property "2" being shared by "2" groups, 821790a1662SGautham R. Shenoy * each group with "4" threads. The "ibm,ppc-interrupt-server#s" of 822790a1662SGautham R. Shenoy * the first group is {8,10,12,14} and the 823790a1662SGautham R. Shenoy * "ibm,ppc-interrupt-server#s" of the second group is 824790a1662SGautham R. Shenoy * {9,11,13,15}. Property "2" indicates that the threads in each 825790a1662SGautham R. Shenoy * group share the L2-cache. 826425752c6SGautham R. Shenoy * 827425752c6SGautham R. Shenoy * Returns 0 on success, -EINVAL if the property does not exist, 828425752c6SGautham R. Shenoy * -ENODATA if property does not have a value, and -EOVERFLOW if the 829425752c6SGautham R. Shenoy * property data isn't large enough. 830425752c6SGautham R. Shenoy */ 831425752c6SGautham R. Shenoy static int parse_thread_groups(struct device_node *dn, 832790a1662SGautham R. Shenoy struct thread_groups_list *tglp) 833425752c6SGautham R. Shenoy { 834790a1662SGautham R. Shenoy unsigned int property_idx = 0; 835790a1662SGautham R. Shenoy u32 *thread_group_array; 836425752c6SGautham R. Shenoy size_t total_threads; 837790a1662SGautham R. Shenoy int ret = 0, count; 838790a1662SGautham R. Shenoy u32 *thread_list; 839790a1662SGautham R. Shenoy int i = 0; 840425752c6SGautham R. Shenoy 841790a1662SGautham R. Shenoy count = of_property_count_u32_elems(dn, "ibm,thread-groups"); 842790a1662SGautham R. Shenoy thread_group_array = kcalloc(count, sizeof(u32), GFP_KERNEL); 843425752c6SGautham R. Shenoy ret = of_property_read_u32_array(dn, "ibm,thread-groups", 844790a1662SGautham R. Shenoy thread_group_array, count); 845425752c6SGautham R. Shenoy if (ret) 846790a1662SGautham R. Shenoy goto out_free; 847425752c6SGautham R. Shenoy 848790a1662SGautham R. Shenoy while (i < count && property_idx < MAX_THREAD_GROUP_PROPERTIES) { 849790a1662SGautham R. Shenoy int j; 850790a1662SGautham R. Shenoy struct thread_groups *tg = &tglp->property_tgs[property_idx++]; 851425752c6SGautham R. Shenoy 852790a1662SGautham R. Shenoy tg->property = thread_group_array[i]; 853790a1662SGautham R. Shenoy tg->nr_groups = thread_group_array[i + 1]; 854790a1662SGautham R. Shenoy tg->threads_per_group = thread_group_array[i + 2]; 855425752c6SGautham R. Shenoy total_threads = tg->nr_groups * tg->threads_per_group; 856425752c6SGautham R. Shenoy 857790a1662SGautham R. Shenoy thread_list = &thread_group_array[i + 3]; 858790a1662SGautham R. Shenoy 859790a1662SGautham R. Shenoy for (j = 0; j < total_threads; j++) 860790a1662SGautham R. Shenoy tg->thread_list[j] = thread_list[j]; 861790a1662SGautham R. Shenoy i = i + 3 + total_threads; 862790a1662SGautham R. Shenoy } 863790a1662SGautham R. Shenoy 864790a1662SGautham R. Shenoy tglp->nr_properties = property_idx; 865790a1662SGautham R. Shenoy 866790a1662SGautham R. Shenoy out_free: 867790a1662SGautham R. Shenoy kfree(thread_group_array); 868425752c6SGautham R. Shenoy return ret; 869425752c6SGautham R. Shenoy } 870425752c6SGautham R. Shenoy 871425752c6SGautham R. Shenoy /* 872425752c6SGautham R. Shenoy * get_cpu_thread_group_start : Searches the thread group in tg->thread_list 873425752c6SGautham R. Shenoy * that @cpu belongs to. 874425752c6SGautham R. Shenoy * 875425752c6SGautham R. Shenoy * @cpu : The logical CPU whose thread group is being searched. 876425752c6SGautham R. Shenoy * @tg : The thread-group structure of the CPU node which @cpu belongs 877425752c6SGautham R. Shenoy * to. 878425752c6SGautham R. Shenoy * 879425752c6SGautham R. Shenoy * Returns the index to tg->thread_list that points to the the start 880425752c6SGautham R. Shenoy * of the thread_group that @cpu belongs to. 881425752c6SGautham R. Shenoy * 882425752c6SGautham R. Shenoy * Returns -1 if cpu doesn't belong to any of the groups pointed to by 883425752c6SGautham R. Shenoy * tg->thread_list. 884425752c6SGautham R. Shenoy */ 885425752c6SGautham R. Shenoy static int get_cpu_thread_group_start(int cpu, struct thread_groups *tg) 886425752c6SGautham R. Shenoy { 887425752c6SGautham R. Shenoy int hw_cpu_id = get_hard_smp_processor_id(cpu); 888425752c6SGautham R. Shenoy int i, j; 889425752c6SGautham R. Shenoy 890425752c6SGautham R. Shenoy for (i = 0; i < tg->nr_groups; i++) { 891425752c6SGautham R. Shenoy int group_start = i * tg->threads_per_group; 892425752c6SGautham R. Shenoy 893425752c6SGautham R. Shenoy for (j = 0; j < tg->threads_per_group; j++) { 894425752c6SGautham R. Shenoy int idx = group_start + j; 895425752c6SGautham R. Shenoy 896425752c6SGautham R. Shenoy if (tg->thread_list[idx] == hw_cpu_id) 897425752c6SGautham R. Shenoy return group_start; 898425752c6SGautham R. Shenoy } 899425752c6SGautham R. Shenoy } 900425752c6SGautham R. Shenoy 901425752c6SGautham R. Shenoy return -1; 902425752c6SGautham R. Shenoy } 903425752c6SGautham R. Shenoy 904790a1662SGautham R. Shenoy static struct thread_groups *__init get_thread_groups(int cpu, 905790a1662SGautham R. Shenoy int group_property, 906790a1662SGautham R. Shenoy int *err) 907790a1662SGautham R. Shenoy { 908790a1662SGautham R. Shenoy struct device_node *dn = of_get_cpu_node(cpu, NULL); 909790a1662SGautham R. Shenoy struct thread_groups_list *cpu_tgl = &tgl[cpu]; 910790a1662SGautham R. Shenoy struct thread_groups *tg = NULL; 911790a1662SGautham R. Shenoy int i; 912790a1662SGautham R. Shenoy *err = 0; 913790a1662SGautham R. Shenoy 914790a1662SGautham R. Shenoy if (!dn) { 915790a1662SGautham R. Shenoy *err = -ENODATA; 916790a1662SGautham R. Shenoy return NULL; 917790a1662SGautham R. Shenoy } 918790a1662SGautham R. Shenoy 919790a1662SGautham R. Shenoy if (!cpu_tgl->nr_properties) { 920790a1662SGautham R. Shenoy *err = parse_thread_groups(dn, cpu_tgl); 921790a1662SGautham R. Shenoy if (*err) 922790a1662SGautham R. Shenoy goto out; 923790a1662SGautham R. Shenoy } 924790a1662SGautham R. Shenoy 925790a1662SGautham R. Shenoy for (i = 0; i < cpu_tgl->nr_properties; i++) { 926790a1662SGautham R. Shenoy if (cpu_tgl->property_tgs[i].property == group_property) { 927790a1662SGautham R. Shenoy tg = &cpu_tgl->property_tgs[i]; 928790a1662SGautham R. Shenoy break; 929790a1662SGautham R. Shenoy } 930790a1662SGautham R. Shenoy } 931790a1662SGautham R. Shenoy 932790a1662SGautham R. Shenoy if (!tg) 933790a1662SGautham R. Shenoy *err = -EINVAL; 934790a1662SGautham R. Shenoy out: 935790a1662SGautham R. Shenoy of_node_put(dn); 936790a1662SGautham R. Shenoy return tg; 937790a1662SGautham R. Shenoy } 938790a1662SGautham R. Shenoy 939*d276960dSNick Child static int __init update_mask_from_threadgroup(cpumask_var_t *mask, struct thread_groups *tg, 940*d276960dSNick Child int cpu, int cpu_group_start) 941425752c6SGautham R. Shenoy { 942425752c6SGautham R. Shenoy int first_thread = cpu_first_thread_sibling(cpu); 943e9ef81e1SParth Shah int i; 9449538abeeSGautham R. Shenoy 945fbd2b672SGautham R. Shenoy zalloc_cpumask_var_node(mask, GFP_KERNEL, cpu_to_node(cpu)); 9466e086302SSrikar Dronamraju 947425752c6SGautham R. Shenoy for (i = first_thread; i < first_thread + threads_per_core; i++) { 948790a1662SGautham R. Shenoy int i_group_start = get_cpu_thread_group_start(i, tg); 949425752c6SGautham R. Shenoy 950425752c6SGautham R. Shenoy if (unlikely(i_group_start == -1)) { 951425752c6SGautham R. Shenoy WARN_ON_ONCE(1); 952790a1662SGautham R. Shenoy return -ENODATA; 953425752c6SGautham R. Shenoy } 954425752c6SGautham R. Shenoy 955425752c6SGautham R. Shenoy if (i_group_start == cpu_group_start) 956fbd2b672SGautham R. Shenoy cpumask_set_cpu(i, *mask); 957425752c6SGautham R. Shenoy } 958425752c6SGautham R. Shenoy 959790a1662SGautham R. Shenoy return 0; 960425752c6SGautham R. Shenoy } 961425752c6SGautham R. Shenoy 962e9ef81e1SParth Shah static int __init init_thread_group_cache_map(int cpu, int cache_property) 963e9ef81e1SParth Shah 964e9ef81e1SParth Shah { 965e9ef81e1SParth Shah int cpu_group_start = -1, err = 0; 966e9ef81e1SParth Shah struct thread_groups *tg = NULL; 967e9ef81e1SParth Shah cpumask_var_t *mask = NULL; 968e9ef81e1SParth Shah 969e9ef81e1SParth Shah if (cache_property != THREAD_GROUP_SHARE_L1 && 970e9ef81e1SParth Shah cache_property != THREAD_GROUP_SHARE_L2_L3) 971e9ef81e1SParth Shah return -EINVAL; 972e9ef81e1SParth Shah 973e9ef81e1SParth Shah tg = get_thread_groups(cpu, cache_property, &err); 974e9ef81e1SParth Shah 975e9ef81e1SParth Shah if (!tg) 976e9ef81e1SParth Shah return err; 977e9ef81e1SParth Shah 978e9ef81e1SParth Shah cpu_group_start = get_cpu_thread_group_start(cpu, tg); 979e9ef81e1SParth Shah 980e9ef81e1SParth Shah if (unlikely(cpu_group_start == -1)) { 981e9ef81e1SParth Shah WARN_ON_ONCE(1); 982e9ef81e1SParth Shah return -ENODATA; 983e9ef81e1SParth Shah } 984e9ef81e1SParth Shah 985e9ef81e1SParth Shah if (cache_property == THREAD_GROUP_SHARE_L1) { 986e9ef81e1SParth Shah mask = &per_cpu(thread_group_l1_cache_map, cpu); 987e9ef81e1SParth Shah update_mask_from_threadgroup(mask, tg, cpu, cpu_group_start); 988e9ef81e1SParth Shah } 989e9ef81e1SParth Shah else if (cache_property == THREAD_GROUP_SHARE_L2_L3) { 990e9ef81e1SParth Shah mask = &per_cpu(thread_group_l2_cache_map, cpu); 991e9ef81e1SParth Shah update_mask_from_threadgroup(mask, tg, cpu, cpu_group_start); 992e9ef81e1SParth Shah mask = &per_cpu(thread_group_l3_cache_map, cpu); 993e9ef81e1SParth Shah update_mask_from_threadgroup(mask, tg, cpu, cpu_group_start); 994e9ef81e1SParth Shah } 995e9ef81e1SParth Shah 996e9ef81e1SParth Shah 997e9ef81e1SParth Shah return 0; 998e9ef81e1SParth Shah } 999e9ef81e1SParth Shah 10005e93f16aSSrikar Dronamraju static bool shared_caches; 10015e93f16aSSrikar Dronamraju 10025e93f16aSSrikar Dronamraju #ifdef CONFIG_SCHED_SMT 10035e93f16aSSrikar Dronamraju /* cpumask of CPUs with asymmetric SMT dependency */ 10045e93f16aSSrikar Dronamraju static int powerpc_smt_flags(void) 10055e93f16aSSrikar Dronamraju { 10065e93f16aSSrikar Dronamraju int flags = SD_SHARE_CPUCAPACITY | SD_SHARE_PKG_RESOURCES; 10075e93f16aSSrikar Dronamraju 10085e93f16aSSrikar Dronamraju if (cpu_has_feature(CPU_FTR_ASYM_SMT)) { 10095e93f16aSSrikar Dronamraju printk_once(KERN_INFO "Enabling Asymmetric SMT scheduling\n"); 10105e93f16aSSrikar Dronamraju flags |= SD_ASYM_PACKING; 10115e93f16aSSrikar Dronamraju } 10125e93f16aSSrikar Dronamraju return flags; 10135e93f16aSSrikar Dronamraju } 10145e93f16aSSrikar Dronamraju #endif 10155e93f16aSSrikar Dronamraju 10165e93f16aSSrikar Dronamraju /* 10175e93f16aSSrikar Dronamraju * P9 has a slightly odd architecture where pairs of cores share an L2 cache. 10185e93f16aSSrikar Dronamraju * This topology makes it *much* cheaper to migrate tasks between adjacent cores 10195e93f16aSSrikar Dronamraju * since the migrated task remains cache hot. We want to take advantage of this 10205e93f16aSSrikar Dronamraju * at the scheduler level so an extra topology level is required. 10215e93f16aSSrikar Dronamraju */ 10225e93f16aSSrikar Dronamraju static int powerpc_shared_cache_flags(void) 10235e93f16aSSrikar Dronamraju { 10245e93f16aSSrikar Dronamraju return SD_SHARE_PKG_RESOURCES; 10255e93f16aSSrikar Dronamraju } 10265e93f16aSSrikar Dronamraju 10275e93f16aSSrikar Dronamraju /* 10285e93f16aSSrikar Dronamraju * We can't just pass cpu_l2_cache_mask() directly because 10295e93f16aSSrikar Dronamraju * returns a non-const pointer and the compiler barfs on that. 10305e93f16aSSrikar Dronamraju */ 10315e93f16aSSrikar Dronamraju static const struct cpumask *shared_cache_mask(int cpu) 10325e93f16aSSrikar Dronamraju { 1033caa8e29dSSrikar Dronamraju return per_cpu(cpu_l2_cache_map, cpu); 10345e93f16aSSrikar Dronamraju } 10355e93f16aSSrikar Dronamraju 10365e93f16aSSrikar Dronamraju #ifdef CONFIG_SCHED_SMT 10375e93f16aSSrikar Dronamraju static const struct cpumask *smallcore_smt_mask(int cpu) 10385e93f16aSSrikar Dronamraju { 10395e93f16aSSrikar Dronamraju return cpu_smallcore_mask(cpu); 10405e93f16aSSrikar Dronamraju } 10415e93f16aSSrikar Dronamraju #endif 10425e93f16aSSrikar Dronamraju 104372730bfcSSrikar Dronamraju static struct cpumask *cpu_coregroup_mask(int cpu) 104472730bfcSSrikar Dronamraju { 104572730bfcSSrikar Dronamraju return per_cpu(cpu_coregroup_map, cpu); 104672730bfcSSrikar Dronamraju } 104772730bfcSSrikar Dronamraju 104872730bfcSSrikar Dronamraju static bool has_coregroup_support(void) 104972730bfcSSrikar Dronamraju { 105072730bfcSSrikar Dronamraju return coregroup_enabled; 105172730bfcSSrikar Dronamraju } 105272730bfcSSrikar Dronamraju 105372730bfcSSrikar Dronamraju static const struct cpumask *cpu_mc_mask(int cpu) 105472730bfcSSrikar Dronamraju { 105572730bfcSSrikar Dronamraju return cpu_coregroup_mask(cpu); 105672730bfcSSrikar Dronamraju } 105772730bfcSSrikar Dronamraju 10585e93f16aSSrikar Dronamraju static struct sched_domain_topology_level powerpc_topology[] = { 10595e93f16aSSrikar Dronamraju #ifdef CONFIG_SCHED_SMT 10605e93f16aSSrikar Dronamraju { cpu_smt_mask, powerpc_smt_flags, SD_INIT_NAME(SMT) }, 10615e93f16aSSrikar Dronamraju #endif 10625e93f16aSSrikar Dronamraju { shared_cache_mask, powerpc_shared_cache_flags, SD_INIT_NAME(CACHE) }, 106372730bfcSSrikar Dronamraju { cpu_mc_mask, SD_INIT_NAME(MC) }, 10645e93f16aSSrikar Dronamraju { cpu_cpu_mask, SD_INIT_NAME(DIE) }, 10655e93f16aSSrikar Dronamraju { NULL, }, 10665e93f16aSSrikar Dronamraju }; 10675e93f16aSSrikar Dronamraju 10689014eab6SCédric Le Goater static int __init init_big_cores(void) 1069425752c6SGautham R. Shenoy { 1070425752c6SGautham R. Shenoy int cpu; 1071425752c6SGautham R. Shenoy 1072425752c6SGautham R. Shenoy for_each_possible_cpu(cpu) { 1073fbd2b672SGautham R. Shenoy int err = init_thread_group_cache_map(cpu, THREAD_GROUP_SHARE_L1); 1074425752c6SGautham R. Shenoy 1075425752c6SGautham R. Shenoy if (err) 1076425752c6SGautham R. Shenoy return err; 1077425752c6SGautham R. Shenoy 1078425752c6SGautham R. Shenoy zalloc_cpumask_var_node(&per_cpu(cpu_smallcore_map, cpu), 1079425752c6SGautham R. Shenoy GFP_KERNEL, 1080425752c6SGautham R. Shenoy cpu_to_node(cpu)); 1081425752c6SGautham R. Shenoy } 1082425752c6SGautham R. Shenoy 1083425752c6SGautham R. Shenoy has_big_cores = true; 10849538abeeSGautham R. Shenoy 10859538abeeSGautham R. Shenoy for_each_possible_cpu(cpu) { 1086e9ef81e1SParth Shah int err = init_thread_group_cache_map(cpu, THREAD_GROUP_SHARE_L2_L3); 10879538abeeSGautham R. Shenoy 10889538abeeSGautham R. Shenoy if (err) 10899538abeeSGautham R. Shenoy return err; 10909538abeeSGautham R. Shenoy } 10919538abeeSGautham R. Shenoy 10929538abeeSGautham R. Shenoy thread_group_shares_l2 = true; 1093e9ef81e1SParth Shah thread_group_shares_l3 = true; 1094e9ef81e1SParth Shah pr_debug("L2/L3 cache only shared by the threads in the small core\n"); 1095e9ef81e1SParth Shah 1096425752c6SGautham R. Shenoy return 0; 1097425752c6SGautham R. Shenoy } 1098425752c6SGautham R. Shenoy 10995ad57078SPaul Mackerras void __init smp_prepare_cpus(unsigned int max_cpus) 11005ad57078SPaul Mackerras { 11015ad57078SPaul Mackerras unsigned int cpu; 11025ad57078SPaul Mackerras 11035ad57078SPaul Mackerras DBG("smp_prepare_cpus\n"); 11045ad57078SPaul Mackerras 11055ad57078SPaul Mackerras /* 11065ad57078SPaul Mackerras * setup_cpu may need to be called on the boot cpu. We havent 11075ad57078SPaul Mackerras * spun any cpus up but lets be paranoid. 11085ad57078SPaul Mackerras */ 11095ad57078SPaul Mackerras BUG_ON(boot_cpuid != smp_processor_id()); 11105ad57078SPaul Mackerras 11115ad57078SPaul Mackerras /* Fixup boot cpu */ 11125ad57078SPaul Mackerras smp_store_cpu_info(boot_cpuid); 11135ad57078SPaul Mackerras cpu_callin_map[boot_cpuid] = 1; 11145ad57078SPaul Mackerras 1115cc1ba8eaSAnton Blanchard for_each_possible_cpu(cpu) { 1116cc1ba8eaSAnton Blanchard zalloc_cpumask_var_node(&per_cpu(cpu_sibling_map, cpu), 1117cc1ba8eaSAnton Blanchard GFP_KERNEL, cpu_to_node(cpu)); 11182a636a56SOliver O'Halloran zalloc_cpumask_var_node(&per_cpu(cpu_l2_cache_map, cpu), 11192a636a56SOliver O'Halloran GFP_KERNEL, cpu_to_node(cpu)); 1120cc1ba8eaSAnton Blanchard zalloc_cpumask_var_node(&per_cpu(cpu_core_map, cpu), 1121cc1ba8eaSAnton Blanchard GFP_KERNEL, cpu_to_node(cpu)); 112272730bfcSSrikar Dronamraju if (has_coregroup_support()) 112372730bfcSSrikar Dronamraju zalloc_cpumask_var_node(&per_cpu(cpu_coregroup_map, cpu), 112472730bfcSSrikar Dronamraju GFP_KERNEL, cpu_to_node(cpu)); 112572730bfcSSrikar Dronamraju 1126a9ee6cf5SMike Rapoport #ifdef CONFIG_NUMA 11272fabf084SNishanth Aravamudan /* 11282fabf084SNishanth Aravamudan * numa_node_id() works after this. 11292fabf084SNishanth Aravamudan */ 1130bc3c4327SLi Zhong if (cpu_present(cpu)) { 11312fabf084SNishanth Aravamudan set_cpu_numa_node(cpu, numa_cpu_lookup_table[cpu]); 1132bc3c4327SLi Zhong set_cpu_numa_mem(cpu, 1133bc3c4327SLi Zhong local_memory_node(numa_cpu_lookup_table[cpu])); 1134bc3c4327SLi Zhong } 1135d0fd24bbSSrikar Dronamraju #endif 1136cc1ba8eaSAnton Blanchard } 1137cc1ba8eaSAnton Blanchard 1138df52f671SOliver O'Halloran /* Init the cpumasks so the boot CPU is related to itself */ 1139cc1ba8eaSAnton Blanchard cpumask_set_cpu(boot_cpuid, cpu_sibling_mask(boot_cpuid)); 11402a636a56SOliver O'Halloran cpumask_set_cpu(boot_cpuid, cpu_l2_cache_mask(boot_cpuid)); 1141c47f892dSSrikar Dronamraju cpumask_set_cpu(boot_cpuid, cpu_core_mask(boot_cpuid)); 1142cc1ba8eaSAnton Blanchard 114372730bfcSSrikar Dronamraju if (has_coregroup_support()) 114472730bfcSSrikar Dronamraju cpumask_set_cpu(boot_cpuid, cpu_coregroup_mask(boot_cpuid)); 114572730bfcSSrikar Dronamraju 1146425752c6SGautham R. Shenoy init_big_cores(); 1147425752c6SGautham R. Shenoy if (has_big_cores) { 1148425752c6SGautham R. Shenoy cpumask_set_cpu(boot_cpuid, 1149425752c6SGautham R. Shenoy cpu_smallcore_mask(boot_cpuid)); 1150425752c6SGautham R. Shenoy } 1151425752c6SGautham R. Shenoy 1152c1e53367SSrikar Dronamraju if (cpu_to_chip_id(boot_cpuid) != -1) { 11538efd249bSSrikar Dronamraju int idx = DIV_ROUND_UP(num_possible_cpus(), threads_per_core); 1154c1e53367SSrikar Dronamraju 1155c1e53367SSrikar Dronamraju /* 1156c1e53367SSrikar Dronamraju * All threads of a core will all belong to the same core, 1157c1e53367SSrikar Dronamraju * chip_id_lookup_table will have one entry per core. 1158c1e53367SSrikar Dronamraju * Assumption: if boot_cpuid doesn't have a chip-id, then no 1159c1e53367SSrikar Dronamraju * other CPUs, will also not have chip-id. 1160c1e53367SSrikar Dronamraju */ 1161c1e53367SSrikar Dronamraju chip_id_lookup_table = kcalloc(idx, sizeof(int), GFP_KERNEL); 1162c1e53367SSrikar Dronamraju if (chip_id_lookup_table) 1163c1e53367SSrikar Dronamraju memset(chip_id_lookup_table, -1, sizeof(int) * idx); 1164c1e53367SSrikar Dronamraju } 1165c1e53367SSrikar Dronamraju 1166dfee0efeSChen Gang if (smp_ops && smp_ops->probe) 1167dfee0efeSChen Gang smp_ops->probe(); 11685ad57078SPaul Mackerras } 11695ad57078SPaul Mackerras 1170cad5cef6SGreg Kroah-Hartman void smp_prepare_boot_cpu(void) 11715ad57078SPaul Mackerras { 11725ad57078SPaul Mackerras BUG_ON(smp_processor_id() != boot_cpuid); 11735ad57078SPaul Mackerras #ifdef CONFIG_PPC64 1174d2e60075SNicholas Piggin paca_ptrs[boot_cpuid]->__current = current; 11755ad57078SPaul Mackerras #endif 11768c272261SNishanth Aravamudan set_numa_node(numa_cpu_lookup_table[boot_cpuid]); 11777c19c2e5SChristophe Leroy current_set[boot_cpuid] = current; 11785ad57078SPaul Mackerras } 11795ad57078SPaul Mackerras 11805ad57078SPaul Mackerras #ifdef CONFIG_HOTPLUG_CPU 11815ad57078SPaul Mackerras 11825ad57078SPaul Mackerras int generic_cpu_disable(void) 11835ad57078SPaul Mackerras { 11845ad57078SPaul Mackerras unsigned int cpu = smp_processor_id(); 11855ad57078SPaul Mackerras 11865ad57078SPaul Mackerras if (cpu == boot_cpuid) 11875ad57078SPaul Mackerras return -EBUSY; 11885ad57078SPaul Mackerras 1189ea0f1cabSRusty Russell set_cpu_online(cpu, false); 1190799d6046SPaul Mackerras #ifdef CONFIG_PPC64 1191a7f290daSBenjamin Herrenschmidt vdso_data->processorCount--; 1192094fe2e7SPaul Mackerras #endif 1193a978e139SBenjamin Herrenschmidt /* Update affinity of all IRQs previously aimed at this CPU */ 1194a978e139SBenjamin Herrenschmidt irq_migrate_all_off_this_cpu(); 1195a978e139SBenjamin Herrenschmidt 1196687b8f24SMichael Ellerman /* 1197687b8f24SMichael Ellerman * Depending on the details of the interrupt controller, it's possible 1198687b8f24SMichael Ellerman * that one of the interrupts we just migrated away from this CPU is 1199687b8f24SMichael Ellerman * actually already pending on this CPU. If we leave it in that state 1200687b8f24SMichael Ellerman * the interrupt will never be EOI'ed, and will never fire again. So 1201687b8f24SMichael Ellerman * temporarily enable interrupts here, to allow any pending interrupt to 1202687b8f24SMichael Ellerman * be received (and EOI'ed), before we take this CPU offline. 1203687b8f24SMichael Ellerman */ 1204a978e139SBenjamin Herrenschmidt local_irq_enable(); 1205a978e139SBenjamin Herrenschmidt mdelay(1); 1206a978e139SBenjamin Herrenschmidt local_irq_disable(); 1207a978e139SBenjamin Herrenschmidt 12085ad57078SPaul Mackerras return 0; 12095ad57078SPaul Mackerras } 12105ad57078SPaul Mackerras 12115ad57078SPaul Mackerras void generic_cpu_die(unsigned int cpu) 12125ad57078SPaul Mackerras { 12135ad57078SPaul Mackerras int i; 12145ad57078SPaul Mackerras 12155ad57078SPaul Mackerras for (i = 0; i < 100; i++) { 12165ad57078SPaul Mackerras smp_rmb(); 12172f4f1f81Schenhui zhao if (is_cpu_dead(cpu)) 12185ad57078SPaul Mackerras return; 12195ad57078SPaul Mackerras msleep(100); 12205ad57078SPaul Mackerras } 12215ad57078SPaul Mackerras printk(KERN_ERR "CPU%d didn't die...\n", cpu); 12225ad57078SPaul Mackerras } 12235ad57078SPaul Mackerras 1224105765f4SBenjamin Herrenschmidt void generic_set_cpu_dead(unsigned int cpu) 1225105765f4SBenjamin Herrenschmidt { 1226105765f4SBenjamin Herrenschmidt per_cpu(cpu_state, cpu) = CPU_DEAD; 1227105765f4SBenjamin Herrenschmidt } 1228fb82b839SBenjamin Herrenschmidt 1229ae5cab47SZhao Chenhui /* 1230ae5cab47SZhao Chenhui * The cpu_state should be set to CPU_UP_PREPARE in kick_cpu(), otherwise 1231ae5cab47SZhao Chenhui * the cpu_state is always CPU_DEAD after calling generic_set_cpu_dead(), 1232ae5cab47SZhao Chenhui * which makes the delay in generic_cpu_die() not happen. 1233ae5cab47SZhao Chenhui */ 1234ae5cab47SZhao Chenhui void generic_set_cpu_up(unsigned int cpu) 1235ae5cab47SZhao Chenhui { 1236ae5cab47SZhao Chenhui per_cpu(cpu_state, cpu) = CPU_UP_PREPARE; 1237ae5cab47SZhao Chenhui } 1238ae5cab47SZhao Chenhui 1239fb82b839SBenjamin Herrenschmidt int generic_check_cpu_restart(unsigned int cpu) 1240fb82b839SBenjamin Herrenschmidt { 1241fb82b839SBenjamin Herrenschmidt return per_cpu(cpu_state, cpu) == CPU_UP_PREPARE; 1242fb82b839SBenjamin Herrenschmidt } 1243512691d4SPaul Mackerras 12442f4f1f81Schenhui zhao int is_cpu_dead(unsigned int cpu) 12452f4f1f81Schenhui zhao { 12462f4f1f81Schenhui zhao return per_cpu(cpu_state, cpu) == CPU_DEAD; 12472f4f1f81Schenhui zhao } 12482f4f1f81Schenhui zhao 1249441c19c8SMichael Ellerman static bool secondaries_inhibited(void) 1250512691d4SPaul Mackerras { 1251441c19c8SMichael Ellerman return kvm_hv_mode_active(); 1252512691d4SPaul Mackerras } 1253512691d4SPaul Mackerras 1254512691d4SPaul Mackerras #else /* HOTPLUG_CPU */ 1255512691d4SPaul Mackerras 1256512691d4SPaul Mackerras #define secondaries_inhibited() 0 1257512691d4SPaul Mackerras 12585ad57078SPaul Mackerras #endif 12595ad57078SPaul Mackerras 126017e32eacSThomas Gleixner static void cpu_idle_thread_init(unsigned int cpu, struct task_struct *idle) 1261c56e5853SBenjamin Herrenschmidt { 1262c56e5853SBenjamin Herrenschmidt #ifdef CONFIG_PPC64 1263d2e60075SNicholas Piggin paca_ptrs[cpu]->__current = idle; 1264678c668aSChristophe Leroy paca_ptrs[cpu]->kstack = (unsigned long)task_stack_page(idle) + 1265678c668aSChristophe Leroy THREAD_SIZE - STACK_FRAME_OVERHEAD; 1266c56e5853SBenjamin Herrenschmidt #endif 1267bcf9033eSArd Biesheuvel task_thread_info(idle)->cpu = cpu; 12687c19c2e5SChristophe Leroy secondary_current = current_set[cpu] = idle; 1269c56e5853SBenjamin Herrenschmidt } 1270c56e5853SBenjamin Herrenschmidt 1271061d19f2SPaul Gortmaker int __cpu_up(unsigned int cpu, struct task_struct *tidle) 12725ad57078SPaul Mackerras { 1273c56e5853SBenjamin Herrenschmidt int rc, c; 12745ad57078SPaul Mackerras 1275512691d4SPaul Mackerras /* 1276512691d4SPaul Mackerras * Don't allow secondary threads to come online if inhibited 1277512691d4SPaul Mackerras */ 1278512691d4SPaul Mackerras if (threads_per_core > 1 && secondaries_inhibited() && 12796f5e40a3SMichael Ellerman cpu_thread_in_subcore(cpu)) 1280512691d4SPaul Mackerras return -EBUSY; 1281512691d4SPaul Mackerras 12828cffc6acSBenjamin Herrenschmidt if (smp_ops == NULL || 12838cffc6acSBenjamin Herrenschmidt (smp_ops->cpu_bootable && !smp_ops->cpu_bootable(cpu))) 12845ad57078SPaul Mackerras return -EINVAL; 12855ad57078SPaul Mackerras 128617e32eacSThomas Gleixner cpu_idle_thread_init(cpu, tidle); 1287c560bbceSkerstin jonsson 128814d4ae5cSBenjamin Herrenschmidt /* 128914d4ae5cSBenjamin Herrenschmidt * The platform might need to allocate resources prior to bringing 129014d4ae5cSBenjamin Herrenschmidt * up the CPU 129114d4ae5cSBenjamin Herrenschmidt */ 129214d4ae5cSBenjamin Herrenschmidt if (smp_ops->prepare_cpu) { 129314d4ae5cSBenjamin Herrenschmidt rc = smp_ops->prepare_cpu(cpu); 129414d4ae5cSBenjamin Herrenschmidt if (rc) 129514d4ae5cSBenjamin Herrenschmidt return rc; 129614d4ae5cSBenjamin Herrenschmidt } 129714d4ae5cSBenjamin Herrenschmidt 12985ad57078SPaul Mackerras /* Make sure callin-map entry is 0 (can be leftover a CPU 12995ad57078SPaul Mackerras * hotplug 13005ad57078SPaul Mackerras */ 13015ad57078SPaul Mackerras cpu_callin_map[cpu] = 0; 13025ad57078SPaul Mackerras 13035ad57078SPaul Mackerras /* The information for processor bringup must 13045ad57078SPaul Mackerras * be written out to main store before we release 13055ad57078SPaul Mackerras * the processor. 13065ad57078SPaul Mackerras */ 13075ad57078SPaul Mackerras smp_mb(); 13085ad57078SPaul Mackerras 13095ad57078SPaul Mackerras /* wake up cpus */ 13105ad57078SPaul Mackerras DBG("smp: kicking cpu %d\n", cpu); 1311de300974SMichael Ellerman rc = smp_ops->kick_cpu(cpu); 1312de300974SMichael Ellerman if (rc) { 1313de300974SMichael Ellerman pr_err("smp: failed starting cpu %d (rc %d)\n", cpu, rc); 1314de300974SMichael Ellerman return rc; 1315de300974SMichael Ellerman } 13165ad57078SPaul Mackerras 13175ad57078SPaul Mackerras /* 13185ad57078SPaul Mackerras * wait to see if the cpu made a callin (is actually up). 13195ad57078SPaul Mackerras * use this value that I found through experimentation. 13205ad57078SPaul Mackerras * -- Cort 13215ad57078SPaul Mackerras */ 13225ad57078SPaul Mackerras if (system_state < SYSTEM_RUNNING) 1323ee0339f2SJon Loeliger for (c = 50000; c && !cpu_callin_map[cpu]; c--) 13245ad57078SPaul Mackerras udelay(100); 13255ad57078SPaul Mackerras #ifdef CONFIG_HOTPLUG_CPU 13265ad57078SPaul Mackerras else 13275ad57078SPaul Mackerras /* 13285ad57078SPaul Mackerras * CPUs can take much longer to come up in the 13295ad57078SPaul Mackerras * hotplug case. Wait five seconds. 13305ad57078SPaul Mackerras */ 133167764263SGautham R Shenoy for (c = 5000; c && !cpu_callin_map[cpu]; c--) 133267764263SGautham R Shenoy msleep(1); 13335ad57078SPaul Mackerras #endif 13345ad57078SPaul Mackerras 13355ad57078SPaul Mackerras if (!cpu_callin_map[cpu]) { 13366685a477SSigned-off-by: Darren Hart printk(KERN_ERR "Processor %u is stuck.\n", cpu); 13375ad57078SPaul Mackerras return -ENOENT; 13385ad57078SPaul Mackerras } 13395ad57078SPaul Mackerras 13406685a477SSigned-off-by: Darren Hart DBG("Processor %u found.\n", cpu); 13415ad57078SPaul Mackerras 13425ad57078SPaul Mackerras if (smp_ops->give_timebase) 13435ad57078SPaul Mackerras smp_ops->give_timebase(); 13445ad57078SPaul Mackerras 1345875ebe94SMichael Ellerman /* Wait until cpu puts itself in the online & active maps */ 13464e287e65SNicholas Piggin spin_until_cond(cpu_online(cpu)); 13475ad57078SPaul Mackerras 13485ad57078SPaul Mackerras return 0; 13495ad57078SPaul Mackerras } 13505ad57078SPaul Mackerras 1351e9efed3bSNathan Lynch /* Return the value of the reg property corresponding to the given 1352e9efed3bSNathan Lynch * logical cpu. 1353e9efed3bSNathan Lynch */ 1354e9efed3bSNathan Lynch int cpu_to_core_id(int cpu) 1355e9efed3bSNathan Lynch { 1356e9efed3bSNathan Lynch struct device_node *np; 1357e9efed3bSNathan Lynch int id = -1; 1358e9efed3bSNathan Lynch 1359e9efed3bSNathan Lynch np = of_get_cpu_node(cpu, NULL); 1360e9efed3bSNathan Lynch if (!np) 1361e9efed3bSNathan Lynch goto out; 1362e9efed3bSNathan Lynch 136341408b22SRob Herring id = of_get_cpu_hwid(np, 0); 1364e9efed3bSNathan Lynch out: 1365e9efed3bSNathan Lynch of_node_put(np); 1366e9efed3bSNathan Lynch return id; 1367e9efed3bSNathan Lynch } 1368f8ab4810SMauricio Faria de Oliveira EXPORT_SYMBOL_GPL(cpu_to_core_id); 1369e9efed3bSNathan Lynch 137099d86705SVaidyanathan Srinivasan /* Helper routines for cpu to core mapping */ 137199d86705SVaidyanathan Srinivasan int cpu_core_index_of_thread(int cpu) 137299d86705SVaidyanathan Srinivasan { 137399d86705SVaidyanathan Srinivasan return cpu >> threads_shift; 137499d86705SVaidyanathan Srinivasan } 137599d86705SVaidyanathan Srinivasan EXPORT_SYMBOL_GPL(cpu_core_index_of_thread); 137699d86705SVaidyanathan Srinivasan 137799d86705SVaidyanathan Srinivasan int cpu_first_thread_of_core(int core) 137899d86705SVaidyanathan Srinivasan { 137999d86705SVaidyanathan Srinivasan return core << threads_shift; 138099d86705SVaidyanathan Srinivasan } 138199d86705SVaidyanathan Srinivasan EXPORT_SYMBOL_GPL(cpu_first_thread_of_core); 138299d86705SVaidyanathan Srinivasan 1383104699c0SKOSAKI Motohiro /* Must be called when no change can occur to cpu_present_mask, 1384440a0857SNathan Lynch * i.e. during cpu online or offline. 1385440a0857SNathan Lynch */ 1386440a0857SNathan Lynch static struct device_node *cpu_to_l2cache(int cpu) 1387440a0857SNathan Lynch { 1388440a0857SNathan Lynch struct device_node *np; 1389b2ea25b9SNathan Lynch struct device_node *cache; 1390440a0857SNathan Lynch 1391440a0857SNathan Lynch if (!cpu_present(cpu)) 1392440a0857SNathan Lynch return NULL; 1393440a0857SNathan Lynch 1394440a0857SNathan Lynch np = of_get_cpu_node(cpu, NULL); 1395440a0857SNathan Lynch if (np == NULL) 1396440a0857SNathan Lynch return NULL; 1397440a0857SNathan Lynch 1398b2ea25b9SNathan Lynch cache = of_find_next_cache_node(np); 1399b2ea25b9SNathan Lynch 1400440a0857SNathan Lynch of_node_put(np); 1401440a0857SNathan Lynch 1402b2ea25b9SNathan Lynch return cache; 1403440a0857SNathan Lynch } 14045ad57078SPaul Mackerras 140584dbf66cSSrikar Dronamraju static bool update_mask_by_l2(int cpu, cpumask_var_t *mask) 1406a8a5356cSPaul Mackerras { 14073ab33d6dSSrikar Dronamraju struct cpumask *(*submask_fn)(int) = cpu_sibling_mask; 1408256f2d4bSPaul Mackerras struct device_node *l2_cache, *np; 1409e3d8b67eSOliver O'Halloran int i; 1410256f2d4bSPaul Mackerras 1411966730a6SSrikar Dronamraju if (has_big_cores) 1412966730a6SSrikar Dronamraju submask_fn = cpu_smallcore_mask; 1413966730a6SSrikar Dronamraju 14149538abeeSGautham R. Shenoy /* 14159538abeeSGautham R. Shenoy * If the threads in a thread-group share L2 cache, then the 14169538abeeSGautham R. Shenoy * L2-mask can be obtained from thread_group_l2_cache_map. 14179538abeeSGautham R. Shenoy */ 14189538abeeSGautham R. Shenoy if (thread_group_shares_l2) { 14199538abeeSGautham R. Shenoy cpumask_set_cpu(cpu, cpu_l2_cache_mask(cpu)); 14209538abeeSGautham R. Shenoy 14219538abeeSGautham R. Shenoy for_each_cpu(i, per_cpu(thread_group_l2_cache_map, cpu)) { 14229538abeeSGautham R. Shenoy if (cpu_online(i)) 14239538abeeSGautham R. Shenoy set_cpus_related(i, cpu, cpu_l2_cache_mask); 14249538abeeSGautham R. Shenoy } 14259538abeeSGautham R. Shenoy 14269538abeeSGautham R. Shenoy /* Verify that L1-cache siblings are a subset of L2 cache-siblings */ 14279538abeeSGautham R. Shenoy if (!cpumask_equal(submask_fn(cpu), cpu_l2_cache_mask(cpu)) && 14289538abeeSGautham R. Shenoy !cpumask_subset(submask_fn(cpu), cpu_l2_cache_mask(cpu))) { 14299538abeeSGautham R. Shenoy pr_warn_once("CPU %d : Inconsistent L1 and L2 cache siblings\n", 14309538abeeSGautham R. Shenoy cpu); 14319538abeeSGautham R. Shenoy } 14329538abeeSGautham R. Shenoy 14339538abeeSGautham R. Shenoy return true; 14349538abeeSGautham R. Shenoy } 14359538abeeSGautham R. Shenoy 1436a8a5356cSPaul Mackerras l2_cache = cpu_to_l2cache(cpu); 143784dbf66cSSrikar Dronamraju if (!l2_cache || !*mask) { 143884dbf66cSSrikar Dronamraju /* Assume only core siblings share cache with this CPU */ 14395bf63497SSrikar Dronamraju for_each_cpu(i, cpu_sibling_mask(cpu)) 1440f6606cfdSSrikar Dronamraju set_cpus_related(cpu, i, cpu_l2_cache_mask); 1441f6606cfdSSrikar Dronamraju 1442f6606cfdSSrikar Dronamraju return false; 1443f6606cfdSSrikar Dronamraju } 1444f6606cfdSSrikar Dronamraju 144584dbf66cSSrikar Dronamraju cpumask_and(*mask, cpu_online_mask, cpu_cpu_mask(cpu)); 14463ab33d6dSSrikar Dronamraju 14473ab33d6dSSrikar Dronamraju /* Update l2-cache mask with all the CPUs that are part of submask */ 14483ab33d6dSSrikar Dronamraju or_cpumasks_related(cpu, cpu, submask_fn, cpu_l2_cache_mask); 14493ab33d6dSSrikar Dronamraju 14503ab33d6dSSrikar Dronamraju /* Skip all CPUs already part of current CPU l2-cache mask */ 145184dbf66cSSrikar Dronamraju cpumask_andnot(*mask, *mask, cpu_l2_cache_mask(cpu)); 14523ab33d6dSSrikar Dronamraju 145384dbf66cSSrikar Dronamraju for_each_cpu(i, *mask) { 1454df52f671SOliver O'Halloran /* 1455df52f671SOliver O'Halloran * when updating the marks the current CPU has not been marked 1456df52f671SOliver O'Halloran * online, but we need to update the cache masks 1457df52f671SOliver O'Halloran */ 1458256f2d4bSPaul Mackerras np = cpu_to_l2cache(i); 1459df52f671SOliver O'Halloran 14603ab33d6dSSrikar Dronamraju /* Skip all CPUs already part of current CPU l2-cache */ 14613ab33d6dSSrikar Dronamraju if (np == l2_cache) { 14623ab33d6dSSrikar Dronamraju or_cpumasks_related(cpu, i, submask_fn, cpu_l2_cache_mask); 146384dbf66cSSrikar Dronamraju cpumask_andnot(*mask, *mask, submask_fn(i)); 14643ab33d6dSSrikar Dronamraju } else { 146584dbf66cSSrikar Dronamraju cpumask_andnot(*mask, *mask, cpu_l2_cache_mask(i)); 14663ab33d6dSSrikar Dronamraju } 1467df52f671SOliver O'Halloran 1468a8a5356cSPaul Mackerras of_node_put(np); 1469a8a5356cSPaul Mackerras } 1470a8a5356cSPaul Mackerras of_node_put(l2_cache); 1471df52f671SOliver O'Halloran 1472df52f671SOliver O'Halloran return true; 1473df52f671SOliver O'Halloran } 1474df52f671SOliver O'Halloran 1475df52f671SOliver O'Halloran #ifdef CONFIG_HOTPLUG_CPU 1476df52f671SOliver O'Halloran static void remove_cpu_from_masks(int cpu) 1477df52f671SOliver O'Halloran { 147870edd4a7SSrikar Dronamraju struct cpumask *(*mask_fn)(int) = cpu_sibling_mask; 1479df52f671SOliver O'Halloran int i; 1480df52f671SOliver O'Halloran 14819a245d0eSSrikar Dronamraju unmap_cpu_from_node(cpu); 14829a245d0eSSrikar Dronamraju 148370edd4a7SSrikar Dronamraju if (shared_caches) 148470edd4a7SSrikar Dronamraju mask_fn = cpu_l2_cache_mask; 148570edd4a7SSrikar Dronamraju 148670edd4a7SSrikar Dronamraju for_each_cpu(i, mask_fn(cpu)) { 14872a636a56SOliver O'Halloran set_cpus_unrelated(cpu, i, cpu_l2_cache_mask); 1488df52f671SOliver O'Halloran set_cpus_unrelated(cpu, i, cpu_sibling_mask); 1489425752c6SGautham R. Shenoy if (has_big_cores) 1490425752c6SGautham R. Shenoy set_cpus_unrelated(cpu, i, cpu_smallcore_mask); 149170edd4a7SSrikar Dronamraju } 149270edd4a7SSrikar Dronamraju 1493c47f892dSSrikar Dronamraju for_each_cpu(i, cpu_core_mask(cpu)) 1494c47f892dSSrikar Dronamraju set_cpus_unrelated(cpu, i, cpu_core_mask); 1495c47f892dSSrikar Dronamraju 149670edd4a7SSrikar Dronamraju if (has_coregroup_support()) { 149770edd4a7SSrikar Dronamraju for_each_cpu(i, cpu_coregroup_mask(cpu)) 149872730bfcSSrikar Dronamraju set_cpus_unrelated(cpu, i, cpu_coregroup_mask); 1499df52f671SOliver O'Halloran } 1500df52f671SOliver O'Halloran } 1501df52f671SOliver O'Halloran #endif 1502df52f671SOliver O'Halloran 1503425752c6SGautham R. Shenoy static inline void add_cpu_to_smallcore_masks(int cpu) 1504425752c6SGautham R. Shenoy { 1505661e3d42SSrikar Dronamraju int i; 1506425752c6SGautham R. Shenoy 1507425752c6SGautham R. Shenoy if (!has_big_cores) 1508425752c6SGautham R. Shenoy return; 1509425752c6SGautham R. Shenoy 1510425752c6SGautham R. Shenoy cpumask_set_cpu(cpu, cpu_smallcore_mask(cpu)); 1511425752c6SGautham R. Shenoy 15121fdc1d66SGautham R. Shenoy for_each_cpu(i, per_cpu(thread_group_l1_cache_map, cpu)) { 1513661e3d42SSrikar Dronamraju if (cpu_online(i)) 1514425752c6SGautham R. Shenoy set_cpus_related(i, cpu, cpu_smallcore_mask); 1515425752c6SGautham R. Shenoy } 1516425752c6SGautham R. Shenoy } 1517425752c6SGautham R. Shenoy 151884dbf66cSSrikar Dronamraju static void update_coregroup_mask(int cpu, cpumask_var_t *mask) 1519b8a97cb4SSrikar Dronamraju { 152070a94089SSrikar Dronamraju struct cpumask *(*submask_fn)(int) = cpu_sibling_mask; 1521b8a97cb4SSrikar Dronamraju int coregroup_id = cpu_to_coregroup_id(cpu); 1522b8a97cb4SSrikar Dronamraju int i; 1523b8a97cb4SSrikar Dronamraju 152470a94089SSrikar Dronamraju if (shared_caches) 152570a94089SSrikar Dronamraju submask_fn = cpu_l2_cache_mask; 152670a94089SSrikar Dronamraju 152784dbf66cSSrikar Dronamraju if (!*mask) { 152884dbf66cSSrikar Dronamraju /* Assume only siblings are part of this CPU's coregroup */ 152984dbf66cSSrikar Dronamraju for_each_cpu(i, submask_fn(cpu)) 153084dbf66cSSrikar Dronamraju set_cpus_related(cpu, i, cpu_coregroup_mask); 153184dbf66cSSrikar Dronamraju 153284dbf66cSSrikar Dronamraju return; 153384dbf66cSSrikar Dronamraju } 153484dbf66cSSrikar Dronamraju 153584dbf66cSSrikar Dronamraju cpumask_and(*mask, cpu_online_mask, cpu_cpu_mask(cpu)); 153684dbf66cSSrikar Dronamraju 153770a94089SSrikar Dronamraju /* Update coregroup mask with all the CPUs that are part of submask */ 153870a94089SSrikar Dronamraju or_cpumasks_related(cpu, cpu, submask_fn, cpu_coregroup_mask); 153970a94089SSrikar Dronamraju 154070a94089SSrikar Dronamraju /* Skip all CPUs already part of coregroup mask */ 154184dbf66cSSrikar Dronamraju cpumask_andnot(*mask, *mask, cpu_coregroup_mask(cpu)); 154270a94089SSrikar Dronamraju 154384dbf66cSSrikar Dronamraju for_each_cpu(i, *mask) { 154470a94089SSrikar Dronamraju /* Skip all CPUs not part of this coregroup */ 154570a94089SSrikar Dronamraju if (coregroup_id == cpu_to_coregroup_id(i)) { 154670a94089SSrikar Dronamraju or_cpumasks_related(cpu, i, submask_fn, cpu_coregroup_mask); 154784dbf66cSSrikar Dronamraju cpumask_andnot(*mask, *mask, submask_fn(i)); 154870a94089SSrikar Dronamraju } else { 154984dbf66cSSrikar Dronamraju cpumask_andnot(*mask, *mask, cpu_coregroup_mask(i)); 1550b8a97cb4SSrikar Dronamraju } 1551b8a97cb4SSrikar Dronamraju } 155270a94089SSrikar Dronamraju } 1553b8a97cb4SSrikar Dronamraju 1554df52f671SOliver O'Halloran static void add_cpu_to_masks(int cpu) 1555df52f671SOliver O'Halloran { 1556c47f892dSSrikar Dronamraju struct cpumask *(*submask_fn)(int) = cpu_sibling_mask; 1557df52f671SOliver O'Halloran int first_thread = cpu_first_thread_sibling(cpu); 155884dbf66cSSrikar Dronamraju cpumask_var_t mask; 1559c1e53367SSrikar Dronamraju int chip_id = -1; 1560c47f892dSSrikar Dronamraju bool ret; 1561df52f671SOliver O'Halloran int i; 1562df52f671SOliver O'Halloran 1563df52f671SOliver O'Halloran /* 1564df52f671SOliver O'Halloran * This CPU will not be in the online mask yet so we need to manually 1565df52f671SOliver O'Halloran * add it to it's own thread sibling mask. 1566df52f671SOliver O'Halloran */ 15679a245d0eSSrikar Dronamraju map_cpu_to_node(cpu, cpu_to_node(cpu)); 1568df52f671SOliver O'Halloran cpumask_set_cpu(cpu, cpu_sibling_mask(cpu)); 1569b8b92803SSrikar Dronamraju cpumask_set_cpu(cpu, cpu_core_mask(cpu)); 1570df52f671SOliver O'Halloran 1571df52f671SOliver O'Halloran for (i = first_thread; i < first_thread + threads_per_core; i++) 1572df52f671SOliver O'Halloran if (cpu_online(i)) 1573df52f671SOliver O'Halloran set_cpus_related(i, cpu, cpu_sibling_mask); 1574df52f671SOliver O'Halloran 1575425752c6SGautham R. Shenoy add_cpu_to_smallcore_masks(cpu); 157684dbf66cSSrikar Dronamraju 157784dbf66cSSrikar Dronamraju /* In CPU-hotplug path, hence use GFP_ATOMIC */ 1578c47f892dSSrikar Dronamraju ret = alloc_cpumask_var_node(&mask, GFP_ATOMIC, cpu_to_node(cpu)); 157984dbf66cSSrikar Dronamraju update_mask_by_l2(cpu, &mask); 15802a636a56SOliver O'Halloran 1581b8a97cb4SSrikar Dronamraju if (has_coregroup_support()) 158284dbf66cSSrikar Dronamraju update_coregroup_mask(cpu, &mask); 158384dbf66cSSrikar Dronamraju 1584c1e53367SSrikar Dronamraju if (chip_id_lookup_table && ret) 1585c1e53367SSrikar Dronamraju chip_id = cpu_to_chip_id(cpu); 1586c1e53367SSrikar Dronamraju 1587c47f892dSSrikar Dronamraju if (shared_caches) 1588c47f892dSSrikar Dronamraju submask_fn = cpu_l2_cache_mask; 1589c47f892dSSrikar Dronamraju 1590c47f892dSSrikar Dronamraju /* Update core_mask with all the CPUs that are part of submask */ 1591c47f892dSSrikar Dronamraju or_cpumasks_related(cpu, cpu, submask_fn, cpu_core_mask); 1592c47f892dSSrikar Dronamraju 1593c47f892dSSrikar Dronamraju /* Skip all CPUs already part of current CPU core mask */ 1594c47f892dSSrikar Dronamraju cpumask_andnot(mask, cpu_online_mask, cpu_core_mask(cpu)); 1595c47f892dSSrikar Dronamraju 1596b8b92803SSrikar Dronamraju /* If chip_id is -1; limit the cpu_core_mask to within DIE*/ 1597b8b92803SSrikar Dronamraju if (chip_id == -1) 1598b8b92803SSrikar Dronamraju cpumask_and(mask, mask, cpu_cpu_mask(cpu)); 1599b8b92803SSrikar Dronamraju 1600c47f892dSSrikar Dronamraju for_each_cpu(i, mask) { 1601c47f892dSSrikar Dronamraju if (chip_id == cpu_to_chip_id(i)) { 1602c47f892dSSrikar Dronamraju or_cpumasks_related(cpu, i, submask_fn, cpu_core_mask); 1603c47f892dSSrikar Dronamraju cpumask_andnot(mask, mask, submask_fn(i)); 1604c47f892dSSrikar Dronamraju } else { 1605c47f892dSSrikar Dronamraju cpumask_andnot(mask, mask, cpu_core_mask(i)); 1606c47f892dSSrikar Dronamraju } 1607c47f892dSSrikar Dronamraju } 1608c47f892dSSrikar Dronamraju 160984dbf66cSSrikar Dronamraju free_cpumask_var(mask); 1610a8a5356cSPaul Mackerras } 1611a8a5356cSPaul Mackerras 16125ad57078SPaul Mackerras /* Activate a secondary processor. */ 1613061d19f2SPaul Gortmaker void start_secondary(void *unused) 16145ad57078SPaul Mackerras { 161599f070b6SQian Cai unsigned int cpu = raw_smp_processor_id(); 16165ad57078SPaul Mackerras 161786f46f34SChristophe Leroy /* PPC64 calls setup_kup() in early_setup_secondary() */ 161886f46f34SChristophe Leroy if (IS_ENABLED(CONFIG_PPC32)) 161986f46f34SChristophe Leroy setup_kup(); 162086f46f34SChristophe Leroy 1621f1f10076SVegard Nossum mmgrab(&init_mm); 16225ad57078SPaul Mackerras current->active_mm = &init_mm; 16235ad57078SPaul Mackerras 16245ad57078SPaul Mackerras smp_store_cpu_info(cpu); 16255ad57078SPaul Mackerras set_dec(tb_ticks_per_jiffy); 162699f070b6SQian Cai rcu_cpu_starting(cpu); 16271be6f10fSMichael Ellerman cpu_callin_map[cpu] = 1; 16285ad57078SPaul Mackerras 1629757cbd46SKumar Gala if (smp_ops->setup_cpu) 16305ad57078SPaul Mackerras smp_ops->setup_cpu(cpu); 16315ad57078SPaul Mackerras if (smp_ops->take_timebase) 16325ad57078SPaul Mackerras smp_ops->take_timebase(); 16335ad57078SPaul Mackerras 1634d831d0b8STony Breeds secondary_cpu_time_init(); 1635d831d0b8STony Breeds 1636aeeafbfaSBenjamin Herrenschmidt #ifdef CONFIG_PPC64 1637aeeafbfaSBenjamin Herrenschmidt if (system_state == SYSTEM_RUNNING) 1638aeeafbfaSBenjamin Herrenschmidt vdso_data->processorCount++; 163918ad51ddSAnton Blanchard 164018ad51ddSAnton Blanchard vdso_getcpu_init(); 1641aeeafbfaSBenjamin Herrenschmidt #endif 16426980d13fSSrikar Dronamraju set_numa_node(numa_cpu_lookup_table[cpu]); 16436980d13fSSrikar Dronamraju set_numa_mem(local_memory_node(numa_cpu_lookup_table[cpu])); 16446980d13fSSrikar Dronamraju 1645df52f671SOliver O'Halloran /* Update topology CPU masks */ 1646df52f671SOliver O'Halloran add_cpu_to_masks(cpu); 16475ad57078SPaul Mackerras 164896d91431SOliver O'Halloran /* 164996d91431SOliver O'Halloran * Check for any shared caches. Note that this must be done on a 165096d91431SOliver O'Halloran * per-core basis because one core in the pair might be disabled. 165196d91431SOliver O'Halloran */ 1652caa8e29dSSrikar Dronamraju if (!shared_caches) { 1653caa8e29dSSrikar Dronamraju struct cpumask *(*sibling_mask)(int) = cpu_sibling_mask; 1654caa8e29dSSrikar Dronamraju struct cpumask *mask = cpu_l2_cache_mask(cpu); 1655caa8e29dSSrikar Dronamraju 1656caa8e29dSSrikar Dronamraju if (has_big_cores) 1657caa8e29dSSrikar Dronamraju sibling_mask = cpu_smallcore_mask; 1658caa8e29dSSrikar Dronamraju 1659caa8e29dSSrikar Dronamraju if (cpumask_weight(mask) > cpumask_weight(sibling_mask(cpu))) 166096d91431SOliver O'Halloran shared_caches = true; 1661caa8e29dSSrikar Dronamraju } 166296d91431SOliver O'Halloran 1663cce606feSLi Zhong smp_wmb(); 1664cce606feSLi Zhong notify_cpu_starting(cpu); 1665cce606feSLi Zhong set_cpu_online(cpu, true); 1666cce606feSLi Zhong 1667b6aeddeaSMichael Ellerman boot_init_stack_canary(); 1668b6aeddeaSMichael Ellerman 16695ad57078SPaul Mackerras local_irq_enable(); 16705ad57078SPaul Mackerras 1671d1039786SNaveen N. Rao /* We can enable ftrace for secondary cpus now */ 1672d1039786SNaveen N. Rao this_cpu_enable_ftrace(); 1673d1039786SNaveen N. Rao 1674fc6d73d6SThomas Gleixner cpu_startup_entry(CPUHP_AP_ONLINE_IDLE); 1675fa3f82c8SBenjamin Herrenschmidt 1676fa3f82c8SBenjamin Herrenschmidt BUG(); 16775ad57078SPaul Mackerras } 16785ad57078SPaul Mackerras 1679a4ac0d24SMichael Ellerman #ifdef CONFIG_PROFILING 16805ad57078SPaul Mackerras int setup_profiling_timer(unsigned int multiplier) 16815ad57078SPaul Mackerras { 16825ad57078SPaul Mackerras return 0; 16835ad57078SPaul Mackerras } 1684a4ac0d24SMichael Ellerman #endif 16855ad57078SPaul Mackerras 1686*d276960dSNick Child static void __init fixup_topology(void) 16873c6032a8SSrikar Dronamraju { 1688375370a1SSrikar Dronamraju int i; 1689375370a1SSrikar Dronamraju 16903c6032a8SSrikar Dronamraju #ifdef CONFIG_SCHED_SMT 16913c6032a8SSrikar Dronamraju if (has_big_cores) { 16923c6032a8SSrikar Dronamraju pr_info("Big cores detected but using small core scheduling\n"); 169372730bfcSSrikar Dronamraju powerpc_topology[smt_idx].mask = smallcore_smt_mask; 16943c6032a8SSrikar Dronamraju } 16953c6032a8SSrikar Dronamraju #endif 169672730bfcSSrikar Dronamraju 169772730bfcSSrikar Dronamraju if (!has_coregroup_support()) 169872730bfcSSrikar Dronamraju powerpc_topology[mc_idx].mask = powerpc_topology[cache_idx].mask; 1699375370a1SSrikar Dronamraju 1700375370a1SSrikar Dronamraju /* 1701375370a1SSrikar Dronamraju * Try to consolidate topology levels here instead of 1702375370a1SSrikar Dronamraju * allowing scheduler to degenerate. 1703375370a1SSrikar Dronamraju * - Dont consolidate if masks are different. 1704375370a1SSrikar Dronamraju * - Dont consolidate if sd_flags exists and are different. 1705375370a1SSrikar Dronamraju */ 1706375370a1SSrikar Dronamraju for (i = 1; i <= die_idx; i++) { 1707375370a1SSrikar Dronamraju if (powerpc_topology[i].mask != powerpc_topology[i - 1].mask) 1708375370a1SSrikar Dronamraju continue; 1709375370a1SSrikar Dronamraju 1710375370a1SSrikar Dronamraju if (powerpc_topology[i].sd_flags && powerpc_topology[i - 1].sd_flags && 1711375370a1SSrikar Dronamraju powerpc_topology[i].sd_flags != powerpc_topology[i - 1].sd_flags) 1712375370a1SSrikar Dronamraju continue; 1713375370a1SSrikar Dronamraju 1714375370a1SSrikar Dronamraju if (!powerpc_topology[i - 1].sd_flags) 1715375370a1SSrikar Dronamraju powerpc_topology[i - 1].sd_flags = powerpc_topology[i].sd_flags; 1716375370a1SSrikar Dronamraju 1717375370a1SSrikar Dronamraju powerpc_topology[i].mask = powerpc_topology[i + 1].mask; 1718375370a1SSrikar Dronamraju powerpc_topology[i].sd_flags = powerpc_topology[i + 1].sd_flags; 1719375370a1SSrikar Dronamraju #ifdef CONFIG_SCHED_DEBUG 1720375370a1SSrikar Dronamraju powerpc_topology[i].name = powerpc_topology[i + 1].name; 1721375370a1SSrikar Dronamraju #endif 1722375370a1SSrikar Dronamraju } 17233c6032a8SSrikar Dronamraju } 17243c6032a8SSrikar Dronamraju 17255ad57078SPaul Mackerras void __init smp_cpus_done(unsigned int max_cpus) 17265ad57078SPaul Mackerras { 17276d11b87dSThomas Gleixner /* 17287b7622bbSMichael Ellerman * We are running pinned to the boot CPU, see rest_init(). 17295ad57078SPaul Mackerras */ 1730757cbd46SKumar Gala if (smp_ops && smp_ops->setup_cpu) 17317b7622bbSMichael Ellerman smp_ops->setup_cpu(boot_cpuid); 17324b703a23SAnton Blanchard 1733d7294445SBenjamin Herrenschmidt if (smp_ops && smp_ops->bringup_done) 1734d7294445SBenjamin Herrenschmidt smp_ops->bringup_done(); 1735d7294445SBenjamin Herrenschmidt 17364b703a23SAnton Blanchard dump_numa_cpu_topology(); 1737d7294445SBenjamin Herrenschmidt 17383c6032a8SSrikar Dronamraju fixup_topology(); 1739607b45e9SVincent Guittot set_sched_topology(powerpc_topology); 1740e1f0ece1SMichael Neuling } 1741e1f0ece1SMichael Neuling 17425ad57078SPaul Mackerras #ifdef CONFIG_HOTPLUG_CPU 17435ad57078SPaul Mackerras int __cpu_disable(void) 17445ad57078SPaul Mackerras { 1745e2075f79SNathan Lynch int cpu = smp_processor_id(); 1746e2075f79SNathan Lynch int err; 17475ad57078SPaul Mackerras 1748e2075f79SNathan Lynch if (!smp_ops->cpu_disable) 17495ad57078SPaul Mackerras return -ENOSYS; 1750e2075f79SNathan Lynch 1751424ef016SNaveen N. Rao this_cpu_disable_ftrace(); 1752424ef016SNaveen N. Rao 1753e2075f79SNathan Lynch err = smp_ops->cpu_disable(); 1754e2075f79SNathan Lynch if (err) 1755e2075f79SNathan Lynch return err; 1756e2075f79SNathan Lynch 1757e2075f79SNathan Lynch /* Update sibling maps */ 1758df52f671SOliver O'Halloran remove_cpu_from_masks(cpu); 1759440a0857SNathan Lynch 1760e2075f79SNathan Lynch return 0; 17615ad57078SPaul Mackerras } 17625ad57078SPaul Mackerras 17635ad57078SPaul Mackerras void __cpu_die(unsigned int cpu) 17645ad57078SPaul Mackerras { 17655ad57078SPaul Mackerras if (smp_ops->cpu_die) 17665ad57078SPaul Mackerras smp_ops->cpu_die(cpu); 17675ad57078SPaul Mackerras } 1768d0174c72SNathan Fontenot 17691ea21ba2SMichael Ellerman void arch_cpu_idle_dead(void) 17701ea21ba2SMichael Ellerman { 1771424ef016SNaveen N. Rao /* 1772424ef016SNaveen N. Rao * Disable on the down path. This will be re-enabled by 1773424ef016SNaveen N. Rao * start_secondary() via start_secondary_resume() below 1774424ef016SNaveen N. Rao */ 1775424ef016SNaveen N. Rao this_cpu_disable_ftrace(); 1776424ef016SNaveen N. Rao 177739f87561SMichael Ellerman if (smp_ops->cpu_offline_self) 177839f87561SMichael Ellerman smp_ops->cpu_offline_self(); 1779fa3f82c8SBenjamin Herrenschmidt 1780fa3f82c8SBenjamin Herrenschmidt /* If we return, we re-enter start_secondary */ 1781fa3f82c8SBenjamin Herrenschmidt start_secondary_resume(); 1782abb17f9cSMilton Miller } 1783fa3f82c8SBenjamin Herrenschmidt 17845ad57078SPaul Mackerras #endif 1785