[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-ia64-devel] [PATCH 6/12]MCA handler support for Xen/ia64 TAKE 2
Hi Alex, > On Fri, 2006-09-22 at 19:33 +0900, SUZUKI Kazuhiro wrote: > > [6/12] Add sal emulation.[mca-fw_emul.patch] > > > case SAL_GET_STATE_INFO: > ... > > + > > + spin_lock_irqsave(&sal_queue_lock, flags); > > + > ... > > + ret = smp_call_function_single(e->cpuid, > > get_state_info_on, &arg, 0, 1); > > Both SAL_GET_STATE_INFO and SAL_CLEAR_STATE_INFO use > smp_call_function_single() with interrupts disabled. This is dangerous > and can lead to deadlocks. Imagine if two processors called > smp_call_function_single() with interrupts disabled, possibly from > unrelated code paths. One processor would get the call_lock and send an > IPI to the second processor. However, the second processor is spinning > trying to get the call_lock with interrupts disabled.... hang. Thanks, Interrupts disabled state was made only the operation of sal_queue[] like list_entry() and list_del(). Thanks, KAZ 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 Thu Sep 28 12:30:34 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,54 @@ 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; + +#define IA64_SAL_NO_INFORMATION_AVAILABLE -5 + +#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 +151,206 @@ 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 = IA64_SAL_NO_INFORMATION_AVAILABLE; + r9 = 0; + spin_unlock_irqrestore(&sal_queue_lock, flags); + break; + } + e = list_entry(sal_queue[in1].next, sal_queue_entry_t, list); + spin_unlock_irqrestore(&sal_queue_lock, flags); + + 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 = IA64_SAL_NO_INFORMATION_AVAILABLE; + 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 = IA64_SAL_NO_INFORMATION_AVAILABLE; + r9 = 0; + } + } + if (r9 == 0) { + spin_lock_irqsave(&sal_queue_lock, flags); + list_del(&e->list); + spin_unlock_irqrestore(&sal_queue_lock, flags); + xfree(e); + } + } 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 = IA64_SAL_NO_INFORMATION_AVAILABLE; + 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 = IA64_SAL_NO_INFORMATION_AVAILABLE; + 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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |