summaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/traps.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64/kernel/traps.c')
-rw-r--r--arch/sparc64/kernel/traps.c99
1 files changed, 69 insertions, 30 deletions
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index cc703d3bc..0a368bcee 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.70 2001/02/09 05:46:44 davem Exp $
+/* $Id: traps.c,v 1.73 2001/03/22 07:26:03 davem Exp $
* arch/sparc64/kernel/traps.c
*
* Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -26,6 +26,7 @@
#include <asm/uaccess.h>
#include <asm/fpumacro.h>
#include <asm/lsu.h>
+#include <asm/dcu.h>
#include <asm/psrcompat.h>
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
@@ -263,6 +264,10 @@ void bad_trap (struct pt_regs *regs, long lvl)
}
if (regs->tstate & TSTATE_PRIV)
die_if_kernel ("Kernel bad trap", regs);
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
info.si_signo = SIGILL;
info.si_errno = 0;
info.si_code = ILL_ILLTRP;
@@ -291,6 +296,10 @@ void instruction_access_exception (struct pt_regs *regs,
#endif
die_if_kernel("Iax", regs);
}
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
info.si_signo = SIGSEGV;
info.si_errno = 0;
info.si_code = SEGV_MAPERR;
@@ -342,32 +351,41 @@ void data_access_exception (struct pt_regs *regs,
#ifdef CONFIG_PCI
/* This is really pathetic... */
-/* #define DEBUG_PCI_POKES */
extern volatile int pci_poke_in_progress;
extern volatile int pci_poke_faulted;
#endif
/* When access exceptions happen, we must do this. */
-static __inline__ void clean_and_reenable_l1_caches(void)
+static void clean_and_reenable_l1_caches(void)
{
unsigned long va;
- /* Clean 'em. */
- for(va = 0; va < (PAGE_SIZE << 1); va += 32) {
- spitfire_put_icache_tag(va, 0x0);
- spitfire_put_dcache_tag(va, 0x0);
- }
+ if (tlb_type == spitfire) {
+ /* Clean 'em. */
+ for (va = 0; va < (PAGE_SIZE << 1); va += 32) {
+ spitfire_put_icache_tag(va, 0x0);
+ spitfire_put_dcache_tag(va, 0x0);
+ }
- /* Re-enable. */
- __asm__ __volatile__("flush %%g6\n\t"
- "membar #Sync\n\t"
- "stxa %0, [%%g0] %1\n\t"
- "membar #Sync"
- : /* no outputs */
- : "r" (LSU_CONTROL_IC | LSU_CONTROL_DC |
- LSU_CONTROL_IM | LSU_CONTROL_DM),
- "i" (ASI_LSU_CONTROL)
- : "memory");
+ /* Re-enable in LSU. */
+ __asm__ __volatile__("flush %%g6\n\t"
+ "membar #Sync\n\t"
+ "stxa %0, [%%g0] %1\n\t"
+ "membar #Sync"
+ : /* no outputs */
+ : "r" (LSU_CONTROL_IC | LSU_CONTROL_DC |
+ LSU_CONTROL_IM | LSU_CONTROL_DM),
+ "i" (ASI_LSU_CONTROL)
+ : "memory");
+ } else if (tlb_type == cheetah) {
+ /* Flush D-cache */
+ for (va = 0; va < (1 << 16); va += (1 << 5)) {
+ __asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
+ "membar #Sync"
+ : /* no outputs */
+ : "r" (va), "i" (ASI_DCACHE_TAG));
+ }
+ }
}
void do_iae(struct pt_regs *regs)
@@ -387,20 +405,16 @@ void do_iae(struct pt_regs *regs)
void do_dae(struct pt_regs *regs)
{
#ifdef CONFIG_PCI
- if(pci_poke_in_progress) {
-#ifdef DEBUG_PCI_POKES
- prom_printf(" (POKE tpc[%016lx] tnpc[%016lx] ",
- regs->tpc, regs->tnpc);
-#endif
+ if (pci_poke_in_progress) {
+ clean_and_reenable_l1_caches();
+
pci_poke_faulted = 1;
- regs->tnpc = regs->tpc + 4;
+ /* Why the fuck did they have to change this? */
+ if (tlb_type == cheetah)
+ regs->tpc += 4;
-#ifdef DEBUG_PCI_POKES
- prom_printf("PCI) ");
- /* prom_halt(); */
-#endif
- clean_and_reenable_l1_caches();
+ regs->tnpc = regs->tpc + 4;
return;
}
#endif
@@ -534,6 +548,10 @@ void do_fpe_common(struct pt_regs *regs)
unsigned long fsr = current->thread.xfsr[0];
siginfo_t info;
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
info.si_signo = SIGFPE;
info.si_errno = 0;
info.si_addr = (void *)regs->tpc;
@@ -589,6 +607,10 @@ void do_tof(struct pt_regs *regs)
if(regs->tstate & TSTATE_PRIV)
die_if_kernel("Penguin overflow trap from kernel mode", regs);
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
info.si_signo = SIGEMT;
info.si_errno = 0;
info.si_code = EMT_TAGOVF;
@@ -601,6 +623,10 @@ void do_div0(struct pt_regs *regs)
{
siginfo_t info;
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
info.si_signo = SIGFPE;
info.si_errno = 0;
info.si_code = FPE_INTDIV;
@@ -700,8 +726,13 @@ void die_if_kernel(char *str, struct pt_regs *regs)
(rw->ins[6] + STACK_BIAS);
}
instruction_dump ((unsigned int *) regs->tpc);
- } else
+ } else {
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
user_instruction_dump ((unsigned int *) regs->tpc);
+ }
#ifdef CONFIG_SMP
smp_report_regs();
#endif
@@ -765,6 +796,10 @@ void do_privop(struct pt_regs *regs)
{
siginfo_t info;
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
info.si_signo = SIGILL;
info.si_errno = 0;
info.si_code = ILL_PRVOPC;
@@ -907,6 +942,10 @@ void do_getpsr(struct pt_regs *regs)
regs->u_regs[UREG_I0] = tstate_to_psr(regs->tstate);
regs->tpc = regs->tnpc;
regs->tnpc += 4;
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
}
void trap_init(void)