···555555 ================ =========================================556556 "on" SMT is enabled557557 "off" SMT is disabled558558+ "<N>" SMT is enabled with N threads per core.558559 "forceoff" SMT is force disabled. Cannot be changed.559560 "notsupported" SMT is not supported by the CPU560561 "notimplemented" SMT runtime toggling is not
+2-2
Documentation/admin-guide/kernel-parameters.txt
···38533853 nosmp [SMP] Tells an SMP kernel to act as a UP kernel,38543854 and disable the IO APIC. legacy for "maxcpus=0".3855385538563856- nosmt [KNL,MIPS,S390] Disable symmetric multithreading (SMT).38563856+ nosmt [KNL,MIPS,PPC,S390] Disable symmetric multithreading (SMT).38573857 Equivalent to smt=1.3858385838593859- [KNL,X86] Disable symmetric multithreading (SMT).38593859+ [KNL,X86,PPC] Disable symmetric multithreading (SMT).38603860 nosmt=force: Force disable SMT, cannot be undone38613861 via the sysfs control file.38623862
+3
arch/Kconfig
···3434config HOTPLUG_SMT3535 bool36363737+config SMT_NUM_THREADS_DYNAMIC3838+ bool3939+3740# Selected by HOTPLUG_CORE_SYNC_DEAD or HOTPLUG_CORE_SYNC_FULL3841config HOTPLUG_CORE_SYNC3942 bool
+2
arch/powerpc/Kconfig
···272272 select HAVE_SYSCALL_TRACEPOINTS273273 select HAVE_VIRT_CPU_ACCOUNTING274274 select HAVE_VIRT_CPU_ACCOUNTING_GEN275275+ select HOTPLUG_SMT if HOTPLUG_CPU276276+ select SMT_NUM_THREADS_DYNAMIC275277 select HUGETLB_PAGE_SIZE_VARIABLE if PPC_BOOK3S_64 && HUGETLB_PAGE276278 select IOMMU_HELPER if PPC64277279 select IRQ_DOMAIN
+15
arch/powerpc/include/asm/topology.h
···143143#endif144144#endif145145146146+#ifdef CONFIG_HOTPLUG_SMT147147+#include <linux/cpu_smt.h>148148+#include <asm/cputhreads.h>149149+150150+static inline bool topology_is_primary_thread(unsigned int cpu)151151+{152152+ return cpu == cpu_first_thread_sibling(cpu);153153+}154154+155155+static inline bool topology_smt_thread_allowed(unsigned int cpu)156156+{157157+ return cpu_thread_in_core(cpu) < cpu_smt_num_threads;158158+}159159+#endif160160+146161#endif /* __KERNEL__ */147162#endif /* _ASM_POWERPC_TOPOLOGY_H */
+7-1
arch/powerpc/kernel/smp.c
···1088108810891089void __init smp_prepare_cpus(unsigned int max_cpus)10901090{10911091- unsigned int cpu;10911091+ unsigned int cpu, num_threads;1092109210931093 DBG("smp_prepare_cpus\n");10941094···1155115511561156 if (smp_ops && smp_ops->probe)11571157 smp_ops->probe();11581158+11591159+ // Initalise the generic SMT topology support11601160+ num_threads = 1;11611161+ if (smt_enabled_at_boot)11621162+ num_threads = smt_enabled_at_boot;11631163+ cpu_smt_set_num_threads(num_threads, threads_per_core);11581164}1159116511601166void smp_prepare_boot_cpu(void)
+21-9
arch/powerpc/platforms/pseries/hotplug-cpu.c
···398398 for_each_present_cpu(cpu) {399399 if (get_hard_smp_processor_id(cpu) != thread)400400 continue;401401+402402+ if (!topology_is_primary_thread(cpu)) {403403+ if (cpu_smt_control != CPU_SMT_ENABLED)404404+ break;405405+ if (!topology_smt_thread_allowed(cpu))406406+ break;407407+ }408408+401409 cpu_maps_update_done();402410 find_and_update_cpu_nid(cpu);403411 rc = device_online(get_cpu_device(cpu));···853845 .notifier_call = pseries_smp_notifier,854846};855847856856-static int __init pseries_cpu_hotplug_init(void)848848+void __init pseries_cpu_hotplug_init(void)857849{858850 int qcss_tok;859859- unsigned int node;860860-861861-#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE862862- ppc_md.cpu_probe = dlpar_cpu_probe;863863- ppc_md.cpu_release = dlpar_cpu_release;864864-#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */865851866852 rtas_stop_self_token = rtas_function_token(RTAS_FN_STOP_SELF);867853 qcss_tok = rtas_function_token(RTAS_FN_QUERY_CPU_STOPPED_STATE);···864862 qcss_tok == RTAS_UNKNOWN_SERVICE) {865863 printk(KERN_INFO "CPU Hotplug not supported by firmware "866864 "- disabling.\n");867867- return 0;865865+ return;868866 }869867870868 smp_ops->cpu_offline_self = pseries_cpu_offline_self;871869 smp_ops->cpu_disable = pseries_cpu_disable;872870 smp_ops->cpu_die = pseries_cpu_die;871871+}872872+873873+static int __init pseries_dlpar_init(void)874874+{875875+ unsigned int node;876876+877877+#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE878878+ ppc_md.cpu_probe = dlpar_cpu_probe;879879+ ppc_md.cpu_release = dlpar_cpu_release;880880+#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */873881874882 /* Processors can be added/removed only on LPAR */875883 if (firmware_has_feature(FW_FEATURE_LPAR)) {···898886899887 return 0;900888}901901-machine_arch_initcall(pseries, pseries_cpu_hotplug_init);889889+machine_arch_initcall(pseries, pseries_dlpar_init);
+2
arch/powerpc/platforms/pseries/pseries.h
···75757676#ifdef CONFIG_HOTPLUG_CPU7777int dlpar_cpu(struct pseries_hp_errorlog *hp_elog);7878+void pseries_cpu_hotplug_init(void);7879#else7980static inline int dlpar_cpu(struct pseries_hp_errorlog *hp_elog)8081{8182 return -EOPNOTSUPP;8283}8484+static inline void pseries_cpu_hotplug_init(void) { }8385#endif84868587/* PCI root bridge prepare function override for pseries */
+2
arch/powerpc/platforms/pseries/setup.c
···816816 /* Discover PIC type and setup ppc_md accordingly */817817 smp_init_pseries();818818819819+ // Setup CPU hotplug callbacks820820+ pseries_cpu_hotplug_init();819821820822 if (radix_enabled() && !mmu_has_feature(MMU_FTR_GTSE))821823 if (!firmware_has_feature(FW_FEATURE_RPT_INVALIDATE))
+2-2
arch/x86/include/asm/topology.h
···136136 return __max_smt_threads;137137}138138139139+#include <linux/cpu_smt.h>140140+139141int topology_update_package_map(unsigned int apicid, unsigned int cpu);140142int topology_update_die_map(unsigned int dieid, unsigned int cpu);141143int topology_phys_to_logical_pkg(unsigned int pkg);142142-bool topology_smt_supported(void);143144144145extern struct cpumask __cpu_primary_thread_mask;145146#define cpu_primary_thread_mask ((const struct cpumask *)&__cpu_primary_thread_mask)···163162static inline int topology_max_die_per_package(void) { return 1; }164163static inline int topology_max_smt_threads(void) { return 1; }165164static inline bool topology_is_primary_thread(unsigned int cpu) { return true; }166166-static inline bool topology_smt_supported(void) { return false; }167165#endif /* !CONFIG_SMP */168166169167static inline void arch_fix_phys_package_id(int num, u32 slot)
+1-1
arch/x86/kernel/cpu/common.c
···23172317 * identify_boot_cpu() initialized SMT support information, let the23182318 * core code know.23192319 */23202320- cpu_smt_check_topology();23202320+ cpu_smt_set_num_threads(smp_num_siblings, smp_num_siblings);2321232123222322 if (!IS_ENABLED(CONFIG_SMP)) {23232323 pr_info("CPU: ");
-8
arch/x86/kernel/smpboot.c
···327327}328328329329/**330330- * topology_smt_supported - Check whether SMT is supported by the CPUs331331- */332332-bool topology_smt_supported(void)333333-{334334- return smp_num_siblings > 1;335335-}336336-337337-/**338330 * topology_phys_to_logical_pkg - Map a physical package id to a logical339331 * @phys_pkg: The physical package id to map340332 *
···11+/* SPDX-License-Identifier: GPL-2.0 */22+#ifndef _LINUX_CPU_SMT_H_33+#define _LINUX_CPU_SMT_H_44+55+enum cpuhp_smt_control {66+ CPU_SMT_ENABLED,77+ CPU_SMT_DISABLED,88+ CPU_SMT_FORCE_DISABLED,99+ CPU_SMT_NOT_SUPPORTED,1010+ CPU_SMT_NOT_IMPLEMENTED,1111+};1212+1313+#if defined(CONFIG_SMP) && defined(CONFIG_HOTPLUG_SMT)1414+extern enum cpuhp_smt_control cpu_smt_control;1515+extern unsigned int cpu_smt_num_threads;1616+extern void cpu_smt_disable(bool force);1717+extern void cpu_smt_set_num_threads(unsigned int num_threads,1818+ unsigned int max_threads);1919+extern bool cpu_smt_possible(void);2020+extern int cpuhp_smt_enable(void);2121+extern int cpuhp_smt_disable(enum cpuhp_smt_control ctrlval);2222+#else2323+# define cpu_smt_control (CPU_SMT_NOT_IMPLEMENTED)2424+# define cpu_smt_num_threads 12525+static inline void cpu_smt_disable(bool force) { }2626+static inline void cpu_smt_set_num_threads(unsigned int num_threads,2727+ unsigned int max_threads) { }2828+static inline bool cpu_smt_possible(void) { return false; }2929+static inline int cpuhp_smt_enable(void) { return 0; }3030+static inline int cpuhp_smt_disable(enum cpuhp_smt_control ctrlval) { return 0; }3131+#endif3232+3333+#endif /* _LINUX_CPU_SMT_H_ */
+104-38
kernel/cpu.c
···592592void __weak arch_smt_update(void) { }593593594594#ifdef CONFIG_HOTPLUG_SMT595595+595596enum cpuhp_smt_control cpu_smt_control __read_mostly = CPU_SMT_ENABLED;597597+static unsigned int cpu_smt_max_threads __ro_after_init;598598+unsigned int cpu_smt_num_threads __read_mostly = UINT_MAX;596599597600void __init cpu_smt_disable(bool force)598601{···609606 pr_info("SMT: disabled\n");610607 cpu_smt_control = CPU_SMT_DISABLED;611608 }609609+ cpu_smt_num_threads = 1;612610}613611614612/*615613 * The decision whether SMT is supported can only be done after the full616614 * CPU identification. Called from architecture code.617615 */618618-void __init cpu_smt_check_topology(void)616616+void __init cpu_smt_set_num_threads(unsigned int num_threads,617617+ unsigned int max_threads)619618{620620- if (!topology_smt_supported())619619+ WARN_ON(!num_threads || (num_threads > max_threads));620620+621621+ if (max_threads == 1)621622 cpu_smt_control = CPU_SMT_NOT_SUPPORTED;623623+624624+ cpu_smt_max_threads = max_threads;625625+626626+ /*627627+ * If SMT has been disabled via the kernel command line or SMT is628628+ * not supported, set cpu_smt_num_threads to 1 for consistency.629629+ * If enabled, take the architecture requested number of threads630630+ * to bring up into account.631631+ */632632+ if (cpu_smt_control != CPU_SMT_ENABLED)633633+ cpu_smt_num_threads = 1;634634+ else if (num_threads < cpu_smt_num_threads)635635+ cpu_smt_num_threads = num_threads;622636}623637624638static int __init smt_cmdline_disable(char *str)···645625}646626early_param("nosmt", smt_cmdline_disable);647627628628+/*629629+ * For Archicture supporting partial SMT states check if the thread is allowed.630630+ * Otherwise this has already been checked through cpu_smt_max_threads when631631+ * setting the SMT level.632632+ */633633+static inline bool cpu_smt_thread_allowed(unsigned int cpu)634634+{635635+#ifdef CONFIG_SMT_NUM_THREADS_DYNAMIC636636+ return topology_smt_thread_allowed(cpu);637637+#else638638+ return true;639639+#endif640640+}641641+648642static inline bool cpu_smt_allowed(unsigned int cpu)649643{650650- if (cpu_smt_control == CPU_SMT_ENABLED)644644+ if (cpu_smt_control == CPU_SMT_ENABLED && cpu_smt_thread_allowed(cpu))651645 return true;652646653647 if (topology_is_primary_thread(cpu))···684650}685651EXPORT_SYMBOL_GPL(cpu_smt_possible);686652687687-static inline bool cpuhp_smt_aware(void)688688-{689689- return topology_smt_supported();690690-}691691-692692-static inline const struct cpumask *cpuhp_get_primary_thread_mask(void)693693-{694694- return cpu_primary_thread_mask;695695-}696653#else697654static inline bool cpu_smt_allowed(unsigned int cpu) { return true; }698698-static inline bool cpuhp_smt_aware(void) { return false; }699699-static inline const struct cpumask *cpuhp_get_primary_thread_mask(void)700700-{701701- return cpu_present_mask;702702-}703655#endif704656705657static inline enum cpuhp_state···18131793}18141794early_param("cpuhp.parallel", parallel_bringup_parse_param);1815179517961796+static inline bool cpuhp_smt_aware(void)17971797+{17981798+ return cpu_smt_max_threads > 1;17991799+}18001800+18011801+static inline const struct cpumask *cpuhp_get_primary_thread_mask(void)18021802+{18031803+ return cpu_primary_thread_mask;18041804+}18051805+18161806/*18171807 * On architectures which have enabled parallel bringup this invokes all BP18181808 * prepare states for each of the to be onlined APs first. The last state···26562626 for_each_online_cpu(cpu) {26572627 if (topology_is_primary_thread(cpu))26582628 continue;26292629+ /*26302630+ * Disable can be called with CPU_SMT_ENABLED when changing26312631+ * from a higher to lower number of SMT threads per core.26322632+ */26332633+ if (ctrlval == CPU_SMT_ENABLED && cpu_smt_thread_allowed(cpu))26342634+ continue;26592635 ret = cpu_down_maps_locked(cpu, CPUHP_OFFLINE);26602636 if (ret)26612637 break;···26952659 for_each_present_cpu(cpu) {26962660 /* Skip online CPUs and CPUs on offline nodes */26972661 if (cpu_online(cpu) || !node_online(cpu_to_node(cpu)))26622662+ continue;26632663+ if (!cpu_smt_thread_allowed(cpu))26982664 continue;26992665 ret = _cpu_up(cpu, 0, CPUHP_ONLINE);27002666 if (ret)···2876283828772839#ifdef CONFIG_HOTPLUG_SMT2878284028412841+static bool cpu_smt_num_threads_valid(unsigned int threads)28422842+{28432843+ if (IS_ENABLED(CONFIG_SMT_NUM_THREADS_DYNAMIC))28442844+ return threads >= 1 && threads <= cpu_smt_max_threads;28452845+ return threads == 1 || threads == cpu_smt_max_threads;28462846+}28472847+28792848static ssize_t28802849__store_smt_control(struct device *dev, struct device_attribute *attr,28812850 const char *buf, size_t count)28822851{28832883- int ctrlval, ret;28842884-28852885- if (sysfs_streq(buf, "on"))28862886- ctrlval = CPU_SMT_ENABLED;28872887- else if (sysfs_streq(buf, "off"))28882888- ctrlval = CPU_SMT_DISABLED;28892889- else if (sysfs_streq(buf, "forceoff"))28902890- ctrlval = CPU_SMT_FORCE_DISABLED;28912891- else28922892- return -EINVAL;28522852+ int ctrlval, ret, num_threads, orig_threads;28532853+ bool force_off;2893285428942855 if (cpu_smt_control == CPU_SMT_FORCE_DISABLED)28952856 return -EPERM;···28962859 if (cpu_smt_control == CPU_SMT_NOT_SUPPORTED)28972860 return -ENODEV;2898286128622862+ if (sysfs_streq(buf, "on")) {28632863+ ctrlval = CPU_SMT_ENABLED;28642864+ num_threads = cpu_smt_max_threads;28652865+ } else if (sysfs_streq(buf, "off")) {28662866+ ctrlval = CPU_SMT_DISABLED;28672867+ num_threads = 1;28682868+ } else if (sysfs_streq(buf, "forceoff")) {28692869+ ctrlval = CPU_SMT_FORCE_DISABLED;28702870+ num_threads = 1;28712871+ } else if (kstrtoint(buf, 10, &num_threads) == 0) {28722872+ if (num_threads == 1)28732873+ ctrlval = CPU_SMT_DISABLED;28742874+ else if (cpu_smt_num_threads_valid(num_threads))28752875+ ctrlval = CPU_SMT_ENABLED;28762876+ else28772877+ return -EINVAL;28782878+ } else {28792879+ return -EINVAL;28802880+ }28812881+28992882 ret = lock_device_hotplug_sysfs();29002883 if (ret)29012884 return ret;2902288529032903- if (ctrlval != cpu_smt_control) {29042904- switch (ctrlval) {29052905- case CPU_SMT_ENABLED:29062906- ret = cpuhp_smt_enable();29072907- break;29082908- case CPU_SMT_DISABLED:29092909- case CPU_SMT_FORCE_DISABLED:29102910- ret = cpuhp_smt_disable(ctrlval);29112911- break;29122912- }29132913- }28862886+ orig_threads = cpu_smt_num_threads;28872887+ cpu_smt_num_threads = num_threads;28882888+28892889+ force_off = ctrlval != cpu_smt_control && ctrlval == CPU_SMT_FORCE_DISABLED;28902890+28912891+ if (num_threads > orig_threads)28922892+ ret = cpuhp_smt_enable();28932893+ else if (num_threads < orig_threads || force_off)28942894+ ret = cpuhp_smt_disable(ctrlval);2914289529152896 unlock_device_hotplug();29162897 return ret ? ret : count;···29552900 struct device_attribute *attr, char *buf)29562901{29572902 const char *state = smt_states[cpu_smt_control];29032903+29042904+#ifdef CONFIG_HOTPLUG_SMT29052905+ /*29062906+ * If SMT is enabled but not all threads are enabled then show the29072907+ * number of threads. If all threads are enabled show "on". Otherwise29082908+ * show the state name.29092909+ */29102910+ if (cpu_smt_control == CPU_SMT_ENABLED &&29112911+ cpu_smt_num_threads != cpu_smt_max_threads)29122912+ return sysfs_emit(buf, "%d\n", cpu_smt_num_threads);29132913+#endif2958291429592915 return snprintf(buf, PAGE_SIZE - 2, "%s\n", state);29602916}