3
3
* Copyright (c) 2025, Intel Corporation.
4
4
*
5
5
* Memory Range and Region Mapping (MRRM) structure
6
+ *
7
+ * Parse and report the platform's MRRM table in /sys.
6
8
*/
7
9
8
10
#define pr_fmt (fmt ) "acpi/mrrm: " fmt
9
11
10
12
#include <linux/acpi.h>
11
13
#include <linux/init.h>
14
+ #include <linux/string.h>
15
+ #include <linux/sysfs.h>
12
16
13
17
static int max_mem_region = - ENOENT ;
14
18
@@ -18,25 +22,161 @@ int acpi_mrrm_max_mem_region(void)
18
22
return max_mem_region ;
19
23
}
20
24
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
+
21
54
static __init int acpi_parse_mrrm (struct acpi_table_header * table )
22
55
{
56
+ struct acpi_mrrm_mem_range_entry * mre_entry ;
23
57
struct acpi_table_mrrm * mrrm ;
58
+ void * mre , * mrrm_end ;
59
+ int mre_count = 0 ;
24
60
25
61
mrrm = (struct acpi_table_mrrm * )table ;
26
62
if (!mrrm )
27
63
return - ENODEV ;
28
64
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
+
29
109
max_mem_region = mrrm -> max_mem_region ;
30
110
31
111
return 0 ;
32
112
}
33
113
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
+
34
172
static __init int mrrm_init (void )
35
173
{
36
174
int ret ;
37
175
38
176
ret = acpi_table_parse (ACPI_SIG_MRRM , acpi_parse_mrrm );
177
+ if (ret < 0 )
178
+ return ret ;
39
179
40
- return ret ;
180
+ return add_boot_memory_ranges () ;
41
181
}
42
182
device_initcall (mrrm_init );
0 commit comments