linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / arch / ia64 / kernel / mca.c
index 2fbe453..ca47dbb 100644 (file)
@@ -55,6 +55,7 @@
  * 2005-10-07 Keith Owens <kaos@sgi.com>
  *           Add notify_die() hooks.
  */
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/sched.h>
@@ -68,7 +69,6 @@
 #include <linux/kernel.h>
 #include <linux/smp.h>
 #include <linux/workqueue.h>
-#include <linux/cpumask.h>
 
 #include <asm/delay.h>
 #include <asm/kdebug.h>
@@ -83,7 +83,6 @@
 #include <asm/irq.h>
 #include <asm/hw_irq.h>
 
-#include "mca_drv.h"
 #include "entry.h"
 
 #if defined(IA64_MCA_DEBUG_INFO)
@@ -134,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
@@ -185,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;
@@ -221,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);
 
@@ -283,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)
@@ -400,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 */
@@ -418,6 +377,8 @@ ia64_mca_register_cpev (int cpev)
 }
 #endif /* CONFIG_ACPI */
 
+#endif /* PLATFORM_MCA_HANDLERS */
+
 /*
  * ia64_mca_cmc_vector_setup
  *
@@ -431,7 +392,7 @@ ia64_mca_register_cpev (int cpev)
  * Outputs
  *     None
  */
-void __cpuinit
+void
 ia64_mca_cmc_vector_setup (void)
 {
        cmcv_reg_t      cmcv;
@@ -580,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__);
 
@@ -595,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__);
 
@@ -603,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__);
 
@@ -671,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 struct task_struct *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
@@ -709,17 +642,17 @@ ia64_mca_modify_comm(const struct task_struct *previous_current)
  * that we can do backtrace on the MCA/INIT handler code itself.
  */
 
-static struct task_struct *
+static task_t *
 ia64_mca_modify_original_stack(struct pt_regs *regs,
                const struct switch_stack *sw,
                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;
-       struct task_struct *previous_current;
+       task_t *previous_current;
        struct pt_regs *old_regs;
        struct switch_stack *old_sw;
        unsigned size = sizeof(struct pt_regs) +
@@ -788,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
@@ -962,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;
@@ -975,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;
 }
 
 /*
@@ -1023,21 +950,15 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw,
        pal_processor_state_info_t *psp = (pal_processor_state_info_t *)
                &sos->proc_state_param;
        int recover, cpu = smp_processor_id();
-       struct task_struct *previous_current;
-       struct ia64_mca_notify_die nd =
-               { .sos = sos, .monarch_cpu = &monarch_cpu };
+       task_t *previous_current;
 
        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
@@ -1046,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__);
 
@@ -1067,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__);
 
@@ -1352,16 +1273,12 @@ ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw,
 {
        static atomic_t slaves;
        static atomic_t monarchs;
-       struct task_struct *previous_current;
+       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);
@@ -1397,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);
@@ -1416,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__);
 
@@ -1428,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);
@@ -1457,38 +1374,38 @@ __setup("disable_cpe_poll", ia64_mca_disable_cpe_polling);
 
 static struct irqaction cmci_irqaction = {
        .handler =      ia64_mca_cmc_int_handler,
-       .flags =        IRQF_DISABLED,
+       .flags =        SA_INTERRUPT,
        .name =         "cmc_hndlr"
 };
 
 static struct irqaction cmcp_irqaction = {
        .handler =      ia64_mca_cmc_int_caller,
-       .flags =        IRQF_DISABLED,
+       .flags =        SA_INTERRUPT,
        .name =         "cmc_poll"
 };
 
 static struct irqaction mca_rdzv_irqaction = {
        .handler =      ia64_mca_rendez_int_handler,
-       .flags =        IRQF_DISABLED,
+       .flags =        SA_INTERRUPT,
        .name =         "mca_rdzv"
 };
 
 static struct irqaction mca_wkup_irqaction = {
        .handler =      ia64_mca_wakeup_int_handler,
-       .flags =        IRQF_DISABLED,
+       .flags =        SA_INTERRUPT,
        .name =         "mca_wkup"
 };
 
 #ifdef CONFIG_ACPI
 static struct irqaction mca_cpe_irqaction = {
        .handler =      ia64_mca_cpe_int_handler,
-       .flags =        IRQF_DISABLED,
+       .flags =        SA_INTERRUPT,
        .name =         "cpe_hndlr"
 };
 
 static struct irqaction mca_cpep_irqaction = {
        .handler =      ia64_mca_cpe_int_caller,
-       .flags =        IRQF_DISABLED,
+       .flags =        SA_INTERRUPT,
        .name =         "cpe_poll"
 };
 #endif /* CONFIG_ACPI */
@@ -1499,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)
 {
@@ -1513,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);
@@ -1523,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 +
@@ -1638,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 "
@@ -1787,10 +1701,9 @@ ia64_mca_late_init(void)
                        cpe_poll_enabled = 0;
                        for (irq = 0; irq < NR_IRQS; ++irq)
                                if (irq_to_vector(irq) == cpe_vector) {
-                                       desc = irq_desc + irq;
+                                       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__);