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/cpu.h> 15#include <linux/acpi.h> 16#include <linux/uaccess.h> 17#include <acpi/processor.h> 18#include <xen/acpi.h> 19#include <xen/interface/platform.h> 20#include <asm/xen/hypercall.h> 21 22#define PREFIX "ACPI:xen_cpu_hotplug:" 23 24#define INSTALL_NOTIFY_HANDLER 0 25#define UNINSTALL_NOTIFY_HANDLER 1 26 27static acpi_status xen_acpi_cpu_hotadd(struct acpi_processor *pr); 28 29/* -------------------------------------------------------------------------- 30 Driver Interface 31-------------------------------------------------------------------------- */ 32 33static int xen_acpi_processor_enable(struct acpi_device *device) 34{ 35 acpi_status status = 0; 36 unsigned long long value; 37 union acpi_object object = { 0 }; 38 struct acpi_buffer buffer = { sizeof(union acpi_object), &object }; 39 struct acpi_processor *pr = acpi_driver_data(device); 40 41 if (!strcmp(acpi_device_hid(device), ACPI_PROCESSOR_OBJECT_HID)) { 42 /* Declared with "Processor" statement; match ProcessorID */ 43 status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer); 44 if (ACPI_FAILURE(status)) { 45 pr_err(PREFIX "Evaluating processor object\n"); 46 return -ENODEV; 47 } 48 49 pr->acpi_id = object.processor.proc_id; 50 } else { 51 /* Declared with "Device" statement; match _UID */ 52 status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID, 53 NULL, &value); 54 if (ACPI_FAILURE(status)) { 55 pr_err(PREFIX "Evaluating processor _UID\n"); 56 return -ENODEV; 57 } 58 59 pr->acpi_id = value; 60 } 61 62 pr->id = xen_pcpu_id(pr->acpi_id); 63 64 if (invalid_logical_cpuid(pr->id)) 65 /* This cpu is not presented at hypervisor, try to hotadd it */ 66 if (ACPI_FAILURE(xen_acpi_cpu_hotadd(pr))) { 67 pr_err(PREFIX "Hotadd CPU (acpi_id = %d) failed.\n", 68 pr->acpi_id); 69 return -ENODEV; 70 } 71 72 return 0; 73} 74 75static int xen_acpi_processor_add(struct acpi_device *device) 76{ 77 int ret; 78 struct acpi_processor *pr; 79 80 if (!device) 81 return -EINVAL; 82 83 pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL); 84 if (!pr) 85 return -ENOMEM; 86 87 pr->handle = device->handle; 88 strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME); 89 strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS); 90 device->driver_data = pr; 91 92 ret = xen_acpi_processor_enable(device); 93 if (ret) 94 pr_err(PREFIX "Error when enabling Xen processor\n"); 95 96 return ret; 97} 98 99static int xen_acpi_processor_remove(struct acpi_device *device) 100{ 101 struct acpi_processor *pr; 102 103 if (!device) 104 return -EINVAL; 105 106 pr = acpi_driver_data(device); 107 if (!pr) 108 return -EINVAL; 109 110 kfree(pr); 111 return 0; 112} 113 114/*-------------------------------------------------------------- 115 Acpi processor hotplug support 116--------------------------------------------------------------*/ 117 118static int is_processor_present(acpi_handle handle) 119{ 120 acpi_status status; 121 unsigned long long sta = 0; 122 123 124 status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); 125 126 if (ACPI_SUCCESS(status) && (sta & ACPI_STA_DEVICE_PRESENT)) 127 return 1; 128 129 /* 130 * _STA is mandatory for a processor that supports hot plug 131 */ 132 if (status == AE_NOT_FOUND) 133 pr_info(PREFIX "Processor does not support hot plug\n"); 134 else 135 pr_info(PREFIX "Processor Device is not present"); 136 return 0; 137} 138 139static int xen_apic_id(acpi_handle handle) 140{ 141 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 142 union acpi_object *obj; 143 struct acpi_madt_local_apic *lapic; 144 int apic_id; 145 146 if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer))) 147 return -EINVAL; 148 149 if (!buffer.length || !buffer.pointer) 150 return -EINVAL; 151 152 obj = buffer.pointer; 153 if (obj->type != ACPI_TYPE_BUFFER || 154 obj->buffer.length < sizeof(*lapic)) { 155 kfree(buffer.pointer); 156 return -EINVAL; 157 } 158 159 lapic = (struct acpi_madt_local_apic *)obj->buffer.pointer; 160 161 if (lapic->header.type != ACPI_MADT_TYPE_LOCAL_APIC || 162 !(lapic->lapic_flags & ACPI_MADT_ENABLED)) { 163 kfree(buffer.pointer); 164 return -EINVAL; 165 } 166 167 apic_id = (uint32_t)lapic->id; 168 kfree(buffer.pointer); 169 buffer.length = ACPI_ALLOCATE_BUFFER; 170 buffer.pointer = NULL; 171 172 return apic_id; 173} 174 175static int xen_hotadd_cpu(struct acpi_processor *pr) 176{ 177 int cpu_id, apic_id, pxm; 178 struct xen_platform_op op; 179 180 apic_id = xen_apic_id(pr->handle); 181 if (apic_id < 0) { 182 pr_err(PREFIX "Failed to get apic_id for acpi_id %d\n", 183 pr->acpi_id); 184 return -ENODEV; 185 } 186 187 pxm = xen_acpi_get_pxm(pr->handle); 188 if (pxm < 0) { 189 pr_err(PREFIX "Failed to get _PXM for acpi_id %d\n", 190 pr->acpi_id); 191 return pxm; 192 } 193 194 op.cmd = XENPF_cpu_hotadd; 195 op.u.cpu_add.apic_id = apic_id; 196 op.u.cpu_add.acpi_id = pr->acpi_id; 197 op.u.cpu_add.pxm = pxm; 198 199 cpu_id = HYPERVISOR_platform_op(&op); 200 if (cpu_id < 0) 201 pr_err(PREFIX "Failed to hotadd CPU for acpi_id %d\n", 202 pr->acpi_id); 203 204 return cpu_id; 205} 206 207static acpi_status xen_acpi_cpu_hotadd(struct acpi_processor *pr) 208{ 209 if (!is_processor_present(pr->handle)) 210 return AE_ERROR; 211 212 pr->id = xen_hotadd_cpu(pr); 213 if (invalid_logical_cpuid(pr->id)) 214 return AE_ERROR; 215 216 /* 217 * Sync with Xen hypervisor, providing new /sys/.../xen_cpuX 218 * interface after cpu hotadded. 219 */ 220 xen_pcpu_hotplug_sync(); 221 222 return AE_OK; 223} 224 225static int acpi_processor_device_remove(struct acpi_device *device) 226{ 227 pr_debug(PREFIX "Xen does not support CPU hotremove\n"); 228 229 return -ENOSYS; 230} 231 232static void acpi_processor_hotplug_notify(acpi_handle handle, 233 u32 event, void *data) 234{ 235 struct acpi_processor *pr; 236 struct acpi_device *device = NULL; 237 u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */ 238 int result; 239 240 acpi_scan_lock_acquire(); 241 242 switch (event) { 243 case ACPI_NOTIFY_BUS_CHECK: 244 case ACPI_NOTIFY_DEVICE_CHECK: 245 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 246 "Processor driver received %s event\n", 247 (event == ACPI_NOTIFY_BUS_CHECK) ? 248 "ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK")); 249 250 if (!is_processor_present(handle)) 251 break; 252 253 acpi_bus_get_device(handle, &device); 254 if (acpi_device_enumerated(device)) 255 break; 256 257 result = acpi_bus_scan(handle); 258 if (result) { 259 pr_err(PREFIX "Unable to add the device\n"); 260 break; 261 } 262 device = NULL; 263 acpi_bus_get_device(handle, &device); 264 if (!acpi_device_enumerated(device)) { 265 pr_err(PREFIX "Missing device object\n"); 266 break; 267 } 268 ost_code = ACPI_OST_SC_SUCCESS; 269 break; 270 271 case ACPI_NOTIFY_EJECT_REQUEST: 272 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 273 "received ACPI_NOTIFY_EJECT_REQUEST\n")); 274 275 if (acpi_bus_get_device(handle, &device)) { 276 pr_err(PREFIX "Device don't exist, dropping EJECT\n"); 277 break; 278 } 279 pr = acpi_driver_data(device); 280 if (!pr) { 281 pr_err(PREFIX "Driver data is NULL, dropping EJECT\n"); 282 break; 283 } 284 285 /* 286 * TBD: implement acpi_processor_device_remove if Xen support 287 * CPU hotremove in the future. 288 */ 289 acpi_processor_device_remove(device); 290 break; 291 292 default: 293 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 294 "Unsupported event [0x%x]\n", event)); 295 296 /* non-hotplug event; possibly handled by other handler */ 297 goto out; 298 } 299 300 (void) acpi_evaluate_ost(handle, event, ost_code, NULL); 301 302out: 303 acpi_scan_lock_release(); 304} 305 306static acpi_status is_processor_device(acpi_handle handle) 307{ 308 struct acpi_device_info *info; 309 char *hid; 310 acpi_status status; 311 312 status = acpi_get_object_info(handle, &info); 313 if (ACPI_FAILURE(status)) 314 return status; 315 316 if (info->type == ACPI_TYPE_PROCESSOR) { 317 kfree(info); 318 return AE_OK; /* found a processor object */ 319 } 320 321 if (!(info->valid & ACPI_VALID_HID)) { 322 kfree(info); 323 return AE_ERROR; 324 } 325 326 hid = info->hardware_id.string; 327 if ((hid == NULL) || strcmp(hid, ACPI_PROCESSOR_DEVICE_HID)) { 328 kfree(info); 329 return AE_ERROR; 330 } 331 332 kfree(info); 333 return AE_OK; /* found a processor device object */ 334} 335 336static acpi_status 337processor_walk_namespace_cb(acpi_handle handle, 338 u32 lvl, void *context, void **rv) 339{ 340 acpi_status status; 341 int *action = context; 342 343 status = is_processor_device(handle); 344 if (ACPI_FAILURE(status)) 345 return AE_OK; /* not a processor; continue to walk */ 346 347 switch (*action) { 348 case INSTALL_NOTIFY_HANDLER: 349 acpi_install_notify_handler(handle, 350 ACPI_SYSTEM_NOTIFY, 351 acpi_processor_hotplug_notify, 352 NULL); 353 break; 354 case UNINSTALL_NOTIFY_HANDLER: 355 acpi_remove_notify_handler(handle, 356 ACPI_SYSTEM_NOTIFY, 357 acpi_processor_hotplug_notify); 358 break; 359 default: 360 break; 361 } 362 363 /* found a processor; skip walking underneath */ 364 return AE_CTRL_DEPTH; 365} 366 367static 368void acpi_processor_install_hotplug_notify(void) 369{ 370 int action = INSTALL_NOTIFY_HANDLER; 371 acpi_walk_namespace(ACPI_TYPE_ANY, 372 ACPI_ROOT_OBJECT, 373 ACPI_UINT32_MAX, 374 processor_walk_namespace_cb, NULL, &action, NULL); 375} 376 377static 378void acpi_processor_uninstall_hotplug_notify(void) 379{ 380 int action = UNINSTALL_NOTIFY_HANDLER; 381 acpi_walk_namespace(ACPI_TYPE_ANY, 382 ACPI_ROOT_OBJECT, 383 ACPI_UINT32_MAX, 384 processor_walk_namespace_cb, NULL, &action, NULL); 385} 386 387static const struct acpi_device_id processor_device_ids[] = { 388 {ACPI_PROCESSOR_OBJECT_HID, 0}, 389 {ACPI_PROCESSOR_DEVICE_HID, 0}, 390 {"", 0}, 391}; 392MODULE_DEVICE_TABLE(acpi, processor_device_ids); 393 394static struct acpi_driver xen_acpi_processor_driver = { 395 .name = "processor", 396 .class = ACPI_PROCESSOR_CLASS, 397 .ids = processor_device_ids, 398 .ops = { 399 .add = xen_acpi_processor_add, 400 .remove = xen_acpi_processor_remove, 401 }, 402}; 403 404static int __init xen_acpi_processor_init(void) 405{ 406 int result = 0; 407 408 if (!xen_initial_domain()) 409 return -ENODEV; 410 411 /* unregister the stub which only used to reserve driver space */ 412 xen_stub_processor_exit(); 413 414 result = acpi_bus_register_driver(&xen_acpi_processor_driver); 415 if (result < 0) { 416 xen_stub_processor_init(); 417 return result; 418 } 419 420 acpi_processor_install_hotplug_notify(); 421 return 0; 422} 423 424static void __exit xen_acpi_processor_exit(void) 425{ 426 if (!xen_initial_domain()) 427 return; 428 429 acpi_processor_uninstall_hotplug_notify(); 430 431 acpi_bus_unregister_driver(&xen_acpi_processor_driver); 432 433 /* 434 * stub reserve space again to prevent any chance of native 435 * driver loading. 436 */ 437 xen_stub_processor_init(); 438 return; 439} 440 441module_init(xen_acpi_processor_init); 442module_exit(xen_acpi_processor_exit); 443ACPI_MODULE_NAME("xen-acpi-cpuhotplug"); 444MODULE_AUTHOR("Liu Jinsong <jinsong.liu@intel.com>"); 445MODULE_DESCRIPTION("Xen Hotplug CPU Driver"); 446MODULE_LICENSE("GPL"); 447