linux/arch/blackfin/include/asm/entry.h
<<
>>
Prefs
   1/*
   2 * Copyright 2004-2009 Analog Devices Inc.
   3 *
   4 * Licensed under the GPL-2 or later.
   5 */
   6
   7#ifndef __BFIN_ENTRY_H
   8#define __BFIN_ENTRY_H
   9
  10#include <asm/setup.h>
  11#include <asm/page.h>
  12
  13#ifdef __ASSEMBLY__
  14
  15#define LFLUSH_I_AND_D  0x00000808
  16#define LSIGTRAP        5
  17
  18/*
  19 * NOTE!  The single-stepping code assumes that all interrupt handlers
  20 * start by saving SYSCFG on the stack with their first instruction.
  21 */
  22
  23/* This one is used for exceptions, emulation, and NMI.  It doesn't push
  24   RETI and doesn't do cli.  */
  25#define SAVE_ALL_SYS            save_context_no_interrupts
  26/* This is used for all normal interrupts.  It saves a minimum of registers
  27   to the stack, loads the IRQ number, and jumps to common code.  */
  28#ifdef CONFIG_IPIPE
  29# define LOAD_IPIPE_IPEND \
  30        P0.l = lo(IPEND); \
  31        P0.h = hi(IPEND); \
  32        R1 = [P0];
  33#else
  34# define LOAD_IPIPE_IPEND
  35#endif
  36
  37/*
  38 * Workaround for anomalies 05000283 and 05000315
  39 */
  40#if ANOMALY_05000283 || ANOMALY_05000315
  41# define ANOMALY_283_315_WORKAROUND(preg, dreg)         \
  42        cc = dreg == dreg;                              \
  43        preg.h = HI(CHIPID);                            \
  44        preg.l = LO(CHIPID);                            \
  45        if cc jump 1f;                                  \
  46        dreg.l = W[preg];                               \
  471:
  48#else
  49# define ANOMALY_283_315_WORKAROUND(preg, dreg)
  50#endif /* ANOMALY_05000283 || ANOMALY_05000315 */
  51
  52#ifndef CONFIG_EXACT_HWERR
  53/* As a debugging aid - we save IPEND when DEBUG_KERNEL is on,
  54 * otherwise it is a waste of cycles.
  55 */
  56# ifndef CONFIG_DEBUG_KERNEL
  57#define INTERRUPT_ENTRY(N)                                              \
  58    [--sp] = SYSCFG;                                                    \
  59    [--sp] = P0;        /*orig_p0*/                                     \
  60    [--sp] = R0;        /*orig_r0*/                                     \
  61    [--sp] = (R7:0,P5:0);                                               \
  62    R0 = (N);                                                           \
  63    LOAD_IPIPE_IPEND                                                    \
  64    jump __common_int_entry;
  65# else /* CONFIG_DEBUG_KERNEL */
  66#define INTERRUPT_ENTRY(N)                                              \
  67    [--sp] = SYSCFG;                                                    \
  68    [--sp] = P0;        /*orig_p0*/                                     \
  69    [--sp] = R0;        /*orig_r0*/                                     \
  70    [--sp] = (R7:0,P5:0);                                               \
  71    p0.l = lo(IPEND);                                                   \
  72    p0.h = hi(IPEND);                                                   \
  73    r1 = [p0];                                                          \
  74    R0 = (N);                                                           \
  75    LOAD_IPIPE_IPEND                                                    \
  76    jump __common_int_entry;
  77# endif /* CONFIG_DEBUG_KERNEL */
  78
  79/* For timer interrupts, we need to save IPEND, since the user_mode
  80 *macro accesses it to determine where to account time.
  81 */
  82#define TIMER_INTERRUPT_ENTRY(N)                                        \
  83    [--sp] = SYSCFG;                                                    \
  84    [--sp] = P0;        /*orig_p0*/                                     \
  85    [--sp] = R0;        /*orig_r0*/                                     \
  86    [--sp] = (R7:0,P5:0);                                               \
  87    p0.l = lo(IPEND);                                                   \
  88    p0.h = hi(IPEND);                                                   \
  89    r1 = [p0];                                                          \
  90    R0 = (N);                                                           \
  91    jump __common_int_entry;
  92#else /* CONFIG_EXACT_HWERR is defined */
  93
  94/* if we want hardware error to be exact, we need to do a SSYNC (which forces
  95 * read/writes to complete to the memory controllers), and check to see that
  96 * caused a pending HW error condition. If so, we assume it was caused by user
  97 * space, by setting the same interrupt that we are in (so it goes off again)
  98 * and context restore, and a RTI (without servicing anything). This should
  99 * cause the pending HWERR to fire, and when that is done, this interrupt will
 100 * be re-serviced properly.
 101 * As you can see by the code - we actually need to do two SSYNCS - one to
 102 * make sure the read/writes complete, and another to make sure the hardware
 103 * error is recognized by the core.
 104 *
 105 * The extra nop before the SSYNC is to make sure we work around 05000244,
 106 * since the 283/315 workaround includes a branch to the end
 107 */
 108#define INTERRUPT_ENTRY(N)                                              \
 109    [--sp] = SYSCFG;                                                    \
 110    [--sp] = P0;        /*orig_p0*/                                     \
 111    [--sp] = R0;        /*orig_r0*/                                     \
 112    [--sp] = (R7:0,P5:0);                                               \
 113    R1 = ASTAT;                                                         \
 114    ANOMALY_283_315_WORKAROUND(p0, r0)                                  \
 115    P0.L = LO(ILAT);                                                    \
 116    P0.H = HI(ILAT);                                                    \
 117    NOP;                                                                \
 118    SSYNC;                                                              \
 119    SSYNC;                                                              \
 120    R0 = [P0];                                                          \
 121    CC = BITTST(R0, EVT_IVHW_P);                                        \
 122    IF CC JUMP 1f;                                                      \
 123    ASTAT = R1;                                                         \
 124    p0.l = lo(IPEND);                                                   \
 125    p0.h = hi(IPEND);                                                   \
 126    r1 = [p0];                                                          \
 127    R0 = (N);                                                           \
 128    LOAD_IPIPE_IPEND                                                    \
 129    jump __common_int_entry;                                            \
 1301:  ASTAT = R1;                                                         \
 131    RAISE N;                                                            \
 132    (R7:0, P5:0) = [SP++];                                              \
 133    SP += 0x8;                                                          \
 134    SYSCFG = [SP++];                                                    \
 135    CSYNC;                                                              \
 136    RTI;
 137
 138#define TIMER_INTERRUPT_ENTRY(N)                                        \
 139    [--sp] = SYSCFG;                                                    \
 140    [--sp] = P0;        /*orig_p0*/                                     \
 141    [--sp] = R0;        /*orig_r0*/                                     \
 142    [--sp] = (R7:0,P5:0);                                               \
 143    R1 = ASTAT;                                                         \
 144    ANOMALY_283_315_WORKAROUND(p0, r0)                                  \
 145    P0.L = LO(ILAT);                                                    \
 146    P0.H = HI(ILAT);                                                    \
 147    NOP;                                                                \
 148    SSYNC;                                                              \
 149    SSYNC;                                                              \
 150    R0 = [P0];                                                          \
 151    CC = BITTST(R0, EVT_IVHW_P);                                        \
 152    IF CC JUMP 1f;                                                      \
 153    ASTAT = R1;                                                         \
 154    p0.l = lo(IPEND);                                                   \
 155    p0.h = hi(IPEND);                                                   \
 156    r1 = [p0];                                                          \
 157    R0 = (N);                                                           \
 158    jump __common_int_entry;                                            \
 1591:  ASTAT = R1;                                                         \
 160    RAISE N;                                                            \
 161    (R7:0, P5:0) = [SP++];                                              \
 162    SP += 0x8;                                                          \
 163    SYSCFG = [SP++];                                                    \
 164    CSYNC;                                                              \
 165    RTI;
 166#endif  /* CONFIG_EXACT_HWERR */
 167
 168/* This one pushes RETI without using CLI.  Interrupts are enabled.  */
 169#define SAVE_CONTEXT_SYSCALL    save_context_syscall
 170#define SAVE_CONTEXT            save_context_with_interrupts
 171#define SAVE_CONTEXT_CPLB       save_context_cplb
 172
 173#define RESTORE_ALL_SYS         restore_context_no_interrupts
 174#define RESTORE_CONTEXT         restore_context_with_interrupts
 175#define RESTORE_CONTEXT_CPLB    restore_context_cplb
 176
 177#endif                          /* __ASSEMBLY__ */
 178#endif                          /* __BFIN_ENTRY_H */
 179