33 * Copyright (c) 2025, Intel Corporation.
44 *
55 * Memory Range and Region Mapping (MRRM) structure
6+ *
7+ * Parse and report the platform's MRRM table in /sys.
68 */
79
810#define pr_fmt (fmt ) "acpi/mrrm: " fmt
911
1012#include <linux/acpi.h>
1113#include <linux/init.h>
14+ #include <linux/string.h>
15+ #include <linux/sysfs.h>
1216
1317static int max_mem_region = - ENOENT ;
1418
@@ -18,25 +22,161 @@ int acpi_mrrm_max_mem_region(void)
1822 return max_mem_region ;
1923}
2024
25+ struct mrrm_mem_range_entry {
26+ u64 base ;
27+ u64 length ;
28+ int node ;
29+ u8 local_region_id ;
30+ u8 remote_region_id ;
31+ };
32+
33+ static struct mrrm_mem_range_entry * mrrm_mem_range_entry ;
34+ static u32 mrrm_mem_entry_num ;
35+
36+ static int get_node_num (struct mrrm_mem_range_entry * e )
37+ {
38+ unsigned int nid ;
39+
40+ for_each_online_node (nid ) {
41+ for (int z = 0 ; z < MAX_NR_ZONES ; z ++ ) {
42+ struct zone * zone = NODE_DATA (nid )-> node_zones + z ;
43+
44+ if (!populated_zone (zone ))
45+ continue ;
46+ if (zone_intersects (zone , PHYS_PFN (e -> base ), PHYS_PFN (e -> length )))
47+ return zone_to_nid (zone );
48+ }
49+ }
50+
51+ return - ENOENT ;
52+ }
53+
2154static __init int acpi_parse_mrrm (struct acpi_table_header * table )
2255{
56+ struct acpi_mrrm_mem_range_entry * mre_entry ;
2357 struct acpi_table_mrrm * mrrm ;
58+ void * mre , * mrrm_end ;
59+ int mre_count = 0 ;
2460
2561 mrrm = (struct acpi_table_mrrm * )table ;
2662 if (!mrrm )
2763 return - ENODEV ;
2864
65+ if (mrrm -> flags & ACPI_MRRM_FLAGS_REGION_ASSIGNMENT_OS )
66+ return - EOPNOTSUPP ;
67+
68+ mrrm_end = (void * )mrrm + mrrm -> header .length - 1 ;
69+ mre = (void * )mrrm + sizeof (struct acpi_table_mrrm );
70+ while (mre < mrrm_end ) {
71+ mre_entry = mre ;
72+ mre_count ++ ;
73+ mre += mre_entry -> header .length ;
74+ }
75+ if (!mre_count ) {
76+ pr_info (FW_BUG "No ranges listed in MRRM table\n" );
77+ return - EINVAL ;
78+ }
79+
80+ mrrm_mem_range_entry = kmalloc_array (mre_count , sizeof (* mrrm_mem_range_entry ),
81+ GFP_KERNEL | __GFP_ZERO );
82+ if (!mrrm_mem_range_entry )
83+ return - ENOMEM ;
84+
85+ mre = (void * )mrrm + sizeof (struct acpi_table_mrrm );
86+ while (mre < mrrm_end ) {
87+ struct mrrm_mem_range_entry * e ;
88+
89+ mre_entry = mre ;
90+ e = mrrm_mem_range_entry + mrrm_mem_entry_num ;
91+
92+ e -> base = mre_entry -> addr_base ;
93+ e -> length = mre_entry -> addr_len ;
94+ e -> node = get_node_num (e );
95+
96+ if (mre_entry -> region_id_flags & ACPI_MRRM_VALID_REGION_ID_FLAGS_LOCAL )
97+ e -> local_region_id = mre_entry -> local_region_id ;
98+ else
99+ e -> local_region_id = -1 ;
100+ if (mre_entry -> region_id_flags & ACPI_MRRM_VALID_REGION_ID_FLAGS_REMOTE )
101+ e -> remote_region_id = mre_entry -> remote_region_id ;
102+ else
103+ e -> remote_region_id = -1 ;
104+
105+ mrrm_mem_entry_num ++ ;
106+ mre += mre_entry -> header .length ;
107+ }
108+
29109 max_mem_region = mrrm -> max_mem_region ;
30110
31111 return 0 ;
32112}
33113
114+ #define RANGE_ATTR (name , fmt ) \
115+ static ssize_t name##_show(struct kobject *kobj, \
116+ struct kobj_attribute *attr, char *buf) \
117+ { \
118+ struct mrrm_mem_range_entry *mre; \
119+ const char *kname = kobject_name(kobj); \
120+ int n, ret; \
121+ \
122+ ret = kstrtoint(kname + 5, 10, &n); \
123+ if (ret) \
124+ return ret; \
125+ \
126+ mre = mrrm_mem_range_entry + n; \
127+ \
128+ return sysfs_emit(buf, fmt, mre->name); \
129+ } \
130+ static struct kobj_attribute name##_attr = __ATTR_RO(name)
131+
132+ RANGE_ATTR (base , "0x%llx\n" );
133+ RANGE_ATTR (length , "0x%llx\n" );
134+ RANGE_ATTR (node , "%d\n" );
135+ RANGE_ATTR (local_region_id , "%d\n" );
136+ RANGE_ATTR (remote_region_id , "%d\n" );
137+
138+ static struct attribute * memory_range_attrs [] = {
139+ & base_attr .attr ,
140+ & length_attr .attr ,
141+ & node_attr .attr ,
142+ & local_region_id_attr .attr ,
143+ & remote_region_id_attr .attr ,
144+ NULL
145+ };
146+
147+ ATTRIBUTE_GROUPS (memory_range );
148+
149+ static __init int add_boot_memory_ranges (void )
150+ {
151+ struct kobject * pkobj , * kobj ;
152+ int ret = - EINVAL ;
153+ char * name ;
154+
155+ pkobj = kobject_create_and_add ("memory_ranges" , acpi_kobj );
156+
157+ for (int i = 0 ; i < mrrm_mem_entry_num ; i ++ ) {
158+ name = kasprintf (GFP_KERNEL , "range%d" , i );
159+ if (!name )
160+ break ;
161+
162+ kobj = kobject_create_and_add (name , pkobj );
163+
164+ ret = sysfs_create_groups (kobj , memory_range_groups );
165+ if (ret )
166+ return ret ;
167+ }
168+
169+ return ret ;
170+ }
171+
34172static __init int mrrm_init (void )
35173{
36174 int ret ;
37175
38176 ret = acpi_table_parse (ACPI_SIG_MRRM , acpi_parse_mrrm );
177+ if (ret < 0 )
178+ return ret ;
39179
40- return ret ;
180+ return add_boot_memory_ranges () ;
41181}
42182device_initcall (mrrm_init );
0 commit comments