[6/12] Add sal emulation.[mca-fw_emul.patch]
Signed-off-by: Yutaka Ezaki <yutaka.ezaki@xxxxxxxxxxxxxx>
Signed-off-by: Masaki Kanno <kanno.masaki@xxxxxxxxxxxxxx>
Signed-off-by: Kazuhiro Suzuki <kaz@xxxxxxxxxxxxxx>
diff -r 3e4fa8b5b245 xen/arch/ia64/xen/fw_emul.c
--- a/xen/arch/ia64/xen/fw_emul.c Tue Sep 12 11:43:22 2006 -0600
+++ b/xen/arch/ia64/xen/fw_emul.c Fri Sep 22 09:26:49 2006 +0900
@@ -23,6 +23,7 @@
#include <linux/efi.h>
#include <asm/pal.h>
#include <asm/sal.h>
+#include <asm/xenmca.h>
#include <public/sched.h>
#include "hpsim_ssc.h"
@@ -32,6 +33,52 @@
extern unsigned long running_on_sim;
+struct sal_mc_params {
+ u64 param_type;
+ u64 i_or_m;
+ u64 i_or_m_val;
+ u64 timeout;
+ u64 rz_always;
+} sal_mc_params[SAL_MC_PARAM_CPE_INT+1];
+
+struct sal_vectors {
+ u64 vector_type;
+ u64 handler_addr1;
+ u64 gp1;
+ u64 handler_len1;
+ u64 handler_addr2;
+ u64 gp2;
+ u64 handler_len2;
+} sal_vectors[SAL_VECTOR_OS_BOOT_RENDEZ+1];
+
+struct smp_call_args_t {
+ u64 type;
+ u64 ret;
+ void *data;
+};
+
+extern spinlock_t sal_queue_lock;
+
+#if defined(IA64_SAL_DEBUG_INFO)
+static const char * const rec_name[] = { "MCA", "INIT", "CMC", "CPE" };
+
+# define IA64_SAL_DEBUG(fmt...) printk("sal_emulator: " fmt)
+#else
+# define IA64_SAL_DEBUG(fmt...)
+#endif
+
+void get_state_info_on(void *data) {
+ struct smp_call_args_t *arg = data;
+
+ arg->ret = ia64_sal_get_state_info(arg->type, (u64 *)arg->data);
+}
+
+void clear_state_info_on(void *data) {
+ struct smp_call_args_t *arg = data;
+
+ arg->ret = ia64_sal_clear_state_info(arg->type);
+}
+
struct sal_ret_values
sal_emulator (long index, unsigned long in1, unsigned long in2,
unsigned long in3, unsigned long in4, unsigned long in5,
@@ -102,27 +149,204 @@ sal_emulator (long index, unsigned long
}
}
else
- printf("*** CALLED SAL_SET_VECTORS %lu. IGNORED...\n",
- in1);
+ {
+ if (in1 > sizeof(sal_vectors)/sizeof(sal_vectors[0])-1)
+ BUG();
+ sal_vectors[in1].vector_type = in1;
+ sal_vectors[in1].handler_addr1 = in2;
+ sal_vectors[in1].gp1 = in3;
+ sal_vectors[in1].handler_len1 = in4;
+ sal_vectors[in1].handler_addr2 = in5;
+ sal_vectors[in1].gp2 = in6;
+ sal_vectors[in1].handler_len2 = in7;
+ }
break;
case SAL_GET_STATE_INFO:
- /* No more info. */
- status = -5;
- r9 = 0;
+ {
+ sal_queue_entry_t *e;
+ unsigned long flags;
+ int size = ia64_sal_get_state_info_size(in1);
+ static sal_log_record_header_t *record = NULL;
+
+ if (record == NULL) {
+ unsigned int pageorder;
+
+ pageorder = get_order_from_bytes(size);
+ record = (sal_log_record_header_t
*)alloc_xenheap_pages(pageorder);
+ }
+ memset(record, 0, size);
+
+ spin_lock_irqsave(&sal_queue_lock, flags);
+ if (list_empty(&sal_queue[in1])) {
+ sal_log_record_header_t header;
+
+ IA64_SAL_DEBUG("SAL_GET_STATE_INFO(%s) "
+
"no sal_queue entry found.\n", rec_name[in1]);
+ memset(&header, 0, sizeof(header));
+ if (copy_to_user((void __user *)in3, &header,
sizeof(header))) {
+ printk("sal_emulator:
SAL_GET_STATE_INFO "
+ "can't copy
empty header to user: 0x%lx\n", in3);
+ }
+ status = -5;
+ r9 = 0;
+ spin_unlock_irqrestore(&sal_queue_lock, flags);
+ break;
+ }
+ e = list_entry(sal_queue[in1].next, sal_queue_entry_t,
list);
+
+ if (e->cpuid == smp_processor_id()) {
+ if (in1 == e->sal_info_type) {
+ IA64_SAL_DEBUG("SAL_GET_STATE_INFO(%s) "
+
"on current CPU.\n", rec_name[in1]);
+ } else {
+ IA64_SAL_DEBUG("SAL_GET_STATE_INFO(%s
<= %s) "
+
"on current CPU.\n",
+
rec_name[e->sal_info_type],
+
rec_name[in1]);
+ }
+ r9 = ia64_sal_get_state_info(e->sal_info_type,
(u64 *)record);
+ IA64_SAL_DEBUG("SAL_GET_STATE_INFO(%s) "
+
"returns %ld.\n", rec_name[in1], r9);
+ } else {
+ int ret;
+ struct smp_call_args_t arg;
+
+ if (in1 == e->sal_info_type) {
+ IA64_SAL_DEBUG("SAL_GET_STATE_INFO(%s) "
+
"on CPU#%d.\n", rec_name[in1], e->cpuid);
+ } else {
+ IA64_SAL_DEBUG("SAL_GET_STATE_INFO(%s
<= %s) "
+
"on CPU#%d.\n", rec_name[e->sal_info_type],
+
rec_name[in1], e->cpuid);
+ }
+
+ IA64_SAL_DEBUG("SAL_GET_STATE_INFO(%s) "
+
"on CPU#%d.\n", rec_name[in1], e->cpuid);
+ if (in1 != e->sal_info_type) {
+ IA64_SAL_DEBUG("SAL_GET_STATE_INFO(%s) "
+
"instead of %s.\n",
+
rec_name[e->sal_info_type],
+
rec_name[in1]);
+ }
+ arg.type = e->sal_info_type;
+ arg.data = record;
+
+ ret = smp_call_function_single(e->cpuid,
get_state_info_on, &arg, 0, 1);
+ r9 = arg.ret;
+ IA64_SAL_DEBUG("SAL_GET_STATE_INFO(%s) on
CPU#%d "
+
"returns %ld.\n", rec_name[in1], e->cpuid, r9);
+ if (ret < 0) {
+ printk("sal_emulator:
SAL_GET_STATE_INFO "
+
"smp_call_function_single error: %d\n", ret);
+ status = ret;
+ r9 = 0;
+ }
+ }
+ if (in1 != e->sal_info_type && e->sal_info_type ==
SAL_INFO_TYPE_MCA) {
+ record->severity = sal_log_severity_corrected;
+ IA64_SAL_DEBUG("%s:
IA64_SAL_CLEAR_STATE_INFO(SAL_INFO_TYPE_MCA) force\n",
+
__FUNCTION__);
+ }
+
+ if (r9 > 0) {
+ if (copy_to_user((void __user *)in3, record,
r9)) {
+ printk("sal_emulator:
SAL_GET_STATE_INFO "
+ "can't copy to
user!!!!\n");
+ status = -5;
+ r9 = 0;
+ }
+ }
+ if (r9 == 0) {
+ list_del(&e->list);
+ xfree(e);
+ }
+ spin_unlock_irqrestore(&sal_queue_lock, flags);
+ }
break;
case SAL_GET_STATE_INFO_SIZE:
- /* Return a dummy size. */
- status = 0;
- r9 = 128;
+ r9 = ia64_sal_get_state_info_size(in1);
break;
case SAL_CLEAR_STATE_INFO:
- /* Noop. */
+ {
+ sal_queue_entry_t *e;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sal_queue_lock, flags);
+ if (list_empty(&sal_queue[in1])) {
+ IA64_SAL_DEBUG("SAL_CLEAR_STATE_INFO(%s) "
+
"no sal_queue entry found.\n", rec_name[in1]);
+ status = -5;
+ r9 = 0;
+ spin_unlock_irqrestore(&sal_queue_lock, flags);
+ break;
+ }
+ e = list_entry(sal_queue[in1].next,
sal_queue_entry_t,list);
+
+ list_del(&e->list);
+ spin_unlock_irqrestore(&sal_queue_lock, flags);
+
+ if (e->cpuid == smp_processor_id()) {
+ if (in1 == e->sal_info_type) {
+
IA64_SAL_DEBUG("SAL_CLEAR_STATE_INFO(%s) "
+
"on current CPU(%d).\n", rec_name[in1], e->cpuid);
+ } else {
+ IA64_SAL_DEBUG("SAL_CLEAR_STATE_INFO(%s
<= %s) "
+
"on current CPU(%d).\n",
+
rec_name[e->sal_info_type],
+
rec_name[in1], e->cpuid);
+ }
+ r9 =
ia64_sal_clear_state_info(e->sal_info_type);
+ IA64_SAL_DEBUG("SAL_CLEAR_STATE_INFO(%s) "
+
"returns %ld.\n", rec_name[in1], r9);
+ } else {
+ int ret;
+ struct smp_call_args_t arg;
+
+ if (in1 == e->sal_info_type) {
+
IA64_SAL_DEBUG("SAL_CLEAR_STATE_INFO(%s) "
+
"on CPU#%d.\n", rec_name[in1], e->cpuid);
+ } else {
+ IA64_SAL_DEBUG("SAL_CLEAR_STATE_INFO(%s
<= %s) "
+
"on CPU#%d.\n", rec_name[e->sal_info_type],
+
rec_name[in1], e->cpuid);
+ }
+
+ IA64_SAL_DEBUG("SAL_CLEAR_STATE_INFO(%s) "
+
"on CPU#%d.\n", rec_name[in1], e->cpuid);
+ if (in1 != e->sal_info_type) {
+
IA64_SAL_DEBUG("SAL_CLEAR_STATE_INFO(%s) "
+
"instead of %s.\n",
+
rec_name[e->sal_info_type],
+
rec_name[in1]);
+ }
+
+ arg.type = e->sal_info_type;
+
+ ret = smp_call_function_single(e->cpuid,
clear_state_info_on, &arg, 0, 1);
+ r9 = arg.ret;
+ IA64_SAL_DEBUG("SAL_CLEAR_STATE_INFO(%s) on
CPU#%d "
+
"returns %ld.\n", rec_name[in1], e->cpuid, r9);
+ if (ret < 0) {
+ printk("sal_emulator:
SAL_CLEAR_STATE_INFO "
+
"smp_call_function_single error: %d\n", ret);
+ status = ret;
+ r9 = 0;
+ }
+ }
+ xfree(e);
+ }
break;
case SAL_MC_RENDEZ:
printf("*** CALLED SAL_MC_RENDEZ. IGNORED...\n");
break;
case SAL_MC_SET_PARAMS:
- printf("*** CALLED SAL_MC_SET_PARAMS. IGNORED...\n");
+ if (in1 > sizeof(sal_mc_params)/sizeof(sal_mc_params[0]))
+ BUG();
+ sal_mc_params[in1].param_type = in1;
+ sal_mc_params[in1].i_or_m = in2;
+ sal_mc_params[in1].i_or_m_val = in3;
+ sal_mc_params[in1].timeout = in4;
+ sal_mc_params[in1].rz_always = in5;
break;
case SAL_CACHE_FLUSH:
if (1) {
_______________________________________________
Xen-ia64-devel mailing list
Xen-ia64-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-ia64-devel
|