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