xref: /qemu/hw/acpi/hmat.c (revision b21e2380)
1e6f123c3SLiu Jingqi /*
2e6f123c3SLiu Jingqi  * HMAT ACPI Implementation
3e6f123c3SLiu Jingqi  *
4e6f123c3SLiu Jingqi  * Copyright(C) 2019 Intel Corporation.
5e6f123c3SLiu Jingqi  *
6e6f123c3SLiu Jingqi  * Author:
7e6f123c3SLiu Jingqi  *  Liu jingqi <jingqi.liu@linux.intel.com>
8e6f123c3SLiu Jingqi  *  Tao Xu <tao3.xu@intel.com>
9e6f123c3SLiu Jingqi  *
10e6f123c3SLiu Jingqi  * HMAT is defined in ACPI 6.3: 5.2.27 Heterogeneous Memory Attribute Table
11e6f123c3SLiu Jingqi  * (HMAT)
12e6f123c3SLiu Jingqi  *
13e6f123c3SLiu Jingqi  * This library is free software; you can redistribute it and/or
14e6f123c3SLiu Jingqi  * modify it under the terms of the GNU Lesser General Public
15e6f123c3SLiu Jingqi  * License as published by the Free Software Foundation; either
1661f3c91aSChetan Pant  * version 2.1 of the License, or (at your option) any later version.
17e6f123c3SLiu Jingqi  *
18e6f123c3SLiu Jingqi  * This library is distributed in the hope that it will be useful,
19e6f123c3SLiu Jingqi  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20e6f123c3SLiu Jingqi  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21e6f123c3SLiu Jingqi  * Lesser General Public License for more details.
22e6f123c3SLiu Jingqi  *
23e6f123c3SLiu Jingqi  * You should have received a copy of the GNU Lesser General Public
24e6f123c3SLiu Jingqi  * License along with this library; if not, see <http://www.gnu.org/licenses/>
25e6f123c3SLiu Jingqi  */
26e6f123c3SLiu Jingqi 
27e6f123c3SLiu Jingqi #include "qemu/osdep.h"
284586a2cbSLiu Jingqi #include "qemu/units.h"
29e6f123c3SLiu Jingqi #include "sysemu/numa.h"
30e6f123c3SLiu Jingqi #include "hw/acpi/hmat.h"
31e6f123c3SLiu Jingqi 
32e6f123c3SLiu Jingqi /*
33e6f123c3SLiu Jingqi  * ACPI 6.3:
34e6f123c3SLiu Jingqi  * 5.2.27.3 Memory Proximity Domain Attributes Structure: Table 5-145
35e6f123c3SLiu Jingqi  */
36e6f123c3SLiu Jingqi static void build_hmat_mpda(GArray *table_data, uint16_t flags,
37e6f123c3SLiu Jingqi                             uint32_t initiator, uint32_t mem_node)
38e6f123c3SLiu Jingqi {
39e6f123c3SLiu Jingqi 
40e6f123c3SLiu Jingqi     /* Memory Proximity Domain Attributes Structure */
41e6f123c3SLiu Jingqi     /* Type */
42e6f123c3SLiu Jingqi     build_append_int_noprefix(table_data, 0, 2);
43e6f123c3SLiu Jingqi     /* Reserved */
44e6f123c3SLiu Jingqi     build_append_int_noprefix(table_data, 0, 2);
45e6f123c3SLiu Jingqi     /* Length */
46e6f123c3SLiu Jingqi     build_append_int_noprefix(table_data, 40, 4);
47e6f123c3SLiu Jingqi     /* Flags */
48e6f123c3SLiu Jingqi     build_append_int_noprefix(table_data, flags, 2);
49e6f123c3SLiu Jingqi     /* Reserved */
50e6f123c3SLiu Jingqi     build_append_int_noprefix(table_data, 0, 2);
51e6f123c3SLiu Jingqi     /* Proximity Domain for the Attached Initiator */
52e6f123c3SLiu Jingqi     build_append_int_noprefix(table_data, initiator, 4);
53e6f123c3SLiu Jingqi     /* Proximity Domain for the Memory */
54e6f123c3SLiu Jingqi     build_append_int_noprefix(table_data, mem_node, 4);
55e6f123c3SLiu Jingqi     /* Reserved */
56e6f123c3SLiu Jingqi     build_append_int_noprefix(table_data, 0, 4);
57e6f123c3SLiu Jingqi     /*
58e6f123c3SLiu Jingqi      * Reserved:
59e6f123c3SLiu Jingqi      * Previously defined as the Start Address of the System Physical
60e6f123c3SLiu Jingqi      * Address Range. Deprecated since ACPI Spec 6.3.
61e6f123c3SLiu Jingqi      */
62e6f123c3SLiu Jingqi     build_append_int_noprefix(table_data, 0, 8);
63e6f123c3SLiu Jingqi     /*
64e6f123c3SLiu Jingqi      * Reserved:
65e6f123c3SLiu Jingqi      * Previously defined as the Range Length of the region in bytes.
66e6f123c3SLiu Jingqi      * Deprecated since ACPI Spec 6.3.
67e6f123c3SLiu Jingqi      */
68e6f123c3SLiu Jingqi     build_append_int_noprefix(table_data, 0, 8);
69e6f123c3SLiu Jingqi }
70e6f123c3SLiu Jingqi 
714586a2cbSLiu Jingqi /*
724586a2cbSLiu Jingqi  * ACPI 6.3: 5.2.27.4 System Locality Latency and Bandwidth Information
734586a2cbSLiu Jingqi  * Structure: Table 5-146
744586a2cbSLiu Jingqi  */
754586a2cbSLiu Jingqi static void build_hmat_lb(GArray *table_data, HMAT_LB_Info *hmat_lb,
764586a2cbSLiu Jingqi                           uint32_t num_initiator, uint32_t num_target,
774586a2cbSLiu Jingqi                           uint32_t *initiator_list)
784586a2cbSLiu Jingqi {
794586a2cbSLiu Jingqi     int i, index;
804586a2cbSLiu Jingqi     HMAT_LB_Data *lb_data;
814586a2cbSLiu Jingqi     uint16_t *entry_list;
824586a2cbSLiu Jingqi     uint32_t base;
834586a2cbSLiu Jingqi     /* Length in bytes for entire structure */
844586a2cbSLiu Jingqi     uint32_t lb_length
854586a2cbSLiu Jingqi         = 32 /* Table length upto and including Entry Base Unit */
864586a2cbSLiu Jingqi         + 4 * num_initiator /* Initiator Proximity Domain List */
874586a2cbSLiu Jingqi         + 4 * num_target /* Target Proximity Domain List */
884586a2cbSLiu Jingqi         + 2 * num_initiator * num_target; /* Latency or Bandwidth Entries */
894586a2cbSLiu Jingqi 
904586a2cbSLiu Jingqi     /* Type */
914586a2cbSLiu Jingqi     build_append_int_noprefix(table_data, 1, 2);
924586a2cbSLiu Jingqi     /* Reserved */
934586a2cbSLiu Jingqi     build_append_int_noprefix(table_data, 0, 2);
944586a2cbSLiu Jingqi     /* Length */
954586a2cbSLiu Jingqi     build_append_int_noprefix(table_data, lb_length, 4);
964586a2cbSLiu Jingqi     /* Flags: Bits [3:0] Memory Hierarchy, Bits[7:4] Reserved */
974586a2cbSLiu Jingqi     assert(!(hmat_lb->hierarchy >> 4));
984586a2cbSLiu Jingqi     build_append_int_noprefix(table_data, hmat_lb->hierarchy, 1);
994586a2cbSLiu Jingqi     /* Data Type */
1004586a2cbSLiu Jingqi     build_append_int_noprefix(table_data, hmat_lb->data_type, 1);
1014586a2cbSLiu Jingqi     /* Reserved */
1024586a2cbSLiu Jingqi     build_append_int_noprefix(table_data, 0, 2);
1034586a2cbSLiu Jingqi     /* Number of Initiator Proximity Domains (s) */
1044586a2cbSLiu Jingqi     build_append_int_noprefix(table_data, num_initiator, 4);
1054586a2cbSLiu Jingqi     /* Number of Target Proximity Domains (t) */
1064586a2cbSLiu Jingqi     build_append_int_noprefix(table_data, num_target, 4);
1074586a2cbSLiu Jingqi     /* Reserved */
1084586a2cbSLiu Jingqi     build_append_int_noprefix(table_data, 0, 4);
1094586a2cbSLiu Jingqi 
1104586a2cbSLiu Jingqi     /* Entry Base Unit */
1114586a2cbSLiu Jingqi     if (hmat_lb->data_type <= HMAT_LB_DATA_WRITE_LATENCY) {
1124586a2cbSLiu Jingqi         /* Convert latency base from nanoseconds to picosecond */
1134586a2cbSLiu Jingqi         base = hmat_lb->base * 1000;
1144586a2cbSLiu Jingqi     } else {
1154586a2cbSLiu Jingqi         /* Convert bandwidth base from Byte to Megabyte */
1164586a2cbSLiu Jingqi         base = hmat_lb->base / MiB;
1174586a2cbSLiu Jingqi     }
1184586a2cbSLiu Jingqi     build_append_int_noprefix(table_data, base, 8);
1194586a2cbSLiu Jingqi 
1204586a2cbSLiu Jingqi     /* Initiator Proximity Domain List */
1214586a2cbSLiu Jingqi     for (i = 0; i < num_initiator; i++) {
1224586a2cbSLiu Jingqi         build_append_int_noprefix(table_data, initiator_list[i], 4);
1234586a2cbSLiu Jingqi     }
1244586a2cbSLiu Jingqi 
1254586a2cbSLiu Jingqi     /* Target Proximity Domain List */
1264586a2cbSLiu Jingqi     for (i = 0; i < num_target; i++) {
1274586a2cbSLiu Jingqi         build_append_int_noprefix(table_data, i, 4);
1284586a2cbSLiu Jingqi     }
1294586a2cbSLiu Jingqi 
1304586a2cbSLiu Jingqi     /* Latency or Bandwidth Entries */
131*b21e2380SMarkus Armbruster     entry_list = g_new0(uint16_t, num_initiator * num_target);
1324586a2cbSLiu Jingqi     for (i = 0; i < hmat_lb->list->len; i++) {
1334586a2cbSLiu Jingqi         lb_data = &g_array_index(hmat_lb->list, HMAT_LB_Data, i);
1344586a2cbSLiu Jingqi         index = lb_data->initiator * num_target + lb_data->target;
1354586a2cbSLiu Jingqi 
1364586a2cbSLiu Jingqi         entry_list[index] = (uint16_t)(lb_data->data / hmat_lb->base);
1374586a2cbSLiu Jingqi     }
1384586a2cbSLiu Jingqi 
1394586a2cbSLiu Jingqi     for (i = 0; i < num_initiator * num_target; i++) {
1404586a2cbSLiu Jingqi         build_append_int_noprefix(table_data, entry_list[i], 2);
1414586a2cbSLiu Jingqi     }
1424586a2cbSLiu Jingqi 
1434586a2cbSLiu Jingqi     g_free(entry_list);
1444586a2cbSLiu Jingqi }
1454586a2cbSLiu Jingqi 
146a9c2b841SLiu Jingqi /* ACPI 6.3: 5.2.27.5 Memory Side Cache Information Structure: Table 5-147 */
147a9c2b841SLiu Jingqi static void build_hmat_cache(GArray *table_data, uint8_t total_levels,
148a9c2b841SLiu Jingqi                              NumaHmatCacheOptions *hmat_cache)
149a9c2b841SLiu Jingqi {
150a9c2b841SLiu Jingqi     /*
151a9c2b841SLiu Jingqi      * Cache Attributes: Bits [3:0] – Total Cache Levels
152a9c2b841SLiu Jingqi      * for this Memory Proximity Domain
153a9c2b841SLiu Jingqi      */
154a9c2b841SLiu Jingqi     uint32_t cache_attr = total_levels;
155a9c2b841SLiu Jingqi 
156a9c2b841SLiu Jingqi     /* Bits [7:4] : Cache Level described in this structure */
157a9c2b841SLiu Jingqi     cache_attr |= (uint32_t) hmat_cache->level << 4;
158a9c2b841SLiu Jingqi 
159a9c2b841SLiu Jingqi     /* Bits [11:8] - Cache Associativity */
160a9c2b841SLiu Jingqi     cache_attr |= (uint32_t) hmat_cache->associativity << 8;
161a9c2b841SLiu Jingqi 
162a9c2b841SLiu Jingqi     /* Bits [15:12] - Write Policy */
163a9c2b841SLiu Jingqi     cache_attr |= (uint32_t) hmat_cache->policy << 12;
164a9c2b841SLiu Jingqi 
165a9c2b841SLiu Jingqi     /* Bits [31:16] - Cache Line size in bytes */
166a9c2b841SLiu Jingqi     cache_attr |= (uint32_t) hmat_cache->line << 16;
167a9c2b841SLiu Jingqi 
168a9c2b841SLiu Jingqi     /* Type */
169a9c2b841SLiu Jingqi     build_append_int_noprefix(table_data, 2, 2);
170a9c2b841SLiu Jingqi     /* Reserved */
171a9c2b841SLiu Jingqi     build_append_int_noprefix(table_data, 0, 2);
172a9c2b841SLiu Jingqi     /* Length */
173a9c2b841SLiu Jingqi     build_append_int_noprefix(table_data, 32, 4);
174a9c2b841SLiu Jingqi     /* Proximity Domain for the Memory */
175a9c2b841SLiu Jingqi     build_append_int_noprefix(table_data, hmat_cache->node_id, 4);
176a9c2b841SLiu Jingqi     /* Reserved */
177a9c2b841SLiu Jingqi     build_append_int_noprefix(table_data, 0, 4);
178a9c2b841SLiu Jingqi     /* Memory Side Cache Size */
179a9c2b841SLiu Jingqi     build_append_int_noprefix(table_data, hmat_cache->size, 8);
180a9c2b841SLiu Jingqi     /* Cache Attributes */
181a9c2b841SLiu Jingqi     build_append_int_noprefix(table_data, cache_attr, 4);
182a9c2b841SLiu Jingqi     /* Reserved */
183a9c2b841SLiu Jingqi     build_append_int_noprefix(table_data, 0, 2);
184a9c2b841SLiu Jingqi     /*
185a9c2b841SLiu Jingqi      * Number of SMBIOS handles (n)
186a9c2b841SLiu Jingqi      * Linux kernel uses Memory Side Cache Information Structure
187a9c2b841SLiu Jingqi      * without SMBIOS entries for now, so set Number of SMBIOS handles
188a9c2b841SLiu Jingqi      * as 0.
189a9c2b841SLiu Jingqi      */
190a9c2b841SLiu Jingqi     build_append_int_noprefix(table_data, 0, 2);
191a9c2b841SLiu Jingqi }
192a9c2b841SLiu Jingqi 
193e6f123c3SLiu Jingqi /* Build HMAT sub table structures */
194e6f123c3SLiu Jingqi static void hmat_build_table_structs(GArray *table_data, NumaState *numa_state)
195e6f123c3SLiu Jingqi {
196e6f123c3SLiu Jingqi     uint16_t flags;
1974586a2cbSLiu Jingqi     uint32_t num_initiator = 0;
1984586a2cbSLiu Jingqi     uint32_t initiator_list[MAX_NODES];
199a9c2b841SLiu Jingqi     int i, hierarchy, type, cache_level, total_levels;
2004586a2cbSLiu Jingqi     HMAT_LB_Info *hmat_lb;
201a9c2b841SLiu Jingqi     NumaHmatCacheOptions *hmat_cache;
202e6f123c3SLiu Jingqi 
203689ef472SIgor Mammedov     build_append_int_noprefix(table_data, 0, 4); /* Reserved */
204689ef472SIgor Mammedov 
205e6f123c3SLiu Jingqi     for (i = 0; i < numa_state->num_nodes; i++) {
206e6f123c3SLiu Jingqi         flags = 0;
207e6f123c3SLiu Jingqi 
208e6f123c3SLiu Jingqi         if (numa_state->nodes[i].initiator < MAX_NODES) {
209e6f123c3SLiu Jingqi             flags |= HMAT_PROXIMITY_INITIATOR_VALID;
210e6f123c3SLiu Jingqi         }
211e6f123c3SLiu Jingqi 
212e6f123c3SLiu Jingqi         build_hmat_mpda(table_data, flags, numa_state->nodes[i].initiator, i);
213e6f123c3SLiu Jingqi     }
2144586a2cbSLiu Jingqi 
2154586a2cbSLiu Jingqi     for (i = 0; i < numa_state->num_nodes; i++) {
2164586a2cbSLiu Jingqi         if (numa_state->nodes[i].has_cpu) {
2174586a2cbSLiu Jingqi             initiator_list[num_initiator++] = i;
2184586a2cbSLiu Jingqi         }
2194586a2cbSLiu Jingqi     }
2204586a2cbSLiu Jingqi 
2214586a2cbSLiu Jingqi     /*
2224586a2cbSLiu Jingqi      * ACPI 6.3: 5.2.27.4 System Locality Latency and Bandwidth Information
2234586a2cbSLiu Jingqi      * Structure: Table 5-146
2244586a2cbSLiu Jingqi      */
2254586a2cbSLiu Jingqi     for (hierarchy = HMAT_LB_MEM_MEMORY;
2264586a2cbSLiu Jingqi          hierarchy <= HMAT_LB_MEM_CACHE_3RD_LEVEL; hierarchy++) {
2274586a2cbSLiu Jingqi         for (type = HMAT_LB_DATA_ACCESS_LATENCY;
2284586a2cbSLiu Jingqi              type <= HMAT_LB_DATA_WRITE_BANDWIDTH; type++) {
2294586a2cbSLiu Jingqi             hmat_lb = numa_state->hmat_lb[hierarchy][type];
2304586a2cbSLiu Jingqi 
2314586a2cbSLiu Jingqi             if (hmat_lb && hmat_lb->list->len) {
2324586a2cbSLiu Jingqi                 build_hmat_lb(table_data, hmat_lb, num_initiator,
2334586a2cbSLiu Jingqi                               numa_state->num_nodes, initiator_list);
2344586a2cbSLiu Jingqi             }
2354586a2cbSLiu Jingqi         }
2364586a2cbSLiu Jingqi     }
237a9c2b841SLiu Jingqi 
238a9c2b841SLiu Jingqi     /*
239a9c2b841SLiu Jingqi      * ACPI 6.3: 5.2.27.5 Memory Side Cache Information Structure:
240a9c2b841SLiu Jingqi      * Table 5-147
241a9c2b841SLiu Jingqi      */
242a9c2b841SLiu Jingqi     for (i = 0; i < numa_state->num_nodes; i++) {
243a9c2b841SLiu Jingqi         total_levels = 0;
244a9c2b841SLiu Jingqi         for (cache_level = 1; cache_level < HMAT_LB_LEVELS; cache_level++) {
245a9c2b841SLiu Jingqi             if (numa_state->hmat_cache[i][cache_level]) {
246a9c2b841SLiu Jingqi                 total_levels++;
247a9c2b841SLiu Jingqi             }
248a9c2b841SLiu Jingqi         }
249a9c2b841SLiu Jingqi         for (cache_level = 0; cache_level <= total_levels; cache_level++) {
250a9c2b841SLiu Jingqi             hmat_cache = numa_state->hmat_cache[i][cache_level];
251a9c2b841SLiu Jingqi             if (hmat_cache) {
252a9c2b841SLiu Jingqi                 build_hmat_cache(table_data, total_levels, hmat_cache);
253a9c2b841SLiu Jingqi             }
254a9c2b841SLiu Jingqi         }
255a9c2b841SLiu Jingqi     }
256e6f123c3SLiu Jingqi }
257e6f123c3SLiu Jingqi 
258602b4582SMarian Postevca void build_hmat(GArray *table_data, BIOSLinker *linker, NumaState *numa_state,
259602b4582SMarian Postevca                 const char *oem_id, const char *oem_table_id)
260e6f123c3SLiu Jingqi {
261689ef472SIgor Mammedov     AcpiTable table = { .sig = "HMAT", .rev = 2,
262689ef472SIgor Mammedov                         .oem_id = oem_id, .oem_table_id = oem_table_id };
263e6f123c3SLiu Jingqi 
264689ef472SIgor Mammedov     acpi_table_begin(&table, table_data);
265e6f123c3SLiu Jingqi     hmat_build_table_structs(table_data, numa_state);
266689ef472SIgor Mammedov     acpi_table_end(linker, &table);
267e6f123c3SLiu Jingqi }
268