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.c328
1 files changed, 42 insertions, 286 deletions
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index da1f82b445e0..5e6301e94920 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -1,5 +1,7 @@
1/* 1/*
2 * Copyright (C) 2004 Intel Corporation <naveen.b.s@intel.com> 2 * Copyright (C) 2004, 2013 Intel Corporation
3 * Author: Naveen B S <naveen.b.s@intel.com>
4 * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
3 * 5 *
4 * All rights reserved. 6 * All rights reserved.
5 * 7 *
@@ -25,14 +27,10 @@
25 * ranges. 27 * ranges.
26 */ 28 */
27 29
28#include <linux/kernel.h>
29#include <linux/module.h>
30#include <linux/init.h>
31#include <linux/types.h>
32#include <linux/memory_hotplug.h>
33#include <linux/slab.h>
34#include <linux/acpi.h> 30#include <linux/acpi.h>
35#include <acpi/acpi_drivers.h> 31#include <linux/memory_hotplug.h>
32
33#include "internal.h"
36 34
37#define ACPI_MEMORY_DEVICE_CLASS "memory" 35#define ACPI_MEMORY_DEVICE_CLASS "memory"
38#define ACPI_MEMORY_DEVICE_HID "PNP0C80" 36#define ACPI_MEMORY_DEVICE_HID "PNP0C80"
@@ -44,32 +42,28 @@
44#define PREFIX "ACPI:memory_hp:" 42#define PREFIX "ACPI:memory_hp:"
45 43
46ACPI_MODULE_NAME("acpi_memhotplug"); 44ACPI_MODULE_NAME("acpi_memhotplug");
47MODULE_AUTHOR("Naveen B S <naveen.b.s@intel.com>");
48MODULE_DESCRIPTION("Hotplug Mem Driver");
49MODULE_LICENSE("GPL");
50 45
51/* Memory Device States */ 46/* Memory Device States */
52#define MEMORY_INVALID_STATE 0 47#define MEMORY_INVALID_STATE 0
53#define MEMORY_POWER_ON_STATE 1 48#define MEMORY_POWER_ON_STATE 1
54#define MEMORY_POWER_OFF_STATE 2 49#define MEMORY_POWER_OFF_STATE 2
55 50
56static int acpi_memory_device_add(struct acpi_device *device); 51static int acpi_memory_device_add(struct acpi_device *device,
57static int acpi_memory_device_remove(struct acpi_device *device); 52 const struct acpi_device_id *not_used);
53static void acpi_memory_device_remove(struct acpi_device *device);
58 54
59static const struct acpi_device_id memory_device_ids[] = { 55static const struct acpi_device_id memory_device_ids[] = {
60 {ACPI_MEMORY_DEVICE_HID, 0}, 56 {ACPI_MEMORY_DEVICE_HID, 0},
61 {"", 0}, 57 {"", 0},
62}; 58};
63MODULE_DEVICE_TABLE(acpi, memory_device_ids);
64 59
65static struct acpi_driver acpi_memory_device_driver = { 60static struct acpi_scan_handler memory_device_handler = {
66 .name = "acpi_memhotplug",
67 .class = ACPI_MEMORY_DEVICE_CLASS,
68 .ids = memory_device_ids, 61 .ids = memory_device_ids,
69 .ops = { 62 .attach = acpi_memory_device_add,
70 .add = acpi_memory_device_add, 63 .detach = acpi_memory_device_remove,
71 .remove = acpi_memory_device_remove, 64 .hotplug = {
72 }, 65 .enabled = true,
66 },
73}; 67};
74 68
75struct acpi_memory_info { 69struct acpi_memory_info {
@@ -79,7 +73,6 @@ struct acpi_memory_info {
79 unsigned short caching; /* memory cache attribute */ 73 unsigned short caching; /* memory cache attribute */
80 unsigned short write_protect; /* memory read/write attribute */ 74 unsigned short write_protect; /* memory read/write attribute */
81 unsigned int enabled:1; 75 unsigned int enabled:1;
82 unsigned int failed:1;
83}; 76};
84 77
85struct acpi_memory_device { 78struct acpi_memory_device {
@@ -153,48 +146,6 @@ acpi_memory_get_device_resources(struct acpi_memory_device *mem_device)
153 return 0; 146 return 0;
154} 147}
155 148
156static int acpi_memory_get_device(acpi_handle handle,
157 struct acpi_memory_device **mem_device)
158{
159 struct acpi_device *device = NULL;
160 int result = 0;
161
162 acpi_scan_lock_acquire();
163
164 acpi_bus_get_device(handle, &device);
165 if (device)
166 goto end;
167
168 /*
169 * Now add the notified device. This creates the acpi_device
170 * and invokes .add function
171 */
172 result = acpi_bus_scan(handle);
173 if (result) {
174 acpi_handle_warn(handle, "ACPI namespace scan failed\n");
175 result = -EINVAL;
176 goto out;
177 }
178 result = acpi_bus_get_device(handle, &device);
179 if (result) {
180 acpi_handle_warn(handle, "Missing device object\n");
181 result = -EINVAL;
182 goto out;
183 }
184
185 end:
186 *mem_device = acpi_driver_data(device);
187 if (!(*mem_device)) {
188 dev_err(&device->dev, "driver data not found\n");
189 result = -ENODEV;
190 goto out;
191 }
192
193 out:
194 acpi_scan_lock_release();
195 return result;
196}
197
198static int acpi_memory_check_device(struct acpi_memory_device *mem_device) 149static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
199{ 150{
200 unsigned long long current_status; 151 unsigned long long current_status;
@@ -249,13 +200,11 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
249 * returns -EEXIST. If add_memory() returns the other error, it 200 * returns -EEXIST. If add_memory() returns the other error, it
250 * means that this memory block is not used by the kernel. 201 * means that this memory block is not used by the kernel.
251 */ 202 */
252 if (result && result != -EEXIST) { 203 if (result && result != -EEXIST)
253 info->failed = 1;
254 continue; 204 continue;
255 }
256 205
257 if (!result) 206 info->enabled = 1;
258 info->enabled = 1; 207
259 /* 208 /*
260 * Add num_enable even if add_memory() returns -EEXIST, so the 209 * Add num_enable even if add_memory() returns -EEXIST, so the
261 * device is bound to this driver. 210 * device is bound to this driver.
@@ -286,16 +235,8 @@ static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device)
286 nid = acpi_get_node(mem_device->device->handle); 235 nid = acpi_get_node(mem_device->device->handle);
287 236
288 list_for_each_entry_safe(info, n, &mem_device->res_list, list) { 237 list_for_each_entry_safe(info, n, &mem_device->res_list, list) {
289 if (info->failed)
290 /* The kernel does not use this memory block */
291 continue;
292
293 if (!info->enabled) 238 if (!info->enabled)
294 /* 239 continue;
295 * The kernel uses this memory block, but it may be not
296 * managed by us.
297 */
298 return -EBUSY;
299 240
300 if (nid < 0) 241 if (nid < 0)
301 nid = memory_add_physaddr_to_nid(info->start_addr); 242 nid = memory_add_physaddr_to_nid(info->start_addr);
@@ -310,95 +251,21 @@ static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device)
310 return result; 251 return result;
311} 252}
312 253
313static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
314{
315 struct acpi_memory_device *mem_device;
316 struct acpi_device *device;
317 struct acpi_eject_event *ej_event = NULL;
318 u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
319 acpi_status status;
320
321 switch (event) {
322 case ACPI_NOTIFY_BUS_CHECK:
323 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
324 "\nReceived BUS CHECK notification for device\n"));
325 /* Fall Through */
326 case ACPI_NOTIFY_DEVICE_CHECK:
327 if (event == ACPI_NOTIFY_DEVICE_CHECK)
328 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
329 "\nReceived DEVICE CHECK notification for device\n"));
330 if (acpi_memory_get_device(handle, &mem_device)) {
331 acpi_handle_err(handle, "Cannot find driver data\n");
332 break;
333 }
334
335 ost_code = ACPI_OST_SC_SUCCESS;
336 break;
337
338 case ACPI_NOTIFY_EJECT_REQUEST:
339 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
340 "\nReceived EJECT REQUEST notification for device\n"));
341
342 status = AE_ERROR;
343 acpi_scan_lock_acquire();
344
345 if (acpi_bus_get_device(handle, &device)) {
346 acpi_handle_err(handle, "Device doesn't exist\n");
347 goto unlock;
348 }
349 mem_device = acpi_driver_data(device);
350 if (!mem_device) {
351 acpi_handle_err(handle, "Driver Data is NULL\n");
352 goto unlock;
353 }
354
355 ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
356 if (!ej_event) {
357 pr_err(PREFIX "No memory, dropping EJECT\n");
358 goto unlock;
359 }
360
361 get_device(&device->dev);
362 ej_event->device = device;
363 ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
364 /* The eject is carried out asynchronously. */
365 status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device,
366 ej_event);
367 if (ACPI_FAILURE(status)) {
368 put_device(&device->dev);
369 kfree(ej_event);
370 }
371
372 unlock:
373 acpi_scan_lock_release();
374 if (ACPI_SUCCESS(status))
375 return;
376 default:
377 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
378 "Unsupported event [0x%x]\n", event));
379
380 /* non-hotplug event; possibly handled by other handler */
381 return;
382 }
383
384 /* Inform firmware that the hotplug operation has completed */
385 (void) acpi_evaluate_hotplug_ost(handle, event, ost_code, NULL);
386}
387
388static void acpi_memory_device_free(struct acpi_memory_device *mem_device) 254static void acpi_memory_device_free(struct acpi_memory_device *mem_device)
389{ 255{
390 if (!mem_device) 256 if (!mem_device)
391 return; 257 return;
392 258
393 acpi_memory_free_device_resources(mem_device); 259 acpi_memory_free_device_resources(mem_device);
260 mem_device->device->driver_data = NULL;
394 kfree(mem_device); 261 kfree(mem_device);
395} 262}
396 263
397static int acpi_memory_device_add(struct acpi_device *device) 264static int acpi_memory_device_add(struct acpi_device *device,
265 const struct acpi_device_id *not_used)
398{ 266{
267 struct acpi_memory_device *mem_device;
399 int result; 268 int result;
400 struct acpi_memory_device *mem_device = NULL;
401
402 269
403 if (!device) 270 if (!device)
404 return -EINVAL; 271 return -EINVAL;
@@ -423,147 +290,36 @@ static int acpi_memory_device_add(struct acpi_device *device)
423 /* Set the device state */ 290 /* Set the device state */
424 mem_device->state = MEMORY_POWER_ON_STATE; 291 mem_device->state = MEMORY_POWER_ON_STATE;
425 292
426 pr_debug("%s\n", acpi_device_name(device)); 293 result = acpi_memory_check_device(mem_device);
294 if (result) {
295 acpi_memory_device_free(mem_device);
296 return 0;
297 }
427 298
428 if (!acpi_memory_check_device(mem_device)) { 299 result = acpi_memory_enable_device(mem_device);
429 /* call add_memory func */ 300 if (result) {
430 result = acpi_memory_enable_device(mem_device); 301 dev_err(&device->dev, "acpi_memory_enable_device() error\n");
431 if (result) { 302 acpi_memory_device_free(mem_device);
432 dev_err(&device->dev, 303 return -ENODEV;
433 "Error in acpi_memory_enable_device\n");
434 acpi_memory_device_free(mem_device);
435 }
436 } 304 }
437 return result; 305
306 dev_dbg(&device->dev, "Memory device configured by ACPI\n");
307 return 1;
438} 308}
439 309
440static int acpi_memory_device_remove(struct acpi_device *device) 310static void acpi_memory_device_remove(struct acpi_device *device)
441{ 311{
442 struct acpi_memory_device *mem_device = NULL; 312 struct acpi_memory_device *mem_device;
443 int result;
444 313
445 if (!device || !acpi_driver_data(device)) 314 if (!device || !acpi_driver_data(device))
446 return -EINVAL; 315 return;
447 316
448 mem_device = acpi_driver_data(device); 317 mem_device = acpi_driver_data(device);
449 318 acpi_memory_remove_memory(mem_device);
450 result = acpi_memory_remove_memory(mem_device);
451 if (result)
452 return result;
453
454 acpi_memory_device_free(mem_device); 319 acpi_memory_device_free(mem_device);
455
456 return 0;
457}
458
459/*
460 * Helper function to check for memory device
461 */
462static acpi_status is_memory_device(acpi_handle handle)
463{
464 char *hardware_id;
465 acpi_status status;
466 struct acpi_device_info *info;
467
468 status = acpi_get_object_info(handle, &info);
469 if (ACPI_FAILURE(status))
470 return status;
471
472 if (!(info->valid & ACPI_VALID_HID)) {
473 kfree(info);
474 return AE_ERROR;
475 }
476
477 hardware_id = info->hardware_id.string;
478 if ((hardware_id == NULL) ||
479 (strcmp(hardware_id, ACPI_MEMORY_DEVICE_HID)))
480 status = AE_ERROR;
481
482 kfree(info);
483 return status;
484}
485
486static acpi_status
487acpi_memory_register_notify_handler(acpi_handle handle,
488 u32 level, void *ctxt, void **retv)
489{
490 acpi_status status;
491
492
493 status = is_memory_device(handle);
494 if (ACPI_FAILURE(status))
495 return AE_OK; /* continue */
496
497 status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
498 acpi_memory_device_notify, NULL);
499 /* continue */
500 return AE_OK;
501}
502
503static acpi_status
504acpi_memory_deregister_notify_handler(acpi_handle handle,
505 u32 level, void *ctxt, void **retv)
506{
507 acpi_status status;
508
509
510 status = is_memory_device(handle);
511 if (ACPI_FAILURE(status))
512 return AE_OK; /* continue */
513
514 status = acpi_remove_notify_handler(handle,
515 ACPI_SYSTEM_NOTIFY,
516 acpi_memory_device_notify);
517
518 return AE_OK; /* continue */
519}
520
521static int __init acpi_memory_device_init(void)
522{
523 int result;
524 acpi_status status;
525
526
527 result = acpi_bus_register_driver(&acpi_memory_device_driver);
528
529 if (result < 0)
530 return -ENODEV;
531
532 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
533 ACPI_UINT32_MAX,
534 acpi_memory_register_notify_handler, NULL,
535 NULL, NULL);
536
537 if (ACPI_FAILURE(status)) {
538 ACPI_EXCEPTION((AE_INFO, status, "walk_namespace failed"));
539 acpi_bus_unregister_driver(&acpi_memory_device_driver);
540 return -ENODEV;
541 }
542
543 return 0;
544} 320}
545 321
546static void __exit acpi_memory_device_exit(void) 322void __init acpi_memory_hotplug_init(void)
547{ 323{
548 acpi_status status; 324 acpi_scan_add_handler_with_hotplug(&memory_device_handler, "memory");
549
550
551 /*
552 * Adding this to un-install notification handlers for all the device
553 * handles.
554 */
555 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
556 ACPI_UINT32_MAX,
557 acpi_memory_deregister_notify_handler, NULL,
558 NULL, NULL);
559
560 if (ACPI_FAILURE(status))
561 ACPI_EXCEPTION((AE_INFO, status, "walk_namespace failed"));
562
563 acpi_bus_unregister_driver(&acpi_memory_device_driver);
564
565 return;
566} 325}
567
568module_init(acpi_memory_device_init);
569module_exit(acpi_memory_device_exit);