Merge branch 'x86-hyperv-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[sfrench/cifs-2.6.git] / drivers / xen / xen-acpi-cpuhotplug.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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");