1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * linux/drivers/firmware/memmap.c 4 * Copyright (C) 2008 SUSE LINUX Products GmbH 5 * by Bernhard Walle <bernhard.walle@gmx.de> 6 */ 7 8 #include <linux/string.h> 9 #include <linux/firmware-map.h> 10 #include <linux/kernel.h> 11 #include <linux/module.h> 12 #include <linux/types.h> 13 #include <linux/memblock.h> 14 #include <linux/slab.h> 15 #include <linux/mm.h> 16 17 /* 18 * Data types ------------------------------------------------------------------ 19 */ 20 21 /* 22 * Firmware map entry. Because firmware memory maps are flat and not 23 * hierarchical, it's ok to organise them in a linked list. No parent 24 * information is necessary as for the resource tree. 25 */ 26 struct firmware_map_entry { 27 /* 28 * start and end must be u64 rather than resource_size_t, because e820 29 * resources can lie at addresses above 4G. 30 */ 31 u64 start; /* start of the memory range */ 32 u64 end; /* end of the memory range (incl.) */ 33 const char *type; /* type of the memory range */ 34 struct list_head list; /* entry for the linked list */ 35 struct kobject kobj; /* kobject for each entry */ 36 }; 37 38 /* 39 * Forward declarations -------------------------------------------------------- 40 */ 41 static ssize_t memmap_attr_show(struct kobject *kobj, 42 struct attribute *attr, char *buf); 43 static ssize_t start_show(struct firmware_map_entry *entry, char *buf); 44 static ssize_t end_show(struct firmware_map_entry *entry, char *buf); 45 static ssize_t type_show(struct firmware_map_entry *entry, char *buf); 46 47 static struct firmware_map_entry * __meminit 48 firmware_map_find_entry(u64 start, u64 end, const char *type); 49 50 /* 51 * Static data ----------------------------------------------------------------- 52 */ 53 54 struct memmap_attribute { 55 struct attribute attr; 56 ssize_t (*show)(struct firmware_map_entry *entry, char *buf); 57 }; 58 59 static struct memmap_attribute memmap_start_attr = __ATTR_RO(start); 60 static struct memmap_attribute memmap_end_attr = __ATTR_RO(end); 61 static struct memmap_attribute memmap_type_attr = __ATTR_RO(type); 62 63 /* 64 * These are default attributes that are added for every memmap entry. 65 */ 66 static struct attribute *def_attrs[] = { 67 &memmap_start_attr.attr, 68 &memmap_end_attr.attr, 69 &memmap_type_attr.attr, 70 NULL 71 }; 72 ATTRIBUTE_GROUPS(def); 73 74 static const struct sysfs_ops memmap_attr_ops = { 75 .show = memmap_attr_show, 76 }; 77 78 /* Firmware memory map entries. */ 79 static LIST_HEAD(map_entries); 80 static DEFINE_SPINLOCK(map_entries_lock); 81 82 /* 83 * For memory hotplug, there is no way to free memory map entries allocated 84 * by boot mem after the system is up. So when we hot-remove memory whose 85 * map entry is allocated by bootmem, we need to remember the storage and 86 * reuse it when the memory is hot-added again. 87 */ 88 static LIST_HEAD(map_entries_bootmem); 89 static DEFINE_SPINLOCK(map_entries_bootmem_lock); 90 91 92 static inline struct firmware_map_entry * 93 to_memmap_entry(struct kobject *kobj) 94 { 95 return container_of(kobj, struct firmware_map_entry, kobj); 96 } 97 98 static void __meminit release_firmware_map_entry(struct kobject *kobj) 99 { 100 struct firmware_map_entry *entry = to_memmap_entry(kobj); 101 102 if (PageReserved(virt_to_page(entry))) { 103 /* 104 * Remember the storage allocated by bootmem, and reuse it when 105 * the memory is hot-added again. The entry will be added to 106 * map_entries_bootmem here, and deleted from &map_entries in 107 * firmware_map_remove_entry(). 108 */ 109 spin_lock(&map_entries_bootmem_lock); 110 list_add(&entry->list, &map_entries_bootmem); 111 spin_unlock(&map_entries_bootmem_lock); 112 113 return; 114 } 115 116 kfree(entry); 117 } 118 119 static const struct kobj_type memmap_ktype = { 120 .release = release_firmware_map_entry, 121 .sysfs_ops = &memmap_attr_ops, 122 .default_groups = def_groups, 123 }; 124 125 /* 126 * Registration functions ------------------------------------------------------ 127 */ 128 129 /** 130 * firmware_map_add_entry() - Does the real work to add a firmware memmap entry. 131 * @start: Start of the memory range. 132 * @end: End of the memory range (exclusive). 133 * @type: Type of the memory range. 134 * @entry: Pre-allocated (either kmalloc() or bootmem allocator), uninitialised 135 * entry. 136 * 137 * Common implementation of firmware_map_add() and firmware_map_add_early() 138 * which expects a pre-allocated struct firmware_map_entry. 139 * 140 * Return: 0 always 141 */ 142 static int firmware_map_add_entry(u64 start, u64 end, 143 const char *type, 144 struct firmware_map_entry *entry) 145 { 146 BUG_ON(start > end); 147 148 entry->start = start; 149 entry->end = end - 1; 150 entry->type = type; 151 INIT_LIST_HEAD(&entry->list); 152 kobject_init(&entry->kobj, &memmap_ktype); 153 154 spin_lock(&map_entries_lock); 155 list_add_tail(&entry->list, &map_entries); 156 spin_unlock(&map_entries_lock); 157 158 return 0; 159 } 160 161 /** 162 * firmware_map_remove_entry() - Does the real work to remove a firmware 163 * memmap entry. 164 * @entry: removed entry. 165 * 166 * The caller must hold map_entries_lock, and release it properly. 167 */ 168 static inline void firmware_map_remove_entry(struct firmware_map_entry *entry) 169 { 170 list_del(&entry->list); 171 } 172 173 /* 174 * Add memmap entry on sysfs 175 */ 176 static int add_sysfs_fw_map_entry(struct firmware_map_entry *entry) 177 { 178 static int map_entries_nr; 179 static struct kset *mmap_kset; 180 181 if (entry->kobj.state_in_sysfs) 182 return -EEXIST; 183 184 if (!mmap_kset) { 185 mmap_kset = kset_create_and_add("memmap", NULL, firmware_kobj); 186 if (!mmap_kset) 187 return -ENOMEM; 188 } 189 190 entry->kobj.kset = mmap_kset; 191 if (kobject_add(&entry->kobj, NULL, "%d", map_entries_nr++)) 192 kobject_put(&entry->kobj); 193 194 return 0; 195 } 196 197 /* 198 * Remove memmap entry on sysfs 199 */ 200 static inline void remove_sysfs_fw_map_entry(struct firmware_map_entry *entry) 201 { 202 kobject_put(&entry->kobj); 203 } 204 205 /** 206 * firmware_map_find_entry_in_list() - Search memmap entry in a given list. 207 * @start: Start of the memory range. 208 * @end: End of the memory range (exclusive). 209 * @type: Type of the memory range. 210 * @list: In which to find the entry. 211 * 212 * This function is to find the memmap entey of a given memory range in a 213 * given list. The caller must hold map_entries_lock, and must not release 214 * the lock until the processing of the returned entry has completed. 215 * 216 * Return: Pointer to the entry to be found on success, or NULL on failure. 217 */ 218 static struct firmware_map_entry * __meminit 219 firmware_map_find_entry_in_list(u64 start, u64 end, const char *type, 220 struct list_head *list) 221 { 222 struct firmware_map_entry *entry; 223 224 list_for_each_entry(entry, list, list) 225 if ((entry->start == start) && (entry->end == end) && 226 (!strcmp(entry->type, type))) { 227 return entry; 228 } 229 230 return NULL; 231 } 232 233 /** 234 * firmware_map_find_entry() - Search memmap entry in map_entries. 235 * @start: Start of the memory range. 236 * @end: End of the memory range (exclusive). 237 * @type: Type of the memory range. 238 * 239 * This function is to find the memmap entey of a given memory range. 240 * The caller must hold map_entries_lock, and must not release the lock 241 * until the processing of the returned entry has completed. 242 * 243 * Return: Pointer to the entry to be found on success, or NULL on failure. 244 */ 245 static struct firmware_map_entry * __meminit 246 firmware_map_find_entry(u64 start, u64 end, const char *type) 247 { 248 return firmware_map_find_entry_in_list(start, end, type, &map_entries); 249 } 250 251 /** 252 * firmware_map_find_entry_bootmem() - Search memmap entry in map_entries_bootmem. 253 * @start: Start of the memory range. 254 * @end: End of the memory range (exclusive). 255 * @type: Type of the memory range. 256 * 257 * This function is similar to firmware_map_find_entry except that it find the 258 * given entry in map_entries_bootmem. 259 * 260 * Return: Pointer to the entry to be found on success, or NULL on failure. 261 */ 262 static struct firmware_map_entry * __meminit 263 firmware_map_find_entry_bootmem(u64 start, u64 end, const char *type) 264 { 265 return firmware_map_find_entry_in_list(start, end, type, 266 &map_entries_bootmem); 267 } 268 269 /** 270 * firmware_map_add_hotplug() - Adds a firmware mapping entry when we do 271 * memory hotplug. 272 * @start: Start of the memory range. 273 * @end: End of the memory range (exclusive) 274 * @type: Type of the memory range. 275 * 276 * Adds a firmware mapping entry. This function is for memory hotplug, it is 277 * similar to function firmware_map_add_early(). The only difference is that 278 * it will create the syfs entry dynamically. 279 * 280 * Return: 0 on success, or -ENOMEM if no memory could be allocated. 281 */ 282 int __meminit firmware_map_add_hotplug(u64 start, u64 end, const char *type) 283 { 284 struct firmware_map_entry *entry; 285 286 entry = firmware_map_find_entry(start, end - 1, type); 287 if (entry) 288 return 0; 289 290 entry = firmware_map_find_entry_bootmem(start, end - 1, type); 291 if (!entry) { 292 entry = kzalloc(sizeof(struct firmware_map_entry), GFP_ATOMIC); 293 if (!entry) 294 return -ENOMEM; 295 } else { 296 /* Reuse storage allocated by bootmem. */ 297 spin_lock(&map_entries_bootmem_lock); 298 list_del(&entry->list); 299 spin_unlock(&map_entries_bootmem_lock); 300 301 memset(entry, 0, sizeof(*entry)); 302 } 303 304 firmware_map_add_entry(start, end, type, entry); 305 /* create the memmap entry */ 306 add_sysfs_fw_map_entry(entry); 307 308 return 0; 309 } 310 311 /** 312 * firmware_map_add_early() - Adds a firmware mapping entry. 313 * @start: Start of the memory range. 314 * @end: End of the memory range. 315 * @type: Type of the memory range. 316 * 317 * Adds a firmware mapping entry. This function uses the bootmem allocator 318 * for memory allocation. 319 * 320 * That function must be called before late_initcall. 321 * 322 * Return: 0 on success, or -ENOMEM if no memory could be allocated. 323 */ 324 int __init firmware_map_add_early(u64 start, u64 end, const char *type) 325 { 326 struct firmware_map_entry *entry; 327 328 entry = memblock_alloc(sizeof(struct firmware_map_entry), 329 SMP_CACHE_BYTES); 330 if (WARN_ON(!entry)) 331 return -ENOMEM; 332 333 return firmware_map_add_entry(start, end, type, entry); 334 } 335 336 /** 337 * firmware_map_remove() - remove a firmware mapping entry 338 * @start: Start of the memory range. 339 * @end: End of the memory range. 340 * @type: Type of the memory range. 341 * 342 * removes a firmware mapping entry. 343 * 344 * Return: 0 on success, or -EINVAL if no entry. 345 */ 346 int __meminit firmware_map_remove(u64 start, u64 end, const char *type) 347 { 348 struct firmware_map_entry *entry; 349 350 spin_lock(&map_entries_lock); 351 entry = firmware_map_find_entry(start, end - 1, type); 352 if (!entry) { 353 spin_unlock(&map_entries_lock); 354 return -EINVAL; 355 } 356 357 firmware_map_remove_entry(entry); 358 spin_unlock(&map_entries_lock); 359 360 /* remove the memmap entry */ 361 remove_sysfs_fw_map_entry(entry); 362 363 return 0; 364 } 365 366 /* 367 * Sysfs functions ------------------------------------------------------------- 368 */ 369 370 static ssize_t start_show(struct firmware_map_entry *entry, char *buf) 371 { 372 return snprintf(buf, PAGE_SIZE, "0x%llx\n", 373 (unsigned long long)entry->start); 374 } 375 376 static ssize_t end_show(struct firmware_map_entry *entry, char *buf) 377 { 378 return snprintf(buf, PAGE_SIZE, "0x%llx\n", 379 (unsigned long long)entry->end); 380 } 381 382 static ssize_t type_show(struct firmware_map_entry *entry, char *buf) 383 { 384 return snprintf(buf, PAGE_SIZE, "%s\n", entry->type); 385 } 386 387 static inline struct memmap_attribute *to_memmap_attr(struct attribute *attr) 388 { 389 return container_of(attr, struct memmap_attribute, attr); 390 } 391 392 static ssize_t memmap_attr_show(struct kobject *kobj, 393 struct attribute *attr, char *buf) 394 { 395 struct firmware_map_entry *entry = to_memmap_entry(kobj); 396 struct memmap_attribute *memmap_attr = to_memmap_attr(attr); 397 398 return memmap_attr->show(entry, buf); 399 } 400 401 /* 402 * Initialises stuff and adds the entries in the map_entries list to 403 * sysfs. Important is that firmware_map_add() and firmware_map_add_early() 404 * must be called before late_initcall. That's just because that function 405 * is called as late_initcall() function, which means that if you call 406 * firmware_map_add() or firmware_map_add_early() afterwards, the entries 407 * are not added to sysfs. 408 */ 409 static int __init firmware_memmap_init(void) 410 { 411 struct firmware_map_entry *entry; 412 413 list_for_each_entry(entry, &map_entries, list) 414 add_sysfs_fw_map_entry(entry); 415 416 return 0; 417 } 418 late_initcall(firmware_memmap_init); 419 420