- Update Xen patches to 3.3-rc5 and c/s 1157.
[linux-flexiantxendom0-3.2.10.git] / arch / x86 / kernel / acpi / processor_extcntl_xen.c
1 /*
2  * processor_extcntl_xen.c - interface to notify Xen
3  *
4  *  Copyright (C) 2008, Intel corporation
5  *
6  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7  *
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.
12  *
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.
17  *
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.
21  *
22  */
23
24 #include <linux/kernel.h>
25 #include <linux/init.h>
26 #include <linux/types.h>
27 #include <linux/acpi.h>
28 #include <linux/pm.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>
34
35 static int xen_cx_notifier(struct acpi_processor *pr, int action)
36 {
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,
43         };
44         struct xen_processor_cx *data, *buf;
45         struct acpi_processor_cx *cx;
46
47         /* Convert to Xen defined structure and hypercall */
48         buf = kzalloc(pr->power.count * sizeof(struct xen_processor_cx),
49                         GFP_KERNEL);
50         if (!buf)
51                 return -ENOMEM;
52
53         data = buf;
54         for (i = 1; i <= pr->power.count; i++) {
55                 cx = &pr->power.states[i];
56                 /* Skip invalid cstate entry */
57                 if (!cx->valid)
58                         continue;
59
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;
68
69                 /* Get dependency relationships */
70                 if (cx->csd_count) {
71                         pr_warning("_CSD found: Not supported for now!\n");
72                         kfree(buf);
73                         return -EINVAL;
74                 } else {
75                         data->dpcnt = 0;
76                         set_xen_guest_handle(data->dp, NULL);
77                 }
78
79                 data++;
80                 count++;
81         }
82
83         if (!count) {
84                 pr_info("No available Cx info for cpu %d\n", pr->acpi_id);
85                 kfree(buf);
86                 return -EINVAL;
87         }
88
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;
94
95         set_xen_guest_handle(op.u.set_pminfo.u.power.states, buf);
96         ret = HYPERVISOR_platform_op(&op);
97         kfree(buf);
98         return ret;
99 }
100
101 static int xen_px_notifier(struct acpi_processor *pr, int action)
102 {
103         int ret = -EINVAL;
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,
109         };
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;
114
115         if (!pr)
116                 return -EINVAL;
117
118         perf = &op.u.set_pminfo.u.perf;
119         px = pr->performance;
120         if (!px)
121                 return -EINVAL;
122
123         switch(action) {
124         case PROCESSOR_PM_CHANGE:
125                 /* ppc dynamic handle */
126                 perf->flags = XEN_PX_PPC;
127                 perf->platform_limit = pr->performance_platform_limit;
128
129                 ret = HYPERVISOR_platform_op(&op);
130                 break;
131
132         case PROCESSOR_PM_INIT:
133                 /* px normal init */
134                 perf->flags = XEN_PX_PPC | 
135                               XEN_PX_PCT | 
136                               XEN_PX_PSS | 
137                               XEN_PX_PSD;
138
139                 /* ppc */
140                 perf->platform_limit = pr->performance_platform_limit;
141
142                 /* pct */
143                 xen_convert_pct_reg(&perf->control_register, &px->control_register);
144                 xen_convert_pct_reg(&perf->status_register, &px->status_register);
145
146                 /* pss */
147                 perf->state_count = px->state_count;
148                 states = kzalloc(px->state_count*sizeof(xen_processor_px_t),GFP_KERNEL);
149                 if (!states)
150                         return -ENOMEM;
151                 xen_convert_pss_states(states, px->states, px->state_count);
152                 set_xen_guest_handle(perf->states, states);
153
154                 /* psd */
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;
163                 else {
164                         ret = -ENODEV;
165                         kfree(states);
166                         break;
167                 }
168
169                 ret = HYPERVISOR_platform_op(&op);
170                 kfree(states);
171                 break;
172
173         default:
174                 break;
175         }
176
177         return ret;
178 }
179
180 static int xen_tx_notifier(struct acpi_processor *pr, int action)
181 {
182         return -EINVAL;
183 }
184
185 static int xen_hotplug_notifier(struct acpi_processor *pr, int event)
186 {
187         int ret = -EINVAL;
188 #ifdef CONFIG_ACPI_HOTPLUG_CPU
189         acpi_status status = 0;
190         acpi_object_type type;
191         uint32_t apic_id;
192         int device_decl = 0;
193         unsigned long long pxm;
194         xen_platform_op_t op;
195
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",
199                         pr->acpi_id);
200                 return -ENXIO;
201         }
202
203         switch (type) {
204         case ACPI_TYPE_PROCESSOR:
205                 break;
206         case ACPI_TYPE_DEVICE:
207                 device_decl = 1;
208                 break;
209         default:
210                 pr_warn("unsupported object type %#x for acpi_id %#x\n",
211                         type, pr->acpi_id);
212                 return -EOPNOTSUPP;
213         }
214
215         apic_id = acpi_get_cpuid(pr->handle, ~device_decl, pr->acpi_id);
216         if (apic_id < 0) {
217                 pr_warn("can't get apic_id for acpi_id %#x\n", pr->acpi_id);
218                 return -ENODATA;
219         }
220
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);
224                 return -ENODATA;
225         }
226
227         switch (event) {
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);
234                 break;
235         case HOTPLUG_TYPE_REMOVE:
236                 pr_warn("Xen doesn't support CPU hot remove\n");
237                 ret = -EOPNOTSUPP;
238                 break;
239         }
240 #endif
241
242         return ret;
243 }
244
245 static struct processor_extcntl_ops xen_extcntl_ops = {
246         .hotplug                = xen_hotplug_notifier,
247 };
248
249 static int __init init_extcntl(void)
250 {
251         unsigned int pmbits = (xen_start_info->flags & SIF_PM_MASK) >> 8;
252
253 #ifndef CONFIG_ACPI_HOTPLUG_CPU
254         if (!pmbits)
255                 return 0;
256 #endif
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;
263
264         processor_extcntl_ops = &xen_extcntl_ops;
265
266         return 0;
267 }
268 arch_initcall(init_extcntl);
269
270 unsigned int cpufreq_quick_get(unsigned int cpu)
271 {
272         xen_platform_op_t op;
273
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;
277 }
278
279 unsigned int cpufreq_quick_get_max(unsigned int cpu)
280 {
281         xen_platform_op_t op;
282
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;
286 }
287 EXPORT_SYMBOL(cpufreq_quick_get_max);