Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/firmware/memmap.c
15109 views
1
/*
2
* linux/drivers/firmware/memmap.c
3
* Copyright (C) 2008 SUSE LINUX Products GmbH
4
* by Bernhard Walle <[email protected]>
5
*
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License v2.0 as published by
8
* the Free Software Foundation
9
*
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
14
*
15
*/
16
17
#include <linux/string.h>
18
#include <linux/firmware-map.h>
19
#include <linux/kernel.h>
20
#include <linux/module.h>
21
#include <linux/types.h>
22
#include <linux/bootmem.h>
23
#include <linux/slab.h>
24
25
/*
26
* Data types ------------------------------------------------------------------
27
*/
28
29
/*
30
* Firmware map entry. Because firmware memory maps are flat and not
31
* hierarchical, it's ok to organise them in a linked list. No parent
32
* information is necessary as for the resource tree.
33
*/
34
struct firmware_map_entry {
35
/*
36
* start and end must be u64 rather than resource_size_t, because e820
37
* resources can lie at addresses above 4G.
38
*/
39
u64 start; /* start of the memory range */
40
u64 end; /* end of the memory range (incl.) */
41
const char *type; /* type of the memory range */
42
struct list_head list; /* entry for the linked list */
43
struct kobject kobj; /* kobject for each entry */
44
};
45
46
/*
47
* Forward declarations --------------------------------------------------------
48
*/
49
static ssize_t memmap_attr_show(struct kobject *kobj,
50
struct attribute *attr, char *buf);
51
static ssize_t start_show(struct firmware_map_entry *entry, char *buf);
52
static ssize_t end_show(struct firmware_map_entry *entry, char *buf);
53
static ssize_t type_show(struct firmware_map_entry *entry, char *buf);
54
55
/*
56
* Static data -----------------------------------------------------------------
57
*/
58
59
struct memmap_attribute {
60
struct attribute attr;
61
ssize_t (*show)(struct firmware_map_entry *entry, char *buf);
62
};
63
64
static struct memmap_attribute memmap_start_attr = __ATTR_RO(start);
65
static struct memmap_attribute memmap_end_attr = __ATTR_RO(end);
66
static struct memmap_attribute memmap_type_attr = __ATTR_RO(type);
67
68
/*
69
* These are default attributes that are added for every memmap entry.
70
*/
71
static struct attribute *def_attrs[] = {
72
&memmap_start_attr.attr,
73
&memmap_end_attr.attr,
74
&memmap_type_attr.attr,
75
NULL
76
};
77
78
static const struct sysfs_ops memmap_attr_ops = {
79
.show = memmap_attr_show,
80
};
81
82
static struct kobj_type memmap_ktype = {
83
.sysfs_ops = &memmap_attr_ops,
84
.default_attrs = def_attrs,
85
};
86
87
/*
88
* Registration functions ------------------------------------------------------
89
*/
90
91
/*
92
* Firmware memory map entries. No locking is needed because the
93
* firmware_map_add() and firmware_map_add_early() functions are called
94
* in firmware initialisation code in one single thread of execution.
95
*/
96
static LIST_HEAD(map_entries);
97
98
/**
99
* firmware_map_add_entry() - Does the real work to add a firmware memmap entry.
100
* @start: Start of the memory range.
101
* @end: End of the memory range (inclusive).
102
* @type: Type of the memory range.
103
* @entry: Pre-allocated (either kmalloc() or bootmem allocator), uninitialised
104
* entry.
105
*
106
* Common implementation of firmware_map_add() and firmware_map_add_early()
107
* which expects a pre-allocated struct firmware_map_entry.
108
**/
109
static int firmware_map_add_entry(u64 start, u64 end,
110
const char *type,
111
struct firmware_map_entry *entry)
112
{
113
BUG_ON(start > end);
114
115
entry->start = start;
116
entry->end = end;
117
entry->type = type;
118
INIT_LIST_HEAD(&entry->list);
119
kobject_init(&entry->kobj, &memmap_ktype);
120
121
list_add_tail(&entry->list, &map_entries);
122
123
return 0;
124
}
125
126
/*
127
* Add memmap entry on sysfs
128
*/
129
static int add_sysfs_fw_map_entry(struct firmware_map_entry *entry)
130
{
131
static int map_entries_nr;
132
static struct kset *mmap_kset;
133
134
if (!mmap_kset) {
135
mmap_kset = kset_create_and_add("memmap", NULL, firmware_kobj);
136
if (!mmap_kset)
137
return -ENOMEM;
138
}
139
140
entry->kobj.kset = mmap_kset;
141
if (kobject_add(&entry->kobj, NULL, "%d", map_entries_nr++))
142
kobject_put(&entry->kobj);
143
144
return 0;
145
}
146
147
/**
148
* firmware_map_add_hotplug() - Adds a firmware mapping entry when we do
149
* memory hotplug.
150
* @start: Start of the memory range.
151
* @end: End of the memory range (inclusive).
152
* @type: Type of the memory range.
153
*
154
* Adds a firmware mapping entry. This function is for memory hotplug, it is
155
* similar to function firmware_map_add_early(). The only difference is that
156
* it will create the syfs entry dynamically.
157
*
158
* Returns 0 on success, or -ENOMEM if no memory could be allocated.
159
**/
160
int __meminit firmware_map_add_hotplug(u64 start, u64 end, const char *type)
161
{
162
struct firmware_map_entry *entry;
163
164
entry = kzalloc(sizeof(struct firmware_map_entry), GFP_ATOMIC);
165
if (!entry)
166
return -ENOMEM;
167
168
firmware_map_add_entry(start, end, type, entry);
169
/* create the memmap entry */
170
add_sysfs_fw_map_entry(entry);
171
172
return 0;
173
}
174
175
/**
176
* firmware_map_add_early() - Adds a firmware mapping entry.
177
* @start: Start of the memory range.
178
* @end: End of the memory range (inclusive).
179
* @type: Type of the memory range.
180
*
181
* Adds a firmware mapping entry. This function uses the bootmem allocator
182
* for memory allocation.
183
*
184
* That function must be called before late_initcall.
185
*
186
* Returns 0 on success, or -ENOMEM if no memory could be allocated.
187
**/
188
int __init firmware_map_add_early(u64 start, u64 end, const char *type)
189
{
190
struct firmware_map_entry *entry;
191
192
entry = alloc_bootmem(sizeof(struct firmware_map_entry));
193
if (WARN_ON(!entry))
194
return -ENOMEM;
195
196
return firmware_map_add_entry(start, end, type, entry);
197
}
198
199
/*
200
* Sysfs functions -------------------------------------------------------------
201
*/
202
203
static ssize_t start_show(struct firmware_map_entry *entry, char *buf)
204
{
205
return snprintf(buf, PAGE_SIZE, "0x%llx\n",
206
(unsigned long long)entry->start);
207
}
208
209
static ssize_t end_show(struct firmware_map_entry *entry, char *buf)
210
{
211
return snprintf(buf, PAGE_SIZE, "0x%llx\n",
212
(unsigned long long)entry->end);
213
}
214
215
static ssize_t type_show(struct firmware_map_entry *entry, char *buf)
216
{
217
return snprintf(buf, PAGE_SIZE, "%s\n", entry->type);
218
}
219
220
#define to_memmap_attr(_attr) container_of(_attr, struct memmap_attribute, attr)
221
#define to_memmap_entry(obj) container_of(obj, struct firmware_map_entry, kobj)
222
223
static ssize_t memmap_attr_show(struct kobject *kobj,
224
struct attribute *attr, char *buf)
225
{
226
struct firmware_map_entry *entry = to_memmap_entry(kobj);
227
struct memmap_attribute *memmap_attr = to_memmap_attr(attr);
228
229
return memmap_attr->show(entry, buf);
230
}
231
232
/*
233
* Initialises stuff and adds the entries in the map_entries list to
234
* sysfs. Important is that firmware_map_add() and firmware_map_add_early()
235
* must be called before late_initcall. That's just because that function
236
* is called as late_initcall() function, which means that if you call
237
* firmware_map_add() or firmware_map_add_early() afterwards, the entries
238
* are not added to sysfs.
239
*/
240
static int __init memmap_init(void)
241
{
242
struct firmware_map_entry *entry;
243
244
list_for_each_entry(entry, &map_entries, list)
245
add_sysfs_fw_map_entry(entry);
246
247
return 0;
248
}
249
late_initcall(memmap_init);
250
251
252