iwl3945: replace station function with station ops
[linux-2.6] / drivers / acpi / acpi_memhotplug.c
1 /*
2  * Copyright (C) 2004 Intel Corporation <naveen.b.s@intel.com>
3  *
4  * All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or (at
9  * your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
14  * NON INFRINGEMENT.  See the GNU General Public License for more
15  * details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  *
21  *
22  * ACPI based HotPlug driver that supports Memory Hotplug
23  * This driver fields notifications from firmware for memory add
24  * and remove operations and alerts the VM of the affected memory
25  * ranges.
26  */
27
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 <acpi/acpi_drivers.h>
34
35 #define ACPI_MEMORY_DEVICE_CLASS                "memory"
36 #define ACPI_MEMORY_DEVICE_HID                  "PNP0C80"
37 #define ACPI_MEMORY_DEVICE_NAME                 "Hotplug Mem Device"
38
39 #define _COMPONENT              ACPI_MEMORY_DEVICE_COMPONENT
40
41 ACPI_MODULE_NAME("acpi_memhotplug");
42 MODULE_AUTHOR("Naveen B S <naveen.b.s@intel.com>");
43 MODULE_DESCRIPTION("Hotplug Mem Driver");
44 MODULE_LICENSE("GPL");
45
46 /* Memory Device States */
47 #define MEMORY_INVALID_STATE    0
48 #define MEMORY_POWER_ON_STATE   1
49 #define MEMORY_POWER_OFF_STATE  2
50
51 static int acpi_memory_device_add(struct acpi_device *device);
52 static int acpi_memory_device_remove(struct acpi_device *device, int type);
53 static int acpi_memory_device_start(struct acpi_device *device);
54
55 static const struct acpi_device_id memory_device_ids[] = {
56         {ACPI_MEMORY_DEVICE_HID, 0},
57         {"", 0},
58 };
59 MODULE_DEVICE_TABLE(acpi, memory_device_ids);
60
61 static struct acpi_driver acpi_memory_device_driver = {
62         .name = "acpi_memhotplug",
63         .class = ACPI_MEMORY_DEVICE_CLASS,
64         .ids = memory_device_ids,
65         .ops = {
66                 .add = acpi_memory_device_add,
67                 .remove = acpi_memory_device_remove,
68                 .start = acpi_memory_device_start,
69                 },
70 };
71
72 struct acpi_memory_info {
73         struct list_head list;
74         u64 start_addr;         /* Memory Range start physical addr */
75         u64 length;             /* Memory Range length */
76         unsigned short caching; /* memory cache attribute */
77         unsigned short write_protect;   /* memory read/write attribute */
78         unsigned int enabled:1;
79 };
80
81 struct acpi_memory_device {
82         struct acpi_device * device;
83         unsigned int state;     /* State of the memory device */
84         struct list_head res_list;
85 };
86
87 static int acpi_hotmem_initialized;
88
89 static acpi_status
90 acpi_memory_get_resource(struct acpi_resource *resource, void *context)
91 {
92         struct acpi_memory_device *mem_device = context;
93         struct acpi_resource_address64 address64;
94         struct acpi_memory_info *info, *new;
95         acpi_status status;
96
97         status = acpi_resource_to_address64(resource, &address64);
98         if (ACPI_FAILURE(status) ||
99             (address64.resource_type != ACPI_MEMORY_RANGE))
100                 return AE_OK;
101
102         list_for_each_entry(info, &mem_device->res_list, list) {
103                 /* Can we combine the resource range information? */
104                 if ((info->caching == address64.info.mem.caching) &&
105                     (info->write_protect == address64.info.mem.write_protect) &&
106                     (info->start_addr + info->length == address64.minimum)) {
107                         info->length += address64.address_length;
108                         return AE_OK;
109                 }
110         }
111
112         new = kzalloc(sizeof(struct acpi_memory_info), GFP_KERNEL);
113         if (!new)
114                 return AE_ERROR;
115
116         INIT_LIST_HEAD(&new->list);
117         new->caching = address64.info.mem.caching;
118         new->write_protect = address64.info.mem.write_protect;
119         new->start_addr = address64.minimum;
120         new->length = address64.address_length;
121         list_add_tail(&new->list, &mem_device->res_list);
122
123         return AE_OK;
124 }
125
126 static int
127 acpi_memory_get_device_resources(struct acpi_memory_device *mem_device)
128 {
129         acpi_status status;
130         struct acpi_memory_info *info, *n;
131
132
133         if (!list_empty(&mem_device->res_list))
134                 return 0;
135
136         status = acpi_walk_resources(mem_device->device->handle, METHOD_NAME__CRS,
137                                      acpi_memory_get_resource, mem_device);
138         if (ACPI_FAILURE(status)) {
139                 list_for_each_entry_safe(info, n, &mem_device->res_list, list)
140                         kfree(info);
141                 INIT_LIST_HEAD(&mem_device->res_list);
142                 return -EINVAL;
143         }
144
145         return 0;
146 }
147
148 static int
149 acpi_memory_get_device(acpi_handle handle,
150                        struct acpi_memory_device **mem_device)
151 {
152         acpi_status status;
153         acpi_handle phandle;
154         struct acpi_device *device = NULL;
155         struct acpi_device *pdevice = NULL;
156
157
158         if (!acpi_bus_get_device(handle, &device) && device)
159                 goto end;
160
161         status = acpi_get_parent(handle, &phandle);
162         if (ACPI_FAILURE(status)) {
163                 ACPI_EXCEPTION((AE_INFO, status, "Cannot find acpi parent"));
164                 return -EINVAL;
165         }
166
167         /* Get the parent device */
168         status = acpi_bus_get_device(phandle, &pdevice);
169         if (ACPI_FAILURE(status)) {
170                 ACPI_EXCEPTION((AE_INFO, status, "Cannot get acpi bus device"));
171                 return -EINVAL;
172         }
173
174         /*
175          * Now add the notified device.  This creates the acpi_device
176          * and invokes .add function
177          */
178         status = acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE);
179         if (ACPI_FAILURE(status)) {
180                 ACPI_EXCEPTION((AE_INFO, status, "Cannot add acpi bus"));
181                 return -EINVAL;
182         }
183
184       end:
185         *mem_device = acpi_driver_data(device);
186         if (!(*mem_device)) {
187                 printk(KERN_ERR "\n driver data not found");
188                 return -ENODEV;
189         }
190
191         return 0;
192 }
193
194 static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
195 {
196         unsigned long long current_status;
197
198         /* Get device present/absent information from the _STA */
199         if (ACPI_FAILURE(acpi_evaluate_integer(mem_device->device->handle, "_STA",
200                                                NULL, &current_status)))
201                 return -ENODEV;
202         /*
203          * Check for device status. Device should be
204          * present/enabled/functioning.
205          */
206         if (!((current_status & ACPI_STA_DEVICE_PRESENT)
207               && (current_status & ACPI_STA_DEVICE_ENABLED)
208               && (current_status & ACPI_STA_DEVICE_FUNCTIONING)))
209                 return -ENODEV;
210
211         return 0;
212 }
213
214 static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
215 {
216         int result, num_enabled = 0;
217         struct acpi_memory_info *info;
218         int node;
219
220
221         /* Get the range from the _CRS */
222         result = acpi_memory_get_device_resources(mem_device);
223         if (result) {
224                 printk(KERN_ERR PREFIX "get_device_resources failed\n");
225                 mem_device->state = MEMORY_INVALID_STATE;
226                 return result;
227         }
228
229         node = acpi_get_node(mem_device->device->handle);
230         /*
231          * Tell the VM there is more memory here...
232          * Note: Assume that this function returns zero on success
233          * We don't have memory-hot-add rollback function,now.
234          * (i.e. memory-hot-remove function)
235          */
236         list_for_each_entry(info, &mem_device->res_list, list) {
237                 if (info->enabled) { /* just sanity check...*/
238                         num_enabled++;
239                         continue;
240                 }
241
242                 if (node < 0)
243                         node = memory_add_physaddr_to_nid(info->start_addr);
244
245                 result = add_memory(node, info->start_addr, info->length);
246                 if (result)
247                         continue;
248                 info->enabled = 1;
249                 num_enabled++;
250         }
251         if (!num_enabled) {
252                 printk(KERN_ERR PREFIX "add_memory failed\n");
253                 mem_device->state = MEMORY_INVALID_STATE;
254                 return -EINVAL;
255         }
256
257         return result;
258 }
259
260 static int acpi_memory_powerdown_device(struct acpi_memory_device *mem_device)
261 {
262         acpi_status status;
263         struct acpi_object_list arg_list;
264         union acpi_object arg;
265         unsigned long long current_status;
266
267
268         /* Issue the _EJ0 command */
269         arg_list.count = 1;
270         arg_list.pointer = &arg;
271         arg.type = ACPI_TYPE_INTEGER;
272         arg.integer.value = 1;
273         status = acpi_evaluate_object(mem_device->device->handle,
274                                       "_EJ0", &arg_list, NULL);
275         /* Return on _EJ0 failure */
276         if (ACPI_FAILURE(status)) {
277                 ACPI_EXCEPTION((AE_INFO, status, "_EJ0 failed"));
278                 return -ENODEV;
279         }
280
281         /* Evalute _STA to check if the device is disabled */
282         status = acpi_evaluate_integer(mem_device->device->handle, "_STA",
283                                        NULL, &current_status);
284         if (ACPI_FAILURE(status))
285                 return -ENODEV;
286
287         /* Check for device status.  Device should be disabled */
288         if (current_status & ACPI_STA_DEVICE_ENABLED)
289                 return -EINVAL;
290
291         return 0;
292 }
293
294 static int acpi_memory_disable_device(struct acpi_memory_device *mem_device)
295 {
296         int result;
297         struct acpi_memory_info *info, *n;
298
299
300         /*
301          * Ask the VM to offline this memory range.
302          * Note: Assume that this function returns zero on success
303          */
304         list_for_each_entry_safe(info, n, &mem_device->res_list, list) {
305                 if (info->enabled) {
306                         result = remove_memory(info->start_addr, info->length);
307                         if (result)
308                                 return result;
309                 }
310                 kfree(info);
311         }
312
313         /* Power-off and eject the device */
314         result = acpi_memory_powerdown_device(mem_device);
315         if (result) {
316                 /* Set the status of the device to invalid */
317                 mem_device->state = MEMORY_INVALID_STATE;
318                 return result;
319         }
320
321         mem_device->state = MEMORY_POWER_OFF_STATE;
322         return result;
323 }
324
325 static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
326 {
327         struct acpi_memory_device *mem_device;
328         struct acpi_device *device;
329
330
331         switch (event) {
332         case ACPI_NOTIFY_BUS_CHECK:
333                 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
334                                   "\nReceived BUS CHECK notification for device\n"));
335                 /* Fall Through */
336         case ACPI_NOTIFY_DEVICE_CHECK:
337                 if (event == ACPI_NOTIFY_DEVICE_CHECK)
338                         ACPI_DEBUG_PRINT((ACPI_DB_INFO,
339                                           "\nReceived DEVICE CHECK notification for device\n"));
340                 if (acpi_memory_get_device(handle, &mem_device)) {
341                         printk(KERN_ERR PREFIX "Cannot find driver data\n");
342                         return;
343                 }
344
345                 if (!acpi_memory_check_device(mem_device)) {
346                         if (acpi_memory_enable_device(mem_device))
347                                 printk(KERN_ERR PREFIX
348                                             "Cannot enable memory device\n");
349                 }
350                 break;
351         case ACPI_NOTIFY_EJECT_REQUEST:
352                 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
353                                   "\nReceived EJECT REQUEST notification for device\n"));
354
355                 if (acpi_bus_get_device(handle, &device)) {
356                         printk(KERN_ERR PREFIX "Device doesn't exist\n");
357                         break;
358                 }
359                 mem_device = acpi_driver_data(device);
360                 if (!mem_device) {
361                         printk(KERN_ERR PREFIX "Driver Data is NULL\n");
362                         break;
363                 }
364
365                 /*
366                  * Currently disabling memory device from kernel mode
367                  * TBD: Can also be disabled from user mode scripts
368                  * TBD: Can also be disabled by Callback registration
369                  *      with generic sysfs driver
370                  */
371                 if (acpi_memory_disable_device(mem_device))
372                         printk(KERN_ERR PREFIX
373                                     "Disable memory device\n");
374                 /*
375                  * TBD: Invoke acpi_bus_remove to cleanup data structures
376                  */
377                 break;
378         default:
379                 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
380                                   "Unsupported event [0x%x]\n", event));
381                 break;
382         }
383
384         return;
385 }
386
387 static int acpi_memory_device_add(struct acpi_device *device)
388 {
389         int result;
390         struct acpi_memory_device *mem_device = NULL;
391
392
393         if (!device)
394                 return -EINVAL;
395
396         mem_device = kzalloc(sizeof(struct acpi_memory_device), GFP_KERNEL);
397         if (!mem_device)
398                 return -ENOMEM;
399
400         INIT_LIST_HEAD(&mem_device->res_list);
401         mem_device->device = device;
402         sprintf(acpi_device_name(device), "%s", ACPI_MEMORY_DEVICE_NAME);
403         sprintf(acpi_device_class(device), "%s", ACPI_MEMORY_DEVICE_CLASS);
404         device->driver_data = mem_device;
405
406         /* Get the range from the _CRS */
407         result = acpi_memory_get_device_resources(mem_device);
408         if (result) {
409                 kfree(mem_device);
410                 return result;
411         }
412
413         /* Set the device state */
414         mem_device->state = MEMORY_POWER_ON_STATE;
415
416         printk(KERN_DEBUG "%s \n", acpi_device_name(device));
417
418         return result;
419 }
420
421 static int acpi_memory_device_remove(struct acpi_device *device, int type)
422 {
423         struct acpi_memory_device *mem_device = NULL;
424
425
426         if (!device || !acpi_driver_data(device))
427                 return -EINVAL;
428
429         mem_device = acpi_driver_data(device);
430         kfree(mem_device);
431
432         return 0;
433 }
434
435 static int acpi_memory_device_start (struct acpi_device *device)
436 {
437         struct acpi_memory_device *mem_device;
438         int result = 0;
439
440         /*
441          * Early boot code has recognized memory area by EFI/E820.
442          * If DSDT shows these memory devices on boot, hotplug is not necessary
443          * for them. So, it just returns until completion of this driver's
444          * start up.
445          */
446         if (!acpi_hotmem_initialized)
447                 return 0;
448
449         mem_device = acpi_driver_data(device);
450
451         if (!acpi_memory_check_device(mem_device)) {
452                 /* call add_memory func */
453                 result = acpi_memory_enable_device(mem_device);
454                 if (result)
455                         printk(KERN_ERR PREFIX
456                                 "Error in acpi_memory_enable_device\n");
457         }
458         return result;
459 }
460
461 /*
462  * Helper function to check for memory device
463  */
464 static acpi_status is_memory_device(acpi_handle handle)
465 {
466         char *hardware_id;
467         acpi_status status;
468         struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
469         struct acpi_device_info *info;
470
471
472         status = acpi_get_object_info(handle, &buffer);
473         if (ACPI_FAILURE(status))
474                 return status;
475
476         info = buffer.pointer;
477         if (!(info->valid & ACPI_VALID_HID)) {
478                 kfree(buffer.pointer);
479                 return AE_ERROR;
480         }
481
482         hardware_id = info->hardware_id.value;
483         if ((hardware_id == NULL) ||
484             (strcmp(hardware_id, ACPI_MEMORY_DEVICE_HID)))
485                 status = AE_ERROR;
486
487         kfree(buffer.pointer);
488         return status;
489 }
490
491 static acpi_status
492 acpi_memory_register_notify_handler(acpi_handle handle,
493                                     u32 level, void *ctxt, void **retv)
494 {
495         acpi_status status;
496
497
498         status = is_memory_device(handle);
499         if (ACPI_FAILURE(status))
500                 return AE_OK;   /* continue */
501
502         status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
503                                              acpi_memory_device_notify, NULL);
504         /* continue */
505         return AE_OK;
506 }
507
508 static acpi_status
509 acpi_memory_deregister_notify_handler(acpi_handle handle,
510                                       u32 level, void *ctxt, void **retv)
511 {
512         acpi_status status;
513
514
515         status = is_memory_device(handle);
516         if (ACPI_FAILURE(status))
517                 return AE_OK;   /* continue */
518
519         status = acpi_remove_notify_handler(handle,
520                                             ACPI_SYSTEM_NOTIFY,
521                                             acpi_memory_device_notify);
522
523         return AE_OK;   /* continue */
524 }
525
526 static int __init acpi_memory_device_init(void)
527 {
528         int result;
529         acpi_status status;
530
531
532         result = acpi_bus_register_driver(&acpi_memory_device_driver);
533
534         if (result < 0)
535                 return -ENODEV;
536
537         status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
538                                      ACPI_UINT32_MAX,
539                                      acpi_memory_register_notify_handler,
540                                      NULL, NULL);
541
542         if (ACPI_FAILURE(status)) {
543                 ACPI_EXCEPTION((AE_INFO, status, "walk_namespace failed"));
544                 acpi_bus_unregister_driver(&acpi_memory_device_driver);
545                 return -ENODEV;
546         }
547
548         acpi_hotmem_initialized = 1;
549         return 0;
550 }
551
552 static void __exit acpi_memory_device_exit(void)
553 {
554         acpi_status status;
555
556
557         /*
558          * Adding this to un-install notification handlers for all the device
559          * handles.
560          */
561         status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
562                                      ACPI_UINT32_MAX,
563                                      acpi_memory_deregister_notify_handler,
564                                      NULL, NULL);
565
566         if (ACPI_FAILURE(status))
567                 ACPI_EXCEPTION((AE_INFO, status, "walk_namespace failed"));
568
569         acpi_bus_unregister_driver(&acpi_memory_device_driver);
570
571         return;
572 }
573
574 module_init(acpi_memory_device_init);
575 module_exit(acpi_memory_device_exit);