aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-03-03 17:18:03 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-03-04 08:25:32 -0500
commit0a34764411aaab0114aa3f3656fda33a69a46d10 (patch)
tree1aa704709ecafeda634418f22ca9bea406dfc6ae /drivers/acpi
parent79917f34ac83140c20b06303b608ce6d740f0266 (diff)
ACPI / scan: Make memory hotplug driver use struct acpi_scan_handler
Make the ACPI memory hotplug driver use struct acpi_scan_handler for representing the object used to set up ACPI memory hotplug functionality and to remove hotplug memory ranges and data structures used by the driver before unregistering ACPI device nodes representing memory. Register the new struct acpi_scan_handler object with the help of acpi_scan_add_handler_with_hotplug() to allow user space to manipulate the attributes of the memory hotplug profile. This results in a significant reduction of the drvier's code size and removes some ACPI hotplug code duplication. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Acked-by: Toshi Kani <toshi.kani@hp.com> Tested-by: Toshi Kani <toshi.kani@hp.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/Kconfig3
-rw-r--r--drivers/acpi/acpi_memhotplug.c309
-rw-r--r--drivers/acpi/internal.h5
-rw-r--r--drivers/acpi/scan.c1
4 files changed, 45 insertions, 273 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 92ed9692c47e..da8082391f97 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -345,9 +345,8 @@ config ACPI_CONTAINER
345 the module will be called container. 345 the module will be called container.
346 346
347config ACPI_HOTPLUG_MEMORY 347config ACPI_HOTPLUG_MEMORY
348 tristate "Memory Hotplug" 348 bool "Memory Hotplug"
349 depends on MEMORY_HOTPLUG 349 depends on MEMORY_HOTPLUG
350 default n
351 help 350 help
352 This driver supports ACPI memory hotplug. The driver 351 This driver supports ACPI memory hotplug. The driver
353 fields notifications on ACPI memory devices (PNP0C80), 352 fields notifications on ACPI memory devices (PNP0C80),
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index da1f82b445e0..d4f2eb8a51ac 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 {
@@ -153,48 +147,6 @@ acpi_memory_get_device_resources(struct acpi_memory_device *mem_device)
153 return 0; 147 return 0;
154} 148}
155 149
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) 150static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
199{ 151{
200 unsigned long long current_status; 152 unsigned long long current_status;
@@ -310,95 +262,21 @@ static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device)
310 return result; 262 return result;
311} 263}
312 264
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) 265static void acpi_memory_device_free(struct acpi_memory_device *mem_device)
389{ 266{
390 if (!mem_device) 267 if (!mem_device)
391 return; 268 return;
392 269
393 acpi_memory_free_device_resources(mem_device); 270 acpi_memory_free_device_resources(mem_device);
271 mem_device->device->driver_data = NULL;
394 kfree(mem_device); 272 kfree(mem_device);
395} 273}
396 274
397static int acpi_memory_device_add(struct acpi_device *device) 275static int acpi_memory_device_add(struct acpi_device *device,
276 const struct acpi_device_id *not_used)
398{ 277{
278 struct acpi_memory_device *mem_device;
399 int result; 279 int result;
400 struct acpi_memory_device *mem_device = NULL;
401
402 280
403 if (!device) 281 if (!device)
404 return -EINVAL; 282 return -EINVAL;
@@ -423,147 +301,36 @@ static int acpi_memory_device_add(struct acpi_device *device)
423 /* Set the device state */ 301 /* Set the device state */
424 mem_device->state = MEMORY_POWER_ON_STATE; 302 mem_device->state = MEMORY_POWER_ON_STATE;
425 303
426 pr_debug("%s\n", acpi_device_name(device)); 304 result = acpi_memory_check_device(mem_device);
305 if (result) {
306 acpi_memory_device_free(mem_device);
307 return 0;
308 }
427 309
428 if (!acpi_memory_check_device(mem_device)) { 310 result = acpi_memory_enable_device(mem_device);
429 /* call add_memory func */ 311 if (result) {
430 result = acpi_memory_enable_device(mem_device); 312 dev_err(&device->dev, "acpi_memory_enable_device() error\n");
431 if (result) { 313 acpi_memory_device_free(mem_device);
432 dev_err(&device->dev, 314 return -ENODEV;
433 "Error in acpi_memory_enable_device\n");
434 acpi_memory_device_free(mem_device);
435 }
436 } 315 }
437 return result; 316
317 dev_dbg(&device->dev, "Memory device configured by ACPI\n");
318 return 1;
438} 319}
439 320
440static int acpi_memory_device_remove(struct acpi_device *device) 321static void acpi_memory_device_remove(struct acpi_device *device)
441{ 322{
442 struct acpi_memory_device *mem_device = NULL; 323 struct acpi_memory_device *mem_device;
443 int result;
444 324
445 if (!device || !acpi_driver_data(device)) 325 if (!device || !acpi_driver_data(device))
446 return -EINVAL; 326 return;
447 327
448 mem_device = acpi_driver_data(device); 328 mem_device = acpi_driver_data(device);
449 329 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); 330 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} 331}
520 332
521static int __init acpi_memory_device_init(void) 333void __init acpi_memory_hotplug_init(void)
522{ 334{
523 int result; 335 acpi_scan_add_handler_with_hotplug(&memory_device_handler, "memory");
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}
545
546static void __exit acpi_memory_device_exit(void)
547{
548 acpi_status status;
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} 336}
567
568module_init(acpi_memory_device_init);
569module_exit(acpi_memory_device_exit);
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index c708e4bad967..7215821ccb25 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -41,6 +41,11 @@ void acpi_container_init(void);
41#else 41#else
42static inline void acpi_container_init(void) {} 42static inline void acpi_container_init(void) {}
43#endif 43#endif
44#ifdef CONFIG_ACPI_HOTPLUG_MEMORY
45void acpi_memory_hotplug_init(void);
46#else
47static inline void acpi_memory_hotplug_init(void) {}
48#endif
44 49
45void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug, 50void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug,
46 const char *name); 51 const char *name);
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 5458403c8249..d69d77ab9c7e 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -2026,6 +2026,7 @@ int __init acpi_scan_init(void)
2026 acpi_csrt_init(); 2026 acpi_csrt_init();
2027 acpi_container_init(); 2027 acpi_container_init();
2028 acpi_pci_slot_init(); 2028 acpi_pci_slot_init();
2029 acpi_memory_hotplug_init();
2029 2030
2030 mutex_lock(&acpi_scan_lock); 2031 mutex_lock(&acpi_scan_lock);
2031 /* 2032 /*