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