debuggers.hg

view xen/arch/x86/platform_hypercall.c @ 22804:d276f4528b32

x86: On CPU online/offline from dom0, try flushing RCU work on EBUSY.

Although the caller should react appropriately to EBUSY, if the error
is due to pending RCU work then we can help things along by executing
rcu_barrier() and then retrying. To this end, this changeset is an
optimisation only.

Signed-off-by: Keir Fraser <keir@xen.org>
author Keir Fraser <keir@xen.org>
date Fri Jan 14 14:19:55 2011 +0000 (2011-01-14)
parents e8acb9753ff1
children
line source
1 /******************************************************************************
2 * platform_hypercall.c
3 *
4 * Hardware platform operations. Intended for use by domain-0 kernel.
5 *
6 * Copyright (c) 2002-2006, K Fraser
7 */
9 #include <xen/config.h>
10 #include <xen/types.h>
11 #include <xen/lib.h>
12 #include <xen/mm.h>
13 #include <xen/sched.h>
14 #include <xen/domain.h>
15 #include <xen/event.h>
16 #include <xen/domain_page.h>
17 #include <xen/trace.h>
18 #include <xen/console.h>
19 #include <xen/iocap.h>
20 #include <xen/guest_access.h>
21 #include <xen/acpi.h>
22 #include <xen/cpu.h>
23 #include <asm/current.h>
24 #include <public/platform.h>
25 #include <acpi/cpufreq/processor_perf.h>
26 #include <asm/edd.h>
27 #include <asm/mtrr.h>
28 #include <asm/io_apic.h>
29 #include "cpu/mtrr/mtrr.h"
30 #include <xsm/xsm.h>
32 extern uint16_t boot_edid_caps;
33 extern uint8_t boot_edid_info[];
35 #ifndef COMPAT
36 typedef long ret_t;
37 DEFINE_SPINLOCK(xenpf_lock);
38 # undef copy_from_compat
39 # define copy_from_compat copy_from_guest
40 # undef copy_to_compat
41 # define copy_to_compat copy_to_guest
42 # undef guest_from_compat_handle
43 # define guest_from_compat_handle(x,y) ((x)=(y))
44 #else
45 extern spinlock_t xenpf_lock;
46 #endif
48 static DEFINE_PER_CPU(uint64_t, freq);
50 extern int set_px_pminfo(uint32_t cpu, struct xen_processor_performance *perf);
51 extern long set_cx_pminfo(uint32_t cpu, struct xen_processor_power *power);
53 static long cpu_frequency_change_helper(void *data)
54 {
55 return cpu_frequency_change(this_cpu(freq));
56 }
58 /* from sysctl.c */
59 long cpu_up_helper(void *data);
60 long cpu_down_helper(void *data);
62 ret_t do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op)
63 {
64 ret_t ret = 0;
65 struct xen_platform_op curop, *op = &curop;
67 if ( !IS_PRIV(current->domain) )
68 return -EPERM;
70 if ( copy_from_guest(op, u_xenpf_op, 1) )
71 return -EFAULT;
73 if ( op->interface_version != XENPF_INTERFACE_VERSION )
74 return -EACCES;
76 /*
77 * Trylock here avoids deadlock with an existing platform critical section
78 * which might (for some current or future reason) want to synchronise
79 * with this vcpu.
80 */
81 while ( !spin_trylock(&xenpf_lock) )
82 if ( hypercall_preempt_check() )
83 return hypercall_create_continuation(
84 __HYPERVISOR_platform_op, "h", u_xenpf_op);
86 switch ( op->cmd )
87 {
88 case XENPF_settime:
89 {
90 ret = xsm_xen_settime();
91 if ( ret )
92 break;
94 do_settime(op->u.settime.secs,
95 op->u.settime.nsecs,
96 op->u.settime.system_time);
97 ret = 0;
98 }
99 break;
101 case XENPF_add_memtype:
102 {
103 ret = xsm_memtype(op->cmd);
104 if ( ret )
105 break;
107 ret = mtrr_add_page(
108 op->u.add_memtype.mfn,
109 op->u.add_memtype.nr_mfns,
110 op->u.add_memtype.type,
111 1);
112 if ( ret >= 0 )
113 {
114 op->u.add_memtype.handle = 0;
115 op->u.add_memtype.reg = ret;
116 ret = copy_to_guest(u_xenpf_op, op, 1) ? -EFAULT : 0;
117 if ( ret != 0 )
118 mtrr_del_page(ret, 0, 0);
119 }
120 }
121 break;
123 case XENPF_del_memtype:
124 {
125 ret = xsm_memtype(op->cmd);
126 if ( ret )
127 break;
129 if (op->u.del_memtype.handle == 0
130 /* mtrr/main.c otherwise does a lookup */
131 && (int)op->u.del_memtype.reg >= 0)
132 {
133 ret = mtrr_del_page(op->u.del_memtype.reg, 0, 0);
134 if ( ret > 0 )
135 ret = 0;
136 }
137 else
138 ret = -EINVAL;
139 }
140 break;
142 case XENPF_read_memtype:
143 {
144 unsigned long mfn, nr_mfns;
145 mtrr_type type;
147 ret = xsm_memtype(op->cmd);
148 if ( ret )
149 break;
151 ret = -EINVAL;
152 if ( op->u.read_memtype.reg < num_var_ranges )
153 {
154 mtrr_if->get(op->u.read_memtype.reg, &mfn, &nr_mfns, &type);
155 op->u.read_memtype.mfn = mfn;
156 op->u.read_memtype.nr_mfns = nr_mfns;
157 op->u.read_memtype.type = type;
158 ret = copy_to_guest(u_xenpf_op, op, 1) ? -EFAULT : 0;
159 }
160 }
161 break;
163 case XENPF_microcode_update:
164 {
165 XEN_GUEST_HANDLE(const_void) data;
167 ret = xsm_microcode();
168 if ( ret )
169 break;
171 guest_from_compat_handle(data, op->u.microcode.data);
172 ret = microcode_update(data, op->u.microcode.length);
173 }
174 break;
176 case XENPF_platform_quirk:
177 {
178 int quirk_id = op->u.platform_quirk.quirk_id;
180 ret = xsm_platform_quirk(quirk_id);
181 if ( ret )
182 break;
184 switch ( quirk_id )
185 {
186 case QUIRK_NOIRQBALANCING:
187 printk("Platform quirk -- Disabling IRQ balancing/affinity.\n");
188 opt_noirqbalance = 1;
189 setup_ioapic_dest();
190 break;
191 case QUIRK_IOAPIC_BAD_REGSEL:
192 case QUIRK_IOAPIC_GOOD_REGSEL:
193 #ifndef sis_apic_bug
194 sis_apic_bug = (quirk_id == QUIRK_IOAPIC_BAD_REGSEL);
195 dprintk(XENLOG_INFO, "Domain 0 says that IO-APIC REGSEL is %s\n",
196 sis_apic_bug ? "bad" : "good");
197 #else
198 if ( sis_apic_bug != (quirk_id == QUIRK_IOAPIC_BAD_REGSEL) )
199 dprintk(XENLOG_WARNING,
200 "Domain 0 thinks that IO-APIC REGSEL is %s\n",
201 sis_apic_bug ? "good" : "bad");
202 #endif
203 break;
204 default:
205 ret = -EINVAL;
206 break;
207 }
208 }
209 break;
211 case XENPF_firmware_info:
212 ret = xsm_firmware_info();
213 if ( ret )
214 break;
216 switch ( op->u.firmware_info.type )
217 {
218 case XEN_FW_DISK_INFO: {
219 const struct edd_info *info;
220 u16 length;
222 ret = -ESRCH;
223 if ( op->u.firmware_info.index >= bootsym(boot_edd_info_nr) )
224 break;
226 info = bootsym(boot_edd_info) + op->u.firmware_info.index;
228 /* Transfer the EDD info block. */
229 ret = -EFAULT;
230 if ( copy_from_compat(&length, op->u.firmware_info.u.
231 disk_info.edd_params, 1) )
232 break;
233 if ( length > info->edd_device_params.length )
234 length = info->edd_device_params.length;
235 if ( copy_to_compat(op->u.firmware_info.u.disk_info.edd_params,
236 (u8 *)&info->edd_device_params,
237 length) )
238 break;
239 if ( copy_to_compat(op->u.firmware_info.u.disk_info.edd_params,
240 &length, 1) )
241 break;
243 /* Transfer miscellaneous other information values. */
244 #define C(x) op->u.firmware_info.u.disk_info.x = info->x
245 C(device);
246 C(version);
247 C(interface_support);
248 C(legacy_max_cylinder);
249 C(legacy_max_head);
250 C(legacy_sectors_per_track);
251 #undef C
253 ret = (copy_field_to_guest(u_xenpf_op, op,
254 u.firmware_info.u.disk_info)
255 ? -EFAULT : 0);
256 break;
257 }
258 case XEN_FW_DISK_MBR_SIGNATURE: {
259 const struct mbr_signature *sig;
261 ret = -ESRCH;
262 if ( op->u.firmware_info.index >= bootsym(boot_mbr_signature_nr) )
263 break;
265 sig = bootsym(boot_mbr_signature) + op->u.firmware_info.index;
267 op->u.firmware_info.u.disk_mbr_signature.device = sig->device;
268 op->u.firmware_info.u.disk_mbr_signature.mbr_signature =
269 sig->signature;
271 ret = (copy_field_to_guest(u_xenpf_op, op,
272 u.firmware_info.u.disk_mbr_signature)
273 ? -EFAULT : 0);
274 break;
275 }
276 case XEN_FW_VBEDDC_INFO:
277 ret = -ESRCH;
278 if ( op->u.firmware_info.index != 0 )
279 break;
280 if ( *(u32 *)bootsym(boot_edid_info) == 0x13131313 )
281 break;
283 op->u.firmware_info.u.vbeddc_info.capabilities =
284 bootsym(boot_edid_caps);
285 op->u.firmware_info.u.vbeddc_info.edid_transfer_time =
286 bootsym(boot_edid_caps) >> 8;
288 ret = 0;
289 if ( copy_field_to_guest(u_xenpf_op, op, u.firmware_info.
290 u.vbeddc_info.capabilities) ||
291 copy_field_to_guest(u_xenpf_op, op, u.firmware_info.
292 u.vbeddc_info.edid_transfer_time) ||
293 copy_to_compat(op->u.firmware_info.u.vbeddc_info.edid,
294 bootsym(boot_edid_info), 128) )
295 ret = -EFAULT;
296 break;
297 default:
298 ret = -EINVAL;
299 break;
300 }
301 break;
303 case XENPF_enter_acpi_sleep:
304 ret = xsm_acpi_sleep();
305 if ( ret )
306 break;
308 ret = acpi_enter_sleep(&op->u.enter_acpi_sleep);
309 break;
311 case XENPF_change_freq:
312 ret = xsm_change_freq();
313 if ( ret )
314 break;
316 ret = -ENOSYS;
317 if ( cpufreq_controller != FREQCTL_dom0_kernel )
318 break;
319 ret = -EINVAL;
320 if ( op->u.change_freq.flags || !cpu_online(op->u.change_freq.cpu) )
321 break;
322 per_cpu(freq, op->u.change_freq.cpu) = op->u.change_freq.freq;
323 ret = continue_hypercall_on_cpu(op->u.change_freq.cpu,
324 cpu_frequency_change_helper,
325 NULL);
326 break;
328 case XENPF_getidletime:
329 {
330 uint32_t cpu;
331 uint64_t idletime, now = NOW();
332 struct xenctl_cpumap ctlmap;
333 cpumask_t cpumap;
334 XEN_GUEST_HANDLE(uint8) cpumap_bitmap;
335 XEN_GUEST_HANDLE(uint64) idletimes;
337 ret = xsm_getidletime();
338 if ( ret )
339 break;
341 ret = -ENOSYS;
342 if ( cpufreq_controller != FREQCTL_dom0_kernel )
343 break;
345 ctlmap.nr_cpus = op->u.getidletime.cpumap_nr_cpus;
346 guest_from_compat_handle(cpumap_bitmap,
347 op->u.getidletime.cpumap_bitmap);
348 ctlmap.bitmap.p = cpumap_bitmap.p; /* handle -> handle_64 conversion */
349 if ( (ret = xenctl_cpumap_to_cpumask(&cpumap, &ctlmap)) != 0 )
350 goto out;
351 guest_from_compat_handle(idletimes, op->u.getidletime.idletime);
353 for_each_cpu_mask ( cpu, cpumap )
354 {
355 if ( idle_vcpu[cpu] == NULL )
356 cpu_clear(cpu, cpumap);
357 idletime = get_cpu_idle_time(cpu);
359 ret = -EFAULT;
360 if ( copy_to_guest_offset(idletimes, cpu, &idletime, 1) )
361 goto out;
362 }
364 op->u.getidletime.now = now;
365 if ( (ret = cpumask_to_xenctl_cpumap(&ctlmap, &cpumap)) != 0 )
366 goto out;
368 ret = copy_to_guest(u_xenpf_op, op, 1) ? -EFAULT : 0;
369 }
370 break;
372 case XENPF_set_processor_pminfo:
373 switch ( op->u.set_pminfo.type )
374 {
375 case XEN_PM_PX:
376 if ( !(xen_processor_pmbits & XEN_PROCESSOR_PM_PX) )
377 {
378 ret = -ENOSYS;
379 break;
380 }
381 ret = set_px_pminfo(op->u.set_pminfo.id, &op->u.set_pminfo.u.perf);
382 break;
384 case XEN_PM_CX:
385 if ( !(xen_processor_pmbits & XEN_PROCESSOR_PM_CX) )
386 {
387 ret = -ENOSYS;
388 break;
389 }
390 ret = set_cx_pminfo(op->u.set_pminfo.id, &op->u.set_pminfo.u.power);
391 break;
393 case XEN_PM_TX:
394 if ( !(xen_processor_pmbits & XEN_PROCESSOR_PM_TX) )
395 {
396 ret = -ENOSYS;
397 break;
398 }
399 ret = -EINVAL;
400 break;
402 default:
403 ret = -EINVAL;
404 break;
405 }
406 break;
408 case XENPF_get_cpuinfo:
409 {
410 struct xenpf_pcpuinfo *g_info;
412 g_info = &op->u.pcpu_info;
414 if ( !get_cpu_maps() )
415 {
416 ret = -EBUSY;
417 break;
418 }
420 if ( (g_info->xen_cpuid >= NR_CPUS) ||
421 !cpu_present(g_info->xen_cpuid) )
422 {
423 g_info->flags |= XEN_PCPU_FLAGS_INVALID;
424 }
425 else
426 {
427 g_info->apic_id = x86_cpu_to_apicid[g_info->xen_cpuid];
428 g_info->acpi_id = acpi_get_processor_id(g_info->xen_cpuid);
429 ASSERT(g_info->apic_id != BAD_APICID);
430 if (cpu_online(g_info->xen_cpuid))
431 g_info->flags |= XEN_PCPU_FLAGS_ONLINE;
432 }
434 g_info->max_present = last_cpu(cpu_present_map);
436 put_cpu_maps();
438 ret = copy_to_guest(u_xenpf_op, op, 1) ? -EFAULT : 0;
439 }
440 break;
442 case XENPF_cpu_online:
443 {
444 int cpu = op->u.cpu_ol.cpuid;
446 if ( !cpu_present(cpu) )
447 {
448 ret = -EINVAL;
449 break;
450 }
452 if ( cpu_online(cpu) )
453 {
454 ret = 0;
455 break;
456 }
458 ret = continue_hypercall_on_cpu(
459 0, cpu_up_helper, (void *)(unsigned long)cpu);
460 break;
461 }
463 case XENPF_cpu_offline:
464 {
465 int cpu = op->u.cpu_ol.cpuid;
467 if ( !cpu_present(cpu) )
468 {
469 ret = -EINVAL;
470 break;
471 }
473 if ( !cpu_online(cpu) )
474 {
475 ret = 0;
476 break;
477 }
479 ret = continue_hypercall_on_cpu(
480 0, cpu_down_helper, (void *)(unsigned long)cpu);
481 break;
482 }
483 break;
485 case XENPF_cpu_hotadd:
486 ret = cpu_add(op->u.cpu_add.apic_id,
487 op->u.cpu_add.acpi_id,
488 op->u.cpu_add.pxm);
489 break;
491 case XENPF_mem_hotadd:
492 ret = memory_add(op->u.mem_add.spfn,
493 op->u.mem_add.epfn,
494 op->u.mem_add.pxm);
495 break;
496 default:
497 ret = -ENOSYS;
498 break;
499 }
501 out:
502 spin_unlock(&xenpf_lock);
504 return ret;
505 }
507 /*
508 * Local variables:
509 * mode: C
510 * c-set-style: "BSD"
511 * c-basic-offset: 4
512 * tab-width: 4
513 * indent-tabs-mode: nil
514 * End:
515 */