~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/x86/kernel/cpu/topology_ext.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php