aboutsummaryrefslogtreecommitdiffstats
path: root/arch/blackfin/kernel
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--arch/blackfin/kernel/bfin_dma_5xx.c6
-rw-r--r--arch/blackfin/kernel/early_printk.c74
-rw-r--r--arch/blackfin/kernel/setup.c3
-rw-r--r--arch/blackfin/kernel/shadow_console.c51
4 files changed, 122 insertions, 12 deletions
diff --git a/arch/blackfin/kernel/bfin_dma_5xx.c b/arch/blackfin/kernel/bfin_dma_5xx.c
index 9f9b82816652..14dea1a87b7c 100644
--- a/arch/blackfin/kernel/bfin_dma_5xx.c
+++ b/arch/blackfin/kernel/bfin_dma_5xx.c
@@ -19,6 +19,7 @@
#include <asm/cacheflush.h>
#include <asm/dma.h>
#include <asm/uaccess.h>
+#include <asm/early_printk.h>
/*
* To make sure we work around 05000119 - we always check DMA_DONE bit,
@@ -236,6 +237,7 @@ void blackfin_dma_resume(void)
*/
void __init blackfin_dma_early_init(void)
{
+ early_shadow_stamp();
bfin_write_MDMA_S0_CONFIG(0);
bfin_write_MDMA_S1_CONFIG(0);
}
@@ -246,6 +248,8 @@ void __init early_dma_memcpy(void *pdst, const void *psrc, size_t size)
unsigned long src = (unsigned long)psrc;
struct dma_register *dst_ch, *src_ch;
+ early_shadow_stamp();
+
/* We assume that everything is 4 byte aligned, so include
* a basic sanity check
*/
@@ -300,6 +304,8 @@ void __init early_dma_memcpy(void *pdst, const void *psrc, size_t size)
void __init early_dma_memcpy_done(void)
{
+ early_shadow_stamp();
+
while ((bfin_read_MDMA_S0_CONFIG() && !(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE)) ||
(bfin_read_MDMA_S1_CONFIG() && !(bfin_read_MDMA_D1_IRQ_STATUS() & DMA_DONE)))
continue;
diff --git a/arch/blackfin/kernel/early_printk.c b/arch/blackfin/kernel/early_printk.c
index 2ab56811841c..931c78b5ea1f 100644
--- a/arch/blackfin/kernel/early_printk.c
+++ b/arch/blackfin/kernel/early_printk.c
@@ -27,6 +27,7 @@
#include <linux/serial_core.h>
#include <linux/console.h>
#include <linux/string.h>
+#include <linux/reboot.h>
#include <asm/blackfin.h>
#include <asm/irq_handler.h>
#include <asm/early_printk.h>
@@ -181,6 +182,22 @@ asmlinkage void __init init_early_exception_vectors(void)
u32 evt;
SSYNC();
+ /*
+ * This starts up the shadow buffer, incase anything crashes before
+ * setup arch
+ */
+ mark_shadow_error();
+ early_shadow_puts(linux_banner);
+ early_shadow_stamp();
+
+ if (CPUID != bfin_cpuid()) {
+ early_shadow_puts("Running on wrong machine type, expected");
+ early_shadow_reg(CPUID, 16);
+ early_shadow_puts(", but running on");
+ early_shadow_reg(bfin_cpuid(), 16);
+ early_shadow_puts("\n");
+ }
+
/* cannot program in software:
* evt0 - emulation (jtag)
* evt1 - reset
@@ -199,6 +216,7 @@ asmlinkage void __init init_early_exception_vectors(void)
}
+__attribute__((__noreturn__))
asmlinkage void __init early_trap_c(struct pt_regs *fp, void *retaddr)
{
/* This can happen before the uart is initialized, so initialize
@@ -210,10 +228,58 @@ asmlinkage void __init early_trap_c(struct pt_regs *fp, void *retaddr)
if (likely(early_console == NULL) && CPUID == bfin_cpuid())
setup_early_printk(DEFAULT_EARLY_PORT);
- printk(KERN_EMERG "Early panic\n");
- dump_bfin_mem(fp);
- show_regs(fp);
- dump_bfin_trace_buffer();
+ if (!shadow_console_enabled()) {
+ /* crap - we crashed before setup_arch() */
+ early_shadow_puts("panic before setup_arch\n");
+ early_shadow_puts("IPEND:");
+ early_shadow_reg(fp->ipend, 16);
+ if (fp->seqstat & SEQSTAT_EXCAUSE) {
+ early_shadow_puts("\nEXCAUSE:");
+ early_shadow_reg(fp->seqstat & SEQSTAT_EXCAUSE, 8);
+ }
+ if (fp->seqstat & SEQSTAT_HWERRCAUSE) {
+ early_shadow_puts("\nHWERRCAUSE:");
+ early_shadow_reg(
+ (fp->seqstat & SEQSTAT_HWERRCAUSE) >> 14, 8);
+ }
+ early_shadow_puts("\nErr @");
+ if (fp->ipend & EVT_EVX)
+ early_shadow_reg(fp->retx, 32);
+ else
+ early_shadow_reg(fp->pc, 32);
+#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
+ early_shadow_puts("\nTrace:");
+ if (likely(bfin_read_TBUFSTAT() & TBUFCNT)) {
+ while (bfin_read_TBUFSTAT() & TBUFCNT) {
+ early_shadow_puts("\nT :");
+ early_shadow_reg(bfin_read_TBUF(), 32);
+ early_shadow_puts("\n S :");
+ early_shadow_reg(bfin_read_TBUF(), 32);
+ }
+ }
+#endif
+ early_shadow_puts("\nUse bfin-elf-addr2line to determine "
+ "function names\n");
+ /*
+ * We should panic(), but we can't - since panic calls printk,
+ * and printk uses memcpy.
+ * we want to reboot, but if the machine type is different,
+ * can't due to machine specific reboot sequences
+ */
+ if (CPUID == bfin_cpuid()) {
+ early_shadow_puts("Trying to restart\n");
+ machine_restart("");
+ }
+
+ early_shadow_puts("Halting, since it is not safe to restart\n");
+ while (1)
+ asm volatile ("EMUEXCPT; IDLE;\n");
+
+ } else {
+ printk(KERN_EMERG "Early panic\n");
+ show_regs(fp);
+ dump_bfin_trace_buffer();
+ }
panic("Died early");
}
diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c
index 3974764acd2c..f92fffc31689 100644
--- a/arch/blackfin/kernel/setup.c
+++ b/arch/blackfin/kernel/setup.c
@@ -187,6 +187,8 @@ void __init bfin_relocate_l1_mem(void)
unsigned long l1_data_b_length;
unsigned long l2_length;
+ early_shadow_stamp();
+
/*
* due to the ALIGN(4) in the arch/blackfin/kernel/vmlinux.lds.S
* we know that everything about l1 text/data is nice and aligned,
@@ -1352,6 +1354,7 @@ const struct seq_operations cpuinfo_op = {
void __init cmdline_init(const char *r0)
{
+ early_shadow_stamp();
if (r0)
strncpy(command_line, r0, COMMAND_LINE_SIZE);
}
diff --git a/arch/blackfin/kernel/shadow_console.c b/arch/blackfin/kernel/shadow_console.c
index 15819ff10573..8b8c7107a162 100644
--- a/arch/blackfin/kernel/shadow_console.c
+++ b/arch/blackfin/kernel/shadow_console.c
@@ -24,15 +24,18 @@
static __initdata char *shadow_console_buffer = (char *)SHADOW_CONSOLE_START;
-static __init void early_shadow_write(struct console *con, const char *s,
+__init void early_shadow_write(struct console *con, const char *s,
unsigned int n)
{
+ unsigned int i;
/*
* save 2 bytes for the double null at the end
* once we fail on a long line, make sure we don't write a short line afterwards
*/
if ((shadow_console_buffer + n) <= (char *)(SHADOW_CONSOLE_END - 2)) {
- memcpy(shadow_console_buffer, s, n);
+ /* can't use memcpy - it may not be relocated yet */
+ for (i = 0; i <= n; i++)
+ shadow_console_buffer[i] = s[i];
shadow_console_buffer += n;
shadow_console_buffer[0] = 0;
shadow_console_buffer[1] = 0;
@@ -48,16 +51,24 @@ static __initdata struct console early_shadow_console = {
.device = 0,
};
-__init void enable_shadow_console(void)
+__init int shadow_console_enabled(void)
+{
+ return early_shadow_console.flags & CON_ENABLED;
+}
+
+__init void mark_shadow_error(void)
{
int *loc = (int *)SHADOW_CONSOLE_MAGIC_LOC;
+ loc[0] = SHADOW_CONSOLE_MAGIC;
+ loc[1] = SHADOW_CONSOLE_START;
+}
- if (!(early_shadow_console.flags & CON_ENABLED)) {
+__init void enable_shadow_console(void)
+{
+ if (!shadow_console_enabled()) {
register_console(&early_shadow_console);
/* for now, assume things are going to fail */
- *loc = SHADOW_CONSOLE_MAGIC;
- loc++;
- *loc = SHADOW_CONSOLE_START;
+ mark_shadow_error();
}
}
@@ -71,8 +82,32 @@ static __init int disable_shadow_console(void)
*/
int *loc = (int *)SHADOW_CONSOLE_MAGIC_LOC;
- *loc = 0;
+ loc[0] = 0;
return 0;
}
pure_initcall(disable_shadow_console);
+
+/*
+ * since we can't use printk, dump numbers (as hex), n = # bits
+ */
+__init void early_shadow_reg(unsigned long reg, unsigned int n)
+{
+ /*
+ * can't use any "normal" kernel features, since thay
+ * may not be relocated to their execute address yet
+ */
+ int i;
+ char ascii[11] = " 0x";
+
+ n = n / 4;
+ reg = reg << ((8 - n) * 4);
+ n += 3;
+
+ for (i = 3; i <= n ; i++) {
+ ascii[i] = hex_asc_lo(reg >> 28);
+ reg <<= 4;
+ }
+ early_shadow_write(NULL, ascii, n);
+
+}