2 * processor_extcntl_xen.c - interface to notify Xen
4 * Copyright (C) 2008, Intel corporation
6 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or (at
11 * your option) any later version.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
24 #include <linux/kernel.h>
25 #include <linux/init.h>
26 #include <linux/types.h>
27 #include <linux/acpi.h>
29 #include <linux/cpu.h>
30 #include <linux/export.h>
31 #include <linux/cpufreq.h>
32 #include <acpi/processor.h>
33 #include <asm/hypercall.h>
35 static int xen_cx_notifier(struct acpi_processor *pr, int action)
37 int ret, count = 0, i;
38 xen_platform_op_t op = {
39 .cmd = XENPF_set_processor_pminfo,
40 .interface_version = XENPF_INTERFACE_VERSION,
41 .u.set_pminfo.id = pr->acpi_id,
42 .u.set_pminfo.type = XEN_PM_CX,
44 struct xen_processor_cx *data, *buf;
45 struct acpi_processor_cx *cx;
47 /* Convert to Xen defined structure and hypercall */
48 buf = kzalloc(pr->power.count * sizeof(struct xen_processor_cx),
54 for (i = 1; i <= pr->power.count; i++) {
55 cx = &pr->power.states[i];
56 /* Skip invalid cstate entry */
60 data->type = cx->type;
61 data->latency = cx->latency;
62 data->power = cx->power;
63 data->reg.space_id = cx->reg.space_id;
64 data->reg.bit_width = cx->reg.bit_width;
65 data->reg.bit_offset = cx->reg.bit_offset;
66 data->reg.access_size = cx->reg.access_size;
67 data->reg.address = cx->reg.address;
69 /* Get dependency relationships */
71 pr_warning("_CSD found: Not supported for now!\n");
76 set_xen_guest_handle(data->dp, NULL);
84 pr_info("No available Cx info for cpu %d\n", pr->acpi_id);
89 op.u.set_pminfo.u.power.count = count;
90 op.u.set_pminfo.u.power.flags.bm_control = pr->flags.bm_control;
91 op.u.set_pminfo.u.power.flags.bm_check = pr->flags.bm_check;
92 op.u.set_pminfo.u.power.flags.has_cst = pr->flags.has_cst;
93 op.u.set_pminfo.u.power.flags.power_setup_done = pr->flags.power_setup_done;
95 set_xen_guest_handle(op.u.set_pminfo.u.power.states, buf);
96 ret = HYPERVISOR_platform_op(&op);
101 static int xen_px_notifier(struct acpi_processor *pr, int action)
104 xen_platform_op_t op = {
105 .cmd = XENPF_set_processor_pminfo,
106 .interface_version = XENPF_INTERFACE_VERSION,
107 .u.set_pminfo.id = pr->acpi_id,
108 .u.set_pminfo.type = XEN_PM_PX,
110 struct xen_processor_performance *perf;
111 struct xen_processor_px *states = NULL;
112 struct acpi_processor_performance *px;
113 struct acpi_psd_package *pdomain;
118 perf = &op.u.set_pminfo.u.perf;
119 px = pr->performance;
124 case PROCESSOR_PM_CHANGE:
125 /* ppc dynamic handle */
126 perf->flags = XEN_PX_PPC;
127 perf->platform_limit = pr->performance_platform_limit;
129 ret = HYPERVISOR_platform_op(&op);
132 case PROCESSOR_PM_INIT:
134 perf->flags = XEN_PX_PPC |
140 perf->platform_limit = pr->performance_platform_limit;
143 xen_convert_pct_reg(&perf->control_register, &px->control_register);
144 xen_convert_pct_reg(&perf->status_register, &px->status_register);
147 perf->state_count = px->state_count;
148 states = kzalloc(px->state_count*sizeof(xen_processor_px_t),GFP_KERNEL);
151 xen_convert_pss_states(states, px->states, px->state_count);
152 set_xen_guest_handle(perf->states, states);
155 pdomain = &px->domain_info;
156 xen_convert_psd_pack(&perf->domain_info, pdomain);
157 if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ALL)
158 perf->shared_type = CPUFREQ_SHARED_TYPE_ALL;
159 else if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ANY)
160 perf->shared_type = CPUFREQ_SHARED_TYPE_ANY;
161 else if (pdomain->coord_type == DOMAIN_COORD_TYPE_HW_ALL)
162 perf->shared_type = CPUFREQ_SHARED_TYPE_HW;
169 ret = HYPERVISOR_platform_op(&op);
180 static int xen_tx_notifier(struct acpi_processor *pr, int action)
185 static int xen_hotplug_notifier(struct acpi_processor *pr, int event)
188 #ifdef CONFIG_ACPI_HOTPLUG_CPU
189 acpi_status status = 0;
190 acpi_object_type type;
193 unsigned long long pxm;
194 xen_platform_op_t op;
196 status = acpi_get_type(pr->handle, &type);
197 if (ACPI_FAILURE(status)) {
198 pr_warn("can't get object type for acpi_id %#x\n",
204 case ACPI_TYPE_PROCESSOR:
206 case ACPI_TYPE_DEVICE:
210 pr_warn("unsupported object type %#x for acpi_id %#x\n",
215 apic_id = acpi_get_cpuid(pr->handle, ~device_decl, pr->acpi_id);
217 pr_warn("can't get apic_id for acpi_id %#x\n", pr->acpi_id);
221 status = acpi_evaluate_integer(pr->handle, "_PXM", NULL, &pxm);
222 if (ACPI_FAILURE(status)) {
223 pr_warn("can't get pxm for acpi_id %#x\n", pr->acpi_id);
228 case HOTPLUG_TYPE_ADD:
229 op.cmd = XENPF_cpu_hotadd;
230 op.u.cpu_add.apic_id = apic_id;
231 op.u.cpu_add.acpi_id = pr->acpi_id;
232 op.u.cpu_add.pxm = pxm;
233 ret = HYPERVISOR_platform_op(&op);
235 case HOTPLUG_TYPE_REMOVE:
236 pr_warn("Xen doesn't support CPU hot remove\n");
245 static struct processor_extcntl_ops xen_extcntl_ops = {
246 .hotplug = xen_hotplug_notifier,
249 static int __init init_extcntl(void)
251 unsigned int pmbits = (xen_start_info->flags & SIF_PM_MASK) >> 8;
253 #ifndef CONFIG_ACPI_HOTPLUG_CPU
257 if (pmbits & XEN_PROCESSOR_PM_CX)
258 xen_extcntl_ops.pm_ops[PM_TYPE_IDLE] = xen_cx_notifier;
259 if (pmbits & XEN_PROCESSOR_PM_PX)
260 xen_extcntl_ops.pm_ops[PM_TYPE_PERF] = xen_px_notifier;
261 if (pmbits & XEN_PROCESSOR_PM_TX)
262 xen_extcntl_ops.pm_ops[PM_TYPE_THR] = xen_tx_notifier;
264 processor_extcntl_ops = &xen_extcntl_ops;
268 arch_initcall(init_extcntl);
270 unsigned int cpufreq_quick_get(unsigned int cpu)
272 xen_platform_op_t op;
274 op.cmd = XENPF_get_cpu_freq;
275 op.u.get_cpu_freq.vcpu = cpu;
276 return HYPERVISOR_platform_op(&op) == 0 ? op.u.get_cpu_freq.freq : 0;
279 unsigned int cpufreq_quick_get_max(unsigned int cpu)
281 xen_platform_op_t op;
283 op.cmd = XENPF_get_cpu_freq_max;
284 op.u.get_cpu_freq.vcpu = cpu;
285 return HYPERVISOR_platform_op(&op) == 0 ? op.u.get_cpu_freq.freq : 0;
287 EXPORT_SYMBOL(cpufreq_quick_get_max);