Path: blob/master/arch/blackfin/include/asm/entry.h
15126 views
/*1* Copyright 2004-2009 Analog Devices Inc.2*3* Licensed under the GPL-2 or later.4*/56#ifndef __BFIN_ENTRY_H7#define __BFIN_ENTRY_H89#include <asm/setup.h>10#include <asm/page.h>1112#ifdef __ASSEMBLY__1314#define LFLUSH_I_AND_D 0x0000080815#define LSIGTRAP 51617/*18* NOTE! The single-stepping code assumes that all interrupt handlers19* start by saving SYSCFG on the stack with their first instruction.20*/2122/* This one is used for exceptions, emulation, and NMI. It doesn't push23RETI and doesn't do cli. */24#define SAVE_ALL_SYS save_context_no_interrupts25/* This is used for all normal interrupts. It saves a minimum of registers26to the stack, loads the IRQ number, and jumps to common code. */27#ifdef CONFIG_IPIPE28# define LOAD_IPIPE_IPEND \29P0.l = lo(IPEND); \30P0.h = hi(IPEND); \31R1 = [P0];32#else33# define LOAD_IPIPE_IPEND34#endif3536/*37* Workaround for anomalies 05000283 and 0500031538*/39#if ANOMALY_05000283 || ANOMALY_0500031540# define ANOMALY_283_315_WORKAROUND(preg, dreg) \41cc = dreg == dreg; \42preg.h = HI(CHIPID); \43preg.l = LO(CHIPID); \44if cc jump 1f; \45dreg.l = W[preg]; \461:47#else48# define ANOMALY_283_315_WORKAROUND(preg, dreg)49#endif /* ANOMALY_05000283 || ANOMALY_05000315 */5051#ifndef CONFIG_EXACT_HWERR52/* As a debugging aid - we save IPEND when DEBUG_KERNEL is on,53* otherwise it is a waste of cycles.54*/55# ifndef CONFIG_DEBUG_KERNEL56#define INTERRUPT_ENTRY(N) \57[--sp] = SYSCFG; \58[--sp] = P0; /*orig_p0*/ \59[--sp] = R0; /*orig_r0*/ \60[--sp] = (R7:0,P5:0); \61R0 = (N); \62LOAD_IPIPE_IPEND \63jump __common_int_entry;64# else /* CONFIG_DEBUG_KERNEL */65#define INTERRUPT_ENTRY(N) \66[--sp] = SYSCFG; \67[--sp] = P0; /*orig_p0*/ \68[--sp] = R0; /*orig_r0*/ \69[--sp] = (R7:0,P5:0); \70p0.l = lo(IPEND); \71p0.h = hi(IPEND); \72r1 = [p0]; \73R0 = (N); \74LOAD_IPIPE_IPEND \75jump __common_int_entry;76# endif /* CONFIG_DEBUG_KERNEL */7778/* For timer interrupts, we need to save IPEND, since the user_mode79*macro accesses it to determine where to account time.80*/81#define TIMER_INTERRUPT_ENTRY(N) \82[--sp] = SYSCFG; \83[--sp] = P0; /*orig_p0*/ \84[--sp] = R0; /*orig_r0*/ \85[--sp] = (R7:0,P5:0); \86p0.l = lo(IPEND); \87p0.h = hi(IPEND); \88r1 = [p0]; \89R0 = (N); \90jump __common_int_entry;91#else /* CONFIG_EXACT_HWERR is defined */9293/* if we want hardware error to be exact, we need to do a SSYNC (which forces94* read/writes to complete to the memory controllers), and check to see that95* caused a pending HW error condition. If so, we assume it was caused by user96* space, by setting the same interrupt that we are in (so it goes off again)97* and context restore, and a RTI (without servicing anything). This should98* cause the pending HWERR to fire, and when that is done, this interrupt will99* be re-serviced properly.100* As you can see by the code - we actually need to do two SSYNCS - one to101* make sure the read/writes complete, and another to make sure the hardware102* error is recognized by the core.103*104* The extra nop before the SSYNC is to make sure we work around 05000244,105* since the 283/315 workaround includes a branch to the end106*/107#define INTERRUPT_ENTRY(N) \108[--sp] = SYSCFG; \109[--sp] = P0; /*orig_p0*/ \110[--sp] = R0; /*orig_r0*/ \111[--sp] = (R7:0,P5:0); \112R1 = ASTAT; \113ANOMALY_283_315_WORKAROUND(p0, r0) \114P0.L = LO(ILAT); \115P0.H = HI(ILAT); \116NOP; \117SSYNC; \118SSYNC; \119R0 = [P0]; \120CC = BITTST(R0, EVT_IVHW_P); \121IF CC JUMP 1f; \122ASTAT = R1; \123p0.l = lo(IPEND); \124p0.h = hi(IPEND); \125r1 = [p0]; \126R0 = (N); \127LOAD_IPIPE_IPEND \128jump __common_int_entry; \1291: ASTAT = R1; \130RAISE N; \131(R7:0, P5:0) = [SP++]; \132SP += 0x8; \133SYSCFG = [SP++]; \134CSYNC; \135RTI;136137#define TIMER_INTERRUPT_ENTRY(N) \138[--sp] = SYSCFG; \139[--sp] = P0; /*orig_p0*/ \140[--sp] = R0; /*orig_r0*/ \141[--sp] = (R7:0,P5:0); \142R1 = ASTAT; \143ANOMALY_283_315_WORKAROUND(p0, r0) \144P0.L = LO(ILAT); \145P0.H = HI(ILAT); \146NOP; \147SSYNC; \148SSYNC; \149R0 = [P0]; \150CC = BITTST(R0, EVT_IVHW_P); \151IF CC JUMP 1f; \152ASTAT = R1; \153p0.l = lo(IPEND); \154p0.h = hi(IPEND); \155r1 = [p0]; \156R0 = (N); \157jump __common_int_entry; \1581: ASTAT = R1; \159RAISE N; \160(R7:0, P5:0) = [SP++]; \161SP += 0x8; \162SYSCFG = [SP++]; \163CSYNC; \164RTI;165#endif /* CONFIG_EXACT_HWERR */166167/* This one pushes RETI without using CLI. Interrupts are enabled. */168#define SAVE_CONTEXT_SYSCALL save_context_syscall169#define SAVE_CONTEXT save_context_with_interrupts170#define SAVE_CONTEXT_CPLB save_context_cplb171172#define RESTORE_ALL_SYS restore_context_no_interrupts173#define RESTORE_CONTEXT restore_context_with_interrupts174#define RESTORE_CONTEXT_CPLB restore_context_cplb175176#endif /* __ASSEMBLY__ */177#endif /* __BFIN_ENTRY_H */178179180