--- zzzz-none-000/linux-2.6.32.61/arch/mips/kernel/traps.c 2013-06-10 09:43:48.000000000 +0000 +++ ar10-7272-687/linux-2.6.32.61/arch/mips/kernel/traps.c 2016-11-17 17:25:39.000000000 +0000 @@ -48,7 +48,10 @@ #include #include #include - +#include +#if defined(CONFIG_MACH_ATHEROS) +#include +#endif /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ extern void check_wait(void); extern asmlinkage void r4k_wait(void); extern asmlinkage void rollback_handle_int(void); @@ -78,11 +81,14 @@ extern int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx, int has_fpu); +extern int print_mem_config(struct mm_struct *mmm, unsigned long addr); +extern int print_code_range(struct seq_file *seq, const char *prefix, unsigned int __user *pc, unsigned int mips16, unsigned int usermode, int left_offset, int right_offset, unsigned long *badaddr); #ifdef CONFIG_CPU_CAVIUM_OCTEON extern asmlinkage void octeon_cop2_restore(struct octeon_cop2_state *task); #endif +unsigned int avm_nmi_taken; void (*board_be_init)(void); int (*board_be_handler)(struct pt_regs *regs, int is_fixup); void (*board_nmi_handler_setup)(void); @@ -95,21 +101,26 @@ unsigned long *sp = (unsigned long *)(reg29 & ~3); unsigned long addr; - printk("Call Trace:"); -#ifdef CONFIG_KALLSYMS - printk("\n"); -#endif + /*--- printk(KERN_ERR " %s/%d", __FUNCTION__, __LINE__); ---*/ + printk(KERN_ERR "Call Trace:\n"); while (!kstack_end(sp)) { unsigned long __user *p = (unsigned long __user *)(unsigned long)sp++; if (__get_user(addr, p)) { - printk(" (Bad stack address)"); + printk("\n"); + printk(KERN_ERR " (Bad stack address)"); break; } - if (__kernel_text_address(addr)) - print_ip_sym(addr); + if (__kernel_text_address(addr)) { + /*--- printk(KERN_ERR " %s/%d", __FUNCTION__, __LINE__); ---*/ + /*--- printk(KERN_ERR); ---*/ + printk(KERN_ERR "[<%p>] %pS\n", (void *)addr, (void *)addr); + /*--- print_ip_sym(addr); ---*/ + } + /*--- printk("\n"); ---*/ + /*--- printk(KERN_ERR " %s/%d", __FUNCTION__, __LINE__); ---*/ } - printk("\n"); + /*--- printk("\n"); ---*/ } #ifdef CONFIG_KALLSYMS @@ -122,17 +133,19 @@ __setup("raw_show_trace", set_raw_show_trace); #endif -static void show_backtrace(struct task_struct *task, const struct pt_regs *regs) +void show_backtrace(struct task_struct *task, const struct pt_regs *regs) { unsigned long sp = regs->regs[29]; unsigned long ra = regs->regs[31]; unsigned long pc = regs->cp0_epc; + if (!task) + task = current; if (raw_show_trace || !__kernel_text_address(pc)) { show_raw_backtrace(sp); return; } - printk("Call Trace:\n"); + printk(KERN_ERR"Call Trace:\n"); do { print_ip_sym(pc); pc = unwind_stack(task, &sp, pc, &ra); @@ -156,7 +169,7 @@ i = 0; while ((unsigned long) sp & (PAGE_SIZE - 1)) { if (i && ((i % (64 / field)) == 0)) - printk("\n "); + printk("\n "); if (i > 39) { printk(" ..."); break; @@ -186,6 +199,11 @@ regs.regs[29] = task->thread.reg29; regs.regs[31] = 0; regs.cp0_epc = task->thread.reg31; +#ifdef CONFIG_KGDB_KDB + } else if (atomic_read(&kgdb_active) != -1 && + kdb_current_regs) { + memcpy(®s, kdb_current_regs, sizeof(regs)); +#endif /* CONFIG_KGDB_KDB */ } else { prepare_frametrace(®s); } @@ -211,7 +229,7 @@ long i; unsigned short __user *pc16 = NULL; - printk("\nCode:"); + printk(KERN_EMERG"\nCode:"); if ((unsigned long)pc & 1) pc16 = (unsigned short __user *)((unsigned long)pc & ~1); @@ -228,7 +246,7 @@ static void __show_regs(const struct pt_regs *regs) { const int field = 2 * sizeof(unsigned long); - unsigned int cause = regs->cp0_cause; + unsigned int cause = regs->cp0_cause, exc_code; int i; printk("Cpu %d\n", smp_processor_id()); @@ -256,16 +274,16 @@ #endif printk("Hi : %0*lx\n", field, regs->hi); printk("Lo : %0*lx\n", field, regs->lo); +#if defined(__mips_dsp) + printk("ac1Hi: %0*lx ac1Lo: %0*lx\n", field, regs->ac1hi, field, regs->ac1lo); + printk("ac2Hi: %0*lx ac2Lo: %0*lx\n", field, regs->ac2hi, field, regs->ac2lo); + printk("ac3Hi: %0*lx ac3Lo: %0*lx\n", field, regs->ac3hi, field, regs->ac3lo); + printk("dspcontrol: %0*lx\n", field, regs->dspctrl); +#endif/*--- #if defined(__mips_dsp) ---*/ /* * Saved cp0 registers */ - printk("epc : %0*lx %pS\n", field, regs->cp0_epc, - (void *) regs->cp0_epc); - printk(" %s\n", print_tainted()); - printk("ra : %0*lx %pS\n", field, regs->regs[31], - (void *) regs->regs[31]); - printk("Status: %08x ", (uint32_t) regs->cp0_status); if (current_cpu_data.isa_level == MIPS_CPU_ISA_I) { @@ -311,11 +329,27 @@ } printk("\n"); - printk("Cause : %08x\n", cause); + exc_code = (cause & CAUSEF_EXCCODE) >> CAUSEB_EXCCODE; + printk(KERN_ERR"Cause : %08x exc_code:%d %s\n", cause, exc_code, + exc_code == 1 ? "Mod" : + exc_code == 2 ? "TLBL" : + exc_code == 3 ? "TLBS" : + exc_code == 4 ? "AdEL" : + exc_code == 5 ? "AdES" : + exc_code == 6 ? "IBE" : + exc_code == 7 ? "DBE" : + exc_code == 25 ? "Thread" : + exc_code == 31 ? "CacheErr" : "" + ); cause = (cause & CAUSEF_EXCCODE) >> CAUSEB_EXCCODE; - if (1 <= cause && cause <= 5) + if (1 <= exc_code && exc_code <= 5) { printk("BadVA : %0*lx\n", field, regs->cp0_badvaddr); + } + printk(KERN_ERR"epc : %0*lx %pS\n", field, regs->cp0_epc, (void *) regs->cp0_epc); + printk(KERN_ERR"errepc: %08lx %pS\n", read_c0_errorepc(), (void *)read_c0_errorepc()); + printk(KERN_ERR" %s\n", print_tainted()); + printk(KERN_ERR"ra : %0*lx %pS\n", field, regs->regs[31], (void *) regs->regs[31]); printk("PrId : %08x (%s)\n", read_c0_prid(), cpu_name_string()); @@ -353,21 +387,43 @@ static DEFINE_SPINLOCK(die_lock); +bool arch_trigger_all_cpu_backtrace(void) { +#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC) + struct pt_regs regs; + int tc = 0, cur_tc; + while((cur_tc = mips_mt_prepare_frametrace(tc, ®s)) != -1) { + if(cur_tc == 0) { + printk("TC %x:\n", tc); + show_backtrace(NULL, ®s); + } + tc++; + } + return 1; +#endif /*--- #if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC) ---*/ + return 0; +} void __noreturn die(const char * str, const struct pt_regs * regs) { static int die_counter; -#ifdef CONFIG_MIPS_MT_SMTC +#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC) unsigned long dvpret = dvpe(); -#endif /* CONFIG_MIPS_MT_SMTC */ +#endif /*--- #if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC) ---*/ console_verbose(); + restore_printk(); + spin_lock_irq(&die_lock); bust_spinlocks(1); -#ifdef CONFIG_MIPS_MT_SMTC +#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC) mips_mt_regdump(dvpret); -#endif /* CONFIG_MIPS_MT_SMTC */ +#endif /*--- #if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC) ---*/ printk("%s[#%d]:\n", str, ++die_counter); +#ifndef CONFIG_MAPPING show_registers(regs); +#endif +#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC) + arch_trigger_all_cpu_backtrace(); +#endif /*--- #if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC) ---*/ add_taint(TAINT_DIE); spin_unlock_irq(&die_lock); @@ -376,13 +432,106 @@ if (panic_on_oops) { printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n"); - ssleep(5); + mdelay(5000); panic("Fatal exception"); } - do_exit(SIGSEGV); } +/*------------------------------------------------------------------------------------------*\ +\*------------------------------------------------------------------------------------------*/ +#ifdef CONFIG_BUG_EXTRA_INFO +extern unsigned long __start___bug_debug_table; +extern unsigned long __stop___bug_debug_table; + +#define MAX_BUG_TABLES 20 +struct bug_debug_tables { + char *name; + struct bug_debug_table_entry *start; + struct bug_debug_table_entry *stop; +} bug_debug_table[MAX_BUG_TABLES] = { + [0] = { + .name = "kernel", + .start = (struct bug_debug_table_entry *)&__start___bug_debug_table, + .stop = (struct bug_debug_table_entry *)&__stop___bug_debug_table + } +}; + +__asm__( +" .section __bug_debug_table, \"a\"\n" +" .previous \n"); + +/*------------------------------------------------------------------------------------------*\ +\*------------------------------------------------------------------------------------------*/ +void register_bug_debug_table(char *name, unsigned long start, unsigned long end) { + unsigned int i; + for(i = 0 ; i < MAX_BUG_TABLES ; i++) { + struct bug_debug_tables *T = &bug_debug_table[i]; + if(T->name == NULL) { + printk("[%s] name='%s' 0x%lx - 0x%lx\n", __FUNCTION__, name, start, end); + T->name = name; + T->start = (struct bug_debug_table_entry *)start; + T->stop = (struct bug_debug_table_entry *)end; + return; + } + } +} + +/*------------------------------------------------------------------------------------------*\ +\*------------------------------------------------------------------------------------------*/ +void release_bug_debug_table(char *name) { + unsigned int i; + for(i = 0 ; i < MAX_BUG_TABLES ; i++) { + struct bug_debug_tables *T = &bug_debug_table[i]; + if(T->name == name) { + T->name = NULL; + T->start = (struct bug_debug_table_entry *)0UL; + T->stop = (struct bug_debug_table_entry *)0UL; + return; + } + } +} + + +EXPORT_SYMBOL(register_bug_debug_table); +EXPORT_SYMBOL(release_bug_debug_table); + +/*------------------------------------------------------------------------------------------*\ +\*------------------------------------------------------------------------------------------*/ +static const struct bug_debug_table_entry *search_bug_debug_tables(unsigned long addr) +{ + const struct bug_debug_table_entry *e; + unsigned int i; + + /*--- printk(KERN_ERR "[%s] addr 0x%lx %s", __FUNCTION__, addr, addr & 0x1 ? "(mips16)" : ""); ---*/ + + addr &= ~0x1; + + + for(i = 0 ; i < MAX_BUG_TABLES ; i++) { + struct bug_debug_tables *T = &bug_debug_table[i]; + /*--- printk(KERN_ERR "[%s] '%s' search from 0x%p to 0x%p\n", __FUNCTION__, T->name, T->start, T->stop); ---*/ + + if(T->name == NULL) + continue; + + for(e = T->start ; e < T->stop ; e++) { + /*--- if(i == 1) ---*/ + /*--- printk(KERN_ERR "[%s] '%s' addr 0x%lx e->addr 0x%lx\n", __FUNCTION__, T->name, addr, e->addr); ---*/ + if(e->addr + 4 == addr) { + /*--- printk(KERN_ERR "[%s] found: '%s' addr 0x%lx + 4 == e->addr 0x%lx\n", __FUNCTION__, T->name, addr, e->addr); ---*/ + return e; + } + if(e->addr == addr) { + /*--- printk(KERN_ERR "[%s] found: '%s' addr 0x%lx == e->addr 0x%lx\n", __FUNCTION__, T->name, addr, e->addr); ---*/ + return e; + } + } + } + return NULL; +} +#endif /*--- #ifdef CONFIG_BUG_EXTRA_INFO ---*/ + extern struct exception_table_entry __start___dbe_table[]; extern struct exception_table_entry __stop___dbe_table[]; @@ -395,7 +544,15 @@ { const struct exception_table_entry *e; - e = search_extable(__start___dbe_table, __stop___dbe_table - 1, addr); + + e = search_extable(__start___dbe_table, __stop___dbe_table - 1, addr - 8UL); + if(e) { + /*--- printk(KERN_ERR "[%s] addr=0x%lx addr-0x%lx=0x%lx e=0x%p, nextinsn 0x%lx\n", ---*/ + /*--- __FUNCTION__, addr, 8UL, addr - 8UL, e, e->nextinsn); ---*/ + return e; + } + /*--- e = search_extable(__start___dbe_table, __stop___dbe_table - 1, addr); ---*/ + if (!e) e = search_module_dbetables(addr); return e; @@ -441,6 +598,7 @@ == NOTIFY_STOP) return; + avm_nmi_taken = ~0xdeadbabe; die_if_kernel("Oops", regs); force_sig(SIGBUS, current); } @@ -618,17 +776,31 @@ return -1; /* Must be something else ... */ } -asmlinkage void do_ov(struct pt_regs *regs) -{ - siginfo_t info; - - die_if_kernel("Integer overflow", regs); - - info.si_code = FPE_INTOVF; - info.si_signo = SIGFPE; - info.si_errno = 0; - info.si_addr = (void __user *) regs->cp0_epc; - force_sig_info(SIGFPE, &info, current); +/*------------------------------------------------------------------------------------------*\ +\*------------------------------------------------------------------------------------------*/ +asmlinkage void do_ov(struct pt_regs *regs) { + siginfo_t info; + unsigned int __user *pc; + unsigned long addr = 0UL; + + pc = (unsigned int __user *) exception_epc(regs); + printk(KERN_ERR "[kernel-integer-overflow] pc=0x%p(%pF) addr=0x%08lx task=%s pid=%d ra=0x%08lx(%pF)\n", + pc, pc, regs->cp0_badvaddr, current->comm, current->pid, + regs->regs[31], (void *)regs->regs[31] + ); + print_code_range(NULL, "kernel-integer-overflow", pc, regs->cp0_epc & 0x1, user_mode(regs), -2, 3, &addr); + if (user_mode(regs)) { + if(print_mem_config(current->active_mm, (unsigned long)pc)) + print_mem_config(current->mm, (unsigned long)pc); + } + + die_if_kernel("Integer overflow", regs); + + info.si_code = FPE_INTOVF; + info.si_signo = SIGFPE; + info.si_errno = 0; + info.si_addr = (void __user *) regs->cp0_epc; + force_sig_info(SIGFPE, &info, current); } /* @@ -637,6 +809,19 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) { siginfo_t info; + unsigned int __user *pc; + unsigned long addr = 0UL; + + pc = (unsigned int __user *) exception_epc(regs); + printk(KERN_ERR "[kernel-floatingpoint-exception] pc=0x%p(%pF) addr=0x%08lx task=%s pid=%d ra=0x%08lx(%pF)\n", + pc, pc, regs->cp0_badvaddr, current->comm, current->pid, + regs->regs[31], (void *)regs->regs[31] + ); + print_code_range(NULL, "kernel-floatingpoint-exception", pc, regs->cp0_epc & 0x1, user_mode(regs), -2, 3, &addr); + if (user_mode(regs)) { + if(print_mem_config(current->active_mm, (unsigned long)pc)) + print_mem_config(current->mm, (unsigned long)pc); + } if (notify_die(DIE_FP, "FP exception", regs, SIGFPE, 0, 0) == NOTIFY_STOP) @@ -724,8 +909,21 @@ force_sig_info(SIGFPE, &info, current); break; case BRK_BUG: - die_if_kernel("Kernel bug detected", regs); - force_sig(SIGTRAP, current); + { +#ifdef CONFIG_BUG_EXTRA_INFO + const struct bug_debug_table_entry *bug_info = search_bug_debug_tables(regs->cp0_epc); + if(bug_info) { + printk(KERN_ERR "BUG%s(%s) at function '%s' line: %d file: %s\n", + bug_info->condition ? "_ON" : "", + bug_info->condition ? bug_info->condition : "", + bug_info->functionname, bug_info->line, bug_info->filename); + } else { + printk(KERN_ERR "BUG() no bug_debug_table_entry found\n"); + } +#endif /*--- #ifdef CONFIG_BUG_EXTRA_INFO ---*/ + die_if_kernel("Kernel bug detected", regs); + force_sig(SIGTRAP, current); + } break; case BRK_MEMU: /* @@ -752,6 +950,19 @@ asmlinkage void do_bp(struct pt_regs *regs) { unsigned int opcode, bcode; + unsigned int __user *pc; + unsigned long addr = 0UL; + + pc = (unsigned int __user *) exception_epc(regs); + printk(KERN_ERR "[kernel-breakpoint] pc=0x%p(%pF) addr=0x%08lx task=%s pid=%d ra=0x%08lx(%pF)\n", + pc, pc, regs->cp0_badvaddr, current->comm, current->pid, + regs->regs[31], (void *)regs->regs[31] + ); + print_code_range(NULL, "kernel-breakpoint", pc, regs->cp0_epc & 0x1, user_mode(regs), -2, 3, &addr); + if (user_mode(regs)) { + if(print_mem_config(current->active_mm, (unsigned long)pc)) + print_mem_config(current->mm, (unsigned long)pc); + } if (__get_user(opcode, (unsigned int __user *) exception_epc(regs))) goto out_sigsegv; @@ -776,6 +987,19 @@ asmlinkage void do_tr(struct pt_regs *regs) { unsigned int opcode, tcode = 0; + unsigned int __user *pc; + unsigned long addr = 0UL; + + pc = (unsigned int __user *) exception_epc(regs); + printk(KERN_ERR "[kernel-trap] pc=0x%p(%pF) addr=0x%08lx task=%s pid=%d ra=0x%08lx(%pF)\n", + pc, pc, regs->cp0_badvaddr, current->comm, current->pid, + regs->regs[31], (void *)regs->regs[31] + ); + print_code_range(NULL, "kernel-trap", pc, regs->cp0_epc & 0x1, user_mode(regs), -2, 3, &addr); + if (user_mode(regs)) { + if(print_mem_config(current->active_mm, (unsigned long)pc)) + print_mem_config(current->mm, (unsigned long)pc); + } if (__get_user(opcode, (unsigned int __user *) exception_epc(regs))) goto out_sigsegv; @@ -943,6 +1167,8 @@ force_sig(SIGILL, current); } + + /* * Called with interrupts disabled. */ @@ -950,6 +1176,13 @@ { u32 cause; + +#if defined(CONFIG_AVM_WP) + if (avm_wp_dispatcher()) { + local_irq_enable(); + return; + } +#endif /* * Clear WP (bit 22) bit of cause register so we don't loop * forever. @@ -957,6 +1190,7 @@ cause = read_c0_cause(); cause &= ~(1 << 22); write_c0_cause(cause); + /* * If the current thread has the watch registers loaded, save @@ -1024,7 +1258,7 @@ printk(KERN_DEBUG "YIELD Scheduler Exception\n"); break; case 5: - printk(KERN_DEBUG "Gating Storage Schedulier Exception\n"); + printk(KERN_DEBUG "Gating Storage Scheduler Exception\n"); break; default: printk(KERN_DEBUG "*** UNKNOWN THREAD EXCEPTION %d ***\n", @@ -1162,22 +1396,26 @@ unsigned int reg_val; /* For the moment, report the problem and hang. */ - printk("Cache error exception:\n"); + printk("Cache error exception, cp0_ecc=0x%08x:\n",read_c0_ecc()); printk("cp0_errorepc == %0*lx\n", field, read_c0_errorepc()); reg_val = read_c0_cacheerr(); printk("c0_cacheerr == %08x\n", reg_val); + if ((reg_val & 0xc0000000) == 0xc0000000) + printk("Decoded c0_cacheerr: FTLB parity error\n"); + else printk("Decoded c0_cacheerr: %s cache fault in %s reference.\n", reg_val & (1<<30) ? "secondary" : "primary", reg_val & (1<<31) ? "data" : "insn"); - printk("Error bits: %s%s%s%s%s%s%s\n", + printk("Error bits: %s%s%s%s%s%s%s%s\n", reg_val & (1<<29) ? "ED " : "", reg_val & (1<<28) ? "ET " : "", + reg_val & (1<<27) ? "ES " : "", reg_val & (1<<26) ? "EE " : "", reg_val & (1<<25) ? "EB " : "", - reg_val & (1<<24) ? "EI " : "", - reg_val & (1<<23) ? "E1 " : "", - reg_val & (1<<22) ? "E0 " : ""); + reg_val & (1<<24) ? "EI/EF " : "", + reg_val & (1<<23) ? "E1/SP " : "", + reg_val & (1<<22) ? "E0/EW " : ""); printk("IDX: 0x%08x\n", reg_val & ((1<<22)-1)); #if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64) @@ -1230,14 +1468,87 @@ /* * NMI exception handler. */ -NORET_TYPE void ATTRIB_NORET nmi_exception_handler(struct pt_regs *regs) -{ +#include +#include + +extern void set_reboot_status_to_NMI(void); +/*--------------------------------------------------------------------------------*\ +Atheros: Exception 0xbfc00380 wird auch auf nmi_exception_handler gelegt +\*--------------------------------------------------------------------------------*/ +void __noreturn nmi_exception_handler(struct pt_regs *regs) { + struct task_struct *curr __attribute__ ((unused)); + int status __attribute__ ((unused)); + char str[100]; +#if !defined(CONFIG_MIPS_UR8) && !defined(CONFIG_MIPS_FUSIV) + set_reboot_status_to_NMI(); +#endif +#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC) + { + unsigned long vpe_status = 0; + vpe_status = dvpe(); +#endif/*--- #ifdef CONFIG_SMP ---*/ +#if defined(CONFIG_NMI_ARBITER_WORKAROUND) + do { + ath_reg_wr(ATH_WATCHDOG_TMR, 0x1000 << 16); + wmb(); + } while(ath_reg_rd(ATH_WATCHDOG_TMR)); + ath_reg_wr(ATH_WATCHDOG_TMR_CONTROL, ATH_WD_ACT_RESET); + wmb(); + memset(&nmi_workaround_func, 0, sizeof(struct _nmi_workaround_func)); +#elif defined(CONFIG_MACH_ATHEROS) + printk(KERN_ERR"nmi_wd-register tmr %x tmr_control %x\n", ath_reg_rd(ATH_WATCHDOG_TMR), ath_reg_rd(ATH_WATCHDOG_TMR_CONTROL)); +#elif defined(CONFIG_VR9) || defined(CONFIG_AR10) + *(volatile unsigned int *)(0xbf101000 + 0xF0) = (1<<31); /*--- clear NMI-IrqStatus ---*/ +#endif /*--- #if defined(CONFIG_VR9) ---*/ + status = read_c0_status(); + status &= ~(1 << 0); /* disable all interrupts */ + status &= ~(1 << 19); /* reset NMI status */ + status &= ~(1 << 22); /* bootstrap bit BEV zurücksetzen */ + /*--------------------------------------------------------------------------------*\ + * mbahr: + Doku MIPS32 4KE Processor Cores Software User's Manual: + Operation: + // If StatusEXL is 1, all exceptions go through the general exception vector !!! + // and neither EPC nor CauseBD nor SRSCtl are modified + if StatusEXL = 1 then + vectorOffset ← 16#180 + else + if InstructionInBranchDelaySlot then + EPC ← restartPC // PC of branch/jump + CauseBD ← 1 + else + EPC ← restartPC //PC of instruction + CauseBD ← 0 + endif + .... + -> NMI setzt EXL!!!!!! + \*--------------------------------------------------------------------------------*/ + status &= ~(1 << 1); /* Superwichtig! EXL ruecksetzen - somit funktionieren nachfolgend auch TLB-Exceptions (Zugriff auf virtuellen Speicher)*/ + write_c0_status(status); + bust_spinlocks(1); - printk("NMI taken!!!!\n"); - die("NMI", regs); + console_verbose(); + restore_printk(); + + + printk(KERN_EMERG"\nHardwareWatchDog - NMI taken !!!!\n"); +#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC) + evpe(vpe_status); + } +#endif + snprintf(str, sizeof(str), "CPU%d NMI taken epc=%pF",smp_processor_id(), (void *)read_c0_errorepc()); + die(str, regs); } +#if defined(CONFIG_NMI_ARBITER_WORKAROUND) +EXPORT_SYMBOL(nmi_exception_handler); +#endif/*--- #if defined(CONFIG_NMI_ARBITER_WORKAROUND) ---*/ + +#if defined(CONFIG_LANTIQ) +#define VECTORSPACING 0x200 /* for EI/VI mode */ +#else #define VECTORSPACING 0x100 /* for EI/VI mode */ +#endif unsigned long ebase; unsigned long exception_handlers[32]; @@ -1248,17 +1559,29 @@ * to interrupt handlers in the address range from * KSEG0 <= x < KSEG0 + 256mb on the Nevada. Oh well ... */ -void *set_except_vector(int n, void *addr) +void __init *set_except_vector(int n, void *addr) { unsigned long handler = (unsigned long) addr; unsigned long old_handler = exception_handlers[n]; + extern char except_vec4_lui, except_vec4_ori, except_vec4; /* genex.S */ exception_handlers[n] = handler; if (n == 0 && cpu_has_divec) { + *(volatile u32 *)(&except_vec4_lui - &except_vec4 + ebase + 0x200) = + (*(volatile u32 *)(&except_vec4_lui - &except_vec4 + ebase + 0x200) & 0xffff0000) | ((handler >> 16) & 0xffff); + + *(volatile u32 *)(&except_vec4_ori - &except_vec4 + ebase + 0x200) = + (*(volatile u32 *)(&except_vec4_ori - &except_vec4 + ebase + 0x200) & 0xffff0000) | (handler & 0xffff); + flush_icache_range(ebase + 0x200, ebase + 0x210); + } +#if 0 + if (n == 0 && cpu_has_divec) { *(u32 *)(ebase + 0x200) = 0x08000000 | (0x03ffffff & (handler >> 2)); local_flush_icache_range(ebase + 0x200, ebase + 0x204); + printk("[%s] setup handler (%#x), %pF, op-code '%#x' \n", __FUNCTION__, handler, (void*)handler, *(u32 *)(ebase + 0x200)); } +#endif return (void *)old_handler; } @@ -1376,8 +1699,10 @@ extern asmlinkage int _save_fp_context(struct sigcontext __user *sc); extern asmlinkage int _restore_fp_context(struct sigcontext __user *sc); +#if !defined(CONFIG_ATH_2x8) extern asmlinkage int fpu_emulator_save_context(struct sigcontext __user *sc); extern asmlinkage int fpu_emulator_restore_context(struct sigcontext __user *sc); +#endif #ifdef CONFIG_SMP static int smp_save_fp_context(struct sigcontext __user *sc) @@ -1519,7 +1844,11 @@ write_c0_status(sr); /* Setting vector spacing enables EI/VI mode */ change_c0_intctl(0x3e0, VECTORSPACING); + } else { + /*--- printk("[%s] ebase before writing %#x, new ebase %#x \n",__FUNCTION__, (unsigned int)read_c0_ebase() , (unsigned int)ebase); ---*/ + write_c0_ebase(ebase); } + if (cpu_has_divec) { if (cpu_has_mipsmt) { unsigned int vpflags = dvpe(); @@ -1628,6 +1957,21 @@ if (kgdb_early_setup) return; /* Already done */ #endif +#if 0 + printk("[%s] rollback = %d \n", __FUNCTION__, rollback); + if (cpu_has_veic ) printk("[%s] cpu_has_veic \n", __FUNCTION__); + if (cpu_has_vint) printk("[%s] cpu_has_vint\n", __FUNCTION__); + if (cpu_has_ejtag ) printk("[%s] cpu_has_ejtag \n", __FUNCTION__); + if (cpu_has_watch) printk("[%s] cpu_has_watch\n", __FUNCTION__); + if (cpu_has_divec) printk("[%s] cpu_has_divec\n", __FUNCTION__); + if (cpu_has_vtag_icache ) printk("[%s] cpu_has_vtag_icache \n", __FUNCTION__); + if (cpu_has_fpu ) printk("[%s] cpu_has_fpu \n", __FUNCTION__); + if (cpu_has_nofpuex) printk("[%s] cpu_has_nofpuex\n", __FUNCTION__); + if (cpu_has_mcheck) printk("[%s] cpu_has_mcheck\n", __FUNCTION__); + if (cpu_has_mipsmt) printk("[%s] cpu_has_mipsmt\n", __FUNCTION__); + if (cpu_has_vce) printk("[%s] cpu_has_vce\n", __FUNCTION__); + if (cpu_has_4kex) printk("[%s] cpu_has_4kex\n", __FUNCTION__); +#endif if (cpu_has_veic || cpu_has_vint) { unsigned long size = 0x200 + VECTORSPACING*64; @@ -1676,7 +2020,10 @@ set_vi_handler(i, NULL); } else if (cpu_has_divec) - set_handler(0x200, &except_vec4, 0x8); + set_handler(0x200, &except_vec4, 0x10); + /* hbl: Vorgeschlagene Lantiq-Aenderung + * set_handler(0x200, &except_vec4, 0x8); + */ /* * Some CPUs can enable/disable for cache parity detection, but does