* Copyright (C) 2000, 01 MIPS Technologies, Inc.
* Copyright (C) 2002, 2003, 2004, 2005 Maciej W. Rozycki
*/
+#include <linux/config.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <asm/watch.h>
#include <asm/types.h>
-extern asmlinkage void handle_int(void);
extern asmlinkage void handle_tlbm(void);
extern asmlinkage void handle_tlbl(void);
extern asmlinkage void handle_tlbs(void);
extern asmlinkage void handle_reserved(void);
extern int fpu_emulator_cop1Handler(struct pt_regs *xcp,
- struct mips_fpu_struct *ctx);
+ struct mips_fpu_soft_struct *ctx);
void (*board_be_init)(void);
int (*board_be_handler)(struct pt_regs *regs, int is_fixup);
NORET_TYPE void ATTRIB_NORET die(const char * str, struct pt_regs * regs)
{
static int die_counter;
-#ifdef CONFIG_MIPS_MT_SMTC
- unsigned long dvpret = dvpe();
-#endif /* CONFIG_MIPS_MT_SMTC */
console_verbose();
spin_lock_irq(&die_lock);
- bust_spinlocks(1);
-#ifdef CONFIG_MIPS_MT_SMTC
- mips_mt_regdump(dvpret);
-#endif /* CONFIG_MIPS_MT_SMTC */
printk("%s[#%d]:\n", str, ++die_counter);
show_registers(regs);
spin_unlock_irq(&die_lock);
*/
asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
{
- die_if_kernel("FP exception in kernel code", regs);
-
if (fcr31 & FPU_CSR_UNI_X) {
int sig;
}
#endif
/*
- * Unimplemented operation exception. If we've got the full
+ * Unimplemented operation exception. If we've got the full
* software emulator on-board, let's use it...
*
* Force FPU to dump state into task/thread context. We're
preempt_enable();
/* Run the emulator */
- sig = fpu_emulator_cop1Handler (regs, ¤t->thread.fpu);
+ sig = fpu_emulator_cop1Handler (regs,
+ ¤t->thread.fpu.soft);
preempt_disable();
* We can't allow the emulated instruction to leave any of
* the cause bit set in $fcr31.
*/
- current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
+ current->thread.fpu.soft.fcr31 &= ~FPU_CSR_ALL_X;
/* Restore the hardware register state */
restore_fp(current);
if (!cpu_has_fpu) {
int sig = fpu_emulator_cop1Handler(regs,
- ¤t->thread.fpu);
+ ¤t->thread.fpu.soft);
if (sig)
force_sig(sig, current);
-#ifdef CONFIG_MIPS_MT_FPAFF
- else {
- /*
- * MIPS MT processors may have fewer FPU contexts
- * than CPU threads. If we've emulated more than
- * some threshold number of instructions, force
- * migration to a "CPU" that has FP support.
- */
- if(mt_fpemul_threshold > 0
- && ((current->thread.emulated_fp++
- > mt_fpemul_threshold))) {
- /*
- * If there's no FPU present, or if the
- * application has already restricted
- * the allowed set to exclude any CPUs
- * with FPUs, we'll skip the procedure.
- */
- if (cpus_intersects(current->cpus_allowed,
- mt_fpu_cpumask)) {
- cpumask_t tmask;
-
- cpus_and(tmask,
- current->thread.user_cpus_allowed,
- mt_fpu_cpumask);
- set_cpus_allowed(current, tmask);
- current->thread.mflags |= MF_FPUBOUND;
- }
- }
- }
-#endif /* CONFIG_MIPS_MT_FPAFF */
}
return;
case 2:
case 3:
- die_if_kernel("do_cpu invoked from kernel context!", regs);
break;
}
asmlinkage void do_mcheck(struct pt_regs *regs)
{
- const int field = 2 * sizeof(unsigned long);
- int multi_match = regs->cp0_status & ST0_TS;
-
show_regs(regs);
-
- if (multi_match) {
- printk("Index : %0x\n", read_c0_index());
- printk("Pagemask: %0x\n", read_c0_pagemask());
- printk("EntryHi : %0*lx\n", field, read_c0_entryhi());
- printk("EntryLo0: %0*lx\n", field, read_c0_entrylo0());
- printk("EntryLo1: %0*lx\n", field, read_c0_entrylo1());
- printk("\n");
- dump_tlb_all();
- }
-
- show_code((unsigned int *) regs->cp0_epc);
-
+ dump_tlb_all();
/*
* Some chips may have other causes of machine check (e.g. SB1
* graduation timer)
*/
panic("Caught Machine Check exception - %scaused by multiple "
"matching entries in the TLB.",
- (multi_match) ? "" : "not ");
+ (regs->cp0_status & ST0_TS) ? "" : "not ");
}
asmlinkage void do_mt(struct pt_regs *regs)
{
- int subcode;
-
- subcode = (read_vpe_c0_vpecontrol() & VPECONTROL_EXCPT)
- >> VPECONTROL_EXCPT_SHIFT;
- switch (subcode) {
- case 0:
- printk(KERN_DEBUG "Thread Underflow\n");
- break;
- case 1:
- printk(KERN_DEBUG "Thread Overflow\n");
- break;
- case 2:
- printk(KERN_DEBUG "Invalid YIELD Qualifier\n");
- break;
- case 3:
- printk(KERN_DEBUG "Gating Storage Exception\n");
- break;
- case 4:
- printk(KERN_DEBUG "YIELD Scheduler Exception\n");
- break;
- case 5:
- printk(KERN_DEBUG "Gating Storage Schedulier Exception\n");
- break;
- default:
- printk(KERN_DEBUG "*** UNKNOWN THREAD EXCEPTION %d ***\n",
- subcode);
- break;
- }
die_if_kernel("MIPS MT Thread exception in kernel", regs);
force_sig(SIGILL, current);
{
switch (current_cpu_data.cputype) {
case CPU_24K:
- case CPU_34K:
case CPU_5KC:
write_c0_ecc(0x80000000);
back_to_back_c0_hazard();
unsigned long depc, old_epc;
unsigned int debug;
- printk(KERN_DEBUG "SDBBP EJTAG debug exception - not handled yet, just ignored!\n");
+ printk("SDBBP EJTAG debug exception - not handled yet, just ignored!\n");
depc = read_c0_depc();
debug = read_c0_debug();
- printk(KERN_DEBUG "c0_depc = %0*lx, DEBUG = %08x\n", field, depc, debug);
+ printk("c0_depc = %0*lx, DEBUG = %08x\n", field, depc, debug);
if (debug & 0x80000000) {
/*
* In branch delay slot.
write_c0_depc(depc);
#if 0
- printk(KERN_DEBUG "\n\n----- Enable EJTAG single stepping ----\n\n");
+ printk("\n\n----- Enable EJTAG single stepping ----\n\n");
write_c0_debug(debug | 0x100);
#endif
}
*/
void nmi_exception_handler(struct pt_regs *regs)
{
-#ifdef CONFIG_MIPS_MT_SMTC
- unsigned long dvpret = dvpe();
- bust_spinlocks(1);
- printk("NMI taken!!!!\n");
- mips_mt_regdump(dvpret);
-#else
- bust_spinlocks(1);
printk("NMI taken!!!!\n");
-#endif /* CONFIG_MIPS_MT_SMTC */
die("NMI", regs);
while(1) ;
}
return (void *)old_handler;
}
-#ifdef CONFIG_CPU_MIPSR2_SRS
+#ifdef CONFIG_CPU_MIPSR2
/*
- * MIPSR2 shadow register set allocation
+ * Shadow register allocation
* FIXME: SMP...
*/
-static struct shadow_registers {
- /*
- * Number of shadow register sets supported
- */
- unsigned long sr_supported;
- /*
- * Bitmap of allocated shadow registers
- */
- unsigned long sr_allocated;
+/* MIPSR2 shadow register sets */
+struct shadow_registers {
+ spinlock_t sr_lock; /* */
+ int sr_supported; /* Number of shadow register sets supported */
+ int sr_allocated; /* Bitmap of allocated shadow registers */
} shadow_registers;
-static void mips_srs_init(void)
+void mips_srs_init(void)
{
+#ifdef CONFIG_CPU_MIPSR2_SRS
shadow_registers.sr_supported = ((read_c0_srsctl() >> 26) & 0x0f) + 1;
- printk(KERN_INFO "%d MIPSR2 register sets available\n",
- shadow_registers.sr_supported);
+ printk ("%d MIPSR2 register sets available\n", shadow_registers.sr_supported);
+#else
+ shadow_registers.sr_supported = 1;
+#endif
shadow_registers.sr_allocated = 1; /* Set 0 used by kernel */
+ spin_lock_init(&shadow_registers.sr_lock);
}
int mips_srs_max(void)
return shadow_registers.sr_supported;
}
-int mips_srs_alloc(void)
+int mips_srs_alloc (void)
{
struct shadow_registers *sr = &shadow_registers;
+ unsigned long flags;
int set;
-again:
- set = find_first_zero_bit(&sr->sr_allocated, sr->sr_supported);
- if (set >= sr->sr_supported)
- return -1;
+ spin_lock_irqsave(&sr->sr_lock, flags);
- if (test_and_set_bit(set, &sr->sr_allocated))
- goto again;
+ for (set = 0; set < sr->sr_supported; set++) {
+ if ((sr->sr_allocated & (1 << set)) == 0) {
+ sr->sr_allocated |= 1 << set;
+ spin_unlock_irqrestore(&sr->sr_lock, flags);
+ return set;
+ }
+ }
- return set;
+ /* None available */
+ spin_unlock_irqrestore(&sr->sr_lock, flags);
+ return -1;
}
-void mips_srs_free(int set)
+void mips_srs_free (int set)
{
struct shadow_registers *sr = &shadow_registers;
+ unsigned long flags;
- clear_bit(set, &sr->sr_allocated);
+ spin_lock_irqsave(&sr->sr_lock, flags);
+ sr->sr_allocated &= ~(1 << set);
+ spin_unlock_irqrestore(&sr->sr_lock, flags);
}
-static void *set_vi_srs_handler(int n, void *addr, int srs)
+void *set_vi_srs_handler (int n, void *addr, int srs)
{
unsigned long handler;
unsigned long old_handler = vi_handlers[n];
if (addr == NULL) {
handler = (unsigned long) do_default_vi;
srs = 0;
- } else
+ }
+ else
handler = (unsigned long) addr;
vi_handlers[n] = (unsigned long) addr;
if (cpu_has_veic) {
if (board_bind_eic_interrupt)
board_bind_eic_interrupt (n, srs);
- } else if (cpu_has_vint) {
+ }
+ else if (cpu_has_vint) {
/* SRSMap is only defined if shadow sets are implemented */
if (mips_srs_max() > 1)
change_c0_srsmap (0xf << n*4, srs << n*4);
extern char except_vec_vi, except_vec_vi_lui;
extern char except_vec_vi_ori, except_vec_vi_end;
-#ifdef CONFIG_MIPS_MT_SMTC
- /*
- * We need to provide the SMTC vectored interrupt handler
- * not only with the address of the handler, but with the
- * Status.IM bit to be masked before going there.
- */
- extern char except_vec_vi_mori;
- const int mori_offset = &except_vec_vi_mori - &except_vec_vi;
-#endif /* CONFIG_MIPS_MT_SMTC */
const int handler_len = &except_vec_vi_end - &except_vec_vi;
const int lui_offset = &except_vec_vi_lui - &except_vec_vi;
const int ori_offset = &except_vec_vi_ori - &except_vec_vi;
}
memcpy (b, &except_vec_vi, handler_len);
-#ifdef CONFIG_MIPS_MT_SMTC
- if (n > 7)
- printk("Vector index %d exceeds SMTC maximum\n", n);
- w = (u32 *)(b + mori_offset);
- *w = (*w & 0xffff0000) | (0x100 << n);
-#endif /* CONFIG_MIPS_MT_SMTC */
w = (u32 *)(b + lui_offset);
*w = (*w & 0xffff0000) | (((u32)handler >> 16) & 0xffff);
w = (u32 *)(b + ori_offset);
return (void *)old_handler;
}
-void *set_vi_handler(int n, void *addr)
+void *set_vi_handler (int n, void *addr)
{
- return set_vi_srs_handler(n, addr, 0);
+ return set_vi_srs_handler (n, addr, 0);
}
-
-#else
-
-static inline void mips_srs_init(void)
-{
-}
-
-#endif /* CONFIG_CPU_MIPSR2_SRS */
+#endif
/*
* This is used by native signal handling
extern asmlinkage int fpu_emulator_save_context(struct sigcontext *sc);
extern asmlinkage int fpu_emulator_restore_context(struct sigcontext *sc);
-#ifdef CONFIG_SMP
-static int smp_save_fp_context(struct sigcontext *sc)
-{
- return cpu_has_fpu
- ? _save_fp_context(sc)
- : fpu_emulator_save_context(sc);
-}
-
-static int smp_restore_fp_context(struct sigcontext *sc)
-{
- return cpu_has_fpu
- ? _restore_fp_context(sc)
- : fpu_emulator_restore_context(sc);
-}
-#endif
-
static inline void signal_init(void)
{
-#ifdef CONFIG_SMP
- /* For now just do the cpu_has_fpu check when the functions are invoked */
- save_fp_context = smp_save_fp_context;
- restore_fp_context = smp_restore_fp_context;
-#else
if (cpu_has_fpu) {
save_fp_context = _save_fp_context;
restore_fp_context = _restore_fp_context;
save_fp_context = fpu_emulator_save_context;
restore_fp_context = fpu_emulator_restore_context;
}
-#endif
}
#ifdef CONFIG_MIPS32_COMPAT
{
unsigned int cpu = smp_processor_id();
unsigned int status_set = ST0_CU0;
-#ifdef CONFIG_MIPS_MT_SMTC
- int secondaryTC = 0;
- int bootTC = (cpu == 0);
-
- /*
- * Only do per_cpu_trap_init() for first TC of Each VPE.
- * Note that this hack assumes that the SMTC init code
- * assigns TCs consecutively and in ascending order.
- */
-
- if (((read_c0_tcbind() & TCBIND_CURTC) != 0) &&
- ((read_c0_tcbind() & TCBIND_CURVPE) == cpu_data[cpu - 1].vpe_id))
- secondaryTC = 1;
-#endif /* CONFIG_MIPS_MT_SMTC */
/*
* Disable coprocessors and select 32-bit or 64-bit addressing
write_c0_hwrena (0x0000000f); /* Allow rdhwr to all registers */
#endif
-#ifdef CONFIG_MIPS_MT_SMTC
- if (!secondaryTC) {
-#endif /* CONFIG_MIPS_MT_SMTC */
-
/*
* Interrupt handling.
*/
} else
set_c0_cause(CAUSEF_IV);
}
-#ifdef CONFIG_MIPS_MT_SMTC
- }
-#endif /* CONFIG_MIPS_MT_SMTC */
cpu_data[cpu].asid_cache = ASID_FIRST_VERSION;
TLBMISS_HANDLER_SETUP();
BUG_ON(current->mm);
enter_lazy_tlb(&init_mm, current);
-#ifdef CONFIG_MIPS_MT_SMTC
- if (bootTC) {
-#endif /* CONFIG_MIPS_MT_SMTC */
- cpu_cache_init();
- tlb_init();
-#ifdef CONFIG_MIPS_MT_SMTC
- }
-#endif /* CONFIG_MIPS_MT_SMTC */
+ cpu_cache_init();
+ tlb_init();
}
/* Install CPU exception handler */
else
ebase = CAC_BASE;
+#ifdef CONFIG_CPU_MIPSR2
mips_srs_init();
+#endif
per_cpu_trap_init();
if (cpu_has_veic || cpu_has_vint) {
int nvec = cpu_has_veic ? 64 : 8;
for (i = 0; i < nvec; i++)
- set_vi_handler(i, NULL);
+ set_vi_handler (i, NULL);
}
else if (cpu_has_divec)
set_handler(0x200, &except_vec4, 0x8);
if (board_be_init)
board_be_init();
- set_except_vector(0, handle_int);
set_except_vector(1, handle_tlbm);
set_except_vector(2, handle_tlbl);
set_except_vector(3, handle_tlbs);