[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] Merge in MCA tree
# HG changeset patch # User awilliam@xxxxxxxxxxx # Node ID 05d227d819355f1f3501ac791f0ece9b6194010d # Parent f78e499dd669c5736abb8c3b8c6bf16cf3ec7f3f # Parent 344fc55eb52fec67bd8cb54cb629fce1ca23485a Merge in MCA tree --- linux-2.6-xen-sparse/arch/ia64/kernel/irq_ia64.c | 61 + linux-2.6-xen-sparse/include/asm-ia64/irq.h | 4 linux-2.6-xen-sparse/include/asm-ia64/sal.h | 904 +++++++++++++++++++++++ xen/arch/ia64/asm-offsets.c | 34 xen/arch/ia64/linux-xen/mca.c | 358 ++++++++- xen/arch/ia64/linux-xen/mca_asm.S | 152 +++ xen/arch/ia64/linux-xen/smpboot.c | 2 xen/arch/ia64/xen/dom_fw.c | 23 xen/arch/ia64/xen/fw_emul.c | 241 +++++- xen/arch/ia64/xen/mm_init.c | 9 xen/arch/ia64/xen/vcpu.c | 2 xen/include/asm-ia64/event.h | 2 xen/include/asm-ia64/linux-xen/asm/mca_asm.h | 4 xen/include/asm-ia64/linux-xen/linux/interrupt.h | 6 xen/include/asm-ia64/vcpu.h | 2 xen/include/asm-ia64/xenmca.h | 34 xen/include/public/arch-ia64.h | 2 xen/include/xen/softirq.h | 6 18 files changed, 1785 insertions(+), 61 deletions(-) diff -r f78e499dd669 -r 05d227d81935 linux-2.6-xen-sparse/arch/ia64/kernel/irq_ia64.c --- a/linux-2.6-xen-sparse/arch/ia64/kernel/irq_ia64.c Tue Nov 14 14:59:37 2006 -0700 +++ b/linux-2.6-xen-sparse/arch/ia64/kernel/irq_ia64.c Wed Nov 15 12:02:09 2006 -0700 @@ -241,9 +241,15 @@ static DEFINE_PER_CPU(int, timer_irq) = static DEFINE_PER_CPU(int, timer_irq) = -1; static DEFINE_PER_CPU(int, ipi_irq) = -1; static DEFINE_PER_CPU(int, resched_irq) = -1; +static DEFINE_PER_CPU(int, cmc_irq) = -1; +static DEFINE_PER_CPU(int, cmcp_irq) = -1; +static DEFINE_PER_CPU(int, cpep_irq) = -1; static char timer_name[NR_CPUS][15]; static char ipi_name[NR_CPUS][15]; static char resched_name[NR_CPUS][15]; +static char cmc_name[NR_CPUS][15]; +static char cmcp_name[NR_CPUS][15]; +static char cpep_name[NR_CPUS][15]; struct saved_irq { unsigned int irq; @@ -323,6 +329,43 @@ xen_register_percpu_irq (unsigned int ir break; case IA64_SPURIOUS_INT_VECTOR: break; + case IA64_CMC_VECTOR: + sprintf(cmc_name[cpu], "%s%d", action->name, cpu); + ret = bind_virq_to_irqhandler(VIRQ_MCA_CMC, cpu, + action->handler, + action->flags, + cmc_name[cpu], + action->dev_id); + per_cpu(cmc_irq,cpu) = ret; + printk(KERN_INFO "register VIRQ_MCA_CMC (%s) to xen " + "irq (%d)\n", cmc_name[cpu], ret); + break; + case IA64_CMCP_VECTOR: + sprintf(cmcp_name[cpu], "%s%d", action->name, cpu); + ret = bind_ipi_to_irqhandler(CMCP_VECTOR, cpu, + action->handler, + action->flags, + cmcp_name[cpu], + action->dev_id); + per_cpu(cmcp_irq,cpu) = ret; + printk(KERN_INFO "register CMCP_VECTOR (%s) to xen " + "irq (%d)\n", cmcp_name[cpu], ret); + break; + case IA64_CPEP_VECTOR: + sprintf(cpep_name[cpu], "%s%d", action->name, cpu); + ret = bind_ipi_to_irqhandler(CPEP_VECTOR, cpu, + action->handler, + action->flags, + cpep_name[cpu], + action->dev_id); + per_cpu(cpep_irq,cpu) = ret; + printk(KERN_INFO "register CPEP_VECTOR (%s) to xen " + "irq (%d)\n", cpep_name[cpu], ret); + break; + case IA64_CPE_VECTOR: + printk(KERN_WARNING "register IA64_CPE_VECTOR " + "IGNORED\n"); + break; default: printk(KERN_WARNING "Percpu irq %d is unsupported by xen!\n", irq); break; @@ -373,6 +416,18 @@ unbind_evtchn_callback(struct notifier_b if (action == CPU_DEAD) { /* Unregister evtchn. */ + if (per_cpu(cpep_irq,cpu) >= 0) { + unbind_from_irqhandler(per_cpu(cpep_irq, cpu), NULL); + per_cpu(cpep_irq, cpu) = -1; + } + if (per_cpu(cmcp_irq,cpu) >= 0) { + unbind_from_irqhandler(per_cpu(cmcp_irq, cpu), NULL); + per_cpu(cmcp_irq, cpu) = -1; + } + if (per_cpu(cmc_irq,cpu) >= 0) { + unbind_from_irqhandler(per_cpu(cmc_irq, cpu), NULL); + per_cpu(cmc_irq, cpu) = -1; + } if (per_cpu(ipi_irq,cpu) >= 0) { unbind_from_irqhandler (per_cpu(ipi_irq, cpu), NULL); per_cpu(ipi_irq, cpu) = -1; @@ -503,6 +558,12 @@ ia64_send_ipi (int cpu, int vector, int case IA64_IPI_RESCHEDULE: irq = per_cpu(ipi_to_irq, cpu)[RESCHEDULE_VECTOR]; break; + case IA64_CMCP_VECTOR: + irq = per_cpu(ipi_to_irq, cpu)[CMCP_VECTOR]; + break; + case IA64_CPEP_VECTOR: + irq = per_cpu(ipi_to_irq, cpu)[CPEP_VECTOR]; + break; default: printk(KERN_WARNING"Unsupported IPI type 0x%x\n", vector); irq = 0; diff -r f78e499dd669 -r 05d227d81935 linux-2.6-xen-sparse/include/asm-ia64/irq.h --- a/linux-2.6-xen-sparse/include/asm-ia64/irq.h Tue Nov 14 14:59:37 2006 -0700 +++ b/linux-2.6-xen-sparse/include/asm-ia64/irq.h Wed Nov 15 12:02:09 2006 -0700 @@ -42,7 +42,9 @@ #define RESCHEDULE_VECTOR 0 #define IPI_VECTOR 1 -#define NR_IPIS 2 +#define CMCP_VECTOR 2 +#define CPEP_VECTOR 3 +#define NR_IPIS 4 #endif /* CONFIG_XEN */ /* diff -r f78e499dd669 -r 05d227d81935 xen/arch/ia64/asm-offsets.c --- a/xen/arch/ia64/asm-offsets.c Tue Nov 14 14:59:37 2006 -0700 +++ b/xen/arch/ia64/asm-offsets.c Wed Nov 15 12:02:09 2006 -0700 @@ -12,6 +12,7 @@ #include <public/xen.h> #include <asm/tlb.h> #include <asm/regs.h> +#include <asm/xenmca.h> #define task_struct vcpu @@ -221,4 +222,37 @@ void foo(void) DEFINE(FAST_HYPERPRIVOP_PERFC_OFS, offsetof (struct perfcounter, fast_hyperprivop)); DEFINE(FAST_REFLECT_PERFC_OFS, offsetof (struct perfcounter, fast_reflect)); #endif + + BLANK(); + DEFINE(IA64_CPUINFO_PTCE_BASE_OFFSET, + offsetof(struct cpuinfo_ia64, ptce_base)); + DEFINE(IA64_CPUINFO_PTCE_COUNT_OFFSET, + offsetof(struct cpuinfo_ia64, ptce_count)); + DEFINE(IA64_CPUINFO_PTCE_STRIDE_OFFSET, + offsetof(struct cpuinfo_ia64, ptce_stride)); + + BLANK(); + DEFINE(IA64_MCA_CPU_PROC_STATE_DUMP_OFFSET, + offsetof(struct ia64_mca_cpu, proc_state_dump)); + DEFINE(IA64_MCA_CPU_STACK_OFFSET, + offsetof(struct ia64_mca_cpu, stack)); + DEFINE(IA64_MCA_CPU_STACKFRAME_OFFSET, + offsetof(struct ia64_mca_cpu, stackframe)); + DEFINE(IA64_MCA_CPU_RBSTORE_OFFSET, + offsetof(struct ia64_mca_cpu, rbstore)); + + DEFINE(IA64_DOMAIN_SHARED_INFO_OFFSET, + offsetof(struct domain, shared_info)); + DEFINE(IA64_DOMAIN_SHARED_INFO_VA_OFFSET, + offsetof(struct domain, arch.shared_info_va)); + DEFINE(IA64_DOMAIN_FLAGS_OFFSET, + offsetof(struct domain, arch.flags)); + + DEFINE(IA64_VCPU_VHPT_MADDR_OFFSET, + offsetof(struct vcpu, arch.vhpt_maddr)); + + BLANK(); + DEFINE(IA64_MCA_TLB_INFO_SIZE, sizeof(struct ia64_mca_tlb_info)); + DEFINE(IA64_MCA_PERCPU_OFFSET, + offsetof(struct ia64_mca_tlb_info, percpu_paddr)); } diff -r f78e499dd669 -r 05d227d81935 xen/arch/ia64/linux-xen/mca.c --- a/xen/arch/ia64/linux-xen/mca.c Tue Nov 14 14:59:37 2006 -0700 +++ b/xen/arch/ia64/linux-xen/mca.c Wed Nov 15 12:02:09 2006 -0700 @@ -81,6 +81,9 @@ #include <xen/symbols.h> #include <xen/mm.h> #include <xen/console.h> +#include <xen/event.h> +#include <xen/softirq.h> +#include <asm/xenmca.h> #endif #if defined(IA64_MCA_DEBUG_INFO) @@ -108,18 +111,33 @@ unsigned long __per_cpu_mca[NR_CPUS]; /* In mca_asm.S */ extern void ia64_monarch_init_handler (void); extern void ia64_slave_init_handler (void); +#ifdef XEN +extern void setup_vector (unsigned int vec, struct irqaction *action); +#define setup_irq(irq, action) setup_vector(irq, action) +#endif static ia64_mc_info_t ia64_mc_info; -#ifndef XEN +#ifdef XEN +#define jiffies NOW() +#undef HZ +#define HZ 1000000000UL +#endif + #define MAX_CPE_POLL_INTERVAL (15*60*HZ) /* 15 minutes */ #define MIN_CPE_POLL_INTERVAL (2*60*HZ) /* 2 minutes */ #define CMC_POLL_INTERVAL (1*60*HZ) /* 1 minute */ #define CPE_HISTORY_LENGTH 5 #define CMC_HISTORY_LENGTH 5 +#ifndef XEN static struct timer_list cpe_poll_timer; static struct timer_list cmc_poll_timer; +#else +#define mod_timer(timer, expires) set_timer(timer, expires) +static struct timer cpe_poll_timer; +static struct timer cmc_poll_timer; +#endif /* * This variable tells whether we are currently in polling mode. * Start with this in the wrong state so we won't play w/ timers @@ -136,11 +154,9 @@ static int cpe_poll_enabled = 1; static int cpe_poll_enabled = 1; extern void salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe); -#endif /* !XEN */ static int mca_init; -#ifndef XEN /* * IA64_MCA log support */ @@ -157,11 +173,24 @@ typedef struct ia64_state_log_s static ia64_state_log_t ia64_state_log[IA64_MAX_LOG_TYPES]; +#ifndef XEN #define IA64_LOG_ALLOCATE(it, size) \ {ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)] = \ (ia64_err_rec_t *)alloc_bootmem(size); \ ia64_state_log[it].isl_log[IA64_LOG_NEXT_INDEX(it)] = \ (ia64_err_rec_t *)alloc_bootmem(size);} +#else +#define IA64_LOG_ALLOCATE(it, size) \ + do { \ + unsigned int pageorder; \ + pageorder = get_order_from_bytes(sizeof(struct ia64_mca_cpu)); \ + ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)] = \ + (ia64_err_rec_t *)alloc_xenheap_pages(pageorder); \ + ia64_state_log[it].isl_log[IA64_LOG_NEXT_INDEX(it)] = \ + (ia64_err_rec_t *)alloc_xenheap_pages(pageorder); \ + } while(0) +#endif + #define IA64_LOG_LOCK_INIT(it) spin_lock_init(&ia64_state_log[it].isl_lock) #define IA64_LOG_LOCK(it) spin_lock_irqsave(&ia64_state_log[it].isl_lock, s) #define IA64_LOG_UNLOCK(it) spin_unlock_irqrestore(&ia64_state_log[it].isl_lock,s) @@ -176,6 +205,12 @@ static ia64_state_log_t ia64_state_log[I #define IA64_LOG_CURR_BUFFER(it) (void *)((ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)])) #define IA64_LOG_COUNT(it) ia64_state_log[it].isl_count +#ifdef XEN +struct list_head sal_queue[IA64_MAX_LOG_TYPES]; +sal_log_record_header_t *sal_record = NULL; +DEFINE_SPINLOCK(sal_queue_lock); +#endif + /* * ia64_log_init * Reset the OS ia64 log buffer @@ -200,8 +235,19 @@ ia64_log_init(int sal_info_type) IA64_LOG_ALLOCATE(sal_info_type, max_size); memset(IA64_LOG_CURR_BUFFER(sal_info_type), 0, max_size); memset(IA64_LOG_NEXT_BUFFER(sal_info_type), 0, max_size); -} - + +#ifdef XEN + if (sal_record == NULL) { + unsigned int pageorder; + pageorder = get_order_from_bytes(max_size); + sal_record = (sal_log_record_header_t *) + alloc_xenheap_pages(pageorder); + BUG_ON(sal_record == NULL); + } +#endif +} + +#ifndef XEN /* * ia64_log_get * @@ -277,15 +323,159 @@ ia64_mca_log_sal_error_record(int sal_in if (rh->severity == sal_log_severity_corrected) ia64_sal_clear_state_info(sal_info_type); } +#else /* !XEN */ +/* + * ia64_log_queue + * + * Get the current MCA log from SAL and copy it into the OS log buffer. + * + * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE}) + * Outputs : size (total record length) + * *buffer (ptr to error record) + * + */ +static u64 +ia64_log_queue(int sal_info_type, int virq) +{ + sal_log_record_header_t *log_buffer; + u64 total_len = 0; + int s; + sal_queue_entry_t *e; + unsigned long flags; + + IA64_LOG_LOCK(sal_info_type); + + /* Get the process state information */ + log_buffer = IA64_LOG_NEXT_BUFFER(sal_info_type); + + total_len = ia64_sal_get_state_info(sal_info_type, (u64 *)log_buffer); + + if (total_len) { + int queue_type; + + spin_lock_irqsave(&sal_queue_lock, flags); + + if (sal_info_type == SAL_INFO_TYPE_MCA && virq == VIRQ_MCA_CMC) + queue_type = SAL_INFO_TYPE_CMC; + else + queue_type = sal_info_type; + + e = xmalloc(sal_queue_entry_t); + BUG_ON(e == NULL); + e->cpuid = smp_processor_id(); + e->sal_info_type = sal_info_type; + e->vector = IA64_CMC_VECTOR; + e->virq = virq; + e->length = total_len; + + list_add_tail(&e->list, &sal_queue[queue_type]); + spin_unlock_irqrestore(&sal_queue_lock, flags); + + IA64_LOG_INDEX_INC(sal_info_type); + IA64_LOG_UNLOCK(sal_info_type); + if (sal_info_type != SAL_INFO_TYPE_MCA && + sal_info_type != SAL_INFO_TYPE_INIT) { + IA64_MCA_DEBUG("%s: SAL error record type %d retrieved. " + "Record length = %ld\n", __FUNCTION__, + sal_info_type, total_len); + } + return total_len; + } else { + IA64_LOG_UNLOCK(sal_info_type); + return 0; + } +} +#endif /* !XEN */ /* * platform dependent error handling */ -#endif /* !XEN */ #ifndef PLATFORM_MCA_HANDLERS -#ifndef XEN #ifdef CONFIG_ACPI + +#ifdef XEN +/** + * Copy from linux/include/asm-generic/bug.h + */ +#define WARN_ON(condition) do { \ + if (unlikely((condition)!=0)) { \ + printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \ + dump_stack(); \ + } \ +} while (0) + +/** + * Copy from linux/kernel/irq/manage.c + * + * disable_irq_nosync - disable an irq without waiting + * @irq: Interrupt to disable + * + * Disable the selected interrupt line. Disables and Enables are + * nested. + * Unlike disable_irq(), this function does not ensure existing + * instances of the IRQ handler have completed before returning. + * + * This function may be called from IRQ context. + */ +void disable_irq_nosync(unsigned int irq) +{ + irq_desc_t *desc = irq_desc + irq; + unsigned long flags; + + if (irq >= NR_IRQS) + return; + + spin_lock_irqsave(&desc->lock, flags); + if (!desc->depth++) { + desc->status |= IRQ_DISABLED; + desc->handler->disable(irq); + } + spin_unlock_irqrestore(&desc->lock, flags); +} + +/** + * Copy from linux/kernel/irq/manage.c + * + * enable_irq - enable handling of an irq + * @irq: Interrupt to enable + * + * Undoes the effect of one call to disable_irq(). If this + * matches the last disable, processing of interrupts on this + * IRQ line is re-enabled. + * + * This function may be called from IRQ context. + */ +void enable_irq(unsigned int irq) +{ + irq_desc_t *desc = irq_desc + irq; + unsigned long flags; + + if (irq >= NR_IRQS) + return; + + spin_lock_irqsave(&desc->lock, flags); + switch (desc->depth) { + case 0: + WARN_ON(1); + break; + case 1: { + unsigned int status = desc->status & ~IRQ_DISABLED; + + desc->status = status; + if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { + desc->status = status | IRQ_REPLAY; + hw_resend_irq(desc->handler,irq); + } + desc->handler->enable(irq); + /* fall-through */ + } + default: + desc->depth--; + } + spin_unlock_irqrestore(&desc->lock, flags); +} +#endif /* XEN */ int cpe_vector = -1; @@ -302,8 +492,15 @@ ia64_mca_cpe_int_handler (int cpe_irq, v /* SAL spec states this should run w/ interrupts enabled */ local_irq_enable(); +#ifndef XEN /* Get the CPE error record and log it */ ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE); +#else + /* CPE error does not inform to dom0 but the following codes are + reserved for future implementation */ +/* ia64_log_queue(SAL_INFO_TYPE_CPE, VIRQ_MCA_CPE); */ +/* send_guest_vcpu_virq(dom0->vcpu[0], VIRQ_MCA_CPE); */ +#endif spin_lock(&cpe_history_lock); if (!cpe_poll_enabled && cpe_vector >= 0) { @@ -345,7 +542,6 @@ ia64_mca_cpe_int_handler (int cpe_irq, v } #endif /* CONFIG_ACPI */ -#endif /* !XEN */ static void show_min_state (pal_min_state_area_t *minstate) @@ -593,7 +789,6 @@ init_handler_platform (pal_min_state_are while (1); /* hang city if no debugger */ } -#ifndef XEN #ifdef CONFIG_ACPI /* * ia64_mca_register_cpev @@ -624,9 +819,7 @@ ia64_mca_register_cpev (int cpev) } #endif /* CONFIG_ACPI */ -#endif /* !XEN */ #endif /* PLATFORM_MCA_HANDLERS */ -#ifndef XEN /* * ia64_mca_cmc_vector_setup @@ -713,6 +906,7 @@ ia64_mca_cmc_vector_enable (void *dummy) __FUNCTION__, smp_processor_id(), cmcv.cmcv_vector); } +#ifndef XEN /* * ia64_mca_cmc_vector_disable_keventd * @@ -736,6 +930,7 @@ ia64_mca_cmc_vector_enable_keventd(void { on_each_cpu(ia64_mca_cmc_vector_enable, NULL, 1, 0); } +#endif /* !XEN */ /* * ia64_mca_wakeup_ipi_wait @@ -887,15 +1082,26 @@ static void static void ia64_return_to_sal_check(int recover) { +#ifdef XEN + int cpu = smp_processor_id(); +#endif /* Copy over some relevant stuff from the sal_to_os_mca_handoff * so that it can be used at the time of os_mca_to_sal_handoff */ +#ifdef XEN + ia64_os_to_sal_handoff_state.imots_sal_gp = + ia64_sal_to_os_handoff_state[cpu].imsto_sal_gp; + + ia64_os_to_sal_handoff_state.imots_sal_check_ra = + ia64_sal_to_os_handoff_state[cpu].imsto_sal_check_ra; +#else ia64_os_to_sal_handoff_state.imots_sal_gp = ia64_sal_to_os_handoff_state.imsto_sal_gp; ia64_os_to_sal_handoff_state.imots_sal_check_ra = ia64_sal_to_os_handoff_state.imsto_sal_check_ra; +#endif if (recover) ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_CORRECTED; @@ -905,8 +1111,13 @@ ia64_return_to_sal_check(int recover) /* Default = tell SAL to return to same context */ ia64_os_to_sal_handoff_state.imots_context = IA64_MCA_SAME_CONTEXT; +#ifdef XEN + ia64_os_to_sal_handoff_state.imots_new_min_state = + (u64 *)ia64_sal_to_os_handoff_state[cpu].pal_min_state; +#else ia64_os_to_sal_handoff_state.imots_new_min_state = (u64 *)ia64_sal_to_os_handoff_state.pal_min_state; +#endif } @@ -954,27 +1165,44 @@ void void ia64_mca_ucmc_handler(void) { +#ifdef XEN + int cpu = smp_processor_id(); + pal_processor_state_info_t *psp = (pal_processor_state_info_t *) + &ia64_sal_to_os_handoff_state[cpu].proc_state_param; +#else pal_processor_state_info_t *psp = (pal_processor_state_info_t *) &ia64_sal_to_os_handoff_state.proc_state_param; +#endif int recover; +#ifndef XEN /* Get the MCA error record and log it */ ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA); +#else + ia64_log_queue(SAL_INFO_TYPE_MCA, VIRQ_MCA_CMC); + send_guest_vcpu_virq(dom0->vcpu[0], VIRQ_MCA_CMC); +#endif /* TLB error is only exist in this SAL error record */ recover = (psp->tc && !(psp->cc || psp->bc || psp->rc || psp->uc)) /* other error recovery */ +#ifndef XEN || (ia64_mca_ucmc_extension && ia64_mca_ucmc_extension( IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_MCA), &ia64_sal_to_os_handoff_state, &ia64_os_to_sal_handoff_state)); - +#else + ; +#endif + +#ifndef XEN if (recover) { sal_log_record_header_t *rh = IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_MCA); rh->severity = sal_log_severity_corrected; ia64_sal_clear_state_info(SAL_INFO_TYPE_MCA); } +#endif /* * Wakeup all the processors which are spinning in the rendezvous * loop. @@ -985,8 +1213,10 @@ ia64_mca_ucmc_handler(void) ia64_return_to_sal_check(recover); } +#ifndef XEN static DECLARE_WORK(cmc_disable_work, ia64_mca_cmc_vector_disable_keventd, NULL); static DECLARE_WORK(cmc_enable_work, ia64_mca_cmc_vector_enable_keventd, NULL); +#endif /* * ia64_mca_cmc_int_handler @@ -1016,8 +1246,13 @@ ia64_mca_cmc_int_handler(int cmc_irq, vo /* SAL spec states this should run w/ interrupts enabled */ local_irq_enable(); +#ifndef XEN /* Get the CMC error record and log it */ ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC); +#else + ia64_log_queue(SAL_INFO_TYPE_CMC, VIRQ_MCA_CMC); + send_guest_vcpu_virq(dom0->vcpu[0], VIRQ_MCA_CMC); +#endif spin_lock(&cmc_history_lock); if (!cmc_polling_enabled) { @@ -1034,7 +1269,12 @@ ia64_mca_cmc_int_handler(int cmc_irq, vo cmc_polling_enabled = 1; spin_unlock(&cmc_history_lock); +#ifndef XEN /* XXX FIXME */ schedule_work(&cmc_disable_work); +#else + cpumask_raise_softirq(cpu_online_map, + CMC_DISABLE_SOFTIRQ); +#endif /* * Corrected errors will still be corrected, but @@ -1083,7 +1323,9 @@ ia64_mca_cmc_int_caller(int cmc_irq, voi if (start_count == -1) start_count = IA64_LOG_COUNT(SAL_INFO_TYPE_CMC); +#ifndef XEN ia64_mca_cmc_int_handler(cmc_irq, arg, ptregs); +#endif for (++cpuid ; cpuid < NR_CPUS && !cpu_online(cpuid) ; cpuid++); @@ -1094,7 +1336,12 @@ ia64_mca_cmc_int_caller(int cmc_irq, voi if (start_count == IA64_LOG_COUNT(SAL_INFO_TYPE_CMC)) { printk(KERN_WARNING "Returning to interrupt driven CMC handler\n"); +#ifndef XEN /* XXX FIXME */ schedule_work(&cmc_enable_work); +#else + cpumask_raise_softirq(cpu_online_map, + CMC_ENABLE_SOFTIRQ); +#endif cmc_polling_enabled = 0; } else { @@ -1104,7 +1351,6 @@ ia64_mca_cmc_int_caller(int cmc_irq, voi start_count = -1; } - return IRQ_HANDLED; } @@ -1118,7 +1364,11 @@ ia64_mca_cmc_int_caller(int cmc_irq, voi * */ static void +#ifndef XEN ia64_mca_cmc_poll (unsigned long dummy) +#else +ia64_mca_cmc_poll (void *dummy) +#endif { /* Trigger a CMC interrupt cascade */ platform_send_ipi(first_cpu(cpu_online_map), IA64_CMCP_VECTOR, IA64_IPI_DM_INT, 0); @@ -1144,7 +1394,11 @@ ia64_mca_cpe_int_caller(int cpe_irq, voi ia64_mca_cpe_int_caller(int cpe_irq, void *arg, struct pt_regs *ptregs) { static int start_count = -1; +#ifdef XEN + static unsigned long poll_time = MIN_CPE_POLL_INTERVAL; +#else static int poll_time = MIN_CPE_POLL_INTERVAL; +#endif unsigned int cpuid; cpuid = smp_processor_id(); @@ -1153,7 +1407,9 @@ ia64_mca_cpe_int_caller(int cpe_irq, voi if (start_count == -1) start_count = IA64_LOG_COUNT(SAL_INFO_TYPE_CPE); +#ifndef XEN ia64_mca_cpe_int_handler(cpe_irq, arg, ptregs); +#endif for (++cpuid ; cpuid < NR_CPUS && !cpu_online(cpuid) ; cpuid++); @@ -1180,7 +1436,6 @@ ia64_mca_cpe_int_caller(int cpe_irq, voi mod_timer(&cpe_poll_timer, jiffies + poll_time); start_count = -1; } - return IRQ_HANDLED; } @@ -1195,14 +1450,17 @@ ia64_mca_cpe_int_caller(int cpe_irq, voi * */ static void +#ifndef XEN ia64_mca_cpe_poll (unsigned long dummy) +#else +ia64_mca_cpe_poll (void *dummy) +#endif { /* Trigger a CPE interrupt cascade */ platform_send_ipi(first_cpu(cpu_online_map), IA64_CPEP_VECTOR, IA64_IPI_DM_INT, 0); } #endif /* CONFIG_ACPI */ -#endif /* !XEN */ /* * C portion of the OS INIT handler @@ -1248,7 +1506,6 @@ ia64_init_handler (struct pt_regs *pt, s init_handler_platform(ms, pt, sw); /* call platform specific routines */ } -#ifndef XEN static int __init ia64_mca_disable_cpe_polling(char *str) { @@ -1260,42 +1517,53 @@ __setup("disable_cpe_poll", ia64_mca_dis static struct irqaction cmci_irqaction = { .handler = ia64_mca_cmc_int_handler, +#ifndef XEN .flags = SA_INTERRUPT, +#endif .name = "cmc_hndlr" }; static struct irqaction cmcp_irqaction = { .handler = ia64_mca_cmc_int_caller, +#ifndef XEN .flags = SA_INTERRUPT, +#endif .name = "cmc_poll" }; static struct irqaction mca_rdzv_irqaction = { .handler = ia64_mca_rendez_int_handler, +#ifndef XEN .flags = SA_INTERRUPT, +#endif .name = "mca_rdzv" }; static struct irqaction mca_wkup_irqaction = { .handler = ia64_mca_wakeup_int_handler, +#ifndef XEN .flags = SA_INTERRUPT, +#endif .name = "mca_wkup" }; #ifdef CONFIG_ACPI static struct irqaction mca_cpe_irqaction = { .handler = ia64_mca_cpe_int_handler, +#ifndef XEN .flags = SA_INTERRUPT, +#endif .name = "cpe_hndlr" }; static struct irqaction mca_cpep_irqaction = { .handler = ia64_mca_cpe_int_caller, +#ifndef XEN .flags = SA_INTERRUPT, +#endif .name = "cpe_poll" }; #endif /* CONFIG_ACPI */ -#endif /* !XEN */ /* Do per-CPU MCA-related initialization. */ @@ -1329,6 +1597,13 @@ ia64_mca_cpu_init(void *cpu_data) #endif } } +#ifdef XEN + else { + int i; + for (i = 0; i < IA64_MAX_LOG_TYPES; i++) + ia64_log_queue(i, 0); + } +#endif /* * The MCA info structure was allocated earlier and its @@ -1395,17 +1670,14 @@ ia64_mca_init(void) ia64_fptr_t *mon_init_ptr = (ia64_fptr_t *)ia64_monarch_init_handler; ia64_fptr_t *slave_init_ptr = (ia64_fptr_t *)ia64_slave_init_handler; ia64_fptr_t *mca_hldlr_ptr = (ia64_fptr_t *)ia64_os_mca_dispatch; -#ifdef XEN - s64 rc; - - slave_init_ptr = (ia64_fptr_t *)ia64_monarch_init_handler; - - IA64_MCA_DEBUG("%s: begin\n", __FUNCTION__); -#else int i; s64 rc; struct ia64_sal_retval isrv; u64 timeout = IA64_MCA_RENDEZ_TIMEOUT; /* platform specific */ + +#ifdef XEN + slave_init_ptr = (ia64_fptr_t *)ia64_monarch_init_handler; +#endif IA64_MCA_DEBUG("%s: begin\n", __FUNCTION__); @@ -1451,7 +1723,6 @@ ia64_mca_init(void) } IA64_MCA_DEBUG("%s: registered MCA rendezvous spinloop and wakeup mech.\n", __FUNCTION__); -#endif /* !XEN */ ia64_mc_info.imi_mca_handler = ia64_tpa(mca_hldlr_ptr->fp); /* @@ -1503,7 +1774,6 @@ ia64_mca_init(void) IA64_MCA_DEBUG("%s: registered OS INIT handler with SAL\n", __FUNCTION__); -#ifndef XEN /* * Configure the CMCI/P vector and handler. Interrupts for CMC are * per-processor, so AP CMC interrupts are setup in smp_callin() (smpboot.c). @@ -1531,13 +1801,26 @@ ia64_mca_init(void) ia64_log_init(SAL_INFO_TYPE_INIT); ia64_log_init(SAL_INFO_TYPE_CMC); ia64_log_init(SAL_INFO_TYPE_CPE); -#endif /* !XEN */ + +#ifdef XEN + INIT_LIST_HEAD(&sal_queue[SAL_INFO_TYPE_MCA]); + INIT_LIST_HEAD(&sal_queue[SAL_INFO_TYPE_INIT]); + INIT_LIST_HEAD(&sal_queue[SAL_INFO_TYPE_CMC]); + INIT_LIST_HEAD(&sal_queue[SAL_INFO_TYPE_CPE]); + + open_softirq(CMC_DISABLE_SOFTIRQ, + (softirq_handler)ia64_mca_cmc_vector_disable); + open_softirq(CMC_ENABLE_SOFTIRQ, + (softirq_handler)ia64_mca_cmc_vector_enable); + + for (i = 0; i < IA64_MAX_LOG_TYPES; i++) + ia64_log_queue(i, 0); +#endif mca_init = 1; printk(KERN_INFO "MCA related initialization done\n"); } -#ifndef XEN /* * ia64_mca_late_init * @@ -1555,20 +1838,34 @@ ia64_mca_late_init(void) return 0; /* Setup the CMCI/P vector and handler */ +#ifndef XEN init_timer(&cmc_poll_timer); cmc_poll_timer.function = ia64_mca_cmc_poll; +#else + init_timer(&cmc_poll_timer, ia64_mca_cmc_poll, NULL, smp_processor_id()); + printk("INIT_TIMER(cmc_poll_timer): on cpu%d\n", smp_processor_id()); +#endif /* Unmask/enable the vector */ cmc_polling_enabled = 0; +#ifndef XEN /* XXX FIXME */ schedule_work(&cmc_enable_work); +#else + cpumask_raise_softirq(cpu_online_map, CMC_ENABLE_SOFTIRQ); +#endif IA64_MCA_DEBUG("%s: CMCI/P setup and enabled.\n", __FUNCTION__); #ifdef CONFIG_ACPI /* Setup the CPEI/P vector and handler */ cpe_vector = acpi_request_vector(ACPI_INTERRUPT_CPEI); +#ifndef XEN init_timer(&cpe_poll_timer); cpe_poll_timer.function = ia64_mca_cpe_poll; +#else + init_timer(&cpe_poll_timer, ia64_mca_cpe_poll, NULL, smp_processor_id()); + printk("INIT_TIMER(cpe_poll_timer): on cpu%d\n", smp_processor_id()); +#endif { irq_desc_t *desc; @@ -1598,5 +1895,8 @@ ia64_mca_late_init(void) return 0; } +#ifndef XEN device_initcall(ia64_mca_late_init); -#endif /* !XEN */ +#else +__initcall(ia64_mca_late_init); +#endif diff -r f78e499dd669 -r 05d227d81935 xen/arch/ia64/linux-xen/mca_asm.S --- a/xen/arch/ia64/linux-xen/mca_asm.S Tue Nov 14 14:59:37 2006 -0700 +++ b/xen/arch/ia64/linux-xen/mca_asm.S Wed Nov 15 12:02:09 2006 -0700 @@ -24,6 +24,9 @@ #include <asm/processor.h> #include <asm/mca_asm.h> #include <asm/mca.h> +#ifdef XEN +#include <asm/vhpt.h> +#endif /* * When we get a machine check, the kernel stack pointer is no longer @@ -50,8 +53,7 @@ */ #ifdef XEN #define SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(_tmp) \ - movl _tmp=THIS_CPU(ia64_sal_to_os_handoff_state_addr);; \ - tpa _tmp=_tmp;; \ + GET_THIS_PADDR(_tmp, ia64_sal_to_os_handoff_state_addr);; \ ld8 _tmp=[_tmp];; \ st8 [_tmp]=r1,0x08;; \ st8 [_tmp]=r8,0x08;; \ @@ -72,6 +74,7 @@ st8 [_tmp]=r12,0x08;; \ st8 [_tmp]=r17,0x08;; \ st8 [_tmp]=r18,0x08 +#endif /* XEN */ /* * OS_MCA_TO_SAL_HANDOFF_STATE (SAL 3.0 spec) @@ -101,6 +104,24 @@ * imots_sal_check_ra=Return address to location within SAL_CHECK * */ +#ifdef XEN +#define COLD_BOOT_HANDOFF_STATE(sal_to_os_handoff,os_to_sal_handoff,tmp)\ + movl tmp=IA64_MCA_COLD_BOOT; \ + GET_THIS_PADDR(r2,ia64_sal_to_os_handoff_state_addr);; \ + ld8 sal_to_os_handoff=[sal_to_os_handoff];; \ + movl os_to_sal_handoff=ia64_os_to_sal_handoff_state;; \ + dep os_to_sal_handoff = 0, os_to_sal_handoff, 60, 4;; \ + /*DATA_VA_TO_PA(os_to_sal_handoff);;*/ \ + st8 [os_to_sal_handoff]=tmp,8;; \ + ld8 tmp=[sal_to_os_handoff],48;; \ + st8 [os_to_sal_handoff]=tmp,8;; \ + movl tmp=IA64_MCA_SAME_CONTEXT;; \ + st8 [os_to_sal_handoff]=tmp,8;; \ + ld8 tmp=[sal_to_os_handoff],-8;; \ + st8 [os_to_sal_handoff]=tmp,8;; \ + ld8 tmp=[sal_to_os_handoff];; \ + st8 [os_to_sal_handoff]=tmp;; +#else /* XEN */ #define COLD_BOOT_HANDOFF_STATE(sal_to_os_handoff,os_to_sal_handoff,tmp)\ movl tmp=IA64_MCA_COLD_BOOT; \ movl sal_to_os_handoff=__pa(ia64_sal_to_os_handoff_state); \ @@ -114,13 +135,13 @@ st8 [os_to_sal_handoff]=tmp,8;; \ ld8 tmp=[sal_to_os_handoff];; \ st8 [os_to_sal_handoff]=tmp;; +#endif /* XEN */ #define GET_IA64_MCA_DATA(reg) \ GET_THIS_PADDR(reg, ia64_mca_data) \ ;; \ ld8 reg=[reg] -#endif /* XEN */ .global ia64_os_mca_dispatch .global ia64_os_mca_dispatch_end #ifndef XEN @@ -132,7 +153,40 @@ .text .align 16 -#ifndef XEN +#ifdef XEN +/* + * void set_per_cpu_data(void) + * { + * int i; + * for (i = 0; i < 64; i++) { + * if (ia64_mca_tlb_list[i].cr_lid == ia64_getreg(_IA64_REG_CR_LID)) { + * ia64_set_kr(IA64_KR_PER_CPU_DATA, ia64_mca_tlb_list[i].percpu_paddr); + * return; + * } + * } + * while(1); // Endless loop on error + * } + */ +#define SET_PER_CPU_DATA() \ + LOAD_PHYSICAL(p0,r2,ia64_mca_tlb_list);; \ + mov r7 = r0; \ + mov r6 = r0;; \ + adds r3 = IA64_MCA_PERCPU_OFFSET, r2; \ +1: add r4 = r6, r2; \ + mov r5=cr.lid;; \ + adds r7 = 1, r7; \ + ld8 r4 = [r4];; \ + cmp.ne p6, p7 = r5, r4; \ + cmp4.lt p8, p9 = NR_CPUS-1, r7; \ +(p7) br.cond.dpnt 3f; \ + adds r6 = 16, r6; \ +(p9) br.cond.sptk 1b; \ +2: br 2b;; /* Endless loop on error */ \ +3: add r4 = r6, r3;; \ + ld8 r4 = [r4];; \ + mov ar.k3=r4 +#endif /* XEN */ + /* * Just the TLB purge part is moved to a separate function * so we can re-use the code for cpu hotplug code as well @@ -221,6 +275,44 @@ 4: ;; srlz.i ;; +#ifdef XEN + // 5. VHPT +#if VHPT_ENABLED + // r25 = __va_ul(vcpu_vhpt_maddr(v)); + GET_THIS_PADDR(r2,cpu_kr);; + add r2=IA64_KR_CURRENT_OFFSET,r2;; + ld8 r2=[r2];; +#ifdef CONFIG_XEN_IA64_PERVCPU_VHPT +#define HAS_PERVCPU_VHPT_MASK 0x2 + dep r3=0,r2,60,4;; // virtual to physical + add r3=IA64_VCPU_DOMAIN_OFFSET,r3;; + ld8 r3=[r3];; + dep r3=0,r3,60,4;; // virtual to physical + add r3=IA64_DOMAIN_FLAGS_OFFSET,r3;; + ld8 r3=[r3];; + and r3=HAS_PERVCPU_VHPT_MASK,r3;; + cmp.eq p6,p0=r3,r0;; +(p6) br.cond.sptk .not_pervcpu_vhpt + add r2=IA64_VCPU_VHPT_MADDR_OFFSET,r2;; + dep r2=0,r2,60,4;; // virtual to physical + ld8 r2=[r2];; + dep r25=-1,r2,60,4;; // physical to virtual + br.sptk .percpu_vhpt_done +#endif +.not_pervcpu_vhpt: + GET_THIS_PADDR(r2, vhpt_paddr);; + ld8 r2=[r2];; + dep r25=-1,r2,60,4;; // physical to virtual +.percpu_vhpt_done: + dep r20=0,r25,0,IA64_GRANULE_SHIFT + mov r24=IA64_GRANULE_SHIFT<<2 + ;; + ptr.d r20,r24 + ;; + srlz.d + ;; +#endif +#endif // Now branch away to caller. br.sptk.many b1 ;; @@ -235,6 +327,9 @@ ia64_os_mca_spin: cmp.ne p6,p0=r4,r0 (p6) br ia64_os_mca_spin +#ifdef XEN + SET_PER_CPU_DATA();; +#endif // Save the SAL to OS MCA handoff state as defined // by SAL SPEC 3.0 // NOTE : The order in which the state gets saved @@ -250,7 +345,19 @@ begin_os_mca_dump: ia64_os_mca_done_dump: +#ifdef XEN + // Set current to ar.k6 + GET_THIS_PADDR(r2,cpu_kr);; + add r2=IA64_KR_CURRENT_OFFSET,r2;; + ld8 r2=[r2];; + mov ar.k6=r2;; + + GET_THIS_PADDR(r2,ia64_sal_to_os_handoff_state_addr);; + ld8 r2=[r2];; + adds r16=56,r2 +#else LOAD_PHYSICAL(p0,r16,ia64_sal_to_os_handoff_state+56) +#endif ;; ld8 r18=[r16] // Get processor state parameter on existing PALE_CHECK. ;; @@ -342,6 +449,28 @@ ia64_reload_tr: ;; srlz.d ;; +#ifdef XEN + // 5. VHPT +#if VHPT_ENABLED + // r25 = __va_ul(vcpu_vhpt_maddr(v)); + dep r20=0,r25,0,IA64_GRANULE_SHIFT + movl r26=PAGE_KERNEL + ;; + mov r21=IA64_TR_VHPT + dep r22=0,r20,60,4 // physical address of + // va_vhpt & ~(IA64_GRANULE_SIZE - 1) + mov r24=IA64_GRANULE_SHIFT<<2 + ;; + or r23=r22,r26 // construct PA | page properties + mov cr.itir=r24 + mov cr.ifa=r20 + ;; + itr.d dtr[r21]=r23 // wire in new mapping... + ;; + srlz.d + ;; +#endif +#endif br.sptk.many done_tlb_purge_and_reload err: COLD_BOOT_HANDOFF_STATE(r20,r21,r22) @@ -874,12 +1003,6 @@ end_os_mca_restore: br ia64_os_mca_done_restore;; //EndStub////////////////////////////////////////////////////////////////////// -#else -ia64_os_mca_dispatch: -1: - br.sptk 1b -ia64_os_mca_dispatch_end: -#endif /* !XEN */ // ok, the issue here is that we need to save state information so @@ -911,6 +1034,15 @@ ia64_os_mca_dispatch_end: GLOBAL_ENTRY(ia64_monarch_init_handler) .prologue +#ifdef XEN /* Need in ia64_monarch_init_handler? */ + SET_PER_CPU_DATA();; + + // Set current to ar.k6 + GET_THIS_PADDR(r2,cpu_kr);; + add r2=IA64_KR_CURRENT_OFFSET,r2;; + ld8 r2=[r2];; + mov ar.k6=r2;; +#endif // stash the information the SAL passed to os SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(r2) ;; diff -r f78e499dd669 -r 05d227d81935 xen/arch/ia64/linux-xen/smpboot.c --- a/xen/arch/ia64/linux-xen/smpboot.c Tue Nov 14 14:59:37 2006 -0700 +++ b/xen/arch/ia64/linux-xen/smpboot.c Wed Nov 15 12:02:09 2006 -0700 @@ -365,9 +365,7 @@ smp_callin (void) smp_setup_percpu_timer(); -#ifndef XEN ia64_mca_cmc_vector_setup(); /* Setup vector on AP */ -#endif #ifdef CONFIG_PERFMON pfm_init_percpu(); diff -r f78e499dd669 -r 05d227d81935 xen/arch/ia64/xen/dom_fw.c --- a/xen/arch/ia64/xen/dom_fw.c Tue Nov 14 14:59:37 2006 -0700 +++ b/xen/arch/ia64/xen/dom_fw.c Wed Nov 15 12:02:09 2006 -0700 @@ -240,6 +240,23 @@ acpi_update_lsapic (acpi_table_entry_hea return 0; } +static int __init +acpi_patch_plat_int_src ( + acpi_table_entry_header *header, const unsigned long end) +{ + struct acpi_table_plat_int_src *plintsrc; + + plintsrc = (struct acpi_table_plat_int_src *)header; + if (!plintsrc) + return -EINVAL; + + if (plintsrc->type == ACPI_INTERRUPT_CPEI) { + printk("ACPI_INTERRUPT_CPEI disabled for Domain0\n"); + plintsrc->type = -1; + } + return 0; +} + static u8 generate_acpi_checksum(void *tbl, unsigned long len) { @@ -271,7 +288,11 @@ static void touch_acpi_table(void) { lsapic_nbr = 0; if (acpi_table_parse_madt(ACPI_MADT_LSAPIC, acpi_update_lsapic, 0) < 0) - printk("Error parsing MADT - no LAPIC entires\n"); + printk("Error parsing MADT - no LAPIC entries\n"); + if (acpi_table_parse_madt(ACPI_MADT_PLAT_INT_SRC, + acpi_patch_plat_int_src, 0) < 0) + printk("Error parsing MADT - no PLAT_INT_SRC entries\n"); + acpi_table_parse(ACPI_APIC, acpi_update_madt_checksum); return; diff -r f78e499dd669 -r 05d227d81935 xen/arch/ia64/xen/fw_emul.c --- a/xen/arch/ia64/xen/fw_emul.c Tue Nov 14 14:59:37 2006 -0700 +++ b/xen/arch/ia64/xen/fw_emul.c Wed Nov 15 12:02:09 2006 -0700 @@ -22,6 +22,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" @@ -36,6 +37,93 @@ static DEFINE_SPINLOCK(efi_time_services 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; + u64 target; + struct domain *domain; + int corrected; + int status; + void *data; +}; + +extern sal_log_record_header_t *sal_record; +DEFINE_SPINLOCK(sal_record_lock); + +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; + int flags; + + spin_lock_irqsave(&sal_record_lock, flags); + memset(sal_record, 0, ia64_sal_get_state_info_size(arg->type)); + arg->ret = ia64_sal_get_state_info(arg->type, (u64 *)sal_record); + IA64_SAL_DEBUG("SAL_GET_STATE_INFO(%s) on CPU#%d returns %ld.\n", + rec_name[arg->type], smp_processor_id(), arg->ret); + if (arg->corrected) { + sal_record->severity = sal_log_severity_corrected; + IA64_SAL_DEBUG("%s: IA64_SAL_CLEAR_STATE_INFO(SAL_INFO_TYPE_MCA)" + " force\n", __FUNCTION__); + } + if (arg->ret > 0) { + /* + * Save current->domain and set to local(caller) domain for + * xencomm_paddr_to_maddr() which calculates maddr from + * paddr using mpa value of current->domain. + */ + struct domain *save; + save = current->domain; + current->domain = arg->domain; + if (xencomm_copy_to_guest((void*)arg->target, + sal_record, arg->ret, 0)) { + printk("SAL_GET_STATE_INFO can't copy to user!!!!\n"); + arg->status = IA64_SAL_NO_INFORMATION_AVAILABLE; + arg->ret = 0; + } + /* Restore current->domain to saved value. */ + current->domain = save; + } + spin_unlock_irqrestore(&sal_record_lock, flags); +} + +void clear_state_info_on(void *data) { + struct smp_call_args_t *arg = data; + + arg->ret = ia64_sal_clear_state_info(arg->type); + IA64_SAL_DEBUG("SAL_CLEAR_STATE_INFO(%s) on CPU#%d returns %ld.\n", + rec_name[arg->type], smp_processor_id(), arg->ret); + +} + struct sal_ret_values sal_emulator (long index, unsigned long in1, unsigned long in2, unsigned long in3, unsigned long in4, unsigned long in5, @@ -106,27 +194,160 @@ sal_emulator (long index, unsigned long } } else - printk("*** 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; + if (current->domain == dom0) { + sal_queue_entry_t *e; + unsigned long flags; + struct smp_call_args_t arg; + + spin_lock_irqsave(&sal_queue_lock, flags); + if (list_empty(&sal_queue[in1])) { + sal_log_record_header_t header; + XEN_GUEST_HANDLE(void) handle = + *(XEN_GUEST_HANDLE(void)*)&in3; + + 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_guest(handle, &header, 1)) { + 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); + + IA64_SAL_DEBUG("SAL_GET_STATE_INFO(%s <= %s) " + "on CPU#%d.\n", + rec_name[e->sal_info_type], + rec_name[in1], e->cpuid); + + arg.type = e->sal_info_type; + arg.target = in3; + arg.corrected = !!((in1 != e->sal_info_type) && + (e->sal_info_type == SAL_INFO_TYPE_MCA)); + arg.domain = current->domain; + arg.status = 0; + + if (e->cpuid == smp_processor_id()) { + IA64_SAL_DEBUG("SAL_GET_STATE_INFO: local\n"); + get_state_info_on(&arg); + } else { + int ret; + IA64_SAL_DEBUG("SAL_GET_STATE_INFO: remote\n"); + ret = smp_call_function_single(e->cpuid, + get_state_info_on, + &arg, 0, 1); + if (ret < 0) { + printk("SAL_GET_STATE_INFO " + "smp_call_function_single error:" + " %d\n", ret); + arg.ret = 0; + arg.status = + IA64_SAL_NO_INFORMATION_AVAILABLE; + } + } + r9 = arg.ret; + status = arg.status; + if (r9 == 0) { + spin_lock_irqsave(&sal_queue_lock, flags); + list_del(&e->list); + spin_unlock_irqrestore(&sal_queue_lock, flags); + xfree(e); + } + } else { + status = IA64_SAL_NO_INFORMATION_AVAILABLE; + r9 = 0; + } 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. */ + if (current->domain == dom0) { + sal_queue_entry_t *e; + unsigned long flags; + struct smp_call_args_t arg; + + 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); + + IA64_SAL_DEBUG("SAL_CLEAR_STATE_INFO(%s <= %s) " + "on CPU#%d.\n", + rec_name[e->sal_info_type], + rec_name[in1], e->cpuid); + + + arg.type = e->sal_info_type; + arg.status = 0; + if (e->cpuid == smp_processor_id()) { + IA64_SAL_DEBUG("SAL_CLEAR_STATE_INFO: local\n"); + clear_state_info_on(&arg); + } else { + int ret; + IA64_SAL_DEBUG("SAL_CLEAR_STATE_INFO: remote\n"); + ret = smp_call_function_single(e->cpuid, + clear_state_info_on, &arg, 0, 1); + if (ret < 0) { + printk("sal_emulator: " + "SAL_CLEAR_STATE_INFO " + "smp_call_function_single error:" + " %d\n", ret); + arg.ret = 0; + arg.status = + IA64_SAL_NO_INFORMATION_AVAILABLE; + } + } + r9 = arg.ret; + status = arg.status; + xfree(e); + } break; case SAL_MC_RENDEZ: printk("*** CALLED SAL_MC_RENDEZ. IGNORED...\n"); break; case SAL_MC_SET_PARAMS: - printk("*** 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) { diff -r f78e499dd669 -r 05d227d81935 xen/arch/ia64/xen/mm_init.c --- a/xen/arch/ia64/xen/mm_init.c Tue Nov 14 14:59:37 2006 -0700 +++ b/xen/arch/ia64/xen/mm_init.c Wed Nov 15 12:02:09 2006 -0700 @@ -10,6 +10,11 @@ #include <xen/sched.h> #include <asm/vhpt.h> +#include <asm/xenmca.h> +#include <asm/meminit.h> +#include <asm/page.h> + +struct ia64_mca_tlb_info ia64_mca_tlb_list[NR_CPUS]; extern void ia64_tlb_init (void); @@ -93,11 +98,13 @@ ia64_mmu_init (void *my_cpu_data) cpu = smp_processor_id(); -#ifndef XEN /* mca handler uses cr.lid as key to pick the right entry */ ia64_mca_tlb_list[cpu].cr_lid = ia64_getreg(_IA64_REG_CR_LID); /* insert this percpu data information into our list for MCA recovery purposes */ +#ifdef XEN + ia64_mca_tlb_list[cpu].percpu_paddr = __pa(my_cpu_data); +#else ia64_mca_tlb_list[cpu].percpu_paddr = pte_val(mk_pte_phys(__pa(my_cpu_data), PAGE_KERNEL)); /* Also save per-cpu tlb flush recipe for use in physical mode mca handler */ ia64_mca_tlb_list[cpu].ptce_base = local_cpu_data->ptce_base; diff -r f78e499dd669 -r 05d227d81935 xen/arch/ia64/xen/vcpu.c --- a/xen/arch/ia64/xen/vcpu.c Tue Nov 14 14:59:37 2006 -0700 +++ b/xen/arch/ia64/xen/vcpu.c Wed Nov 15 12:02:09 2006 -0700 @@ -46,8 +46,6 @@ typedef union { // this def for vcpu_regs won't work if kernel stack is present //#define vcpu_regs(vcpu) ((struct pt_regs *) vcpu->arch.regs -#define TRUE 1 -#define FALSE 0 #define IA64_PTA_SZ_BIT 2 #define IA64_PTA_VF_BIT 8 #define IA64_PTA_BASE_BIT 15 diff -r f78e499dd669 -r 05d227d81935 xen/include/asm-ia64/event.h --- a/xen/include/asm-ia64/event.h Tue Nov 14 14:59:37 2006 -0700 +++ b/xen/include/asm-ia64/event.h Wed Nov 15 12:02:09 2006 -0700 @@ -70,6 +70,8 @@ static inline int arch_virq_is_global(in switch ( virq ) { case VIRQ_ITC: + case VIRQ_MCA_CMC: + case VIRQ_MCA_CPE: rc = 0; break; default: diff -r f78e499dd669 -r 05d227d81935 xen/include/asm-ia64/linux-xen/asm/mca_asm.h --- a/xen/include/asm-ia64/linux-xen/asm/mca_asm.h Tue Nov 14 14:59:37 2006 -0700 +++ b/xen/include/asm-ia64/linux-xen/asm/mca_asm.h Wed Nov 15 12:02:09 2006 -0700 @@ -59,8 +59,8 @@ #ifdef XEN #define GET_THIS_PADDR(reg, var) \ - movl reg = THIS_CPU(var) \ - tpa reg = reg + mov reg = IA64_KR(PER_CPU_DATA);; \ + addl reg = THIS_CPU(var) - PERCPU_ADDR, reg #else #define GET_THIS_PADDR(reg, var) \ mov reg = IA64_KR(PER_CPU_DATA);; \ diff -r f78e499dd669 -r 05d227d81935 xen/include/asm-ia64/linux-xen/linux/interrupt.h --- a/xen/include/asm-ia64/linux-xen/linux/interrupt.h Tue Nov 14 14:59:37 2006 -0700 +++ b/xen/include/asm-ia64/linux-xen/linux/interrupt.h Wed Nov 15 12:02:09 2006 -0700 @@ -29,13 +29,15 @@ */ #ifdef XEN typedef void irqreturn_t; +#define IRQ_NONE +#define IRQ_HANDLED +#define IRQ_RETVAL(x) #else typedef int irqreturn_t; -#endif - #define IRQ_NONE (0) #define IRQ_HANDLED (1) #define IRQ_RETVAL(x) ((x) != 0) +#endif #ifndef XEN struct irqaction { diff -r f78e499dd669 -r 05d227d81935 xen/include/asm-ia64/vcpu.h --- a/xen/include/asm-ia64/vcpu.h Tue Nov 14 14:59:37 2006 -0700 +++ b/xen/include/asm-ia64/vcpu.h Wed Nov 15 12:02:09 2006 -0700 @@ -10,7 +10,7 @@ #include <asm/ia64_int.h> #include <xen/types.h> #include <public/xen.h> -typedef int BOOLEAN; +#include <linux/acpi.h> struct vcpu; typedef struct vcpu VCPU; typedef cpu_user_regs_t REGS; diff -r f78e499dd669 -r 05d227d81935 xen/include/public/arch-ia64.h --- a/xen/include/public/arch-ia64.h Tue Nov 14 14:59:37 2006 -0700 +++ b/xen/include/public/arch-ia64.h Wed Nov 15 12:02:09 2006 -0700 @@ -59,6 +59,8 @@ DEFINE_XEN_GUEST_HANDLE(xen_pfn_t); /* Arch specific VIRQs definition */ #define VIRQ_ITC VIRQ_ARCH_0 /* V. Virtual itc timer */ +#define VIRQ_MCA_CMC VIRQ_ARCH_1 /* MCA cmc interrupt */ +#define VIRQ_MCA_CPE VIRQ_ARCH_2 /* MCA cpe interrupt */ /* Maximum number of virtual CPUs in multi-processor guests. */ /* WARNING: before changing this, check that shared_info fits on a page */ diff -r f78e499dd669 -r 05d227d81935 xen/include/xen/softirq.h --- a/xen/include/xen/softirq.h Tue Nov 14 14:59:37 2006 -0700 +++ b/xen/include/xen/softirq.h Wed Nov 15 12:02:09 2006 -0700 @@ -9,7 +9,13 @@ #define NMI_SOFTIRQ 4 #define PAGE_SCRUB_SOFTIRQ 5 #define TRACE_SOFTIRQ 6 +#ifdef __ia64__ +#define CMC_DISABLE_SOFTIRQ 7 +#define CMC_ENABLE_SOFTIRQ 8 +#define NR_SOFTIRQS 9 +#else /* __ia64__ */ #define NR_SOFTIRQS 7 +#endif /* __ia64__ */ #ifndef __ASSEMBLY__ diff -r f78e499dd669 -r 05d227d81935 linux-2.6-xen-sparse/include/asm-ia64/sal.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/linux-2.6-xen-sparse/include/asm-ia64/sal.h Wed Nov 15 12:02:09 2006 -0700 @@ -0,0 +1,904 @@ +#ifndef _ASM_IA64_SAL_H +#define _ASM_IA64_SAL_H + +/* + * System Abstraction Layer definitions. + * + * This is based on version 2.5 of the manual "IA-64 System + * Abstraction Layer". + * + * Copyright (C) 2001 Intel + * Copyright (C) 2002 Jenna Hall <jenna.s.hall@xxxxxxxxx> + * Copyright (C) 2001 Fred Lewis <frederick.v.lewis@xxxxxxxxx> + * Copyright (C) 1998, 1999, 2001, 2003 Hewlett-Packard Co + * David Mosberger-Tang <davidm@xxxxxxxxxx> + * Copyright (C) 1999 Srinivasa Prasad Thirumalachar <sprasad@xxxxxxxxxxxxxxxxxxxx> + * + * 02/01/04 J. Hall Updated Error Record Structures to conform to July 2001 + * revision of the SAL spec. + * 01/01/03 fvlewis Updated Error Record Structures to conform with Nov. 2000 + * revision of the SAL spec. + * 99/09/29 davidm Updated for SAL 2.6. + * 00/03/29 cfleck Updated SAL Error Logging info for processor (SAL 2.6) + * (plus examples of platform error info structures from smariset @ Intel) + */ + +#define IA64_SAL_PLATFORM_FEATURE_BUS_LOCK_BIT 0 +#define IA64_SAL_PLATFORM_FEATURE_IRQ_REDIR_HINT_BIT 1 +#define IA64_SAL_PLATFORM_FEATURE_IPI_REDIR_HINT_BIT 2 +#define IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT_BIT 3 + +#define IA64_SAL_PLATFORM_FEATURE_BUS_LOCK (1<<IA64_SAL_PLATFORM_FEATURE_BUS_LOCK_BIT) +#define IA64_SAL_PLATFORM_FEATURE_IRQ_REDIR_HINT (1<<IA64_SAL_PLATFORM_FEATURE_IRQ_REDIR_HINT_BIT) +#define IA64_SAL_PLATFORM_FEATURE_IPI_REDIR_HINT (1<<IA64_SAL_PLATFORM_FEATURE_IPI_REDIR_HINT_BIT) +#define IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT (1<<IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT_BIT) + +#ifndef __ASSEMBLY__ + +#include <linux/bcd.h> +#include <linux/spinlock.h> +#include <linux/efi.h> + +#include <asm/pal.h> +#include <asm/system.h> +#include <asm/fpu.h> +#ifdef CONFIG_XEN +#include <asm/xen/xencomm.h> +#endif + +extern spinlock_t sal_lock; + +/* SAL spec _requires_ eight args for each call. */ +#define __SAL_CALL(result,a0,a1,a2,a3,a4,a5,a6,a7) \ + result = (*ia64_sal)(a0,a1,a2,a3,a4,a5,a6,a7) + +# define SAL_CALL(result,args...) do { \ + unsigned long __ia64_sc_flags; \ + struct ia64_fpreg __ia64_sc_fr[6]; \ + ia64_save_scratch_fpregs(__ia64_sc_fr); \ + spin_lock_irqsave(&sal_lock, __ia64_sc_flags); \ + __SAL_CALL(result, args); \ + spin_unlock_irqrestore(&sal_lock, __ia64_sc_flags); \ + ia64_load_scratch_fpregs(__ia64_sc_fr); \ +} while (0) + +# define SAL_CALL_NOLOCK(result,args...) do { \ + unsigned long __ia64_scn_flags; \ + struct ia64_fpreg __ia64_scn_fr[6]; \ + ia64_save_scratch_fpregs(__ia64_scn_fr); \ + local_irq_save(__ia64_scn_flags); \ + __SAL_CALL(result, args); \ + local_irq_restore(__ia64_scn_flags); \ + ia64_load_scratch_fpregs(__ia64_scn_fr); \ +} while (0) + +# define SAL_CALL_REENTRANT(result,args...) do { \ + struct ia64_fpreg __ia64_scs_fr[6]; \ + ia64_save_scratch_fpregs(__ia64_scs_fr); \ + preempt_disable(); \ + __SAL_CALL(result, args); \ + preempt_enable(); \ + ia64_load_scratch_fpregs(__ia64_scs_fr); \ +} while (0) + +#define SAL_SET_VECTORS 0x01000000 +#define SAL_GET_STATE_INFO 0x01000001 +#define SAL_GET_STATE_INFO_SIZE 0x01000002 +#define SAL_CLEAR_STATE_INFO 0x01000003 +#define SAL_MC_RENDEZ 0x01000004 +#define SAL_MC_SET_PARAMS 0x01000005 +#define SAL_REGISTER_PHYSICAL_ADDR 0x01000006 + +#define SAL_CACHE_FLUSH 0x01000008 +#define SAL_CACHE_INIT 0x01000009 +#define SAL_PCI_CONFIG_READ 0x01000010 +#define SAL_PCI_CONFIG_WRITE 0x01000011 +#define SAL_FREQ_BASE 0x01000012 +#define SAL_PHYSICAL_ID_INFO 0x01000013 + +#define SAL_UPDATE_PAL 0x01000020 + +struct ia64_sal_retval { + /* + * A zero status value indicates call completed without error. + * A negative status value indicates reason of call failure. + * A positive status value indicates success but an + * informational value should be printed (e.g., "reboot for + * change to take effect"). + */ + s64 status; + u64 v0; + u64 v1; + u64 v2; +}; + +typedef struct ia64_sal_retval (*ia64_sal_handler) (u64, ...); + +enum { + SAL_FREQ_BASE_PLATFORM = 0, + SAL_FREQ_BASE_INTERVAL_TIMER = 1, + SAL_FREQ_BASE_REALTIME_CLOCK = 2 +}; + +/* + * The SAL system table is followed by a variable number of variable + * length descriptors. The structure of these descriptors follows + * below. + * The defininition follows SAL specs from July 2000 + */ +struct ia64_sal_systab { + u8 signature[4]; /* should be "SST_" */ + u32 size; /* size of this table in bytes */ + u8 sal_rev_minor; + u8 sal_rev_major; + u16 entry_count; /* # of entries in variable portion */ + u8 checksum; + u8 reserved1[7]; + u8 sal_a_rev_minor; + u8 sal_a_rev_major; + u8 sal_b_rev_minor; + u8 sal_b_rev_major; + /* oem_id & product_id: terminating NUL is missing if string is exactly 32 bytes long. */ + u8 oem_id[32]; + u8 product_id[32]; /* ASCII product id */ + u8 reserved2[8]; +}; + +enum sal_systab_entry_type { + SAL_DESC_ENTRY_POINT = 0, + SAL_DESC_MEMORY = 1, + SAL_DESC_PLATFORM_FEATURE = 2, + SAL_DESC_TR = 3, + SAL_DESC_PTC = 4, + SAL_DESC_AP_WAKEUP = 5 +}; + +/* + * Entry type: Size: + * 0 48 + * 1 32 + * 2 16 + * 3 32 + * 4 16 + * 5 16 + */ +#define SAL_DESC_SIZE(type) "\060\040\020\040\020\020"[(unsigned) type] + +typedef struct ia64_sal_desc_entry_point { + u8 type; + u8 reserved1[7]; + u64 pal_proc; + u64 sal_proc; + u64 gp; + u8 reserved2[16]; +}ia64_sal_desc_entry_point_t; + +typedef struct ia64_sal_desc_memory { + u8 type; + u8 used_by_sal; /* needs to be mapped for SAL? */ + u8 mem_attr; /* current memory attribute setting */ + u8 access_rights; /* access rights set up by SAL */ + u8 mem_attr_mask; /* mask of supported memory attributes */ + u8 reserved1; + u8 mem_type; /* memory type */ + u8 mem_usage; /* memory usage */ + u64 addr; /* physical address of memory */ + u32 length; /* length (multiple of 4KB pages) */ + u32 reserved2; + u8 oem_reserved[8]; +} ia64_sal_desc_memory_t; + +typedef struct ia64_sal_desc_platform_feature { + u8 type; + u8 feature_mask; + u8 reserved1[14]; +} ia64_sal_desc_platform_feature_t; + +typedef struct ia64_sal_desc_tr { + u8 type; + u8 tr_type; /* 0 == instruction, 1 == data */ + u8 regnum; /* translation register number */ + u8 reserved1[5]; + u64 addr; /* virtual address of area covered */ + u64 page_size; /* encoded page size */ + u8 reserved2[8]; +} ia64_sal_desc_tr_t; + +typedef struct ia64_sal_desc_ptc { + u8 type; + u8 reserved1[3]; + u32 num_domains; /* # of coherence domains */ + u64 domain_info; /* physical address of domain info table */ +} ia64_sal_desc_ptc_t; + +typedef struct ia64_sal_ptc_domain_info { + u64 proc_count; /* number of processors in domain */ + u64 proc_list; /* physical address of LID array */ +} ia64_sal_ptc_domain_info_t; + +typedef struct ia64_sal_ptc_domain_proc_entry { + u64 id : 8; /* id of processor */ + u64 eid : 8; /* eid of processor */ +} ia64_sal_ptc_domain_proc_entry_t; + + +#define IA64_SAL_AP_EXTERNAL_INT 0 + +typedef struct ia64_sal_desc_ap_wakeup { + u8 type; + u8 mechanism; /* 0 == external interrupt */ + u8 reserved1[6]; + u64 vector; /* interrupt vector in range 0x10-0xff */ +} ia64_sal_desc_ap_wakeup_t ; + +extern ia64_sal_handler ia64_sal; +extern struct ia64_sal_desc_ptc *ia64_ptc_domain_info; + +extern unsigned short sal_revision; /* supported SAL spec revision */ +extern unsigned short sal_version; /* SAL version; OEM dependent */ +#define SAL_VERSION_CODE(major, minor) ((BIN2BCD(major) << 8) | BIN2BCD(minor)) + +extern const char *ia64_sal_strerror (long status); +extern void ia64_sal_init (struct ia64_sal_systab *sal_systab); + +/* SAL information type encodings */ +enum { + SAL_INFO_TYPE_MCA = 0, /* Machine check abort information */ + SAL_INFO_TYPE_INIT = 1, /* Init information */ + SAL_INFO_TYPE_CMC = 2, /* Corrected machine check information */ + SAL_INFO_TYPE_CPE = 3 /* Corrected platform error information */ +}; + +/* Encodings for machine check parameter types */ +enum { + SAL_MC_PARAM_RENDEZ_INT = 1, /* Rendezvous interrupt */ + SAL_MC_PARAM_RENDEZ_WAKEUP = 2, /* Wakeup */ + SAL_MC_PARAM_CPE_INT = 3 /* Corrected Platform Error Int */ +}; + +/* Encodings for rendezvous mechanisms */ +enum { + SAL_MC_PARAM_MECHANISM_INT = 1, /* Use interrupt */ + SAL_MC_PARAM_MECHANISM_MEM = 2 /* Use memory synchronization variable*/ +}; + +/* Encodings for vectors which can be registered by the OS with SAL */ +enum { + SAL_VECTOR_OS_MCA = 0, + SAL_VECTOR_OS_INIT = 1, + SAL_VECTOR_OS_BOOT_RENDEZ = 2 +}; + +/* Encodings for mca_opt parameter sent to SAL_MC_SET_PARAMS */ +#define SAL_MC_PARAM_RZ_ALWAYS 0x1 +#define SAL_MC_PARAM_BINIT_ESCALATE 0x10 + +/* + * Definition of the SAL Error Log from the SAL spec + */ + +/* SAL Error Record Section GUID Definitions */ +#define SAL_PROC_DEV_ERR_SECT_GUID \ + EFI_GUID(0xe429faf1, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81) +#define SAL_PLAT_MEM_DEV_ERR_SECT_GUID \ + EFI_GUID(0xe429faf2, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81) +#define SAL_PLAT_SEL_DEV_ERR_SECT_GUID \ + EFI_GUID(0xe429faf3, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81) +#define SAL_PLAT_PCI_BUS_ERR_SECT_GUID \ + EFI_GUID(0xe429faf4, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81) +#define SAL_PLAT_SMBIOS_DEV_ERR_SECT_GUID \ + EFI_GUID(0xe429faf5, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81) +#define SAL_PLAT_PCI_COMP_ERR_SECT_GUID \ + EFI_GUID(0xe429faf6, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81) +#define SAL_PLAT_SPECIFIC_ERR_SECT_GUID \ + EFI_GUID(0xe429faf7, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81) +#define SAL_PLAT_HOST_CTLR_ERR_SECT_GUID \ + EFI_GUID(0xe429faf8, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81) +#define SAL_PLAT_BUS_ERR_SECT_GUID \ + EFI_GUID(0xe429faf9, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81) + +#define MAX_CACHE_ERRORS 6 +#define MAX_TLB_ERRORS 6 +#define MAX_BUS_ERRORS 1 + +/* Definition of version according to SAL spec for logging purposes */ +typedef struct sal_log_revision { + u8 minor; /* BCD (0..99) */ + u8 major; /* BCD (0..99) */ +} sal_log_revision_t; + +/* Definition of timestamp according to SAL spec for logging purposes */ +typedef struct sal_log_timestamp { + u8 slh_second; /* Second (0..59) */ + u8 slh_minute; /* Minute (0..59) */ + u8 slh_hour; /* Hour (0..23) */ + u8 slh_reserved; + u8 slh_day; /* Day (1..31) */ + u8 slh_month; /* Month (1..12) */ + u8 slh_year; /* Year (00..99) */ + u8 slh_century; /* Century (19, 20, 21, ...) */ +} sal_log_timestamp_t; + +/* Definition of log record header structures */ +typedef struct sal_log_record_header { + u64 id; /* Unique monotonically increasing ID */ + sal_log_revision_t revision; /* Major and Minor revision of header */ + u8 severity; /* Error Severity */ + u8 validation_bits; /* 0: platform_guid, 1: !timestamp */ + u32 len; /* Length of this error log in bytes */ + sal_log_timestamp_t timestamp; /* Timestamp */ + efi_guid_t platform_guid; /* Unique OEM Platform ID */ +} sal_log_record_header_t; + +#define sal_log_severity_recoverable 0 +#define sal_log_severity_fatal 1 +#define sal_log_severity_corrected 2 + +/* Definition of log section header structures */ +typedef struct sal_log_sec_header { + efi_guid_t guid; /* Unique Section ID */ + sal_log_revision_t revision; /* Major and Minor revision of Section */ + u16 reserved; + u32 len; /* Section length */ +} sal_log_section_hdr_t; + +typedef struct sal_log_mod_error_info { + struct { + u64 check_info : 1, + requestor_identifier : 1, + responder_identifier : 1, + target_identifier : 1, + precise_ip : 1, + reserved : 59; + } valid; + u64 check_info; + u64 requestor_identifier; + u64 responder_identifier; + u64 target_identifier; + u64 precise_ip; +} sal_log_mod_error_info_t; + +typedef struct sal_processor_static_info { + struct { + u64 minstate : 1, + br : 1, + cr : 1, + ar : 1, + rr : 1, + fr : 1, + reserved : 58; + } valid; + pal_min_state_area_t min_state_area; + u64 br[8]; + u64 cr[128]; + u64 ar[128]; + u64 rr[8]; + struct ia64_fpreg __attribute__ ((packed)) fr[128]; +} sal_processor_static_info_t; + +struct sal_cpuid_info { + u64 regs[5]; + u64 reserved; +}; + +typedef struct sal_log_processor_info { + sal_log_section_hdr_t header; + struct { + u64 proc_error_map : 1, + proc_state_param : 1, + proc_cr_lid : 1, + psi_static_struct : 1, + num_cache_check : 4, + num_tlb_check : 4, + num_bus_check : 4, + num_reg_file_check : 4, + num_ms_check : 4, + cpuid_info : 1, + reserved1 : 39; + } valid; + u64 proc_error_map; + u64 proc_state_parameter; + u64 proc_cr_lid; + /* + * The rest of this structure consists of variable-length arrays, which can't be + * expressed in C. + */ + sal_log_mod_error_info_t info[0]; + /* + * This is what the rest looked like if C supported variable-length arrays: + * + * sal_log_mod_error_info_t cache_check_info[.valid.num_cache_check]; + * sal_log_mod_error_info_t tlb_check_info[.valid.num_tlb_check]; + * sal_log_mod_error_info_t bus_check_info[.valid.num_bus_check]; + * sal_log_mod_error_info_t reg_file_check_info[.valid.num_reg_file_check]; + * sal_log_mod_error_info_t ms_check_info[.valid.num_ms_check]; + * struct sal_cpuid_info cpuid_info; + * sal_processor_static_info_t processor_static_info; + */ +} sal_log_processor_info_t; + +/* Given a sal_log_processor_info_t pointer, return a pointer to the processor_static_info: */ +#define SAL_LPI_PSI_INFO(l) \ +({ sal_log_processor_info_t *_l = (l); \ + ((sal_processor_static_info_t *) \ + ((char *) _l->info + ((_l->valid.num_cache_check + _l->valid.num_tlb_check \ + + _l->valid.num_bus_check + _l->valid.num_reg_file_check \ + + _l->valid.num_ms_check) * sizeof(sal_log_mod_error_info_t) \ + + sizeof(struct sal_cpuid_info)))); \ +}) + +/* platform error log structures */ + +typedef struct sal_log_mem_dev_err_info { + sal_log_section_hdr_t header; + struct { + u64 error_status : 1, + physical_addr : 1, + addr_mask : 1, + node : 1, + card : 1, + module : 1, + bank : 1, + device : 1, + row : 1, + column : 1, + bit_position : 1, + requestor_id : 1, + responder_id : 1, + target_id : 1, + bus_spec_data : 1, + oem_id : 1, + oem_data : 1, + reserved : 47; + } valid; + u64 error_status; + u64 physical_addr; + u64 addr_mask; + u16 node; + u16 card; + u16 module; + u16 bank; + u16 device; + u16 row; + u16 column; + u16 bit_position; + u64 requestor_id; + u64 responder_id; + u64 target_id; + u64 bus_spec_data; + u8 oem_id[16]; + u8 oem_data[1]; /* Variable length data */ +} sal_log_mem_dev_err_info_t; + +typedef struct sal_log_sel_dev_err_info { + sal_log_section_hdr_t header; + struct { + u64 record_id : 1, + record_type : 1, + generator_id : 1, + evm_rev : 1, + sensor_type : 1, + sensor_num : 1, + event_dir : 1, + event_data1 : 1, + event_data2 : 1, + event_data3 : 1, + reserved : 54; + } valid; + u16 record_id; + u8 record_type; + u8 timestamp[4]; + u16 generator_id; + u8 evm_rev; + u8 sensor_type; + u8 sensor_num; + u8 event_dir; + u8 event_data1; + u8 event_data2; + u8 event_data3; +} sal_log_sel_dev_err_info_t; + +typedef struct sal_log_pci_bus_err_info { + sal_log_section_hdr_t header; + struct { + u64 err_status : 1, + err_type : 1, + bus_id : 1, + bus_address : 1, + bus_data : 1, + bus_cmd : 1, + requestor_id : 1, + responder_id : 1, + target_id : 1, + oem_data : 1, + reserved : 54; + } valid; + u64 err_status; + u16 err_type; + u16 bus_id; + u32 reserved; + u64 bus_address; + u64 bus_data; + u64 bus_cmd; + u64 requestor_id; + u64 responder_id; + u64 target_id; + u8 oem_data[1]; /* Variable length data */ +} sal_log_pci_bus_err_info_t; + +typedef struct sal_log_smbios_dev_err_info { + sal_log_section_hdr_t header; + struct { + u64 event_type : 1, + length : 1, + time_stamp : 1, + data : 1, + reserved1 : 60; + } valid; + u8 event_type; + u8 length; + u8 time_stamp[6]; + u8 data[1]; /* data of variable length, length == slsmb_length */ +} sal_log_smbios_dev_err_info_t; + +typedef struct sal_log_pci_comp_err_info { + sal_log_section_hdr_t header; + struct { + u64 err_status : 1, + comp_info : 1, + num_mem_regs : 1, + num_io_regs : 1, + reg_data_pairs : 1, + oem_data : 1, + reserved : 58; + } valid; + u64 err_status; + struct { + u16 vendor_id; + u16 device_id; + u8 class_code[3]; + u8 func_num; + u8 dev_num; + u8 bus_num; + u8 seg_num; + u8 reserved[5]; + } comp_info; + u32 num_mem_regs; + u32 num_io_regs; + u64 reg_data_pairs[1]; + /* + * array of address/data register pairs is num_mem_regs + num_io_regs elements + * long. Each array element consists of a u64 address followed by a u64 data + * value. The oem_data array immediately follows the reg_data_pairs array + */ + u8 oem_data[1]; /* Variable length data */ +} sal_log_pci_comp_err_info_t; + +typedef struct sal_log_plat_specific_err_info { + sal_log_section_hdr_t header; + struct { + u64 err_status : 1, + guid : 1, + oem_data : 1, + reserved : 61; + } valid; + u64 err_status; + efi_guid_t guid; + u8 oem_data[1]; /* platform specific variable length data */ +} sal_log_plat_specific_err_info_t; + +typedef struct sal_log_host_ctlr_err_info { + sal_log_section_hdr_t header; + struct { + u64 err_status : 1, + requestor_id : 1, + responder_id : 1, + target_id : 1, + bus_spec_data : 1, + oem_data : 1, + reserved : 58; + } valid; + u64 err_status; + u64 requestor_id; + u64 responder_id; + u64 target_id; + u64 bus_spec_data; + u8 oem_data[1]; /* Variable length OEM data */ +} sal_log_host_ctlr_err_info_t; + +typedef struct sal_log_plat_bus_err_info { + sal_log_section_hdr_t header; + struct { + u64 err_status : 1, + requestor_id : 1, + responder_id : 1, + target_id : 1, + bus_spec_data : 1, + oem_data : 1, + reserved : 58; + } valid; + u64 err_status; + u64 requestor_id; + u64 responder_id; + u64 target_id; + u64 bus_spec_data; + u8 oem_data[1]; /* Variable length OEM data */ +} sal_log_plat_bus_err_info_t; + +/* Overall platform error section structure */ +typedef union sal_log_platform_err_info { + sal_log_mem_dev_err_info_t mem_dev_err; + sal_log_sel_dev_err_info_t sel_dev_err; + sal_log_pci_bus_err_info_t pci_bus_err; + sal_log_smbios_dev_err_info_t smbios_dev_err; + sal_log_pci_comp_err_info_t pci_comp_err; + sal_log_plat_specific_err_info_t plat_specific_err; + sal_log_host_ctlr_err_info_t host_ctlr_err; + sal_log_plat_bus_err_info_t plat_bus_err; +} sal_log_platform_err_info_t; + +/* SAL log over-all, multi-section error record structure (processor+platform) */ +typedef struct err_rec { + sal_log_record_header_t sal_elog_header; + sal_log_processor_info_t proc_err; + sal_log_platform_err_info_t plat_err; + u8 oem_data_pad[1024]; +} ia64_err_rec_t; + +/* + * Now define a couple of inline functions for improved type checking + * and convenience. + */ +static inline long +ia64_sal_freq_base (unsigned long which, unsigned long *ticks_per_second, + unsigned long *drift_info) +{ + struct ia64_sal_retval isrv; + + SAL_CALL(isrv, SAL_FREQ_BASE, which, 0, 0, 0, 0, 0, 0); + *ticks_per_second = isrv.v0; + *drift_info = isrv.v1; + return isrv.status; +} + +extern s64 ia64_sal_cache_flush (u64 cache_type); + +/* Initialize all the processor and platform level instruction and data caches */ +static inline s64 +ia64_sal_cache_init (void) +{ + struct ia64_sal_retval isrv; + SAL_CALL(isrv, SAL_CACHE_INIT, 0, 0, 0, 0, 0, 0, 0); + return isrv.status; +} + +/* + * Clear the processor and platform information logged by SAL with respect to the machine + * state at the time of MCA's, INITs, CMCs, or CPEs. + */ +static inline s64 +ia64_sal_clear_state_info (u64 sal_info_type) +{ + struct ia64_sal_retval isrv; + SAL_CALL_REENTRANT(isrv, SAL_CLEAR_STATE_INFO, sal_info_type, 0, + 0, 0, 0, 0, 0); + return isrv.status; +} + + +/* Get the processor and platform information logged by SAL with respect to the machine + * state at the time of the MCAs, INITs, CMCs, or CPEs. + */ +#ifdef CONFIG_XEN +static inline u64 ia64_sal_get_state_info_size (u64 sal_info_type); +#endif + +static inline u64 +ia64_sal_get_state_info (u64 sal_info_type, u64 *sal_info) +{ + struct ia64_sal_retval isrv; +#ifdef CONFIG_XEN + if (is_running_on_xen()) { + struct xencomm_handle *desc; + + if (xencomm_create(sal_info, + ia64_sal_get_state_info_size(sal_info_type), + &desc, GFP_KERNEL)) + return 0; + + SAL_CALL_REENTRANT(isrv, SAL_GET_STATE_INFO, sal_info_type, 0, + desc, 0, 0, 0, 0); + xencomm_free(desc); + } else +#endif + SAL_CALL_REENTRANT(isrv, SAL_GET_STATE_INFO, sal_info_type, 0, + sal_info, 0, 0, 0, 0); + if (isrv.status) + return 0; + + return isrv.v0; +} + +/* + * Get the maximum size of the information logged by SAL with respect to the machine state + * at the time of MCAs, INITs, CMCs, or CPEs. + */ +static inline u64 +ia64_sal_get_state_info_size (u64 sal_info_type) +{ + struct ia64_sal_retval isrv; + SAL_CALL_REENTRANT(isrv, SAL_GET_STATE_INFO_SIZE, sal_info_type, 0, + 0, 0, 0, 0, 0); + if (isrv.status) + return 0; + return isrv.v0; +} + +/* + * Causes the processor to go into a spin loop within SAL where SAL awaits a wakeup from + * the monarch processor. Must not lock, because it will not return on any cpu until the + * monarch processor sends a wake up. + */ +static inline s64 +ia64_sal_mc_rendez (void) +{ + struct ia64_sal_retval isrv; + SAL_CALL_NOLOCK(isrv, SAL_MC_RENDEZ, 0, 0, 0, 0, 0, 0, 0); + return isrv.status; +} + +/* + * Allow the OS to specify the interrupt number to be used by SAL to interrupt OS during + * the machine check rendezvous sequence as well as the mechanism to wake up the + * non-monarch processor at the end of machine check processing. + * Returns the complete ia64_sal_retval because some calls return more than just a status + * value. + */ +static inline struct ia64_sal_retval +ia64_sal_mc_set_params (u64 param_type, u64 i_or_m, u64 i_or_m_val, u64 timeout, u64 rz_always) +{ + struct ia64_sal_retval isrv; + SAL_CALL(isrv, SAL_MC_SET_PARAMS, param_type, i_or_m, i_or_m_val, + timeout, rz_always, 0, 0); + return isrv; +} + +/* Read from PCI configuration space */ +static inline s64 +ia64_sal_pci_config_read (u64 pci_config_addr, int type, u64 size, u64 *value) +{ + struct ia64_sal_retval isrv; + SAL_CALL(isrv, SAL_PCI_CONFIG_READ, pci_config_addr, size, type, 0, 0, 0, 0); + if (value) + *value = isrv.v0; + return isrv.status; +} + +/* Write to PCI configuration space */ +static inline s64 +ia64_sal_pci_config_write (u64 pci_config_addr, int type, u64 size, u64 value) +{ + struct ia64_sal_retval isrv; + SAL_CALL(isrv, SAL_PCI_CONFIG_WRITE, pci_config_addr, size, value, + type, 0, 0, 0); + return isrv.status; +} + +/* + * Register physical addresses of locations needed by SAL when SAL procedures are invoked + * in virtual mode. + */ +static inline s64 +ia64_sal_register_physical_addr (u64 phys_entry, u64 phys_addr) +{ + struct ia64_sal_retval isrv; + SAL_CALL(isrv, SAL_REGISTER_PHYSICAL_ADDR, phys_entry, phys_addr, + 0, 0, 0, 0, 0); + return isrv.status; +} + +/* + * Register software dependent code locations within SAL. These locations are handlers or + * entry points where SAL will pass control for the specified event. These event handlers + * are for the bott rendezvous, MCAs and INIT scenarios. + */ +static inline s64 +ia64_sal_set_vectors (u64 vector_type, + u64 handler_addr1, u64 gp1, u64 handler_len1, + u64 handler_addr2, u64 gp2, u64 handler_len2) +{ + struct ia64_sal_retval isrv; + SAL_CALL(isrv, SAL_SET_VECTORS, vector_type, + handler_addr1, gp1, handler_len1, + handler_addr2, gp2, handler_len2); + + return isrv.status; +} + +/* Update the contents of PAL block in the non-volatile storage device */ +static inline s64 +ia64_sal_update_pal (u64 param_buf, u64 scratch_buf, u64 scratch_buf_size, + u64 *error_code, u64 *scratch_buf_size_needed) +{ + struct ia64_sal_retval isrv; + SAL_CALL(isrv, SAL_UPDATE_PAL, param_buf, scratch_buf, scratch_buf_size, + 0, 0, 0, 0); + if (error_code) + *error_code = isrv.v0; + if (scratch_buf_size_needed) + *scratch_buf_size_needed = isrv.v1; + return isrv.status; +} + +/* Get physical processor die mapping in the platform. */ +static inline s64 +ia64_sal_physical_id_info(u16 *splid) +{ + struct ia64_sal_retval isrv; + SAL_CALL(isrv, SAL_PHYSICAL_ID_INFO, 0, 0, 0, 0, 0, 0, 0); + if (splid) + *splid = isrv.v0; + return isrv.status; +} + +extern unsigned long sal_platform_features; + +extern int (*salinfo_platform_oemdata)(const u8 *, u8 **, u64 *); + +struct sal_ret_values { + long r8; long r9; long r10; long r11; +}; + +#define IA64_SAL_OEMFUNC_MIN 0x02000000 +#define IA64_SAL_OEMFUNC_MAX 0x03ffffff + +extern int ia64_sal_oemcall(struct ia64_sal_retval *, u64, u64, u64, u64, u64, + u64, u64, u64); +extern int ia64_sal_oemcall_nolock(struct ia64_sal_retval *, u64, u64, u64, + u64, u64, u64, u64, u64); +extern int ia64_sal_oemcall_reentrant(struct ia64_sal_retval *, u64, u64, u64, + u64, u64, u64, u64, u64); +#ifdef CONFIG_HOTPLUG_CPU +/* + * System Abstraction Layer Specification + * Section 3.2.5.1: OS_BOOT_RENDEZ to SAL return State. + * Note: region regs are stored first in head.S _start. Hence they must + * stay up front. + */ +struct sal_to_os_boot { + u64 rr[8]; /* Region Registers */ + u64 br[6]; /* br0: return addr into SAL boot rendez routine */ + u64 gr1; /* SAL:GP */ + u64 gr12; /* SAL:SP */ + u64 gr13; /* SAL: Task Pointer */ + u64 fpsr; + u64 pfs; + u64 rnat; + u64 unat; + u64 bspstore; + u64 dcr; /* Default Control Register */ + u64 iva; + u64 pta; + u64 itv; + u64 pmv; + u64 cmcv; + u64 lrr[2]; + u64 gr[4]; + u64 pr; /* Predicate registers */ + u64 lc; /* Loop Count */ + struct ia64_fpreg fp[20]; +}; + +/* + * Global array allocated for NR_CPUS at boot time + */ +extern struct sal_to_os_boot sal_boot_rendez_state[NR_CPUS]; + +extern void ia64_jump_to_sal(struct sal_to_os_boot *); +#endif + +extern void ia64_sal_handler_init(void *entry_point, void *gpval); + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_IA64_SAL_H */ diff -r f78e499dd669 -r 05d227d81935 xen/include/asm-ia64/xenmca.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/include/asm-ia64/xenmca.h Wed Nov 15 12:02:09 2006 -0700 @@ -0,0 +1,34 @@ +/* + * File: xenmca.h + * Purpose: Machine check handling specific defines for Xen + * + * Copyright (C) 2006 FUJITSU LTD. (kaz@xxxxxxxxxxxxxx) + */ + +#ifndef _ASM_IA64_XENMCA_H +#define _ASM_IA64_XENMCA_H + +#ifndef __ASSEMBLER__ +#include <linux/list.h> +#include <asm/sal.h> + +typedef struct sal_queue_entry_t { + int cpuid; + int sal_info_type; + unsigned int vector; + unsigned int virq; + unsigned int length; + struct list_head list; +} sal_queue_entry_t; + +extern struct list_head sal_queue[]; + +struct ia64_mca_tlb_info { + u64 cr_lid; + u64 percpu_paddr; +}; + +extern struct ia64_mca_tlb_info ia64_mca_tlb_list[]; +#endif /* __ASSEMBLER__ */ + +#endif /* _ASM_IA64_XENMCA_H */ _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |