aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/acpi_memhotplug.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/acpi_memhotplug.c')
-rw-r--r--drivers/acpi/acpi_memhotplug.c193
1 files changed, 86 insertions, 107 deletions
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index 24c807f96636..eb30e5ab4cab 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -31,6 +31,7 @@
31#include <linux/types.h> 31#include <linux/types.h>
32#include <linux/memory_hotplug.h> 32#include <linux/memory_hotplug.h>
33#include <linux/slab.h> 33#include <linux/slab.h>
34#include <linux/acpi.h>
34#include <acpi/acpi_drivers.h> 35#include <acpi/acpi_drivers.h>
35 36
36#define ACPI_MEMORY_DEVICE_CLASS "memory" 37#define ACPI_MEMORY_DEVICE_CLASS "memory"
@@ -78,6 +79,7 @@ struct acpi_memory_info {
78 unsigned short caching; /* memory cache attribute */ 79 unsigned short caching; /* memory cache attribute */
79 unsigned short write_protect; /* memory read/write attribute */ 80 unsigned short write_protect; /* memory read/write attribute */
80 unsigned int enabled:1; 81 unsigned int enabled:1;
82 unsigned int failed:1;
81}; 83};
82 84
83struct acpi_memory_device { 85struct acpi_memory_device {
@@ -86,8 +88,6 @@ struct acpi_memory_device {
86 struct list_head res_list; 88 struct list_head res_list;
87}; 89};
88 90
89static int acpi_hotmem_initialized;
90
91static acpi_status 91static acpi_status
92acpi_memory_get_resource(struct acpi_resource *resource, void *context) 92acpi_memory_get_resource(struct acpi_resource *resource, void *context)
93{ 93{
@@ -125,12 +125,20 @@ acpi_memory_get_resource(struct acpi_resource *resource, void *context)
125 return AE_OK; 125 return AE_OK;
126} 126}
127 127
128static void
129acpi_memory_free_device_resources(struct acpi_memory_device *mem_device)
130{
131 struct acpi_memory_info *info, *n;
132
133 list_for_each_entry_safe(info, n, &mem_device->res_list, list)
134 kfree(info);
135 INIT_LIST_HEAD(&mem_device->res_list);
136}
137
128static int 138static int
129acpi_memory_get_device_resources(struct acpi_memory_device *mem_device) 139acpi_memory_get_device_resources(struct acpi_memory_device *mem_device)
130{ 140{
131 acpi_status status; 141 acpi_status status;
132 struct acpi_memory_info *info, *n;
133
134 142
135 if (!list_empty(&mem_device->res_list)) 143 if (!list_empty(&mem_device->res_list))
136 return 0; 144 return 0;
@@ -138,9 +146,7 @@ acpi_memory_get_device_resources(struct acpi_memory_device *mem_device)
138 status = acpi_walk_resources(mem_device->device->handle, METHOD_NAME__CRS, 146 status = acpi_walk_resources(mem_device->device->handle, METHOD_NAME__CRS,
139 acpi_memory_get_resource, mem_device); 147 acpi_memory_get_resource, mem_device);
140 if (ACPI_FAILURE(status)) { 148 if (ACPI_FAILURE(status)) {
141 list_for_each_entry_safe(info, n, &mem_device->res_list, list) 149 acpi_memory_free_device_resources(mem_device);
142 kfree(info);
143 INIT_LIST_HEAD(&mem_device->res_list);
144 return -EINVAL; 150 return -EINVAL;
145 } 151 }
146 152
@@ -170,7 +176,7 @@ acpi_memory_get_device(acpi_handle handle,
170 /* Get the parent device */ 176 /* Get the parent device */
171 result = acpi_bus_get_device(phandle, &pdevice); 177 result = acpi_bus_get_device(phandle, &pdevice);
172 if (result) { 178 if (result) {
173 printk(KERN_WARNING PREFIX "Cannot get acpi bus device"); 179 acpi_handle_warn(phandle, "Cannot get acpi bus device\n");
174 return -EINVAL; 180 return -EINVAL;
175 } 181 }
176 182
@@ -180,14 +186,14 @@ acpi_memory_get_device(acpi_handle handle,
180 */ 186 */
181 result = acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE); 187 result = acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE);
182 if (result) { 188 if (result) {
183 printk(KERN_WARNING PREFIX "Cannot add acpi bus"); 189 acpi_handle_warn(handle, "Cannot add acpi bus\n");
184 return -EINVAL; 190 return -EINVAL;
185 } 191 }
186 192
187 end: 193 end:
188 *mem_device = acpi_driver_data(device); 194 *mem_device = acpi_driver_data(device);
189 if (!(*mem_device)) { 195 if (!(*mem_device)) {
190 printk(KERN_ERR "\n driver data not found"); 196 dev_err(&device->dev, "driver data not found\n");
191 return -ENODEV; 197 return -ENODEV;
192 } 198 }
193 199
@@ -224,7 +230,8 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
224 /* Get the range from the _CRS */ 230 /* Get the range from the _CRS */
225 result = acpi_memory_get_device_resources(mem_device); 231 result = acpi_memory_get_device_resources(mem_device);
226 if (result) { 232 if (result) {
227 printk(KERN_ERR PREFIX "get_device_resources failed\n"); 233 dev_err(&mem_device->device->dev,
234 "get_device_resources failed\n");
228 mem_device->state = MEMORY_INVALID_STATE; 235 mem_device->state = MEMORY_INVALID_STATE;
229 return result; 236 return result;
230 } 237 }
@@ -251,13 +258,27 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
251 node = memory_add_physaddr_to_nid(info->start_addr); 258 node = memory_add_physaddr_to_nid(info->start_addr);
252 259
253 result = add_memory(node, info->start_addr, info->length); 260 result = add_memory(node, info->start_addr, info->length);
254 if (result) 261
262 /*
263 * If the memory block has been used by the kernel, add_memory()
264 * returns -EEXIST. If add_memory() returns the other error, it
265 * means that this memory block is not used by the kernel.
266 */
267 if (result && result != -EEXIST) {
268 info->failed = 1;
255 continue; 269 continue;
256 info->enabled = 1; 270 }
271
272 if (!result)
273 info->enabled = 1;
274 /*
275 * Add num_enable even if add_memory() returns -EEXIST, so the
276 * device is bound to this driver.
277 */
257 num_enabled++; 278 num_enabled++;
258 } 279 }
259 if (!num_enabled) { 280 if (!num_enabled) {
260 printk(KERN_ERR PREFIX "add_memory failed\n"); 281 dev_err(&mem_device->device->dev, "add_memory failed\n");
261 mem_device->state = MEMORY_INVALID_STATE; 282 mem_device->state = MEMORY_INVALID_STATE;
262 return -EINVAL; 283 return -EINVAL;
263 } 284 }
@@ -272,68 +293,31 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
272 return 0; 293 return 0;
273} 294}
274 295
275static int acpi_memory_powerdown_device(struct acpi_memory_device *mem_device) 296static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device)
276{ 297{
277 acpi_status status; 298 int result = 0;
278 struct acpi_object_list arg_list; 299 struct acpi_memory_info *info, *n;
279 union acpi_object arg;
280 unsigned long long current_status;
281
282
283 /* Issue the _EJ0 command */
284 arg_list.count = 1;
285 arg_list.pointer = &arg;
286 arg.type = ACPI_TYPE_INTEGER;
287 arg.integer.value = 1;
288 status = acpi_evaluate_object(mem_device->device->handle,
289 "_EJ0", &arg_list, NULL);
290 /* Return on _EJ0 failure */
291 if (ACPI_FAILURE(status)) {
292 ACPI_EXCEPTION((AE_INFO, status, "_EJ0 failed"));
293 return -ENODEV;
294 }
295
296 /* Evalute _STA to check if the device is disabled */
297 status = acpi_evaluate_integer(mem_device->device->handle, "_STA",
298 NULL, &current_status);
299 if (ACPI_FAILURE(status))
300 return -ENODEV;
301
302 /* Check for device status. Device should be disabled */
303 if (current_status & ACPI_STA_DEVICE_ENABLED)
304 return -EINVAL;
305 300
306 return 0; 301 list_for_each_entry_safe(info, n, &mem_device->res_list, list) {
307} 302 if (info->failed)
303 /* The kernel does not use this memory block */
304 continue;
308 305
309static int acpi_memory_disable_device(struct acpi_memory_device *mem_device) 306 if (!info->enabled)
310{ 307 /*
311 int result; 308 * The kernel uses this memory block, but it may be not
312 struct acpi_memory_info *info, *n; 309 * managed by us.
310 */
311 return -EBUSY;
313 312
313 result = remove_memory(info->start_addr, info->length);
314 if (result)
315 return result;
314 316
315 /* 317 list_del(&info->list);
316 * Ask the VM to offline this memory range.
317 * Note: Assume that this function returns zero on success
318 */
319 list_for_each_entry_safe(info, n, &mem_device->res_list, list) {
320 if (info->enabled) {
321 result = remove_memory(info->start_addr, info->length);
322 if (result)
323 return result;
324 }
325 kfree(info); 318 kfree(info);
326 } 319 }
327 320
328 /* Power-off and eject the device */
329 result = acpi_memory_powerdown_device(mem_device);
330 if (result) {
331 /* Set the status of the device to invalid */
332 mem_device->state = MEMORY_INVALID_STATE;
333 return result;
334 }
335
336 mem_device->state = MEMORY_POWER_OFF_STATE;
337 return result; 321 return result;
338} 322}
339 323
@@ -341,6 +325,7 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
341{ 325{
342 struct acpi_memory_device *mem_device; 326 struct acpi_memory_device *mem_device;
343 struct acpi_device *device; 327 struct acpi_device *device;
328 struct acpi_eject_event *ej_event = NULL;
344 u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */ 329 u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
345 330
346 switch (event) { 331 switch (event) {
@@ -353,7 +338,7 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
353 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 338 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
354 "\nReceived DEVICE CHECK notification for device\n")); 339 "\nReceived DEVICE CHECK notification for device\n"));
355 if (acpi_memory_get_device(handle, &mem_device)) { 340 if (acpi_memory_get_device(handle, &mem_device)) {
356 printk(KERN_ERR PREFIX "Cannot find driver data\n"); 341 acpi_handle_err(handle, "Cannot find driver data\n");
357 break; 342 break;
358 } 343 }
359 344
@@ -361,7 +346,7 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
361 break; 346 break;
362 347
363 if (acpi_memory_enable_device(mem_device)) { 348 if (acpi_memory_enable_device(mem_device)) {
364 printk(KERN_ERR PREFIX "Cannot enable memory device\n"); 349 acpi_handle_err(handle,"Cannot enable memory device\n");
365 break; 350 break;
366 } 351 }
367 352
@@ -373,40 +358,28 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
373 "\nReceived EJECT REQUEST notification for device\n")); 358 "\nReceived EJECT REQUEST notification for device\n"));
374 359
375 if (acpi_bus_get_device(handle, &device)) { 360 if (acpi_bus_get_device(handle, &device)) {
376 printk(KERN_ERR PREFIX "Device doesn't exist\n"); 361 acpi_handle_err(handle, "Device doesn't exist\n");
377 break; 362 break;
378 } 363 }
379 mem_device = acpi_driver_data(device); 364 mem_device = acpi_driver_data(device);
380 if (!mem_device) { 365 if (!mem_device) {
381 printk(KERN_ERR PREFIX "Driver Data is NULL\n"); 366 acpi_handle_err(handle, "Driver Data is NULL\n");
382 break; 367 break;
383 } 368 }
384 369
385 /* 370 ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
386 * Currently disabling memory device from kernel mode 371 if (!ej_event) {
387 * TBD: Can also be disabled from user mode scripts 372 pr_err(PREFIX "No memory, dropping EJECT\n");
388 * TBD: Can also be disabled by Callback registration
389 * with generic sysfs driver
390 */
391 if (acpi_memory_disable_device(mem_device)) {
392 printk(KERN_ERR PREFIX "Disable memory device\n");
393 /*
394 * If _EJ0 was called but failed, _OST is not
395 * necessary.
396 */
397 if (mem_device->state == MEMORY_INVALID_STATE)
398 return;
399
400 break; 373 break;
401 } 374 }
402 375
403 /* 376 ej_event->handle = handle;
404 * TBD: Invoke acpi_bus_remove to cleanup data structures 377 ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
405 */ 378 acpi_os_hotplug_execute(acpi_bus_hot_remove_device,
379 (void *)ej_event);
406 380
407 /* _EJ0 succeeded; _OST is not necessary */ 381 /* eject is performed asynchronously */
408 return; 382 return;
409
410 default: 383 default:
411 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 384 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
412 "Unsupported event [0x%x]\n", event)); 385 "Unsupported event [0x%x]\n", event));
@@ -420,6 +393,15 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
420 return; 393 return;
421} 394}
422 395
396static void acpi_memory_device_free(struct acpi_memory_device *mem_device)
397{
398 if (!mem_device)
399 return;
400
401 acpi_memory_free_device_resources(mem_device);
402 kfree(mem_device);
403}
404
423static int acpi_memory_device_add(struct acpi_device *device) 405static int acpi_memory_device_add(struct acpi_device *device)
424{ 406{
425 int result; 407 int result;
@@ -449,23 +431,16 @@ static int acpi_memory_device_add(struct acpi_device *device)
449 /* Set the device state */ 431 /* Set the device state */
450 mem_device->state = MEMORY_POWER_ON_STATE; 432 mem_device->state = MEMORY_POWER_ON_STATE;
451 433
452 printk(KERN_DEBUG "%s \n", acpi_device_name(device)); 434 pr_debug("%s\n", acpi_device_name(device));
453
454 /*
455 * Early boot code has recognized memory area by EFI/E820.
456 * If DSDT shows these memory devices on boot, hotplug is not necessary
457 * for them. So, it just returns until completion of this driver's
458 * start up.
459 */
460 if (!acpi_hotmem_initialized)
461 return 0;
462 435
463 if (!acpi_memory_check_device(mem_device)) { 436 if (!acpi_memory_check_device(mem_device)) {
464 /* call add_memory func */ 437 /* call add_memory func */
465 result = acpi_memory_enable_device(mem_device); 438 result = acpi_memory_enable_device(mem_device);
466 if (result) 439 if (result) {
467 printk(KERN_ERR PREFIX 440 dev_err(&device->dev,
468 "Error in acpi_memory_enable_device\n"); 441 "Error in acpi_memory_enable_device\n");
442 acpi_memory_device_free(mem_device);
443 }
469 } 444 }
470 return result; 445 return result;
471} 446}
@@ -473,13 +448,18 @@ static int acpi_memory_device_add(struct acpi_device *device)
473static int acpi_memory_device_remove(struct acpi_device *device, int type) 448static int acpi_memory_device_remove(struct acpi_device *device, int type)
474{ 449{
475 struct acpi_memory_device *mem_device = NULL; 450 struct acpi_memory_device *mem_device = NULL;
476 451 int result;
477 452
478 if (!device || !acpi_driver_data(device)) 453 if (!device || !acpi_driver_data(device))
479 return -EINVAL; 454 return -EINVAL;
480 455
481 mem_device = acpi_driver_data(device); 456 mem_device = acpi_driver_data(device);
482 kfree(mem_device); 457
458 result = acpi_memory_remove_memory(mem_device);
459 if (result)
460 return result;
461
462 acpi_memory_device_free(mem_device);
483 463
484 return 0; 464 return 0;
485} 465}
@@ -568,7 +548,6 @@ static int __init acpi_memory_device_init(void)
568 return -ENODEV; 548 return -ENODEV;
569 } 549 }
570 550
571 acpi_hotmem_initialized = 1;
572 return 0; 551 return 0;
573} 552}
574 553