• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
27 static acpi_status xen_acpi_cpu_hotadd(struct acpi_processor *pr);
28 
29 /* --------------------------------------------------------------------------
30 				Driver Interface
31 -------------------------------------------------------------------------- */
32 
xen_acpi_processor_enable(struct acpi_device * device)33 static 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 
xen_acpi_processor_add(struct acpi_device * device)75 static 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 
xen_acpi_processor_remove(struct acpi_device * device)99 static 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 
is_processor_present(acpi_handle handle)118 static 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 
xen_apic_id(acpi_handle handle)139 static 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 
xen_hotadd_cpu(struct acpi_processor * pr)175 static 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 
xen_acpi_cpu_hotadd(struct acpi_processor * pr)207 static 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 
acpi_processor_device_remove(struct acpi_device * device)225 static 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 
acpi_processor_hotplug_notify(acpi_handle handle,u32 event,void * data)232 static 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 
302 out:
303 	acpi_scan_lock_release();
304 }
305 
is_processor_device(acpi_handle handle)306 static 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 
336 static acpi_status
processor_walk_namespace_cb(acpi_handle handle,u32 lvl,void * context,void ** rv)337 processor_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 
367 static
acpi_processor_install_hotplug_notify(void)368 void 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 
377 static
acpi_processor_uninstall_hotplug_notify(void)378 void 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 
387 static const struct acpi_device_id processor_device_ids[] = {
388 	{ACPI_PROCESSOR_OBJECT_HID, 0},
389 	{ACPI_PROCESSOR_DEVICE_HID, 0},
390 	{"", 0},
391 };
392 MODULE_DEVICE_TABLE(acpi, processor_device_ids);
393 
394 static 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 
xen_acpi_processor_init(void)404 static 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 
xen_acpi_processor_exit(void)424 static 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 
441 module_init(xen_acpi_processor_init);
442 module_exit(xen_acpi_processor_exit);
443 ACPI_MODULE_NAME("xen-acpi-cpuhotplug");
444 MODULE_AUTHOR("Liu Jinsong <jinsong.liu@intel.com>");
445 MODULE_DESCRIPTION("Xen Hotplug CPU Driver");
446 MODULE_LICENSE("GPL");
447