]>
Commit | Line | Data |
---|---|---|
e6f123c3 LJ |
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 | |
61f3c91a | 16 | * version 2.1 of the License, or (at your option) any later version. |
e6f123c3 LJ |
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 | ||
27 | #include "qemu/osdep.h" | |
4586a2cb | 28 | #include "qemu/units.h" |
e6f123c3 LJ |
29 | #include "sysemu/numa.h" |
30 | #include "hw/acpi/hmat.h" | |
31 | ||
32 | /* | |
33 | * ACPI 6.3: | |
34 | * 5.2.27.3 Memory Proximity Domain Attributes Structure: Table 5-145 | |
35 | */ | |
36 | static void build_hmat_mpda(GArray *table_data, uint16_t flags, | |
37 | uint32_t initiator, uint32_t mem_node) | |
38 | { | |
39 | ||
40 | /* Memory Proximity Domain Attributes Structure */ | |
41 | /* Type */ | |
42 | build_append_int_noprefix(table_data, 0, 2); | |
43 | /* Reserved */ | |
44 | build_append_int_noprefix(table_data, 0, 2); | |
45 | /* Length */ | |
46 | build_append_int_noprefix(table_data, 40, 4); | |
47 | /* Flags */ | |
48 | build_append_int_noprefix(table_data, flags, 2); | |
49 | /* Reserved */ | |
50 | build_append_int_noprefix(table_data, 0, 2); | |
51 | /* Proximity Domain for the Attached Initiator */ | |
52 | build_append_int_noprefix(table_data, initiator, 4); | |
53 | /* Proximity Domain for the Memory */ | |
54 | build_append_int_noprefix(table_data, mem_node, 4); | |
55 | /* Reserved */ | |
56 | build_append_int_noprefix(table_data, 0, 4); | |
57 | /* | |
58 | * Reserved: | |
59 | * Previously defined as the Start Address of the System Physical | |
60 | * Address Range. Deprecated since ACPI Spec 6.3. | |
61 | */ | |
62 | build_append_int_noprefix(table_data, 0, 8); | |
63 | /* | |
64 | * Reserved: | |
65 | * Previously defined as the Range Length of the region in bytes. | |
66 | * Deprecated since ACPI Spec 6.3. | |
67 | */ | |
68 | build_append_int_noprefix(table_data, 0, 8); | |
69 | } | |
70 | ||
4586a2cb LJ |
71 | /* |
72 | * ACPI 6.3: 5.2.27.4 System Locality Latency and Bandwidth Information | |
73 | * Structure: Table 5-146 | |
74 | */ | |
75 | static void build_hmat_lb(GArray *table_data, HMAT_LB_Info *hmat_lb, | |
76 | uint32_t num_initiator, uint32_t num_target, | |
77 | uint32_t *initiator_list) | |
78 | { | |
79 | int i, index; | |
80 | HMAT_LB_Data *lb_data; | |
81 | uint16_t *entry_list; | |
82 | uint32_t base; | |
83 | /* Length in bytes for entire structure */ | |
84 | uint32_t lb_length | |
85 | = 32 /* Table length upto and including Entry Base Unit */ | |
86 | + 4 * num_initiator /* Initiator Proximity Domain List */ | |
87 | + 4 * num_target /* Target Proximity Domain List */ | |
88 | + 2 * num_initiator * num_target; /* Latency or Bandwidth Entries */ | |
89 | ||
90 | /* Type */ | |
91 | build_append_int_noprefix(table_data, 1, 2); | |
92 | /* Reserved */ | |
93 | build_append_int_noprefix(table_data, 0, 2); | |
94 | /* Length */ | |
95 | build_append_int_noprefix(table_data, lb_length, 4); | |
96 | /* Flags: Bits [3:0] Memory Hierarchy, Bits[7:4] Reserved */ | |
97 | assert(!(hmat_lb->hierarchy >> 4)); | |
98 | build_append_int_noprefix(table_data, hmat_lb->hierarchy, 1); | |
99 | /* Data Type */ | |
100 | build_append_int_noprefix(table_data, hmat_lb->data_type, 1); | |
101 | /* Reserved */ | |
102 | build_append_int_noprefix(table_data, 0, 2); | |
103 | /* Number of Initiator Proximity Domains (s) */ | |
104 | build_append_int_noprefix(table_data, num_initiator, 4); | |
105 | /* Number of Target Proximity Domains (t) */ | |
106 | build_append_int_noprefix(table_data, num_target, 4); | |
107 | /* Reserved */ | |
108 | build_append_int_noprefix(table_data, 0, 4); | |
109 | ||
110 | /* Entry Base Unit */ | |
111 | if (hmat_lb->data_type <= HMAT_LB_DATA_WRITE_LATENCY) { | |
112 | /* Convert latency base from nanoseconds to picosecond */ | |
113 | base = hmat_lb->base * 1000; | |
114 | } else { | |
115 | /* Convert bandwidth base from Byte to Megabyte */ | |
116 | base = hmat_lb->base / MiB; | |
117 | } | |
118 | build_append_int_noprefix(table_data, base, 8); | |
119 | ||
120 | /* Initiator Proximity Domain List */ | |
121 | for (i = 0; i < num_initiator; i++) { | |
122 | build_append_int_noprefix(table_data, initiator_list[i], 4); | |
123 | } | |
124 | ||
125 | /* Target Proximity Domain List */ | |
126 | for (i = 0; i < num_target; i++) { | |
127 | build_append_int_noprefix(table_data, i, 4); | |
128 | } | |
129 | ||
130 | /* Latency or Bandwidth Entries */ | |
b21e2380 | 131 | entry_list = g_new0(uint16_t, num_initiator * num_target); |
4586a2cb LJ |
132 | for (i = 0; i < hmat_lb->list->len; i++) { |
133 | lb_data = &g_array_index(hmat_lb->list, HMAT_LB_Data, i); | |
134 | index = lb_data->initiator * num_target + lb_data->target; | |
135 | ||
136 | entry_list[index] = (uint16_t)(lb_data->data / hmat_lb->base); | |
137 | } | |
138 | ||
139 | for (i = 0; i < num_initiator * num_target; i++) { | |
140 | build_append_int_noprefix(table_data, entry_list[i], 2); | |
141 | } | |
142 | ||
143 | g_free(entry_list); | |
144 | } | |
145 | ||
a9c2b841 LJ |
146 | /* ACPI 6.3: 5.2.27.5 Memory Side Cache Information Structure: Table 5-147 */ |
147 | static void build_hmat_cache(GArray *table_data, uint8_t total_levels, | |
148 | NumaHmatCacheOptions *hmat_cache) | |
149 | { | |
150 | /* | |
151 | * Cache Attributes: Bits [3:0] – Total Cache Levels | |
152 | * for this Memory Proximity Domain | |
153 | */ | |
154 | uint32_t cache_attr = total_levels; | |
155 | ||
156 | /* Bits [7:4] : Cache Level described in this structure */ | |
157 | cache_attr |= (uint32_t) hmat_cache->level << 4; | |
158 | ||
159 | /* Bits [11:8] - Cache Associativity */ | |
160 | cache_attr |= (uint32_t) hmat_cache->associativity << 8; | |
161 | ||
162 | /* Bits [15:12] - Write Policy */ | |
163 | cache_attr |= (uint32_t) hmat_cache->policy << 12; | |
164 | ||
165 | /* Bits [31:16] - Cache Line size in bytes */ | |
166 | cache_attr |= (uint32_t) hmat_cache->line << 16; | |
167 | ||
168 | /* Type */ | |
169 | build_append_int_noprefix(table_data, 2, 2); | |
170 | /* Reserved */ | |
171 | build_append_int_noprefix(table_data, 0, 2); | |
172 | /* Length */ | |
173 | build_append_int_noprefix(table_data, 32, 4); | |
174 | /* Proximity Domain for the Memory */ | |
175 | build_append_int_noprefix(table_data, hmat_cache->node_id, 4); | |
176 | /* Reserved */ | |
177 | build_append_int_noprefix(table_data, 0, 4); | |
178 | /* Memory Side Cache Size */ | |
179 | build_append_int_noprefix(table_data, hmat_cache->size, 8); | |
180 | /* Cache Attributes */ | |
181 | build_append_int_noprefix(table_data, cache_attr, 4); | |
182 | /* Reserved */ | |
183 | build_append_int_noprefix(table_data, 0, 2); | |
184 | /* | |
185 | * Number of SMBIOS handles (n) | |
186 | * Linux kernel uses Memory Side Cache Information Structure | |
187 | * without SMBIOS entries for now, so set Number of SMBIOS handles | |
188 | * as 0. | |
189 | */ | |
190 | build_append_int_noprefix(table_data, 0, 2); | |
191 | } | |
192 | ||
e6f123c3 LJ |
193 | /* Build HMAT sub table structures */ |
194 | static void hmat_build_table_structs(GArray *table_data, NumaState *numa_state) | |
195 | { | |
196 | uint16_t flags; | |
4586a2cb LJ |
197 | uint32_t num_initiator = 0; |
198 | uint32_t initiator_list[MAX_NODES]; | |
a9c2b841 | 199 | int i, hierarchy, type, cache_level, total_levels; |
4586a2cb | 200 | HMAT_LB_Info *hmat_lb; |
a9c2b841 | 201 | NumaHmatCacheOptions *hmat_cache; |
e6f123c3 | 202 | |
689ef472 IM |
203 | build_append_int_noprefix(table_data, 0, 4); /* Reserved */ |
204 | ||
e6f123c3 LJ |
205 | for (i = 0; i < numa_state->num_nodes; i++) { |
206 | flags = 0; | |
207 | ||
208 | if (numa_state->nodes[i].initiator < MAX_NODES) { | |
209 | flags |= HMAT_PROXIMITY_INITIATOR_VALID; | |
210 | } | |
211 | ||
212 | build_hmat_mpda(table_data, flags, numa_state->nodes[i].initiator, i); | |
213 | } | |
4586a2cb LJ |
214 | |
215 | for (i = 0; i < numa_state->num_nodes; i++) { | |
216 | if (numa_state->nodes[i].has_cpu) { | |
217 | initiator_list[num_initiator++] = i; | |
218 | } | |
219 | } | |
220 | ||
221 | /* | |
222 | * ACPI 6.3: 5.2.27.4 System Locality Latency and Bandwidth Information | |
223 | * Structure: Table 5-146 | |
224 | */ | |
225 | for (hierarchy = HMAT_LB_MEM_MEMORY; | |
226 | hierarchy <= HMAT_LB_MEM_CACHE_3RD_LEVEL; hierarchy++) { | |
227 | for (type = HMAT_LB_DATA_ACCESS_LATENCY; | |
228 | type <= HMAT_LB_DATA_WRITE_BANDWIDTH; type++) { | |
229 | hmat_lb = numa_state->hmat_lb[hierarchy][type]; | |
230 | ||
231 | if (hmat_lb && hmat_lb->list->len) { | |
232 | build_hmat_lb(table_data, hmat_lb, num_initiator, | |
233 | numa_state->num_nodes, initiator_list); | |
234 | } | |
235 | } | |
236 | } | |
a9c2b841 LJ |
237 | |
238 | /* | |
239 | * ACPI 6.3: 5.2.27.5 Memory Side Cache Information Structure: | |
240 | * Table 5-147 | |
241 | */ | |
242 | for (i = 0; i < numa_state->num_nodes; i++) { | |
243 | total_levels = 0; | |
244 | for (cache_level = 1; cache_level < HMAT_LB_LEVELS; cache_level++) { | |
245 | if (numa_state->hmat_cache[i][cache_level]) { | |
246 | total_levels++; | |
247 | } | |
248 | } | |
249 | for (cache_level = 0; cache_level <= total_levels; cache_level++) { | |
250 | hmat_cache = numa_state->hmat_cache[i][cache_level]; | |
251 | if (hmat_cache) { | |
252 | build_hmat_cache(table_data, total_levels, hmat_cache); | |
253 | } | |
254 | } | |
255 | } | |
e6f123c3 LJ |
256 | } |
257 | ||
602b4582 MP |
258 | void build_hmat(GArray *table_data, BIOSLinker *linker, NumaState *numa_state, |
259 | const char *oem_id, const char *oem_table_id) | |
e6f123c3 | 260 | { |
689ef472 IM |
261 | AcpiTable table = { .sig = "HMAT", .rev = 2, |
262 | .oem_id = oem_id, .oem_table_id = oem_table_id }; | |
e6f123c3 | 263 | |
689ef472 | 264 | acpi_table_begin(&table, table_data); |
e6f123c3 | 265 | hmat_build_table_structs(table_data, numa_state); |
689ef472 | 266 | acpi_table_end(linker, &table); |
e6f123c3 | 267 | } |