xref: /openbmc/linux/arch/x86/kernel/cpu/topology.c (revision 6c4f5aba)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
22decb194SH. Peter Anvin /*
32decb194SH. Peter Anvin  * Check for extended topology enumeration cpuid leaf 0xb and if it
42decb194SH. Peter Anvin  * exists, use it for populating initial_apicid and cpu topology
52decb194SH. Peter Anvin  * detection.
62decb194SH. Peter Anvin  */
72decb194SH. Peter Anvin 
82decb194SH. Peter Anvin #include <linux/cpu.h>
92decb194SH. Peter Anvin #include <asm/apic.h>
102decb194SH. Peter Anvin #include <asm/pat.h>
112decb194SH. Peter Anvin #include <asm/processor.h>
122decb194SH. Peter Anvin 
132decb194SH. Peter Anvin /* leaf 0xb SMT level */
142decb194SH. Peter Anvin #define SMT_LEVEL	0
152decb194SH. Peter Anvin 
162decb194SH. Peter Anvin /* leaf 0xb sub-leaf types */
172decb194SH. Peter Anvin #define INVALID_TYPE	0
182decb194SH. Peter Anvin #define SMT_TYPE	1
192decb194SH. Peter Anvin #define CORE_TYPE	2
202decb194SH. Peter Anvin 
212decb194SH. Peter Anvin #define LEAFB_SUBTYPE(ecx)		(((ecx) >> 8) & 0xff)
222decb194SH. Peter Anvin #define BITS_SHIFT_NEXT_LEVEL(eax)	((eax) & 0x1f)
232decb194SH. Peter Anvin #define LEVEL_MAX_SIBLINGS(ebx)		((ebx) & 0xffff)
242decb194SH. Peter Anvin 
252decb194SH. Peter Anvin /*
262decb194SH. Peter Anvin  * Check for extended topology enumeration cpuid leaf 0xb and if it
272decb194SH. Peter Anvin  * exists, use it for populating initial_apicid and cpu topology
282decb194SH. Peter Anvin  * detection.
292decb194SH. Peter Anvin  */
306c4f5abaSSuravee Suthikulpanit int detect_extended_topology(struct cpuinfo_x86 *c)
312decb194SH. Peter Anvin {
322decb194SH. Peter Anvin #ifdef CONFIG_SMP
332decb194SH. Peter Anvin 	unsigned int eax, ebx, ecx, edx, sub_index;
342decb194SH. Peter Anvin 	unsigned int ht_mask_width, core_plus_mask_width;
352decb194SH. Peter Anvin 	unsigned int core_select_mask, core_level_siblings;
362decb194SH. Peter Anvin 	static bool printed;
372decb194SH. Peter Anvin 
382decb194SH. Peter Anvin 	if (c->cpuid_level < 0xb)
396c4f5abaSSuravee Suthikulpanit 		return -1;
402decb194SH. Peter Anvin 
412decb194SH. Peter Anvin 	cpuid_count(0xb, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
422decb194SH. Peter Anvin 
432decb194SH. Peter Anvin 	/*
442decb194SH. Peter Anvin 	 * check if the cpuid leaf 0xb is actually implemented.
452decb194SH. Peter Anvin 	 */
462decb194SH. Peter Anvin 	if (ebx == 0 || (LEAFB_SUBTYPE(ecx) != SMT_TYPE))
476c4f5abaSSuravee Suthikulpanit 		return -1;
482decb194SH. Peter Anvin 
492decb194SH. Peter Anvin 	set_cpu_cap(c, X86_FEATURE_XTOPOLOGY);
502decb194SH. Peter Anvin 
512decb194SH. Peter Anvin 	/*
522decb194SH. Peter Anvin 	 * initial apic id, which also represents 32-bit extended x2apic id.
532decb194SH. Peter Anvin 	 */
542decb194SH. Peter Anvin 	c->initial_apicid = edx;
552decb194SH. Peter Anvin 
562decb194SH. Peter Anvin 	/*
572decb194SH. Peter Anvin 	 * Populate HT related information from sub-leaf level 0.
582decb194SH. Peter Anvin 	 */
592decb194SH. Peter Anvin 	core_level_siblings = smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx);
602decb194SH. Peter Anvin 	core_plus_mask_width = ht_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
612decb194SH. Peter Anvin 
622decb194SH. Peter Anvin 	sub_index = 1;
632decb194SH. Peter Anvin 	do {
642decb194SH. Peter Anvin 		cpuid_count(0xb, sub_index, &eax, &ebx, &ecx, &edx);
652decb194SH. Peter Anvin 
662decb194SH. Peter Anvin 		/*
672decb194SH. Peter Anvin 		 * Check for the Core type in the implemented sub leaves.
682decb194SH. Peter Anvin 		 */
692decb194SH. Peter Anvin 		if (LEAFB_SUBTYPE(ecx) == CORE_TYPE) {
702decb194SH. Peter Anvin 			core_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
712decb194SH. Peter Anvin 			core_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
722decb194SH. Peter Anvin 			break;
732decb194SH. Peter Anvin 		}
742decb194SH. Peter Anvin 
752decb194SH. Peter Anvin 		sub_index++;
762decb194SH. Peter Anvin 	} while (LEAFB_SUBTYPE(ecx) != INVALID_TYPE);
772decb194SH. Peter Anvin 
782decb194SH. Peter Anvin 	core_select_mask = (~(-1 << core_plus_mask_width)) >> ht_mask_width;
792decb194SH. Peter Anvin 
802decb194SH. Peter Anvin 	c->cpu_core_id = apic->phys_pkg_id(c->initial_apicid, ht_mask_width)
812decb194SH. Peter Anvin 						 & core_select_mask;
822decb194SH. Peter Anvin 	c->phys_proc_id = apic->phys_pkg_id(c->initial_apicid, core_plus_mask_width);
832decb194SH. Peter Anvin 	/*
842decb194SH. Peter Anvin 	 * Reinit the apicid, now that we have extended initial_apicid.
852decb194SH. Peter Anvin 	 */
862decb194SH. Peter Anvin 	c->apicid = apic->phys_pkg_id(c->initial_apicid, 0);
872decb194SH. Peter Anvin 
882decb194SH. Peter Anvin 	c->x86_max_cores = (core_level_siblings / smp_num_siblings);
892decb194SH. Peter Anvin 
902decb194SH. Peter Anvin 	if (!printed) {
911b74dde7SChen Yucong 		pr_info("CPU: Physical Processor ID: %d\n",
922decb194SH. Peter Anvin 		       c->phys_proc_id);
932decb194SH. Peter Anvin 		if (c->x86_max_cores > 1)
941b74dde7SChen Yucong 			pr_info("CPU: Processor Core ID: %d\n",
952decb194SH. Peter Anvin 			       c->cpu_core_id);
962decb194SH. Peter Anvin 		printed = 1;
972decb194SH. Peter Anvin 	}
982decb194SH. Peter Anvin #endif
996c4f5abaSSuravee Suthikulpanit 	return 0;
1002decb194SH. Peter Anvin }
101