Path: blob/master/arch/x86/kernel/cpu/topology_common.c
26493 views
// SPDX-License-Identifier: GPL-2.01#include <linux/cpu.h>23#include <xen/xen.h>45#include <asm/intel-family.h>6#include <asm/apic.h>7#include <asm/processor.h>8#include <asm/smp.h>910#include "cpu.h"1112struct x86_topology_system x86_topo_system __ro_after_init;13EXPORT_SYMBOL_GPL(x86_topo_system);1415unsigned int __amd_nodes_per_pkg __ro_after_init;16EXPORT_SYMBOL_GPL(__amd_nodes_per_pkg);1718void topology_set_dom(struct topo_scan *tscan, enum x86_topology_domains dom,19unsigned int shift, unsigned int ncpus)20{21topology_update_dom(tscan, dom, shift, ncpus);2223/* Propagate to the upper levels */24for (dom++; dom < TOPO_MAX_DOMAIN; dom++) {25tscan->dom_shifts[dom] = tscan->dom_shifts[dom - 1];26tscan->dom_ncpus[dom] = tscan->dom_ncpus[dom - 1];27}28}2930enum x86_topology_cpu_type get_topology_cpu_type(struct cpuinfo_x86 *c)31{32if (c->x86_vendor == X86_VENDOR_INTEL) {33switch (c->topo.intel_type) {34case INTEL_CPU_TYPE_ATOM: return TOPO_CPU_TYPE_EFFICIENCY;35case INTEL_CPU_TYPE_CORE: return TOPO_CPU_TYPE_PERFORMANCE;36}37}38if (c->x86_vendor == X86_VENDOR_AMD) {39switch (c->topo.amd_type) {40case 0: return TOPO_CPU_TYPE_PERFORMANCE;41case 1: return TOPO_CPU_TYPE_EFFICIENCY;42}43}4445return TOPO_CPU_TYPE_UNKNOWN;46}4748const char *get_topology_cpu_type_name(struct cpuinfo_x86 *c)49{50switch (get_topology_cpu_type(c)) {51case TOPO_CPU_TYPE_PERFORMANCE:52return "performance";53case TOPO_CPU_TYPE_EFFICIENCY:54return "efficiency";55default:56return "unknown";57}58}5960static unsigned int __maybe_unused parse_num_cores_legacy(struct cpuinfo_x86 *c)61{62struct {63u32 cache_type : 5,64unused : 21,65ncores : 6;66} eax;6768if (c->cpuid_level < 4)69return 1;7071cpuid_subleaf_reg(4, 0, CPUID_EAX, &eax);72if (!eax.cache_type)73return 1;7475return eax.ncores + 1;76}7778static void parse_legacy(struct topo_scan *tscan)79{80unsigned int cores, core_shift, smt_shift = 0;81struct cpuinfo_x86 *c = tscan->c;8283cores = parse_num_cores_legacy(c);84core_shift = get_count_order(cores);8586if (cpu_has(c, X86_FEATURE_HT)) {87if (!WARN_ON_ONCE(tscan->ebx1_nproc_shift < core_shift))88smt_shift = tscan->ebx1_nproc_shift - core_shift;89/*90* The parser expects leaf 0xb/0x1f format, which means91* the number of logical processors at core level is92* counting threads.93*/94core_shift += smt_shift;95cores <<= smt_shift;96}9798topology_set_dom(tscan, TOPO_SMT_DOMAIN, smt_shift, 1U << smt_shift);99topology_set_dom(tscan, TOPO_CORE_DOMAIN, core_shift, cores);100}101102static bool fake_topology(struct topo_scan *tscan)103{104/*105* Preset the CORE level shift for CPUID less systems and XEN_PV,106* which has useless CPUID information.107*/108topology_set_dom(tscan, TOPO_SMT_DOMAIN, 0, 1);109topology_set_dom(tscan, TOPO_CORE_DOMAIN, 0, 1);110111return tscan->c->cpuid_level < 1;112}113114static void parse_topology(struct topo_scan *tscan, bool early)115{116const struct cpuinfo_topology topo_defaults = {117.cu_id = 0xff,118.llc_id = BAD_APICID,119.l2c_id = BAD_APICID,120.cpu_type = TOPO_CPU_TYPE_UNKNOWN,121};122struct cpuinfo_x86 *c = tscan->c;123struct {124u32 unused0 : 16,125nproc : 8,126apicid : 8;127} ebx;128129c->topo = topo_defaults;130131if (fake_topology(tscan))132return;133134/* Preset Initial APIC ID from CPUID leaf 1 */135cpuid_leaf_reg(1, CPUID_EBX, &ebx);136c->topo.initial_apicid = ebx.apicid;137138/*139* The initial invocation from early_identify_cpu() happens before140* the APIC is mapped or X2APIC enabled. For establishing the141* topology, that's not required. Use the initial APIC ID.142*/143if (early)144c->topo.apicid = c->topo.initial_apicid;145else146c->topo.apicid = read_apic_id();147148/* The above is sufficient for UP */149if (!IS_ENABLED(CONFIG_SMP))150return;151152tscan->ebx1_nproc_shift = get_count_order(ebx.nproc);153154switch (c->x86_vendor) {155case X86_VENDOR_AMD:156if (IS_ENABLED(CONFIG_CPU_SUP_AMD))157cpu_parse_topology_amd(tscan);158break;159case X86_VENDOR_CENTAUR:160case X86_VENDOR_ZHAOXIN:161parse_legacy(tscan);162break;163case X86_VENDOR_INTEL:164if (!IS_ENABLED(CONFIG_CPU_SUP_INTEL) || !cpu_parse_topology_ext(tscan))165parse_legacy(tscan);166if (c->cpuid_level >= 0x1a)167c->topo.cpu_type = cpuid_eax(0x1a);168break;169case X86_VENDOR_HYGON:170if (IS_ENABLED(CONFIG_CPU_SUP_HYGON))171cpu_parse_topology_amd(tscan);172break;173}174}175176static void topo_set_ids(struct topo_scan *tscan, bool early)177{178struct cpuinfo_x86 *c = tscan->c;179u32 apicid = c->topo.apicid;180181c->topo.pkg_id = topo_shift_apicid(apicid, TOPO_PKG_DOMAIN);182c->topo.die_id = topo_shift_apicid(apicid, TOPO_DIE_DOMAIN);183184if (!early) {185c->topo.logical_pkg_id = topology_get_logical_id(apicid, TOPO_PKG_DOMAIN);186c->topo.logical_die_id = topology_get_logical_id(apicid, TOPO_DIE_DOMAIN);187c->topo.logical_core_id = topology_get_logical_id(apicid, TOPO_CORE_DOMAIN);188}189190/* Package relative core ID */191c->topo.core_id = (apicid & topo_domain_mask(TOPO_PKG_DOMAIN)) >>192x86_topo_system.dom_shifts[TOPO_SMT_DOMAIN];193194c->topo.amd_node_id = tscan->amd_node_id;195196if (c->x86_vendor == X86_VENDOR_AMD)197cpu_topology_fixup_amd(tscan);198}199200void cpu_parse_topology(struct cpuinfo_x86 *c)201{202unsigned int dom, cpu = smp_processor_id();203struct topo_scan tscan = { .c = c, };204205parse_topology(&tscan, false);206207if (IS_ENABLED(CONFIG_X86_LOCAL_APIC)) {208if (c->topo.initial_apicid != c->topo.apicid) {209pr_err(FW_BUG "CPU%4u: APIC ID mismatch. CPUID: 0x%04x APIC: 0x%04x\n",210cpu, c->topo.initial_apicid, c->topo.apicid);211}212213if (c->topo.apicid != cpuid_to_apicid[cpu]) {214pr_err(FW_BUG "CPU%4u: APIC ID mismatch. Firmware: 0x%04x APIC: 0x%04x\n",215cpu, cpuid_to_apicid[cpu], c->topo.apicid);216}217}218219for (dom = TOPO_SMT_DOMAIN; dom < TOPO_MAX_DOMAIN; dom++) {220if (tscan.dom_shifts[dom] == x86_topo_system.dom_shifts[dom])221continue;222pr_err(FW_BUG "CPU%d: Topology domain %u shift %u != %u\n", cpu, dom,223tscan.dom_shifts[dom], x86_topo_system.dom_shifts[dom]);224}225226topo_set_ids(&tscan, false);227}228229void __init cpu_init_topology(struct cpuinfo_x86 *c)230{231struct topo_scan tscan = { .c = c, };232unsigned int dom, sft;233234parse_topology(&tscan, true);235236/* Copy the shift values and calculate the unit sizes. */237memcpy(x86_topo_system.dom_shifts, tscan.dom_shifts, sizeof(x86_topo_system.dom_shifts));238239dom = TOPO_SMT_DOMAIN;240x86_topo_system.dom_size[dom] = 1U << x86_topo_system.dom_shifts[dom];241242for (dom++; dom < TOPO_MAX_DOMAIN; dom++) {243sft = x86_topo_system.dom_shifts[dom] - x86_topo_system.dom_shifts[dom - 1];244x86_topo_system.dom_size[dom] = 1U << sft;245}246247topo_set_ids(&tscan, true);248249/*250* AMD systems have Nodes per package which cannot be mapped to251* APIC ID.252*/253__amd_nodes_per_pkg = tscan.amd_nodes_per_pkg;254}255256257