@@ -113,6 +113,7 @@ fwts_SOURCES = main.c \
acpi/madt/madt.c \
acpi/mcfg/mcfg.c \
acpi/mchi/mchi.c \
+ acpi/mpam/mpam.c \
acpi/mpst/mpst.c \
acpi/msct/msct.c \
acpi/msdm/msdm.c \
new file mode 100644
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2023 Canonical
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include "fwts.h"
+
+#if defined(FWTS_HAS_ACPI)
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+static fwts_acpi_table_info *table;
+acpi_table_init(MPAM, &table)
+
+static int mpam_test1(fwts_framework *fw)
+{
+ fwts_acpi_mpam_msc_node *node;
+ bool passed = true;
+ uint32_t offset;
+
+ fwts_log_info_verbatim(fw, "MPAM Memory System Resource Partitioning And Monitoring Table:");
+
+ offset = sizeof(fwts_acpi_table_mpam);
+ node = (fwts_acpi_mpam_msc_node *)(table->data + offset);
+ while (offset < table->length) {
+
+ if (fwts_acpi_structure_length_zero(fw, "MPAM", node->length, offset)) {
+ passed = false;
+ break;
+ }
+
+ fwts_log_info_verbatim(fw, "MPAM MSC node:");
+ fwts_log_info_simp_int(fw, " Length: ", node->length);
+ fwts_log_info_simp_int(fw, " Interface type: ", node->interface_type);
+ fwts_log_info_simp_int(fw, " Reserved: ", node->reserved);
+ fwts_log_info_simp_int(fw, " Identifier: ", node->identifier);
+ fwts_log_info_simp_int(fw, " Base address: ", node->base_address);
+ fwts_log_info_simp_int(fw, " MMIO size: ", node->mmio_size);
+ fwts_log_info_simp_int(fw, " Overflow interrupt: ", node->overflow_interrupt);
+ fwts_log_info_simp_int(fw, " Overflow interrupt flags: ", node->overflow_interrupt_flags);
+ fwts_log_info_simp_int(fw, " Reserved1: ", node->reserved1);
+ fwts_log_info_simp_int(fw, " Overflow interrupt affinity: ", node->overflow_interrupt_affinity);
+ fwts_log_info_simp_int(fw, " Error interrupt: ", node->error_interrupt);
+ fwts_log_info_simp_int(fw, " Error interrupt flags: ", node->error_interrupt_flags);
+ fwts_log_info_simp_int(fw, " Reserved2: ", node->reserved2);
+ fwts_log_info_simp_int(fw, " Error interrupt affinity: ", node->error_interrupt_affinity);
+ fwts_log_info_simp_int(fw, " MAX_NRDY_USEC: ", node->max_nrdy_usec);
+ fwts_log_info_simp_int(fw, " Hardware ID of linked device: ", node->hardware_id_linked_device);
+ fwts_log_info_simp_int(fw, " Instance ID of linked device: ", node->instance_id_linked_device);
+ fwts_log_info_simp_int(fw, " Number of resource nodes: ", node->num_resouce_nodes);
+
+ if (node->interface_type != 0 && node->interface_type != 0x0a) {
+ passed = false;
+ fwts_failed(fw, LOG_LEVEL_HIGH,
+ "MPAMBadInterfaceType",
+ "MPAM MSC node interface type must have value with 0 or 0x0a, got "
+ "0x%2.2" PRIx8 " instead", node->interface_type);
+ }
+
+ fwts_acpi_reserved_zero("MPAM", "Reserved", node->reserved, &passed);
+ fwts_acpi_reserved_bits("MPAM", "Overflow interrupt flags", node->overflow_interrupt_flags, 1, 2, &passed);
+ fwts_acpi_reserved_bits("MPAM", "Overflow interrupt flags", node->overflow_interrupt_flags, 5, 31, &passed);
+ fwts_acpi_reserved_zero("MPAM", "Reserved1", node->reserved1, &passed);
+ fwts_acpi_reserved_bits("MPAM", "Error interrupt flags", node->error_interrupt_flags, 1, 2, &passed);
+ fwts_acpi_reserved_bits("MPAM", "Error interrupt flags", node->error_interrupt_flags, 5, 31, &passed);
+ fwts_acpi_reserved_zero("MPAM", "Reserved2", node->reserved2, &passed);
+
+ uint32_t msc_offset = sizeof(fwts_acpi_mpam_msc_node);
+
+ for (uint32_t i = 0; i < node->num_resouce_nodes; i++) {
+ fwts_acpi_mpam_resource_node *res_node = (fwts_acpi_mpam_resource_node *)(table->data + offset + msc_offset);
+ fwts_log_info_verbatim(fw, " List of resource nodes: ");
+ fwts_log_info_simp_int(fw, " Identifier: ", res_node->identifier);
+ fwts_log_info_simp_int(fw, " RIS Index: ", res_node->ris_index);
+ fwts_log_info_simp_int(fw, " Reserved1: ", res_node->reserved1);
+ fwts_log_info_simp_int(fw, " Locator type: ", res_node->locator_type);
+ fwts_log_info_verbatim(fw, " Locator:");
+
+ switch(res_node->locator_type) {
+ case FWTS_MPAM_PROCESSOR_CACHE:
+ fwts_log_info_verbatim(fw, " Processor cache locator:");
+ fwts_hexdump_data_prefix_all(fw, res_node->locator, " ", sizeof(res_node->locator));
+ fwts_acpi_reserved_zero_array(fw, "MPAM", "Locator", res_node->locator + 8, 4, &passed);
+ break;
+ case FWTS_MPAM_MEMORY:
+ fwts_log_info_verbatim(fw, " Memory locator:");
+ fwts_hexdump_data_prefix_all(fw, res_node->locator, " ", sizeof(res_node->locator));
+ fwts_acpi_reserved_zero_array(fw, "MPAM", "Locator", res_node->locator + 8, 4, &passed);
+ break;
+ case FWTS_MPAM_SMMU:
+ fwts_log_info_verbatim(fw, " SMMU locator:");
+ fwts_hexdump_data_prefix_all(fw, res_node->locator, " ", sizeof(res_node->locator));
+ fwts_acpi_reserved_zero_array(fw, "MPAM", "Locator", res_node->locator + 8, 4, &passed);
+ break;
+ case FWTS_MPAM_MEMORY_CACHE:
+ fwts_log_info_verbatim(fw, " Memory-side cache locator:");
+ fwts_hexdump_data_prefix_all(fw, res_node->locator, " ", sizeof(res_node->locator));
+ fwts_acpi_reserved_zero_array(fw, "MPAM", "Locator", res_node->locator, 7, &passed);
+ break;
+ case FWTS_MPAM_ACPI_DEVICE:
+ fwts_log_info_verbatim(fw, " ACPI device locator:");
+ fwts_hexdump_data_prefix_all(fw, res_node->locator, " ", sizeof(res_node->locator));
+ break;
+ case FWTS_MPAM_INTERCONNECT:
+ fwts_log_info_verbatim(fw, " Interconnect locator:");
+ fwts_hexdump_data_prefix_all(fw, res_node->locator, " ", sizeof(res_node->locator));
+ fwts_acpi_reserved_zero_array(fw, "MPAM", "Locator", res_node->locator + 8, 4, &passed);
+ break;
+ case FWTS_MPAM_UNKNOWN:
+ fwts_log_info_verbatim(fw, " Unknown locator:");
+ fwts_hexdump_data_prefix_all(fw, res_node->locator, " ", sizeof(res_node->locator));
+ break;
+ default:
+ passed = false;
+ fwts_failed(fw, LOG_LEVEL_HIGH,
+ "MPAMBadLocaterType",
+ "MPAM MPAM MSC locator type must not have the value 0x06..0xfe, got "
+ "0x%2.2" PRIx8 "instead", res_node->locator_type);
+ break;
+ }
+
+ fwts_log_info_simp_int(fw, " Number of functional dependencies: ", res_node->num_functional_deps);
+
+ fwts_acpi_reserved_zero("MPAM", "Reserved1", res_node->reserved1, &passed);
+
+ msc_offset += sizeof(fwts_acpi_mpam_resource_node);
+
+ for (uint32_t j = 0; j < res_node->num_functional_deps; j++) {
+ fwts_acpi_mpam_func_deps *fun_deps = (fwts_acpi_mpam_func_deps *)(table->data + offset + msc_offset);
+ fwts_log_info_verbatim(fw, " Functional dependency descriptor: ");
+ fwts_log_info_simp_int(fw, " Producer: ", fun_deps->producer);
+ fwts_log_info_simp_int(fw, " Reserved: ", fun_deps->reserved);
+
+ fwts_acpi_reserved_zero("MPAM", "Reserved1", fun_deps->reserved, &passed);
+
+ msc_offset += sizeof(fwts_acpi_mpam_func_deps);
+ }
+ }
+
+ if (node->length > msc_offset) {
+ fwts_log_info_verbatim(fw, " Resource-specific data: ");
+ fwts_hexdump_data_prefix_all(fw, (uint8_t *)(table->data + offset + msc_offset), " ", node->length - msc_offset);
+ }
+
+ offset += node->length;
+
+ node = (fwts_acpi_mpam_msc_node *)(table->data + offset);
+ fwts_log_nl(fw);
+ }
+
+ if (passed)
+ fwts_passed(fw, "No issues found in MPAM table.");
+
+ return FWTS_OK;
+}
+
+static fwts_framework_minor_test mpam_tests[] = {
+ { mpam_test1, "Validate MPAM table." },
+ { NULL, NULL }
+};
+
+static fwts_framework_ops mpam_ops = {
+ .description = "MPAM Memory System Resource Partitioning And Monitoring Table test.",
+ .init = MPAM_init,
+ .minor_tests = mpam_tests
+};
+
+FWTS_REGISTER("mpam", &mpam_ops, FWTS_TEST_ANYTIME, FWTS_FLAG_BATCH | FWTS_FLAG_ACPI)
+
+#endif
@@ -2522,4 +2522,59 @@ typedef struct {
uint64_t mem_block_len;
} __attribute__ ((packed)) fwts_acpi_table_ivmd;
+/*
+ * ACPI MPAM(Memory System Resource Partitioning And Monitoring)
+ * https://developer.arm.com/documentation/ddi0598/latest/
+ */
+typedef enum {
+ FWTS_MPAM_PROCESSOR_CACHE = 0,
+ FWTS_MPAM_MEMORY = 1,
+ FWTS_MPAM_SMMU = 2,
+ FWTS_MPAM_MEMORY_CACHE = 3,
+ FWTS_MPAM_ACPI_DEVICE = 4,
+ FWTS_MPAM_INTERCONNECT = 5,
+ FWTS_MPAM_UNKNOWN = 0xFF
+} fwts_mpam_location_types;
+
+typedef struct
+{
+ uint32_t producer;
+ uint32_t reserved;
+} __attribute__ ((packed)) fwts_acpi_mpam_func_deps;
+
+typedef struct {
+ uint32_t identifier;
+ uint8_t ris_index;
+ uint16_t reserved1;
+ uint8_t locator_type;
+ uint8_t locator[12];
+ uint32_t num_functional_deps;
+} __attribute__ ((packed)) fwts_acpi_mpam_resource_node;
+
+typedef struct
+{
+ uint16_t length;
+ uint8_t interface_type;
+ uint8_t reserved;
+ uint32_t identifier;
+ uint64_t base_address;
+ uint32_t mmio_size;
+ uint32_t overflow_interrupt;
+ uint32_t overflow_interrupt_flags;
+ uint32_t reserved1;
+ uint32_t overflow_interrupt_affinity;
+ uint32_t error_interrupt;
+ uint32_t error_interrupt_flags;
+ uint32_t reserved2;
+ uint32_t error_interrupt_affinity;
+ uint32_t max_nrdy_usec;
+ uint64_t hardware_id_linked_device;
+ uint32_t instance_id_linked_device;
+ uint32_t num_resouce_nodes;
+} __attribute__ ((packed)) fwts_acpi_mpam_msc_node;
+
+typedef struct {
+ fwts_acpi_table_header header;
+} __attribute__ ((packed)) fwts_acpi_table_mpam;
+
#endif
BugLink: https://bugs.launchpad.net/fwts/+bug/2023358 New table on ACPI specification 6.4 The MPAM(Memory Resource Partitioning and Monitoring table) specification link: https://developer.arm.com/documentation/ddi0598/latest/ Signed-off-by: Ivan Hu <ivan.hu@canonical.com> --- src/Makefile.am | 1 + src/acpi/mpam/mpam.c | 183 ++++++++++++++++++++++++++++++++++++ src/lib/include/fwts_acpi.h | 55 +++++++++++ 3 files changed, 239 insertions(+) create mode 100644 src/acpi/mpam/mpam.c