ambaIntrCtl.c
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:19k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* ambaIntrCtl.c - AMBA interrupt controller driver */
  2. /* Copyright 1984-1998, Wind River Systems, Inc. */
  3. /*
  4. modification history
  5. --------------------
  6. 01i,03dec01,rec  fix compiler warnings
  7. 01h,21sep98,cdp  fixed intEnable/Disable(0) (TSR#115062);
  8.  corrected range check in ambaIntLvlEnable/Disable;
  9.  made AMBA_INT_CSR_MASK optional;
  10.  added configurable interrupt priorities.
  11. 01f,10mar98,jpd  layout tidying.
  12. 01e,13nov97,cdp  include intLib.h and remove things pulled in from it;
  13.  make default I/O access 32 (not 16) bits wide; documentation.
  14. 01d,15aug97,cdp  rewritten for new interrupt structure (template 01d).
  15. 01c,14may97,jpd  added conditional use of valid interrupts mask.
  16. 01b,18feb97,cdp  renamed sysIntEnable/Disable and made global with result.
  17.  Tidyup for mangen. intEnable/Disable now return int.
  18. 01a,13dec96,cdp  created from target/config/pid7t/intPid.c.
  19. */
  20. /*
  21. This module implements the AMBA interrupt controller driver.
  22. The AMBA interrupt controller is a simple, generic interrupt controller
  23. described in full in the ARM Reference Peripherals Specification.  The
  24. interrupt controller has status and request registers, separate enable
  25. and disable registers and supports level-sensitive interrupts.  This
  26. library provides the routines to manage interrupts multiplexed by the
  27. AMBA interrupt controller.
  28. The AMBA interrupt controller has a number of registers.  Those used by
  29. this driver are described below under the symbolic names used herein.
  30. AMBA_INT_CSR_ENB (write): this is the "Enable Set" register described
  31. in the ARM Reference Peripherals Specification.  When this register is
  32. written, each data bit that is set (1) causes the corresponding
  33. interrupt to be enabled.  Bits that are clear (0) have no effect.
  34. AMBA_INT_CSR_DIS (write): this is the "Enable Clear" register which has
  35. the opposite effect.  When this register is written, each data bit that
  36. is set (1) causes the corresponding interrupt to be disabled.  Bits
  37. that are clear (0) have no effect.
  38. AMBA_INT_CSR_PEND (read): this is the "Interrupt Request" register.
  39. When this register is read, each data bit that is set (1) indicates an
  40. interrupt source that is both active and enabled i.e. can interrupt the
  41. processor.  This driver provides a means by which bits in this register
  42. can be masked if the particular implementation of AMBA returns bits in
  43. an undefined state.  Setting AMBA_INT_CSR_MASK to be a bitwise OR of
  44. all the valid bits achieves the required effect.  If
  45. AMBA_INT_PRIORITY_MAP is not #defined (see below), the driver also uses
  46. an external array ambaIntLvlMask[] to determine what should be written
  47. to AMBA_INT_CSR_ENB to change interrupt levels.  This should be defined
  48. by the BSP such that ambaIntLvlMask[n] has a bit set (1) for each
  49. interrupt source that should be enabled for interrupt level <n>. For
  50. example, ambaIntLvlMask[0] should be 0 so that all interrupts are
  51. disabled when interrupt level 0 is selected.
  52. The number of interrupts supported by the device i.e. the number of
  53. bits in the AMBA_INT_CSR_PEND register, is specified by
  54. AMBA_INT_NUM_LEVELS.
  55. We assume that config.h or <bsp>.h has defined the addresses of the
  56. controller chips registers: AMBA_INT_CSR_ENB, AMBA_INT_CSR_DIS and
  57. AMBA_INT_CSR_PEND and also the driver constants AMBA_INT_CSR_MASK (if
  58. required) and AMBA_INT_NUM_LEVELS.
  59. This driver assumes that the chip is memory-mapped and does direct
  60. memory accesses to the registers which are assumed to be 32 bits wide.
  61. If a different access method is needed, the BSP can redefine the macros
  62. AMBA_INT_REG_READ(addr,result) and AMBA_INT_REG_WRITE(addr,data).
  63. This driver assumes that interrupt vector numbers are calculated and
  64. not the result of a special cycle on the bus.  Vector numbers are
  65. generated by adding the current interrupt level number to
  66. AMBA_INT_VEC_BASE to generate a vector number which the architecture
  67. level will use to invoke the proper handling routine.  If a different
  68. mapping scheme, or a special hardware routine is needed, then the BSP
  69. should redefine the macro AMBA_INT_LVL_VEC_MAP(level,vector) to
  70. override the version defined in this file.
  71. This driver was designed to support a single instance of a real
  72. device.  At some point it should be upgraded to operate on an object
  73. model and to support any number of real devices.
  74. Priorities
  75. ==========
  76. The order of interrupt level priority is undefined at the architecture
  77. level.  In this driver, level 0 is highest and and indicates that all
  78. levels are disabled; level <AMBA_INT_NUM_LEVELS> is the lowest and
  79. indicates that all levels are enabled.
  80. By default, this driver implements a least-significant bit first
  81. interrupt priority scheme (this is compatible with earlier versions of
  82. this driver) which requires a definition of ambaIntLvlMask (see above).
  83. If required, the driver can be compiled to implement a BSP-configurable
  84. interrupt priority scheme by #defining AMBA_INT_PRIORITY_MAP.  For this
  85. model, the BSP should define an array of int called ambaIntLvlPriMap,
  86. each element of which is a bit number to be polled.  The list should be
  87. terminated with an entry containing -1.  This list is used in the
  88. interrupt handler to check bits in the requested order and is also used
  89. to generate a map of interrupt source to new interrupt level such that
  90. whilst servicing an interrupt, all interrupts defined by the BSP to be
  91. of lower priority than that interrupt are disabled.  Interrupt sources
  92. not in the list are serviced after all others in least-significant bit
  93. first priority.  (Note that the list is a list of ints rather than
  94. bytes because it causes the current compiler to generate faster code.)
  95. Note that in this priority system, intLevelSet(n) does not necessarily
  96. disable interrupt bit n and all lower-priority ones but uses
  97. ambaIntLvlPriMap to determine which interrupts should be masked e.g.
  98. if ambaIntLvlPriMap[] contains { 9, 4, 8, 5, -1 }, intLevelSet(0)
  99. disables all interrupt bits; intLevelSet(1) enables interrupt bit 9 but
  100. disables interrupts 4, 8, 5 and all others not listed; intLevelSet(3)
  101. enables interrupt bits 9, 4 and 8 but disables all others.  This
  102. enabling of interrupts only occurs if the interrupt has been explicitly
  103. enabled via a call to ambaIntLvlEnable().
  104. If the list is empty (contains just a terminator) or ambaIntLvlPriMap
  105. is declared as an int pointer of value 0 (this is more efficient),
  106. interrupts are handled as least-significant bit is highest priority.
  107. The BSP will initialize this driver in sysHwInit2(), after initializing
  108. the main interrupt library, usually intLibInit().  The initialization
  109. routine, ambaIntDevInit() will setup the interrupt controller device,
  110. it will mask off all individual interrupt sources and then set the
  111. interrupt level to enable all interrupts.  See ambaIntDevInit for more
  112. information.
  113. All of the functions in this library are global.  This allows them to
  114. be used by the BSP if it is necessary to create wrapper routines or to
  115. incorporate several drivers together as one.
  116. */
  117. #include "vxWorks.h"
  118. #include "config.h"
  119. #include "intLib.h"
  120. IMPORT int ffsLsb (UINT32);
  121. /* Defines from config.h, or <bsp>.h */
  122. #if !defined (AMBA_INT_CSR_PEND) || !defined (AMBA_INT_CSR_ENB) || 
  123.     !defined (AMBA_INT_NUM_LEVELS) || !defined (AMBA_INT_CSR_DIS)
  124. #   error missing AMBA interrupt definitions
  125. #endif
  126. #define AMBA_INT_VEC_BASE (0x0)
  127. /* hardware access methods */
  128. #ifndef AMBA_INT_REG_READ
  129. #define AMBA_INT_REG_READ(reg,result) 
  130. ((result) = *(volatile UINT32 *)(reg))
  131. #endif /*AMBA_INT_REG_READ*/
  132. #ifndef AMBA_INT_REG_WRITE
  133. #define AMBA_INT_REG_WRITE(reg,data) 
  134. (*((volatile UINT32 *)(reg)) = (data))
  135. #endif /*AMBA_INT_REG_WRITE*/
  136. /* Convert level number to vector number */
  137. #ifndef AMBA_INT_LVL_VEC_MAP
  138. #define AMBA_INT_LVL_VEC_MAP(level, vector) 
  139. ((vector) = ((level) + AMBA_INT_VEC_BASE))
  140. #endif /* AMBA_INT_LVL_VEC_MAP */
  141. #ifndef AMBA_INT_PRIORITY_MAP
  142. /* Convert pending register value, to a level number */
  143. #ifndef AMBA_INT_PEND_LVL_MAP
  144. #define AMBA_INT_PEND_LVL_MAP(pendReg, level) 
  145. ((level) = (pendReg))
  146. #endif /* AMBA_INT_PEND_LVL_MAP */
  147. #endif /* AMBA_INT_PRIORITY_MAP */
  148. /* driver constants */
  149. #define AMBA_INT_ALL_ENABLED (AMBA_INT_NUM_LEVELS)
  150. #define AMBA_INT_ALL_DISABLED 0
  151. /* Local data */
  152. /* Current interrupt level setting (ambaIntLvlChg). */
  153. LOCAL UINT32 ambaIntLvlCurrent = AMBA_INT_ALL_DISABLED; /* all levels disabled*/
  154. /*
  155.  * A mask word.  Bits are set in this word when a specific level
  156.  * is enabled. It is used to mask off individual levels that have
  157.  * not been explicitly enabled.
  158.  */
  159. LOCAL UINT32 ambaIntLvlEnabled;
  160. #ifdef AMBA_INT_PRIORITY_MAP
  161. /*
  162.  * Controller masks: for each interrupt level, this provides a mask for
  163.  * the controller (see IntLvlChg).
  164.  * Mask is 32 bits * (levels + 1)
  165.  */
  166.     
  167. LOCAL UINT32 ambaIntLvlMask[(1 + AMBA_INT_NUM_LEVELS) * sizeof(UINT32)];
  168. /*
  169.  * Map of interrupt bit number to level: if bit n is set, ambaIntLvlMap[n]
  170.  * is the interrupt level to change to such that interrupt n and all lower
  171.  * priority ones are disabled.
  172.  */
  173. LOCAL int ambaIntLvlMap[AMBA_INT_NUM_LEVELS * sizeof(int)];
  174. #endif /* AMBA_INT_PRIORITY_MAP */
  175. /* forward declarations */
  176. STATUS ambaIntLvlVecChk (int*, int*);
  177. STATUS  ambaIntLvlVecAck (int, int);
  178. int ambaIntLvlChg (int);
  179. STATUS ambaIntLvlEnable (int);
  180. STATUS ambaIntLvlDisable (int);
  181. /*******************************************************************************
  182. *
  183. * ambaIntDevInit - initialize the interrupt controller
  184. *
  185. * This routine will initialize the interrupt controller device, disabling all
  186. * interrupt sources.  It will also connect the device driver specific routines
  187. * into the architecture level hooks.  If the BSP needs to create a wrapper
  188. * routine around any of the arhitecture level routines, it should install the
  189. * pointer to the wrapper routine after calling this routine.
  190. *
  191. * If used with configurable priorities (#define AMBA_INT_PRIORITY_MAP),
  192. * before this routine is called, ambaIntLvlPriMap should be initialised
  193. * as a list of interrupt bits to poll in order of decreasing priority and
  194. * terminated by an entry containing -1.  If ambaIntLvlPriMap is a null
  195. * pointer (or an empty list), the priority scheme used will be
  196. * least-significant bit first.  This is equivalent to the scheme used if
  197. * AMBA_INT_PRIORITY_MAP is not defined but slightly less efficient.
  198. *
  199. * The return value ERROR indicates that the contents of
  200. * ambaIntLvlPriMap (if used) were invalid.
  201. *
  202. * RETURNS: OK or ERROR if ambaIntLvlPriMap invalid.
  203. */
  204. int ambaIntDevInit (void)
  205.     {
  206. #ifdef AMBA_INT_PRIORITY_MAP
  207.     int i, j;
  208.     int level;
  209.     UINT32 bit;
  210.     /* if priorities are supplied, validate the supplied list */
  211.     if (ambaIntLvlPriMap != 0)
  212. {
  213. /* first check the list is terminated (VecChk requires this) */
  214. for (i = 0; i < AMBA_INT_NUM_LEVELS; ++i)
  215.     if (ambaIntLvlPriMap[i] == -1)
  216. break;
  217. if (!(i < AMBA_INT_NUM_LEVELS))
  218.     return ERROR; /* no terminator */
  219. /* now check that all are in range and that there are no duplicates */
  220. for (i = 0; ambaIntLvlPriMap[i] != -1; ++i)
  221.     if (ambaIntLvlPriMap[i] < 0 ||
  222. ambaIntLvlPriMap[i] >= AMBA_INT_NUM_LEVELS)
  223. {
  224. return ERROR; /* out of range */
  225. }
  226.     else
  227. for (j = i + 1; ambaIntLvlPriMap[j] != -1; ++j)
  228.     if (ambaIntLvlPriMap[j] == ambaIntLvlPriMap[i])
  229. {
  230. return ERROR; /* duplicate */
  231. }
  232. }
  233.     /*
  234.      * Now initialise the mask array.
  235.      * For each level (in ascending order), the mask is the mask of the
  236.      * previous level with the bit for the current level set to enable it.
  237.      */
  238.     ambaIntLvlMask[0] = 0; /* mask for level 0 = all disabled */
  239.     /* do the levels for which priority has been specified */
  240.     level = 1;
  241.     if (ambaIntLvlPriMap != 0)
  242. {
  243. for ( ; level <= AMBA_INT_NUM_LEVELS &&
  244. (i = ambaIntLvlPriMap[level - 1], i >= 0); ++level)
  245.     {
  246.     /* copy previous level's mask to this one's */
  247.     ambaIntLvlMask[level] = ambaIntLvlMask[level - 1];
  248.     /* OR in the bit indicated by the next entry in PriMap[] */
  249.     ambaIntLvlMask[level] |= 1 << i;
  250.     /*
  251.      * set index in level map: to disable this interrupt and all
  252.      * lower-priority ones, select the level one less than this
  253.      */
  254.     ambaIntLvlMap[i] = level - 1;
  255.     }
  256. }
  257.     /* do the rest of the levels */
  258.     i = 0; /* lowest-numbered interrupt bit */
  259.     for ( ; level <= AMBA_INT_NUM_LEVELS; ++level)
  260. {
  261. /* copy previous level's mask to this one's */
  262. ambaIntLvlMask[level] = ambaIntLvlMask[level - 1];
  263. /* try to find a bit that has not yet been set */
  264. for ( ; ; ++i)
  265.     {
  266.     bit = 1 << i;
  267.     if ((ambaIntLvlMask[level] & bit) == 0)
  268. {
  269. /* this bit not set so put it in the mask */
  270. ambaIntLvlMask[level] |= bit;
  271. /*
  272.  * set index in level map: to disable this interrupt and all
  273.  * lower-priority ones, select the level one less than this
  274.  */
  275. ambaIntLvlMap[i] = level - 1;
  276. break;
  277. }
  278.     }
  279. }
  280. #endif
  281.     /* install the driver routines in the architecture hooks */
  282.     sysIntLvlVecChkRtn = ambaIntLvlVecChk;
  283.     sysIntLvlVecAckRtn = ambaIntLvlVecAck;
  284.     sysIntLvlChgRtn = ambaIntLvlChg;
  285.     sysIntLvlEnableRtn = ambaIntLvlEnable;
  286.     sysIntLvlDisableRtn = ambaIntLvlDisable;
  287.     ambaIntLvlEnabled = 0;  /* all sources disabled */
  288.     ambaIntLvlChg (AMBA_INT_ALL_ENABLED); /* enable all levels */
  289.     return OK;
  290.     }
  291. /*******************************************************************************
  292. *
  293. * ambaIntLvlVecChk - check for and return any pending interrupts
  294. *
  295. * This routine interrogates the hardware to determine the highest priority
  296. * interrupt pending.  It returns the vector associated with that interrupt, and
  297. * also the interrupt priority level prior to the interrupt (not the
  298. * level of the interrupt).  The current interrupt priority level is then
  299. * raised to the level of the current interrupt so that only higher priority
  300. * interrupts will be accepted until this interrupt is finished.
  301. *
  302. * This routine must be called with CPU interrupts disabled.
  303. *
  304. * The return value ERROR indicates that no pending interrupt was found and
  305. * that the level and vector values were not returned.
  306. *
  307. * RETURNS: OK or ERROR if no interrupt is pending.
  308. */
  309. STATUS  ambaIntLvlVecChk
  310.     (
  311.     int* pLevel,  /* ptr to receive old interrupt level */
  312.     int* pVector  /* ptr to receive current interrupt vector */
  313.     )
  314.     {
  315.     int newLevel;
  316.     UINT32 isr;
  317. #ifdef AMBA_INT_PRIORITY_MAP
  318.     UINT32 *priPtr;
  319.     int bitNum;
  320. #endif
  321.     /* Read pending interrupt register and mask undefined bits */
  322.     AMBA_INT_REG_READ (AMBA_INT_CSR_PEND, isr);
  323. #ifdef AMBA_INT_CSR_MASK
  324.     isr &= AMBA_INT_CSR_MASK;
  325. #endif
  326.     /* If no interrupt is pending, return ERROR */
  327.     if (isr == 0)
  328. return ERROR;
  329. #ifdef AMBA_INT_PRIORITY_MAP
  330.     priPtr = (UINT32 *)ambaIntLvlPriMap;
  331.     if (priPtr == 0)
  332. bitNum = -1;
  333.     else
  334. {
  335. /* service interrupts according to priority specifed in map */
  336. while (bitNum = *priPtr++, bitNum != -1)
  337.     {
  338.     /* bitNum = interrupt bit from priority map */
  339.     if (isr & (1 << bitNum))
  340. {
  341. break;
  342. }
  343.     }
  344. }
  345.     /*
  346.      * if priority scan didn't find anything, look for any bit set,
  347.      * starting with the lowest-numbered bit
  348.      */
  349.     if (bitNum == -1)
  350. bitNum = ffsLsb (isr) - 1; /* ffsLsb returns numbers from 1, not 0 */
  351.     /* if no interrupt is pending, return ERROR */
  352.     if (bitNum == -1)
  353. return ERROR;
  354.     /* map the interrupting device to an interrupt level number */
  355.     newLevel = ambaIntLvlMap[bitNum];
  356. #else
  357.     /* find first bit set in ISR, starting from lowest-numbered bit */
  358.     if (newLevel = ffsLsb (isr), newLevel == 0)
  359. return ERROR;
  360.     --newLevel; /* ffsLsb returns numbers from 1, not 0 */
  361.     /* map the interrupting device to an interrupt level number */
  362.     AMBA_INT_PEND_LVL_MAP (newLevel, newLevel);
  363. #endif /* ifdef AMBA_INT_PRIORITY_MAP */
  364.     /* change to new interrupt level, returning previous level to caller */
  365.     *pLevel = ambaIntLvlChg (newLevel);
  366.     /* fetch, or compute the interrupt vector number */
  367. #ifdef AMBA_INT_PRIORITY_MAP
  368.     AMBA_INT_LVL_VEC_MAP (bitNum, *pVector);
  369. #else
  370.     AMBA_INT_LVL_VEC_MAP (newLevel, *pVector);
  371. #endif
  372.     return OK;
  373.     }
  374. /*******************************************************************************
  375. *
  376. * ambaIntLvlVecAck - acknowledge the current interrupt
  377. *
  378. * Acknowledge the current interrupt cycle.  The level and vector values are
  379. * those generated during the ambaIntLvlVecChk() routine for this interrupt
  380. * cycle.  The basic action is to reset the current interrupt and return
  381. * the interrupt level to its previous setting.  Note that the AMBA interrupt
  382. * controller does not need an acknowledge cycle.
  383. *
  384. * RETURNS: OK or ERROR if a hardware fault is detected.
  385. * ARGSUSED
  386. */
  387. STATUS  ambaIntLvlVecAck
  388.     (
  389.     int level, /* old interrupt level to be restored */
  390.     int vector /* current interrupt vector, if needed */
  391.     )
  392.     {
  393.     /* restore the previous interrupt level */
  394.     ambaIntLvlChg (level);
  395.     return OK;
  396.     }
  397. /*******************************************************************************
  398. *
  399. * ambaIntLvlChg - change the interrupt level value
  400. *
  401. * This routine implements the overall interrupt setting.  All levels
  402. * up to and including the specifed level are disabled.  All levels above
  403. * the specified level will be enabled, but only if they were specifically
  404. * enabled by the ambaIntLvlEnable() routine.
  405. *
  406. * The specific priority level AMBA_INT_NUM_LEVELS is valid and represents
  407. * all levels enabled.
  408. *
  409. * RETURNS: Previous interrupt level.
  410. */
  411. int  ambaIntLvlChg
  412.     (
  413.     int level /* new interrupt level */
  414.     )
  415.     {
  416.     int oldLevel;
  417.     oldLevel = ambaIntLvlCurrent;
  418.     if (level >= 0 &&
  419.         level <= AMBA_INT_NUM_LEVELS)
  420. {
  421. /* change current interrupt level */
  422. ambaIntLvlCurrent = level;
  423. }
  424.     /* Switch off all interrupts */
  425.     AMBA_INT_REG_WRITE (AMBA_INT_CSR_DIS, -1);
  426.     /* Activate the enabled interrupts */
  427.     AMBA_INT_REG_WRITE (AMBA_INT_CSR_ENB,
  428. (ambaIntLvlMask[ambaIntLvlCurrent] & ambaIntLvlEnabled));
  429.     return oldLevel;
  430.     }
  431. /*******************************************************************************
  432. *
  433. * ambaIntLvlEnable - enable a single interrupt level
  434. *
  435. * Enable a specific interrupt level.  The enabled level will be allowed
  436. * to generate an interrupt when the overall interrupt level is set to
  437. * enable interrupts of this priority (as configured by ambaIntLvlPriMap,
  438. * if appropriate).  Without being enabled, the interrupt is blocked
  439. * regardless of the overall interrupt level setting.
  440. *
  441. * RETURNS: OK or ERROR if the specified level cannot be enabled.
  442. */
  443. STATUS  ambaIntLvlEnable
  444.     (
  445.     int level  /* level to be enabled */
  446.     )
  447.     {
  448.     int key;
  449.     if (level < 0 ||
  450. level >= AMBA_INT_NUM_LEVELS)
  451. return ERROR;
  452.     /* set bit in enable mask */
  453.     key = intLock ();
  454.     ambaIntLvlEnabled |= (1 << level);
  455.     intUnlock (key);
  456.     ambaIntLvlChg (-1); /* reset current mask */
  457.     return OK;
  458.     }
  459. /*******************************************************************************
  460. *
  461. * ambaIntLvlDisable - disable a single interrupt level
  462. *
  463. * Disable a specific interrupt level.  The disabled level is prevented
  464. * from generating an interrupt even if the overall interrupt level is
  465. * set to enable interrupts of this priority (as configured by
  466. * ambaIntLvlPriMap, if appropriate).
  467. *
  468. * RETURNS: OK or ERROR, if the specified interrupt level cannot be disabled.
  469. */
  470. STATUS  ambaIntLvlDisable
  471.     (
  472.     int level  /* level to be disabled */
  473.     )
  474.     {
  475.     int key;
  476.     if (level < 0 ||
  477. level >= AMBA_INT_NUM_LEVELS)
  478. return ERROR;
  479.     /* clear bit in enable mask */
  480.     key = intLock ();
  481.     ambaIntLvlEnabled &= ~(1 << level);
  482.     intUnlock (key);
  483.     ambaIntLvlChg (-1); /* reset current mask */
  484.     return OK;
  485.     }