topology_amd.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include <linux/cpu.h>
  3. #include <asm/apic.h>
  4. #include <asm/memtype.h>
  5. #include <asm/processor.h>
  6. #include "cpu.h"
  7. static bool parse_8000_0008(struct topo_scan *tscan)
  8. {
  9. struct {
  10. // ecx
  11. u32 cpu_nthreads : 8, // Number of physical threads - 1
  12. : 4, // Reserved
  13. apicid_coreid_len : 4, // Number of thread core ID bits (shift) in APIC ID
  14. perf_tsc_len : 2, // Performance time-stamp counter size
  15. : 14; // Reserved
  16. } ecx;
  17. unsigned int sft;
  18. if (tscan->c->extended_cpuid_level < 0x80000008)
  19. return false;
  20. cpuid_leaf_reg(0x80000008, CPUID_ECX, &ecx);
  21. /* If the thread bits are 0, then get the shift value from ecx.cpu_nthreads */
  22. sft = ecx.apicid_coreid_len;
  23. if (!sft)
  24. sft = get_count_order(ecx.cpu_nthreads + 1);
  25. /*
  26. * cpu_nthreads describes the number of threads in the package
  27. * sft is the number of APIC ID bits per package
  28. *
  29. * As the number of actual threads per core is not described in
  30. * this leaf, just set the CORE domain shift and let the later
  31. * parsers set SMT shift. Assume one thread per core by default
  32. * which is correct if there are no other CPUID leafs to parse.
  33. */
  34. topology_update_dom(tscan, TOPO_SMT_DOMAIN, 0, 1);
  35. topology_set_dom(tscan, TOPO_CORE_DOMAIN, sft, ecx.cpu_nthreads + 1);
  36. return true;
  37. }
  38. static void store_node(struct topo_scan *tscan, u16 nr_nodes, u16 node_id)
  39. {
  40. /*
  41. * Starting with Fam 17h the DIE domain could probably be used to
  42. * retrieve the node info on AMD/HYGON. Analysis of CPUID dumps
  43. * suggests it's the topmost bit(s) of the CPU cores area, but
  44. * that's guess work and neither enumerated nor documented.
  45. *
  46. * Up to Fam 16h this does not work at all and the legacy node ID
  47. * has to be used.
  48. */
  49. tscan->amd_nodes_per_pkg = nr_nodes;
  50. tscan->amd_node_id = node_id;
  51. }
  52. static bool parse_8000_001e(struct topo_scan *tscan, bool has_topoext)
  53. {
  54. struct {
  55. // eax
  56. u32 ext_apic_id : 32; // Extended APIC ID
  57. // ebx
  58. u32 core_id : 8, // Unique per-socket logical core unit ID
  59. core_nthreads : 8, // #Threads per core (zero-based)
  60. : 16; // Reserved
  61. // ecx
  62. u32 node_id : 8, // Node (die) ID of invoking logical CPU
  63. nnodes_per_socket : 3, // #nodes in invoking logical CPU's package/socket
  64. : 21; // Reserved
  65. // edx
  66. u32 : 32; // Reserved
  67. } leaf;
  68. if (!boot_cpu_has(X86_FEATURE_TOPOEXT))
  69. return false;
  70. cpuid_leaf(0x8000001e, &leaf);
  71. /*
  72. * If leaf 0xb/0x26 is available, then the APIC ID and the domain
  73. * shifts are set already.
  74. */
  75. if (!has_topoext) {
  76. tscan->c->topo.initial_apicid = leaf.ext_apic_id;
  77. /*
  78. * Leaf 0x8000008 sets the CORE domain shift but not the
  79. * SMT domain shift. On CPUs with family >= 0x17, there
  80. * might be hyperthreads.
  81. */
  82. if (tscan->c->x86 >= 0x17) {
  83. /* Update the SMT domain, but do not propagate it. */
  84. unsigned int nthreads = leaf.core_nthreads + 1;
  85. topology_update_dom(tscan, TOPO_SMT_DOMAIN,
  86. get_count_order(nthreads), nthreads);
  87. }
  88. }
  89. store_node(tscan, leaf.nnodes_per_socket + 1, leaf.node_id);
  90. if (tscan->c->x86_vendor == X86_VENDOR_AMD) {
  91. if (tscan->c->x86 == 0x15)
  92. tscan->c->topo.cu_id = leaf.core_id;
  93. cacheinfo_amd_init_llc_id(tscan->c, leaf.node_id);
  94. } else {
  95. /*
  96. * Package ID is ApicId[6..] on certain Hygon CPUs. See
  97. * commit e0ceeae708ce for explanation. The topology info
  98. * is screwed up: The package shift is always 6 and the
  99. * node ID is bit [4:5].
  100. */
  101. if (!boot_cpu_has(X86_FEATURE_HYPERVISOR) && tscan->c->x86_model <= 0x3) {
  102. topology_set_dom(tscan, TOPO_CORE_DOMAIN, 6,
  103. tscan->dom_ncpus[TOPO_CORE_DOMAIN]);
  104. }
  105. cacheinfo_hygon_init_llc_id(tscan->c);
  106. }
  107. return true;
  108. }
  109. static void parse_fam10h_node_id(struct topo_scan *tscan)
  110. {
  111. union {
  112. struct {
  113. u64 node_id : 3,
  114. nodes_per_pkg : 3,
  115. unused : 58;
  116. };
  117. u64 msr;
  118. } nid;
  119. if (!boot_cpu_has(X86_FEATURE_NODEID_MSR))
  120. return;
  121. rdmsrl(MSR_FAM10H_NODE_ID, nid.msr);
  122. store_node(tscan, nid.nodes_per_pkg + 1, nid.node_id);
  123. tscan->c->topo.llc_id = nid.node_id;
  124. }
  125. static void legacy_set_llc(struct topo_scan *tscan)
  126. {
  127. unsigned int apicid = tscan->c->topo.initial_apicid;
  128. /* If none of the parsers set LLC ID then use the die ID for it. */
  129. if (tscan->c->topo.llc_id == BAD_APICID)
  130. tscan->c->topo.llc_id = apicid >> tscan->dom_shifts[TOPO_CORE_DOMAIN];
  131. }
  132. static void topoext_fixup(struct topo_scan *tscan)
  133. {
  134. struct cpuinfo_x86 *c = tscan->c;
  135. u64 msrval;
  136. /* Try to re-enable TopologyExtensions if switched off by BIOS */
  137. if (cpu_has(c, X86_FEATURE_TOPOEXT) || c->x86_vendor != X86_VENDOR_AMD ||
  138. c->x86 != 0x15 || c->x86_model < 0x10 || c->x86_model > 0x6f)
  139. return;
  140. if (msr_set_bit(0xc0011005, 54) <= 0)
  141. return;
  142. rdmsrl(0xc0011005, msrval);
  143. if (msrval & BIT_64(54)) {
  144. set_cpu_cap(c, X86_FEATURE_TOPOEXT);
  145. pr_info_once(FW_INFO "CPU: Re-enabling disabled Topology Extensions Support.\n");
  146. }
  147. }
  148. static void parse_topology_amd(struct topo_scan *tscan)
  149. {
  150. /*
  151. * Try to get SMT, CORE, TILE, and DIE shifts from extended
  152. * CPUID leaf 0x8000_0026 on supported processors first. If
  153. * extended CPUID leaf 0x8000_0026 is not supported, try to
  154. * get SMT and CORE shift from leaf 0xb. If either leaf is
  155. * available, cpu_parse_topology_ext() will return true.
  156. */
  157. bool has_xtopology = cpu_parse_topology_ext(tscan);
  158. /*
  159. * If XTOPOLOGY leaves (0x26/0xb) are not available, try to
  160. * get the CORE shift from leaf 0x8000_0008 first.
  161. */
  162. if (!has_xtopology && !parse_8000_0008(tscan))
  163. return;
  164. /*
  165. * Prefer leaf 0x8000001e if available to get the SMT shift and
  166. * the initial APIC ID if XTOPOLOGY leaves are not available.
  167. */
  168. if (parse_8000_001e(tscan, has_xtopology))
  169. return;
  170. /* Try the NODEID MSR */
  171. parse_fam10h_node_id(tscan);
  172. }
  173. void cpu_parse_topology_amd(struct topo_scan *tscan)
  174. {
  175. tscan->amd_nodes_per_pkg = 1;
  176. topoext_fixup(tscan);
  177. parse_topology_amd(tscan);
  178. legacy_set_llc(tscan);
  179. if (tscan->amd_nodes_per_pkg > 1)
  180. set_cpu_cap(tscan->c, X86_FEATURE_AMD_DCM);
  181. }
  182. void cpu_topology_fixup_amd(struct topo_scan *tscan)
  183. {
  184. struct cpuinfo_x86 *c = tscan->c;
  185. /*
  186. * Adjust the core_id relative to the node when there is more than
  187. * one node.
  188. */
  189. if (tscan->c->x86 < 0x17 && tscan->amd_nodes_per_pkg > 1)
  190. c->topo.core_id %= tscan->dom_ncpus[TOPO_CORE_DOMAIN] / tscan->amd_nodes_per_pkg;
  191. }