LCOV - code coverage report
Current view: top level - arch/x86/kernel/cpu - topology.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 55 61 90.2 %
Date: 2021-04-22 12:43:58 Functions: 3 3 100.0 %

          Line data    Source code
       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             : 
      28             : unsigned int __max_die_per_package __read_mostly = 1;
      29             : EXPORT_SYMBOL(__max_die_per_package);
      30             : 
      31             : #ifdef CONFIG_SMP
      32             : /*
      33             :  * Check if given CPUID extended toplogy "leaf" is implemented
      34             :  */
      35           9 : static int check_extended_topology_leaf(int leaf)
      36             : {
      37           9 :         unsigned int eax, ebx, ecx, edx;
      38             : 
      39          18 :         cpuid_count(leaf, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
      40             : 
      41           9 :         if (ebx == 0 || (LEAFB_SUBTYPE(ecx) != SMT_TYPE))
      42             :                 return -1;
      43             : 
      44             :         return 0;
      45             : }
      46             : /*
      47             :  * Return best CPUID Extended Toplogy Leaf supported
      48             :  */
      49           9 : static int detect_extended_topology_leaf(struct cpuinfo_x86 *c)
      50             : {
      51           9 :         if (c->cpuid_level >= 0x1f) {
      52           0 :                 if (check_extended_topology_leaf(0x1f) == 0)
      53             :                         return 0x1f;
      54             :         }
      55             : 
      56           9 :         if (c->cpuid_level >= 0xb) {
      57           9 :                 if (check_extended_topology_leaf(0xb) == 0)
      58           9 :                         return 0xb;
      59             :         }
      60             : 
      61             :         return -1;
      62             : }
      63             : #endif
      64             : 
      65           5 : int detect_extended_topology_early(struct cpuinfo_x86 *c)
      66             : {
      67             : #ifdef CONFIG_SMP
      68           5 :         unsigned int eax, ebx, ecx, edx;
      69           5 :         int leaf;
      70             : 
      71           5 :         leaf = detect_extended_topology_leaf(c);
      72           5 :         if (leaf < 0)
      73             :                 return -1;
      74             : 
      75           5 :         set_cpu_cap(c, X86_FEATURE_XTOPOLOGY);
      76             : 
      77           5 :         cpuid_count(leaf, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
      78             :         /*
      79             :          * initial apic id, which also represents 32-bit extended x2apic id.
      80             :          */
      81           5 :         c->initial_apicid = edx;
      82           5 :         smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx);
      83             : #endif
      84           5 :         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             :  */
      92           4 : int detect_extended_topology(struct cpuinfo_x86 *c)
      93             : {
      94             : #ifdef CONFIG_SMP
      95           4 :         unsigned int eax, ebx, ecx, edx, sub_index;
      96           4 :         unsigned int ht_mask_width, core_plus_mask_width, die_plus_mask_width;
      97           4 :         unsigned int core_select_mask, core_level_siblings;
      98           4 :         unsigned int die_select_mask, die_level_siblings;
      99           4 :         bool die_level_present = false;
     100           4 :         int leaf;
     101             : 
     102           4 :         leaf = detect_extended_topology_leaf(c);
     103           4 :         if (leaf < 0)
     104             :                 return -1;
     105             : 
     106             :         /*
     107             :          * Populate HT related information from sub-leaf level 0.
     108             :          */
     109           4 :         cpuid_count(leaf, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
     110           4 :         c->initial_apicid = edx;
     111           4 :         core_level_siblings = smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx);
     112           4 :         core_plus_mask_width = ht_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
     113           4 :         die_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
     114           4 :         die_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
     115             : 
     116           4 :         sub_index = 1;
     117           8 :         do {
     118           8 :                 cpuid_count(leaf, sub_index, &eax, &ebx, &ecx, &edx);
     119             : 
     120             :                 /*
     121             :                  * Check for the Core type in the implemented sub leaves.
     122             :                  */
     123           8 :                 if (LEAFB_SUBTYPE(ecx) == CORE_TYPE) {
     124           4 :                         core_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
     125           4 :                         core_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
     126           4 :                         die_level_siblings = core_level_siblings;
     127           4 :                         die_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
     128             :                 }
     129           8 :                 if (LEAFB_SUBTYPE(ecx) == DIE_TYPE) {
     130           0 :                         die_level_present = true;
     131           0 :                         die_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
     132           0 :                         die_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
     133             :                 }
     134             : 
     135           8 :                 sub_index++;
     136           8 :         } while (LEAFB_SUBTYPE(ecx) != INVALID_TYPE);
     137             : 
     138           4 :         core_select_mask = (~(-1 << core_plus_mask_width)) >> ht_mask_width;
     139           4 :         die_select_mask = (~(-1 << die_plus_mask_width)) >>
     140             :                                 core_plus_mask_width;
     141             : 
     142           4 :         c->cpu_core_id = apic->phys_pkg_id(c->initial_apicid,
     143           4 :                                 ht_mask_width) & core_select_mask;
     144             : 
     145           4 :         if (die_level_present) {
     146           0 :                 c->cpu_die_id = apic->phys_pkg_id(c->initial_apicid,
     147           0 :                                         core_plus_mask_width) & die_select_mask;
     148             :         }
     149             : 
     150           4 :         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           4 :         c->apicid = apic->phys_pkg_id(c->initial_apicid, 0);
     156             : 
     157           4 :         c->x86_max_cores = (core_level_siblings / smp_num_siblings);
     158           4 :         __max_die_per_package = (die_level_siblings / core_level_siblings);
     159             : #endif
     160           4 :         return 0;
     161             : }

Generated by: LCOV version 1.14