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