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