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

VxWorks

开发平台:

C/C++

  1. /* ixp425IntrCtl.c - interrupt controller driver for the ixp425 */
  2. /* Copyright 2002 Wind River Systems, Inc. */
  3. /*
  4. modification history
  5. --------------------
  6. 01a,05jun02,jb  initial version...
  7. */
  8. /*
  9. DESCRIPTION
  10. This module implements the Ixp425 interrupt controller driver.
  11. The Ixp425 interrupt controller is a simple, generic interrupt controller
  12. described in full Ixp425 Data Book [Reference[]].  The
  13. interrupt controller has status and request registers, separate enable
  14. and disable registers and supports level-sensitive interrupts. This
  15. library provides the routines to manage interrupts multiplexed by the
  16. Ixp425 interrupt controller.
  17. The Ixp425 interrupt controller has a number of registers.  Those used by
  18. this driver are described below under the symbolic names used herein.
  19. IXP425_ICMR (write): this is the "Enable Set" register.  When this register is
  20. written, each data bit that is set (1) causes the corresponding
  21. interrupt to be enabled.  Bits that are clear (0) have no effect.
  22. IXP425_ICIP (read): this is the "Interrupt Request" register.
  23. When this register is read, each data bit that is set (1) indicates an
  24. interrupt source that is both active and enabled i.e. can interrupt the
  25. processor.  
  26. The number of interrupts supported by the device i.e. the number of
  27. bits in the IXP425_ICIP register, is specified by
  28. IXP425_INT_NUM_LEVELS.
  29. We assume that config.h or <bsp>.h has defined the addresses of the
  30. controller chips registers: IXP425_ICMR,
  31. IXP425_ICIP and also the driver constant IXP425_INT_NUM_LEVELS.
  32. This driver assumes that the chip is memory-mapped and does direct
  33. memory accesses to the registers which are assumed to be 32 bits wide.
  34. If a different access method is needed, the BSP can redefine the macros
  35. IXP425_INT_REG_READ(addr,result) and IXP425_INT_REG_WRITE(addr,data).
  36. This driver assumes that interrupt vector numbers are calculated and
  37. not the result of a special cycle on the bus.  Vector numbers are
  38. generated by adding the current interrupt level number to
  39. AMBA_INT_VEC_BASE to generate a vector number which the architecture
  40. level will use to invoke the proper handling routine.  If a different
  41. mapping scheme, or a special hardware routine is needed, then the BSP
  42. should redefine the macro IXP425_INT_LVL_VEC_MAP(level,vector) to
  43. override the version defined in this file.
  44. Priorities
  45. ==========
  46. The order of interrupt level priority is undefined at the architecture
  47. level. In this driver, level 0 is highest and and indicates that all
  48. levels are disabled; level <IXP425_INT_NUM_LEVELS> is the lowest and
  49. indicates that all levels are enabled.
  50. By default, this driver implements a least-significant bit first
  51. interrupt priority scheme (this is compatible with earlier versions of
  52. this driver) which requires a definition of ambaIntLvlMask (see above).
  53. Note: The IXP425 interrupt controller provides a mechanism to reorder the 
  54. priority order of the top 8 interrupts sources. The IXP425_ICHR may 
  55. be programmed to change the default behaviour. To change the default 
  56. priority IXP425_ICHR_INIT_VALUE should be redefined.
  57. The BSP will initialize this driver in sysHwInit2(), after initializing
  58. the main interrupt library, usually intLibInit().  The initialization
  59. routine, ixp425IntDevInit() will setup the interrupt controller device,
  60. it will mask off all individual interrupt sources and then set the
  61. interrupt level to enable all interrupts.  See ixp425IntDevInit for more
  62. information.
  63. All of the functions in this library are global.  This allows them to
  64. be used by the BSP if it is necessary to create wrapper routines or to
  65. incorporate several drivers together as one.
  66. .SH INCLUDE FILES:
  67. drv/intrCtl/ixp425IntrCtl.h
  68. SEE ALSO:
  69. .I "Ixp425 Data Sheet,"
  70. */
  71. #include "vxWorks.h"
  72. #include "config.h"
  73. #include "ixp425.h"
  74. #include "ixp425IntrCtl.h"
  75. #include "intLib.h"
  76. IMPORT int ffsLsb (UINT32);
  77. /* Defines from config.h, or <bsp>.h */
  78. #if !defined (IXP425_ICIP) || !defined (IXP425_ICMR) || 
  79.     !defined (IXP425_INT_NUM_LEVELS) 
  80. #error missing IXP425 interrupt definitions
  81. #endif
  82. #define IXP425_INT_VEC_BASE (0x0)
  83. /* hardware access methods */
  84. #ifndef IXP425_REG_INT_READ
  85. #define IXP425_REG_INT_READ(reg,result) 
  86. ((result) = *(volatile UINT32 *)(reg))
  87. #endif /*IXP425_REG_INT_READ*/
  88. #ifndef IXP425_REG_INT_WRITE
  89. #define IXP425_REG_INT_WRITE(reg,data) 
  90. (*((volatile UINT32 *)(reg)) = (data))
  91. #endif /*IXP425_REG_INT_WRITE*/
  92. /* Convert level number to vector number */
  93. #ifndef IXP425_INT_LVL_VEC_MAP
  94. #define IXP425_INT_LVL_VEC_MAP(level, vector) 
  95. ((vector) = ((level) + IXP425_INT_VEC_BASE))
  96. #endif /* IXP425_INT_LVL_VEC_MAP */
  97. /* Convert pending register value, to a level number */
  98. #ifndef IXP425_INT_PEND_LVL_MAP
  99. #define IXP425_INT_PEND_LVL_MAP(pendReg, level) 
  100. ((level) = (pendReg))
  101. #endif /* IXP425_INT_PEND_LVL_MAP */
  102. /* driver constants */
  103. #define IXP425_INT_ALL_ENABLED (IXP425_INT_NUM_LEVELS)
  104. #define IXP425_INT_ALL_DISABLED 0
  105. #define IXP425_MASK_ALL_INTERRUPTS() { IXP425_REG_INT_WRITE (IXP425_ICMR,0x00000000); }
  106. /* Local data */
  107. /* Current interrupt level setting (ixp425IntLvlChg). */
  108. LOCAL UINT32 ixp425IntLvlCurrent = IXP425_INT_ALL_DISABLED; /* all levels disabled*/
  109. /*
  110.  * A mask word.  Bits are set in this word when a specific level
  111.  * is enabled. It is used to mask off individual levels that have
  112.  * not been explicitly enabled.
  113.  */
  114. LOCAL UINT32 ixp425IntLvlEnabled;
  115. /* forward declarations */
  116. STATUS ixp425IntLvlVecChk (int*, int*);
  117. STATUS ixp425IntLvlVecAck (int, int);
  118. int ixp425IntLvlChg (int);
  119. STATUS ixp425IntLvlEnable (int);
  120. STATUS ixp425IntLvlDisable (int);
  121. /*******************************************************************************
  122. *
  123. * ixp425IntDevInit - initialize the interrupt controller
  124. *
  125. * This routine will initialize the interrupt controller device, disabling all
  126. * interrupt sources.  It will also connect the device driver specific routines
  127. * into the architecture level hooks.  If the BSP needs to create a wrapper
  128. * routine around any of the arhitecture level routines, it should install the
  129. * pointer to the wrapper routine after calling this routine.
  130. *
  131. * RETURNS: OK
  132. */
  133. STATUS ixp425IntDevInit (void)
  134.     {
  135.     /* install the driver routines in the architecture hooks */
  136.     sysIntLvlVecChkRtn = ixp425IntLvlVecChk;
  137.     sysIntLvlVecAckRtn = ixp425IntLvlVecAck;
  138.     sysIntLvlChgRtn = ixp425IntLvlChg;
  139.     sysIntLvlEnableRtn = ixp425IntLvlEnable;
  140.     sysIntLvlDisableRtn = ixp425IntLvlDisable;
  141.     ixp425IntLvlEnabled = 0; /* all sources disabled */
  142.     /* 
  143.      * Set default interrupty priority.
  144.      */
  145.     IXP425_REG_INT_WRITE (IXP425_ICHR, IXP425_ICHR_INIT_VALUE);
  146.     ixp425IntLvlChg (IXP425_INT_ALL_ENABLED); /* enable all levels */
  147.     return OK;
  148.     }
  149. /*******************************************************************************
  150. *
  151. * ixp425IntLvlVecChk - check for and return any pending interrupts
  152. *
  153. * This routine interrogates the hardware to determine the highest priority
  154. * interrupt pending.  It returns the vector associated with that interrupt, and
  155. * also the interrupt priority level prior to the interrupt (not the
  156. * level of the interrupt).  The current interrupt priority level is then
  157. * raised to the level of the current interrupt so that only higher priority
  158. * interrupts will be accepted until this interrupt is finished.
  159. *
  160. * This routine must be called with CPU interrupts disabled.
  161. *
  162. * The return value ERROR indicates that no pending interrupt was found and
  163. * that the level and vector values were not returned.
  164. *
  165. * RETURNS: OK or ERROR if no interrupt is pending.
  166. */
  167. STATUS ixp425IntLvlVecChk
  168.     (
  169.     int* pLevel,  /* ptr to receive old interrupt level */
  170.     int* pVector  /* ptr to receive current interrupt vector */
  171.     )
  172.     {
  173.     int newLevel;
  174.     UINT32 isr;
  175.     /* Read pending interrupt register and mask undefined bits */
  176.     IXP425_REG_INT_READ (IXP425_ICIP, isr);
  177.     /* If no interrupt is pending, return ERROR */
  178.     if (isr == 0)
  179. return ERROR;
  180.     /* find first bit set in ISR, starting from lowest-numbered bit */
  181.     if (newLevel = ffsLsb (isr), newLevel == 0)
  182. return ERROR;
  183.     --newLevel; /* ffsLsb returns numbers from 1, not 0 */
  184.     /* map the interrupting device to an interrupt level number */
  185.     IXP425_INT_PEND_LVL_MAP (newLevel, newLevel);
  186.     /* change to new interrupt level, returning previous level to caller */
  187.     *pLevel = ixp425IntLvlChg (newLevel);
  188.     /* fetch, or compute the interrupt vector number */
  189.     IXP425_INT_LVL_VEC_MAP (newLevel, *pVector);
  190.     return OK;
  191.     }
  192. /*******************************************************************************
  193. *
  194. * ixp425IntLvlVecAck - acknowledge the current interrupt
  195. *
  196. * Acknowledge the current interrupt cycle.  The level and vector values are
  197. * those generated during the ixp425IntLvlVecChk() routine for this interrupt
  198. * cycle.  The basic action is to reset the current interrupt and return
  199. * the interrupt level to its previous setting. Note that the Ixp425 interrupt
  200. * controller does not need an acknowledge cycle.
  201. *
  202. * RETURNS: OK or ERROR if a hardware fault is detected.
  203. */
  204. STATUS ixp425IntLvlVecAck
  205.     (
  206.     int level, /* old interrupt level to be restored */
  207.     int vector /* current interrupt vector, if needed */
  208.     )
  209.     {
  210.     /* restore the previous interrupt level */
  211.     ixp425IntLvlChg (level);
  212.     return OK;
  213.     }
  214. /*******************************************************************************
  215. *
  216. * ixp425IntLvlChg - change the interrupt level value
  217. *
  218. * This routine implements the overall interrupt setting.  All levels
  219. * up to and including the specifed level are disabled. All levels above
  220. * the specified level will be enabled, but only if they were specifically
  221. * enabled by the ixp425IntLvlEnable() routine.
  222. *
  223. * The specific priority level IXP425_INT_NUM_LEVELS is valid and represents
  224. * all levels enabled.
  225. *
  226. * Passing a value of -1 will reset the current interrupt level mask.
  227. *
  228. * RETURNS: Previous interrupt level.
  229. */
  230. int  ixp425IntLvlChg
  231.     (
  232.     int level /* new interrupt level */
  233.     )
  234.     {
  235.     int oldLevel;
  236.     oldLevel = ixp425IntLvlCurrent;
  237.     if (level >= 0 &&
  238. level <= IXP425_INT_NUM_LEVELS)
  239. {
  240. /* change current interrupt level */
  241. ixp425IntLvlCurrent = level;
  242. }
  243.     /* Activate the enabled interrupts */
  244.     IXP425_REG_INT_WRITE (IXP425_ICMR,
  245. (ixp425IntLvlMask[ixp425IntLvlCurrent] & ixp425IntLvlEnabled));
  246.     return oldLevel;
  247.     }
  248. /*******************************************************************************
  249. *
  250. * ixp425IntLvlEnable - enable a single interrupt level
  251. *
  252. * Enable a specific interrupt level.  The enabled level will be allowed
  253. * to generate an interrupt when the overall interrupt level is set to
  254. * enable interrupts of this priority (as configured by ixp425IntLvlPriMap,
  255. * if appropriate).  Without being enabled, the interrupt is blocked
  256. * regardless of the overall interrupt level setting.
  257. *
  258. * RETURNS: OK or ERROR if the specified level cannot be enabled.
  259. */
  260. STATUS ixp425IntLvlEnable
  261.     (
  262.     int level  /* level to be enabled */
  263.     )
  264.     {
  265.     int key;
  266.     if (level < 0 ||
  267. level >= IXP425_INT_NUM_LEVELS)
  268. return ERROR;
  269.     /* set bit in enable mask */
  270.     key = intLock ();
  271.     ixp425IntLvlEnabled |= (1 << level);
  272.     intUnlock (key);
  273.     ixp425IntLvlChg (-1); /* reset current mask */
  274.     return OK;
  275.     }
  276. /*******************************************************************************
  277. *
  278. * ixp425IntLvlDisable - disable a single interrupt level
  279. *
  280. * Disable a specific interrupt level.  The disabled level is prevented
  281. * from generating an interrupt even if the overall interrupt level is
  282. * set to enable interrupts of this priority.
  283. *
  284. * RETURNS: OK or ERROR, if the specified interrupt level cannot be disabled.
  285. */
  286. STATUS ixp425IntLvlDisable
  287.     (
  288.     int level  /* level to be disabled */
  289.     )
  290.     {
  291.     int key;
  292.     if (level < 0 ||
  293. level >= IXP425_INT_NUM_LEVELS)
  294. return ERROR;
  295.     /* clear bit in enable mask */
  296.     key = intLock ();
  297.     ixp425IntLvlEnabled &= ~(1 << level);
  298.     intUnlock (key);
  299.     ixp425IntLvlChg (-1); /* reset current mask */
  300.     return OK;
  301.     }