From 18eb45b67544b995a8a6f48a72b816fd75776f52 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 15 Apr 2025 16:20:29 -0700 Subject: [PATCH 1/7] ACPI: tables: Add __nonstring annotations for unterminated strings When a character array without a terminating NUL character has a static initializer, GCC 15's -Wunterminated-string-initialization will only warn if the array lacks the "nonstring" attribute[1]. Mark the 4-byte ACPI identifier arrays with __nonstring (and the new __nonstring_array) to correctly identify the char arrays as "not C strings" and thereby eliminate the many warnings like this: In file included from include/acpi/actbl.h:371, from include/acpi/acpi.h:26, from include/linux/acpi.h:26, from drivers/acpi/tables.c:19: include/acpi/actbl1.h:30:33: warning: initializer-string for array of 'char' truncates NUL terminator but destination lacks 'nonstring' attribute (5 chars into 4 available) [-Wunterminated-string-initialization] 30 | #define ACPI_SIG_BERT "BERT" /* Boot Error Record Table */ | ^~~~~~ drivers/acpi/tables.c:400:9: note: in expansion of macro 'ACPI_SIG_BERT' 400 | ACPI_SIG_BERT, ACPI_SIG_BGRT, ACPI_SIG_CPEP, ACPI_SIG_ECDT, | ^~~~~~~~~~~~~ Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117178 [1] Signed-off-by: Kees Cook Link: https://patch.msgid.link/20250415232028.work.843-kees@kernel.org Signed-off-by: Rafael J. Wysocki --- drivers/acpi/tables.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index 2295abbecd14..0a9ade7117bd 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -396,7 +396,7 @@ static u8 __init acpi_table_checksum(u8 *buffer, u32 length) } /* All but ACPI_SIG_RSDP and ACPI_SIG_FACS: */ -static const char table_sigs[][ACPI_NAMESEG_SIZE] __initconst = { +static const char table_sigs[][ACPI_NAMESEG_SIZE] __nonstring_array __initconst = { ACPI_SIG_BERT, ACPI_SIG_BGRT, ACPI_SIG_CPEP, ACPI_SIG_ECDT, ACPI_SIG_EINJ, ACPI_SIG_ERST, ACPI_SIG_HEST, ACPI_SIG_MADT, ACPI_SIG_MSCT, ACPI_SIG_SBST, ACPI_SIG_SLIT, ACPI_SIG_SRAT, From b9020bdb9f76b58117f9902db3047693fd12b11b Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Mon, 5 May 2025 10:38:17 -0700 Subject: [PATCH 2/7] ACPI: MRRM: Minimal parse of ACPI MRRM table The resctrl file system code needs to know how many region tags are supported. Parse the ACPI MRRM table and save the max_mem_region value. Provide a function for resctrl to collect that value. Signed-off-by: Tony Luck Link: https://patch.msgid.link/20250505173819.419271-2-tony.luck@intel.com Signed-off-by: Rafael J. Wysocki --- arch/x86/Kconfig | 1 + drivers/acpi/Kconfig | 3 +++ drivers/acpi/Makefile | 1 + drivers/acpi/acpi_mrrm.c | 42 ++++++++++++++++++++++++++++++++++++++++ include/linux/acpi.h | 9 +++++++++ 5 files changed, 56 insertions(+) create mode 100644 drivers/acpi/acpi_mrrm.c diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 4b9f378e05f6..0e43069082df 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -38,6 +38,7 @@ config X86_64 select ARCH_HAS_ELFCORE_COMPAT select ZONE_DMA32 select EXECMEM if DYNAMIC_FTRACE + select ACPI_MRRM if ACPI config FORCE_DYNAMIC_FTRACE def_bool y diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 7f10aa38269d..7bc40c2735ac 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -576,6 +576,9 @@ config ACPI_FFH Enable this feature if you want to set up and install the FFH Address Space handler to handle FFH OpRegion in the firmware. +config ACPI_MRRM + bool + source "drivers/acpi/pmic/Kconfig" config ACPI_VIOT diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 797070fc9a3f..d1b0affb844f 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -66,6 +66,7 @@ acpi-$(CONFIG_ACPI_WATCHDOG) += acpi_watchdog.o acpi-$(CONFIG_ACPI_PRMT) += prmt.o acpi-$(CONFIG_ACPI_PCC) += acpi_pcc.o acpi-$(CONFIG_ACPI_FFH) += acpi_ffh.o +acpi-$(CONFIG_ACPI_MRRM) += acpi_mrrm.o # Address translation acpi-$(CONFIG_ACPI_ADXL) += acpi_adxl.o diff --git a/drivers/acpi/acpi_mrrm.c b/drivers/acpi/acpi_mrrm.c new file mode 100644 index 000000000000..ab8022e58da5 --- /dev/null +++ b/drivers/acpi/acpi_mrrm.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2025, Intel Corporation. + * + * Memory Range and Region Mapping (MRRM) structure + */ + +#define pr_fmt(fmt) "acpi/mrrm: " fmt + +#include +#include + +static int max_mem_region = -ENOENT; + +/* Access for use by resctrl file system */ +int acpi_mrrm_max_mem_region(void) +{ + return max_mem_region; +} + +static __init int acpi_parse_mrrm(struct acpi_table_header *table) +{ + struct acpi_table_mrrm *mrrm; + + mrrm = (struct acpi_table_mrrm *)table; + if (!mrrm) + return -ENODEV; + + max_mem_region = mrrm->max_mem_region; + + return 0; +} + +static __init int mrrm_init(void) +{ + int ret; + + ret = acpi_table_parse(ACPI_SIG_MRRM, acpi_parse_mrrm); + + return ret; +} +device_initcall(mrrm_init); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 3f2e93ed9730..c409f4cecb09 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -772,6 +772,10 @@ int acpi_get_local_u64_address(acpi_handle handle, u64 *addr); int acpi_get_local_address(acpi_handle handle, u32 *addr); const char *acpi_get_subsystem_id(acpi_handle handle); +#ifdef CONFIG_ACPI_MRRM +int acpi_mrrm_max_mem_region(void); +#endif + #else /* !CONFIG_ACPI */ #define acpi_disabled 1 @@ -1092,6 +1096,11 @@ static inline acpi_handle acpi_get_processor_handle(int cpu) return NULL; } +static inline int acpi_mrrm_max_mem_region(void) +{ + return -ENOENT; +} + #endif /* !CONFIG_ACPI */ #ifdef CONFIG_ACPI_HMAT From 04f53540f791f160b42710ea64aeba8edc9753cd Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Mon, 5 May 2025 10:38:18 -0700 Subject: [PATCH 3/7] ACPI: MRRM: Add /sys files to describe memory ranges Perf and resctrl users need an enumeration of which memory addresses are bound to which "region" tag. Parse the ACPI MRRM table and add /sys entries for each memory range describing base address, length, NUMA node, and which region tags apply for same-socket and cross-socket access. Signed-off-by: Tony Luck Link: https://patch.msgid.link/20250505173819.419271-3-tony.luck@intel.com Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_mrrm.c | 142 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 141 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/acpi_mrrm.c b/drivers/acpi/acpi_mrrm.c index ab8022e58da5..2f22f013959a 100644 --- a/drivers/acpi/acpi_mrrm.c +++ b/drivers/acpi/acpi_mrrm.c @@ -3,12 +3,16 @@ * Copyright (c) 2025, Intel Corporation. * * Memory Range and Region Mapping (MRRM) structure + * + * Parse and report the platform's MRRM table in /sys. */ #define pr_fmt(fmt) "acpi/mrrm: " fmt #include #include +#include +#include static int max_mem_region = -ENOENT; @@ -18,25 +22,161 @@ int acpi_mrrm_max_mem_region(void) return max_mem_region; } +struct mrrm_mem_range_entry { + u64 base; + u64 length; + int node; + u8 local_region_id; + u8 remote_region_id; +}; + +static struct mrrm_mem_range_entry *mrrm_mem_range_entry; +static u32 mrrm_mem_entry_num; + +static int get_node_num(struct mrrm_mem_range_entry *e) +{ + unsigned int nid; + + for_each_online_node(nid) { + for (int z = 0; z < MAX_NR_ZONES; z++) { + struct zone *zone = NODE_DATA(nid)->node_zones + z; + + if (!populated_zone(zone)) + continue; + if (zone_intersects(zone, PHYS_PFN(e->base), PHYS_PFN(e->length))) + return zone_to_nid(zone); + } + } + + return -ENOENT; +} + static __init int acpi_parse_mrrm(struct acpi_table_header *table) { + struct acpi_mrrm_mem_range_entry *mre_entry; struct acpi_table_mrrm *mrrm; + void *mre, *mrrm_end; + int mre_count = 0; mrrm = (struct acpi_table_mrrm *)table; if (!mrrm) return -ENODEV; + if (mrrm->flags & ACPI_MRRM_FLAGS_REGION_ASSIGNMENT_OS) + return -EOPNOTSUPP; + + mrrm_end = (void *)mrrm + mrrm->header.length - 1; + mre = (void *)mrrm + sizeof(struct acpi_table_mrrm); + while (mre < mrrm_end) { + mre_entry = mre; + mre_count++; + mre += mre_entry->header.length; + } + if (!mre_count) { + pr_info(FW_BUG "No ranges listed in MRRM table\n"); + return -EINVAL; + } + + mrrm_mem_range_entry = kmalloc_array(mre_count, sizeof(*mrrm_mem_range_entry), + GFP_KERNEL | __GFP_ZERO); + if (!mrrm_mem_range_entry) + return -ENOMEM; + + mre = (void *)mrrm + sizeof(struct acpi_table_mrrm); + while (mre < mrrm_end) { + struct mrrm_mem_range_entry *e; + + mre_entry = mre; + e = mrrm_mem_range_entry + mrrm_mem_entry_num; + + e->base = mre_entry->addr_base; + e->length = mre_entry->addr_len; + e->node = get_node_num(e); + + if (mre_entry->region_id_flags & ACPI_MRRM_VALID_REGION_ID_FLAGS_LOCAL) + e->local_region_id = mre_entry->local_region_id; + else + e->local_region_id = -1; + if (mre_entry->region_id_flags & ACPI_MRRM_VALID_REGION_ID_FLAGS_REMOTE) + e->remote_region_id = mre_entry->remote_region_id; + else + e->remote_region_id = -1; + + mrrm_mem_entry_num++; + mre += mre_entry->header.length; + } + max_mem_region = mrrm->max_mem_region; return 0; } +#define RANGE_ATTR(name, fmt) \ +static ssize_t name##_show(struct kobject *kobj, \ + struct kobj_attribute *attr, char *buf) \ +{ \ + struct mrrm_mem_range_entry *mre; \ + const char *kname = kobject_name(kobj); \ + int n, ret; \ + \ + ret = kstrtoint(kname + 5, 10, &n); \ + if (ret) \ + return ret; \ + \ + mre = mrrm_mem_range_entry + n; \ + \ + return sysfs_emit(buf, fmt, mre->name); \ +} \ +static struct kobj_attribute name##_attr = __ATTR_RO(name) + +RANGE_ATTR(base, "0x%llx\n"); +RANGE_ATTR(length, "0x%llx\n"); +RANGE_ATTR(node, "%d\n"); +RANGE_ATTR(local_region_id, "%d\n"); +RANGE_ATTR(remote_region_id, "%d\n"); + +static struct attribute *memory_range_attrs[] = { + &base_attr.attr, + &length_attr.attr, + &node_attr.attr, + &local_region_id_attr.attr, + &remote_region_id_attr.attr, + NULL +}; + +ATTRIBUTE_GROUPS(memory_range); + +static __init int add_boot_memory_ranges(void) +{ + struct kobject *pkobj, *kobj; + int ret = -EINVAL; + char *name; + + pkobj = kobject_create_and_add("memory_ranges", acpi_kobj); + + for (int i = 0; i < mrrm_mem_entry_num; i++) { + name = kasprintf(GFP_KERNEL, "range%d", i); + if (!name) + break; + + kobj = kobject_create_and_add(name, pkobj); + + ret = sysfs_create_groups(kobj, memory_range_groups); + if (ret) + return ret; + } + + return ret; +} + static __init int mrrm_init(void) { int ret; ret = acpi_table_parse(ACPI_SIG_MRRM, acpi_parse_mrrm); + if (ret < 0) + return ret; - return ret; + return add_boot_memory_ranges(); } device_initcall(mrrm_init); From 0a07a5af234b8cc6c2982e5c1e7bdff806902e16 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Mon, 5 May 2025 10:38:19 -0700 Subject: [PATCH 4/7] ACPI: Add documentation for exposing MRRM data Initial implementation provides enumeration of the address ranges NUMA node numbers, and BIOS assigned region IDs for each range. Signed-off-by: Tony Luck Link: https://patch.msgid.link/20250505173819.419271-4-tony.luck@intel.com Signed-off-by: Rafael J. Wysocki --- Documentation/ABI/testing/sysfs-firmware-acpi | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-firmware-acpi b/Documentation/ABI/testing/sysfs-firmware-acpi index 5249ad5a96d9..f4de60c4134d 100644 --- a/Documentation/ABI/testing/sysfs-firmware-acpi +++ b/Documentation/ABI/testing/sysfs-firmware-acpi @@ -248,3 +248,24 @@ Description: # cat ff_pwr_btn 7 enabled +What: /sys/firmware/acpi/memory_ranges/rangeX +Date: February 2025 +Contact: Tony Luck +Description: + On systems with the ACPI MRRM table reports the parameters for + each range. + + base: Starting system physical address. + + length: Length of this range in bytes. + + node: NUMA node that this range belongs to. Negative numbers + indicate that the node number could not be determined (e.g + for an address range that is reserved for future hot add of + memory). + + local_region_id: ID associated with access by agents + local to this range of addresses. + + remote_region_id: ID associated with access by agents + non-local to this range of addresses. From 6b2ffe2bb0157e1295f920090071c985e89ce893 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 31 Mar 2025 10:23:11 +0300 Subject: [PATCH 5/7] ACPI: VIOT: Remove (explicitly) unused header The fwnode.h is not supposed to be used by the drivers as it has the definitions for the core parts for different device property provider implementations. Drop it. Note, that fwnode API for drivers is provided in property.h which is included here. Signed-off-by: Andy Shevchenko Reviewed-by: Jean-Philippe Brucker Link: https://patch.msgid.link/20250331072311.3987967-1-andriy.shevchenko@linux.intel.com Signed-off-by: Rafael J. Wysocki --- drivers/acpi/viot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/viot.c b/drivers/acpi/viot.c index 2aa69a2fba73..c13a20365c2c 100644 --- a/drivers/acpi/viot.c +++ b/drivers/acpi/viot.c @@ -19,11 +19,11 @@ #define pr_fmt(fmt) "ACPI: VIOT: " fmt #include -#include #include #include #include #include +#include struct viot_iommu { /* Node offset within the table */ From 8e66be071bd4d44e8870a37d2e1a9109c47ef22e Mon Sep 17 00:00:00 2001 From: Bartosz Szczepanek Date: Wed, 23 Apr 2025 08:56:36 +0000 Subject: [PATCH 6/7] ACPI: tables: Improve logging around acpi_initialize_tables() Emit a warning that includes return code in a readable format. Example: ACPI: Failed to initialize tables, status=0x5 (AE_NOT_FOUND) No other functional changes intended. Signed-off-by: Bartosz Szczepanek Link: https://patch.msgid.link/20250423085637.38658-1-bsz@amazon.de [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/tables.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index 0a9ade7117bd..fa9bb8c8ce95 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -719,8 +719,12 @@ int __init acpi_locate_initial_tables(void) } status = acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status)) { + const char *msg = acpi_format_exception(status); + + pr_warn("Failed to initialize tables, status=0x%x (%s)", status, msg); return -EINVAL; + } return 0; } From 059717c2ba1f745f35f4bbb8991e408c12031f1e Mon Sep 17 00:00:00 2001 From: Anil S Keshavamurthy Date: Fri, 23 May 2025 13:20:01 -0400 Subject: [PATCH 7/7] ACPI: MRRM: Fix default max memory region Per the spec, the default max memory region must be 1 covering all system memory. When platform does not provide ACPI MRRM table or when CONFIG_ACPI is opted out, the acpi_mrrm_max_mem_region() function defaults to returning 1 region complying to RDT spec. Signed-off-by: Anil S Keshavamurthy Reviewed-by: Tony Luck Link: https://patch.msgid.link/20250523172001.1761634-1-anil.s.keshavamurthy@intel.com Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_mrrm.c | 3 ++- include/linux/acpi.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/acpi_mrrm.c b/drivers/acpi/acpi_mrrm.c index 2f22f013959a..26c1a4e6b6ec 100644 --- a/drivers/acpi/acpi_mrrm.c +++ b/drivers/acpi/acpi_mrrm.c @@ -14,7 +14,8 @@ #include #include -static int max_mem_region = -ENOENT; +/* Default assume one memory region covering all system memory, per the spec */ +static int max_mem_region = 1; /* Access for use by resctrl file system */ int acpi_mrrm_max_mem_region(void) diff --git a/include/linux/acpi.h b/include/linux/acpi.h index c409f4cecb09..d9ba7b4fa2cd 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -1098,7 +1098,7 @@ static inline acpi_handle acpi_get_processor_handle(int cpu) static inline int acpi_mrrm_max_mem_region(void) { - return -ENOENT; + return 1; } #endif /* !CONFIG_ACPI */