Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-or-later
2 : : /*
3 : : * Copyright (C) 2004, 2013 Intel Corporation
4 : : * Author: Naveen B S <naveen.b.s@intel.com>
5 : : * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
6 : : *
7 : : * All rights reserved.
8 : : *
9 : : * ACPI based HotPlug driver that supports Memory Hotplug
10 : : * This driver fields notifications from firmware for memory add
11 : : * and remove operations and alerts the VM of the affected memory
12 : : * ranges.
13 : : */
14 : :
15 : : #include <linux/acpi.h>
16 : : #include <linux/memory.h>
17 : : #include <linux/memory_hotplug.h>
18 : :
19 : : #include "internal.h"
20 : :
21 : : #define ACPI_MEMORY_DEVICE_CLASS "memory"
22 : : #define ACPI_MEMORY_DEVICE_HID "PNP0C80"
23 : : #define ACPI_MEMORY_DEVICE_NAME "Hotplug Mem Device"
24 : :
25 : : #define _COMPONENT ACPI_MEMORY_DEVICE_COMPONENT
26 : :
27 : : #undef PREFIX
28 : : #define PREFIX "ACPI:memory_hp:"
29 : :
30 : : ACPI_MODULE_NAME("acpi_memhotplug");
31 : :
32 : : static const struct acpi_device_id memory_device_ids[] = {
33 : : {ACPI_MEMORY_DEVICE_HID, 0},
34 : : {"", 0},
35 : : };
36 : :
37 : : #ifdef CONFIG_ACPI_HOTPLUG_MEMORY
38 : :
39 : : /* Memory Device States */
40 : : #define MEMORY_INVALID_STATE 0
41 : : #define MEMORY_POWER_ON_STATE 1
42 : : #define MEMORY_POWER_OFF_STATE 2
43 : :
44 : : static int acpi_memory_device_add(struct acpi_device *device,
45 : : const struct acpi_device_id *not_used);
46 : : static void acpi_memory_device_remove(struct acpi_device *device);
47 : :
48 : : static struct acpi_scan_handler memory_device_handler = {
49 : : .ids = memory_device_ids,
50 : : .attach = acpi_memory_device_add,
51 : : .detach = acpi_memory_device_remove,
52 : : .hotplug = {
53 : : .enabled = true,
54 : : },
55 : : };
56 : :
57 : : struct acpi_memory_info {
58 : : struct list_head list;
59 : : u64 start_addr; /* Memory Range start physical addr */
60 : : u64 length; /* Memory Range length */
61 : : unsigned short caching; /* memory cache attribute */
62 : : unsigned short write_protect; /* memory read/write attribute */
63 : : unsigned int enabled:1;
64 : : };
65 : :
66 : : struct acpi_memory_device {
67 : : struct acpi_device * device;
68 : : unsigned int state; /* State of the memory device */
69 : : struct list_head res_list;
70 : : };
71 : :
72 : : static acpi_status
73 : : acpi_memory_get_resource(struct acpi_resource *resource, void *context)
74 : : {
75 : : struct acpi_memory_device *mem_device = context;
76 : : struct acpi_resource_address64 address64;
77 : : struct acpi_memory_info *info, *new;
78 : : acpi_status status;
79 : :
80 : : status = acpi_resource_to_address64(resource, &address64);
81 : : if (ACPI_FAILURE(status) ||
82 : : (address64.resource_type != ACPI_MEMORY_RANGE))
83 : : return AE_OK;
84 : :
85 : : list_for_each_entry(info, &mem_device->res_list, list) {
86 : : /* Can we combine the resource range information? */
87 : : if ((info->caching == address64.info.mem.caching) &&
88 : : (info->write_protect == address64.info.mem.write_protect) &&
89 : : (info->start_addr + info->length == address64.address.minimum)) {
90 : : info->length += address64.address.address_length;
91 : : return AE_OK;
92 : : }
93 : : }
94 : :
95 : : new = kzalloc(sizeof(struct acpi_memory_info), GFP_KERNEL);
96 : : if (!new)
97 : : return AE_ERROR;
98 : :
99 : : INIT_LIST_HEAD(&new->list);
100 : : new->caching = address64.info.mem.caching;
101 : : new->write_protect = address64.info.mem.write_protect;
102 : : new->start_addr = address64.address.minimum;
103 : : new->length = address64.address.address_length;
104 : : list_add_tail(&new->list, &mem_device->res_list);
105 : :
106 : : return AE_OK;
107 : : }
108 : :
109 : : static void
110 : : acpi_memory_free_device_resources(struct acpi_memory_device *mem_device)
111 : : {
112 : : struct acpi_memory_info *info, *n;
113 : :
114 : : list_for_each_entry_safe(info, n, &mem_device->res_list, list)
115 : : kfree(info);
116 : : INIT_LIST_HEAD(&mem_device->res_list);
117 : : }
118 : :
119 : : static int
120 : : acpi_memory_get_device_resources(struct acpi_memory_device *mem_device)
121 : : {
122 : : acpi_status status;
123 : :
124 : : if (!list_empty(&mem_device->res_list))
125 : : return 0;
126 : :
127 : : status = acpi_walk_resources(mem_device->device->handle, METHOD_NAME__CRS,
128 : : acpi_memory_get_resource, mem_device);
129 : : if (ACPI_FAILURE(status)) {
130 : : acpi_memory_free_device_resources(mem_device);
131 : : return -EINVAL;
132 : : }
133 : :
134 : : return 0;
135 : : }
136 : :
137 : : static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
138 : : {
139 : : unsigned long long current_status;
140 : :
141 : : /* Get device present/absent information from the _STA */
142 : : if (ACPI_FAILURE(acpi_evaluate_integer(mem_device->device->handle,
143 : : METHOD_NAME__STA, NULL,
144 : : ¤t_status)))
145 : : return -ENODEV;
146 : : /*
147 : : * Check for device status. Device should be
148 : : * present/enabled/functioning.
149 : : */
150 : : if (!((current_status & ACPI_STA_DEVICE_PRESENT)
151 : : && (current_status & ACPI_STA_DEVICE_ENABLED)
152 : : && (current_status & ACPI_STA_DEVICE_FUNCTIONING)))
153 : : return -ENODEV;
154 : :
155 : : return 0;
156 : : }
157 : :
158 : : static int acpi_bind_memblk(struct memory_block *mem, void *arg)
159 : : {
160 : : return acpi_bind_one(&mem->dev, arg);
161 : : }
162 : :
163 : : static int acpi_bind_memory_blocks(struct acpi_memory_info *info,
164 : : struct acpi_device *adev)
165 : : {
166 : : return walk_memory_blocks(info->start_addr, info->length, adev,
167 : : acpi_bind_memblk);
168 : : }
169 : :
170 : : static int acpi_unbind_memblk(struct memory_block *mem, void *arg)
171 : : {
172 : : acpi_unbind_one(&mem->dev);
173 : : return 0;
174 : : }
175 : :
176 : : static void acpi_unbind_memory_blocks(struct acpi_memory_info *info)
177 : : {
178 : : walk_memory_blocks(info->start_addr, info->length, NULL,
179 : : acpi_unbind_memblk);
180 : : }
181 : :
182 : : static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
183 : : {
184 : : acpi_handle handle = mem_device->device->handle;
185 : : int result, num_enabled = 0;
186 : : struct acpi_memory_info *info;
187 : : int node;
188 : :
189 : : node = acpi_get_node(handle);
190 : : /*
191 : : * Tell the VM there is more memory here...
192 : : * Note: Assume that this function returns zero on success
193 : : * We don't have memory-hot-add rollback function,now.
194 : : * (i.e. memory-hot-remove function)
195 : : */
196 : : list_for_each_entry(info, &mem_device->res_list, list) {
197 : : if (info->enabled) { /* just sanity check...*/
198 : : num_enabled++;
199 : : continue;
200 : : }
201 : : /*
202 : : * If the memory block size is zero, please ignore it.
203 : : * Don't try to do the following memory hotplug flowchart.
204 : : */
205 : : if (!info->length)
206 : : continue;
207 : : if (node < 0)
208 : : node = memory_add_physaddr_to_nid(info->start_addr);
209 : :
210 : : result = __add_memory(node, info->start_addr, info->length);
211 : :
212 : : /*
213 : : * If the memory block has been used by the kernel, add_memory()
214 : : * returns -EEXIST. If add_memory() returns the other error, it
215 : : * means that this memory block is not used by the kernel.
216 : : */
217 : : if (result && result != -EEXIST)
218 : : continue;
219 : :
220 : : result = acpi_bind_memory_blocks(info, mem_device->device);
221 : : if (result) {
222 : : acpi_unbind_memory_blocks(info);
223 : : return -ENODEV;
224 : : }
225 : :
226 : : info->enabled = 1;
227 : :
228 : : /*
229 : : * Add num_enable even if add_memory() returns -EEXIST, so the
230 : : * device is bound to this driver.
231 : : */
232 : : num_enabled++;
233 : : }
234 : : if (!num_enabled) {
235 : : dev_err(&mem_device->device->dev, "add_memory failed\n");
236 : : mem_device->state = MEMORY_INVALID_STATE;
237 : : return -EINVAL;
238 : : }
239 : : /*
240 : : * Sometimes the memory device will contain several memory blocks.
241 : : * When one memory block is hot-added to the system memory, it will
242 : : * be regarded as a success.
243 : : * Otherwise if the last memory block can't be hot-added to the system
244 : : * memory, it will be failure and the memory device can't be bound with
245 : : * driver.
246 : : */
247 : : return 0;
248 : : }
249 : :
250 : : static void acpi_memory_remove_memory(struct acpi_memory_device *mem_device)
251 : : {
252 : : acpi_handle handle = mem_device->device->handle;
253 : : struct acpi_memory_info *info, *n;
254 : : int nid = acpi_get_node(handle);
255 : :
256 : : list_for_each_entry_safe(info, n, &mem_device->res_list, list) {
257 : : if (!info->enabled)
258 : : continue;
259 : :
260 : : if (nid == NUMA_NO_NODE)
261 : : nid = memory_add_physaddr_to_nid(info->start_addr);
262 : :
263 : : acpi_unbind_memory_blocks(info);
264 : : __remove_memory(nid, info->start_addr, info->length);
265 : : list_del(&info->list);
266 : : kfree(info);
267 : : }
268 : : }
269 : :
270 : : static void acpi_memory_device_free(struct acpi_memory_device *mem_device)
271 : : {
272 : : if (!mem_device)
273 : : return;
274 : :
275 : : acpi_memory_free_device_resources(mem_device);
276 : : mem_device->device->driver_data = NULL;
277 : : kfree(mem_device);
278 : : }
279 : :
280 : : static int acpi_memory_device_add(struct acpi_device *device,
281 : : const struct acpi_device_id *not_used)
282 : : {
283 : : struct acpi_memory_device *mem_device;
284 : : int result;
285 : :
286 : : if (!device)
287 : : return -EINVAL;
288 : :
289 : : mem_device = kzalloc(sizeof(struct acpi_memory_device), GFP_KERNEL);
290 : : if (!mem_device)
291 : : return -ENOMEM;
292 : :
293 : : INIT_LIST_HEAD(&mem_device->res_list);
294 : : mem_device->device = device;
295 : : sprintf(acpi_device_name(device), "%s", ACPI_MEMORY_DEVICE_NAME);
296 : : sprintf(acpi_device_class(device), "%s", ACPI_MEMORY_DEVICE_CLASS);
297 : : device->driver_data = mem_device;
298 : :
299 : : /* Get the range from the _CRS */
300 : : result = acpi_memory_get_device_resources(mem_device);
301 : : if (result) {
302 : : device->driver_data = NULL;
303 : : kfree(mem_device);
304 : : return result;
305 : : }
306 : :
307 : : /* Set the device state */
308 : : mem_device->state = MEMORY_POWER_ON_STATE;
309 : :
310 : : result = acpi_memory_check_device(mem_device);
311 : : if (result) {
312 : : acpi_memory_device_free(mem_device);
313 : : return 0;
314 : : }
315 : :
316 : : result = acpi_memory_enable_device(mem_device);
317 : : if (result) {
318 : : dev_err(&device->dev, "acpi_memory_enable_device() error\n");
319 : : acpi_memory_device_free(mem_device);
320 : : return result;
321 : : }
322 : :
323 : : dev_dbg(&device->dev, "Memory device configured by ACPI\n");
324 : : return 1;
325 : : }
326 : :
327 : : static void acpi_memory_device_remove(struct acpi_device *device)
328 : : {
329 : : struct acpi_memory_device *mem_device;
330 : :
331 : : if (!device || !acpi_driver_data(device))
332 : : return;
333 : :
334 : : mem_device = acpi_driver_data(device);
335 : : acpi_memory_remove_memory(mem_device);
336 : : acpi_memory_device_free(mem_device);
337 : : }
338 : :
339 : : static bool __initdata acpi_no_memhotplug;
340 : :
341 : : void __init acpi_memory_hotplug_init(void)
342 : : {
343 : : if (acpi_no_memhotplug) {
344 : : memory_device_handler.attach = NULL;
345 : : acpi_scan_add_handler(&memory_device_handler);
346 : : return;
347 : : }
348 : : acpi_scan_add_handler_with_hotplug(&memory_device_handler, "memory");
349 : : }
350 : :
351 : : static int __init disable_acpi_memory_hotplug(char *str)
352 : : {
353 : : acpi_no_memhotplug = true;
354 : : return 1;
355 : : }
356 : : __setup("acpi_no_memhotplug", disable_acpi_memory_hotplug);
357 : :
358 : : #else
359 : :
360 : : static struct acpi_scan_handler memory_device_handler = {
361 : : .ids = memory_device_ids,
362 : : };
363 : :
364 : 30 : void __init acpi_memory_hotplug_init(void)
365 : : {
366 : 30 : acpi_scan_add_handler(&memory_device_handler);
367 : 30 : }
368 : :
369 : : #endif /* CONFIG_ACPI_HOTPLUG_MEMORY */
|