- Linus: more PageDirty / swapcache handling
[davej-history.git] / arch / mips64 / sgi-ip27 / ip27-nmi.c
blob8b03918f817a336c524be1fb4ec8093d17cc625b
1 #include <linux/kernel.h>
2 #include <linux/mmzone.h>
3 #include <linux/spinlock.h>
4 #include <linux/smp.h>
5 #include <asm/atomic.h>
6 #include <asm/sn/types.h>
7 #include <asm/sn/addrs.h>
8 #include <asm/sn/nmi.h>
9 #include <asm/sn/arch.h>
10 #include <asm/sn/sn0/hub.h>
12 #if 0
13 #define NODE_NUM_CPUS(n) CNODE_NUM_CPUS(n)
14 #else
15 #define NODE_NUM_CPUS(n) CPUS_PER_NODE
16 #endif
18 #define CNODEID_NONE (cnodeid_t)-1
19 #define enter_panic_mode() spin_lock(&nmi_lock)
21 typedef unsigned long machreg_t;
23 spinlock_t nmi_lock = SPIN_LOCK_UNLOCKED;
26 * Lets see what else we need to do here. Set up sp, gp?
28 void nmi_dump(void)
30 void cont_nmi_dump(void);
32 cont_nmi_dump();
35 void install_cpu_nmi_handler(int slice)
37 nmi_t *nmi_addr;
39 nmi_addr = (nmi_t *)NMI_ADDR(get_nasid(), slice);
40 if (nmi_addr->call_addr)
41 return;
42 nmi_addr->magic = NMI_MAGIC;
43 nmi_addr->call_addr = (void *)nmi_dump;
44 nmi_addr->call_addr_c =
45 (void *)(~((unsigned long)(nmi_addr->call_addr)));
46 nmi_addr->call_parm = 0;
50 * Copy the cpu registers which have been saved in the IP27prom format
51 * into the eframe format for the node under consideration.
54 void
55 nmi_cpu_eframe_save(nasid_t nasid,
56 int slice)
58 int i, numberof_nmi_cpu_regs;
59 machreg_t *prom_format;
61 /* Get the total number of registers being saved by the prom */
62 numberof_nmi_cpu_regs = sizeof(struct reg_struct) / sizeof(machreg_t);
64 /* Get the pointer to the current cpu's register set. */
65 prom_format =
66 (machreg_t *)(TO_UNCAC(TO_NODE(nasid, IP27_NMI_KREGS_OFFSET)) +
67 slice * IP27_NMI_KREGS_CPU_SIZE);
69 printk("NMI nasid %d: slice %d\n", nasid, slice);
70 for (i = 0; i < numberof_nmi_cpu_regs; i++)
71 printk("0x%lx ", prom_format[i]);
72 printk("\n\n");
76 * Copy the cpu registers which have been saved in the IP27prom format
77 * into the eframe format for the node under consideration.
79 void
80 nmi_node_eframe_save(cnodeid_t cnode)
82 int cpu;
83 nasid_t nasid;
85 /* Make sure that we have a valid node */
86 if (cnode == CNODEID_NONE)
87 return;
89 nasid = COMPACT_TO_NASID_NODEID(cnode);
90 if (nasid == INVALID_NASID)
91 return;
93 /* Save the registers into eframe for each cpu */
94 for(cpu = 0; cpu < NODE_NUM_CPUS(cnode); cpu++)
95 nmi_cpu_eframe_save(nasid, cpu);
99 * Save the nmi cpu registers for all cpus in the system.
101 void
102 nmi_eframes_save(void)
104 cnodeid_t cnode;
106 for(cnode = 0 ; cnode < numnodes; cnode++)
107 nmi_node_eframe_save(cnode);
110 void
111 cont_nmi_dump(void)
113 #ifndef REAL_NMI_SIGNAL
114 static atomic_t nmied_cpus = ATOMIC_INIT(0);
116 atomic_inc(&nmied_cpus);
117 #endif
119 * Use enter_panic_mode to allow only 1 cpu to proceed
121 enter_panic_mode();
123 #ifdef REAL_NMI_SIGNAL
125 * Wait up to 15 seconds for the other cpus to respond to the NMI.
126 * If a cpu has not responded after 10 sec, send it 1 additional NMI.
127 * This is for 2 reasons:
128 * - sometimes a MMSC fail to NMI all cpus.
129 * - on 512p SN0 system, the MMSC will only send NMIs to
130 * half the cpus. Unfortunately, we dont know which cpus may be
131 * NMIed - it depends on how the site chooses to configure.
133 * Note: it has been measure that it takes the MMSC up to 2.3 secs to
134 * send NMIs to all cpus on a 256p system.
136 for (i=0; i < 1500; i++) {
137 for (node=0; node < numnodes; node++)
138 if (NODEPDA(node)->dump_count == 0)
139 break;
140 if (node == numnodes)
141 break;
142 if (i == 1000) {
143 for (node=0; node < numnodes; node++)
144 if (NODEPDA(node)->dump_count == 0) {
145 cpu = CNODE_TO_CPU_BASE(node);
146 for (n=0; n < CNODE_NUM_CPUS(node); cpu++, n++) {
147 CPUMASK_SETB(nmied_cpus, cpu);
149 * cputonasid, cputoslice
150 * needs kernel cpuid
152 SEND_NMI((cputonasid(cpu)), (cputoslice(cpu)));
157 udelay(10000);
159 #else
160 while (atomic_read(&nmied_cpus) != smp_num_cpus);
161 #endif
164 * Save the nmi cpu registers for all cpu in the eframe format.
166 nmi_eframes_save();
167 LOCAL_HUB_S(NI_PORT_RESET, NPR_PORTRESET | NPR_LOCALRESET);