OMAP3 SRAM: add more comments on the SRAM code
[linux-ginger.git] / arch / ia64 / kvm / kvm_fw.c
bloba8ae52ed56358e3e3d1b81edf095ebfceaa36a3b
1 /*
2 * PAL/SAL call delegation
4 * Copyright (c) 2004 Li Susie <susie.li@intel.com>
5 * Copyright (c) 2005 Yu Ke <ke.yu@intel.com>
6 * Copyright (c) 2007 Xiantao Zhang <xiantao.zhang@intel.com>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place - Suite 330, Boston, MA 02111-1307 USA.
22 #include <linux/kvm_host.h>
23 #include <linux/smp.h>
25 #include "vti.h"
26 #include "misc.h"
28 #include <asm/pal.h>
29 #include <asm/sal.h>
30 #include <asm/tlb.h>
33 * Handy macros to make sure that the PAL return values start out
34 * as something meaningful.
36 #define INIT_PAL_STATUS_UNIMPLEMENTED(x) \
37 { \
38 x.status = PAL_STATUS_UNIMPLEMENTED; \
39 x.v0 = 0; \
40 x.v1 = 0; \
41 x.v2 = 0; \
44 #define INIT_PAL_STATUS_SUCCESS(x) \
45 { \
46 x.status = PAL_STATUS_SUCCESS; \
47 x.v0 = 0; \
48 x.v1 = 0; \
49 x.v2 = 0; \
52 static void kvm_get_pal_call_data(struct kvm_vcpu *vcpu,
53 u64 *gr28, u64 *gr29, u64 *gr30, u64 *gr31) {
54 struct exit_ctl_data *p;
56 if (vcpu) {
57 p = &vcpu->arch.exit_data;
58 if (p->exit_reason == EXIT_REASON_PAL_CALL) {
59 *gr28 = p->u.pal_data.gr28;
60 *gr29 = p->u.pal_data.gr29;
61 *gr30 = p->u.pal_data.gr30;
62 *gr31 = p->u.pal_data.gr31;
63 return ;
66 printk(KERN_DEBUG"Failed to get vcpu pal data!!!\n");
69 static void set_pal_result(struct kvm_vcpu *vcpu,
70 struct ia64_pal_retval result) {
72 struct exit_ctl_data *p;
74 p = kvm_get_exit_data(vcpu);
75 if (p && p->exit_reason == EXIT_REASON_PAL_CALL) {
76 p->u.pal_data.ret = result;
77 return ;
79 INIT_PAL_STATUS_UNIMPLEMENTED(p->u.pal_data.ret);
82 static void set_sal_result(struct kvm_vcpu *vcpu,
83 struct sal_ret_values result) {
84 struct exit_ctl_data *p;
86 p = kvm_get_exit_data(vcpu);
87 if (p && p->exit_reason == EXIT_REASON_SAL_CALL) {
88 p->u.sal_data.ret = result;
89 return ;
91 printk(KERN_WARNING"Failed to set sal result!!\n");
94 struct cache_flush_args {
95 u64 cache_type;
96 u64 operation;
97 u64 progress;
98 long status;
101 cpumask_t cpu_cache_coherent_map;
103 static void remote_pal_cache_flush(void *data)
105 struct cache_flush_args *args = data;
106 long status;
107 u64 progress = args->progress;
109 status = ia64_pal_cache_flush(args->cache_type, args->operation,
110 &progress, NULL);
111 if (status != 0)
112 args->status = status;
115 static struct ia64_pal_retval pal_cache_flush(struct kvm_vcpu *vcpu)
117 u64 gr28, gr29, gr30, gr31;
118 struct ia64_pal_retval result = {0, 0, 0, 0};
119 struct cache_flush_args args = {0, 0, 0, 0};
120 long psr;
122 gr28 = gr29 = gr30 = gr31 = 0;
123 kvm_get_pal_call_data(vcpu, &gr28, &gr29, &gr30, &gr31);
125 if (gr31 != 0)
126 printk(KERN_ERR"vcpu:%p called cache_flush error!\n", vcpu);
128 /* Always call Host Pal in int=1 */
129 gr30 &= ~PAL_CACHE_FLUSH_CHK_INTRS;
130 args.cache_type = gr29;
131 args.operation = gr30;
132 smp_call_function(remote_pal_cache_flush,
133 (void *)&args, 1);
134 if (args.status != 0)
135 printk(KERN_ERR"pal_cache_flush error!,"
136 "status:0x%lx\n", args.status);
138 * Call Host PAL cache flush
139 * Clear psr.ic when call PAL_CACHE_FLUSH
141 local_irq_save(psr);
142 result.status = ia64_pal_cache_flush(gr29, gr30, &result.v1,
143 &result.v0);
144 local_irq_restore(psr);
145 if (result.status != 0)
146 printk(KERN_ERR"vcpu:%p crashed due to cache_flush err:%ld"
147 "in1:%lx,in2:%lx\n",
148 vcpu, result.status, gr29, gr30);
150 #if 0
151 if (gr29 == PAL_CACHE_TYPE_COHERENT) {
152 cpus_setall(vcpu->arch.cache_coherent_map);
153 cpu_clear(vcpu->cpu, vcpu->arch.cache_coherent_map);
154 cpus_setall(cpu_cache_coherent_map);
155 cpu_clear(vcpu->cpu, cpu_cache_coherent_map);
157 #endif
158 return result;
161 struct ia64_pal_retval pal_cache_summary(struct kvm_vcpu *vcpu)
164 struct ia64_pal_retval result;
166 PAL_CALL(result, PAL_CACHE_SUMMARY, 0, 0, 0);
167 return result;
170 static struct ia64_pal_retval pal_freq_base(struct kvm_vcpu *vcpu)
173 struct ia64_pal_retval result;
175 PAL_CALL(result, PAL_FREQ_BASE, 0, 0, 0);
178 * PAL_FREQ_BASE may not be implemented in some platforms,
179 * call SAL instead.
181 if (result.v0 == 0) {
182 result.status = ia64_sal_freq_base(SAL_FREQ_BASE_PLATFORM,
183 &result.v0,
184 &result.v1);
185 result.v2 = 0;
188 return result;
191 static struct ia64_pal_retval pal_freq_ratios(struct kvm_vcpu *vcpu)
194 struct ia64_pal_retval result;
196 PAL_CALL(result, PAL_FREQ_RATIOS, 0, 0, 0);
197 return result;
200 static struct ia64_pal_retval pal_logical_to_physica(struct kvm_vcpu *vcpu)
202 struct ia64_pal_retval result;
204 INIT_PAL_STATUS_UNIMPLEMENTED(result);
205 return result;
208 static struct ia64_pal_retval pal_platform_addr(struct kvm_vcpu *vcpu)
211 struct ia64_pal_retval result;
213 INIT_PAL_STATUS_SUCCESS(result);
214 return result;
217 static struct ia64_pal_retval pal_proc_get_features(struct kvm_vcpu *vcpu)
220 struct ia64_pal_retval result = {0, 0, 0, 0};
221 long in0, in1, in2, in3;
223 kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
224 result.status = ia64_pal_proc_get_features(&result.v0, &result.v1,
225 &result.v2, in2);
227 return result;
230 static struct ia64_pal_retval pal_register_info(struct kvm_vcpu *vcpu)
233 struct ia64_pal_retval result = {0, 0, 0, 0};
234 long in0, in1, in2, in3;
236 kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
237 result.status = ia64_pal_register_info(in1, &result.v1, &result.v2);
239 return result;
242 static struct ia64_pal_retval pal_cache_info(struct kvm_vcpu *vcpu)
245 pal_cache_config_info_t ci;
246 long status;
247 unsigned long in0, in1, in2, in3, r9, r10;
249 kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
250 status = ia64_pal_cache_config_info(in1, in2, &ci);
251 r9 = ci.pcci_info_1.pcci1_data;
252 r10 = ci.pcci_info_2.pcci2_data;
253 return ((struct ia64_pal_retval){status, r9, r10, 0});
256 #define GUEST_IMPL_VA_MSB 59
257 #define GUEST_RID_BITS 18
259 static struct ia64_pal_retval pal_vm_summary(struct kvm_vcpu *vcpu)
262 pal_vm_info_1_u_t vminfo1;
263 pal_vm_info_2_u_t vminfo2;
264 struct ia64_pal_retval result;
266 PAL_CALL(result, PAL_VM_SUMMARY, 0, 0, 0);
267 if (!result.status) {
268 vminfo1.pvi1_val = result.v0;
269 vminfo1.pal_vm_info_1_s.max_itr_entry = 8;
270 vminfo1.pal_vm_info_1_s.max_dtr_entry = 8;
271 result.v0 = vminfo1.pvi1_val;
272 vminfo2.pal_vm_info_2_s.impl_va_msb = GUEST_IMPL_VA_MSB;
273 vminfo2.pal_vm_info_2_s.rid_size = GUEST_RID_BITS;
274 result.v1 = vminfo2.pvi2_val;
277 return result;
280 static struct ia64_pal_retval pal_vm_info(struct kvm_vcpu *vcpu)
282 struct ia64_pal_retval result;
283 unsigned long in0, in1, in2, in3;
285 kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
287 result.status = ia64_pal_vm_info(in1, in2,
288 (pal_tc_info_u_t *)&result.v1, &result.v2);
290 return result;
293 static u64 kvm_get_pal_call_index(struct kvm_vcpu *vcpu)
295 u64 index = 0;
296 struct exit_ctl_data *p;
298 p = kvm_get_exit_data(vcpu);
299 if (p && (p->exit_reason == EXIT_REASON_PAL_CALL))
300 index = p->u.pal_data.gr28;
302 return index;
305 static void prepare_for_halt(struct kvm_vcpu *vcpu)
307 vcpu->arch.timer_pending = 1;
308 vcpu->arch.timer_fired = 0;
311 static struct ia64_pal_retval pal_perf_mon_info(struct kvm_vcpu *vcpu)
313 long status;
314 unsigned long in0, in1, in2, in3, r9;
315 unsigned long pm_buffer[16];
317 kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
318 status = ia64_pal_perf_mon_info(pm_buffer,
319 (pal_perf_mon_info_u_t *) &r9);
320 if (status != 0) {
321 printk(KERN_DEBUG"PAL_PERF_MON_INFO fails ret=%ld\n", status);
322 } else {
323 if (in1)
324 memcpy((void *)in1, pm_buffer, sizeof(pm_buffer));
325 else {
326 status = PAL_STATUS_EINVAL;
327 printk(KERN_WARNING"Invalid parameters "
328 "for PAL call:0x%lx!\n", in0);
331 return (struct ia64_pal_retval){status, r9, 0, 0};
334 static struct ia64_pal_retval pal_halt_info(struct kvm_vcpu *vcpu)
336 unsigned long in0, in1, in2, in3;
337 long status;
338 unsigned long res = 1000UL | (1000UL << 16) | (10UL << 32)
339 | (1UL << 61) | (1UL << 60);
341 kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
342 if (in1) {
343 memcpy((void *)in1, &res, sizeof(res));
344 status = 0;
345 } else{
346 status = PAL_STATUS_EINVAL;
347 printk(KERN_WARNING"Invalid parameters "
348 "for PAL call:0x%lx!\n", in0);
351 return (struct ia64_pal_retval){status, 0, 0, 0};
354 static struct ia64_pal_retval pal_mem_attrib(struct kvm_vcpu *vcpu)
356 unsigned long r9;
357 long status;
359 status = ia64_pal_mem_attrib(&r9);
361 return (struct ia64_pal_retval){status, r9, 0, 0};
364 static void remote_pal_prefetch_visibility(void *v)
366 s64 trans_type = (s64)v;
367 ia64_pal_prefetch_visibility(trans_type);
370 static struct ia64_pal_retval pal_prefetch_visibility(struct kvm_vcpu *vcpu)
372 struct ia64_pal_retval result = {0, 0, 0, 0};
373 unsigned long in0, in1, in2, in3;
374 kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
375 result.status = ia64_pal_prefetch_visibility(in1);
376 if (result.status == 0) {
377 /* Must be performed on all remote processors
378 in the coherence domain. */
379 smp_call_function(remote_pal_prefetch_visibility,
380 (void *)in1, 1);
381 /* Unnecessary on remote processor for other vcpus!*/
382 result.status = 1;
384 return result;
387 static void remote_pal_mc_drain(void *v)
389 ia64_pal_mc_drain();
392 static struct ia64_pal_retval pal_get_brand_info(struct kvm_vcpu *vcpu)
394 struct ia64_pal_retval result = {0, 0, 0, 0};
395 unsigned long in0, in1, in2, in3;
397 kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
399 if (in1 == 0 && in2) {
400 char brand_info[128];
401 result.status = ia64_pal_get_brand_info(brand_info);
402 if (result.status == PAL_STATUS_SUCCESS)
403 memcpy((void *)in2, brand_info, 128);
404 } else {
405 result.status = PAL_STATUS_REQUIRES_MEMORY;
406 printk(KERN_WARNING"Invalid parameters for "
407 "PAL call:0x%lx!\n", in0);
410 return result;
413 int kvm_pal_emul(struct kvm_vcpu *vcpu, struct kvm_run *run)
416 u64 gr28;
417 struct ia64_pal_retval result;
418 int ret = 1;
420 gr28 = kvm_get_pal_call_index(vcpu);
421 switch (gr28) {
422 case PAL_CACHE_FLUSH:
423 result = pal_cache_flush(vcpu);
424 break;
425 case PAL_MEM_ATTRIB:
426 result = pal_mem_attrib(vcpu);
427 break;
428 case PAL_CACHE_SUMMARY:
429 result = pal_cache_summary(vcpu);
430 break;
431 case PAL_PERF_MON_INFO:
432 result = pal_perf_mon_info(vcpu);
433 break;
434 case PAL_HALT_INFO:
435 result = pal_halt_info(vcpu);
436 break;
437 case PAL_HALT_LIGHT:
439 INIT_PAL_STATUS_SUCCESS(result);
440 prepare_for_halt(vcpu);
441 if (kvm_highest_pending_irq(vcpu) == -1)
442 ret = kvm_emulate_halt(vcpu);
444 break;
446 case PAL_PREFETCH_VISIBILITY:
447 result = pal_prefetch_visibility(vcpu);
448 break;
449 case PAL_MC_DRAIN:
450 result.status = ia64_pal_mc_drain();
451 /* FIXME: All vcpus likely call PAL_MC_DRAIN.
452 That causes the congestion. */
453 smp_call_function(remote_pal_mc_drain, NULL, 1);
454 break;
456 case PAL_FREQ_RATIOS:
457 result = pal_freq_ratios(vcpu);
458 break;
460 case PAL_FREQ_BASE:
461 result = pal_freq_base(vcpu);
462 break;
464 case PAL_LOGICAL_TO_PHYSICAL :
465 result = pal_logical_to_physica(vcpu);
466 break;
468 case PAL_VM_SUMMARY :
469 result = pal_vm_summary(vcpu);
470 break;
472 case PAL_VM_INFO :
473 result = pal_vm_info(vcpu);
474 break;
475 case PAL_PLATFORM_ADDR :
476 result = pal_platform_addr(vcpu);
477 break;
478 case PAL_CACHE_INFO:
479 result = pal_cache_info(vcpu);
480 break;
481 case PAL_PTCE_INFO:
482 INIT_PAL_STATUS_SUCCESS(result);
483 result.v1 = (1L << 32) | 1L;
484 break;
485 case PAL_REGISTER_INFO:
486 result = pal_register_info(vcpu);
487 break;
488 case PAL_VM_PAGE_SIZE:
489 result.status = ia64_pal_vm_page_size(&result.v0,
490 &result.v1);
491 break;
492 case PAL_RSE_INFO:
493 result.status = ia64_pal_rse_info(&result.v0,
494 (pal_hints_u_t *)&result.v1);
495 break;
496 case PAL_PROC_GET_FEATURES:
497 result = pal_proc_get_features(vcpu);
498 break;
499 case PAL_DEBUG_INFO:
500 result.status = ia64_pal_debug_info(&result.v0,
501 &result.v1);
502 break;
503 case PAL_VERSION:
504 result.status = ia64_pal_version(
505 (pal_version_u_t *)&result.v0,
506 (pal_version_u_t *)&result.v1);
507 break;
508 case PAL_FIXED_ADDR:
509 result.status = PAL_STATUS_SUCCESS;
510 result.v0 = vcpu->vcpu_id;
511 break;
512 case PAL_BRAND_INFO:
513 result = pal_get_brand_info(vcpu);
514 break;
515 case PAL_GET_PSTATE:
516 case PAL_CACHE_SHARED_INFO:
517 INIT_PAL_STATUS_UNIMPLEMENTED(result);
518 break;
519 default:
520 INIT_PAL_STATUS_UNIMPLEMENTED(result);
521 printk(KERN_WARNING"kvm: Unsupported pal call,"
522 " index:0x%lx\n", gr28);
524 set_pal_result(vcpu, result);
525 return ret;
528 static struct sal_ret_values sal_emulator(struct kvm *kvm,
529 long index, unsigned long in1,
530 unsigned long in2, unsigned long in3,
531 unsigned long in4, unsigned long in5,
532 unsigned long in6, unsigned long in7)
534 unsigned long r9 = 0;
535 unsigned long r10 = 0;
536 long r11 = 0;
537 long status;
539 status = 0;
540 switch (index) {
541 case SAL_FREQ_BASE:
542 status = ia64_sal_freq_base(in1, &r9, &r10);
543 break;
544 case SAL_PCI_CONFIG_READ:
545 printk(KERN_WARNING"kvm: Not allowed to call here!"
546 " SAL_PCI_CONFIG_READ\n");
547 break;
548 case SAL_PCI_CONFIG_WRITE:
549 printk(KERN_WARNING"kvm: Not allowed to call here!"
550 " SAL_PCI_CONFIG_WRITE\n");
551 break;
552 case SAL_SET_VECTORS:
553 if (in1 == SAL_VECTOR_OS_BOOT_RENDEZ) {
554 if (in4 != 0 || in5 != 0 || in6 != 0 || in7 != 0) {
555 status = -2;
556 } else {
557 kvm->arch.rdv_sal_data.boot_ip = in2;
558 kvm->arch.rdv_sal_data.boot_gp = in3;
560 printk("Rendvous called! iip:%lx\n\n", in2);
561 } else
562 printk(KERN_WARNING"kvm: CALLED SAL_SET_VECTORS %lu."
563 "ignored...\n", in1);
564 break;
565 case SAL_GET_STATE_INFO:
566 /* No more info. */
567 status = -5;
568 r9 = 0;
569 break;
570 case SAL_GET_STATE_INFO_SIZE:
571 /* Return a dummy size. */
572 status = 0;
573 r9 = 128;
574 break;
575 case SAL_CLEAR_STATE_INFO:
576 /* Noop. */
577 break;
578 case SAL_MC_RENDEZ:
579 printk(KERN_WARNING
580 "kvm: called SAL_MC_RENDEZ. ignored...\n");
581 break;
582 case SAL_MC_SET_PARAMS:
583 printk(KERN_WARNING
584 "kvm: called SAL_MC_SET_PARAMS.ignored!\n");
585 break;
586 case SAL_CACHE_FLUSH:
587 if (1) {
588 /*Flush using SAL.
589 This method is faster but has a side
590 effect on other vcpu running on
591 this cpu. */
592 status = ia64_sal_cache_flush(in1);
593 } else {
594 /*Maybe need to implement the method
595 without side effect!*/
596 status = 0;
598 break;
599 case SAL_CACHE_INIT:
600 printk(KERN_WARNING
601 "kvm: called SAL_CACHE_INIT. ignored...\n");
602 break;
603 case SAL_UPDATE_PAL:
604 printk(KERN_WARNING
605 "kvm: CALLED SAL_UPDATE_PAL. ignored...\n");
606 break;
607 default:
608 printk(KERN_WARNING"kvm: called SAL_CALL with unknown index."
609 " index:%ld\n", index);
610 status = -1;
611 break;
613 return ((struct sal_ret_values) {status, r9, r10, r11});
616 static void kvm_get_sal_call_data(struct kvm_vcpu *vcpu, u64 *in0, u64 *in1,
617 u64 *in2, u64 *in3, u64 *in4, u64 *in5, u64 *in6, u64 *in7){
619 struct exit_ctl_data *p;
621 p = kvm_get_exit_data(vcpu);
623 if (p) {
624 if (p->exit_reason == EXIT_REASON_SAL_CALL) {
625 *in0 = p->u.sal_data.in0;
626 *in1 = p->u.sal_data.in1;
627 *in2 = p->u.sal_data.in2;
628 *in3 = p->u.sal_data.in3;
629 *in4 = p->u.sal_data.in4;
630 *in5 = p->u.sal_data.in5;
631 *in6 = p->u.sal_data.in6;
632 *in7 = p->u.sal_data.in7;
633 return ;
636 *in0 = 0;
639 void kvm_sal_emul(struct kvm_vcpu *vcpu)
642 struct sal_ret_values result;
643 u64 index, in1, in2, in3, in4, in5, in6, in7;
645 kvm_get_sal_call_data(vcpu, &index, &in1, &in2,
646 &in3, &in4, &in5, &in6, &in7);
647 result = sal_emulator(vcpu->kvm, index, in1, in2, in3,
648 in4, in5, in6, in7);
649 set_sal_result(vcpu, result);