diff options
Diffstat (limited to 'cvmx-interrupt.c')
-rw-r--r-- | cvmx-interrupt.c | 373 |
1 files changed, 194 insertions, 179 deletions
diff --git a/cvmx-interrupt.c b/cvmx-interrupt.c index fdf3645c320d3..9280e8d7d9a6b 100644 --- a/cvmx-interrupt.c +++ b/cvmx-interrupt.c @@ -1,39 +1,40 @@ /***********************license start*************** - * Copyright (c) 2003-2008 Cavium Networks (support@cavium.com). All rights - * reserved. + * Copyright (c) 2003-2010 Cavium Networks (support@cavium.com). All rights + * reserved. * * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * * Neither the name of Cavium Networks nor the names of - * its contributors may be used to endorse or promote products - * derived from this software without specific prior written - * permission. - * - * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" - * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS - * OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH - * RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY - * REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT - * DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES - * OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR - * PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET - * POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT - * OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU. - * - * - * For any questions regarding licensing please contact marketing@caviumnetworks.com + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + + * * Neither the name of Cavium Networks nor the names of + * its contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + + * This Software, including technical data, may be subject to U.S. export control + * laws, including the U.S. Export Administration Act and its associated + * regulations, and may be subject to export or import regulations in other + * countries. + + * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" + * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR + * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO + * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR + * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM + * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, + * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF + * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR + * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR + * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. ***********************license end**************************************/ @@ -41,17 +42,20 @@ + /** * @file * * Interface to the Mips interrupts. * - * <hr>$Revision: 42264 $<hr> + * <hr>$Revision: 52004 $<hr> */ +#ifndef __U_BOOT__ #if __GNUC__ >= 4 /* Backtrace is only available with the new toolchain. */ #include <execinfo.h> #endif +#endif /* __U_BOOT__ */ #include "cvmx-config.h" #include "cvmx.h" #include "cvmx-interrupt.h" @@ -62,10 +66,15 @@ #include "cvmx-coremask.h" #include "cvmx-spinlock.h" #include "cvmx-app-init.h" +#include "cvmx-error.h" +#include "../../bootloader/u-boot/include/octeon_mem_map.h" EXTERN_ASM void cvmx_interrupt_stage1(void); +EXTERN_ASM void cvmx_debug_handler_stage1(void); EXTERN_ASM void cvmx_interrupt_cache_error(void); +int cvmx_interrupt_in_isr = 0; + /** * Internal status the interrupt registration */ @@ -79,17 +88,108 @@ typedef struct /** * Internal state the interrupt registration */ +#ifndef __U_BOOT__ static CVMX_SHARED cvmx_interrupt_state_t cvmx_interrupt_state; static CVMX_SHARED cvmx_spinlock_t cvmx_interrupt_default_lock; +#endif /* __U_BOOT__ */ -#define COP0_CAUSE "$13,0" -#define COP0_STATUS "$12,0" -#define COP0_BADVADDR "$8,0" -#define COP0_EPC "$14,0" -#define READ_COP0(dest, R) asm volatile ("dmfc0 %[rt]," R : [rt] "=r" (dest)) #define ULL unsigned long long +#define HI32(data64) ((uint32_t)(data64 >> 32)) +#define LO32(data64) ((uint32_t)(data64 & 0xFFFFFFFF)) +static const char reg_names[][32] = { "r0","at","v0","v1","a0","a1","a2","a3", + "t0","t1","t2","t3","t4","t5","t6","t7", + "s0","s1","s2","s3","s4","s5", "s6","s7", + "t8","t9", "k0","k1","gp","sp","s8","ra" }; + +/** + * version of printf that works better in exception context. + * + * @param format + */ +void cvmx_safe_printf(const char *format, ...) +{ + char buffer[256]; + char *ptr = buffer; + int count; + va_list args; + + va_start(args, format); +#ifndef __U_BOOT__ + count = vsnprintf(buffer, sizeof(buffer), format, args); +#else + count = vsprintf(buffer, format, args); +#endif + va_end(args); + + while (count-- > 0) + { + cvmx_uart_lsr_t lsrval; + + /* Spin until there is room */ + do + { + lsrval.u64 = cvmx_read_csr(CVMX_MIO_UARTX_LSR(0)); +#if !defined(CONFIG_OCTEON_SIM_SPEED) + if (lsrval.s.temt == 0) + cvmx_wait(10000); /* Just to reduce the load on the system */ +#endif + } + while (lsrval.s.temt == 0); + + if (*ptr == '\n') + cvmx_write_csr(CVMX_MIO_UARTX_THR(0), '\r'); + cvmx_write_csr(CVMX_MIO_UARTX_THR(0), *ptr++); + } +} + +/* Textual descriptions of cause codes */ +static const char cause_names[][128] = { + /* 0 */ "Interrupt", + /* 1 */ "TLB modification", + /* 2 */ "tlb load/fetch", + /* 3 */ "tlb store", + /* 4 */ "address exc, load/fetch", + /* 5 */ "address exc, store", + /* 6 */ "bus error, instruction fetch", + /* 7 */ "bus error, load/store", + /* 8 */ "syscall", + /* 9 */ "breakpoint", + /* 10 */ "reserved instruction", + /* 11 */ "cop unusable", + /* 12 */ "arithmetic overflow", + /* 13 */ "trap", + /* 14 */ "", + /* 15 */ "floating point exc", + /* 16 */ "", + /* 17 */ "", + /* 18 */ "cop2 exception", + /* 19 */ "", + /* 20 */ "", + /* 21 */ "", + /* 22 */ "mdmx unusable", + /* 23 */ "watch", + /* 24 */ "machine check", + /* 25 */ "", + /* 26 */ "", + /* 27 */ "", + /* 28 */ "", + /* 29 */ "", + /* 30 */ "cache error", + /* 31 */ "" +}; + +/** + * @INTERNAL + * print_reg64 + * @param name Name of the value to print + * @param reg Value to print + */ +static inline void print_reg64(const char *name, uint64_t reg) +{ + cvmx_safe_printf("%16s: 0x%08x%08x\n", name, (unsigned int)HI32(reg),(unsigned int)LO32(reg)); +} /** * @INTERNAL @@ -99,26 +199,25 @@ static CVMX_SHARED cvmx_spinlock_t cvmx_interrupt_default_lock; */ static void __cvmx_interrupt_dump_registers(uint64_t registers[32]) { - static const char *name[32] = {"r0","at","v0","v1","a0","a1","a2","a3", - "t0","t1","t2","t3","t4","t5","t6","t7","s0","s1","s2","s3","s4","s5", - "s6","s7", "t8","t9", "k0","k1","gp","sp","s8","ra"}; - uint64_t reg; + uint64_t r1, r2; + int reg; for (reg=0; reg<16; reg++) { - cvmx_safe_printf("%3s ($%02d): 0x%016llx \t %3s ($%02d): 0x%016llx\n", - name[reg], (int)reg, (ULL)registers[reg], name[reg+16], (int)reg+16, (ULL)registers[reg+16]); + r1 = registers[reg]; r2 = registers[reg+16]; + cvmx_safe_printf("%3s ($%02d): 0x%08x%08x \t %3s ($%02d): 0x%08x%08x\n", + reg_names[reg], reg, (unsigned int)HI32(r1), (unsigned int)LO32(r1), + reg_names[reg+16], reg+16, (unsigned int)HI32(r2), (unsigned int)LO32(r2)); } - READ_COP0(reg, COP0_CAUSE); - cvmx_safe_printf("%16s: 0x%016llx\n", "COP0_CAUSE", (ULL)reg); - READ_COP0(reg, COP0_STATUS); - cvmx_safe_printf("%16s: 0x%016llx\n", "COP0_STATUS", (ULL)reg); - READ_COP0(reg, COP0_BADVADDR); - cvmx_safe_printf("%16s: 0x%016llx\n", "COP0_BADVADDR", (ULL)reg); - READ_COP0(reg, COP0_EPC); - cvmx_safe_printf("%16s: 0x%016llx\n", "COP0_EPC", (ULL)reg); + CVMX_MF_COP0 (r1, COP0_CAUSE); + print_reg64 ("COP0_CAUSE", r1); + CVMX_MF_COP0 (r2, COP0_STATUS); + print_reg64 ("COP0_STATUS", r2); + CVMX_MF_COP0 (r1, COP0_BADVADDR); + print_reg64 ("COP0_BADVADDR", r1); + CVMX_MF_COP0 (r2, COP0_EPC); + print_reg64 ("COP0_EPC", r2); } - /** * @INTERNAL * Default exception handler. Prints out the exception @@ -126,87 +225,27 @@ static void __cvmx_interrupt_dump_registers(uint64_t registers[32]) * * @param registers Registers at time of the exception */ -static void __cvmx_interrupt_default_exception_handler(uint64_t registers[32]) +#ifndef __U_BOOT__ +static +#endif /* __U_BOOT__ */ +void __cvmx_interrupt_default_exception_handler(uint64_t registers[32]) { uint64_t trap_print_cause; + const char *str; +#ifndef __U_BOOT__ ebt3000_str_write("Trap"); cvmx_spinlock_lock(&cvmx_interrupt_default_lock); +#endif + CVMX_MF_COP0 (trap_print_cause, COP0_CAUSE); + str = cause_names [(trap_print_cause >> 2) & 0x1f]; + cvmx_safe_printf("Core %d: Unhandled Exception. Cause register decodes to:\n%s\n", (int)cvmx_get_core_num(), str && *str ? str : "Reserved exception cause"); cvmx_safe_printf("******************************************************************\n"); - cvmx_safe_printf("Core %d: Unhandled Exception. Cause register decodes to:\n", (int)cvmx_get_core_num()); - READ_COP0(trap_print_cause, COP0_CAUSE); - switch ((trap_print_cause >> 2) & 0x1f) - { - case 0x0: - cvmx_safe_printf("Interrupt\n"); - break; - case 0x1: - cvmx_safe_printf("TLB Mod\n"); - break; - case 0x2: - cvmx_safe_printf("tlb load/fetch\n"); - break; - case 0x3: - cvmx_safe_printf("tlb store\n"); - break; - case 0x4: - cvmx_safe_printf("address exc, load/fetch\n"); - break; - case 0x5: - cvmx_safe_printf("address exc, store\n"); - break; - case 0x6: - cvmx_safe_printf("bus error, inst. fetch\n"); - break; - case 0x7: - cvmx_safe_printf("bus error, load/store\n"); - break; - case 0x8: - cvmx_safe_printf("syscall\n"); - break; - case 0x9: - cvmx_safe_printf("breakpoint \n"); - break; - case 0xa: - cvmx_safe_printf("reserved instruction\n"); - break; - case 0xb: - cvmx_safe_printf("cop unusable\n"); - break; - case 0xc: - cvmx_safe_printf("arithmetic overflow\n"); - break; - case 0xd: - cvmx_safe_printf("trap\n"); - break; - case 0xf: - cvmx_safe_printf("floating point exc\n"); - break; - case 0x12: - cvmx_safe_printf("cop2 exception\n"); - break; - case 0x16: - cvmx_safe_printf("mdmx unusable\n"); - break; - case 0x17: - cvmx_safe_printf("watch\n"); - break; - case 0x18: - cvmx_safe_printf("machine check\n"); - break; - case 0x1e: - cvmx_safe_printf("cache error\n"); - break; - default: - cvmx_safe_printf("Reserved exception cause.\n"); - break; + __cvmx_interrupt_dump_registers(registers); - } +#ifndef __U_BOOT__ cvmx_safe_printf("******************************************************************\n"); - __cvmx_interrupt_dump_registers(registers); - cvmx_safe_printf("******************************************************************\n"); - #if __GNUC__ >= 4 && !defined(OCTEON_DISABLE_BACKTRACE) cvmx_safe_printf("Backtrace:\n\n"); __octeon_print_backtrace_func ((__octeon_backtrace_printf_t)cvmx_safe_printf); @@ -216,7 +255,7 @@ static void __cvmx_interrupt_default_exception_handler(uint64_t registers[32]) cvmx_spinlock_unlock(&cvmx_interrupt_default_lock); if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) - CVMX_BREAK; + CVMX_BREAK; while (1) { @@ -230,19 +269,20 @@ static void __cvmx_interrupt_default_exception_handler(uint64_t registers[32]) uint64_t tmp; /* Pulse the MCD0 signal. */ asm volatile ( - ".set push\n" - ".set noreorder\n" - ".set mips64\n" - "dmfc0 %0, $22\n" - "ori %0, %0, 0x10\n" - "dmtc0 %0, $22\n" - ".set pop\n" - : "=r" (tmp)); + ".set push\n" + ".set noreorder\n" + ".set mips64\n" + "dmfc0 %0, $22\n" + "ori %0, %0, 0x10\n" + "dmtc0 %0, $22\n" + ".set pop\n" + : "=r" (tmp)); } } +#endif /* __U_BOOT__ */ } - +#ifndef __U_BOOT__ /** * @INTERNAL * Default interrupt handler if the user doesn't register one. @@ -313,7 +353,7 @@ static void __cvmx_interrupt_ciu(int irq_number, uint64_t registers[32], void *u */ static void __cvmx_interrupt_ecc(int irq_number, uint64_t registers[32], void *user_arg) { - cvmx_interrupt_rsl_decode(); + cvmx_error_poll(); } @@ -333,11 +373,15 @@ void cvmx_interrupt_do_irq(uint64_t registers[35]) uint64_t cache_err; int i; uint32_t exc_vec; - /* Determine the cause of the interrupt */ asm volatile ("dmfc0 %0,$13,0" : "=r" (cause)); asm volatile ("dmfc0 %0,$12,0" : "=r" (status)); - + /* In case of exception, clear all interrupts to avoid recursive interrupts. + Also clear EXL bit to display the correct PC value. */ + if ((cause & 0x7c) == 0) + { + asm volatile ("dmtc0 %0, $12, 0" : : "r" (status & ~(0xff02))); + } /* The assembly stub at each exception vector saves its address in k1 when ** it calls the stage 2 handler. We use this to compute the exception vector ** that brought us here */ @@ -371,25 +415,31 @@ void cvmx_interrupt_do_irq(uint64_t registers[35]) if ((cause & 0x7c) != 0) { cvmx_interrupt_state.exception_handler(registers); - return; + goto return_from_interrupt; } /* Convert the cause into an active mask */ mask = ((cause & status) >> 8) & 0xff; if (mask == 0) - return; /* Spurious interrupt */ + { + goto return_from_interrupt; /* Spurious interrupt */ + } for (i=0; i<8; i++) { if (mask & (1<<i)) { cvmx_interrupt_state.handlers[i](i, registers, cvmx_interrupt_state.data[i]); - return; + goto return_from_interrupt; } } /* We should never get here */ __cvmx_interrupt_default_exception_handler(registers); + +return_from_interrupt: + /* Restore Status register before returning from exception. */ + asm volatile ("dmtc0 %0, $12, 0" : : "r" (status)); } @@ -425,6 +475,7 @@ void cvmx_interrupt_initialize(void) memcpy(low_level_loc + 0x100, (void*)cvmx_interrupt_cache_error, 0x80); memcpy(low_level_loc + 0x180, (void*)cvmx_interrupt_stage1, 0x80); memcpy(low_level_loc + 0x200, (void*)cvmx_interrupt_stage1, 0x80); + /* Make sure the locations used to count Icache and Dcache exceptions starts out as zero */ cvmx_write64_uint64(CVMX_ADD_SEG32(CVMX_MIPS32_SPACE_KSEG0, 8), 0); @@ -439,7 +490,8 @@ void cvmx_interrupt_initialize(void) /* Add an interrupt handler for ECC failures */ cvmx_interrupt_register(CVMX_IRQ_RML, __cvmx_interrupt_ecc, NULL); - cvmx_interrupt_rsl_enable(); + if (cvmx_error_initialize(0 /* || CVMX_ERROR_FLAGS_ECC_SINGLE_BIT */)) + cvmx_warn("cvmx_error_initialize() failed\n"); cvmx_interrupt_unmask_irq(CVMX_IRQ_RML); } @@ -486,43 +538,6 @@ cvmx_interrupt_exception_t cvmx_interrupt_set_exception(cvmx_interrupt_exception CVMX_SYNCWS; return result; } - - -/** - * version of printf that works better in exception context. - * - * @param format - */ -void cvmx_safe_printf(const char *format, ...) -{ - static char buffer[256]; - va_list args; - va_start(args, format); - int count = vsnprintf(buffer, sizeof(buffer), format, args); - va_end(args); - - char *ptr = buffer; - while (count-- > 0) - { - cvmx_uart_lsr_t lsrval; - - /* Spin until there is room */ - do - { - lsrval.u64 = cvmx_read_csr(CVMX_MIO_UARTX_LSR(0)); - if (lsrval.s.temt == 0) - cvmx_wait(10000); /* Just to reduce the load on the system */ - } - while (lsrval.s.temt == 0); - - if (*ptr == '\n') - cvmx_write_csr(CVMX_MIO_UARTX_THR(0), '\r'); - cvmx_write_csr(CVMX_MIO_UARTX_THR(0), *ptr++); - } -} - - - - +#endif /* !__U_BOOT__ */ |