X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fia64%2Fkernel%2Fmca.c;h=ca47dbb4561dfc14ca0c0071097bf028a384d2e7;hb=987b0145d94eecf292d8b301228356f44611ab7c;hp=6a0880639bc9396208c30a9f9ccd4b3ae93aa835;hpb=f7ed79d23a47594e7834d66a8f14449796d4f3e6;p=linux-2.6.git diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c index 6a0880639..ca47dbb45 100644 --- a/arch/ia64/kernel/mca.c +++ b/arch/ia64/kernel/mca.c @@ -69,7 +69,6 @@ #include #include #include -#include #include #include @@ -84,7 +83,6 @@ #include #include -#include "mca_drv.h" #include "entry.h" #if defined(IA64_MCA_DEBUG_INFO) @@ -135,7 +133,7 @@ static int cpe_poll_enabled = 1; extern void salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe); -static int mca_init __initdata; +static int mca_init; static void inline @@ -186,7 +184,7 @@ static ia64_state_log_t ia64_state_log[IA64_MAX_LOG_TYPES]; * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE}) * Outputs : None */ -static void __init +static void ia64_log_init(int sal_info_type) { u64 max_size = 0; @@ -222,7 +220,7 @@ ia64_log_get(int sal_info_type, u8 **buffer, int irq_safe) { sal_log_record_header_t *log_buffer; u64 total_len = 0; - int s; + unsigned long s; IA64_LOG_LOCK(sal_info_type); @@ -284,53 +282,13 @@ ia64_mca_log_sal_error_record(int sal_info_type) } /* - * search_mca_table - * See if the MCA surfaced in an instruction range - * that has been tagged as recoverable. - * - * Inputs - * first First address range to check - * last Last address range to check - * ip Instruction pointer, address we are looking for - * - * Return value: - * 1 on Success (in the table)/ 0 on Failure (not in the table) + * platform dependent error handling */ -int -search_mca_table (const struct mca_table_entry *first, - const struct mca_table_entry *last, - unsigned long ip) -{ - const struct mca_table_entry *curr; - u64 curr_start, curr_end; - - curr = first; - while (curr <= last) { - curr_start = (u64) &curr->start_addr + curr->start_addr; - curr_end = (u64) &curr->end_addr + curr->end_addr; - - if ((ip >= curr_start) && (ip <= curr_end)) { - return 1; - } - curr++; - } - return 0; -} - -/* Given an address, look for it in the mca tables. */ -int mca_recover_range(unsigned long addr) -{ - extern struct mca_table_entry __start___mca_table[]; - extern struct mca_table_entry __stop___mca_table[]; - - return search_mca_table(__start___mca_table, __stop___mca_table-1, addr); -} -EXPORT_SYMBOL_GPL(mca_recover_range); +#ifndef PLATFORM_MCA_HANDLERS #ifdef CONFIG_ACPI int cpe_vector = -1; -int ia64_cpe_irq = -1; static irqreturn_t ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs) @@ -401,7 +359,7 @@ ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs) * Outputs * None */ -static void __init +static void ia64_mca_register_cpev (int cpev) { /* Register the CPE interrupt vector with SAL */ @@ -419,6 +377,8 @@ ia64_mca_register_cpev (int cpev) } #endif /* CONFIG_ACPI */ +#endif /* PLATFORM_MCA_HANDLERS */ + /* * ia64_mca_cmc_vector_setup * @@ -432,7 +392,7 @@ ia64_mca_register_cpev (int cpev) * Outputs * None */ -void __cpuinit +void ia64_mca_cmc_vector_setup (void) { cmcv_reg_t cmcv; @@ -581,12 +541,10 @@ ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *regs) { unsigned long flags; int cpu = smp_processor_id(); - struct ia64_mca_notify_die nd = - { .sos = NULL, .monarch_cpu = &monarch_cpu }; /* Mask all interrupts */ local_irq_save(flags); - if (notify_die(DIE_MCA_RENDZVOUS_ENTER, "MCA", regs, (long)&nd, 0, 0) + if (notify_die(DIE_MCA_RENDZVOUS_ENTER, "MCA", regs, 0, 0, 0) == NOTIFY_STOP) ia64_mca_spin(__FUNCTION__); @@ -596,7 +554,7 @@ ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *regs) */ ia64_sal_mc_rendez(); - if (notify_die(DIE_MCA_RENDZVOUS_PROCESS, "MCA", regs, (long)&nd, 0, 0) + if (notify_die(DIE_MCA_RENDZVOUS_PROCESS, "MCA", regs, 0, 0, 0) == NOTIFY_STOP) ia64_mca_spin(__FUNCTION__); @@ -604,7 +562,7 @@ ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *regs) while (monarch_cpu != -1) cpu_relax(); /* spin until monarch leaves */ - if (notify_die(DIE_MCA_RENDZVOUS_LEAVE, "MCA", regs, (long)&nd, 0, 0) + if (notify_die(DIE_MCA_RENDZVOUS_LEAVE, "MCA", regs, 0, 0, 0) == NOTIFY_STOP) ia64_mca_spin(__FUNCTION__); @@ -672,32 +630,6 @@ copy_reg(const u64 *fr, u64 fnat, u64 *tr, u64 *tnat) *tnat |= (nat << tslot); } -/* Change the comm field on the MCA/INT task to include the pid that - * was interrupted, it makes for easier debugging. If that pid was 0 - * (swapper or nested MCA/INIT) then use the start of the previous comm - * field suffixed with its cpu. - */ - -static void -ia64_mca_modify_comm(const task_t *previous_current) -{ - char *p, comm[sizeof(current->comm)]; - if (previous_current->pid) - snprintf(comm, sizeof(comm), "%s %d", - current->comm, previous_current->pid); - else { - int l; - if ((p = strchr(previous_current->comm, ' '))) - l = p - previous_current->comm; - else - l = strlen(previous_current->comm); - snprintf(comm, sizeof(comm), "%s %*s %d", - current->comm, l, previous_current->comm, - task_thread_info(previous_current)->cpu); - } - memcpy(current->comm, comm, sizeof(current->comm)); -} - /* On entry to this routine, we are running on the per cpu stack, see * mca_asm.h. The original stack has not been touched by this event. Some of * the original stack's registers will be in the RBS on this stack. This stack @@ -716,7 +648,7 @@ ia64_mca_modify_original_stack(struct pt_regs *regs, struct ia64_sal_os_state *sos, const char *type) { - char *p; + char *p, comm[sizeof(current->comm)]; ia64_va va; extern char ia64_leave_kernel[]; /* Need asm address, not function descriptor */ const pal_min_state_area_t *ms = sos->pal_min_state; @@ -789,43 +721,54 @@ ia64_mca_modify_original_stack(struct pt_regs *regs, /* Verify the previous stack state before we change it */ if (user_mode(regs)) { msg = "occurred in user space"; - /* previous_current is guaranteed to be valid when the task was - * in user space, so ... - */ - ia64_mca_modify_comm(previous_current); goto no_mod; } - - if (!mca_recover_range(ms->pmsa_iip)) { - if (r13 != sos->prev_IA64_KR_CURRENT) { - msg = "inconsistent previous current and r13"; - goto no_mod; - } - if ((r12 - r13) >= KERNEL_STACK_SIZE) { - msg = "inconsistent r12 and r13"; - goto no_mod; - } - if ((ar_bspstore - r13) >= KERNEL_STACK_SIZE) { - msg = "inconsistent ar.bspstore and r13"; - goto no_mod; - } - va.p = old_bspstore; - if (va.f.reg < 5) { - msg = "old_bspstore is in the wrong region"; - goto no_mod; - } - if ((ar_bsp - r13) >= KERNEL_STACK_SIZE) { - msg = "inconsistent ar.bsp and r13"; - goto no_mod; - } - size += (ia64_rse_skip_regs(old_bspstore, slots) - old_bspstore) * 8; - if (ar_bspstore + size > r12) { - msg = "no room for blocked state"; - goto no_mod; - } + if (r13 != sos->prev_IA64_KR_CURRENT) { + msg = "inconsistent previous current and r13"; + goto no_mod; + } + if ((r12 - r13) >= KERNEL_STACK_SIZE) { + msg = "inconsistent r12 and r13"; + goto no_mod; + } + if ((ar_bspstore - r13) >= KERNEL_STACK_SIZE) { + msg = "inconsistent ar.bspstore and r13"; + goto no_mod; + } + va.p = old_bspstore; + if (va.f.reg < 5) { + msg = "old_bspstore is in the wrong region"; + goto no_mod; + } + if ((ar_bsp - r13) >= KERNEL_STACK_SIZE) { + msg = "inconsistent ar.bsp and r13"; + goto no_mod; + } + size += (ia64_rse_skip_regs(old_bspstore, slots) - old_bspstore) * 8; + if (ar_bspstore + size > r12) { + msg = "no room for blocked state"; + goto no_mod; } - ia64_mca_modify_comm(previous_current); + /* Change the comm field on the MCA/INT task to include the pid that + * was interrupted, it makes for easier debugging. If that pid was 0 + * (swapper or nested MCA/INIT) then use the start of the previous comm + * field suffixed with its cpu. + */ + if (previous_current->pid) + snprintf(comm, sizeof(comm), "%s %d", + current->comm, previous_current->pid); + else { + int l; + if ((p = strchr(previous_current->comm, ' '))) + l = p - previous_current->comm; + else + l = strlen(previous_current->comm); + snprintf(comm, sizeof(comm), "%s %*s %d", + current->comm, l, previous_current->comm, + task_thread_info(previous_current)->cpu); + } + memcpy(current->comm, comm, sizeof(current->comm)); /* Make the original task look blocked. First stack a struct pt_regs, * describing the state at the time of interrupt. mca_asm.S built a @@ -963,9 +906,9 @@ no_mod: */ static void -ia64_wait_for_slaves(int monarch, const char *type) +ia64_wait_for_slaves(int monarch) { - int c, wait = 0, missing = 0; + int c, wait = 0; for_each_online_cpu(c) { if (c == monarch) continue; @@ -976,32 +919,15 @@ ia64_wait_for_slaves(int monarch, const char *type) } } if (!wait) - goto all_in; + return; for_each_online_cpu(c) { if (c == monarch) continue; if (ia64_mc_info.imi_rendez_checkin[c] == IA64_MCA_RENDEZ_CHECKIN_NOTDONE) { udelay(5*1000000); /* wait 5 seconds for slaves (arbitrary) */ - if (ia64_mc_info.imi_rendez_checkin[c] == IA64_MCA_RENDEZ_CHECKIN_NOTDONE) - missing = 1; break; } } - if (!missing) - goto all_in; - printk(KERN_INFO "OS %s slave did not rendezvous on cpu", type); - for_each_online_cpu(c) { - if (c == monarch) - continue; - if (ia64_mc_info.imi_rendez_checkin[c] == IA64_MCA_RENDEZ_CHECKIN_NOTDONE) - printk(" %d", c); - } - printk("\n"); - return; - -all_in: - printk(KERN_INFO "All OS %s slaves have reached rendezvous\n", type); - return; } /* @@ -1025,20 +951,14 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw, &sos->proc_state_param; int recover, cpu = smp_processor_id(); task_t *previous_current; - struct ia64_mca_notify_die nd = - { .sos = sos, .monarch_cpu = &monarch_cpu }; oops_in_progress = 1; /* FIXME: make printk NMI/MCA/INIT safe */ - console_loglevel = 15; /* make sure printks make it to console */ - printk(KERN_INFO "Entered OS MCA handler. PSP=%lx cpu=%d monarch=%ld\n", - sos->proc_state_param, cpu, sos->monarch); - previous_current = ia64_mca_modify_original_stack(regs, sw, sos, "MCA"); monarch_cpu = cpu; - if (notify_die(DIE_MCA_MONARCH_ENTER, "MCA", regs, (long)&nd, 0, 0) + if (notify_die(DIE_MCA_MONARCH_ENTER, "MCA", regs, 0, 0, 0) == NOTIFY_STOP) ia64_mca_spin(__FUNCTION__); - ia64_wait_for_slaves(cpu, "MCA"); + ia64_wait_for_slaves(cpu); /* Wakeup all the processors which are spinning in the rendezvous loop. * They will leave SAL, then spin in the OS with interrupts disabled @@ -1047,7 +967,7 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw, * spinning in SAL does not work. */ ia64_mca_wakeup_all(); - if (notify_die(DIE_MCA_MONARCH_PROCESS, "MCA", regs, (long)&nd, 0, 0) + if (notify_die(DIE_MCA_MONARCH_PROCESS, "MCA", regs, 0, 0, 0) == NOTIFY_STOP) ia64_mca_spin(__FUNCTION__); @@ -1068,7 +988,7 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw, ia64_sal_clear_state_info(SAL_INFO_TYPE_MCA); sos->os_status = IA64_MCA_CORRECTED; } - if (notify_die(DIE_MCA_MONARCH_LEAVE, "MCA", regs, (long)&nd, 0, recover) + if (notify_die(DIE_MCA_MONARCH_LEAVE, "MCA", regs, 0, 0, recover) == NOTIFY_STOP) ia64_mca_spin(__FUNCTION__); @@ -1355,14 +1275,10 @@ ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw, static atomic_t monarchs; task_t *previous_current; int cpu = smp_processor_id(); - struct ia64_mca_notify_die nd = - { .sos = sos, .monarch_cpu = &monarch_cpu }; oops_in_progress = 1; /* FIXME: make printk NMI/MCA/INIT safe */ console_loglevel = 15; /* make sure printks make it to console */ - (void) notify_die(DIE_INIT_ENTER, "INIT", regs, (long)&nd, 0, 0); - printk(KERN_INFO "Entered OS INIT handler. PSP=%lx cpu=%d monarch=%ld\n", sos->proc_state_param, cpu, sos->monarch); salinfo_log_wakeup(SAL_INFO_TYPE_INIT, NULL, 0, 0); @@ -1398,15 +1314,15 @@ ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw, ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_INIT; while (monarch_cpu == -1) cpu_relax(); /* spin until monarch enters */ - if (notify_die(DIE_INIT_SLAVE_ENTER, "INIT", regs, (long)&nd, 0, 0) + if (notify_die(DIE_INIT_SLAVE_ENTER, "INIT", regs, 0, 0, 0) == NOTIFY_STOP) ia64_mca_spin(__FUNCTION__); - if (notify_die(DIE_INIT_SLAVE_PROCESS, "INIT", regs, (long)&nd, 0, 0) + if (notify_die(DIE_INIT_SLAVE_PROCESS, "INIT", regs, 0, 0, 0) == NOTIFY_STOP) ia64_mca_spin(__FUNCTION__); while (monarch_cpu != -1) cpu_relax(); /* spin until monarch leaves */ - if (notify_die(DIE_INIT_SLAVE_LEAVE, "INIT", regs, (long)&nd, 0, 0) + if (notify_die(DIE_INIT_SLAVE_LEAVE, "INIT", regs, 0, 0, 0) == NOTIFY_STOP) ia64_mca_spin(__FUNCTION__); printk("Slave on cpu %d returning to normal service.\n", cpu); @@ -1417,7 +1333,7 @@ ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw, } monarch_cpu = cpu; - if (notify_die(DIE_INIT_MONARCH_ENTER, "INIT", regs, (long)&nd, 0, 0) + if (notify_die(DIE_INIT_MONARCH_ENTER, "INIT", regs, 0, 0, 0) == NOTIFY_STOP) ia64_mca_spin(__FUNCTION__); @@ -1429,15 +1345,15 @@ ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw, */ printk("Delaying for 5 seconds...\n"); udelay(5*1000000); - ia64_wait_for_slaves(cpu, "INIT"); + ia64_wait_for_slaves(cpu); /* If nobody intercepts DIE_INIT_MONARCH_PROCESS then we drop through * to default_monarch_init_process() above and just print all the * tasks. */ - if (notify_die(DIE_INIT_MONARCH_PROCESS, "INIT", regs, (long)&nd, 0, 0) + if (notify_die(DIE_INIT_MONARCH_PROCESS, "INIT", regs, 0, 0, 0) == NOTIFY_STOP) ia64_mca_spin(__FUNCTION__); - if (notify_die(DIE_INIT_MONARCH_LEAVE, "INIT", regs, (long)&nd, 0, 0) + if (notify_die(DIE_INIT_MONARCH_LEAVE, "INIT", regs, 0, 0, 0) == NOTIFY_STOP) ia64_mca_spin(__FUNCTION__); printk("\nINIT dump complete. Monarch on cpu %d returning to normal service.\n", cpu); @@ -1500,7 +1416,7 @@ static struct irqaction mca_cpep_irqaction = { * format most of the fields. */ -static void __cpuinit +static void format_mca_init_stack(void *mca_data, unsigned long offset, const char *type, int cpu) { @@ -1514,7 +1430,7 @@ format_mca_init_stack(void *mca_data, unsigned long offset, ti->cpu = cpu; p->thread_info = ti; p->state = TASK_UNINTERRUPTIBLE; - cpu_set(cpu, p->cpus_allowed); + __set_bit(cpu, &p->cpus_allowed); INIT_LIST_HEAD(&p->tasks); p->parent = p->real_parent = p->group_leader = p; INIT_LIST_HEAD(&p->children); @@ -1524,17 +1440,15 @@ format_mca_init_stack(void *mca_data, unsigned long offset, /* Do per-CPU MCA-related initialization. */ -void __cpuinit +void __devinit ia64_mca_cpu_init(void *cpu_data) { void *pal_vaddr; - static int first_time = 1; - if (first_time) { + if (smp_processor_id() == 0) { void *mca_data; int cpu; - first_time = 0; mca_data = alloc_bootmem(sizeof(struct ia64_mca_cpu) * NR_CPUS + KERNEL_STACK_SIZE); mca_data = (void *)(((unsigned long)mca_data + @@ -1639,7 +1553,6 @@ ia64_mca_init(void) printk(KERN_INFO "Increasing MCA rendezvous timeout from " "%ld to %ld milliseconds\n", timeout, isrv.v0); timeout = isrv.v0; - (void) notify_die(DIE_MCA_NEW_TIMEOUT, "MCA", NULL, timeout, 0, 0); continue; } printk(KERN_ERR "Failed to register rendezvous interrupt " @@ -1791,7 +1704,6 @@ ia64_mca_late_init(void) desc = irq_descp(irq); desc->status |= IRQ_PER_CPU; setup_irq(irq, &mca_cpe_irqaction); - ia64_cpe_irq = irq; } ia64_mca_register_cpev(cpe_vector); IA64_MCA_DEBUG("%s: CPEI/P setup and enabled.\n", __FUNCTION__);