Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | // SPDX-License-Identifier: GPL-2.0 #include <linux/cpu.h> #include <asm/apic.h> #include <asm/memtype.h> #include <asm/processor.h> #include "cpu.h" enum topo_types { INVALID_TYPE = 0, SMT_TYPE = 1, CORE_TYPE = 2, MAX_TYPE_0B = 3, MODULE_TYPE = 3, TILE_TYPE = 4, DIE_TYPE = 5, DIEGRP_TYPE = 6, MAX_TYPE_1F = 7, }; /* * Use a lookup table for the case that there are future types > 6 which * describe an intermediate domain level which does not exist today. */ static const unsigned int topo_domain_map_0b_1f[MAX_TYPE_1F] = { [SMT_TYPE] = TOPO_SMT_DOMAIN, [CORE_TYPE] = TOPO_CORE_DOMAIN, [MODULE_TYPE] = TOPO_MODULE_DOMAIN, [TILE_TYPE] = TOPO_TILE_DOMAIN, [DIE_TYPE] = TOPO_DIE_DOMAIN, [DIEGRP_TYPE] = TOPO_DIEGRP_DOMAIN, }; static inline bool topo_subleaf(struct topo_scan *tscan, u32 leaf, u32 subleaf, unsigned int *last_dom) { unsigned int dom, maxtype; const unsigned int *map; struct { // eax u32 x2apic_shift : 5, // Number of bits to shift APIC ID right // for the topology ID at the next level : 27; // Reserved // ebx u32 num_processors : 16, // Number of processors at current level : 16; // Reserved // ecx u32 level : 8, // Current topology level. Same as sub leaf number type : 8, // Level type. If 0, invalid : 16; // Reserved // edx u32 x2apic_id : 32; // X2APIC ID of the current logical processor } sl; switch (leaf) { case 0x0b: maxtype = MAX_TYPE_0B; map = topo_domain_map_0b_1f; break; case 0x1f: maxtype = MAX_TYPE_1F; map = topo_domain_map_0b_1f; break; default: return false; } cpuid_subleaf(leaf, subleaf, &sl); if (!sl.num_processors || sl.type == INVALID_TYPE) return false; if (sl.type >= maxtype) { pr_err_once("Topology: leaf 0x%x:%d Unknown domain type %u\n", leaf, subleaf, sl.type); /* * It really would have been too obvious to make the domain * type space sparse and leave a few reserved types between * the points which might change instead of following the * usual "this can be fixed in software" principle. */ dom = *last_dom + 1; } else { dom = map[sl.type]; *last_dom = dom; } if (!dom) { tscan->c->topo.initial_apicid = sl.x2apic_id; } else if (tscan->c->topo.initial_apicid != sl.x2apic_id) { pr_warn_once(FW_BUG "CPUID leaf 0x%x subleaf %d APIC ID mismatch %x != %x\n", leaf, subleaf, tscan->c->topo.initial_apicid, sl.x2apic_id); } topology_set_dom(tscan, dom, sl.x2apic_shift, sl.num_processors); return true; } static bool parse_topology_leaf(struct topo_scan *tscan, u32 leaf) { unsigned int last_dom; u32 subleaf; /* Read all available subleafs and populate the levels */ for (subleaf = 0, last_dom = 0; topo_subleaf(tscan, leaf, subleaf, &last_dom); subleaf++); /* If subleaf 0 failed to parse, give up */ if (!subleaf) return false; /* * There are machines in the wild which have shift 0 in the subleaf * 0, but advertise 2 logical processors at that level. They are * truly SMT. */ if (!tscan->dom_shifts[TOPO_SMT_DOMAIN] && tscan->dom_ncpus[TOPO_SMT_DOMAIN] > 1) { unsigned int sft = get_count_order(tscan->dom_ncpus[TOPO_SMT_DOMAIN]); pr_warn_once(FW_BUG "CPUID leaf 0x%x subleaf 0 has shift level 0 but %u CPUs. Fixing it up.\n", leaf, tscan->dom_ncpus[TOPO_SMT_DOMAIN]); topology_update_dom(tscan, TOPO_SMT_DOMAIN, sft, tscan->dom_ncpus[TOPO_SMT_DOMAIN]); } set_cpu_cap(tscan->c, X86_FEATURE_XTOPOLOGY); return true; } bool cpu_parse_topology_ext(struct topo_scan *tscan) { /* Intel: Try leaf 0x1F first. */ if (tscan->c->cpuid_level >= 0x1f && parse_topology_leaf(tscan, 0x1f)) return true; /* Intel/AMD: Fall back to leaf 0xB if available */ return tscan->c->cpuid_level >= 0x0b && parse_topology_leaf(tscan, 0x0b); } |