blob: 342da21642393aba048fc51139748375244bcf9b [file] [log] [blame]
David S. Millerd979f172007-10-27 00:13:04 -07001/* arch/sparc64/kernel/traps.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 *
David S. Miller4fe3ebe2008-07-17 22:11:32 -07003 * Copyright (C) 1995,1997,2008 David S. Miller (davem@davemloft.net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 * Copyright (C) 1997,1999,2000 Jakub Jelinek (jakub@redhat.com)
5 */
6
7/*
8 * I like traps on v9, :))))
9 */
10
Linus Torvalds1da177e2005-04-16 15:20:36 -070011#include <linux/module.h>
David S. Millera2c1e062006-11-29 21:16:21 -080012#include <linux/sched.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include <linux/signal.h>
15#include <linux/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include <linux/mm.h>
17#include <linux/init.h>
Christoph Hellwig1eeb66a2007-05-08 00:27:03 -070018#include <linux/kdebug.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019
Fernando Luis Vazquez Cao2f4dfe22007-05-09 02:33:25 -070020#include <asm/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <asm/delay.h>
22#include <asm/system.h>
23#include <asm/ptrace.h>
24#include <asm/oplib.h>
25#include <asm/page.h>
26#include <asm/pgtable.h>
27#include <asm/unistd.h>
28#include <asm/uaccess.h>
29#include <asm/fpumacro.h>
30#include <asm/lsu.h>
31#include <asm/dcu.h>
32#include <asm/estate.h>
33#include <asm/chafsr.h>
David S. Miller6c52a962005-08-29 12:45:11 -070034#include <asm/sfafsr.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <asm/psrcompat.h>
36#include <asm/processor.h>
37#include <asm/timer.h>
David S. Miller92704a12006-02-26 23:27:19 -080038#include <asm/head.h>
David S. Miller07f8e5f2006-06-21 23:34:02 -070039#include <asm/prom.h>
David S. Miller881d0212008-08-24 22:08:34 -070040#include <asm/memctrl.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
David S. Miller99cd2202008-03-26 00:19:43 -070042#include "entry.h"
David S. Miller4f70f7a2008-08-12 18:33:56 -070043#include "kstack.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
45/* When an irrecoverable trap occurs at tl > 0, the trap entry
46 * code logs the trap state registers at every level in the trap
47 * stack. It is found at (pt_regs + sizeof(pt_regs)) and the layout
48 * is as follows:
49 */
50struct tl1_traplog {
51 struct {
52 unsigned long tstate;
53 unsigned long tpc;
54 unsigned long tnpc;
55 unsigned long tt;
56 } trapstack[4];
57 unsigned long tl;
58};
59
60static void dump_tl1_traplog(struct tl1_traplog *p)
61{
David S. Miller3d6395c2006-02-16 01:41:41 -080062 int i, limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
David S. Miller04d74752006-02-18 17:06:28 -080064 printk(KERN_EMERG "TRAPLOG: Error at trap level 0x%lx, "
65 "dumping track stack.\n", p->tl);
David S. Miller3d6395c2006-02-16 01:41:41 -080066
67 limit = (tlb_type == hypervisor) ? 2 : 4;
David S. Miller39334a42006-02-20 00:54:09 -080068 for (i = 0; i < limit; i++) {
David S. Miller04d74752006-02-18 17:06:28 -080069 printk(KERN_EMERG
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 "TRAPLOG: Trap level %d TSTATE[%016lx] TPC[%016lx] "
71 "TNPC[%016lx] TT[%lx]\n",
72 i + 1,
73 p->trapstack[i].tstate, p->trapstack[i].tpc,
74 p->trapstack[i].tnpc, p->trapstack[i].tt);
David S. Miller4fe3ebe2008-07-17 22:11:32 -070075 printk("TRAPLOG: TPC<%pS>\n", (void *) p->trapstack[i].tpc);
Linus Torvalds1da177e2005-04-16 15:20:36 -070076 }
77}
78
Linus Torvalds1da177e2005-04-16 15:20:36 -070079void bad_trap(struct pt_regs *regs, long lvl)
80{
81 char buffer[32];
82 siginfo_t info;
83
84 if (notify_die(DIE_TRAP, "bad trap", regs,
85 0, lvl, SIGTRAP) == NOTIFY_STOP)
86 return;
87
88 if (lvl < 0x100) {
89 sprintf(buffer, "Bad hw trap %lx at tl0\n", lvl);
90 die_if_kernel(buffer, regs);
91 }
92
93 lvl -= 0x100;
94 if (regs->tstate & TSTATE_PRIV) {
95 sprintf(buffer, "Kernel bad sw trap %lx", lvl);
96 die_if_kernel(buffer, regs);
97 }
98 if (test_thread_flag(TIF_32BIT)) {
99 regs->tpc &= 0xffffffff;
100 regs->tnpc &= 0xffffffff;
101 }
102 info.si_signo = SIGILL;
103 info.si_errno = 0;
104 info.si_code = ILL_ILLTRP;
105 info.si_addr = (void __user *)regs->tpc;
106 info.si_trapno = lvl;
107 force_sig_info(SIGILL, &info, current);
108}
109
110void bad_trap_tl1(struct pt_regs *regs, long lvl)
111{
112 char buffer[32];
113
114 if (notify_die(DIE_TRAP_TL1, "bad trap tl1", regs,
115 0, lvl, SIGTRAP) == NOTIFY_STOP)
116 return;
117
118 dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
119
120 sprintf (buffer, "Bad trap %lx at tl>0", lvl);
121 die_if_kernel (buffer, regs);
122}
123
124#ifdef CONFIG_DEBUG_BUGVERBOSE
125void do_BUG(const char *file, int line)
126{
127 bust_spinlocks(1);
128 printk("kernel BUG at %s:%d!\n", file, line);
129}
130#endif
131
David S. Miller881d0212008-08-24 22:08:34 -0700132static DEFINE_SPINLOCK(dimm_handler_lock);
133static dimm_printer_t dimm_handler;
134
135static int sprintf_dimm(int synd_code, unsigned long paddr, char *buf, int buflen)
136{
137 unsigned long flags;
138 int ret = -ENODEV;
139
140 spin_lock_irqsave(&dimm_handler_lock, flags);
141 if (dimm_handler) {
142 ret = dimm_handler(synd_code, paddr, buf, buflen);
143 } else if (tlb_type == spitfire) {
144 if (prom_getunumber(synd_code, paddr, buf, buflen) == -1)
145 ret = -EINVAL;
146 else
147 ret = 0;
148 } else
149 ret = -ENODEV;
150 spin_unlock_irqrestore(&dimm_handler_lock, flags);
151
152 return ret;
153}
154
155int register_dimm_printer(dimm_printer_t func)
156{
157 unsigned long flags;
158 int ret = 0;
159
160 spin_lock_irqsave(&dimm_handler_lock, flags);
161 if (!dimm_handler)
162 dimm_handler = func;
163 else
164 ret = -EEXIST;
165 spin_unlock_irqrestore(&dimm_handler_lock, flags);
166
167 return ret;
168}
David S. Miller41660e92008-08-24 22:17:29 -0700169EXPORT_SYMBOL_GPL(register_dimm_printer);
David S. Miller881d0212008-08-24 22:08:34 -0700170
171void unregister_dimm_printer(dimm_printer_t func)
172{
173 unsigned long flags;
174
175 spin_lock_irqsave(&dimm_handler_lock, flags);
176 if (dimm_handler == func)
177 dimm_handler = NULL;
178 spin_unlock_irqrestore(&dimm_handler_lock, flags);
179}
David S. Miller41660e92008-08-24 22:17:29 -0700180EXPORT_SYMBOL_GPL(unregister_dimm_printer);
David S. Miller881d0212008-08-24 22:08:34 -0700181
David S. Miller6c52a962005-08-29 12:45:11 -0700182void spitfire_insn_access_exception(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183{
184 siginfo_t info;
185
186 if (notify_die(DIE_TRAP, "instruction access exception", regs,
187 0, 0x8, SIGTRAP) == NOTIFY_STOP)
188 return;
189
190 if (regs->tstate & TSTATE_PRIV) {
David S. Miller6c52a962005-08-29 12:45:11 -0700191 printk("spitfire_insn_access_exception: SFSR[%016lx] "
192 "SFAR[%016lx], going.\n", sfsr, sfar);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 die_if_kernel("Iax", regs);
194 }
195 if (test_thread_flag(TIF_32BIT)) {
196 regs->tpc &= 0xffffffff;
197 regs->tnpc &= 0xffffffff;
198 }
199 info.si_signo = SIGSEGV;
200 info.si_errno = 0;
201 info.si_code = SEGV_MAPERR;
202 info.si_addr = (void __user *)regs->tpc;
203 info.si_trapno = 0;
204 force_sig_info(SIGSEGV, &info, current);
205}
206
David S. Miller6c52a962005-08-29 12:45:11 -0700207void spitfire_insn_access_exception_tl1(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208{
209 if (notify_die(DIE_TRAP_TL1, "instruction access exception tl1", regs,
210 0, 0x8, SIGTRAP) == NOTIFY_STOP)
211 return;
212
213 dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
David S. Miller6c52a962005-08-29 12:45:11 -0700214 spitfire_insn_access_exception(regs, sfsr, sfar);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215}
216
David S. Millered6b0b42006-02-09 20:20:34 -0800217void sun4v_insn_access_exception(struct pt_regs *regs, unsigned long addr, unsigned long type_ctx)
218{
219 unsigned short type = (type_ctx >> 16);
220 unsigned short ctx = (type_ctx & 0xffff);
221 siginfo_t info;
222
223 if (notify_die(DIE_TRAP, "instruction access exception", regs,
224 0, 0x8, SIGTRAP) == NOTIFY_STOP)
225 return;
226
227 if (regs->tstate & TSTATE_PRIV) {
228 printk("sun4v_insn_access_exception: ADDR[%016lx] "
229 "CTX[%04x] TYPE[%04x], going.\n",
230 addr, ctx, type);
231 die_if_kernel("Iax", regs);
232 }
233
234 if (test_thread_flag(TIF_32BIT)) {
235 regs->tpc &= 0xffffffff;
236 regs->tnpc &= 0xffffffff;
237 }
238 info.si_signo = SIGSEGV;
239 info.si_errno = 0;
240 info.si_code = SEGV_MAPERR;
241 info.si_addr = (void __user *) addr;
242 info.si_trapno = 0;
243 force_sig_info(SIGSEGV, &info, current);
244}
245
246void sun4v_insn_access_exception_tl1(struct pt_regs *regs, unsigned long addr, unsigned long type_ctx)
247{
248 if (notify_die(DIE_TRAP_TL1, "instruction access exception tl1", regs,
249 0, 0x8, SIGTRAP) == NOTIFY_STOP)
250 return;
251
252 dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
253 sun4v_insn_access_exception(regs, addr, type_ctx);
254}
255
David S. Miller6c52a962005-08-29 12:45:11 -0700256void spitfire_data_access_exception(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257{
258 siginfo_t info;
259
260 if (notify_die(DIE_TRAP, "data access exception", regs,
261 0, 0x30, SIGTRAP) == NOTIFY_STOP)
262 return;
263
264 if (regs->tstate & TSTATE_PRIV) {
265 /* Test if this comes from uaccess places. */
David S. Miller8cf14af2005-09-28 20:21:11 -0700266 const struct exception_table_entry *entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267
David S. Miller8cf14af2005-09-28 20:21:11 -0700268 entry = search_exception_tables(regs->tpc);
269 if (entry) {
270 /* Ouch, somebody is trying VM hole tricks on us... */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271#ifdef DEBUG_EXCEPTIONS
272 printk("Exception: PC<%016lx> faddr<UNKNOWN>\n", regs->tpc);
David S. Miller8cf14af2005-09-28 20:21:11 -0700273 printk("EX_TABLE: insn<%016lx> fixup<%016lx>\n",
274 regs->tpc, entry->fixup);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275#endif
David S. Miller8cf14af2005-09-28 20:21:11 -0700276 regs->tpc = entry->fixup;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 regs->tnpc = regs->tpc + 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 return;
279 }
280 /* Shit... */
David S. Miller6c52a962005-08-29 12:45:11 -0700281 printk("spitfire_data_access_exception: SFSR[%016lx] "
282 "SFAR[%016lx], going.\n", sfsr, sfar);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 die_if_kernel("Dax", regs);
284 }
285
286 info.si_signo = SIGSEGV;
287 info.si_errno = 0;
288 info.si_code = SEGV_MAPERR;
289 info.si_addr = (void __user *)sfar;
290 info.si_trapno = 0;
291 force_sig_info(SIGSEGV, &info, current);
292}
293
David S. Miller6c52a962005-08-29 12:45:11 -0700294void spitfire_data_access_exception_tl1(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar)
David S. Millerbde4e4e2005-08-29 12:44:57 -0700295{
296 if (notify_die(DIE_TRAP_TL1, "data access exception tl1", regs,
297 0, 0x30, SIGTRAP) == NOTIFY_STOP)
298 return;
299
300 dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
David S. Miller6c52a962005-08-29 12:45:11 -0700301 spitfire_data_access_exception(regs, sfsr, sfar);
David S. Millerbde4e4e2005-08-29 12:44:57 -0700302}
303
David S. Millered6b0b42006-02-09 20:20:34 -0800304void sun4v_data_access_exception(struct pt_regs *regs, unsigned long addr, unsigned long type_ctx)
305{
306 unsigned short type = (type_ctx >> 16);
307 unsigned short ctx = (type_ctx & 0xffff);
308 siginfo_t info;
309
310 if (notify_die(DIE_TRAP, "data access exception", regs,
311 0, 0x8, SIGTRAP) == NOTIFY_STOP)
312 return;
313
314 if (regs->tstate & TSTATE_PRIV) {
315 printk("sun4v_data_access_exception: ADDR[%016lx] "
316 "CTX[%04x] TYPE[%04x], going.\n",
317 addr, ctx, type);
David S. Miller55555632006-02-20 01:50:09 -0800318 die_if_kernel("Dax", regs);
David S. Millered6b0b42006-02-09 20:20:34 -0800319 }
320
321 if (test_thread_flag(TIF_32BIT)) {
322 regs->tpc &= 0xffffffff;
323 regs->tnpc &= 0xffffffff;
324 }
325 info.si_signo = SIGSEGV;
326 info.si_errno = 0;
327 info.si_code = SEGV_MAPERR;
328 info.si_addr = (void __user *) addr;
329 info.si_trapno = 0;
330 force_sig_info(SIGSEGV, &info, current);
331}
332
333void sun4v_data_access_exception_tl1(struct pt_regs *regs, unsigned long addr, unsigned long type_ctx)
334{
335 if (notify_die(DIE_TRAP_TL1, "data access exception tl1", regs,
336 0, 0x8, SIGTRAP) == NOTIFY_STOP)
337 return;
338
339 dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
340 sun4v_data_access_exception(regs, addr, type_ctx);
341}
342
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343#ifdef CONFIG_PCI
David S. Miller77d10d02008-09-11 23:57:40 -0700344#include "pci_impl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345#endif
346
347/* When access exceptions happen, we must do this. */
348static void spitfire_clean_and_reenable_l1_caches(void)
349{
350 unsigned long va;
351
352 if (tlb_type != spitfire)
353 BUG();
354
355 /* Clean 'em. */
356 for (va = 0; va < (PAGE_SIZE << 1); va += 32) {
357 spitfire_put_icache_tag(va, 0x0);
358 spitfire_put_dcache_tag(va, 0x0);
359 }
360
361 /* Re-enable in LSU. */
362 __asm__ __volatile__("flush %%g6\n\t"
363 "membar #Sync\n\t"
364 "stxa %0, [%%g0] %1\n\t"
365 "membar #Sync"
366 : /* no outputs */
367 : "r" (LSU_CONTROL_IC | LSU_CONTROL_DC |
368 LSU_CONTROL_IM | LSU_CONTROL_DM),
369 "i" (ASI_LSU_CONTROL)
370 : "memory");
371}
372
David S. Miller6c52a962005-08-29 12:45:11 -0700373static void spitfire_enable_estate_errors(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374{
David S. Miller6c52a962005-08-29 12:45:11 -0700375 __asm__ __volatile__("stxa %0, [%%g0] %1\n\t"
376 "membar #Sync"
377 : /* no outputs */
378 : "r" (ESTATE_ERR_ALL),
379 "i" (ASI_ESTATE_ERROR_EN));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380}
381
382static char ecc_syndrome_table[] = {
383 0x4c, 0x40, 0x41, 0x48, 0x42, 0x48, 0x48, 0x49,
384 0x43, 0x48, 0x48, 0x49, 0x48, 0x49, 0x49, 0x4a,
385 0x44, 0x48, 0x48, 0x20, 0x48, 0x39, 0x4b, 0x48,
386 0x48, 0x25, 0x31, 0x48, 0x28, 0x48, 0x48, 0x2c,
387 0x45, 0x48, 0x48, 0x21, 0x48, 0x3d, 0x04, 0x48,
388 0x48, 0x4b, 0x35, 0x48, 0x2d, 0x48, 0x48, 0x29,
389 0x48, 0x00, 0x01, 0x48, 0x0a, 0x48, 0x48, 0x4b,
390 0x0f, 0x48, 0x48, 0x4b, 0x48, 0x49, 0x49, 0x48,
391 0x46, 0x48, 0x48, 0x2a, 0x48, 0x3b, 0x27, 0x48,
392 0x48, 0x4b, 0x33, 0x48, 0x22, 0x48, 0x48, 0x2e,
393 0x48, 0x19, 0x1d, 0x48, 0x1b, 0x4a, 0x48, 0x4b,
394 0x1f, 0x48, 0x4a, 0x4b, 0x48, 0x4b, 0x4b, 0x48,
395 0x48, 0x4b, 0x24, 0x48, 0x07, 0x48, 0x48, 0x36,
396 0x4b, 0x48, 0x48, 0x3e, 0x48, 0x30, 0x38, 0x48,
397 0x49, 0x48, 0x48, 0x4b, 0x48, 0x4b, 0x16, 0x48,
398 0x48, 0x12, 0x4b, 0x48, 0x49, 0x48, 0x48, 0x4b,
399 0x47, 0x48, 0x48, 0x2f, 0x48, 0x3f, 0x4b, 0x48,
400 0x48, 0x06, 0x37, 0x48, 0x23, 0x48, 0x48, 0x2b,
401 0x48, 0x05, 0x4b, 0x48, 0x4b, 0x48, 0x48, 0x32,
402 0x26, 0x48, 0x48, 0x3a, 0x48, 0x34, 0x3c, 0x48,
403 0x48, 0x11, 0x15, 0x48, 0x13, 0x4a, 0x48, 0x4b,
404 0x17, 0x48, 0x4a, 0x4b, 0x48, 0x4b, 0x4b, 0x48,
405 0x49, 0x48, 0x48, 0x4b, 0x48, 0x4b, 0x1e, 0x48,
406 0x48, 0x1a, 0x4b, 0x48, 0x49, 0x48, 0x48, 0x4b,
407 0x48, 0x08, 0x0d, 0x48, 0x02, 0x48, 0x48, 0x49,
408 0x03, 0x48, 0x48, 0x49, 0x48, 0x4b, 0x4b, 0x48,
409 0x49, 0x48, 0x48, 0x49, 0x48, 0x4b, 0x10, 0x48,
410 0x48, 0x14, 0x4b, 0x48, 0x4b, 0x48, 0x48, 0x4b,
411 0x49, 0x48, 0x48, 0x49, 0x48, 0x4b, 0x18, 0x48,
412 0x48, 0x1c, 0x4b, 0x48, 0x4b, 0x48, 0x48, 0x4b,
413 0x4a, 0x0c, 0x09, 0x48, 0x0e, 0x48, 0x48, 0x4b,
414 0x0b, 0x48, 0x48, 0x4b, 0x48, 0x4b, 0x4b, 0x4a
415};
416
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417static char *syndrome_unknown = "<Unknown>";
418
David S. Miller6c52a962005-08-29 12:45:11 -0700419static void spitfire_log_udb_syndrome(unsigned long afar, unsigned long udbh, unsigned long udbl, unsigned long bit)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420{
David S. Miller6c52a962005-08-29 12:45:11 -0700421 unsigned short scode;
422 char memmod_str[64], *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
David S. Miller6c52a962005-08-29 12:45:11 -0700424 if (udbl & bit) {
425 scode = ecc_syndrome_table[udbl & 0xff];
David S. Miller881d0212008-08-24 22:08:34 -0700426 if (sprintf_dimm(scode, afar, memmod_str, sizeof(memmod_str)) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 p = syndrome_unknown;
428 else
429 p = memmod_str;
430 printk(KERN_WARNING "CPU[%d]: UDBL Syndrome[%x] "
431 "Memory Module \"%s\"\n",
432 smp_processor_id(), scode, p);
433 }
434
David S. Miller6c52a962005-08-29 12:45:11 -0700435 if (udbh & bit) {
436 scode = ecc_syndrome_table[udbh & 0xff];
David S. Miller881d0212008-08-24 22:08:34 -0700437 if (sprintf_dimm(scode, afar, memmod_str, sizeof(memmod_str)) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 p = syndrome_unknown;
439 else
440 p = memmod_str;
441 printk(KERN_WARNING "CPU[%d]: UDBH Syndrome[%x] "
442 "Memory Module \"%s\"\n",
443 smp_processor_id(), scode, p);
444 }
David S. Miller6c52a962005-08-29 12:45:11 -0700445
446}
447
448static void spitfire_cee_log(unsigned long afsr, unsigned long afar, unsigned long udbh, unsigned long udbl, int tl1, struct pt_regs *regs)
449{
450
451 printk(KERN_WARNING "CPU[%d]: Correctable ECC Error "
452 "AFSR[%lx] AFAR[%016lx] UDBL[%lx] UDBH[%lx] TL>1[%d]\n",
453 smp_processor_id(), afsr, afar, udbl, udbh, tl1);
454
455 spitfire_log_udb_syndrome(afar, udbh, udbl, UDBE_CE);
456
457 /* We always log it, even if someone is listening for this
458 * trap.
459 */
460 notify_die(DIE_TRAP, "Correctable ECC Error", regs,
461 0, TRAP_TYPE_CEE, SIGTRAP);
462
463 /* The Correctable ECC Error trap does not disable I/D caches. So
464 * we only have to restore the ESTATE Error Enable register.
465 */
466 spitfire_enable_estate_errors();
467}
468
469static void spitfire_ue_log(unsigned long afsr, unsigned long afar, unsigned long udbh, unsigned long udbl, unsigned long tt, int tl1, struct pt_regs *regs)
470{
471 siginfo_t info;
472
473 printk(KERN_WARNING "CPU[%d]: Uncorrectable Error AFSR[%lx] "
474 "AFAR[%lx] UDBL[%lx] UDBH[%ld] TT[%lx] TL>1[%d]\n",
475 smp_processor_id(), afsr, afar, udbl, udbh, tt, tl1);
476
477 /* XXX add more human friendly logging of the error status
478 * XXX as is implemented for cheetah
479 */
480
481 spitfire_log_udb_syndrome(afar, udbh, udbl, UDBE_UE);
482
483 /* We always log it, even if someone is listening for this
484 * trap.
485 */
486 notify_die(DIE_TRAP, "Uncorrectable Error", regs,
487 0, tt, SIGTRAP);
488
489 if (regs->tstate & TSTATE_PRIV) {
490 if (tl1)
491 dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
492 die_if_kernel("UE", regs);
493 }
494
495 /* XXX need more intelligent processing here, such as is implemented
496 * XXX for cheetah errors, in fact if the E-cache still holds the
497 * XXX line with bad parity this will loop
498 */
499
500 spitfire_clean_and_reenable_l1_caches();
501 spitfire_enable_estate_errors();
502
503 if (test_thread_flag(TIF_32BIT)) {
504 regs->tpc &= 0xffffffff;
505 regs->tnpc &= 0xffffffff;
506 }
507 info.si_signo = SIGBUS;
508 info.si_errno = 0;
509 info.si_code = BUS_OBJERR;
510 info.si_addr = (void *)0;
511 info.si_trapno = 0;
512 force_sig_info(SIGBUS, &info, current);
513}
514
515void spitfire_access_error(struct pt_regs *regs, unsigned long status_encoded, unsigned long afar)
516{
517 unsigned long afsr, tt, udbh, udbl;
518 int tl1;
519
520 afsr = (status_encoded & SFSTAT_AFSR_MASK) >> SFSTAT_AFSR_SHIFT;
521 tt = (status_encoded & SFSTAT_TRAP_TYPE) >> SFSTAT_TRAP_TYPE_SHIFT;
522 tl1 = (status_encoded & SFSTAT_TL_GT_ONE) ? 1 : 0;
523 udbl = (status_encoded & SFSTAT_UDBL_MASK) >> SFSTAT_UDBL_SHIFT;
524 udbh = (status_encoded & SFSTAT_UDBH_MASK) >> SFSTAT_UDBH_SHIFT;
525
526#ifdef CONFIG_PCI
527 if (tt == TRAP_TYPE_DAE &&
528 pci_poke_in_progress && pci_poke_cpu == smp_processor_id()) {
529 spitfire_clean_and_reenable_l1_caches();
530 spitfire_enable_estate_errors();
531
532 pci_poke_faulted = 1;
533 regs->tnpc = regs->tpc + 4;
534 return;
535 }
536#endif
537
538 if (afsr & SFAFSR_UE)
539 spitfire_ue_log(afsr, afar, udbh, udbl, tt, tl1, regs);
540
541 if (tt == TRAP_TYPE_CEE) {
542 /* Handle the case where we took a CEE trap, but ACK'd
543 * only the UE state in the UDB error registers.
544 */
545 if (afsr & SFAFSR_UE) {
546 if (udbh & UDBE_CE) {
547 __asm__ __volatile__(
548 "stxa %0, [%1] %2\n\t"
549 "membar #Sync"
550 : /* no outputs */
551 : "r" (udbh & UDBE_CE),
552 "r" (0x0), "i" (ASI_UDB_ERROR_W));
553 }
554 if (udbl & UDBE_CE) {
555 __asm__ __volatile__(
556 "stxa %0, [%1] %2\n\t"
557 "membar #Sync"
558 : /* no outputs */
559 : "r" (udbl & UDBE_CE),
560 "r" (0x18), "i" (ASI_UDB_ERROR_W));
561 }
562 }
563
564 spitfire_cee_log(afsr, afar, udbh, udbl, tl1, regs);
565 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566}
567
David S. Miller816242d2005-05-23 15:52:08 -0700568int cheetah_pcache_forced_on;
569
570void cheetah_enable_pcache(void)
571{
572 unsigned long dcr;
573
574 printk("CHEETAH: Enabling P-Cache on cpu %d.\n",
575 smp_processor_id());
576
577 __asm__ __volatile__("ldxa [%%g0] %1, %0"
578 : "=r" (dcr)
579 : "i" (ASI_DCU_CONTROL_REG));
580 dcr |= (DCU_PE | DCU_HPE | DCU_SPE | DCU_SL);
581 __asm__ __volatile__("stxa %0, [%%g0] %1\n\t"
582 "membar #Sync"
583 : /* no outputs */
584 : "r" (dcr), "i" (ASI_DCU_CONTROL_REG));
585}
586
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587/* Cheetah error trap handling. */
588static unsigned long ecache_flush_physbase;
589static unsigned long ecache_flush_linesize;
590static unsigned long ecache_flush_size;
591
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592/* This table is ordered in priority of errors and matches the
593 * AFAR overwrite policy as well.
594 */
595
596struct afsr_error_table {
597 unsigned long mask;
598 const char *name;
599};
600
601static const char CHAFSR_PERR_msg[] =
602 "System interface protocol error";
603static const char CHAFSR_IERR_msg[] =
604 "Internal processor error";
605static const char CHAFSR_ISAP_msg[] =
606 "System request parity error on incoming addresss";
607static const char CHAFSR_UCU_msg[] =
608 "Uncorrectable E-cache ECC error for ifetch/data";
609static const char CHAFSR_UCC_msg[] =
610 "SW Correctable E-cache ECC error for ifetch/data";
611static const char CHAFSR_UE_msg[] =
612 "Uncorrectable system bus data ECC error for read";
613static const char CHAFSR_EDU_msg[] =
614 "Uncorrectable E-cache ECC error for stmerge/blkld";
615static const char CHAFSR_EMU_msg[] =
616 "Uncorrectable system bus MTAG error";
617static const char CHAFSR_WDU_msg[] =
618 "Uncorrectable E-cache ECC error for writeback";
619static const char CHAFSR_CPU_msg[] =
620 "Uncorrectable ECC error for copyout";
621static const char CHAFSR_CE_msg[] =
622 "HW corrected system bus data ECC error for read";
623static const char CHAFSR_EDC_msg[] =
624 "HW corrected E-cache ECC error for stmerge/blkld";
625static const char CHAFSR_EMC_msg[] =
626 "HW corrected system bus MTAG ECC error";
627static const char CHAFSR_WDC_msg[] =
628 "HW corrected E-cache ECC error for writeback";
629static const char CHAFSR_CPC_msg[] =
630 "HW corrected ECC error for copyout";
631static const char CHAFSR_TO_msg[] =
632 "Unmapped error from system bus";
633static const char CHAFSR_BERR_msg[] =
634 "Bus error response from system bus";
635static const char CHAFSR_IVC_msg[] =
636 "HW corrected system bus data ECC error for ivec read";
637static const char CHAFSR_IVU_msg[] =
638 "Uncorrectable system bus data ECC error for ivec read";
639static struct afsr_error_table __cheetah_error_table[] = {
640 { CHAFSR_PERR, CHAFSR_PERR_msg },
641 { CHAFSR_IERR, CHAFSR_IERR_msg },
642 { CHAFSR_ISAP, CHAFSR_ISAP_msg },
643 { CHAFSR_UCU, CHAFSR_UCU_msg },
644 { CHAFSR_UCC, CHAFSR_UCC_msg },
645 { CHAFSR_UE, CHAFSR_UE_msg },
646 { CHAFSR_EDU, CHAFSR_EDU_msg },
647 { CHAFSR_EMU, CHAFSR_EMU_msg },
648 { CHAFSR_WDU, CHAFSR_WDU_msg },
649 { CHAFSR_CPU, CHAFSR_CPU_msg },
650 { CHAFSR_CE, CHAFSR_CE_msg },
651 { CHAFSR_EDC, CHAFSR_EDC_msg },
652 { CHAFSR_EMC, CHAFSR_EMC_msg },
653 { CHAFSR_WDC, CHAFSR_WDC_msg },
654 { CHAFSR_CPC, CHAFSR_CPC_msg },
655 { CHAFSR_TO, CHAFSR_TO_msg },
656 { CHAFSR_BERR, CHAFSR_BERR_msg },
657 /* These two do not update the AFAR. */
658 { CHAFSR_IVC, CHAFSR_IVC_msg },
659 { CHAFSR_IVU, CHAFSR_IVU_msg },
660 { 0, NULL },
661};
662static const char CHPAFSR_DTO_msg[] =
663 "System bus unmapped error for prefetch/storequeue-read";
664static const char CHPAFSR_DBERR_msg[] =
665 "System bus error for prefetch/storequeue-read";
666static const char CHPAFSR_THCE_msg[] =
667 "Hardware corrected E-cache Tag ECC error";
668static const char CHPAFSR_TSCE_msg[] =
669 "SW handled correctable E-cache Tag ECC error";
670static const char CHPAFSR_TUE_msg[] =
671 "Uncorrectable E-cache Tag ECC error";
672static const char CHPAFSR_DUE_msg[] =
673 "System bus uncorrectable data ECC error due to prefetch/store-fill";
674static struct afsr_error_table __cheetah_plus_error_table[] = {
675 { CHAFSR_PERR, CHAFSR_PERR_msg },
676 { CHAFSR_IERR, CHAFSR_IERR_msg },
677 { CHAFSR_ISAP, CHAFSR_ISAP_msg },
678 { CHAFSR_UCU, CHAFSR_UCU_msg },
679 { CHAFSR_UCC, CHAFSR_UCC_msg },
680 { CHAFSR_UE, CHAFSR_UE_msg },
681 { CHAFSR_EDU, CHAFSR_EDU_msg },
682 { CHAFSR_EMU, CHAFSR_EMU_msg },
683 { CHAFSR_WDU, CHAFSR_WDU_msg },
684 { CHAFSR_CPU, CHAFSR_CPU_msg },
685 { CHAFSR_CE, CHAFSR_CE_msg },
686 { CHAFSR_EDC, CHAFSR_EDC_msg },
687 { CHAFSR_EMC, CHAFSR_EMC_msg },
688 { CHAFSR_WDC, CHAFSR_WDC_msg },
689 { CHAFSR_CPC, CHAFSR_CPC_msg },
690 { CHAFSR_TO, CHAFSR_TO_msg },
691 { CHAFSR_BERR, CHAFSR_BERR_msg },
692 { CHPAFSR_DTO, CHPAFSR_DTO_msg },
693 { CHPAFSR_DBERR, CHPAFSR_DBERR_msg },
694 { CHPAFSR_THCE, CHPAFSR_THCE_msg },
695 { CHPAFSR_TSCE, CHPAFSR_TSCE_msg },
696 { CHPAFSR_TUE, CHPAFSR_TUE_msg },
697 { CHPAFSR_DUE, CHPAFSR_DUE_msg },
698 /* These two do not update the AFAR. */
699 { CHAFSR_IVC, CHAFSR_IVC_msg },
700 { CHAFSR_IVU, CHAFSR_IVU_msg },
701 { 0, NULL },
702};
703static const char JPAFSR_JETO_msg[] =
704 "System interface protocol error, hw timeout caused";
705static const char JPAFSR_SCE_msg[] =
706 "Parity error on system snoop results";
707static const char JPAFSR_JEIC_msg[] =
708 "System interface protocol error, illegal command detected";
709static const char JPAFSR_JEIT_msg[] =
710 "System interface protocol error, illegal ADTYPE detected";
711static const char JPAFSR_OM_msg[] =
712 "Out of range memory error has occurred";
713static const char JPAFSR_ETP_msg[] =
714 "Parity error on L2 cache tag SRAM";
715static const char JPAFSR_UMS_msg[] =
716 "Error due to unsupported store";
717static const char JPAFSR_RUE_msg[] =
718 "Uncorrectable ECC error from remote cache/memory";
719static const char JPAFSR_RCE_msg[] =
720 "Correctable ECC error from remote cache/memory";
721static const char JPAFSR_BP_msg[] =
722 "JBUS parity error on returned read data";
723static const char JPAFSR_WBP_msg[] =
724 "JBUS parity error on data for writeback or block store";
725static const char JPAFSR_FRC_msg[] =
726 "Foreign read to DRAM incurring correctable ECC error";
727static const char JPAFSR_FRU_msg[] =
728 "Foreign read to DRAM incurring uncorrectable ECC error";
729static struct afsr_error_table __jalapeno_error_table[] = {
730 { JPAFSR_JETO, JPAFSR_JETO_msg },
731 { JPAFSR_SCE, JPAFSR_SCE_msg },
732 { JPAFSR_JEIC, JPAFSR_JEIC_msg },
733 { JPAFSR_JEIT, JPAFSR_JEIT_msg },
734 { CHAFSR_PERR, CHAFSR_PERR_msg },
735 { CHAFSR_IERR, CHAFSR_IERR_msg },
736 { CHAFSR_ISAP, CHAFSR_ISAP_msg },
737 { CHAFSR_UCU, CHAFSR_UCU_msg },
738 { CHAFSR_UCC, CHAFSR_UCC_msg },
739 { CHAFSR_UE, CHAFSR_UE_msg },
740 { CHAFSR_EDU, CHAFSR_EDU_msg },
741 { JPAFSR_OM, JPAFSR_OM_msg },
742 { CHAFSR_WDU, CHAFSR_WDU_msg },
743 { CHAFSR_CPU, CHAFSR_CPU_msg },
744 { CHAFSR_CE, CHAFSR_CE_msg },
745 { CHAFSR_EDC, CHAFSR_EDC_msg },
746 { JPAFSR_ETP, JPAFSR_ETP_msg },
747 { CHAFSR_WDC, CHAFSR_WDC_msg },
748 { CHAFSR_CPC, CHAFSR_CPC_msg },
749 { CHAFSR_TO, CHAFSR_TO_msg },
750 { CHAFSR_BERR, CHAFSR_BERR_msg },
751 { JPAFSR_UMS, JPAFSR_UMS_msg },
752 { JPAFSR_RUE, JPAFSR_RUE_msg },
753 { JPAFSR_RCE, JPAFSR_RCE_msg },
754 { JPAFSR_BP, JPAFSR_BP_msg },
755 { JPAFSR_WBP, JPAFSR_WBP_msg },
756 { JPAFSR_FRC, JPAFSR_FRC_msg },
757 { JPAFSR_FRU, JPAFSR_FRU_msg },
758 /* These two do not update the AFAR. */
759 { CHAFSR_IVU, CHAFSR_IVU_msg },
760 { 0, NULL },
761};
762static struct afsr_error_table *cheetah_error_table;
763static unsigned long cheetah_afsr_errors;
764
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765struct cheetah_err_info *cheetah_error_log;
766
David S. Millerd979f172007-10-27 00:13:04 -0700767static inline struct cheetah_err_info *cheetah_get_error_log(unsigned long afsr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768{
769 struct cheetah_err_info *p;
770 int cpu = smp_processor_id();
771
772 if (!cheetah_error_log)
773 return NULL;
774
775 p = cheetah_error_log + (cpu * 2);
776 if ((afsr & CHAFSR_TL1) != 0UL)
777 p++;
778
779 return p;
780}
781
782extern unsigned int tl0_icpe[], tl1_icpe[];
783extern unsigned int tl0_dcpe[], tl1_dcpe[];
784extern unsigned int tl0_fecc[], tl1_fecc[];
785extern unsigned int tl0_cee[], tl1_cee[];
786extern unsigned int tl0_iae[], tl1_iae[];
787extern unsigned int tl0_dae[], tl1_dae[];
788extern unsigned int cheetah_plus_icpe_trap_vector[], cheetah_plus_icpe_trap_vector_tl1[];
789extern unsigned int cheetah_plus_dcpe_trap_vector[], cheetah_plus_dcpe_trap_vector_tl1[];
790extern unsigned int cheetah_fecc_trap_vector[], cheetah_fecc_trap_vector_tl1[];
791extern unsigned int cheetah_cee_trap_vector[], cheetah_cee_trap_vector_tl1[];
792extern unsigned int cheetah_deferred_trap_vector[], cheetah_deferred_trap_vector_tl1[];
793
794void __init cheetah_ecache_flush_init(void)
795{
796 unsigned long largest_size, smallest_linesize, order, ver;
David S. Miller5cbc3072007-05-25 15:49:59 -0700797 int i, sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798
799 /* Scan all cpu device tree nodes, note two values:
800 * 1) largest E-cache size
801 * 2) smallest E-cache line size
802 */
803 largest_size = 0UL;
804 smallest_linesize = ~0UL;
805
David S. Miller5cbc3072007-05-25 15:49:59 -0700806 for (i = 0; i < NR_CPUS; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 unsigned long val;
808
David S. Miller5cbc3072007-05-25 15:49:59 -0700809 val = cpu_data(i).ecache_size;
810 if (!val)
811 continue;
812
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 if (val > largest_size)
814 largest_size = val;
David S. Miller5cbc3072007-05-25 15:49:59 -0700815
816 val = cpu_data(i).ecache_line_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 if (val < smallest_linesize)
818 smallest_linesize = val;
David S. Miller5cbc3072007-05-25 15:49:59 -0700819
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 }
821
822 if (largest_size == 0UL || smallest_linesize == ~0UL) {
823 prom_printf("cheetah_ecache_flush_init: Cannot probe cpu E-cache "
824 "parameters.\n");
825 prom_halt();
826 }
827
828 ecache_flush_size = (2 * largest_size);
829 ecache_flush_linesize = smallest_linesize;
830
David S. Miller10147572005-09-28 21:46:43 -0700831 ecache_flush_physbase = find_ecache_flush_span(ecache_flush_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
David S. Miller10147572005-09-28 21:46:43 -0700833 if (ecache_flush_physbase == ~0UL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 prom_printf("cheetah_ecache_flush_init: Cannot find %d byte "
David S. Miller10147572005-09-28 21:46:43 -0700835 "contiguous physical memory.\n",
836 ecache_flush_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 prom_halt();
838 }
839
840 /* Now allocate error trap reporting scoreboard. */
David S. Miller07f8e5f2006-06-21 23:34:02 -0700841 sz = NR_CPUS * (2 * sizeof(struct cheetah_err_info));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 for (order = 0; order < MAX_ORDER; order++) {
David S. Miller07f8e5f2006-06-21 23:34:02 -0700843 if ((PAGE_SIZE << order) >= sz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 break;
845 }
846 cheetah_error_log = (struct cheetah_err_info *)
847 __get_free_pages(GFP_KERNEL, order);
848 if (!cheetah_error_log) {
849 prom_printf("cheetah_ecache_flush_init: Failed to allocate "
David S. Miller07f8e5f2006-06-21 23:34:02 -0700850 "error logging scoreboard (%d bytes).\n", sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 prom_halt();
852 }
853 memset(cheetah_error_log, 0, PAGE_SIZE << order);
854
855 /* Mark all AFSRs as invalid so that the trap handler will
856 * log new new information there.
857 */
858 for (i = 0; i < 2 * NR_CPUS; i++)
859 cheetah_error_log[i].afsr = CHAFSR_INVALID;
860
861 __asm__ ("rdpr %%ver, %0" : "=r" (ver));
David S. Miller92704a12006-02-26 23:27:19 -0800862 if ((ver >> 32) == __JALAPENO_ID ||
863 (ver >> 32) == __SERRANO_ID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 cheetah_error_table = &__jalapeno_error_table[0];
865 cheetah_afsr_errors = JPAFSR_ERRORS;
866 } else if ((ver >> 32) == 0x003e0015) {
867 cheetah_error_table = &__cheetah_plus_error_table[0];
868 cheetah_afsr_errors = CHPAFSR_ERRORS;
869 } else {
870 cheetah_error_table = &__cheetah_error_table[0];
871 cheetah_afsr_errors = CHAFSR_ERRORS;
872 }
873
874 /* Now patch trap tables. */
875 memcpy(tl0_fecc, cheetah_fecc_trap_vector, (8 * 4));
876 memcpy(tl1_fecc, cheetah_fecc_trap_vector_tl1, (8 * 4));
877 memcpy(tl0_cee, cheetah_cee_trap_vector, (8 * 4));
878 memcpy(tl1_cee, cheetah_cee_trap_vector_tl1, (8 * 4));
879 memcpy(tl0_iae, cheetah_deferred_trap_vector, (8 * 4));
880 memcpy(tl1_iae, cheetah_deferred_trap_vector_tl1, (8 * 4));
881 memcpy(tl0_dae, cheetah_deferred_trap_vector, (8 * 4));
882 memcpy(tl1_dae, cheetah_deferred_trap_vector_tl1, (8 * 4));
883 if (tlb_type == cheetah_plus) {
884 memcpy(tl0_dcpe, cheetah_plus_dcpe_trap_vector, (8 * 4));
885 memcpy(tl1_dcpe, cheetah_plus_dcpe_trap_vector_tl1, (8 * 4));
886 memcpy(tl0_icpe, cheetah_plus_icpe_trap_vector, (8 * 4));
887 memcpy(tl1_icpe, cheetah_plus_icpe_trap_vector_tl1, (8 * 4));
888 }
889 flushi(PAGE_OFFSET);
890}
891
892static void cheetah_flush_ecache(void)
893{
894 unsigned long flush_base = ecache_flush_physbase;
895 unsigned long flush_linesize = ecache_flush_linesize;
896 unsigned long flush_size = ecache_flush_size;
897
898 __asm__ __volatile__("1: subcc %0, %4, %0\n\t"
899 " bne,pt %%xcc, 1b\n\t"
900 " ldxa [%2 + %0] %3, %%g0\n\t"
901 : "=&r" (flush_size)
902 : "0" (flush_size), "r" (flush_base),
903 "i" (ASI_PHYS_USE_EC), "r" (flush_linesize));
904}
905
906static void cheetah_flush_ecache_line(unsigned long physaddr)
907{
908 unsigned long alias;
909
910 physaddr &= ~(8UL - 1UL);
911 physaddr = (ecache_flush_physbase +
912 (physaddr & ((ecache_flush_size>>1UL) - 1UL)));
913 alias = physaddr + (ecache_flush_size >> 1UL);
914 __asm__ __volatile__("ldxa [%0] %2, %%g0\n\t"
915 "ldxa [%1] %2, %%g0\n\t"
916 "membar #Sync"
917 : /* no outputs */
918 : "r" (physaddr), "r" (alias),
919 "i" (ASI_PHYS_USE_EC));
920}
921
922/* Unfortunately, the diagnostic access to the I-cache tags we need to
923 * use to clear the thing interferes with I-cache coherency transactions.
924 *
925 * So we must only flush the I-cache when it is disabled.
926 */
927static void __cheetah_flush_icache(void)
928{
David S. Miller80dc0d62005-09-26 00:32:17 -0700929 unsigned int icache_size, icache_line_size;
930 unsigned long addr;
931
932 icache_size = local_cpu_data().icache_size;
933 icache_line_size = local_cpu_data().icache_line_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934
935 /* Clear the valid bits in all the tags. */
David S. Miller80dc0d62005-09-26 00:32:17 -0700936 for (addr = 0; addr < icache_size; addr += icache_line_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 __asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
938 "membar #Sync"
939 : /* no outputs */
David S. Miller80dc0d62005-09-26 00:32:17 -0700940 : "r" (addr | (2 << 3)),
941 "i" (ASI_IC_TAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 }
943}
944
945static void cheetah_flush_icache(void)
946{
947 unsigned long dcu_save;
948
949 /* Save current DCU, disable I-cache. */
950 __asm__ __volatile__("ldxa [%%g0] %1, %0\n\t"
951 "or %0, %2, %%g1\n\t"
952 "stxa %%g1, [%%g0] %1\n\t"
953 "membar #Sync"
954 : "=r" (dcu_save)
955 : "i" (ASI_DCU_CONTROL_REG), "i" (DCU_IC)
956 : "g1");
957
958 __cheetah_flush_icache();
959
960 /* Restore DCU register */
961 __asm__ __volatile__("stxa %0, [%%g0] %1\n\t"
962 "membar #Sync"
963 : /* no outputs */
964 : "r" (dcu_save), "i" (ASI_DCU_CONTROL_REG));
965}
966
967static void cheetah_flush_dcache(void)
968{
David S. Miller80dc0d62005-09-26 00:32:17 -0700969 unsigned int dcache_size, dcache_line_size;
970 unsigned long addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971
David S. Miller80dc0d62005-09-26 00:32:17 -0700972 dcache_size = local_cpu_data().dcache_size;
973 dcache_line_size = local_cpu_data().dcache_line_size;
974
975 for (addr = 0; addr < dcache_size; addr += dcache_line_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 __asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
977 "membar #Sync"
978 : /* no outputs */
David S. Miller80dc0d62005-09-26 00:32:17 -0700979 : "r" (addr), "i" (ASI_DCACHE_TAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 }
981}
982
983/* In order to make the even parity correct we must do two things.
984 * First, we clear DC_data_parity and set DC_utag to an appropriate value.
985 * Next, we clear out all 32-bytes of data for that line. Data of
986 * all-zero + tag parity value of zero == correct parity.
987 */
988static void cheetah_plus_zap_dcache_parity(void)
989{
David S. Miller80dc0d62005-09-26 00:32:17 -0700990 unsigned int dcache_size, dcache_line_size;
991 unsigned long addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
David S. Miller80dc0d62005-09-26 00:32:17 -0700993 dcache_size = local_cpu_data().dcache_size;
994 dcache_line_size = local_cpu_data().dcache_line_size;
995
996 for (addr = 0; addr < dcache_size; addr += dcache_line_size) {
997 unsigned long tag = (addr >> 14);
998 unsigned long line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999
1000 __asm__ __volatile__("membar #Sync\n\t"
1001 "stxa %0, [%1] %2\n\t"
1002 "membar #Sync"
1003 : /* no outputs */
David S. Miller80dc0d62005-09-26 00:32:17 -07001004 : "r" (tag), "r" (addr),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 "i" (ASI_DCACHE_UTAG));
David S. Miller80dc0d62005-09-26 00:32:17 -07001006 for (line = addr; line < addr + dcache_line_size; line += 8)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 __asm__ __volatile__("membar #Sync\n\t"
1008 "stxa %%g0, [%0] %1\n\t"
1009 "membar #Sync"
1010 : /* no outputs */
David S. Miller80dc0d62005-09-26 00:32:17 -07001011 : "r" (line),
1012 "i" (ASI_DCACHE_DATA));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 }
1014}
1015
1016/* Conversion tables used to frob Cheetah AFSR syndrome values into
1017 * something palatable to the memory controller driver get_unumber
1018 * routine.
1019 */
1020#define MT0 137
1021#define MT1 138
1022#define MT2 139
1023#define NONE 254
1024#define MTC0 140
1025#define MTC1 141
1026#define MTC2 142
1027#define MTC3 143
1028#define C0 128
1029#define C1 129
1030#define C2 130
1031#define C3 131
1032#define C4 132
1033#define C5 133
1034#define C6 134
1035#define C7 135
1036#define C8 136
1037#define M2 144
1038#define M3 145
1039#define M4 146
1040#define M 147
1041static unsigned char cheetah_ecc_syntab[] = {
1042/*00*/NONE, C0, C1, M2, C2, M2, M3, 47, C3, M2, M2, 53, M2, 41, 29, M,
1043/*01*/C4, M, M, 50, M2, 38, 25, M2, M2, 33, 24, M2, 11, M, M2, 16,
1044/*02*/C5, M, M, 46, M2, 37, 19, M2, M, 31, 32, M, 7, M2, M2, 10,
1045/*03*/M2, 40, 13, M2, 59, M, M2, 66, M, M2, M2, 0, M2, 67, 71, M,
1046/*04*/C6, M, M, 43, M, 36, 18, M, M2, 49, 15, M, 63, M2, M2, 6,
1047/*05*/M2, 44, 28, M2, M, M2, M2, 52, 68, M2, M2, 62, M2, M3, M3, M4,
1048/*06*/M2, 26, 106, M2, 64, M, M2, 2, 120, M, M2, M3, M, M3, M3, M4,
1049/*07*/116, M2, M2, M3, M2, M3, M, M4, M2, 58, 54, M2, M, M4, M4, M3,
1050/*08*/C7, M2, M, 42, M, 35, 17, M2, M, 45, 14, M2, 21, M2, M2, 5,
1051/*09*/M, 27, M, M, 99, M, M, 3, 114, M2, M2, 20, M2, M3, M3, M,
1052/*0a*/M2, 23, 113, M2, 112, M2, M, 51, 95, M, M2, M3, M2, M3, M3, M2,
1053/*0b*/103, M, M2, M3, M2, M3, M3, M4, M2, 48, M, M, 73, M2, M, M3,
1054/*0c*/M2, 22, 110, M2, 109, M2, M, 9, 108, M2, M, M3, M2, M3, M3, M,
1055/*0d*/102, M2, M, M, M2, M3, M3, M, M2, M3, M3, M2, M, M4, M, M3,
1056/*0e*/98, M, M2, M3, M2, M, M3, M4, M2, M3, M3, M4, M3, M, M, M,
1057/*0f*/M2, M3, M3, M, M3, M, M, M, 56, M4, M, M3, M4, M, M, M,
1058/*10*/C8, M, M2, 39, M, 34, 105, M2, M, 30, 104, M, 101, M, M, 4,
1059/*11*/M, M, 100, M, 83, M, M2, 12, 87, M, M, 57, M2, M, M3, M,
1060/*12*/M2, 97, 82, M2, 78, M2, M2, 1, 96, M, M, M, M, M, M3, M2,
1061/*13*/94, M, M2, M3, M2, M, M3, M, M2, M, 79, M, 69, M, M4, M,
1062/*14*/M2, 93, 92, M, 91, M, M2, 8, 90, M2, M2, M, M, M, M, M4,
1063/*15*/89, M, M, M3, M2, M3, M3, M, M, M, M3, M2, M3, M2, M, M3,
1064/*16*/86, M, M2, M3, M2, M, M3, M, M2, M, M3, M, M3, M, M, M3,
1065/*17*/M, M, M3, M2, M3, M2, M4, M, 60, M, M2, M3, M4, M, M, M2,
1066/*18*/M2, 88, 85, M2, 84, M, M2, 55, 81, M2, M2, M3, M2, M3, M3, M4,
1067/*19*/77, M, M, M, M2, M3, M, M, M2, M3, M3, M4, M3, M2, M, M,
1068/*1a*/74, M, M2, M3, M, M, M3, M, M, M, M3, M, M3, M, M4, M3,
1069/*1b*/M2, 70, 107, M4, 65, M2, M2, M, 127, M, M, M, M2, M3, M3, M,
1070/*1c*/80, M2, M2, 72, M, 119, 118, M, M2, 126, 76, M, 125, M, M4, M3,
1071/*1d*/M2, 115, 124, M, 75, M, M, M3, 61, M, M4, M, M4, M, M, M,
1072/*1e*/M, 123, 122, M4, 121, M4, M, M3, 117, M2, M2, M3, M4, M3, M, M,
1073/*1f*/111, M, M, M, M4, M3, M3, M, M, M, M3, M, M3, M2, M, M
1074};
1075static unsigned char cheetah_mtag_syntab[] = {
1076 NONE, MTC0,
1077 MTC1, NONE,
1078 MTC2, NONE,
1079 NONE, MT0,
1080 MTC3, NONE,
1081 NONE, MT1,
1082 NONE, MT2,
1083 NONE, NONE
1084};
1085
1086/* Return the highest priority error conditon mentioned. */
David S. Millerd979f172007-10-27 00:13:04 -07001087static inline unsigned long cheetah_get_hipri(unsigned long afsr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088{
1089 unsigned long tmp = 0;
1090 int i;
1091
1092 for (i = 0; cheetah_error_table[i].mask; i++) {
1093 if ((tmp = (afsr & cheetah_error_table[i].mask)) != 0UL)
1094 return tmp;
1095 }
1096 return tmp;
1097}
1098
1099static const char *cheetah_get_string(unsigned long bit)
1100{
1101 int i;
1102
1103 for (i = 0; cheetah_error_table[i].mask; i++) {
1104 if ((bit & cheetah_error_table[i].mask) != 0UL)
1105 return cheetah_error_table[i].name;
1106 }
1107 return "???";
1108}
1109
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110static void cheetah_log_errors(struct pt_regs *regs, struct cheetah_err_info *info,
1111 unsigned long afsr, unsigned long afar, int recoverable)
1112{
1113 unsigned long hipri;
1114 char unum[256];
1115
1116 printk("%s" "ERROR(%d): Cheetah error trap taken afsr[%016lx] afar[%016lx] TL1(%d)\n",
1117 (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
1118 afsr, afar,
1119 (afsr & CHAFSR_TL1) ? 1 : 0);
David S. Miller955c0542006-04-01 23:29:56 -08001120 printk("%s" "ERROR(%d): TPC[%lx] TNPC[%lx] O7[%lx] TSTATE[%lx]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
David S. Miller955c0542006-04-01 23:29:56 -08001122 regs->tpc, regs->tnpc, regs->u_regs[UREG_I7], regs->tstate);
David S. Miller5af47db2006-10-30 01:10:20 -08001123 printk("%s" "ERROR(%d): ",
1124 (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id());
David S. Miller4fe3ebe2008-07-17 22:11:32 -07001125 printk("TPC<%pS>\n", (void *) regs->tpc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 printk("%s" "ERROR(%d): M_SYND(%lx), E_SYND(%lx)%s%s\n",
1127 (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
1128 (afsr & CHAFSR_M_SYNDROME) >> CHAFSR_M_SYNDROME_SHIFT,
1129 (afsr & CHAFSR_E_SYNDROME) >> CHAFSR_E_SYNDROME_SHIFT,
1130 (afsr & CHAFSR_ME) ? ", Multiple Errors" : "",
1131 (afsr & CHAFSR_PRIV) ? ", Privileged" : "");
1132 hipri = cheetah_get_hipri(afsr);
1133 printk("%s" "ERROR(%d): Highest priority error (%016lx) \"%s\"\n",
1134 (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
1135 hipri, cheetah_get_string(hipri));
1136
1137 /* Try to get unumber if relevant. */
1138#define ESYND_ERRORS (CHAFSR_IVC | CHAFSR_IVU | \
1139 CHAFSR_CPC | CHAFSR_CPU | \
1140 CHAFSR_UE | CHAFSR_CE | \
1141 CHAFSR_EDC | CHAFSR_EDU | \
1142 CHAFSR_UCC | CHAFSR_UCU | \
1143 CHAFSR_WDU | CHAFSR_WDC)
1144#define MSYND_ERRORS (CHAFSR_EMC | CHAFSR_EMU)
1145 if (afsr & ESYND_ERRORS) {
1146 int syndrome;
1147 int ret;
1148
1149 syndrome = (afsr & CHAFSR_E_SYNDROME) >> CHAFSR_E_SYNDROME_SHIFT;
1150 syndrome = cheetah_ecc_syntab[syndrome];
David S. Miller881d0212008-08-24 22:08:34 -07001151 ret = sprintf_dimm(syndrome, afar, unum, sizeof(unum));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 if (ret != -1)
1153 printk("%s" "ERROR(%d): AFAR E-syndrome [%s]\n",
1154 (recoverable ? KERN_WARNING : KERN_CRIT),
1155 smp_processor_id(), unum);
1156 } else if (afsr & MSYND_ERRORS) {
1157 int syndrome;
1158 int ret;
1159
1160 syndrome = (afsr & CHAFSR_M_SYNDROME) >> CHAFSR_M_SYNDROME_SHIFT;
1161 syndrome = cheetah_mtag_syntab[syndrome];
David S. Miller881d0212008-08-24 22:08:34 -07001162 ret = sprintf_dimm(syndrome, afar, unum, sizeof(unum));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 if (ret != -1)
1164 printk("%s" "ERROR(%d): AFAR M-syndrome [%s]\n",
1165 (recoverable ? KERN_WARNING : KERN_CRIT),
1166 smp_processor_id(), unum);
1167 }
1168
1169 /* Now dump the cache snapshots. */
1170 printk("%s" "ERROR(%d): D-cache idx[%x] tag[%016lx] utag[%016lx] stag[%016lx]\n",
1171 (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
1172 (int) info->dcache_index,
1173 info->dcache_tag,
1174 info->dcache_utag,
1175 info->dcache_stag);
1176 printk("%s" "ERROR(%d): D-cache data0[%016lx] data1[%016lx] data2[%016lx] data3[%016lx]\n",
1177 (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
1178 info->dcache_data[0],
1179 info->dcache_data[1],
1180 info->dcache_data[2],
1181 info->dcache_data[3]);
1182 printk("%s" "ERROR(%d): I-cache idx[%x] tag[%016lx] utag[%016lx] stag[%016lx] "
1183 "u[%016lx] l[%016lx]\n",
1184 (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
1185 (int) info->icache_index,
1186 info->icache_tag,
1187 info->icache_utag,
1188 info->icache_stag,
1189 info->icache_upper,
1190 info->icache_lower);
1191 printk("%s" "ERROR(%d): I-cache INSN0[%016lx] INSN1[%016lx] INSN2[%016lx] INSN3[%016lx]\n",
1192 (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
1193 info->icache_data[0],
1194 info->icache_data[1],
1195 info->icache_data[2],
1196 info->icache_data[3]);
1197 printk("%s" "ERROR(%d): I-cache INSN4[%016lx] INSN5[%016lx] INSN6[%016lx] INSN7[%016lx]\n",
1198 (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
1199 info->icache_data[4],
1200 info->icache_data[5],
1201 info->icache_data[6],
1202 info->icache_data[7]);
1203 printk("%s" "ERROR(%d): E-cache idx[%x] tag[%016lx]\n",
1204 (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
1205 (int) info->ecache_index, info->ecache_tag);
1206 printk("%s" "ERROR(%d): E-cache data0[%016lx] data1[%016lx] data2[%016lx] data3[%016lx]\n",
1207 (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
1208 info->ecache_data[0],
1209 info->ecache_data[1],
1210 info->ecache_data[2],
1211 info->ecache_data[3]);
1212
1213 afsr = (afsr & ~hipri) & cheetah_afsr_errors;
1214 while (afsr != 0UL) {
1215 unsigned long bit = cheetah_get_hipri(afsr);
1216
1217 printk("%s" "ERROR: Multiple-error (%016lx) \"%s\"\n",
1218 (recoverable ? KERN_WARNING : KERN_CRIT),
1219 bit, cheetah_get_string(bit));
1220
1221 afsr &= ~bit;
1222 }
1223
1224 if (!recoverable)
1225 printk(KERN_CRIT "ERROR: This condition is not recoverable.\n");
1226}
1227
1228static int cheetah_recheck_errors(struct cheetah_err_info *logp)
1229{
1230 unsigned long afsr, afar;
1231 int ret = 0;
1232
1233 __asm__ __volatile__("ldxa [%%g0] %1, %0\n\t"
1234 : "=r" (afsr)
1235 : "i" (ASI_AFSR));
1236 if ((afsr & cheetah_afsr_errors) != 0) {
1237 if (logp != NULL) {
1238 __asm__ __volatile__("ldxa [%%g0] %1, %0\n\t"
1239 : "=r" (afar)
1240 : "i" (ASI_AFAR));
1241 logp->afsr = afsr;
1242 logp->afar = afar;
1243 }
1244 ret = 1;
1245 }
1246 __asm__ __volatile__("stxa %0, [%%g0] %1\n\t"
1247 "membar #Sync\n\t"
1248 : : "r" (afsr), "i" (ASI_AFSR));
1249
1250 return ret;
1251}
1252
1253void cheetah_fecc_handler(struct pt_regs *regs, unsigned long afsr, unsigned long afar)
1254{
1255 struct cheetah_err_info local_snapshot, *p;
1256 int recoverable;
1257
1258 /* Flush E-cache */
1259 cheetah_flush_ecache();
1260
1261 p = cheetah_get_error_log(afsr);
1262 if (!p) {
1263 prom_printf("ERROR: Early Fast-ECC error afsr[%016lx] afar[%016lx]\n",
1264 afsr, afar);
1265 prom_printf("ERROR: CPU(%d) TPC[%016lx] TNPC[%016lx] TSTATE[%016lx]\n",
1266 smp_processor_id(), regs->tpc, regs->tnpc, regs->tstate);
1267 prom_halt();
1268 }
1269
1270 /* Grab snapshot of logged error. */
1271 memcpy(&local_snapshot, p, sizeof(local_snapshot));
1272
1273 /* If the current trap snapshot does not match what the
1274 * trap handler passed along into our args, big trouble.
1275 * In such a case, mark the local copy as invalid.
1276 *
1277 * Else, it matches and we mark the afsr in the non-local
1278 * copy as invalid so we may log new error traps there.
1279 */
1280 if (p->afsr != afsr || p->afar != afar)
1281 local_snapshot.afsr = CHAFSR_INVALID;
1282 else
1283 p->afsr = CHAFSR_INVALID;
1284
1285 cheetah_flush_icache();
1286 cheetah_flush_dcache();
1287
1288 /* Re-enable I-cache/D-cache */
1289 __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
1290 "or %%g1, %1, %%g1\n\t"
1291 "stxa %%g1, [%%g0] %0\n\t"
1292 "membar #Sync"
1293 : /* no outputs */
1294 : "i" (ASI_DCU_CONTROL_REG),
1295 "i" (DCU_DC | DCU_IC)
1296 : "g1");
1297
1298 /* Re-enable error reporting */
1299 __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
1300 "or %%g1, %1, %%g1\n\t"
1301 "stxa %%g1, [%%g0] %0\n\t"
1302 "membar #Sync"
1303 : /* no outputs */
1304 : "i" (ASI_ESTATE_ERROR_EN),
1305 "i" (ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN)
1306 : "g1");
1307
1308 /* Decide if we can continue after handling this trap and
1309 * logging the error.
1310 */
1311 recoverable = 1;
1312 if (afsr & (CHAFSR_PERR | CHAFSR_IERR | CHAFSR_ISAP))
1313 recoverable = 0;
1314
1315 /* Re-check AFSR/AFAR. What we are looking for here is whether a new
1316 * error was logged while we had error reporting traps disabled.
1317 */
1318 if (cheetah_recheck_errors(&local_snapshot)) {
1319 unsigned long new_afsr = local_snapshot.afsr;
1320
1321 /* If we got a new asynchronous error, die... */
1322 if (new_afsr & (CHAFSR_EMU | CHAFSR_EDU |
1323 CHAFSR_WDU | CHAFSR_CPU |
1324 CHAFSR_IVU | CHAFSR_UE |
1325 CHAFSR_BERR | CHAFSR_TO))
1326 recoverable = 0;
1327 }
1328
1329 /* Log errors. */
1330 cheetah_log_errors(regs, &local_snapshot, afsr, afar, recoverable);
1331
1332 if (!recoverable)
1333 panic("Irrecoverable Fast-ECC error trap.\n");
1334
1335 /* Flush E-cache to kick the error trap handlers out. */
1336 cheetah_flush_ecache();
1337}
1338
1339/* Try to fix a correctable error by pushing the line out from
1340 * the E-cache. Recheck error reporting registers to see if the
1341 * problem is intermittent.
1342 */
1343static int cheetah_fix_ce(unsigned long physaddr)
1344{
1345 unsigned long orig_estate;
1346 unsigned long alias1, alias2;
1347 int ret;
1348
1349 /* Make sure correctable error traps are disabled. */
1350 __asm__ __volatile__("ldxa [%%g0] %2, %0\n\t"
1351 "andn %0, %1, %%g1\n\t"
1352 "stxa %%g1, [%%g0] %2\n\t"
1353 "membar #Sync"
1354 : "=&r" (orig_estate)
1355 : "i" (ESTATE_ERROR_CEEN),
1356 "i" (ASI_ESTATE_ERROR_EN)
1357 : "g1");
1358
1359 /* We calculate alias addresses that will force the
1360 * cache line in question out of the E-cache. Then
1361 * we bring it back in with an atomic instruction so
1362 * that we get it in some modified/exclusive state,
1363 * then we displace it again to try and get proper ECC
1364 * pushed back into the system.
1365 */
1366 physaddr &= ~(8UL - 1UL);
1367 alias1 = (ecache_flush_physbase +
1368 (physaddr & ((ecache_flush_size >> 1) - 1)));
1369 alias2 = alias1 + (ecache_flush_size >> 1);
1370 __asm__ __volatile__("ldxa [%0] %3, %%g0\n\t"
1371 "ldxa [%1] %3, %%g0\n\t"
1372 "casxa [%2] %3, %%g0, %%g0\n\t"
1373 "membar #StoreLoad | #StoreStore\n\t"
1374 "ldxa [%0] %3, %%g0\n\t"
1375 "ldxa [%1] %3, %%g0\n\t"
1376 "membar #Sync"
1377 : /* no outputs */
1378 : "r" (alias1), "r" (alias2),
1379 "r" (physaddr), "i" (ASI_PHYS_USE_EC));
1380
1381 /* Did that trigger another error? */
1382 if (cheetah_recheck_errors(NULL)) {
1383 /* Try one more time. */
1384 __asm__ __volatile__("ldxa [%0] %1, %%g0\n\t"
1385 "membar #Sync"
1386 : : "r" (physaddr), "i" (ASI_PHYS_USE_EC));
1387 if (cheetah_recheck_errors(NULL))
1388 ret = 2;
1389 else
1390 ret = 1;
1391 } else {
1392 /* No new error, intermittent problem. */
1393 ret = 0;
1394 }
1395
1396 /* Restore error enables. */
1397 __asm__ __volatile__("stxa %0, [%%g0] %1\n\t"
1398 "membar #Sync"
1399 : : "r" (orig_estate), "i" (ASI_ESTATE_ERROR_EN));
1400
1401 return ret;
1402}
1403
1404/* Return non-zero if PADDR is a valid physical memory address. */
1405static int cheetah_check_main_memory(unsigned long paddr)
1406{
David S. Miller10147572005-09-28 21:46:43 -07001407 unsigned long vaddr = PAGE_OFFSET + paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408
David S. Miller13edad72005-09-29 17:58:26 -07001409 if (vaddr > (unsigned long) high_memory)
David S. Millered3ffaf2005-09-28 21:48:25 -07001410 return 0;
1411
David S. Miller10147572005-09-28 21:46:43 -07001412 return kern_addr_valid(vaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413}
1414
1415void cheetah_cee_handler(struct pt_regs *regs, unsigned long afsr, unsigned long afar)
1416{
1417 struct cheetah_err_info local_snapshot, *p;
1418 int recoverable, is_memory;
1419
1420 p = cheetah_get_error_log(afsr);
1421 if (!p) {
1422 prom_printf("ERROR: Early CEE error afsr[%016lx] afar[%016lx]\n",
1423 afsr, afar);
1424 prom_printf("ERROR: CPU(%d) TPC[%016lx] TNPC[%016lx] TSTATE[%016lx]\n",
1425 smp_processor_id(), regs->tpc, regs->tnpc, regs->tstate);
1426 prom_halt();
1427 }
1428
1429 /* Grab snapshot of logged error. */
1430 memcpy(&local_snapshot, p, sizeof(local_snapshot));
1431
1432 /* If the current trap snapshot does not match what the
1433 * trap handler passed along into our args, big trouble.
1434 * In such a case, mark the local copy as invalid.
1435 *
1436 * Else, it matches and we mark the afsr in the non-local
1437 * copy as invalid so we may log new error traps there.
1438 */
1439 if (p->afsr != afsr || p->afar != afar)
1440 local_snapshot.afsr = CHAFSR_INVALID;
1441 else
1442 p->afsr = CHAFSR_INVALID;
1443
1444 is_memory = cheetah_check_main_memory(afar);
1445
1446 if (is_memory && (afsr & CHAFSR_CE) != 0UL) {
1447 /* XXX Might want to log the results of this operation
1448 * XXX somewhere... -DaveM
1449 */
1450 cheetah_fix_ce(afar);
1451 }
1452
1453 {
1454 int flush_all, flush_line;
1455
1456 flush_all = flush_line = 0;
1457 if ((afsr & CHAFSR_EDC) != 0UL) {
1458 if ((afsr & cheetah_afsr_errors) == CHAFSR_EDC)
1459 flush_line = 1;
1460 else
1461 flush_all = 1;
1462 } else if ((afsr & CHAFSR_CPC) != 0UL) {
1463 if ((afsr & cheetah_afsr_errors) == CHAFSR_CPC)
1464 flush_line = 1;
1465 else
1466 flush_all = 1;
1467 }
1468
1469 /* Trap handler only disabled I-cache, flush it. */
1470 cheetah_flush_icache();
1471
1472 /* Re-enable I-cache */
1473 __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
1474 "or %%g1, %1, %%g1\n\t"
1475 "stxa %%g1, [%%g0] %0\n\t"
1476 "membar #Sync"
1477 : /* no outputs */
1478 : "i" (ASI_DCU_CONTROL_REG),
1479 "i" (DCU_IC)
1480 : "g1");
1481
1482 if (flush_all)
1483 cheetah_flush_ecache();
1484 else if (flush_line)
1485 cheetah_flush_ecache_line(afar);
1486 }
1487
1488 /* Re-enable error reporting */
1489 __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
1490 "or %%g1, %1, %%g1\n\t"
1491 "stxa %%g1, [%%g0] %0\n\t"
1492 "membar #Sync"
1493 : /* no outputs */
1494 : "i" (ASI_ESTATE_ERROR_EN),
1495 "i" (ESTATE_ERROR_CEEN)
1496 : "g1");
1497
1498 /* Decide if we can continue after handling this trap and
1499 * logging the error.
1500 */
1501 recoverable = 1;
1502 if (afsr & (CHAFSR_PERR | CHAFSR_IERR | CHAFSR_ISAP))
1503 recoverable = 0;
1504
1505 /* Re-check AFSR/AFAR */
1506 (void) cheetah_recheck_errors(&local_snapshot);
1507
1508 /* Log errors. */
1509 cheetah_log_errors(regs, &local_snapshot, afsr, afar, recoverable);
1510
1511 if (!recoverable)
1512 panic("Irrecoverable Correctable-ECC error trap.\n");
1513}
1514
1515void cheetah_deferred_handler(struct pt_regs *regs, unsigned long afsr, unsigned long afar)
1516{
1517 struct cheetah_err_info local_snapshot, *p;
1518 int recoverable, is_memory;
1519
1520#ifdef CONFIG_PCI
1521 /* Check for the special PCI poke sequence. */
1522 if (pci_poke_in_progress && pci_poke_cpu == smp_processor_id()) {
1523 cheetah_flush_icache();
1524 cheetah_flush_dcache();
1525
1526 /* Re-enable I-cache/D-cache */
1527 __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
1528 "or %%g1, %1, %%g1\n\t"
1529 "stxa %%g1, [%%g0] %0\n\t"
1530 "membar #Sync"
1531 : /* no outputs */
1532 : "i" (ASI_DCU_CONTROL_REG),
1533 "i" (DCU_DC | DCU_IC)
1534 : "g1");
1535
1536 /* Re-enable error reporting */
1537 __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
1538 "or %%g1, %1, %%g1\n\t"
1539 "stxa %%g1, [%%g0] %0\n\t"
1540 "membar #Sync"
1541 : /* no outputs */
1542 : "i" (ASI_ESTATE_ERROR_EN),
1543 "i" (ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN)
1544 : "g1");
1545
1546 (void) cheetah_recheck_errors(NULL);
1547
1548 pci_poke_faulted = 1;
1549 regs->tpc += 4;
1550 regs->tnpc = regs->tpc + 4;
1551 return;
1552 }
1553#endif
1554
1555 p = cheetah_get_error_log(afsr);
1556 if (!p) {
1557 prom_printf("ERROR: Early deferred error afsr[%016lx] afar[%016lx]\n",
1558 afsr, afar);
1559 prom_printf("ERROR: CPU(%d) TPC[%016lx] TNPC[%016lx] TSTATE[%016lx]\n",
1560 smp_processor_id(), regs->tpc, regs->tnpc, regs->tstate);
1561 prom_halt();
1562 }
1563
1564 /* Grab snapshot of logged error. */
1565 memcpy(&local_snapshot, p, sizeof(local_snapshot));
1566
1567 /* If the current trap snapshot does not match what the
1568 * trap handler passed along into our args, big trouble.
1569 * In such a case, mark the local copy as invalid.
1570 *
1571 * Else, it matches and we mark the afsr in the non-local
1572 * copy as invalid so we may log new error traps there.
1573 */
1574 if (p->afsr != afsr || p->afar != afar)
1575 local_snapshot.afsr = CHAFSR_INVALID;
1576 else
1577 p->afsr = CHAFSR_INVALID;
1578
1579 is_memory = cheetah_check_main_memory(afar);
1580
1581 {
1582 int flush_all, flush_line;
1583
1584 flush_all = flush_line = 0;
1585 if ((afsr & CHAFSR_EDU) != 0UL) {
1586 if ((afsr & cheetah_afsr_errors) == CHAFSR_EDU)
1587 flush_line = 1;
1588 else
1589 flush_all = 1;
1590 } else if ((afsr & CHAFSR_BERR) != 0UL) {
1591 if ((afsr & cheetah_afsr_errors) == CHAFSR_BERR)
1592 flush_line = 1;
1593 else
1594 flush_all = 1;
1595 }
1596
1597 cheetah_flush_icache();
1598 cheetah_flush_dcache();
1599
1600 /* Re-enable I/D caches */
1601 __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
1602 "or %%g1, %1, %%g1\n\t"
1603 "stxa %%g1, [%%g0] %0\n\t"
1604 "membar #Sync"
1605 : /* no outputs */
1606 : "i" (ASI_DCU_CONTROL_REG),
1607 "i" (DCU_IC | DCU_DC)
1608 : "g1");
1609
1610 if (flush_all)
1611 cheetah_flush_ecache();
1612 else if (flush_line)
1613 cheetah_flush_ecache_line(afar);
1614 }
1615
1616 /* Re-enable error reporting */
1617 __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
1618 "or %%g1, %1, %%g1\n\t"
1619 "stxa %%g1, [%%g0] %0\n\t"
1620 "membar #Sync"
1621 : /* no outputs */
1622 : "i" (ASI_ESTATE_ERROR_EN),
1623 "i" (ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN)
1624 : "g1");
1625
1626 /* Decide if we can continue after handling this trap and
1627 * logging the error.
1628 */
1629 recoverable = 1;
1630 if (afsr & (CHAFSR_PERR | CHAFSR_IERR | CHAFSR_ISAP))
1631 recoverable = 0;
1632
1633 /* Re-check AFSR/AFAR. What we are looking for here is whether a new
1634 * error was logged while we had error reporting traps disabled.
1635 */
1636 if (cheetah_recheck_errors(&local_snapshot)) {
1637 unsigned long new_afsr = local_snapshot.afsr;
1638
1639 /* If we got a new asynchronous error, die... */
1640 if (new_afsr & (CHAFSR_EMU | CHAFSR_EDU |
1641 CHAFSR_WDU | CHAFSR_CPU |
1642 CHAFSR_IVU | CHAFSR_UE |
1643 CHAFSR_BERR | CHAFSR_TO))
1644 recoverable = 0;
1645 }
1646
1647 /* Log errors. */
1648 cheetah_log_errors(regs, &local_snapshot, afsr, afar, recoverable);
1649
1650 /* "Recoverable" here means we try to yank the page from ever
1651 * being newly used again. This depends upon a few things:
1652 * 1) Must be main memory, and AFAR must be valid.
1653 * 2) If we trapped from user, OK.
1654 * 3) Else, if we trapped from kernel we must find exception
1655 * table entry (ie. we have to have been accessing user
1656 * space).
1657 *
1658 * If AFAR is not in main memory, or we trapped from kernel
1659 * and cannot find an exception table entry, it is unacceptable
1660 * to try and continue.
1661 */
1662 if (recoverable && is_memory) {
1663 if ((regs->tstate & TSTATE_PRIV) == 0UL) {
1664 /* OK, usermode access. */
1665 recoverable = 1;
1666 } else {
David S. Miller8cf14af2005-09-28 20:21:11 -07001667 const struct exception_table_entry *entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668
David S. Miller8cf14af2005-09-28 20:21:11 -07001669 entry = search_exception_tables(regs->tpc);
1670 if (entry) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 /* OK, kernel access to userspace. */
1672 recoverable = 1;
1673
1674 } else {
1675 /* BAD, privileged state is corrupted. */
1676 recoverable = 0;
1677 }
1678
1679 if (recoverable) {
1680 if (pfn_valid(afar >> PAGE_SHIFT))
1681 get_page(pfn_to_page(afar >> PAGE_SHIFT));
1682 else
1683 recoverable = 0;
1684
1685 /* Only perform fixup if we still have a
1686 * recoverable condition.
1687 */
1688 if (recoverable) {
David S. Miller8cf14af2005-09-28 20:21:11 -07001689 regs->tpc = entry->fixup;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 regs->tnpc = regs->tpc + 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 }
1692 }
1693 }
1694 } else {
1695 recoverable = 0;
1696 }
1697
1698 if (!recoverable)
1699 panic("Irrecoverable deferred error trap.\n");
1700}
1701
1702/* Handle a D/I cache parity error trap. TYPE is encoded as:
1703 *
1704 * Bit0: 0=dcache,1=icache
1705 * Bit1: 0=recoverable,1=unrecoverable
1706 *
1707 * The hardware has disabled both the I-cache and D-cache in
1708 * the %dcr register.
1709 */
1710void cheetah_plus_parity_error(int type, struct pt_regs *regs)
1711{
1712 if (type & 0x1)
1713 __cheetah_flush_icache();
1714 else
1715 cheetah_plus_zap_dcache_parity();
1716 cheetah_flush_dcache();
1717
1718 /* Re-enable I-cache/D-cache */
1719 __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
1720 "or %%g1, %1, %%g1\n\t"
1721 "stxa %%g1, [%%g0] %0\n\t"
1722 "membar #Sync"
1723 : /* no outputs */
1724 : "i" (ASI_DCU_CONTROL_REG),
1725 "i" (DCU_DC | DCU_IC)
1726 : "g1");
1727
1728 if (type & 0x2) {
1729 printk(KERN_EMERG "CPU[%d]: Cheetah+ %c-cache parity error at TPC[%016lx]\n",
1730 smp_processor_id(),
1731 (type & 0x1) ? 'I' : 'D',
1732 regs->tpc);
David S. Miller4fe3ebe2008-07-17 22:11:32 -07001733 printk(KERN_EMERG "TPC<%pS>\n", (void *) regs->tpc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 panic("Irrecoverable Cheetah+ parity error.");
1735 }
1736
1737 printk(KERN_WARNING "CPU[%d]: Cheetah+ %c-cache parity error at TPC[%016lx]\n",
1738 smp_processor_id(),
1739 (type & 0x1) ? 'I' : 'D',
1740 regs->tpc);
David S. Miller4fe3ebe2008-07-17 22:11:32 -07001741 printk(KERN_WARNING "TPC<%pS>\n", (void *) regs->tpc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742}
1743
David S. Miller5b0c0572006-02-08 02:53:50 -08001744struct sun4v_error_entry {
1745 u64 err_handle;
1746 u64 err_stick;
1747
1748 u32 err_type;
1749#define SUN4V_ERR_TYPE_UNDEFINED 0
1750#define SUN4V_ERR_TYPE_UNCORRECTED_RES 1
1751#define SUN4V_ERR_TYPE_PRECISE_NONRES 2
1752#define SUN4V_ERR_TYPE_DEFERRED_NONRES 3
1753#define SUN4V_ERR_TYPE_WARNING_RES 4
1754
1755 u32 err_attrs;
1756#define SUN4V_ERR_ATTRS_PROCESSOR 0x00000001
1757#define SUN4V_ERR_ATTRS_MEMORY 0x00000002
1758#define SUN4V_ERR_ATTRS_PIO 0x00000004
1759#define SUN4V_ERR_ATTRS_INT_REGISTERS 0x00000008
1760#define SUN4V_ERR_ATTRS_FPU_REGISTERS 0x00000010
1761#define SUN4V_ERR_ATTRS_USER_MODE 0x01000000
1762#define SUN4V_ERR_ATTRS_PRIV_MODE 0x02000000
1763#define SUN4V_ERR_ATTRS_RES_QUEUE_FULL 0x80000000
1764
1765 u64 err_raddr;
1766 u32 err_size;
1767 u16 err_cpu;
1768 u16 err_pad;
1769};
1770
1771static atomic_t sun4v_resum_oflow_cnt = ATOMIC_INIT(0);
1772static atomic_t sun4v_nonresum_oflow_cnt = ATOMIC_INIT(0);
1773
1774static const char *sun4v_err_type_to_str(u32 type)
1775{
1776 switch (type) {
1777 case SUN4V_ERR_TYPE_UNDEFINED:
1778 return "undefined";
1779 case SUN4V_ERR_TYPE_UNCORRECTED_RES:
1780 return "uncorrected resumable";
1781 case SUN4V_ERR_TYPE_PRECISE_NONRES:
1782 return "precise nonresumable";
1783 case SUN4V_ERR_TYPE_DEFERRED_NONRES:
1784 return "deferred nonresumable";
1785 case SUN4V_ERR_TYPE_WARNING_RES:
1786 return "warning resumable";
1787 default:
1788 return "unknown";
1789 };
1790}
1791
David S. Miller5224e6c2006-06-06 17:37:41 -07001792static void sun4v_log_error(struct pt_regs *regs, struct sun4v_error_entry *ent, int cpu, const char *pfx, atomic_t *ocnt)
David S. Miller5b0c0572006-02-08 02:53:50 -08001793{
1794 int cnt;
1795
1796 printk("%s: Reporting on cpu %d\n", pfx, cpu);
1797 printk("%s: err_handle[%lx] err_stick[%lx] err_type[%08x:%s]\n",
1798 pfx,
1799 ent->err_handle, ent->err_stick,
1800 ent->err_type,
1801 sun4v_err_type_to_str(ent->err_type));
1802 printk("%s: err_attrs[%08x:%s %s %s %s %s %s %s %s]\n",
1803 pfx,
1804 ent->err_attrs,
1805 ((ent->err_attrs & SUN4V_ERR_ATTRS_PROCESSOR) ?
1806 "processor" : ""),
1807 ((ent->err_attrs & SUN4V_ERR_ATTRS_MEMORY) ?
1808 "memory" : ""),
1809 ((ent->err_attrs & SUN4V_ERR_ATTRS_PIO) ?
1810 "pio" : ""),
1811 ((ent->err_attrs & SUN4V_ERR_ATTRS_INT_REGISTERS) ?
1812 "integer-regs" : ""),
1813 ((ent->err_attrs & SUN4V_ERR_ATTRS_FPU_REGISTERS) ?
1814 "fpu-regs" : ""),
1815 ((ent->err_attrs & SUN4V_ERR_ATTRS_USER_MODE) ?
1816 "user" : ""),
1817 ((ent->err_attrs & SUN4V_ERR_ATTRS_PRIV_MODE) ?
1818 "privileged" : ""),
1819 ((ent->err_attrs & SUN4V_ERR_ATTRS_RES_QUEUE_FULL) ?
1820 "queue-full" : ""));
1821 printk("%s: err_raddr[%016lx] err_size[%u] err_cpu[%u]\n",
1822 pfx,
1823 ent->err_raddr, ent->err_size, ent->err_cpu);
1824
David S. Millerdbf3e952008-07-31 20:33:43 -07001825 show_regs(regs);
David S. Miller5224e6c2006-06-06 17:37:41 -07001826
David S. Miller5b0c0572006-02-08 02:53:50 -08001827 if ((cnt = atomic_read(ocnt)) != 0) {
1828 atomic_set(ocnt, 0);
1829 wmb();
1830 printk("%s: Queue overflowed %d times.\n",
1831 pfx, cnt);
1832 }
1833}
1834
1835/* We run with %pil set to 15 and PSTATE_IE enabled in %pstate.
1836 * Log the event and clear the first word of the entry.
1837 */
1838void sun4v_resum_error(struct pt_regs *regs, unsigned long offset)
1839{
1840 struct sun4v_error_entry *ent, local_copy;
1841 struct trap_per_cpu *tb;
1842 unsigned long paddr;
1843 int cpu;
1844
1845 cpu = get_cpu();
1846
1847 tb = &trap_block[cpu];
1848 paddr = tb->resum_kernel_buf_pa + offset;
1849 ent = __va(paddr);
1850
1851 memcpy(&local_copy, ent, sizeof(struct sun4v_error_entry));
1852
1853 /* We have a local copy now, so release the entry. */
1854 ent->err_handle = 0;
1855 wmb();
1856
1857 put_cpu();
1858
David S. Millera2c1e062006-11-29 21:16:21 -08001859 if (ent->err_type == SUN4V_ERR_TYPE_WARNING_RES) {
1860 /* If err_type is 0x4, it's a powerdown request. Do
1861 * not do the usual resumable error log because that
1862 * makes it look like some abnormal error.
1863 */
1864 printk(KERN_INFO "Power down request...\n");
1865 kill_cad_pid(SIGINT, 1);
1866 return;
1867 }
1868
David S. Miller5224e6c2006-06-06 17:37:41 -07001869 sun4v_log_error(regs, &local_copy, cpu,
David S. Miller5b0c0572006-02-08 02:53:50 -08001870 KERN_ERR "RESUMABLE ERROR",
1871 &sun4v_resum_oflow_cnt);
1872}
1873
1874/* If we try to printk() we'll probably make matters worse, by trying
1875 * to retake locks this cpu already holds or causing more errors. So
1876 * just bump a counter, and we'll report these counter bumps above.
1877 */
1878void sun4v_resum_overflow(struct pt_regs *regs)
1879{
1880 atomic_inc(&sun4v_resum_oflow_cnt);
1881}
1882
1883/* We run with %pil set to 15 and PSTATE_IE enabled in %pstate.
1884 * Log the event, clear the first word of the entry, and die.
1885 */
1886void sun4v_nonresum_error(struct pt_regs *regs, unsigned long offset)
1887{
1888 struct sun4v_error_entry *ent, local_copy;
1889 struct trap_per_cpu *tb;
1890 unsigned long paddr;
1891 int cpu;
1892
1893 cpu = get_cpu();
1894
1895 tb = &trap_block[cpu];
1896 paddr = tb->nonresum_kernel_buf_pa + offset;
1897 ent = __va(paddr);
1898
1899 memcpy(&local_copy, ent, sizeof(struct sun4v_error_entry));
1900
1901 /* We have a local copy now, so release the entry. */
1902 ent->err_handle = 0;
1903 wmb();
1904
1905 put_cpu();
1906
1907#ifdef CONFIG_PCI
1908 /* Check for the special PCI poke sequence. */
1909 if (pci_poke_in_progress && pci_poke_cpu == cpu) {
1910 pci_poke_faulted = 1;
1911 regs->tpc += 4;
1912 regs->tnpc = regs->tpc + 4;
1913 return;
1914 }
1915#endif
1916
David S. Miller5224e6c2006-06-06 17:37:41 -07001917 sun4v_log_error(regs, &local_copy, cpu,
David S. Miller5b0c0572006-02-08 02:53:50 -08001918 KERN_EMERG "NON-RESUMABLE ERROR",
1919 &sun4v_nonresum_oflow_cnt);
1920
1921 panic("Non-resumable error.");
1922}
1923
1924/* If we try to printk() we'll probably make matters worse, by trying
1925 * to retake locks this cpu already holds or causing more errors. So
1926 * just bump a counter, and we'll report these counter bumps above.
1927 */
1928void sun4v_nonresum_overflow(struct pt_regs *regs)
1929{
1930 /* XXX Actually even this can make not that much sense. Perhaps
1931 * XXX we should just pull the plug and panic directly from here?
1932 */
1933 atomic_inc(&sun4v_nonresum_oflow_cnt);
1934}
1935
David S. Miller6c8927c2006-02-17 14:58:02 -08001936unsigned long sun4v_err_itlb_vaddr;
1937unsigned long sun4v_err_itlb_ctx;
1938unsigned long sun4v_err_itlb_pte;
1939unsigned long sun4v_err_itlb_error;
1940
1941void sun4v_itlb_error_report(struct pt_regs *regs, int tl)
1942{
1943 if (tl > 1)
1944 dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
1945
David S. Miller04d74752006-02-18 17:06:28 -08001946 printk(KERN_EMERG "SUN4V-ITLB: Error at TPC[%lx], tl %d\n",
1947 regs->tpc, tl);
David S. Miller4fe3ebe2008-07-17 22:11:32 -07001948 printk(KERN_EMERG "SUN4V-ITLB: TPC<%pS>\n", (void *) regs->tpc);
David S. Miller6320bce2008-01-17 01:32:09 -08001949 printk(KERN_EMERG "SUN4V-ITLB: O7[%lx]\n", regs->u_regs[UREG_I7]);
David S. Miller4fe3ebe2008-07-17 22:11:32 -07001950 printk(KERN_EMERG "SUN4V-ITLB: O7<%pS>\n",
1951 (void *) regs->u_regs[UREG_I7]);
David S. Miller04d74752006-02-18 17:06:28 -08001952 printk(KERN_EMERG "SUN4V-ITLB: vaddr[%lx] ctx[%lx] "
1953 "pte[%lx] error[%lx]\n",
David S. Miller6c8927c2006-02-17 14:58:02 -08001954 sun4v_err_itlb_vaddr, sun4v_err_itlb_ctx,
1955 sun4v_err_itlb_pte, sun4v_err_itlb_error);
David S. Miller04d74752006-02-18 17:06:28 -08001956
David S. Miller6c8927c2006-02-17 14:58:02 -08001957 prom_halt();
1958}
1959
1960unsigned long sun4v_err_dtlb_vaddr;
1961unsigned long sun4v_err_dtlb_ctx;
1962unsigned long sun4v_err_dtlb_pte;
1963unsigned long sun4v_err_dtlb_error;
1964
1965void sun4v_dtlb_error_report(struct pt_regs *regs, int tl)
1966{
1967 if (tl > 1)
1968 dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
1969
David S. Miller04d74752006-02-18 17:06:28 -08001970 printk(KERN_EMERG "SUN4V-DTLB: Error at TPC[%lx], tl %d\n",
1971 regs->tpc, tl);
David S. Miller4fe3ebe2008-07-17 22:11:32 -07001972 printk(KERN_EMERG "SUN4V-DTLB: TPC<%pS>\n", (void *) regs->tpc);
David S. Miller6320bce2008-01-17 01:32:09 -08001973 printk(KERN_EMERG "SUN4V-DTLB: O7[%lx]\n", regs->u_regs[UREG_I7]);
David S. Miller4fe3ebe2008-07-17 22:11:32 -07001974 printk(KERN_EMERG "SUN4V-DTLB: O7<%pS>\n",
1975 (void *) regs->u_regs[UREG_I7]);
David S. Miller04d74752006-02-18 17:06:28 -08001976 printk(KERN_EMERG "SUN4V-DTLB: vaddr[%lx] ctx[%lx] "
1977 "pte[%lx] error[%lx]\n",
David S. Miller6c8927c2006-02-17 14:58:02 -08001978 sun4v_err_dtlb_vaddr, sun4v_err_dtlb_ctx,
1979 sun4v_err_dtlb_pte, sun4v_err_dtlb_error);
David S. Miller04d74752006-02-18 17:06:28 -08001980
David S. Miller6c8927c2006-02-17 14:58:02 -08001981 prom_halt();
1982}
1983
David S. Miller2a3a5f52006-02-26 19:31:49 -08001984void hypervisor_tlbop_error(unsigned long err, unsigned long op)
1985{
1986 printk(KERN_CRIT "SUN4V: TLB hv call error %lu for op %lu\n",
1987 err, op);
1988}
1989
1990void hypervisor_tlbop_error_xcall(unsigned long err, unsigned long op)
1991{
1992 printk(KERN_CRIT "SUN4V: XCALL TLB hv call error %lu for op %lu\n",
1993 err, op);
1994}
1995
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996void do_fpe_common(struct pt_regs *regs)
1997{
1998 if (regs->tstate & TSTATE_PRIV) {
1999 regs->tpc = regs->tnpc;
2000 regs->tnpc += 4;
2001 } else {
2002 unsigned long fsr = current_thread_info()->xfsr[0];
2003 siginfo_t info;
2004
2005 if (test_thread_flag(TIF_32BIT)) {
2006 regs->tpc &= 0xffffffff;
2007 regs->tnpc &= 0xffffffff;
2008 }
2009 info.si_signo = SIGFPE;
2010 info.si_errno = 0;
2011 info.si_addr = (void __user *)regs->tpc;
2012 info.si_trapno = 0;
2013 info.si_code = __SI_FAULT;
2014 if ((fsr & 0x1c000) == (1 << 14)) {
2015 if (fsr & 0x10)
2016 info.si_code = FPE_FLTINV;
2017 else if (fsr & 0x08)
2018 info.si_code = FPE_FLTOVF;
2019 else if (fsr & 0x04)
2020 info.si_code = FPE_FLTUND;
2021 else if (fsr & 0x02)
2022 info.si_code = FPE_FLTDIV;
2023 else if (fsr & 0x01)
2024 info.si_code = FPE_FLTRES;
2025 }
2026 force_sig_info(SIGFPE, &info, current);
2027 }
2028}
2029
2030void do_fpieee(struct pt_regs *regs)
2031{
2032 if (notify_die(DIE_TRAP, "fpu exception ieee", regs,
2033 0, 0x24, SIGFPE) == NOTIFY_STOP)
2034 return;
2035
2036 do_fpe_common(regs);
2037}
2038
2039extern int do_mathemu(struct pt_regs *, struct fpustate *);
2040
2041void do_fpother(struct pt_regs *regs)
2042{
2043 struct fpustate *f = FPUSTATE;
2044 int ret = 0;
2045
2046 if (notify_die(DIE_TRAP, "fpu exception other", regs,
2047 0, 0x25, SIGFPE) == NOTIFY_STOP)
2048 return;
2049
2050 switch ((current_thread_info()->xfsr[0] & 0x1c000)) {
2051 case (2 << 14): /* unfinished_FPop */
2052 case (3 << 14): /* unimplemented_FPop */
2053 ret = do_mathemu(regs, f);
2054 break;
2055 }
2056 if (ret)
2057 return;
2058 do_fpe_common(regs);
2059}
2060
2061void do_tof(struct pt_regs *regs)
2062{
2063 siginfo_t info;
2064
2065 if (notify_die(DIE_TRAP, "tagged arithmetic overflow", regs,
2066 0, 0x26, SIGEMT) == NOTIFY_STOP)
2067 return;
2068
2069 if (regs->tstate & TSTATE_PRIV)
2070 die_if_kernel("Penguin overflow trap from kernel mode", regs);
2071 if (test_thread_flag(TIF_32BIT)) {
2072 regs->tpc &= 0xffffffff;
2073 regs->tnpc &= 0xffffffff;
2074 }
2075 info.si_signo = SIGEMT;
2076 info.si_errno = 0;
2077 info.si_code = EMT_TAGOVF;
2078 info.si_addr = (void __user *)regs->tpc;
2079 info.si_trapno = 0;
2080 force_sig_info(SIGEMT, &info, current);
2081}
2082
2083void do_div0(struct pt_regs *regs)
2084{
2085 siginfo_t info;
2086
2087 if (notify_die(DIE_TRAP, "integer division by zero", regs,
2088 0, 0x28, SIGFPE) == NOTIFY_STOP)
2089 return;
2090
2091 if (regs->tstate & TSTATE_PRIV)
2092 die_if_kernel("TL0: Kernel divide by zero.", regs);
2093 if (test_thread_flag(TIF_32BIT)) {
2094 regs->tpc &= 0xffffffff;
2095 regs->tnpc &= 0xffffffff;
2096 }
2097 info.si_signo = SIGFPE;
2098 info.si_errno = 0;
2099 info.si_code = FPE_INTDIV;
2100 info.si_addr = (void __user *)regs->tpc;
2101 info.si_trapno = 0;
2102 force_sig_info(SIGFPE, &info, current);
2103}
2104
David S. Miller99cd2202008-03-26 00:19:43 -07002105static void instruction_dump(unsigned int *pc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106{
2107 int i;
2108
2109 if ((((unsigned long) pc) & 3))
2110 return;
2111
2112 printk("Instruction DUMP:");
2113 for (i = -3; i < 6; i++)
2114 printk("%c%08x%c",i?' ':'<',pc[i],i?' ':'>');
2115 printk("\n");
2116}
2117
David S. Miller99cd2202008-03-26 00:19:43 -07002118static void user_instruction_dump(unsigned int __user *pc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119{
2120 int i;
2121 unsigned int buf[9];
2122
2123 if ((((unsigned long) pc) & 3))
2124 return;
2125
2126 if (copy_from_user(buf, pc - 3, sizeof(buf)))
2127 return;
2128
2129 printk("Instruction DUMP:");
2130 for (i = 0; i < 9; i++)
2131 printk("%c%08x%c",i==3?' ':'<',buf[i],i==3?' ':'>');
2132 printk("\n");
2133}
2134
2135void show_stack(struct task_struct *tsk, unsigned long *_ksp)
2136{
David S. Miller77c664f2008-04-24 03:28:52 -07002137 unsigned long fp, thread_base, ksp;
David S. Millerc1f193a2007-07-30 00:17:12 -07002138 struct thread_info *tp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 int count = 0;
2140
2141 ksp = (unsigned long) _ksp;
David S. Millerc1f193a2007-07-30 00:17:12 -07002142 if (!tsk)
2143 tsk = current;
2144 tp = task_thread_info(tsk);
2145 if (ksp == 0UL) {
2146 if (tsk == current)
2147 asm("mov %%fp, %0" : "=r" (ksp));
2148 else
2149 ksp = tp->ksp;
2150 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151 if (tp == current_thread_info())
2152 flushw_all();
2153
2154 fp = ksp + STACK_BIAS;
2155 thread_base = (unsigned long) tp;
2156
David S. Miller4fe3ebe2008-07-17 22:11:32 -07002157 printk("Call Trace:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 do {
David S. Miller14d2c682008-05-21 18:15:53 -07002159 struct sparc_stackf *sf;
David S. Miller77c664f2008-04-24 03:28:52 -07002160 struct pt_regs *regs;
2161 unsigned long pc;
2162
David S. Miller4f70f7a2008-08-12 18:33:56 -07002163 if (!kstack_valid(tp, fp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 break;
David S. Miller14d2c682008-05-21 18:15:53 -07002165 sf = (struct sparc_stackf *) fp;
2166 regs = (struct pt_regs *) (sf + 1);
David S. Miller77c664f2008-04-24 03:28:52 -07002167
David S. Miller4f70f7a2008-08-12 18:33:56 -07002168 if (kstack_is_trap_frame(tp, regs)) {
David S. Miller14d2c682008-05-21 18:15:53 -07002169 if (!(regs->tstate & TSTATE_PRIV))
2170 break;
David S. Miller77c664f2008-04-24 03:28:52 -07002171 pc = regs->tpc;
2172 fp = regs->u_regs[UREG_I6] + STACK_BIAS;
2173 } else {
David S. Miller14d2c682008-05-21 18:15:53 -07002174 pc = sf->callers_pc;
2175 fp = (unsigned long)sf->fp + STACK_BIAS;
David S. Miller77c664f2008-04-24 03:28:52 -07002176 }
2177
David S. Miller4fe3ebe2008-07-17 22:11:32 -07002178 printk(" [%016lx] %pS\n", pc, (void *) pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179 } while (++count < 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180}
2181
2182void dump_stack(void)
2183{
David S. Millerc1f193a2007-07-30 00:17:12 -07002184 show_stack(current, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185}
2186
2187EXPORT_SYMBOL(dump_stack);
2188
2189static inline int is_kernel_stack(struct task_struct *task,
2190 struct reg_window *rw)
2191{
2192 unsigned long rw_addr = (unsigned long) rw;
2193 unsigned long thread_base, thread_end;
2194
2195 if (rw_addr < PAGE_OFFSET) {
2196 if (task != &init_task)
2197 return 0;
2198 }
2199
Al Viroee3eea12006-01-12 01:05:43 -08002200 thread_base = (unsigned long) task_stack_page(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 thread_end = thread_base + sizeof(union thread_union);
2202 if (rw_addr >= thread_base &&
2203 rw_addr < thread_end &&
2204 !(rw_addr & 0x7UL))
2205 return 1;
2206
2207 return 0;
2208}
2209
2210static inline struct reg_window *kernel_stack_up(struct reg_window *rw)
2211{
2212 unsigned long fp = rw->ins[6];
2213
2214 if (!fp)
2215 return NULL;
2216
2217 return (struct reg_window *) (fp + STACK_BIAS);
2218}
2219
2220void die_if_kernel(char *str, struct pt_regs *regs)
2221{
2222 static int die_counter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 int count = 0;
2224
2225 /* Amuse the user. */
2226 printk(
2227" \\|/ ____ \\|/\n"
2228" \"@'/ .. \\`@\"\n"
2229" /_| \\__/ |_\\\n"
2230" \\__U_/\n");
2231
Alexey Dobriyan19c58702007-10-18 23:40:41 -07002232 printk("%s(%d): %s [#%d]\n", current->comm, task_pid_nr(current), str, ++die_counter);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 notify_die(DIE_OOPS, str, regs, 0, 255, SIGSEGV);
2234 __asm__ __volatile__("flushw");
David S. Millerdbf3e952008-07-31 20:33:43 -07002235 show_regs(regs);
Pavel Emelianovbcdcd8e2007-07-17 04:03:42 -07002236 add_taint(TAINT_DIE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 if (regs->tstate & TSTATE_PRIV) {
2238 struct reg_window *rw = (struct reg_window *)
2239 (regs->u_regs[UREG_FP] + STACK_BIAS);
2240
2241 /* Stop the back trace when we hit userland or we
2242 * find some badly aligned kernel stack.
2243 */
2244 while (rw &&
2245 count++ < 30&&
2246 is_kernel_stack(current, rw)) {
David S. Miller4fe3ebe2008-07-17 22:11:32 -07002247 printk("Caller[%016lx]: %pS\n", rw->ins[7],
2248 (void *) rw->ins[7]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249
2250 rw = kernel_stack_up(rw);
2251 }
2252 instruction_dump ((unsigned int *) regs->tpc);
2253 } else {
2254 if (test_thread_flag(TIF_32BIT)) {
2255 regs->tpc &= 0xffffffff;
2256 regs->tnpc &= 0xffffffff;
2257 }
2258 user_instruction_dump ((unsigned int __user *) regs->tpc);
2259 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 if (regs->tstate & TSTATE_PRIV)
2261 do_exit(SIGKILL);
2262 do_exit(SIGSEGV);
2263}
2264
David S. Miller6e7726e2006-11-19 14:38:25 -08002265#define VIS_OPCODE_MASK ((0x3 << 30) | (0x3f << 19))
2266#define VIS_OPCODE_VAL ((0x2 << 30) | (0x36 << 19))
2267
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268extern int handle_popc(u32 insn, struct pt_regs *regs);
2269extern int handle_ldf_stq(u32 insn, struct pt_regs *regs);
2270
2271void do_illegal_instruction(struct pt_regs *regs)
2272{
2273 unsigned long pc = regs->tpc;
2274 unsigned long tstate = regs->tstate;
2275 u32 insn;
2276 siginfo_t info;
2277
2278 if (notify_die(DIE_TRAP, "illegal instruction", regs,
2279 0, 0x10, SIGILL) == NOTIFY_STOP)
2280 return;
2281
2282 if (tstate & TSTATE_PRIV)
2283 die_if_kernel("Kernel illegal instruction", regs);
2284 if (test_thread_flag(TIF_32BIT))
2285 pc = (u32)pc;
2286 if (get_user(insn, (u32 __user *) pc) != -EFAULT) {
2287 if ((insn & 0xc1ffc000) == 0x81700000) /* POPC */ {
2288 if (handle_popc(insn, regs))
2289 return;
2290 } else if ((insn & 0xc1580000) == 0xc1100000) /* LDQ/STQ */ {
2291 if (handle_ldf_stq(insn, regs))
2292 return;
David S. Miller0c51ed92006-03-13 01:27:34 -08002293 } else if (tlb_type == hypervisor) {
David S. Miller6e7726e2006-11-19 14:38:25 -08002294 if ((insn & VIS_OPCODE_MASK) == VIS_OPCODE_VAL) {
2295 if (!vis_emul(regs, insn))
2296 return;
2297 } else {
2298 struct fpustate *f = FPUSTATE;
David S. Miller0c51ed92006-03-13 01:27:34 -08002299
David S. Miller6e7726e2006-11-19 14:38:25 -08002300 /* XXX maybe verify XFSR bits like
2301 * XXX do_fpother() does?
2302 */
2303 if (do_mathemu(regs, f))
2304 return;
2305 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 }
2307 }
2308 info.si_signo = SIGILL;
2309 info.si_errno = 0;
2310 info.si_code = ILL_ILLOPC;
2311 info.si_addr = (void __user *)pc;
2312 info.si_trapno = 0;
2313 force_sig_info(SIGILL, &info, current);
2314}
2315
David S. Millered6b0b42006-02-09 20:20:34 -08002316extern void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn);
2317
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318void mem_address_unaligned(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr)
2319{
2320 siginfo_t info;
2321
2322 if (notify_die(DIE_TRAP, "memory address unaligned", regs,
2323 0, 0x34, SIGSEGV) == NOTIFY_STOP)
2324 return;
2325
2326 if (regs->tstate & TSTATE_PRIV) {
David S. Millered6b0b42006-02-09 20:20:34 -08002327 kernel_unaligned_trap(regs, *((unsigned int *)regs->tpc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 return;
2329 }
2330 info.si_signo = SIGBUS;
2331 info.si_errno = 0;
2332 info.si_code = BUS_ADRALN;
2333 info.si_addr = (void __user *)sfar;
2334 info.si_trapno = 0;
2335 force_sig_info(SIGBUS, &info, current);
2336}
2337
David S. Miller9f8a5b82006-02-14 16:39:22 -08002338void sun4v_do_mna(struct pt_regs *regs, unsigned long addr, unsigned long type_ctx)
David S. Millered6b0b42006-02-09 20:20:34 -08002339{
2340 siginfo_t info;
2341
2342 if (notify_die(DIE_TRAP, "memory address unaligned", regs,
2343 0, 0x34, SIGSEGV) == NOTIFY_STOP)
2344 return;
2345
2346 if (regs->tstate & TSTATE_PRIV) {
2347 kernel_unaligned_trap(regs, *((unsigned int *)regs->tpc));
2348 return;
2349 }
2350 info.si_signo = SIGBUS;
2351 info.si_errno = 0;
2352 info.si_code = BUS_ADRALN;
2353 info.si_addr = (void __user *) addr;
2354 info.si_trapno = 0;
2355 force_sig_info(SIGBUS, &info, current);
2356}
2357
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358void do_privop(struct pt_regs *regs)
2359{
2360 siginfo_t info;
2361
2362 if (notify_die(DIE_TRAP, "privileged operation", regs,
2363 0, 0x11, SIGILL) == NOTIFY_STOP)
2364 return;
2365
2366 if (test_thread_flag(TIF_32BIT)) {
2367 regs->tpc &= 0xffffffff;
2368 regs->tnpc &= 0xffffffff;
2369 }
2370 info.si_signo = SIGILL;
2371 info.si_errno = 0;
2372 info.si_code = ILL_PRVOPC;
2373 info.si_addr = (void __user *)regs->tpc;
2374 info.si_trapno = 0;
2375 force_sig_info(SIGILL, &info, current);
2376}
2377
2378void do_privact(struct pt_regs *regs)
2379{
2380 do_privop(regs);
2381}
2382
2383/* Trap level 1 stuff or other traps we should never see... */
2384void do_cee(struct pt_regs *regs)
2385{
2386 die_if_kernel("TL0: Cache Error Exception", regs);
2387}
2388
2389void do_cee_tl1(struct pt_regs *regs)
2390{
2391 dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
2392 die_if_kernel("TL1: Cache Error Exception", regs);
2393}
2394
2395void do_dae_tl1(struct pt_regs *regs)
2396{
2397 dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
2398 die_if_kernel("TL1: Data Access Exception", regs);
2399}
2400
2401void do_iae_tl1(struct pt_regs *regs)
2402{
2403 dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
2404 die_if_kernel("TL1: Instruction Access Exception", regs);
2405}
2406
2407void do_div0_tl1(struct pt_regs *regs)
2408{
2409 dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
2410 die_if_kernel("TL1: DIV0 Exception", regs);
2411}
2412
2413void do_fpdis_tl1(struct pt_regs *regs)
2414{
2415 dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
2416 die_if_kernel("TL1: FPU Disabled", regs);
2417}
2418
2419void do_fpieee_tl1(struct pt_regs *regs)
2420{
2421 dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
2422 die_if_kernel("TL1: FPU IEEE Exception", regs);
2423}
2424
2425void do_fpother_tl1(struct pt_regs *regs)
2426{
2427 dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
2428 die_if_kernel("TL1: FPU Other Exception", regs);
2429}
2430
2431void do_ill_tl1(struct pt_regs *regs)
2432{
2433 dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
2434 die_if_kernel("TL1: Illegal Instruction Exception", regs);
2435}
2436
2437void do_irq_tl1(struct pt_regs *regs)
2438{
2439 dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
2440 die_if_kernel("TL1: IRQ Exception", regs);
2441}
2442
2443void do_lddfmna_tl1(struct pt_regs *regs)
2444{
2445 dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
2446 die_if_kernel("TL1: LDDF Exception", regs);
2447}
2448
2449void do_stdfmna_tl1(struct pt_regs *regs)
2450{
2451 dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
2452 die_if_kernel("TL1: STDF Exception", regs);
2453}
2454
2455void do_paw(struct pt_regs *regs)
2456{
2457 die_if_kernel("TL0: Phys Watchpoint Exception", regs);
2458}
2459
2460void do_paw_tl1(struct pt_regs *regs)
2461{
2462 dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
2463 die_if_kernel("TL1: Phys Watchpoint Exception", regs);
2464}
2465
2466void do_vaw(struct pt_regs *regs)
2467{
2468 die_if_kernel("TL0: Virt Watchpoint Exception", regs);
2469}
2470
2471void do_vaw_tl1(struct pt_regs *regs)
2472{
2473 dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
2474 die_if_kernel("TL1: Virt Watchpoint Exception", regs);
2475}
2476
2477void do_tof_tl1(struct pt_regs *regs)
2478{
2479 dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
2480 die_if_kernel("TL1: Tag Overflow Exception", regs);
2481}
2482
2483void do_getpsr(struct pt_regs *regs)
2484{
2485 regs->u_regs[UREG_I0] = tstate_to_psr(regs->tstate);
2486 regs->tpc = regs->tnpc;
2487 regs->tnpc += 4;
2488 if (test_thread_flag(TIF_32BIT)) {
2489 regs->tpc &= 0xffffffff;
2490 regs->tnpc &= 0xffffffff;
2491 }
2492}
2493
David S. Miller56fb4df2006-02-26 23:24:22 -08002494struct trap_per_cpu trap_block[NR_CPUS];
2495
2496/* This can get invoked before sched_init() so play it super safe
2497 * and use hard_smp_processor_id().
2498 */
David S. Miller72aff532006-02-17 01:29:17 -08002499void init_cur_cpu_trap(struct thread_info *t)
David S. Miller56fb4df2006-02-26 23:24:22 -08002500{
2501 int cpu = hard_smp_processor_id();
2502 struct trap_per_cpu *p = &trap_block[cpu];
2503
David S. Miller72aff532006-02-17 01:29:17 -08002504 p->thread = t;
David S. Miller56fb4df2006-02-26 23:24:22 -08002505 p->pgd_paddr = 0;
2506}
2507
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508extern void thread_info_offsets_are_bolixed_dave(void);
David S. Miller56fb4df2006-02-26 23:24:22 -08002509extern void trap_per_cpu_offsets_are_bolixed_dave(void);
David S. Millerdcc1e8d2006-03-22 00:49:59 -08002510extern void tsb_config_offsets_are_bolixed_dave(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511
2512/* Only invoked on boot processor. */
2513void __init trap_init(void)
2514{
2515 /* Compile time sanity check. */
2516 if (TI_TASK != offsetof(struct thread_info, task) ||
2517 TI_FLAGS != offsetof(struct thread_info, flags) ||
2518 TI_CPU != offsetof(struct thread_info, cpu) ||
2519 TI_FPSAVED != offsetof(struct thread_info, fpsaved) ||
2520 TI_KSP != offsetof(struct thread_info, ksp) ||
2521 TI_FAULT_ADDR != offsetof(struct thread_info, fault_address) ||
2522 TI_KREGS != offsetof(struct thread_info, kregs) ||
2523 TI_UTRAPS != offsetof(struct thread_info, utraps) ||
2524 TI_EXEC_DOMAIN != offsetof(struct thread_info, exec_domain) ||
2525 TI_REG_WINDOW != offsetof(struct thread_info, reg_window) ||
2526 TI_RWIN_SPTRS != offsetof(struct thread_info, rwbuf_stkptrs) ||
2527 TI_GSR != offsetof(struct thread_info, gsr) ||
2528 TI_XFSR != offsetof(struct thread_info, xfsr) ||
2529 TI_USER_CNTD0 != offsetof(struct thread_info, user_cntd0) ||
2530 TI_USER_CNTD1 != offsetof(struct thread_info, user_cntd1) ||
2531 TI_KERN_CNTD0 != offsetof(struct thread_info, kernel_cntd0) ||
2532 TI_KERN_CNTD1 != offsetof(struct thread_info, kernel_cntd1) ||
2533 TI_PCR != offsetof(struct thread_info, pcr_reg) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534 TI_PRE_COUNT != offsetof(struct thread_info, preempt_count) ||
David S. Millerdb7d9a42005-07-24 19:36:26 -07002535 TI_NEW_CHILD != offsetof(struct thread_info, new_child) ||
2536 TI_SYS_NOERROR != offsetof(struct thread_info, syscall_noerror) ||
David S. Millera3f99852005-08-19 15:55:33 -07002537 TI_RESTART_BLOCK != offsetof(struct thread_info, restart_block) ||
2538 TI_KUNA_REGS != offsetof(struct thread_info, kern_una_regs) ||
2539 TI_KUNA_INSN != offsetof(struct thread_info, kern_una_insn) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540 TI_FPREGS != offsetof(struct thread_info, fpregs) ||
2541 (TI_FPREGS & (64 - 1)))
2542 thread_info_offsets_are_bolixed_dave();
2543
David S. Miller56fb4df2006-02-26 23:24:22 -08002544 if (TRAP_PER_CPU_THREAD != offsetof(struct trap_per_cpu, thread) ||
David S. Millere088ad72006-02-07 23:51:49 -08002545 (TRAP_PER_CPU_PGD_PADDR !=
2546 offsetof(struct trap_per_cpu, pgd_paddr)) ||
2547 (TRAP_PER_CPU_CPU_MONDO_PA !=
2548 offsetof(struct trap_per_cpu, cpu_mondo_pa)) ||
2549 (TRAP_PER_CPU_DEV_MONDO_PA !=
2550 offsetof(struct trap_per_cpu, dev_mondo_pa)) ||
2551 (TRAP_PER_CPU_RESUM_MONDO_PA !=
2552 offsetof(struct trap_per_cpu, resum_mondo_pa)) ||
David S. Miller5b0c0572006-02-08 02:53:50 -08002553 (TRAP_PER_CPU_RESUM_KBUF_PA !=
2554 offsetof(struct trap_per_cpu, resum_kernel_buf_pa)) ||
David S. Millere088ad72006-02-07 23:51:49 -08002555 (TRAP_PER_CPU_NONRESUM_MONDO_PA !=
2556 offsetof(struct trap_per_cpu, nonresum_mondo_pa)) ||
David S. Miller5b0c0572006-02-08 02:53:50 -08002557 (TRAP_PER_CPU_NONRESUM_KBUF_PA !=
2558 offsetof(struct trap_per_cpu, nonresum_kernel_buf_pa)) ||
David S. Millere088ad72006-02-07 23:51:49 -08002559 (TRAP_PER_CPU_FAULT_INFO !=
David S. Miller1d2f1f92006-02-08 16:41:20 -08002560 offsetof(struct trap_per_cpu, fault_info)) ||
2561 (TRAP_PER_CPU_CPU_MONDO_BLOCK_PA !=
2562 offsetof(struct trap_per_cpu, cpu_mondo_block_pa)) ||
2563 (TRAP_PER_CPU_CPU_LIST_PA !=
David S. Millerdcc1e8d2006-03-22 00:49:59 -08002564 offsetof(struct trap_per_cpu, cpu_list_pa)) ||
2565 (TRAP_PER_CPU_TSB_HUGE !=
2566 offsetof(struct trap_per_cpu, tsb_huge)) ||
2567 (TRAP_PER_CPU_TSB_HUGE_TEMP !=
David S. Millerfd0504c32006-06-20 01:20:00 -07002568 offsetof(struct trap_per_cpu, tsb_huge_temp)) ||
David S. Millereb2d8d62007-10-13 21:42:46 -07002569 (TRAP_PER_CPU_IRQ_WORKLIST_PA !=
2570 offsetof(struct trap_per_cpu, irq_worklist_pa)) ||
David S. Miller5cbc3072007-05-25 15:49:59 -07002571 (TRAP_PER_CPU_CPU_MONDO_QMASK !=
2572 offsetof(struct trap_per_cpu, cpu_mondo_qmask)) ||
2573 (TRAP_PER_CPU_DEV_MONDO_QMASK !=
2574 offsetof(struct trap_per_cpu, dev_mondo_qmask)) ||
2575 (TRAP_PER_CPU_RESUM_QMASK !=
2576 offsetof(struct trap_per_cpu, resum_qmask)) ||
2577 (TRAP_PER_CPU_NONRESUM_QMASK !=
2578 offsetof(struct trap_per_cpu, nonresum_qmask)))
David S. Miller56fb4df2006-02-26 23:24:22 -08002579 trap_per_cpu_offsets_are_bolixed_dave();
2580
David S. Millerdcc1e8d2006-03-22 00:49:59 -08002581 if ((TSB_CONFIG_TSB !=
2582 offsetof(struct tsb_config, tsb)) ||
2583 (TSB_CONFIG_RSS_LIMIT !=
2584 offsetof(struct tsb_config, tsb_rss_limit)) ||
2585 (TSB_CONFIG_NENTRIES !=
2586 offsetof(struct tsb_config, tsb_nentries)) ||
2587 (TSB_CONFIG_REG_VAL !=
2588 offsetof(struct tsb_config, tsb_reg_val)) ||
2589 (TSB_CONFIG_MAP_VADDR !=
2590 offsetof(struct tsb_config, tsb_map_vaddr)) ||
2591 (TSB_CONFIG_MAP_PTE !=
2592 offsetof(struct tsb_config, tsb_map_pte)))
2593 tsb_config_offsets_are_bolixed_dave();
2594
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595 /* Attach to the address space of init_task. On SMP we
2596 * do this in smp.c:smp_callin for other cpus.
2597 */
2598 atomic_inc(&init_mm.mm_count);
2599 current->active_mm = &init_mm;
2600}