[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

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.