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					       &current_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