1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (C) 2012 Intel Corporation 4 * Author: Liu Jinsong <jinsong.liu@intel.com> 5 * Author: Jiang Yunhong <yunhong.jiang@intel.com> 6 */ 7 8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 9 10#include <linux/kernel.h> 11#include <linux/module.h> 12#include <linux/init.h> 13#include <linux/types.h> 14#include <linux/acpi.h> 15#include <xen/acpi.h> 16#include <xen/interface/platform.h> 17#include <asm/xen/hypercall.h> 18 19#define PREFIX "ACPI:xen_memory_hotplug:" 20 21struct acpi_memory_info { 22 struct list_head list; 23 u64 start_addr; /* Memory Range start physical addr */ 24 u64 length; /* Memory Range length */ 25 unsigned short caching; /* memory cache attribute */ 26 unsigned short write_protect; /* memory read/write attribute */ 27 /* copied from buffer getting from _CRS */ 28 unsigned int enabled:1; 29}; 30 31struct acpi_memory_device { 32 struct acpi_device *device; 33 struct list_head res_list; 34}; 35 36static bool acpi_hotmem_initialized __read_mostly; 37 38static int xen_hotadd_memory(int pxm, struct acpi_memory_info *info) 39{ 40 int rc; 41 struct xen_platform_op op; 42 43 op.cmd = XENPF_mem_hotadd; 44 op.u.mem_add.spfn = info->start_addr >> PAGE_SHIFT; 45 op.u.mem_add.epfn = (info->start_addr + info->length) >> PAGE_SHIFT; 46 op.u.mem_add.pxm = pxm; 47 48 rc = HYPERVISOR_dom0_op(&op); 49 if (rc) 50 pr_err(PREFIX "Xen Hotplug Memory Add failed on " 51 "0x%lx -> 0x%lx, _PXM: %d, error: %d\n", 52 (unsigned long)info->start_addr, 53 (unsigned long)(info->start_addr + info->length), 54 pxm, rc); 55 56 return rc; 57} 58 59static int xen_acpi_memory_enable_device(struct acpi_memory_device *mem_device) 60{ 61 int pxm, result; 62 int num_enabled = 0; 63 struct acpi_memory_info *info; 64 65 if (!mem_device) 66 return -EINVAL; 67 68 pxm = xen_acpi_get_pxm(mem_device->device->handle); 69 if (pxm < 0) 70 return pxm; 71 72 list_for_each_entry(info, &mem_device->res_list, list) { 73 if (info->enabled) { /* just sanity check...*/ 74 num_enabled++; 75 continue; 76 } 77 78 if (!info->length) 79 continue; 80 81 result = xen_hotadd_memory(pxm, info); 82 if (result) 83 continue; 84 info->enabled = 1; 85 num_enabled++; 86 } 87 88 if (!num_enabled) 89 return -ENODEV; 90 91 return 0; 92} 93 94static acpi_status 95acpi_memory_get_resource(struct acpi_resource *resource, void *context) 96{ 97 struct acpi_memory_device *mem_device = context; 98 struct acpi_resource_address64 address64; 99 struct acpi_memory_info *info, *new; 100 acpi_status status; 101 102 status = acpi_resource_to_address64(resource, &address64); 103 if (ACPI_FAILURE(status) || 104 (address64.resource_type != ACPI_MEMORY_RANGE)) 105 return AE_OK; 106 107 list_for_each_entry(info, &mem_device->res_list, list) { 108 if ((info->caching == address64.info.mem.caching) && 109 (info->write_protect == address64.info.mem.write_protect) && 110 (info->start_addr + info->length == address64.address.minimum)) { 111 info->length += address64.address.address_length; 112 return AE_OK; 113 } 114 } 115 116 new = kzalloc(sizeof(struct acpi_memory_info), GFP_KERNEL); 117 if (!new) 118 return AE_ERROR; 119 120 INIT_LIST_HEAD(&new->list); 121 new->caching = address64.info.mem.caching; 122 new->write_protect = address64.info.mem.write_protect; 123 new->start_addr = address64.address.minimum; 124 new->length = address64.address.address_length; 125 list_add_tail(&new->list, &mem_device->res_list); 126 127 return AE_OK; 128} 129 130static int 131acpi_memory_get_device_resources(struct acpi_memory_device *mem_device) 132{ 133 acpi_status status; 134 struct acpi_memory_info *info, *n; 135 136 if (!list_empty(&mem_device->res_list)) 137 return 0; 138 139 status = acpi_walk_resources(mem_device->device->handle, 140 METHOD_NAME__CRS, acpi_memory_get_resource, mem_device); 141 142 if (ACPI_FAILURE(status)) { 143 list_for_each_entry_safe(info, n, &mem_device->res_list, list) 144 kfree(info); 145 INIT_LIST_HEAD(&mem_device->res_list); 146 return -EINVAL; 147 } 148 149 return 0; 150} 151 152static int acpi_memory_get_device(acpi_handle handle, 153 struct acpi_memory_device **mem_device) 154{ 155 struct acpi_device *device = NULL; 156 int result = 0; 157 158 acpi_scan_lock_acquire(); 159 160 acpi_bus_get_device(handle, &device); 161 if (acpi_device_enumerated(device)) 162 goto end; 163 164 /* 165 * Now add the notified device. This creates the acpi_device 166 * and invokes .add function 167 */ 168 result = acpi_bus_scan(handle); 169 if (result) { 170 pr_warn(PREFIX "ACPI namespace scan failed\n"); 171 result = -EINVAL; 172 goto out; 173 } 174 device = NULL; 175 acpi_bus_get_device(handle, &device); 176 if (!acpi_device_enumerated(device)) { 177 pr_warn(PREFIX "Missing device object\n"); 178 result = -EINVAL; 179 goto out; 180 } 181 182end: 183 *mem_device = acpi_driver_data(device); 184 if (!(*mem_device)) { 185 pr_err(PREFIX "driver data not found\n"); 186 result = -ENODEV; 187 goto out; 188 } 189 190out: 191 acpi_scan_lock_release(); 192 return result; 193} 194 195static int acpi_memory_check_device(struct acpi_memory_device *mem_device) 196{ 197 unsigned long long current_status; 198 199 /* Get device present/absent information from the _STA */ 200 if (ACPI_FAILURE(acpi_evaluate_integer(mem_device->device->handle, 201 "_STA", NULL, ¤t_status))) 202 return -ENODEV; 203 /* 204 * Check for device status. Device should be 205 * present/enabled/functioning. 206 */ 207 if (!((current_status & ACPI_STA_DEVICE_PRESENT) 208 && (current_status & ACPI_STA_DEVICE_ENABLED) 209 && (current_status & ACPI_STA_DEVICE_FUNCTIONING))) 210 return -ENODEV; 211 212 return 0; 213} 214 215static int acpi_memory_disable_device(struct acpi_memory_device *mem_device) 216{ 217 pr_debug(PREFIX "Xen does not support memory hotremove\n"); 218 219 return -ENOSYS; 220} 221 222static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data) 223{ 224 struct acpi_memory_device *mem_device; 225 struct acpi_device *device; 226 u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */ 227 228 switch (event) { 229 case ACPI_NOTIFY_BUS_CHECK: 230 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 231 "\nReceived BUS CHECK notification for device\n")); 232 fallthrough; 233 case ACPI_NOTIFY_DEVICE_CHECK: 234 if (event == ACPI_NOTIFY_DEVICE_CHECK) 235 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 236 "\nReceived DEVICE CHECK notification for device\n")); 237 238 if (acpi_memory_get_device(handle, &mem_device)) { 239 pr_err(PREFIX "Cannot find driver data\n"); 240 break; 241 } 242 243 ost_code = ACPI_OST_SC_SUCCESS; 244 break; 245 246 case ACPI_NOTIFY_EJECT_REQUEST: 247 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 248 "\nReceived EJECT REQUEST notification for device\n")); 249 250 acpi_scan_lock_acquire(); 251 if (acpi_bus_get_device(handle, &device)) { 252 acpi_scan_lock_release(); 253 pr_err(PREFIX "Device doesn't exist\n"); 254 break; 255 } 256 mem_device = acpi_driver_data(device); 257 if (!mem_device) { 258 acpi_scan_lock_release(); 259 pr_err(PREFIX "Driver Data is NULL\n"); 260 break; 261 } 262 263 /* 264 * TBD: implement acpi_memory_disable_device and invoke 265 * acpi_bus_remove if Xen support hotremove in the future 266 */ 267 acpi_memory_disable_device(mem_device); 268 acpi_scan_lock_release(); 269 break; 270 271 default: 272 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 273 "Unsupported event [0x%x]\n", event)); 274 /* non-hotplug event; possibly handled by other handler */ 275 return; 276 } 277 278 (void) acpi_evaluate_ost(handle, event, ost_code, NULL); 279 return; 280} 281 282static int xen_acpi_memory_device_add(struct acpi_device *device) 283{ 284 int result; 285 struct acpi_memory_device *mem_device = NULL; 286 287 288 if (!device) 289 return -EINVAL; 290 291 mem_device = kzalloc(sizeof(struct acpi_memory_device), GFP_KERNEL); 292 if (!mem_device) 293 return -ENOMEM; 294 295 INIT_LIST_HEAD(&mem_device->res_list); 296 mem_device->device = device; 297 sprintf(acpi_device_name(device), "%s", ACPI_MEMORY_DEVICE_NAME); 298 sprintf(acpi_device_class(device), "%s", ACPI_MEMORY_DEVICE_CLASS); 299 device->driver_data = mem_device; 300 301 /* Get the range from the _CRS */ 302 result = acpi_memory_get_device_resources(mem_device); 303 if (result) { 304 kfree(mem_device); 305 return result; 306 } 307 308 /* 309 * For booting existed memory devices, early boot code has recognized 310 * memory area by EFI/E820. If DSDT shows these memory devices on boot, 311 * hotplug is not necessary for them. 312 * For hot-added memory devices during runtime, it need hypercall to 313 * Xen hypervisor to add memory. 314 */ 315 if (!acpi_hotmem_initialized) 316 return 0; 317 318 if (!acpi_memory_check_device(mem_device)) 319 result = xen_acpi_memory_enable_device(mem_device); 320 321 return result; 322} 323 324static int xen_acpi_memory_device_remove(struct acpi_device *device) 325{ 326 struct acpi_memory_device *mem_device = NULL; 327 328 if (!device || !acpi_driver_data(device)) 329 return -EINVAL; 330 331 mem_device = acpi_driver_data(device); 332 kfree(mem_device); 333 334 return 0; 335} 336 337/* 338 * Helper function to check for memory device 339 */ 340static acpi_status is_memory_device(acpi_handle handle) 341{ 342 char *hardware_id; 343 acpi_status status; 344 struct acpi_device_info *info; 345 346 status = acpi_get_object_info(handle, &info); 347 if (ACPI_FAILURE(status)) 348 return status; 349 350 if (!(info->valid & ACPI_VALID_HID)) { 351 kfree(info); 352 return AE_ERROR; 353 } 354 355 hardware_id = info->hardware_id.string; 356 if ((hardware_id == NULL) || 357 (strcmp(hardware_id, ACPI_MEMORY_DEVICE_HID))) 358 status = AE_ERROR; 359 360 kfree(info); 361 return status; 362} 363 364static acpi_status 365acpi_memory_register_notify_handler(acpi_handle handle, 366 u32 level, void *ctxt, void **retv) 367{ 368 acpi_status status; 369 370 status = is_memory_device(handle); 371 if (ACPI_FAILURE(status)) 372 return AE_OK; /* continue */ 373 374 status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, 375 acpi_memory_device_notify, NULL); 376 /* continue */ 377 return AE_OK; 378} 379 380static acpi_status 381acpi_memory_deregister_notify_handler(acpi_handle handle, 382 u32 level, void *ctxt, void **retv) 383{ 384 acpi_status status; 385 386 status = is_memory_device(handle); 387 if (ACPI_FAILURE(status)) 388 return AE_OK; /* continue */ 389 390 status = acpi_remove_notify_handler(handle, 391 ACPI_SYSTEM_NOTIFY, 392 acpi_memory_device_notify); 393 394 return AE_OK; /* continue */ 395} 396 397static const struct acpi_device_id memory_device_ids[] = { 398 {ACPI_MEMORY_DEVICE_HID, 0}, 399 {"", 0}, 400}; 401MODULE_DEVICE_TABLE(acpi, memory_device_ids); 402 403static struct acpi_driver xen_acpi_memory_device_driver = { 404 .name = "acpi_memhotplug", 405 .class = ACPI_MEMORY_DEVICE_CLASS, 406 .ids = memory_device_ids, 407 .ops = { 408 .add = xen_acpi_memory_device_add, 409 .remove = xen_acpi_memory_device_remove, 410 }, 411}; 412 413static int __init xen_acpi_memory_device_init(void) 414{ 415 int result; 416 acpi_status status; 417 418 if (!xen_initial_domain()) 419 return -ENODEV; 420 421 /* unregister the stub which only used to reserve driver space */ 422 xen_stub_memory_device_exit(); 423 424 result = acpi_bus_register_driver(&xen_acpi_memory_device_driver); 425 if (result < 0) { 426 xen_stub_memory_device_init(); 427 return -ENODEV; 428 } 429 430 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 431 ACPI_UINT32_MAX, 432 acpi_memory_register_notify_handler, 433 NULL, NULL, NULL); 434 435 if (ACPI_FAILURE(status)) { 436 pr_warn(PREFIX "walk_namespace failed\n"); 437 acpi_bus_unregister_driver(&xen_acpi_memory_device_driver); 438 xen_stub_memory_device_init(); 439 return -ENODEV; 440 } 441 442 acpi_hotmem_initialized = true; 443 return 0; 444} 445 446static void __exit xen_acpi_memory_device_exit(void) 447{ 448 acpi_status status; 449 450 if (!xen_initial_domain()) 451 return; 452 453 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 454 ACPI_UINT32_MAX, 455 acpi_memory_deregister_notify_handler, 456 NULL, NULL, NULL); 457 if (ACPI_FAILURE(status)) 458 pr_warn(PREFIX "walk_namespace failed\n"); 459 460 acpi_bus_unregister_driver(&xen_acpi_memory_device_driver); 461 462 /* 463 * stub reserve space again to prevent any chance of native 464 * driver loading. 465 */ 466 xen_stub_memory_device_init(); 467 return; 468} 469 470module_init(xen_acpi_memory_device_init); 471module_exit(xen_acpi_memory_device_exit); 472ACPI_MODULE_NAME("xen-acpi-memhotplug"); 473MODULE_AUTHOR("Liu Jinsong <jinsong.liu@intel.com>"); 474MODULE_DESCRIPTION("Xen Hotplug Mem Driver"); 475MODULE_LICENSE("GPL"); 476