summaryrefslogtreecommitdiff
path: root/cvmx-interrupt.c
diff options
context:
space:
mode:
Diffstat (limited to 'cvmx-interrupt.c')
-rw-r--r--cvmx-interrupt.c373
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__ */