18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/drivers/firmware/memmap.c 48c2ecf20Sopenharmony_ci * Copyright (C) 2008 SUSE LINUX Products GmbH 58c2ecf20Sopenharmony_ci * by Bernhard Walle <bernhard.walle@gmx.de> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/string.h> 98c2ecf20Sopenharmony_ci#include <linux/firmware-map.h> 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/types.h> 138c2ecf20Sopenharmony_ci#include <linux/memblock.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci#include <linux/mm.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci/* 188c2ecf20Sopenharmony_ci * Data types ------------------------------------------------------------------ 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* 228c2ecf20Sopenharmony_ci * Firmware map entry. Because firmware memory maps are flat and not 238c2ecf20Sopenharmony_ci * hierarchical, it's ok to organise them in a linked list. No parent 248c2ecf20Sopenharmony_ci * information is necessary as for the resource tree. 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_cistruct firmware_map_entry { 278c2ecf20Sopenharmony_ci /* 288c2ecf20Sopenharmony_ci * start and end must be u64 rather than resource_size_t, because e820 298c2ecf20Sopenharmony_ci * resources can lie at addresses above 4G. 308c2ecf20Sopenharmony_ci */ 318c2ecf20Sopenharmony_ci u64 start; /* start of the memory range */ 328c2ecf20Sopenharmony_ci u64 end; /* end of the memory range (incl.) */ 338c2ecf20Sopenharmony_ci const char *type; /* type of the memory range */ 348c2ecf20Sopenharmony_ci struct list_head list; /* entry for the linked list */ 358c2ecf20Sopenharmony_ci struct kobject kobj; /* kobject for each entry */ 368c2ecf20Sopenharmony_ci}; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* 398c2ecf20Sopenharmony_ci * Forward declarations -------------------------------------------------------- 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_cistatic ssize_t memmap_attr_show(struct kobject *kobj, 428c2ecf20Sopenharmony_ci struct attribute *attr, char *buf); 438c2ecf20Sopenharmony_cistatic ssize_t start_show(struct firmware_map_entry *entry, char *buf); 448c2ecf20Sopenharmony_cistatic ssize_t end_show(struct firmware_map_entry *entry, char *buf); 458c2ecf20Sopenharmony_cistatic ssize_t type_show(struct firmware_map_entry *entry, char *buf); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic struct firmware_map_entry * __meminit 488c2ecf20Sopenharmony_cifirmware_map_find_entry(u64 start, u64 end, const char *type); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/* 518c2ecf20Sopenharmony_ci * Static data ----------------------------------------------------------------- 528c2ecf20Sopenharmony_ci */ 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistruct memmap_attribute { 558c2ecf20Sopenharmony_ci struct attribute attr; 568c2ecf20Sopenharmony_ci ssize_t (*show)(struct firmware_map_entry *entry, char *buf); 578c2ecf20Sopenharmony_ci}; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic struct memmap_attribute memmap_start_attr = __ATTR_RO(start); 608c2ecf20Sopenharmony_cistatic struct memmap_attribute memmap_end_attr = __ATTR_RO(end); 618c2ecf20Sopenharmony_cistatic struct memmap_attribute memmap_type_attr = __ATTR_RO(type); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/* 648c2ecf20Sopenharmony_ci * These are default attributes that are added for every memmap entry. 658c2ecf20Sopenharmony_ci */ 668c2ecf20Sopenharmony_cistatic struct attribute *def_attrs[] = { 678c2ecf20Sopenharmony_ci &memmap_start_attr.attr, 688c2ecf20Sopenharmony_ci &memmap_end_attr.attr, 698c2ecf20Sopenharmony_ci &memmap_type_attr.attr, 708c2ecf20Sopenharmony_ci NULL 718c2ecf20Sopenharmony_ci}; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic const struct sysfs_ops memmap_attr_ops = { 748c2ecf20Sopenharmony_ci .show = memmap_attr_show, 758c2ecf20Sopenharmony_ci}; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/* Firmware memory map entries. */ 788c2ecf20Sopenharmony_cistatic LIST_HEAD(map_entries); 798c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(map_entries_lock); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci/* 828c2ecf20Sopenharmony_ci * For memory hotplug, there is no way to free memory map entries allocated 838c2ecf20Sopenharmony_ci * by boot mem after the system is up. So when we hot-remove memory whose 848c2ecf20Sopenharmony_ci * map entry is allocated by bootmem, we need to remember the storage and 858c2ecf20Sopenharmony_ci * reuse it when the memory is hot-added again. 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_cistatic LIST_HEAD(map_entries_bootmem); 888c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(map_entries_bootmem_lock); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic inline struct firmware_map_entry * 928c2ecf20Sopenharmony_cito_memmap_entry(struct kobject *kobj) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci return container_of(kobj, struct firmware_map_entry, kobj); 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic void __meminit release_firmware_map_entry(struct kobject *kobj) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci struct firmware_map_entry *entry = to_memmap_entry(kobj); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci if (PageReserved(virt_to_page(entry))) { 1028c2ecf20Sopenharmony_ci /* 1038c2ecf20Sopenharmony_ci * Remember the storage allocated by bootmem, and reuse it when 1048c2ecf20Sopenharmony_ci * the memory is hot-added again. The entry will be added to 1058c2ecf20Sopenharmony_ci * map_entries_bootmem here, and deleted from &map_entries in 1068c2ecf20Sopenharmony_ci * firmware_map_remove_entry(). 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_ci spin_lock(&map_entries_bootmem_lock); 1098c2ecf20Sopenharmony_ci list_add(&entry->list, &map_entries_bootmem); 1108c2ecf20Sopenharmony_ci spin_unlock(&map_entries_bootmem_lock); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci return; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci kfree(entry); 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic struct kobj_type __refdata memmap_ktype = { 1198c2ecf20Sopenharmony_ci .release = release_firmware_map_entry, 1208c2ecf20Sopenharmony_ci .sysfs_ops = &memmap_attr_ops, 1218c2ecf20Sopenharmony_ci .default_attrs = def_attrs, 1228c2ecf20Sopenharmony_ci}; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci/* 1258c2ecf20Sopenharmony_ci * Registration functions ------------------------------------------------------ 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci/** 1298c2ecf20Sopenharmony_ci * firmware_map_add_entry() - Does the real work to add a firmware memmap entry. 1308c2ecf20Sopenharmony_ci * @start: Start of the memory range. 1318c2ecf20Sopenharmony_ci * @end: End of the memory range (exclusive). 1328c2ecf20Sopenharmony_ci * @type: Type of the memory range. 1338c2ecf20Sopenharmony_ci * @entry: Pre-allocated (either kmalloc() or bootmem allocator), uninitialised 1348c2ecf20Sopenharmony_ci * entry. 1358c2ecf20Sopenharmony_ci * 1368c2ecf20Sopenharmony_ci * Common implementation of firmware_map_add() and firmware_map_add_early() 1378c2ecf20Sopenharmony_ci * which expects a pre-allocated struct firmware_map_entry. 1388c2ecf20Sopenharmony_ci * 1398c2ecf20Sopenharmony_ci * Return: 0 always 1408c2ecf20Sopenharmony_ci */ 1418c2ecf20Sopenharmony_cistatic int firmware_map_add_entry(u64 start, u64 end, 1428c2ecf20Sopenharmony_ci const char *type, 1438c2ecf20Sopenharmony_ci struct firmware_map_entry *entry) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci BUG_ON(start > end); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci entry->start = start; 1488c2ecf20Sopenharmony_ci entry->end = end - 1; 1498c2ecf20Sopenharmony_ci entry->type = type; 1508c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&entry->list); 1518c2ecf20Sopenharmony_ci kobject_init(&entry->kobj, &memmap_ktype); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci spin_lock(&map_entries_lock); 1548c2ecf20Sopenharmony_ci list_add_tail(&entry->list, &map_entries); 1558c2ecf20Sopenharmony_ci spin_unlock(&map_entries_lock); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci return 0; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci/** 1618c2ecf20Sopenharmony_ci * firmware_map_remove_entry() - Does the real work to remove a firmware 1628c2ecf20Sopenharmony_ci * memmap entry. 1638c2ecf20Sopenharmony_ci * @entry: removed entry. 1648c2ecf20Sopenharmony_ci * 1658c2ecf20Sopenharmony_ci * The caller must hold map_entries_lock, and release it properly. 1668c2ecf20Sopenharmony_ci */ 1678c2ecf20Sopenharmony_cistatic inline void firmware_map_remove_entry(struct firmware_map_entry *entry) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci list_del(&entry->list); 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci/* 1738c2ecf20Sopenharmony_ci * Add memmap entry on sysfs 1748c2ecf20Sopenharmony_ci */ 1758c2ecf20Sopenharmony_cistatic int add_sysfs_fw_map_entry(struct firmware_map_entry *entry) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci static int map_entries_nr; 1788c2ecf20Sopenharmony_ci static struct kset *mmap_kset; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci if (entry->kobj.state_in_sysfs) 1818c2ecf20Sopenharmony_ci return -EEXIST; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (!mmap_kset) { 1848c2ecf20Sopenharmony_ci mmap_kset = kset_create_and_add("memmap", NULL, firmware_kobj); 1858c2ecf20Sopenharmony_ci if (!mmap_kset) 1868c2ecf20Sopenharmony_ci return -ENOMEM; 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci entry->kobj.kset = mmap_kset; 1908c2ecf20Sopenharmony_ci if (kobject_add(&entry->kobj, NULL, "%d", map_entries_nr++)) 1918c2ecf20Sopenharmony_ci kobject_put(&entry->kobj); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci return 0; 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci/* 1978c2ecf20Sopenharmony_ci * Remove memmap entry on sysfs 1988c2ecf20Sopenharmony_ci */ 1998c2ecf20Sopenharmony_cistatic inline void remove_sysfs_fw_map_entry(struct firmware_map_entry *entry) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci kobject_put(&entry->kobj); 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci/** 2058c2ecf20Sopenharmony_ci * firmware_map_find_entry_in_list() - Search memmap entry in a given list. 2068c2ecf20Sopenharmony_ci * @start: Start of the memory range. 2078c2ecf20Sopenharmony_ci * @end: End of the memory range (exclusive). 2088c2ecf20Sopenharmony_ci * @type: Type of the memory range. 2098c2ecf20Sopenharmony_ci * @list: In which to find the entry. 2108c2ecf20Sopenharmony_ci * 2118c2ecf20Sopenharmony_ci * This function is to find the memmap entey of a given memory range in a 2128c2ecf20Sopenharmony_ci * given list. The caller must hold map_entries_lock, and must not release 2138c2ecf20Sopenharmony_ci * the lock until the processing of the returned entry has completed. 2148c2ecf20Sopenharmony_ci * 2158c2ecf20Sopenharmony_ci * Return: Pointer to the entry to be found on success, or NULL on failure. 2168c2ecf20Sopenharmony_ci */ 2178c2ecf20Sopenharmony_cistatic struct firmware_map_entry * __meminit 2188c2ecf20Sopenharmony_cifirmware_map_find_entry_in_list(u64 start, u64 end, const char *type, 2198c2ecf20Sopenharmony_ci struct list_head *list) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci struct firmware_map_entry *entry; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci list_for_each_entry(entry, list, list) 2248c2ecf20Sopenharmony_ci if ((entry->start == start) && (entry->end == end) && 2258c2ecf20Sopenharmony_ci (!strcmp(entry->type, type))) { 2268c2ecf20Sopenharmony_ci return entry; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci return NULL; 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci/** 2338c2ecf20Sopenharmony_ci * firmware_map_find_entry() - Search memmap entry in map_entries. 2348c2ecf20Sopenharmony_ci * @start: Start of the memory range. 2358c2ecf20Sopenharmony_ci * @end: End of the memory range (exclusive). 2368c2ecf20Sopenharmony_ci * @type: Type of the memory range. 2378c2ecf20Sopenharmony_ci * 2388c2ecf20Sopenharmony_ci * This function is to find the memmap entey of a given memory range. 2398c2ecf20Sopenharmony_ci * The caller must hold map_entries_lock, and must not release the lock 2408c2ecf20Sopenharmony_ci * until the processing of the returned entry has completed. 2418c2ecf20Sopenharmony_ci * 2428c2ecf20Sopenharmony_ci * Return: Pointer to the entry to be found on success, or NULL on failure. 2438c2ecf20Sopenharmony_ci */ 2448c2ecf20Sopenharmony_cistatic struct firmware_map_entry * __meminit 2458c2ecf20Sopenharmony_cifirmware_map_find_entry(u64 start, u64 end, const char *type) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci return firmware_map_find_entry_in_list(start, end, type, &map_entries); 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci/** 2518c2ecf20Sopenharmony_ci * firmware_map_find_entry_bootmem() - Search memmap entry in map_entries_bootmem. 2528c2ecf20Sopenharmony_ci * @start: Start of the memory range. 2538c2ecf20Sopenharmony_ci * @end: End of the memory range (exclusive). 2548c2ecf20Sopenharmony_ci * @type: Type of the memory range. 2558c2ecf20Sopenharmony_ci * 2568c2ecf20Sopenharmony_ci * This function is similar to firmware_map_find_entry except that it find the 2578c2ecf20Sopenharmony_ci * given entry in map_entries_bootmem. 2588c2ecf20Sopenharmony_ci * 2598c2ecf20Sopenharmony_ci * Return: Pointer to the entry to be found on success, or NULL on failure. 2608c2ecf20Sopenharmony_ci */ 2618c2ecf20Sopenharmony_cistatic struct firmware_map_entry * __meminit 2628c2ecf20Sopenharmony_cifirmware_map_find_entry_bootmem(u64 start, u64 end, const char *type) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci return firmware_map_find_entry_in_list(start, end, type, 2658c2ecf20Sopenharmony_ci &map_entries_bootmem); 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci/** 2698c2ecf20Sopenharmony_ci * firmware_map_add_hotplug() - Adds a firmware mapping entry when we do 2708c2ecf20Sopenharmony_ci * memory hotplug. 2718c2ecf20Sopenharmony_ci * @start: Start of the memory range. 2728c2ecf20Sopenharmony_ci * @end: End of the memory range (exclusive) 2738c2ecf20Sopenharmony_ci * @type: Type of the memory range. 2748c2ecf20Sopenharmony_ci * 2758c2ecf20Sopenharmony_ci * Adds a firmware mapping entry. This function is for memory hotplug, it is 2768c2ecf20Sopenharmony_ci * similar to function firmware_map_add_early(). The only difference is that 2778c2ecf20Sopenharmony_ci * it will create the syfs entry dynamically. 2788c2ecf20Sopenharmony_ci * 2798c2ecf20Sopenharmony_ci * Return: 0 on success, or -ENOMEM if no memory could be allocated. 2808c2ecf20Sopenharmony_ci */ 2818c2ecf20Sopenharmony_ciint __meminit firmware_map_add_hotplug(u64 start, u64 end, const char *type) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci struct firmware_map_entry *entry; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci entry = firmware_map_find_entry(start, end - 1, type); 2868c2ecf20Sopenharmony_ci if (entry) 2878c2ecf20Sopenharmony_ci return 0; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci entry = firmware_map_find_entry_bootmem(start, end - 1, type); 2908c2ecf20Sopenharmony_ci if (!entry) { 2918c2ecf20Sopenharmony_ci entry = kzalloc(sizeof(struct firmware_map_entry), GFP_ATOMIC); 2928c2ecf20Sopenharmony_ci if (!entry) 2938c2ecf20Sopenharmony_ci return -ENOMEM; 2948c2ecf20Sopenharmony_ci } else { 2958c2ecf20Sopenharmony_ci /* Reuse storage allocated by bootmem. */ 2968c2ecf20Sopenharmony_ci spin_lock(&map_entries_bootmem_lock); 2978c2ecf20Sopenharmony_ci list_del(&entry->list); 2988c2ecf20Sopenharmony_ci spin_unlock(&map_entries_bootmem_lock); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci memset(entry, 0, sizeof(*entry)); 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci firmware_map_add_entry(start, end, type, entry); 3048c2ecf20Sopenharmony_ci /* create the memmap entry */ 3058c2ecf20Sopenharmony_ci add_sysfs_fw_map_entry(entry); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci return 0; 3088c2ecf20Sopenharmony_ci} 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci/** 3118c2ecf20Sopenharmony_ci * firmware_map_add_early() - Adds a firmware mapping entry. 3128c2ecf20Sopenharmony_ci * @start: Start of the memory range. 3138c2ecf20Sopenharmony_ci * @end: End of the memory range. 3148c2ecf20Sopenharmony_ci * @type: Type of the memory range. 3158c2ecf20Sopenharmony_ci * 3168c2ecf20Sopenharmony_ci * Adds a firmware mapping entry. This function uses the bootmem allocator 3178c2ecf20Sopenharmony_ci * for memory allocation. 3188c2ecf20Sopenharmony_ci * 3198c2ecf20Sopenharmony_ci * That function must be called before late_initcall. 3208c2ecf20Sopenharmony_ci * 3218c2ecf20Sopenharmony_ci * Return: 0 on success, or -ENOMEM if no memory could be allocated. 3228c2ecf20Sopenharmony_ci */ 3238c2ecf20Sopenharmony_ciint __init firmware_map_add_early(u64 start, u64 end, const char *type) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci struct firmware_map_entry *entry; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci entry = memblock_alloc(sizeof(struct firmware_map_entry), 3288c2ecf20Sopenharmony_ci SMP_CACHE_BYTES); 3298c2ecf20Sopenharmony_ci if (WARN_ON(!entry)) 3308c2ecf20Sopenharmony_ci return -ENOMEM; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci return firmware_map_add_entry(start, end, type, entry); 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci/** 3368c2ecf20Sopenharmony_ci * firmware_map_remove() - remove a firmware mapping entry 3378c2ecf20Sopenharmony_ci * @start: Start of the memory range. 3388c2ecf20Sopenharmony_ci * @end: End of the memory range. 3398c2ecf20Sopenharmony_ci * @type: Type of the memory range. 3408c2ecf20Sopenharmony_ci * 3418c2ecf20Sopenharmony_ci * removes a firmware mapping entry. 3428c2ecf20Sopenharmony_ci * 3438c2ecf20Sopenharmony_ci * Return: 0 on success, or -EINVAL if no entry. 3448c2ecf20Sopenharmony_ci */ 3458c2ecf20Sopenharmony_ciint __meminit firmware_map_remove(u64 start, u64 end, const char *type) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci struct firmware_map_entry *entry; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci spin_lock(&map_entries_lock); 3508c2ecf20Sopenharmony_ci entry = firmware_map_find_entry(start, end - 1, type); 3518c2ecf20Sopenharmony_ci if (!entry) { 3528c2ecf20Sopenharmony_ci spin_unlock(&map_entries_lock); 3538c2ecf20Sopenharmony_ci return -EINVAL; 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci firmware_map_remove_entry(entry); 3578c2ecf20Sopenharmony_ci spin_unlock(&map_entries_lock); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci /* remove the memmap entry */ 3608c2ecf20Sopenharmony_ci remove_sysfs_fw_map_entry(entry); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci return 0; 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci/* 3668c2ecf20Sopenharmony_ci * Sysfs functions ------------------------------------------------------------- 3678c2ecf20Sopenharmony_ci */ 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_cistatic ssize_t start_show(struct firmware_map_entry *entry, char *buf) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "0x%llx\n", 3728c2ecf20Sopenharmony_ci (unsigned long long)entry->start); 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic ssize_t end_show(struct firmware_map_entry *entry, char *buf) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "0x%llx\n", 3788c2ecf20Sopenharmony_ci (unsigned long long)entry->end); 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_cistatic ssize_t type_show(struct firmware_map_entry *entry, char *buf) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%s\n", entry->type); 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cistatic inline struct memmap_attribute *to_memmap_attr(struct attribute *attr) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci return container_of(attr, struct memmap_attribute, attr); 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_cistatic ssize_t memmap_attr_show(struct kobject *kobj, 3928c2ecf20Sopenharmony_ci struct attribute *attr, char *buf) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci struct firmware_map_entry *entry = to_memmap_entry(kobj); 3958c2ecf20Sopenharmony_ci struct memmap_attribute *memmap_attr = to_memmap_attr(attr); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci return memmap_attr->show(entry, buf); 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci/* 4018c2ecf20Sopenharmony_ci * Initialises stuff and adds the entries in the map_entries list to 4028c2ecf20Sopenharmony_ci * sysfs. Important is that firmware_map_add() and firmware_map_add_early() 4038c2ecf20Sopenharmony_ci * must be called before late_initcall. That's just because that function 4048c2ecf20Sopenharmony_ci * is called as late_initcall() function, which means that if you call 4058c2ecf20Sopenharmony_ci * firmware_map_add() or firmware_map_add_early() afterwards, the entries 4068c2ecf20Sopenharmony_ci * are not added to sysfs. 4078c2ecf20Sopenharmony_ci */ 4088c2ecf20Sopenharmony_cistatic int __init firmware_memmap_init(void) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci struct firmware_map_entry *entry; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci list_for_each_entry(entry, &map_entries, list) 4138c2ecf20Sopenharmony_ci add_sysfs_fw_map_entry(entry); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci return 0; 4168c2ecf20Sopenharmony_ci} 4178c2ecf20Sopenharmony_cilate_initcall(firmware_memmap_init); 4188c2ecf20Sopenharmony_ci 419