18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2004, 2013 Intel Corporation 48c2ecf20Sopenharmony_ci * Author: Naveen B S <naveen.b.s@intel.com> 58c2ecf20Sopenharmony_ci * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * All rights reserved. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * ACPI based HotPlug driver that supports Memory Hotplug 108c2ecf20Sopenharmony_ci * This driver fields notifications from firmware for memory add 118c2ecf20Sopenharmony_ci * and remove operations and alerts the VM of the affected memory 128c2ecf20Sopenharmony_ci * ranges. 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/acpi.h> 168c2ecf20Sopenharmony_ci#include <linux/memory.h> 178c2ecf20Sopenharmony_ci#include <linux/memory_hotplug.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "internal.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define ACPI_MEMORY_DEVICE_CLASS "memory" 228c2ecf20Sopenharmony_ci#define ACPI_MEMORY_DEVICE_HID "PNP0C80" 238c2ecf20Sopenharmony_ci#define ACPI_MEMORY_DEVICE_NAME "Hotplug Mem Device" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic const struct acpi_device_id memory_device_ids[] = { 268c2ecf20Sopenharmony_ci {ACPI_MEMORY_DEVICE_HID, 0}, 278c2ecf20Sopenharmony_ci {"", 0}, 288c2ecf20Sopenharmony_ci}; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI_HOTPLUG_MEMORY 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic int acpi_memory_device_add(struct acpi_device *device, 338c2ecf20Sopenharmony_ci const struct acpi_device_id *not_used); 348c2ecf20Sopenharmony_cistatic void acpi_memory_device_remove(struct acpi_device *device); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic struct acpi_scan_handler memory_device_handler = { 378c2ecf20Sopenharmony_ci .ids = memory_device_ids, 388c2ecf20Sopenharmony_ci .attach = acpi_memory_device_add, 398c2ecf20Sopenharmony_ci .detach = acpi_memory_device_remove, 408c2ecf20Sopenharmony_ci .hotplug = { 418c2ecf20Sopenharmony_ci .enabled = true, 428c2ecf20Sopenharmony_ci }, 438c2ecf20Sopenharmony_ci}; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistruct acpi_memory_info { 468c2ecf20Sopenharmony_ci struct list_head list; 478c2ecf20Sopenharmony_ci u64 start_addr; /* Memory Range start physical addr */ 488c2ecf20Sopenharmony_ci u64 length; /* Memory Range length */ 498c2ecf20Sopenharmony_ci unsigned short caching; /* memory cache attribute */ 508c2ecf20Sopenharmony_ci unsigned short write_protect; /* memory read/write attribute */ 518c2ecf20Sopenharmony_ci unsigned int enabled:1; 528c2ecf20Sopenharmony_ci}; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistruct acpi_memory_device { 558c2ecf20Sopenharmony_ci struct acpi_device *device; 568c2ecf20Sopenharmony_ci struct list_head res_list; 578c2ecf20Sopenharmony_ci}; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic acpi_status 608c2ecf20Sopenharmony_ciacpi_memory_get_resource(struct acpi_resource *resource, void *context) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci struct acpi_memory_device *mem_device = context; 638c2ecf20Sopenharmony_ci struct acpi_resource_address64 address64; 648c2ecf20Sopenharmony_ci struct acpi_memory_info *info, *new; 658c2ecf20Sopenharmony_ci acpi_status status; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci status = acpi_resource_to_address64(resource, &address64); 688c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status) || 698c2ecf20Sopenharmony_ci (address64.resource_type != ACPI_MEMORY_RANGE)) 708c2ecf20Sopenharmony_ci return AE_OK; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci list_for_each_entry(info, &mem_device->res_list, list) { 738c2ecf20Sopenharmony_ci /* Can we combine the resource range information? */ 748c2ecf20Sopenharmony_ci if ((info->caching == address64.info.mem.caching) && 758c2ecf20Sopenharmony_ci (info->write_protect == address64.info.mem.write_protect) && 768c2ecf20Sopenharmony_ci (info->start_addr + info->length == address64.address.minimum)) { 778c2ecf20Sopenharmony_ci info->length += address64.address.address_length; 788c2ecf20Sopenharmony_ci return AE_OK; 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci new = kzalloc(sizeof(struct acpi_memory_info), GFP_KERNEL); 838c2ecf20Sopenharmony_ci if (!new) 848c2ecf20Sopenharmony_ci return AE_ERROR; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&new->list); 878c2ecf20Sopenharmony_ci new->caching = address64.info.mem.caching; 888c2ecf20Sopenharmony_ci new->write_protect = address64.info.mem.write_protect; 898c2ecf20Sopenharmony_ci new->start_addr = address64.address.minimum; 908c2ecf20Sopenharmony_ci new->length = address64.address.address_length; 918c2ecf20Sopenharmony_ci list_add_tail(&new->list, &mem_device->res_list); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci return AE_OK; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic void 978c2ecf20Sopenharmony_ciacpi_memory_free_device_resources(struct acpi_memory_device *mem_device) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci struct acpi_memory_info *info, *n; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci list_for_each_entry_safe(info, n, &mem_device->res_list, list) 1028c2ecf20Sopenharmony_ci kfree(info); 1038c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&mem_device->res_list); 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic int 1078c2ecf20Sopenharmony_ciacpi_memory_get_device_resources(struct acpi_memory_device *mem_device) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci acpi_status status; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (!list_empty(&mem_device->res_list)) 1128c2ecf20Sopenharmony_ci return 0; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci status = acpi_walk_resources(mem_device->device->handle, METHOD_NAME__CRS, 1158c2ecf20Sopenharmony_ci acpi_memory_get_resource, mem_device); 1168c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 1178c2ecf20Sopenharmony_ci acpi_memory_free_device_resources(mem_device); 1188c2ecf20Sopenharmony_ci return -EINVAL; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci return 0; 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic int acpi_memory_check_device(struct acpi_memory_device *mem_device) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci unsigned long long current_status; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci /* Get device present/absent information from the _STA */ 1298c2ecf20Sopenharmony_ci if (ACPI_FAILURE(acpi_evaluate_integer(mem_device->device->handle, 1308c2ecf20Sopenharmony_ci METHOD_NAME__STA, NULL, 1318c2ecf20Sopenharmony_ci ¤t_status))) 1328c2ecf20Sopenharmony_ci return -ENODEV; 1338c2ecf20Sopenharmony_ci /* 1348c2ecf20Sopenharmony_ci * Check for device status. Device should be 1358c2ecf20Sopenharmony_ci * present/enabled/functioning. 1368c2ecf20Sopenharmony_ci */ 1378c2ecf20Sopenharmony_ci if (!((current_status & ACPI_STA_DEVICE_PRESENT) 1388c2ecf20Sopenharmony_ci && (current_status & ACPI_STA_DEVICE_ENABLED) 1398c2ecf20Sopenharmony_ci && (current_status & ACPI_STA_DEVICE_FUNCTIONING))) 1408c2ecf20Sopenharmony_ci return -ENODEV; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci return 0; 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic int acpi_bind_memblk(struct memory_block *mem, void *arg) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci return acpi_bind_one(&mem->dev, arg); 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic int acpi_bind_memory_blocks(struct acpi_memory_info *info, 1518c2ecf20Sopenharmony_ci struct acpi_device *adev) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci return walk_memory_blocks(info->start_addr, info->length, adev, 1548c2ecf20Sopenharmony_ci acpi_bind_memblk); 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic int acpi_unbind_memblk(struct memory_block *mem, void *arg) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci acpi_unbind_one(&mem->dev); 1608c2ecf20Sopenharmony_ci return 0; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic void acpi_unbind_memory_blocks(struct acpi_memory_info *info) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci walk_memory_blocks(info->start_addr, info->length, NULL, 1668c2ecf20Sopenharmony_ci acpi_unbind_memblk); 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic int acpi_memory_enable_device(struct acpi_memory_device *mem_device) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci acpi_handle handle = mem_device->device->handle; 1728c2ecf20Sopenharmony_ci int result, num_enabled = 0; 1738c2ecf20Sopenharmony_ci struct acpi_memory_info *info; 1748c2ecf20Sopenharmony_ci int node; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci node = acpi_get_node(handle); 1778c2ecf20Sopenharmony_ci /* 1788c2ecf20Sopenharmony_ci * Tell the VM there is more memory here... 1798c2ecf20Sopenharmony_ci * Note: Assume that this function returns zero on success 1808c2ecf20Sopenharmony_ci * We don't have memory-hot-add rollback function,now. 1818c2ecf20Sopenharmony_ci * (i.e. memory-hot-remove function) 1828c2ecf20Sopenharmony_ci */ 1838c2ecf20Sopenharmony_ci list_for_each_entry(info, &mem_device->res_list, list) { 1848c2ecf20Sopenharmony_ci if (info->enabled) { /* just sanity check...*/ 1858c2ecf20Sopenharmony_ci num_enabled++; 1868c2ecf20Sopenharmony_ci continue; 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci /* 1898c2ecf20Sopenharmony_ci * If the memory block size is zero, please ignore it. 1908c2ecf20Sopenharmony_ci * Don't try to do the following memory hotplug flowchart. 1918c2ecf20Sopenharmony_ci */ 1928c2ecf20Sopenharmony_ci if (!info->length) 1938c2ecf20Sopenharmony_ci continue; 1948c2ecf20Sopenharmony_ci if (node < 0) 1958c2ecf20Sopenharmony_ci node = memory_add_physaddr_to_nid(info->start_addr); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci result = __add_memory(node, info->start_addr, info->length, 1988c2ecf20Sopenharmony_ci MHP_NONE); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci /* 2018c2ecf20Sopenharmony_ci * If the memory block has been used by the kernel, add_memory() 2028c2ecf20Sopenharmony_ci * returns -EEXIST. If add_memory() returns the other error, it 2038c2ecf20Sopenharmony_ci * means that this memory block is not used by the kernel. 2048c2ecf20Sopenharmony_ci */ 2058c2ecf20Sopenharmony_ci if (result && result != -EEXIST) 2068c2ecf20Sopenharmony_ci continue; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci result = acpi_bind_memory_blocks(info, mem_device->device); 2098c2ecf20Sopenharmony_ci if (result) { 2108c2ecf20Sopenharmony_ci acpi_unbind_memory_blocks(info); 2118c2ecf20Sopenharmony_ci return -ENODEV; 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci info->enabled = 1; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci /* 2178c2ecf20Sopenharmony_ci * Add num_enable even if add_memory() returns -EEXIST, so the 2188c2ecf20Sopenharmony_ci * device is bound to this driver. 2198c2ecf20Sopenharmony_ci */ 2208c2ecf20Sopenharmony_ci num_enabled++; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci if (!num_enabled) { 2238c2ecf20Sopenharmony_ci dev_err(&mem_device->device->dev, "add_memory failed\n"); 2248c2ecf20Sopenharmony_ci return -EINVAL; 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci /* 2278c2ecf20Sopenharmony_ci * Sometimes the memory device will contain several memory blocks. 2288c2ecf20Sopenharmony_ci * When one memory block is hot-added to the system memory, it will 2298c2ecf20Sopenharmony_ci * be regarded as a success. 2308c2ecf20Sopenharmony_ci * Otherwise if the last memory block can't be hot-added to the system 2318c2ecf20Sopenharmony_ci * memory, it will be failure and the memory device can't be bound with 2328c2ecf20Sopenharmony_ci * driver. 2338c2ecf20Sopenharmony_ci */ 2348c2ecf20Sopenharmony_ci return 0; 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic void acpi_memory_remove_memory(struct acpi_memory_device *mem_device) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci acpi_handle handle = mem_device->device->handle; 2408c2ecf20Sopenharmony_ci struct acpi_memory_info *info, *n; 2418c2ecf20Sopenharmony_ci int nid = acpi_get_node(handle); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci list_for_each_entry_safe(info, n, &mem_device->res_list, list) { 2448c2ecf20Sopenharmony_ci if (!info->enabled) 2458c2ecf20Sopenharmony_ci continue; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (nid == NUMA_NO_NODE) 2488c2ecf20Sopenharmony_ci nid = memory_add_physaddr_to_nid(info->start_addr); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci acpi_unbind_memory_blocks(info); 2518c2ecf20Sopenharmony_ci __remove_memory(nid, info->start_addr, info->length); 2528c2ecf20Sopenharmony_ci list_del(&info->list); 2538c2ecf20Sopenharmony_ci kfree(info); 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic void acpi_memory_device_free(struct acpi_memory_device *mem_device) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci if (!mem_device) 2608c2ecf20Sopenharmony_ci return; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci acpi_memory_free_device_resources(mem_device); 2638c2ecf20Sopenharmony_ci mem_device->device->driver_data = NULL; 2648c2ecf20Sopenharmony_ci kfree(mem_device); 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic int acpi_memory_device_add(struct acpi_device *device, 2688c2ecf20Sopenharmony_ci const struct acpi_device_id *not_used) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci struct acpi_memory_device *mem_device; 2718c2ecf20Sopenharmony_ci int result; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (!device) 2748c2ecf20Sopenharmony_ci return -EINVAL; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci mem_device = kzalloc(sizeof(struct acpi_memory_device), GFP_KERNEL); 2778c2ecf20Sopenharmony_ci if (!mem_device) 2788c2ecf20Sopenharmony_ci return -ENOMEM; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&mem_device->res_list); 2818c2ecf20Sopenharmony_ci mem_device->device = device; 2828c2ecf20Sopenharmony_ci sprintf(acpi_device_name(device), "%s", ACPI_MEMORY_DEVICE_NAME); 2838c2ecf20Sopenharmony_ci sprintf(acpi_device_class(device), "%s", ACPI_MEMORY_DEVICE_CLASS); 2848c2ecf20Sopenharmony_ci device->driver_data = mem_device; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci /* Get the range from the _CRS */ 2878c2ecf20Sopenharmony_ci result = acpi_memory_get_device_resources(mem_device); 2888c2ecf20Sopenharmony_ci if (result) { 2898c2ecf20Sopenharmony_ci device->driver_data = NULL; 2908c2ecf20Sopenharmony_ci kfree(mem_device); 2918c2ecf20Sopenharmony_ci return result; 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci result = acpi_memory_check_device(mem_device); 2958c2ecf20Sopenharmony_ci if (result) { 2968c2ecf20Sopenharmony_ci acpi_memory_device_free(mem_device); 2978c2ecf20Sopenharmony_ci return 0; 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci result = acpi_memory_enable_device(mem_device); 3018c2ecf20Sopenharmony_ci if (result) { 3028c2ecf20Sopenharmony_ci dev_err(&device->dev, "acpi_memory_enable_device() error\n"); 3038c2ecf20Sopenharmony_ci acpi_memory_device_free(mem_device); 3048c2ecf20Sopenharmony_ci return result; 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci dev_dbg(&device->dev, "Memory device configured by ACPI\n"); 3088c2ecf20Sopenharmony_ci return 1; 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_cistatic void acpi_memory_device_remove(struct acpi_device *device) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci struct acpi_memory_device *mem_device; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if (!device || !acpi_driver_data(device)) 3168c2ecf20Sopenharmony_ci return; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci mem_device = acpi_driver_data(device); 3198c2ecf20Sopenharmony_ci acpi_memory_remove_memory(mem_device); 3208c2ecf20Sopenharmony_ci acpi_memory_device_free(mem_device); 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistatic bool __initdata acpi_no_memhotplug; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_civoid __init acpi_memory_hotplug_init(void) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci if (acpi_no_memhotplug) { 3288c2ecf20Sopenharmony_ci memory_device_handler.attach = NULL; 3298c2ecf20Sopenharmony_ci acpi_scan_add_handler(&memory_device_handler); 3308c2ecf20Sopenharmony_ci return; 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci acpi_scan_add_handler_with_hotplug(&memory_device_handler, "memory"); 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cistatic int __init disable_acpi_memory_hotplug(char *str) 3368c2ecf20Sopenharmony_ci{ 3378c2ecf20Sopenharmony_ci acpi_no_memhotplug = true; 3388c2ecf20Sopenharmony_ci return 1; 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci__setup("acpi_no_memhotplug", disable_acpi_memory_hotplug); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci#else 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic struct acpi_scan_handler memory_device_handler = { 3458c2ecf20Sopenharmony_ci .ids = memory_device_ids, 3468c2ecf20Sopenharmony_ci}; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_civoid __init acpi_memory_hotplug_init(void) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci acpi_scan_add_handler(&memory_device_handler); 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci#endif /* CONFIG_ACPI_HOTPLUG_MEMORY */ 354