diff options
author | Kanoj Sarcar <kanoj@engr.sgi.com> | 2000-05-12 02:20:25 +0000 |
---|---|---|
committer | Kanoj Sarcar <kanoj@engr.sgi.com> | 2000-05-12 02:20:25 +0000 |
commit | 71f45a9f27e34707e745439e1d5fc5bf88894607 (patch) | |
tree | 91535375313229d58bfa1480df2de8a83a6b1ae0 /arch | |
parent | 1dfd14568d2f2d73e8625ab3e5fa575a75f26af9 (diff) |
Rudimentary nmi support to be able to do simple debugging on SMP
machines.
Diffstat (limited to 'arch')
-rw-r--r-- | arch/mips64/sgi-ip27/Makefile | 2 | ||||
-rw-r--r-- | arch/mips64/sgi-ip27/ip27-init.c | 3 | ||||
-rw-r--r-- | arch/mips64/sgi-ip27/ip27-nmi.c | 165 |
3 files changed, 169 insertions, 1 deletions
diff --git a/arch/mips64/sgi-ip27/Makefile b/arch/mips64/sgi-ip27/Makefile index 514beaa81..c15231c93 100644 --- a/arch/mips64/sgi-ip27/Makefile +++ b/arch/mips64/sgi-ip27/Makefile @@ -11,6 +11,6 @@ L_TARGET = ip27.a L_OBJS = ip27-berr.o ip27-irq.o ip27-irq-glue.o ip27-klconfig.o \ ip27-memory.o ip27-pci.o ip27-pci-dma.o ip27-reset.o ip27-setup.o \ - ip27-timer.o ip27-init.o + ip27-timer.o ip27-init.o ip27-nmi.o include $(TOPDIR)/Rules.make diff --git a/arch/mips64/sgi-ip27/ip27-init.c b/arch/mips64/sgi-ip27/ip27-init.c index 253022f37..9e2df3662 100644 --- a/arch/mips64/sgi-ip27/ip27-init.c +++ b/arch/mips64/sgi-ip27/ip27-init.c @@ -314,6 +314,7 @@ cpuid_t getcpuid(void) void per_cpu_init(void) { + extern void install_cpu_nmi_handler(int slice); extern void load_mmu(void); static int is_slave = 0; cpuid_t cpu = getcpuid(); @@ -328,6 +329,8 @@ void per_cpu_init(void) cpu_time_init(); if (smp_processor_id()) /* master can't do this early, no kmalloc */ install_cpuintr(cpu); + /* Install our NMI handler if symmon hasn't installed one. */ + install_cpu_nmi_handler(cputoslice(smp_processor_id())); #if 0 install_tlbintr(cpu); #endif diff --git a/arch/mips64/sgi-ip27/ip27-nmi.c b/arch/mips64/sgi-ip27/ip27-nmi.c new file mode 100644 index 000000000..3511c62e7 --- /dev/null +++ b/arch/mips64/sgi-ip27/ip27-nmi.c @@ -0,0 +1,165 @@ +#include <linux/kernel.h> +#include <linux/mmzone.h> +#include <linux/spinlock.h> +#include <linux/smp.h> +#include <asm/atomic.h> +#include <asm/sn/types.h> +#include <asm/sn/addrs.h> +#include <asm/sn/nmi.h> +#include <asm/sn/arch.h> +#include <asm/sn/sn0/hub.h> + +#if 0 +#define NODE_NUM_CPUS(n) CNODE_NUM_CPUS(n) +#else +#define NODE_NUM_CPUS(n) CPUS_PER_NODE +#endif + +#define CNODEID_NONE (cnodeid_t)-1 +#define enter_panic_mode() spin_lock(&nmi_lock) + +typedef unsigned long machreg_t; + +spinlock_t nmi_lock = SPIN_LOCK_UNLOCKED; + +/* + * Lets see what else we need to do here. Set up sp, gp? + */ +void nmi_dump(void) +{ + void cont_nmi_dump(void); + + cont_nmi_dump(); +} + +void install_cpu_nmi_handler(int slice) +{ + nmi_t *nmi_addr; + + nmi_addr = (nmi_t *)NMI_ADDR(get_nasid(), slice); + if (nmi_addr->call_addr) + return; + nmi_addr->magic = NMI_MAGIC; + nmi_addr->call_addr = (void *)nmi_dump; + nmi_addr->call_addr_c = + (void *)(~((unsigned long)(nmi_addr->call_addr))); + nmi_addr->call_parm = 0; +} + +/* + * Copy the cpu registers which have been saved in the IP27prom format + * into the eframe format for the node under consideration. + */ + +void +nmi_cpu_eframe_save(nasid_t nasid, + int slice) +{ + int i, numberof_nmi_cpu_regs; + machreg_t *prom_format; + + /* Get the total number of registers being saved by the prom */ + numberof_nmi_cpu_regs = sizeof(struct reg_struct) / sizeof(machreg_t); + + /* Get the pointer to the current cpu's register set. */ + prom_format = + (machreg_t *)(TO_UNCAC(TO_NODE(nasid, IP27_NMI_KREGS_OFFSET)) + + slice * IP27_NMI_KREGS_CPU_SIZE); + + printk("NMI nasid %d: slice %d\n", nasid, slice); + for (i = 0; i < numberof_nmi_cpu_regs; i++) + printk("0x%lx ", prom_format[i]); + printk("\n\n"); +} + +/* + * Copy the cpu registers which have been saved in the IP27prom format + * into the eframe format for the node under consideration. + */ +void +nmi_node_eframe_save(cnodeid_t cnode) +{ + int cpu; + nasid_t nasid; + + /* Make sure that we have a valid node */ + if (cnode == CNODEID_NONE) + return; + + nasid = COMPACT_TO_NASID_NODEID(cnode); + if (nasid == INVALID_NASID) + return; + + /* Save the registers into eframe for each cpu */ + for(cpu = 0; cpu < NODE_NUM_CPUS(cnode); cpu++) + nmi_cpu_eframe_save(nasid, cpu); +} + +/* + * Save the nmi cpu registers for all cpus in the system. + */ +void +nmi_eframes_save(void) +{ + cnodeid_t cnode; + + for(cnode = 0 ; cnode < numnodes; cnode++) + nmi_node_eframe_save(cnode); +} + +void +cont_nmi_dump(void) +{ +#ifndef REAL_NMI_SIGNAL + static atomic_t nmied_cpus = ATOMIC_INIT(0); + + atomic_inc(&nmied_cpus); +#endif + /* + * Use enter_panic_mode to allow only 1 cpu to proceed + */ + enter_panic_mode(); + +#ifdef REAL_NMI_SIGNAL + /* + * Wait up to 15 seconds for the other cpus to respond to the NMI. + * If a cpu has not responded after 10 sec, send it 1 additional NMI. + * This is for 2 reasons: + * - sometimes a MMSC fail to NMI all cpus. + * - on 512p SN0 system, the MMSC will only send NMIs to + * half the cpus. Unfortunately, we dont know which cpus may be + * NMIed - it depends on how the site chooses to configure. + * + * Note: it has been measure that it takes the MMSC up to 2.3 secs to + * send NMIs to all cpus on a 256p system. + */ + for (i=0; i < 1500; i++) { + for (node=0; node < numnodes; node++) + if (NODEPDA(node)->dump_count == 0) + break; + if (node == numnodes) + break; + if (i == 1000) { + for (node=0; node < numnodes; node++) + if (NODEPDA(node)->dump_count == 0) { + cpu = CNODE_TO_CPU_BASE(node); + for (n=0; n < CNODE_NUM_CPUS(node); cpu++, n++) { + CPUMASK_SETB(nmied_cpus, cpu); + SEND_NMI((cputonasid(cpu)), (cputoslice(cpu))); + } + } + + } + udelay(10000); + } +#else + while (atomic_read(&nmied_cpus) != smp_num_cpus); +#endif + + /* + * Save the nmi cpu registers for all cpu in the eframe format. + */ + nmi_eframes_save(); + LOCAL_HUB_S(NI_PORT_RESET, NPR_PORTRESET | NPR_LOCALRESET); +} + |