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