mirror of
https://github.com/torvalds/linux.git
synced 2026-05-24 07:03:03 +02:00
Merge branch 'acpi-tables'
Merge updates related to the handling of static (data-only) ACPI tables for 6.16-rc1: - Add __nonstring annotations for unterminated strings in the static ACPI tables parsing code (Kees Cook). - Add support for parsing the MRRM ACPI table and sysfs files to describe memory regions listed in it (Tony Luck, Anil Keshavamurthy). - Remove an (explicitly) unused header file include from the VIOT ACPI table parser file (Andy Shevchenko). - Improve logging around acpi_initialize_tables() (Bartosz Szczepanek). * acpi-tables: ACPI: MRRM: Fix default max memory region ACPI: tables: Improve logging around acpi_initialize_tables() ACPI: VIOT: Remove (explicitly) unused header ACPI: Add documentation for exposing MRRM data ACPI: MRRM: Add /sys files to describe memory ranges ACPI: MRRM: Minimal parse of ACPI MRRM table ACPI: tables: Add __nonstring annotations for unterminated strings
This commit is contained in:
commit
5349b0051b
|
|
@ -248,3 +248,24 @@ Description:
|
|||
# cat ff_pwr_btn
|
||||
7 enabled
|
||||
|
||||
What: /sys/firmware/acpi/memory_ranges/rangeX
|
||||
Date: February 2025
|
||||
Contact: Tony Luck <tony.luck@intel.com>
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
183
drivers/acpi/acpi_mrrm.c
Normal file
183
drivers/acpi/acpi_mrrm.c
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* 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 <linux/acpi.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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 add_boot_memory_ranges();
|
||||
}
|
||||
device_initcall(mrrm_init);
|
||||
|
|
@ -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,
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,11 +19,11 @@
|
|||
#define pr_fmt(fmt) "ACPI: VIOT: " fmt
|
||||
|
||||
#include <linux/acpi_viot.h>
|
||||
#include <linux/fwnode.h>
|
||||
#include <linux/iommu.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
|
||||
struct viot_iommu {
|
||||
/* Node offset within the table */
|
||||
|
|
|
|||
|
|
@ -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 1;
|
||||
}
|
||||
|
||||
#endif /* !CONFIG_ACPI */
|
||||
|
||||
#ifdef CONFIG_ACPI_HMAT
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user