1f65c9bb3SLiu, Jinsong /******************************************************************************
2f65c9bb3SLiu, Jinsong * pcpu.c
3f65c9bb3SLiu, Jinsong * Management physical cpu in dom0, get pcpu info and provide sys interface
4f65c9bb3SLiu, Jinsong *
5f65c9bb3SLiu, Jinsong * Copyright (c) 2012 Intel Corporation
6f65c9bb3SLiu, Jinsong * Author: Liu, Jinsong <jinsong.liu@intel.com>
7f65c9bb3SLiu, Jinsong * Author: Jiang, Yunhong <yunhong.jiang@intel.com>
8f65c9bb3SLiu, Jinsong *
9f65c9bb3SLiu, Jinsong * This program is free software; you can redistribute it and/or
10f65c9bb3SLiu, Jinsong * modify it under the terms of the GNU General Public License version 2
11f65c9bb3SLiu, Jinsong * as published by the Free Software Foundation; or, when distributed
12f65c9bb3SLiu, Jinsong * separately from the Linux kernel or incorporated into other
13f65c9bb3SLiu, Jinsong * software packages, subject to the following license:
14f65c9bb3SLiu, Jinsong *
15f65c9bb3SLiu, Jinsong * Permission is hereby granted, free of charge, to any person obtaining a copy
16f65c9bb3SLiu, Jinsong * of this source file (the "Software"), to deal in the Software without
17f65c9bb3SLiu, Jinsong * restriction, including without limitation the rights to use, copy, modify,
18f65c9bb3SLiu, Jinsong * merge, publish, distribute, sublicense, and/or sell copies of the Software,
19f65c9bb3SLiu, Jinsong * and to permit persons to whom the Software is furnished to do so, subject to
20f65c9bb3SLiu, Jinsong * the following conditions:
21f65c9bb3SLiu, Jinsong *
22f65c9bb3SLiu, Jinsong * The above copyright notice and this permission notice shall be included in
23f65c9bb3SLiu, Jinsong * all copies or substantial portions of the Software.
24f65c9bb3SLiu, Jinsong *
25f65c9bb3SLiu, Jinsong * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26f65c9bb3SLiu, Jinsong * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27f65c9bb3SLiu, Jinsong * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28f65c9bb3SLiu, Jinsong * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29f65c9bb3SLiu, Jinsong * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30f65c9bb3SLiu, Jinsong * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
31f65c9bb3SLiu, Jinsong * IN THE SOFTWARE.
32f65c9bb3SLiu, Jinsong */
33f65c9bb3SLiu, Jinsong
34283c0972SJoe Perches #define pr_fmt(fmt) "xen_cpu: " fmt
35283c0972SJoe Perches
36f65c9bb3SLiu, Jinsong #include <linux/interrupt.h>
37f65c9bb3SLiu, Jinsong #include <linux/spinlock.h>
38f65c9bb3SLiu, Jinsong #include <linux/cpu.h>
39f65c9bb3SLiu, Jinsong #include <linux/stat.h>
40f65c9bb3SLiu, Jinsong #include <linux/capability.h>
41f65c9bb3SLiu, Jinsong
42f65c9bb3SLiu, Jinsong #include <xen/xen.h>
436cb606f1SRashika Kheria #include <xen/acpi.h>
44f65c9bb3SLiu, Jinsong #include <xen/xenbus.h>
45f65c9bb3SLiu, Jinsong #include <xen/events.h>
46f65c9bb3SLiu, Jinsong #include <xen/interface/platform.h>
47f65c9bb3SLiu, Jinsong #include <asm/xen/hypervisor.h>
48f65c9bb3SLiu, Jinsong #include <asm/xen/hypercall.h>
49f65c9bb3SLiu, Jinsong
50*32ca78deSRoger Pau Monne #ifdef CONFIG_ACPI
51*32ca78deSRoger Pau Monne #include <acpi/processor.h>
52*32ca78deSRoger Pau Monne #endif
53f65c9bb3SLiu, Jinsong
54f65c9bb3SLiu, Jinsong /*
55f65c9bb3SLiu, Jinsong * @cpu_id: Xen physical cpu logic number
56f65c9bb3SLiu, Jinsong * @flags: Xen physical cpu status flag
57f65c9bb3SLiu, Jinsong * - XEN_PCPU_FLAGS_ONLINE: cpu is online
58f65c9bb3SLiu, Jinsong * - XEN_PCPU_FLAGS_INVALID: cpu is not present
59f65c9bb3SLiu, Jinsong */
60f65c9bb3SLiu, Jinsong struct pcpu {
61f65c9bb3SLiu, Jinsong struct list_head list;
62f65c9bb3SLiu, Jinsong struct device dev;
63f65c9bb3SLiu, Jinsong uint32_t cpu_id;
64073828e9SRoger Pau Monne uint32_t acpi_id;
65f65c9bb3SLiu, Jinsong uint32_t flags;
66f65c9bb3SLiu, Jinsong };
67f65c9bb3SLiu, Jinsong
68f65c9bb3SLiu, Jinsong static struct bus_type xen_pcpu_subsys = {
69f65c9bb3SLiu, Jinsong .name = "xen_cpu",
70f65c9bb3SLiu, Jinsong .dev_name = "xen_cpu",
71f65c9bb3SLiu, Jinsong };
72f65c9bb3SLiu, Jinsong
73f65c9bb3SLiu, Jinsong static DEFINE_MUTEX(xen_pcpu_lock);
74f65c9bb3SLiu, Jinsong
75f65c9bb3SLiu, Jinsong static LIST_HEAD(xen_pcpus);
76f65c9bb3SLiu, Jinsong
xen_pcpu_down(uint32_t cpu_id)77f65c9bb3SLiu, Jinsong static int xen_pcpu_down(uint32_t cpu_id)
78f65c9bb3SLiu, Jinsong {
79f65c9bb3SLiu, Jinsong struct xen_platform_op op = {
80f65c9bb3SLiu, Jinsong .cmd = XENPF_cpu_offline,
81f65c9bb3SLiu, Jinsong .interface_version = XENPF_INTERFACE_VERSION,
82f65c9bb3SLiu, Jinsong .u.cpu_ol.cpuid = cpu_id,
83f65c9bb3SLiu, Jinsong };
84f65c9bb3SLiu, Jinsong
85cfafae94SStefano Stabellini return HYPERVISOR_platform_op(&op);
86f65c9bb3SLiu, Jinsong }
87f65c9bb3SLiu, Jinsong
xen_pcpu_up(uint32_t cpu_id)88f65c9bb3SLiu, Jinsong static int xen_pcpu_up(uint32_t cpu_id)
89f65c9bb3SLiu, Jinsong {
90f65c9bb3SLiu, Jinsong struct xen_platform_op op = {
91f65c9bb3SLiu, Jinsong .cmd = XENPF_cpu_online,
92f65c9bb3SLiu, Jinsong .interface_version = XENPF_INTERFACE_VERSION,
93f65c9bb3SLiu, Jinsong .u.cpu_ol.cpuid = cpu_id,
94f65c9bb3SLiu, Jinsong };
95f65c9bb3SLiu, Jinsong
96cfafae94SStefano Stabellini return HYPERVISOR_platform_op(&op);
97f65c9bb3SLiu, Jinsong }
98f65c9bb3SLiu, Jinsong
online_show(struct device * dev,struct device_attribute * attr,char * buf)9920600617SYueHaibing static ssize_t online_show(struct device *dev,
100f65c9bb3SLiu, Jinsong struct device_attribute *attr,
101f65c9bb3SLiu, Jinsong char *buf)
102f65c9bb3SLiu, Jinsong {
103f65c9bb3SLiu, Jinsong struct pcpu *cpu = container_of(dev, struct pcpu, dev);
104f65c9bb3SLiu, Jinsong
105f65c9bb3SLiu, Jinsong return sprintf(buf, "%u\n", !!(cpu->flags & XEN_PCPU_FLAGS_ONLINE));
106f65c9bb3SLiu, Jinsong }
107f65c9bb3SLiu, Jinsong
online_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)10820600617SYueHaibing static ssize_t __ref online_store(struct device *dev,
109f65c9bb3SLiu, Jinsong struct device_attribute *attr,
110f65c9bb3SLiu, Jinsong const char *buf, size_t count)
111f65c9bb3SLiu, Jinsong {
112f65c9bb3SLiu, Jinsong struct pcpu *pcpu = container_of(dev, struct pcpu, dev);
113f65c9bb3SLiu, Jinsong unsigned long long val;
114f65c9bb3SLiu, Jinsong ssize_t ret;
115f65c9bb3SLiu, Jinsong
116f65c9bb3SLiu, Jinsong if (!capable(CAP_SYS_ADMIN))
117f65c9bb3SLiu, Jinsong return -EPERM;
118f65c9bb3SLiu, Jinsong
119f65c9bb3SLiu, Jinsong if (kstrtoull(buf, 0, &val) < 0)
120f65c9bb3SLiu, Jinsong return -EINVAL;
121f65c9bb3SLiu, Jinsong
122f65c9bb3SLiu, Jinsong switch (val) {
123f65c9bb3SLiu, Jinsong case 0:
124f65c9bb3SLiu, Jinsong ret = xen_pcpu_down(pcpu->cpu_id);
125f65c9bb3SLiu, Jinsong break;
126f65c9bb3SLiu, Jinsong case 1:
127f65c9bb3SLiu, Jinsong ret = xen_pcpu_up(pcpu->cpu_id);
128f65c9bb3SLiu, Jinsong break;
129f65c9bb3SLiu, Jinsong default:
130f65c9bb3SLiu, Jinsong ret = -EINVAL;
131f65c9bb3SLiu, Jinsong }
132f65c9bb3SLiu, Jinsong
133f65c9bb3SLiu, Jinsong if (ret >= 0)
134f65c9bb3SLiu, Jinsong ret = count;
135f65c9bb3SLiu, Jinsong return ret;
136f65c9bb3SLiu, Jinsong }
13720600617SYueHaibing static DEVICE_ATTR_RW(online);
138f65c9bb3SLiu, Jinsong
1394644e5abSTakashi Iwai static struct attribute *pcpu_dev_attrs[] = {
1404644e5abSTakashi Iwai &dev_attr_online.attr,
1414644e5abSTakashi Iwai NULL
1424644e5abSTakashi Iwai };
1434644e5abSTakashi Iwai
pcpu_dev_is_visible(struct kobject * kobj,struct attribute * attr,int idx)1444644e5abSTakashi Iwai static umode_t pcpu_dev_is_visible(struct kobject *kobj,
1454644e5abSTakashi Iwai struct attribute *attr, int idx)
1464644e5abSTakashi Iwai {
1474644e5abSTakashi Iwai struct device *dev = kobj_to_dev(kobj);
1484644e5abSTakashi Iwai /*
1494644e5abSTakashi Iwai * Xen never offline cpu0 due to several restrictions
1504644e5abSTakashi Iwai * and assumptions. This basically doesn't add a sys control
1514644e5abSTakashi Iwai * to user, one cannot attempt to offline BSP.
1524644e5abSTakashi Iwai */
1534644e5abSTakashi Iwai return dev->id ? attr->mode : 0;
1544644e5abSTakashi Iwai }
1554644e5abSTakashi Iwai
1564644e5abSTakashi Iwai static const struct attribute_group pcpu_dev_group = {
1574644e5abSTakashi Iwai .attrs = pcpu_dev_attrs,
1584644e5abSTakashi Iwai .is_visible = pcpu_dev_is_visible,
1594644e5abSTakashi Iwai };
1604644e5abSTakashi Iwai
1614644e5abSTakashi Iwai static const struct attribute_group *pcpu_dev_groups[] = {
1624644e5abSTakashi Iwai &pcpu_dev_group,
1634644e5abSTakashi Iwai NULL
1644644e5abSTakashi Iwai };
1654644e5abSTakashi Iwai
xen_pcpu_online(uint32_t flags)166f65c9bb3SLiu, Jinsong static bool xen_pcpu_online(uint32_t flags)
167f65c9bb3SLiu, Jinsong {
168f65c9bb3SLiu, Jinsong return !!(flags & XEN_PCPU_FLAGS_ONLINE);
169f65c9bb3SLiu, Jinsong }
170f65c9bb3SLiu, Jinsong
pcpu_online_status(struct xenpf_pcpuinfo * info,struct pcpu * pcpu)171f65c9bb3SLiu, Jinsong static void pcpu_online_status(struct xenpf_pcpuinfo *info,
172f65c9bb3SLiu, Jinsong struct pcpu *pcpu)
173f65c9bb3SLiu, Jinsong {
174f65c9bb3SLiu, Jinsong if (xen_pcpu_online(info->flags) &&
175f65c9bb3SLiu, Jinsong !xen_pcpu_online(pcpu->flags)) {
176f65c9bb3SLiu, Jinsong /* the pcpu is onlined */
177f65c9bb3SLiu, Jinsong pcpu->flags |= XEN_PCPU_FLAGS_ONLINE;
178f65c9bb3SLiu, Jinsong kobject_uevent(&pcpu->dev.kobj, KOBJ_ONLINE);
179f65c9bb3SLiu, Jinsong } else if (!xen_pcpu_online(info->flags) &&
180f65c9bb3SLiu, Jinsong xen_pcpu_online(pcpu->flags)) {
181f65c9bb3SLiu, Jinsong /* The pcpu is offlined */
182f65c9bb3SLiu, Jinsong pcpu->flags &= ~XEN_PCPU_FLAGS_ONLINE;
183f65c9bb3SLiu, Jinsong kobject_uevent(&pcpu->dev.kobj, KOBJ_OFFLINE);
184f65c9bb3SLiu, Jinsong }
185f65c9bb3SLiu, Jinsong }
186f65c9bb3SLiu, Jinsong
get_pcpu(uint32_t cpu_id)187f65c9bb3SLiu, Jinsong static struct pcpu *get_pcpu(uint32_t cpu_id)
188f65c9bb3SLiu, Jinsong {
189f65c9bb3SLiu, Jinsong struct pcpu *pcpu;
190f65c9bb3SLiu, Jinsong
191f65c9bb3SLiu, Jinsong list_for_each_entry(pcpu, &xen_pcpus, list) {
192f65c9bb3SLiu, Jinsong if (pcpu->cpu_id == cpu_id)
193f65c9bb3SLiu, Jinsong return pcpu;
194f65c9bb3SLiu, Jinsong }
195f65c9bb3SLiu, Jinsong
196f65c9bb3SLiu, Jinsong return NULL;
197f65c9bb3SLiu, Jinsong }
198f65c9bb3SLiu, Jinsong
pcpu_release(struct device * dev)199f65c9bb3SLiu, Jinsong static void pcpu_release(struct device *dev)
200f65c9bb3SLiu, Jinsong {
201f65c9bb3SLiu, Jinsong struct pcpu *pcpu = container_of(dev, struct pcpu, dev);
202f65c9bb3SLiu, Jinsong
203f65c9bb3SLiu, Jinsong list_del(&pcpu->list);
204f65c9bb3SLiu, Jinsong kfree(pcpu);
205f65c9bb3SLiu, Jinsong }
206f65c9bb3SLiu, Jinsong
unregister_and_remove_pcpu(struct pcpu * pcpu)207f65c9bb3SLiu, Jinsong static void unregister_and_remove_pcpu(struct pcpu *pcpu)
208f65c9bb3SLiu, Jinsong {
209f65c9bb3SLiu, Jinsong struct device *dev;
210f65c9bb3SLiu, Jinsong
211f65c9bb3SLiu, Jinsong if (!pcpu)
212f65c9bb3SLiu, Jinsong return;
213f65c9bb3SLiu, Jinsong
214f65c9bb3SLiu, Jinsong dev = &pcpu->dev;
215f65c9bb3SLiu, Jinsong /* pcpu remove would be implicitly done */
216f65c9bb3SLiu, Jinsong device_unregister(dev);
217f65c9bb3SLiu, Jinsong }
218f65c9bb3SLiu, Jinsong
register_pcpu(struct pcpu * pcpu)219f65c9bb3SLiu, Jinsong static int register_pcpu(struct pcpu *pcpu)
220f65c9bb3SLiu, Jinsong {
221f65c9bb3SLiu, Jinsong struct device *dev;
222f65c9bb3SLiu, Jinsong int err = -EINVAL;
223f65c9bb3SLiu, Jinsong
224f65c9bb3SLiu, Jinsong if (!pcpu)
225f65c9bb3SLiu, Jinsong return err;
226f65c9bb3SLiu, Jinsong
227f65c9bb3SLiu, Jinsong dev = &pcpu->dev;
228f65c9bb3SLiu, Jinsong dev->bus = &xen_pcpu_subsys;
229f65c9bb3SLiu, Jinsong dev->id = pcpu->cpu_id;
230f65c9bb3SLiu, Jinsong dev->release = pcpu_release;
2314644e5abSTakashi Iwai dev->groups = pcpu_dev_groups;
232f65c9bb3SLiu, Jinsong
233f65c9bb3SLiu, Jinsong err = device_register(dev);
234f65c9bb3SLiu, Jinsong if (err) {
235da36a2a7SYang Yingliang put_device(dev);
236f65c9bb3SLiu, Jinsong return err;
237f65c9bb3SLiu, Jinsong }
238f65c9bb3SLiu, Jinsong
239f65c9bb3SLiu, Jinsong return 0;
240f65c9bb3SLiu, Jinsong }
241f65c9bb3SLiu, Jinsong
create_and_register_pcpu(struct xenpf_pcpuinfo * info)242f65c9bb3SLiu, Jinsong static struct pcpu *create_and_register_pcpu(struct xenpf_pcpuinfo *info)
243f65c9bb3SLiu, Jinsong {
244f65c9bb3SLiu, Jinsong struct pcpu *pcpu;
245f65c9bb3SLiu, Jinsong int err;
246f65c9bb3SLiu, Jinsong
247f65c9bb3SLiu, Jinsong if (info->flags & XEN_PCPU_FLAGS_INVALID)
248f65c9bb3SLiu, Jinsong return ERR_PTR(-ENODEV);
249f65c9bb3SLiu, Jinsong
250f65c9bb3SLiu, Jinsong pcpu = kzalloc(sizeof(struct pcpu), GFP_KERNEL);
251f65c9bb3SLiu, Jinsong if (!pcpu)
252f65c9bb3SLiu, Jinsong return ERR_PTR(-ENOMEM);
253f65c9bb3SLiu, Jinsong
254f65c9bb3SLiu, Jinsong INIT_LIST_HEAD(&pcpu->list);
255f65c9bb3SLiu, Jinsong pcpu->cpu_id = info->xen_cpuid;
256073828e9SRoger Pau Monne pcpu->acpi_id = info->acpi_id;
257f65c9bb3SLiu, Jinsong pcpu->flags = info->flags;
258f65c9bb3SLiu, Jinsong
259f65c9bb3SLiu, Jinsong /* Need hold on xen_pcpu_lock before pcpu list manipulations */
260f65c9bb3SLiu, Jinsong list_add_tail(&pcpu->list, &xen_pcpus);
261f65c9bb3SLiu, Jinsong
262f65c9bb3SLiu, Jinsong err = register_pcpu(pcpu);
263f65c9bb3SLiu, Jinsong if (err) {
264283c0972SJoe Perches pr_warn("Failed to register pcpu%u\n", info->xen_cpuid);
265f65c9bb3SLiu, Jinsong return ERR_PTR(-ENOENT);
266f65c9bb3SLiu, Jinsong }
267f65c9bb3SLiu, Jinsong
268f65c9bb3SLiu, Jinsong return pcpu;
269f65c9bb3SLiu, Jinsong }
270f65c9bb3SLiu, Jinsong
271f65c9bb3SLiu, Jinsong /*
272f65c9bb3SLiu, Jinsong * Caller should hold the xen_pcpu_lock
273f65c9bb3SLiu, Jinsong */
sync_pcpu(uint32_t cpu,uint32_t * max_cpu)274f65c9bb3SLiu, Jinsong static int sync_pcpu(uint32_t cpu, uint32_t *max_cpu)
275f65c9bb3SLiu, Jinsong {
276f65c9bb3SLiu, Jinsong int ret;
277f65c9bb3SLiu, Jinsong struct pcpu *pcpu = NULL;
278f65c9bb3SLiu, Jinsong struct xenpf_pcpuinfo *info;
279f65c9bb3SLiu, Jinsong struct xen_platform_op op = {
280f65c9bb3SLiu, Jinsong .cmd = XENPF_get_cpuinfo,
281f65c9bb3SLiu, Jinsong .interface_version = XENPF_INTERFACE_VERSION,
282f65c9bb3SLiu, Jinsong .u.pcpu_info.xen_cpuid = cpu,
283f65c9bb3SLiu, Jinsong };
284f65c9bb3SLiu, Jinsong
285cfafae94SStefano Stabellini ret = HYPERVISOR_platform_op(&op);
286f65c9bb3SLiu, Jinsong if (ret)
287f65c9bb3SLiu, Jinsong return ret;
288f65c9bb3SLiu, Jinsong
289f65c9bb3SLiu, Jinsong info = &op.u.pcpu_info;
290f65c9bb3SLiu, Jinsong if (max_cpu)
291f65c9bb3SLiu, Jinsong *max_cpu = info->max_present;
292f65c9bb3SLiu, Jinsong
293f65c9bb3SLiu, Jinsong pcpu = get_pcpu(cpu);
294f65c9bb3SLiu, Jinsong
295f65c9bb3SLiu, Jinsong /*
296f65c9bb3SLiu, Jinsong * Only those at cpu present map has its sys interface.
297f65c9bb3SLiu, Jinsong */
298f65c9bb3SLiu, Jinsong if (info->flags & XEN_PCPU_FLAGS_INVALID) {
299f65c9bb3SLiu, Jinsong unregister_and_remove_pcpu(pcpu);
300f65c9bb3SLiu, Jinsong return 0;
301f65c9bb3SLiu, Jinsong }
302f65c9bb3SLiu, Jinsong
303f65c9bb3SLiu, Jinsong if (!pcpu) {
304f65c9bb3SLiu, Jinsong pcpu = create_and_register_pcpu(info);
305f65c9bb3SLiu, Jinsong if (IS_ERR_OR_NULL(pcpu))
306f65c9bb3SLiu, Jinsong return -ENODEV;
307f65c9bb3SLiu, Jinsong } else
308f65c9bb3SLiu, Jinsong pcpu_online_status(info, pcpu);
309f65c9bb3SLiu, Jinsong
310f65c9bb3SLiu, Jinsong return 0;
311f65c9bb3SLiu, Jinsong }
312f65c9bb3SLiu, Jinsong
313f65c9bb3SLiu, Jinsong /*
314f65c9bb3SLiu, Jinsong * Sync dom0's pcpu information with xen hypervisor's
315f65c9bb3SLiu, Jinsong */
xen_sync_pcpus(void)316f65c9bb3SLiu, Jinsong static int xen_sync_pcpus(void)
317f65c9bb3SLiu, Jinsong {
318f65c9bb3SLiu, Jinsong /*
319f65c9bb3SLiu, Jinsong * Boot cpu always have cpu_id 0 in xen
320f65c9bb3SLiu, Jinsong */
321f65c9bb3SLiu, Jinsong uint32_t cpu = 0, max_cpu = 0;
322f65c9bb3SLiu, Jinsong int err = 0;
323f65c9bb3SLiu, Jinsong struct pcpu *pcpu, *tmp;
324f65c9bb3SLiu, Jinsong
325f65c9bb3SLiu, Jinsong mutex_lock(&xen_pcpu_lock);
326f65c9bb3SLiu, Jinsong
327f65c9bb3SLiu, Jinsong while (!err && (cpu <= max_cpu)) {
328f65c9bb3SLiu, Jinsong err = sync_pcpu(cpu, &max_cpu);
329f65c9bb3SLiu, Jinsong cpu++;
330f65c9bb3SLiu, Jinsong }
331f65c9bb3SLiu, Jinsong
332f65c9bb3SLiu, Jinsong if (err)
333f65c9bb3SLiu, Jinsong list_for_each_entry_safe(pcpu, tmp, &xen_pcpus, list)
334f65c9bb3SLiu, Jinsong unregister_and_remove_pcpu(pcpu);
335f65c9bb3SLiu, Jinsong
336f65c9bb3SLiu, Jinsong mutex_unlock(&xen_pcpu_lock);
337f65c9bb3SLiu, Jinsong
338f65c9bb3SLiu, Jinsong return err;
339f65c9bb3SLiu, Jinsong }
340f65c9bb3SLiu, Jinsong
xen_pcpu_work_fn(struct work_struct * work)341f65c9bb3SLiu, Jinsong static void xen_pcpu_work_fn(struct work_struct *work)
342f65c9bb3SLiu, Jinsong {
343f65c9bb3SLiu, Jinsong xen_sync_pcpus();
344f65c9bb3SLiu, Jinsong }
345f65c9bb3SLiu, Jinsong static DECLARE_WORK(xen_pcpu_work, xen_pcpu_work_fn);
346f65c9bb3SLiu, Jinsong
xen_pcpu_interrupt(int irq,void * dev_id)347f65c9bb3SLiu, Jinsong static irqreturn_t xen_pcpu_interrupt(int irq, void *dev_id)
348f65c9bb3SLiu, Jinsong {
349f65c9bb3SLiu, Jinsong schedule_work(&xen_pcpu_work);
350f65c9bb3SLiu, Jinsong return IRQ_HANDLED;
351f65c9bb3SLiu, Jinsong }
352f65c9bb3SLiu, Jinsong
xen_pcpu_init(void)353f65c9bb3SLiu, Jinsong static int __init xen_pcpu_init(void)
354f65c9bb3SLiu, Jinsong {
355f65c9bb3SLiu, Jinsong int irq, ret;
356f65c9bb3SLiu, Jinsong
357f65c9bb3SLiu, Jinsong if (!xen_initial_domain())
358f65c9bb3SLiu, Jinsong return -ENODEV;
359f65c9bb3SLiu, Jinsong
360f65c9bb3SLiu, Jinsong irq = bind_virq_to_irqhandler(VIRQ_PCPU_STATE, 0,
361f65c9bb3SLiu, Jinsong xen_pcpu_interrupt, 0,
362f65c9bb3SLiu, Jinsong "xen-pcpu", NULL);
363f65c9bb3SLiu, Jinsong if (irq < 0) {
364283c0972SJoe Perches pr_warn("Failed to bind pcpu virq\n");
365f65c9bb3SLiu, Jinsong return irq;
366f65c9bb3SLiu, Jinsong }
367f65c9bb3SLiu, Jinsong
368f65c9bb3SLiu, Jinsong ret = subsys_system_register(&xen_pcpu_subsys, NULL);
369f65c9bb3SLiu, Jinsong if (ret) {
370283c0972SJoe Perches pr_warn("Failed to register pcpu subsys\n");
371f65c9bb3SLiu, Jinsong goto err1;
372f65c9bb3SLiu, Jinsong }
373f65c9bb3SLiu, Jinsong
374f65c9bb3SLiu, Jinsong ret = xen_sync_pcpus();
375f65c9bb3SLiu, Jinsong if (ret) {
376283c0972SJoe Perches pr_warn("Failed to sync pcpu info\n");
377f65c9bb3SLiu, Jinsong goto err2;
378f65c9bb3SLiu, Jinsong }
379f65c9bb3SLiu, Jinsong
380f65c9bb3SLiu, Jinsong return 0;
381f65c9bb3SLiu, Jinsong
382f65c9bb3SLiu, Jinsong err2:
383f65c9bb3SLiu, Jinsong bus_unregister(&xen_pcpu_subsys);
384f65c9bb3SLiu, Jinsong err1:
385f65c9bb3SLiu, Jinsong unbind_from_irqhandler(irq, NULL);
386f65c9bb3SLiu, Jinsong return ret;
387f65c9bb3SLiu, Jinsong }
388f65c9bb3SLiu, Jinsong arch_initcall(xen_pcpu_init);
389073828e9SRoger Pau Monne
390073828e9SRoger Pau Monne #ifdef CONFIG_ACPI
xen_processor_present(uint32_t acpi_id)391073828e9SRoger Pau Monne bool __init xen_processor_present(uint32_t acpi_id)
392073828e9SRoger Pau Monne {
393073828e9SRoger Pau Monne const struct pcpu *pcpu;
394073828e9SRoger Pau Monne bool online = false;
395073828e9SRoger Pau Monne
396073828e9SRoger Pau Monne mutex_lock(&xen_pcpu_lock);
397073828e9SRoger Pau Monne list_for_each_entry(pcpu, &xen_pcpus, list)
398073828e9SRoger Pau Monne if (pcpu->acpi_id == acpi_id) {
399073828e9SRoger Pau Monne online = pcpu->flags & XEN_PCPU_FLAGS_ONLINE;
400073828e9SRoger Pau Monne break;
401073828e9SRoger Pau Monne }
402073828e9SRoger Pau Monne mutex_unlock(&xen_pcpu_lock);
403073828e9SRoger Pau Monne
404073828e9SRoger Pau Monne return online;
405073828e9SRoger Pau Monne }
406*32ca78deSRoger Pau Monne
xen_sanitize_proc_cap_bits(uint32_t * cap)407*32ca78deSRoger Pau Monne void xen_sanitize_proc_cap_bits(uint32_t *cap)
408*32ca78deSRoger Pau Monne {
409*32ca78deSRoger Pau Monne struct xen_platform_op op = {
410*32ca78deSRoger Pau Monne .cmd = XENPF_set_processor_pminfo,
411*32ca78deSRoger Pau Monne .u.set_pminfo.id = -1,
412*32ca78deSRoger Pau Monne .u.set_pminfo.type = XEN_PM_PDC,
413*32ca78deSRoger Pau Monne };
414*32ca78deSRoger Pau Monne u32 buf[3] = { ACPI_PDC_REVISION_ID, 1, *cap };
415*32ca78deSRoger Pau Monne int ret;
416*32ca78deSRoger Pau Monne
417*32ca78deSRoger Pau Monne set_xen_guest_handle(op.u.set_pminfo.pdc, buf);
418*32ca78deSRoger Pau Monne ret = HYPERVISOR_platform_op(&op);
419*32ca78deSRoger Pau Monne if (ret)
420*32ca78deSRoger Pau Monne pr_err("sanitize of _PDC buffer bits from Xen failed: %d\n",
421*32ca78deSRoger Pau Monne ret);
422*32ca78deSRoger Pau Monne else
423*32ca78deSRoger Pau Monne *cap = buf[2];
424*32ca78deSRoger Pau Monne }
425073828e9SRoger Pau Monne #endif
426