Path: blob/master/arch/x86/kernel/cpu/topology_common.c
50333 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);1718/* CPUs which are the primary SMT threads */19struct cpumask __cpu_primary_thread_mask __read_mostly;2021void topology_set_dom(struct topo_scan *tscan, enum x86_topology_domains dom,22unsigned int shift, unsigned int ncpus)23{24topology_update_dom(tscan, dom, shift, ncpus);2526/* Propagate to the upper levels */27for (dom++; dom < TOPO_MAX_DOMAIN; dom++) {28tscan->dom_shifts[dom] = tscan->dom_shifts[dom - 1];29tscan->dom_ncpus[dom] = tscan->dom_ncpus[dom - 1];30}31}3233enum x86_topology_cpu_type get_topology_cpu_type(struct cpuinfo_x86 *c)34{35if (c->x86_vendor == X86_VENDOR_INTEL) {36switch (c->topo.intel_type) {37case INTEL_CPU_TYPE_ATOM: return TOPO_CPU_TYPE_EFFICIENCY;38case INTEL_CPU_TYPE_CORE: return TOPO_CPU_TYPE_PERFORMANCE;39}40}41if (c->x86_vendor == X86_VENDOR_AMD) {42switch (c->topo.amd_type) {43case 0: return TOPO_CPU_TYPE_PERFORMANCE;44case 1: return TOPO_CPU_TYPE_EFFICIENCY;45}46}4748return TOPO_CPU_TYPE_UNKNOWN;49}5051const char *get_topology_cpu_type_name(struct cpuinfo_x86 *c)52{53switch (get_topology_cpu_type(c)) {54case TOPO_CPU_TYPE_PERFORMANCE:55return "performance";56case TOPO_CPU_TYPE_EFFICIENCY:57return "efficiency";58default:59return "unknown";60}61}6263static unsigned int __maybe_unused parse_num_cores_legacy(struct cpuinfo_x86 *c)64{65struct {66u32 cache_type : 5,67unused : 21,68ncores : 6;69} eax;7071if (c->cpuid_level < 4)72return 1;7374cpuid_subleaf_reg(4, 0, CPUID_EAX, &eax);75if (!eax.cache_type)76return 1;7778return eax.ncores + 1;79}8081static void parse_legacy(struct topo_scan *tscan)82{83unsigned int cores, core_shift, smt_shift = 0;84struct cpuinfo_x86 *c = tscan->c;8586cores = parse_num_cores_legacy(c);87core_shift = get_count_order(cores);8889if (cpu_has(c, X86_FEATURE_HT)) {90if (!WARN_ON_ONCE(tscan->ebx1_nproc_shift < core_shift))91smt_shift = tscan->ebx1_nproc_shift - core_shift;92/*93* The parser expects leaf 0xb/0x1f format, which means94* the number of logical processors at core level is95* counting threads.96*/97core_shift += smt_shift;98cores <<= smt_shift;99}100101topology_set_dom(tscan, TOPO_SMT_DOMAIN, smt_shift, 1U << smt_shift);102topology_set_dom(tscan, TOPO_CORE_DOMAIN, core_shift, cores);103}104105static bool fake_topology(struct topo_scan *tscan)106{107/*108* Preset the CORE level shift for CPUID less systems and XEN_PV,109* which has useless CPUID information.110*/111topology_set_dom(tscan, TOPO_SMT_DOMAIN, 0, 1);112topology_set_dom(tscan, TOPO_CORE_DOMAIN, 0, 1);113114return tscan->c->cpuid_level < 1;115}116117static void parse_topology(struct topo_scan *tscan, bool early)118{119const struct cpuinfo_topology topo_defaults = {120.cu_id = 0xff,121.llc_id = BAD_APICID,122.l2c_id = BAD_APICID,123.cpu_type = TOPO_CPU_TYPE_UNKNOWN,124};125struct cpuinfo_x86 *c = tscan->c;126struct {127u32 unused0 : 16,128nproc : 8,129apicid : 8;130} ebx;131132c->topo = topo_defaults;133134if (fake_topology(tscan))135return;136137/* Preset Initial APIC ID from CPUID leaf 1 */138cpuid_leaf_reg(1, CPUID_EBX, &ebx);139c->topo.initial_apicid = ebx.apicid;140141/*142* The initial invocation from early_identify_cpu() happens before143* the APIC is mapped or X2APIC enabled. For establishing the144* topology, that's not required. Use the initial APIC ID.145*/146if (early)147c->topo.apicid = c->topo.initial_apicid;148else149c->topo.apicid = read_apic_id();150151/* The above is sufficient for UP */152if (!IS_ENABLED(CONFIG_SMP))153return;154155tscan->ebx1_nproc_shift = get_count_order(ebx.nproc);156157switch (c->x86_vendor) {158case X86_VENDOR_AMD:159if (IS_ENABLED(CONFIG_CPU_SUP_AMD))160cpu_parse_topology_amd(tscan);161break;162case X86_VENDOR_CENTAUR:163case X86_VENDOR_ZHAOXIN:164parse_legacy(tscan);165break;166case X86_VENDOR_INTEL:167if (!IS_ENABLED(CONFIG_CPU_SUP_INTEL) || !cpu_parse_topology_ext(tscan))168parse_legacy(tscan);169if (c->cpuid_level >= 0x1a)170c->topo.cpu_type = cpuid_eax(0x1a);171break;172case X86_VENDOR_HYGON:173if (IS_ENABLED(CONFIG_CPU_SUP_HYGON))174cpu_parse_topology_amd(tscan);175break;176}177}178179static void topo_set_ids(struct topo_scan *tscan, bool early)180{181struct cpuinfo_x86 *c = tscan->c;182u32 apicid = c->topo.apicid;183184c->topo.pkg_id = topo_shift_apicid(apicid, TOPO_PKG_DOMAIN);185c->topo.die_id = topo_shift_apicid(apicid, TOPO_DIE_DOMAIN);186187if (!early) {188c->topo.logical_pkg_id = topology_get_logical_id(apicid, TOPO_PKG_DOMAIN);189c->topo.logical_die_id = topology_get_logical_id(apicid, TOPO_DIE_DOMAIN);190c->topo.logical_core_id = topology_get_logical_id(apicid, TOPO_CORE_DOMAIN);191}192193/* Package relative core ID */194c->topo.core_id = (apicid & topo_domain_mask(TOPO_PKG_DOMAIN)) >>195x86_topo_system.dom_shifts[TOPO_SMT_DOMAIN];196197c->topo.amd_node_id = tscan->amd_node_id;198199if (c->x86_vendor == X86_VENDOR_AMD)200cpu_topology_fixup_amd(tscan);201}202203void cpu_parse_topology(struct cpuinfo_x86 *c)204{205unsigned int dom, cpu = smp_processor_id();206struct topo_scan tscan = { .c = c, };207208parse_topology(&tscan, false);209210if (IS_ENABLED(CONFIG_X86_LOCAL_APIC)) {211if (c->topo.initial_apicid != c->topo.apicid) {212pr_err(FW_BUG "CPU%4u: APIC ID mismatch. CPUID: 0x%04x APIC: 0x%04x\n",213cpu, c->topo.initial_apicid, c->topo.apicid);214}215216if (c->topo.apicid != cpuid_to_apicid[cpu]) {217pr_err(FW_BUG "CPU%4u: APIC ID mismatch. Firmware: 0x%04x APIC: 0x%04x\n",218cpu, cpuid_to_apicid[cpu], c->topo.apicid);219}220}221222for (dom = TOPO_SMT_DOMAIN; dom < TOPO_MAX_DOMAIN; dom++) {223if (tscan.dom_shifts[dom] == x86_topo_system.dom_shifts[dom])224continue;225pr_err(FW_BUG "CPU%d: Topology domain %u shift %u != %u\n", cpu, dom,226tscan.dom_shifts[dom], x86_topo_system.dom_shifts[dom]);227}228229topo_set_ids(&tscan, false);230}231232void __init cpu_init_topology(struct cpuinfo_x86 *c)233{234struct topo_scan tscan = { .c = c, };235unsigned int dom, sft;236237parse_topology(&tscan, true);238239/* Copy the shift values and calculate the unit sizes. */240memcpy(x86_topo_system.dom_shifts, tscan.dom_shifts, sizeof(x86_topo_system.dom_shifts));241242dom = TOPO_SMT_DOMAIN;243x86_topo_system.dom_size[dom] = 1U << x86_topo_system.dom_shifts[dom];244245for (dom++; dom < TOPO_MAX_DOMAIN; dom++) {246sft = x86_topo_system.dom_shifts[dom] - x86_topo_system.dom_shifts[dom - 1];247x86_topo_system.dom_size[dom] = 1U << sft;248}249250topo_set_ids(&tscan, true);251252/*253* AMD systems have Nodes per package which cannot be mapped to254* APIC ID.255*/256__amd_nodes_per_pkg = tscan.amd_nodes_per_pkg;257}258259260