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