summaryrefslogtreecommitdiff
path: root/arch/blackfin/include/asm/entry.h
diff options
context:
space:
mode:
Diffstat (limited to 'arch/blackfin/include/asm/entry.h')
-rw-r--r--arch/blackfin/include/asm/entry.h178
1 files changed, 178 insertions, 0 deletions
diff --git a/arch/blackfin/include/asm/entry.h b/arch/blackfin/include/asm/entry.h
new file mode 100644
index 00000000..4104d578
--- /dev/null
+++ b/arch/blackfin/include/asm/entry.h
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2004-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __BFIN_ENTRY_H
+#define __BFIN_ENTRY_H
+
+#include <asm/setup.h>
+#include <asm/page.h>
+
+#ifdef __ASSEMBLY__
+
+#define LFLUSH_I_AND_D 0x00000808
+#define LSIGTRAP 5
+
+/*
+ * NOTE! The single-stepping code assumes that all interrupt handlers
+ * start by saving SYSCFG on the stack with their first instruction.
+ */
+
+/* This one is used for exceptions, emulation, and NMI. It doesn't push
+ RETI and doesn't do cli. */
+#define SAVE_ALL_SYS save_context_no_interrupts
+/* This is used for all normal interrupts. It saves a minimum of registers
+ to the stack, loads the IRQ number, and jumps to common code. */
+#ifdef CONFIG_IPIPE
+# define LOAD_IPIPE_IPEND \
+ P0.l = lo(IPEND); \
+ P0.h = hi(IPEND); \
+ R1 = [P0];
+#else
+# define LOAD_IPIPE_IPEND
+#endif
+
+/*
+ * Workaround for anomalies 05000283 and 05000315
+ */
+#if ANOMALY_05000283 || ANOMALY_05000315
+# define ANOMALY_283_315_WORKAROUND(preg, dreg) \
+ cc = dreg == dreg; \
+ preg.h = HI(CHIPID); \
+ preg.l = LO(CHIPID); \
+ if cc jump 1f; \
+ dreg.l = W[preg]; \
+1:
+#else
+# define ANOMALY_283_315_WORKAROUND(preg, dreg)
+#endif /* ANOMALY_05000283 || ANOMALY_05000315 */
+
+#ifndef CONFIG_EXACT_HWERR
+/* As a debugging aid - we save IPEND when DEBUG_KERNEL is on,
+ * otherwise it is a waste of cycles.
+ */
+# ifndef CONFIG_DEBUG_KERNEL
+#define INTERRUPT_ENTRY(N) \
+ [--sp] = SYSCFG; \
+ [--sp] = P0; /*orig_p0*/ \
+ [--sp] = R0; /*orig_r0*/ \
+ [--sp] = (R7:0,P5:0); \
+ R0 = (N); \
+ LOAD_IPIPE_IPEND \
+ jump __common_int_entry;
+# else /* CONFIG_DEBUG_KERNEL */
+#define INTERRUPT_ENTRY(N) \
+ [--sp] = SYSCFG; \
+ [--sp] = P0; /*orig_p0*/ \
+ [--sp] = R0; /*orig_r0*/ \
+ [--sp] = (R7:0,P5:0); \
+ p0.l = lo(IPEND); \
+ p0.h = hi(IPEND); \
+ r1 = [p0]; \
+ R0 = (N); \
+ LOAD_IPIPE_IPEND \
+ jump __common_int_entry;
+# endif /* CONFIG_DEBUG_KERNEL */
+
+/* For timer interrupts, we need to save IPEND, since the user_mode
+ *macro accesses it to determine where to account time.
+ */
+#define TIMER_INTERRUPT_ENTRY(N) \
+ [--sp] = SYSCFG; \
+ [--sp] = P0; /*orig_p0*/ \
+ [--sp] = R0; /*orig_r0*/ \
+ [--sp] = (R7:0,P5:0); \
+ p0.l = lo(IPEND); \
+ p0.h = hi(IPEND); \
+ r1 = [p0]; \
+ R0 = (N); \
+ jump __common_int_entry;
+#else /* CONFIG_EXACT_HWERR is defined */
+
+/* if we want hardware error to be exact, we need to do a SSYNC (which forces
+ * read/writes to complete to the memory controllers), and check to see that
+ * caused a pending HW error condition. If so, we assume it was caused by user
+ * space, by setting the same interrupt that we are in (so it goes off again)
+ * and context restore, and a RTI (without servicing anything). This should
+ * cause the pending HWERR to fire, and when that is done, this interrupt will
+ * be re-serviced properly.
+ * As you can see by the code - we actually need to do two SSYNCS - one to
+ * make sure the read/writes complete, and another to make sure the hardware
+ * error is recognized by the core.
+ *
+ * The extra nop before the SSYNC is to make sure we work around 05000244,
+ * since the 283/315 workaround includes a branch to the end
+ */
+#define INTERRUPT_ENTRY(N) \
+ [--sp] = SYSCFG; \
+ [--sp] = P0; /*orig_p0*/ \
+ [--sp] = R0; /*orig_r0*/ \
+ [--sp] = (R7:0,P5:0); \
+ R1 = ASTAT; \
+ ANOMALY_283_315_WORKAROUND(p0, r0) \
+ P0.L = LO(ILAT); \
+ P0.H = HI(ILAT); \
+ NOP; \
+ SSYNC; \
+ SSYNC; \
+ R0 = [P0]; \
+ CC = BITTST(R0, EVT_IVHW_P); \
+ IF CC JUMP 1f; \
+ ASTAT = R1; \
+ p0.l = lo(IPEND); \
+ p0.h = hi(IPEND); \
+ r1 = [p0]; \
+ R0 = (N); \
+ LOAD_IPIPE_IPEND \
+ jump __common_int_entry; \
+1: ASTAT = R1; \
+ RAISE N; \
+ (R7:0, P5:0) = [SP++]; \
+ SP += 0x8; \
+ SYSCFG = [SP++]; \
+ CSYNC; \
+ RTI;
+
+#define TIMER_INTERRUPT_ENTRY(N) \
+ [--sp] = SYSCFG; \
+ [--sp] = P0; /*orig_p0*/ \
+ [--sp] = R0; /*orig_r0*/ \
+ [--sp] = (R7:0,P5:0); \
+ R1 = ASTAT; \
+ ANOMALY_283_315_WORKAROUND(p0, r0) \
+ P0.L = LO(ILAT); \
+ P0.H = HI(ILAT); \
+ NOP; \
+ SSYNC; \
+ SSYNC; \
+ R0 = [P0]; \
+ CC = BITTST(R0, EVT_IVHW_P); \
+ IF CC JUMP 1f; \
+ ASTAT = R1; \
+ p0.l = lo(IPEND); \
+ p0.h = hi(IPEND); \
+ r1 = [p0]; \
+ R0 = (N); \
+ jump __common_int_entry; \
+1: ASTAT = R1; \
+ RAISE N; \
+ (R7:0, P5:0) = [SP++]; \
+ SP += 0x8; \
+ SYSCFG = [SP++]; \
+ CSYNC; \
+ RTI;
+#endif /* CONFIG_EXACT_HWERR */
+
+/* This one pushes RETI without using CLI. Interrupts are enabled. */
+#define SAVE_CONTEXT_SYSCALL save_context_syscall
+#define SAVE_CONTEXT save_context_with_interrupts
+#define SAVE_CONTEXT_CPLB save_context_cplb
+
+#define RESTORE_ALL_SYS restore_context_no_interrupts
+#define RESTORE_CONTEXT restore_context_with_interrupts
+#define RESTORE_CONTEXT_CPLB restore_context_cplb
+
+#endif /* __ASSEMBLY__ */
+#endif /* __BFIN_ENTRY_H */