1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27#include "qemu/osdep.h"
28#include "qemu/units.h"
29#include "sysemu/numa.h"
30#include "hw/acpi/hmat.h"
31
32
33
34
35
36static void build_hmat_mpda(GArray *table_data, uint16_t flags,
37 uint32_t initiator, uint32_t mem_node)
38{
39
40
41
42 build_append_int_noprefix(table_data, 0, 2);
43
44 build_append_int_noprefix(table_data, 0, 2);
45
46 build_append_int_noprefix(table_data, 40, 4);
47
48 build_append_int_noprefix(table_data, flags, 2);
49
50 build_append_int_noprefix(table_data, 0, 2);
51
52 build_append_int_noprefix(table_data, initiator, 4);
53
54 build_append_int_noprefix(table_data, mem_node, 4);
55
56 build_append_int_noprefix(table_data, 0, 4);
57
58
59
60
61
62 build_append_int_noprefix(table_data, 0, 8);
63
64
65
66
67
68 build_append_int_noprefix(table_data, 0, 8);
69}
70
71
72
73
74
75static 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
84 uint32_t lb_length
85 = 32
86 + 4 * num_initiator
87 + 4 * num_target
88 + 2 * num_initiator * num_target;
89
90
91 build_append_int_noprefix(table_data, 1, 2);
92
93 build_append_int_noprefix(table_data, 0, 2);
94
95 build_append_int_noprefix(table_data, lb_length, 4);
96
97 assert(!(hmat_lb->hierarchy >> 4));
98 build_append_int_noprefix(table_data, hmat_lb->hierarchy, 1);
99
100 build_append_int_noprefix(table_data, hmat_lb->data_type, 1);
101
102 build_append_int_noprefix(table_data, 0, 2);
103
104 build_append_int_noprefix(table_data, num_initiator, 4);
105
106 build_append_int_noprefix(table_data, num_target, 4);
107
108 build_append_int_noprefix(table_data, 0, 4);
109
110
111 if (hmat_lb->data_type <= HMAT_LB_DATA_WRITE_LATENCY) {
112
113 base = hmat_lb->base * 1000;
114 } else {
115
116 base = hmat_lb->base / MiB;
117 }
118 build_append_int_noprefix(table_data, base, 8);
119
120
121 for (i = 0; i < num_initiator; i++) {
122 build_append_int_noprefix(table_data, initiator_list[i], 4);
123 }
124
125
126 for (i = 0; i < num_target; i++) {
127 build_append_int_noprefix(table_data, i, 4);
128 }
129
130
131 entry_list = g_malloc0(num_initiator * num_target * sizeof(uint16_t));
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
146
147static void build_hmat_cache(GArray *table_data, uint8_t total_levels,
148 NumaHmatCacheOptions *hmat_cache)
149{
150
151
152
153
154 uint32_t cache_attr = total_levels;
155
156
157 cache_attr |= (uint32_t) hmat_cache->level << 4;
158
159
160 cache_attr |= (uint32_t) hmat_cache->associativity << 8;
161
162
163 cache_attr |= (uint32_t) hmat_cache->policy << 12;
164
165
166 cache_attr |= (uint32_t) hmat_cache->line << 16;
167
168
169 build_append_int_noprefix(table_data, 2, 2);
170
171 build_append_int_noprefix(table_data, 0, 2);
172
173 build_append_int_noprefix(table_data, 32, 4);
174
175 build_append_int_noprefix(table_data, hmat_cache->node_id, 4);
176
177 build_append_int_noprefix(table_data, 0, 4);
178
179 build_append_int_noprefix(table_data, hmat_cache->size, 8);
180
181 build_append_int_noprefix(table_data, cache_attr, 4);
182
183 build_append_int_noprefix(table_data, 0, 2);
184
185
186
187
188
189
190 build_append_int_noprefix(table_data, 0, 2);
191}
192
193
194static void hmat_build_table_structs(GArray *table_data, NumaState *numa_state)
195{
196 uint16_t flags;
197 uint32_t num_initiator = 0;
198 uint32_t initiator_list[MAX_NODES];
199 int i, hierarchy, type, cache_level, total_levels;
200 HMAT_LB_Info *hmat_lb;
201 NumaHmatCacheOptions *hmat_cache;
202
203 build_append_int_noprefix(table_data, 0, 4);
204
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 }
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
223
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 }
237
238
239
240
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 }
256}
257
258void build_hmat(GArray *table_data, BIOSLinker *linker, NumaState *numa_state,
259 const char *oem_id, const char *oem_table_id)
260{
261 AcpiTable table = { .sig = "HMAT", .rev = 2,
262 .oem_id = oem_id, .oem_table_id = oem_table_id };
263
264 acpi_table_begin(&table, table_data);
265 hmat_build_table_structs(table_data, numa_state);
266 acpi_table_end(linker, &table);
267}
268