ixgbe: Add 82598 support for BX mezzanine devices
[linux-2.6/mini2440.git] / arch / ia64 / kvm / kvm_fw.c
blobcb7600bdff9d3a81bcf76648e0859a4061820a0f
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_cache_info(struct kvm_vcpu *vcpu)
233 pal_cache_config_info_t ci;
234 long status;
235 unsigned long in0, in1, in2, in3, r9, r10;
237 kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
238 status = ia64_pal_cache_config_info(in1, in2, &ci);
239 r9 = ci.pcci_info_1.pcci1_data;
240 r10 = ci.pcci_info_2.pcci2_data;
241 return ((struct ia64_pal_retval){status, r9, r10, 0});
244 #define GUEST_IMPL_VA_MSB 59
245 #define GUEST_RID_BITS 18
247 static struct ia64_pal_retval pal_vm_summary(struct kvm_vcpu *vcpu)
250 pal_vm_info_1_u_t vminfo1;
251 pal_vm_info_2_u_t vminfo2;
252 struct ia64_pal_retval result;
254 PAL_CALL(result, PAL_VM_SUMMARY, 0, 0, 0);
255 if (!result.status) {
256 vminfo1.pvi1_val = result.v0;
257 vminfo1.pal_vm_info_1_s.max_itr_entry = 8;
258 vminfo1.pal_vm_info_1_s.max_dtr_entry = 8;
259 result.v0 = vminfo1.pvi1_val;
260 vminfo2.pal_vm_info_2_s.impl_va_msb = GUEST_IMPL_VA_MSB;
261 vminfo2.pal_vm_info_2_s.rid_size = GUEST_RID_BITS;
262 result.v1 = vminfo2.pvi2_val;
265 return result;
268 static struct ia64_pal_retval pal_vm_info(struct kvm_vcpu *vcpu)
270 struct ia64_pal_retval result;
272 INIT_PAL_STATUS_UNIMPLEMENTED(result);
274 return result;
277 static u64 kvm_get_pal_call_index(struct kvm_vcpu *vcpu)
279 u64 index = 0;
280 struct exit_ctl_data *p;
282 p = kvm_get_exit_data(vcpu);
283 if (p && (p->exit_reason == EXIT_REASON_PAL_CALL))
284 index = p->u.pal_data.gr28;
286 return index;
289 static void prepare_for_halt(struct kvm_vcpu *vcpu)
291 vcpu->arch.timer_pending = 1;
292 vcpu->arch.timer_fired = 0;
295 int kvm_pal_emul(struct kvm_vcpu *vcpu, struct kvm_run *run)
298 u64 gr28;
299 struct ia64_pal_retval result;
300 int ret = 1;
302 gr28 = kvm_get_pal_call_index(vcpu);
303 /*printk("pal_call index:%lx\n",gr28);*/
304 switch (gr28) {
305 case PAL_CACHE_FLUSH:
306 result = pal_cache_flush(vcpu);
307 break;
308 case PAL_CACHE_SUMMARY:
309 result = pal_cache_summary(vcpu);
310 break;
311 case PAL_HALT_LIGHT:
313 INIT_PAL_STATUS_SUCCESS(result);
314 prepare_for_halt(vcpu);
315 if (kvm_highest_pending_irq(vcpu) == -1)
316 ret = kvm_emulate_halt(vcpu);
318 break;
320 case PAL_FREQ_RATIOS:
321 result = pal_freq_ratios(vcpu);
322 break;
324 case PAL_FREQ_BASE:
325 result = pal_freq_base(vcpu);
326 break;
328 case PAL_LOGICAL_TO_PHYSICAL :
329 result = pal_logical_to_physica(vcpu);
330 break;
332 case PAL_VM_SUMMARY :
333 result = pal_vm_summary(vcpu);
334 break;
336 case PAL_VM_INFO :
337 result = pal_vm_info(vcpu);
338 break;
339 case PAL_PLATFORM_ADDR :
340 result = pal_platform_addr(vcpu);
341 break;
342 case PAL_CACHE_INFO:
343 result = pal_cache_info(vcpu);
344 break;
345 case PAL_PTCE_INFO:
346 INIT_PAL_STATUS_SUCCESS(result);
347 result.v1 = (1L << 32) | 1L;
348 break;
349 case PAL_VM_PAGE_SIZE:
350 result.status = ia64_pal_vm_page_size(&result.v0,
351 &result.v1);
352 break;
353 case PAL_RSE_INFO:
354 result.status = ia64_pal_rse_info(&result.v0,
355 (pal_hints_u_t *)&result.v1);
356 break;
357 case PAL_PROC_GET_FEATURES:
358 result = pal_proc_get_features(vcpu);
359 break;
360 case PAL_DEBUG_INFO:
361 result.status = ia64_pal_debug_info(&result.v0,
362 &result.v1);
363 break;
364 case PAL_VERSION:
365 result.status = ia64_pal_version(
366 (pal_version_u_t *)&result.v0,
367 (pal_version_u_t *)&result.v1);
369 break;
370 case PAL_FIXED_ADDR:
371 result.status = PAL_STATUS_SUCCESS;
372 result.v0 = vcpu->vcpu_id;
373 break;
374 default:
375 INIT_PAL_STATUS_UNIMPLEMENTED(result);
376 printk(KERN_WARNING"kvm: Unsupported pal call,"
377 " index:0x%lx\n", gr28);
379 set_pal_result(vcpu, result);
380 return ret;
383 static struct sal_ret_values sal_emulator(struct kvm *kvm,
384 long index, unsigned long in1,
385 unsigned long in2, unsigned long in3,
386 unsigned long in4, unsigned long in5,
387 unsigned long in6, unsigned long in7)
389 unsigned long r9 = 0;
390 unsigned long r10 = 0;
391 long r11 = 0;
392 long status;
394 status = 0;
395 switch (index) {
396 case SAL_FREQ_BASE:
397 status = ia64_sal_freq_base(in1, &r9, &r10);
398 break;
399 case SAL_PCI_CONFIG_READ:
400 printk(KERN_WARNING"kvm: Not allowed to call here!"
401 " SAL_PCI_CONFIG_READ\n");
402 break;
403 case SAL_PCI_CONFIG_WRITE:
404 printk(KERN_WARNING"kvm: Not allowed to call here!"
405 " SAL_PCI_CONFIG_WRITE\n");
406 break;
407 case SAL_SET_VECTORS:
408 if (in1 == SAL_VECTOR_OS_BOOT_RENDEZ) {
409 if (in4 != 0 || in5 != 0 || in6 != 0 || in7 != 0) {
410 status = -2;
411 } else {
412 kvm->arch.rdv_sal_data.boot_ip = in2;
413 kvm->arch.rdv_sal_data.boot_gp = in3;
415 printk("Rendvous called! iip:%lx\n\n", in2);
416 } else
417 printk(KERN_WARNING"kvm: CALLED SAL_SET_VECTORS %lu."
418 "ignored...\n", in1);
419 break;
420 case SAL_GET_STATE_INFO:
421 /* No more info. */
422 status = -5;
423 r9 = 0;
424 break;
425 case SAL_GET_STATE_INFO_SIZE:
426 /* Return a dummy size. */
427 status = 0;
428 r9 = 128;
429 break;
430 case SAL_CLEAR_STATE_INFO:
431 /* Noop. */
432 break;
433 case SAL_MC_RENDEZ:
434 printk(KERN_WARNING
435 "kvm: called SAL_MC_RENDEZ. ignored...\n");
436 break;
437 case SAL_MC_SET_PARAMS:
438 printk(KERN_WARNING
439 "kvm: called SAL_MC_SET_PARAMS.ignored!\n");
440 break;
441 case SAL_CACHE_FLUSH:
442 if (1) {
443 /*Flush using SAL.
444 This method is faster but has a side
445 effect on other vcpu running on
446 this cpu. */
447 status = ia64_sal_cache_flush(in1);
448 } else {
449 /*Maybe need to implement the method
450 without side effect!*/
451 status = 0;
453 break;
454 case SAL_CACHE_INIT:
455 printk(KERN_WARNING
456 "kvm: called SAL_CACHE_INIT. ignored...\n");
457 break;
458 case SAL_UPDATE_PAL:
459 printk(KERN_WARNING
460 "kvm: CALLED SAL_UPDATE_PAL. ignored...\n");
461 break;
462 default:
463 printk(KERN_WARNING"kvm: called SAL_CALL with unknown index."
464 " index:%ld\n", index);
465 status = -1;
466 break;
468 return ((struct sal_ret_values) {status, r9, r10, r11});
471 static void kvm_get_sal_call_data(struct kvm_vcpu *vcpu, u64 *in0, u64 *in1,
472 u64 *in2, u64 *in3, u64 *in4, u64 *in5, u64 *in6, u64 *in7){
474 struct exit_ctl_data *p;
476 p = kvm_get_exit_data(vcpu);
478 if (p) {
479 if (p->exit_reason == EXIT_REASON_SAL_CALL) {
480 *in0 = p->u.sal_data.in0;
481 *in1 = p->u.sal_data.in1;
482 *in2 = p->u.sal_data.in2;
483 *in3 = p->u.sal_data.in3;
484 *in4 = p->u.sal_data.in4;
485 *in5 = p->u.sal_data.in5;
486 *in6 = p->u.sal_data.in6;
487 *in7 = p->u.sal_data.in7;
488 return ;
491 *in0 = 0;
494 void kvm_sal_emul(struct kvm_vcpu *vcpu)
497 struct sal_ret_values result;
498 u64 index, in1, in2, in3, in4, in5, in6, in7;
500 kvm_get_sal_call_data(vcpu, &index, &in1, &in2,
501 &in3, &in4, &in5, &in6, &in7);
502 result = sal_emulator(vcpu->kvm, index, in1, in2, in3,
503 in4, in5, in6, in7);
504 set_sal_result(vcpu, result);