hmat.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /*
  2. * HMAT ACPI Implementation
  3. *
  4. * Copyright(C) 2019 Intel Corporation.
  5. *
  6. * Author:
  7. * Liu jingqi <jingqi.liu@linux.intel.com>
  8. * Tao Xu <tao3.xu@intel.com>
  9. *
  10. * HMAT is defined in ACPI 6.3: 5.2.27 Heterogeneous Memory Attribute Table
  11. * (HMAT)
  12. *
  13. * This library is free software; you can redistribute it and/or
  14. * modify it under the terms of the GNU Lesser General Public
  15. * License as published by the Free Software Foundation; either
  16. * version 2 of the License, or (at your option) any later version.
  17. *
  18. * This library is distributed in the hope that it will be useful,
  19. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  21. * Lesser General Public License for more details.
  22. *
  23. * You should have received a copy of the GNU Lesser General Public
  24. * License along with this library; if not, see <http://www.gnu.org/licenses/>
  25. */
  26. #include "qemu/osdep.h"
  27. #include "qemu/units.h"
  28. #include "sysemu/numa.h"
  29. #include "hw/acpi/hmat.h"
  30. /*
  31. * ACPI 6.3:
  32. * 5.2.27.3 Memory Proximity Domain Attributes Structure: Table 5-145
  33. */
  34. static void build_hmat_mpda(GArray *table_data, uint16_t flags,
  35. uint32_t initiator, uint32_t mem_node)
  36. {
  37. /* Memory Proximity Domain Attributes Structure */
  38. /* Type */
  39. build_append_int_noprefix(table_data, 0, 2);
  40. /* Reserved */
  41. build_append_int_noprefix(table_data, 0, 2);
  42. /* Length */
  43. build_append_int_noprefix(table_data, 40, 4);
  44. /* Flags */
  45. build_append_int_noprefix(table_data, flags, 2);
  46. /* Reserved */
  47. build_append_int_noprefix(table_data, 0, 2);
  48. /* Proximity Domain for the Attached Initiator */
  49. build_append_int_noprefix(table_data, initiator, 4);
  50. /* Proximity Domain for the Memory */
  51. build_append_int_noprefix(table_data, mem_node, 4);
  52. /* Reserved */
  53. build_append_int_noprefix(table_data, 0, 4);
  54. /*
  55. * Reserved:
  56. * Previously defined as the Start Address of the System Physical
  57. * Address Range. Deprecated since ACPI Spec 6.3.
  58. */
  59. build_append_int_noprefix(table_data, 0, 8);
  60. /*
  61. * Reserved:
  62. * Previously defined as the Range Length of the region in bytes.
  63. * Deprecated since ACPI Spec 6.3.
  64. */
  65. build_append_int_noprefix(table_data, 0, 8);
  66. }
  67. /*
  68. * ACPI 6.3: 5.2.27.4 System Locality Latency and Bandwidth Information
  69. * Structure: Table 5-146
  70. */
  71. static void build_hmat_lb(GArray *table_data, HMAT_LB_Info *hmat_lb,
  72. uint32_t num_initiator, uint32_t num_target,
  73. uint32_t *initiator_list)
  74. {
  75. int i, index;
  76. HMAT_LB_Data *lb_data;
  77. uint16_t *entry_list;
  78. uint32_t base;
  79. /* Length in bytes for entire structure */
  80. uint32_t lb_length
  81. = 32 /* Table length upto and including Entry Base Unit */
  82. + 4 * num_initiator /* Initiator Proximity Domain List */
  83. + 4 * num_target /* Target Proximity Domain List */
  84. + 2 * num_initiator * num_target; /* Latency or Bandwidth Entries */
  85. /* Type */
  86. build_append_int_noprefix(table_data, 1, 2);
  87. /* Reserved */
  88. build_append_int_noprefix(table_data, 0, 2);
  89. /* Length */
  90. build_append_int_noprefix(table_data, lb_length, 4);
  91. /* Flags: Bits [3:0] Memory Hierarchy, Bits[7:4] Reserved */
  92. assert(!(hmat_lb->hierarchy >> 4));
  93. build_append_int_noprefix(table_data, hmat_lb->hierarchy, 1);
  94. /* Data Type */
  95. build_append_int_noprefix(table_data, hmat_lb->data_type, 1);
  96. /* Reserved */
  97. build_append_int_noprefix(table_data, 0, 2);
  98. /* Number of Initiator Proximity Domains (s) */
  99. build_append_int_noprefix(table_data, num_initiator, 4);
  100. /* Number of Target Proximity Domains (t) */
  101. build_append_int_noprefix(table_data, num_target, 4);
  102. /* Reserved */
  103. build_append_int_noprefix(table_data, 0, 4);
  104. /* Entry Base Unit */
  105. if (hmat_lb->data_type <= HMAT_LB_DATA_WRITE_LATENCY) {
  106. /* Convert latency base from nanoseconds to picosecond */
  107. base = hmat_lb->base * 1000;
  108. } else {
  109. /* Convert bandwidth base from Byte to Megabyte */
  110. base = hmat_lb->base / MiB;
  111. }
  112. build_append_int_noprefix(table_data, base, 8);
  113. /* Initiator Proximity Domain List */
  114. for (i = 0; i < num_initiator; i++) {
  115. build_append_int_noprefix(table_data, initiator_list[i], 4);
  116. }
  117. /* Target Proximity Domain List */
  118. for (i = 0; i < num_target; i++) {
  119. build_append_int_noprefix(table_data, i, 4);
  120. }
  121. /* Latency or Bandwidth Entries */
  122. entry_list = g_malloc0(num_initiator * num_target * sizeof(uint16_t));
  123. for (i = 0; i < hmat_lb->list->len; i++) {
  124. lb_data = &g_array_index(hmat_lb->list, HMAT_LB_Data, i);
  125. index = lb_data->initiator * num_target + lb_data->target;
  126. entry_list[index] = (uint16_t)(lb_data->data / hmat_lb->base);
  127. }
  128. for (i = 0; i < num_initiator * num_target; i++) {
  129. build_append_int_noprefix(table_data, entry_list[i], 2);
  130. }
  131. g_free(entry_list);
  132. }
  133. /* ACPI 6.3: 5.2.27.5 Memory Side Cache Information Structure: Table 5-147 */
  134. static void build_hmat_cache(GArray *table_data, uint8_t total_levels,
  135. NumaHmatCacheOptions *hmat_cache)
  136. {
  137. /*
  138. * Cache Attributes: Bits [3:0] – Total Cache Levels
  139. * for this Memory Proximity Domain
  140. */
  141. uint32_t cache_attr = total_levels;
  142. /* Bits [7:4] : Cache Level described in this structure */
  143. cache_attr |= (uint32_t) hmat_cache->level << 4;
  144. /* Bits [11:8] - Cache Associativity */
  145. cache_attr |= (uint32_t) hmat_cache->associativity << 8;
  146. /* Bits [15:12] - Write Policy */
  147. cache_attr |= (uint32_t) hmat_cache->policy << 12;
  148. /* Bits [31:16] - Cache Line size in bytes */
  149. cache_attr |= (uint32_t) hmat_cache->line << 16;
  150. /* Type */
  151. build_append_int_noprefix(table_data, 2, 2);
  152. /* Reserved */
  153. build_append_int_noprefix(table_data, 0, 2);
  154. /* Length */
  155. build_append_int_noprefix(table_data, 32, 4);
  156. /* Proximity Domain for the Memory */
  157. build_append_int_noprefix(table_data, hmat_cache->node_id, 4);
  158. /* Reserved */
  159. build_append_int_noprefix(table_data, 0, 4);
  160. /* Memory Side Cache Size */
  161. build_append_int_noprefix(table_data, hmat_cache->size, 8);
  162. /* Cache Attributes */
  163. build_append_int_noprefix(table_data, cache_attr, 4);
  164. /* Reserved */
  165. build_append_int_noprefix(table_data, 0, 2);
  166. /*
  167. * Number of SMBIOS handles (n)
  168. * Linux kernel uses Memory Side Cache Information Structure
  169. * without SMBIOS entries for now, so set Number of SMBIOS handles
  170. * as 0.
  171. */
  172. build_append_int_noprefix(table_data, 0, 2);
  173. }
  174. /* Build HMAT sub table structures */
  175. static void hmat_build_table_structs(GArray *table_data, NumaState *numa_state)
  176. {
  177. uint16_t flags;
  178. uint32_t num_initiator = 0;
  179. uint32_t initiator_list[MAX_NODES];
  180. int i, hierarchy, type, cache_level, total_levels;
  181. HMAT_LB_Info *hmat_lb;
  182. NumaHmatCacheOptions *hmat_cache;
  183. for (i = 0; i < numa_state->num_nodes; i++) {
  184. flags = 0;
  185. if (numa_state->nodes[i].initiator < MAX_NODES) {
  186. flags |= HMAT_PROXIMITY_INITIATOR_VALID;
  187. }
  188. build_hmat_mpda(table_data, flags, numa_state->nodes[i].initiator, i);
  189. }
  190. for (i = 0; i < numa_state->num_nodes; i++) {
  191. if (numa_state->nodes[i].has_cpu) {
  192. initiator_list[num_initiator++] = i;
  193. }
  194. }
  195. /*
  196. * ACPI 6.3: 5.2.27.4 System Locality Latency and Bandwidth Information
  197. * Structure: Table 5-146
  198. */
  199. for (hierarchy = HMAT_LB_MEM_MEMORY;
  200. hierarchy <= HMAT_LB_MEM_CACHE_3RD_LEVEL; hierarchy++) {
  201. for (type = HMAT_LB_DATA_ACCESS_LATENCY;
  202. type <= HMAT_LB_DATA_WRITE_BANDWIDTH; type++) {
  203. hmat_lb = numa_state->hmat_lb[hierarchy][type];
  204. if (hmat_lb && hmat_lb->list->len) {
  205. build_hmat_lb(table_data, hmat_lb, num_initiator,
  206. numa_state->num_nodes, initiator_list);
  207. }
  208. }
  209. }
  210. /*
  211. * ACPI 6.3: 5.2.27.5 Memory Side Cache Information Structure:
  212. * Table 5-147
  213. */
  214. for (i = 0; i < numa_state->num_nodes; i++) {
  215. total_levels = 0;
  216. for (cache_level = 1; cache_level < HMAT_LB_LEVELS; cache_level++) {
  217. if (numa_state->hmat_cache[i][cache_level]) {
  218. total_levels++;
  219. }
  220. }
  221. for (cache_level = 0; cache_level <= total_levels; cache_level++) {
  222. hmat_cache = numa_state->hmat_cache[i][cache_level];
  223. if (hmat_cache) {
  224. build_hmat_cache(table_data, total_levels, hmat_cache);
  225. }
  226. }
  227. }
  228. }
  229. void build_hmat(GArray *table_data, BIOSLinker *linker, NumaState *numa_state)
  230. {
  231. int hmat_start = table_data->len;
  232. /* reserve space for HMAT header */
  233. acpi_data_push(table_data, 40);
  234. hmat_build_table_structs(table_data, numa_state);
  235. build_header(linker, table_data,
  236. (void *)(table_data->data + hmat_start),
  237. "HMAT", table_data->len - hmat_start, 2, NULL, NULL);
  238. }