cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

topology.c (4149B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Check for extended topology enumeration cpuid leaf 0xb and if it
      4 * exists, use it for populating initial_apicid and cpu topology
      5 * detection.
      6 */
      7
      8#include <linux/cpu.h>
      9#include <asm/apic.h>
     10#include <asm/memtype.h>
     11#include <asm/processor.h>
     12
     13#include "cpu.h"
     14
     15/* leaf 0xb SMT level */
     16#define SMT_LEVEL	0
     17
     18/* extended topology sub-leaf types */
     19#define INVALID_TYPE	0
     20#define SMT_TYPE	1
     21#define CORE_TYPE	2
     22#define DIE_TYPE	5
     23
     24#define LEAFB_SUBTYPE(ecx)		(((ecx) >> 8) & 0xff)
     25#define BITS_SHIFT_NEXT_LEVEL(eax)	((eax) & 0x1f)
     26#define LEVEL_MAX_SIBLINGS(ebx)		((ebx) & 0xffff)
     27
     28unsigned int __max_die_per_package __read_mostly = 1;
     29EXPORT_SYMBOL(__max_die_per_package);
     30
     31#ifdef CONFIG_SMP
     32/*
     33 * Check if given CPUID extended topology "leaf" is implemented
     34 */
     35static int check_extended_topology_leaf(int leaf)
     36{
     37	unsigned int eax, ebx, ecx, edx;
     38
     39	cpuid_count(leaf, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
     40
     41	if (ebx == 0 || (LEAFB_SUBTYPE(ecx) != SMT_TYPE))
     42		return -1;
     43
     44	return 0;
     45}
     46/*
     47 * Return best CPUID Extended Topology Leaf supported
     48 */
     49static int detect_extended_topology_leaf(struct cpuinfo_x86 *c)
     50{
     51	if (c->cpuid_level >= 0x1f) {
     52		if (check_extended_topology_leaf(0x1f) == 0)
     53			return 0x1f;
     54	}
     55
     56	if (c->cpuid_level >= 0xb) {
     57		if (check_extended_topology_leaf(0xb) == 0)
     58			return 0xb;
     59	}
     60
     61	return -1;
     62}
     63#endif
     64
     65int detect_extended_topology_early(struct cpuinfo_x86 *c)
     66{
     67#ifdef CONFIG_SMP
     68	unsigned int eax, ebx, ecx, edx;
     69	int leaf;
     70
     71	leaf = detect_extended_topology_leaf(c);
     72	if (leaf < 0)
     73		return -1;
     74
     75	set_cpu_cap(c, X86_FEATURE_XTOPOLOGY);
     76
     77	cpuid_count(leaf, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
     78	/*
     79	 * initial apic id, which also represents 32-bit extended x2apic id.
     80	 */
     81	c->initial_apicid = edx;
     82	smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx);
     83#endif
     84	return 0;
     85}
     86
     87/*
     88 * Check for extended topology enumeration cpuid leaf, and if it
     89 * exists, use it for populating initial_apicid and cpu topology
     90 * detection.
     91 */
     92int detect_extended_topology(struct cpuinfo_x86 *c)
     93{
     94#ifdef CONFIG_SMP
     95	unsigned int eax, ebx, ecx, edx, sub_index;
     96	unsigned int ht_mask_width, core_plus_mask_width, die_plus_mask_width;
     97	unsigned int core_select_mask, core_level_siblings;
     98	unsigned int die_select_mask, die_level_siblings;
     99	bool die_level_present = false;
    100	int leaf;
    101
    102	leaf = detect_extended_topology_leaf(c);
    103	if (leaf < 0)
    104		return -1;
    105
    106	/*
    107	 * Populate HT related information from sub-leaf level 0.
    108	 */
    109	cpuid_count(leaf, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
    110	c->initial_apicid = edx;
    111	core_level_siblings = smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx);
    112	core_plus_mask_width = ht_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
    113	die_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
    114	die_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
    115
    116	sub_index = 1;
    117	do {
    118		cpuid_count(leaf, sub_index, &eax, &ebx, &ecx, &edx);
    119
    120		/*
    121		 * Check for the Core type in the implemented sub leaves.
    122		 */
    123		if (LEAFB_SUBTYPE(ecx) == CORE_TYPE) {
    124			core_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
    125			core_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
    126			die_level_siblings = core_level_siblings;
    127			die_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
    128		}
    129		if (LEAFB_SUBTYPE(ecx) == DIE_TYPE) {
    130			die_level_present = true;
    131			die_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
    132			die_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
    133		}
    134
    135		sub_index++;
    136	} while (LEAFB_SUBTYPE(ecx) != INVALID_TYPE);
    137
    138	core_select_mask = (~(-1 << core_plus_mask_width)) >> ht_mask_width;
    139	die_select_mask = (~(-1 << die_plus_mask_width)) >>
    140				core_plus_mask_width;
    141
    142	c->cpu_core_id = apic->phys_pkg_id(c->initial_apicid,
    143				ht_mask_width) & core_select_mask;
    144
    145	if (die_level_present) {
    146		c->cpu_die_id = apic->phys_pkg_id(c->initial_apicid,
    147					core_plus_mask_width) & die_select_mask;
    148	}
    149
    150	c->phys_proc_id = apic->phys_pkg_id(c->initial_apicid,
    151				die_plus_mask_width);
    152	/*
    153	 * Reinit the apicid, now that we have extended initial_apicid.
    154	 */
    155	c->apicid = apic->phys_pkg_id(c->initial_apicid, 0);
    156
    157	c->x86_max_cores = (core_level_siblings / smp_num_siblings);
    158	__max_die_per_package = (die_level_siblings / core_level_siblings);
    159#endif
    160	return 0;
    161}