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

VxWorks

开发平台:

C/C++

  1. /* ppc860Intr.c - PowerPC 800 series interrupt driver */
  2. /* Copyright 1984-2001 Wind River Systems, Inc. */
  3. /* Copyright 1997,1998 Motorola, Inc., All Rights Reserved */
  4. #include "copyright_wrs.h"
  5. /*
  6. modification history
  7. --------------------
  8. 01i,28jan02,dtr  Removing diab warnings.
  9. 01h,15sep01,dat  Removed special def of CACHE_PIPE_FLUSH
  10. 01g,28apr99,dat  Merge from 2_0_0
  11. 01o,30jan99,cn   fixed SPR #22321.
  12. 01n,24aug98,cjtc windview 2.0 event logging is now single step. Timestamp no
  13.                  longer stored by intEnt. Avoids out-of-sequence timestamps in
  14.                  event log (SPR 21868)
  15. 0lm,12aug98,gls  corrected assignment of evtIntNum
  16. 01l,04aug98,gls  fixed SPR #21239, kernel locks on boot when instrumented
  17. 01k,16apr98,pr   added WindView 20 instrumentation.
  18. 01j,30mar98,map  initialize _func_int{Enable,Disable}Rtn [SPR# 20447]
  19. 01i,26mar98,map  added ppc860IntEnable, ppc860IntDisable, removed duplicate
  20.                  #ifdef'd code, reworked ppc860IntrInit(). [SPR# 20447]
  21. 01h,11nov97,map  redo clearing CISR bits [SPR# 8781], and default SCC
  22.                  interrupt priority
  23. 01g,23jun97,map  added default SCC interrupt priority [SPR# 8692]
  24. 01f,19jun97,map  added IV_SCC[34] definitions [SPR# 8450]
  25. 01e,17jun97,map  fixed clearing CISR bits [SPR# 8781]
  26. 01d,06mar97,tpr  fixed properly SPR #8042.
  27. 01c,21feb97,tpr  fixed interrupt bit clearing in CISR (SPR #8042).
  28. 01b,18sep96,pr   added WindView instrumentation.
  29. 01a,17feb96,tpr  written.
  30. */
  31. /*
  32. DESCRIPTION
  33. The PowerPC 800 CPU series is divided in three units: PowerPC core, System
  34. Interface Unit (SIU) and Communication Processor Unit (CPM). The PowerPC
  35. core accepts only one external interrupt exception (vector 0x500). The SIU
  36. provides an interrupt controller which provides 32 levels but only 16 are
  37. used. The Interrupt controller is connected to the PowerPC core external 
  38. interrupt. The CPM unit also provides an interrupt controller which can
  39. be connected to one of the SIU interrupt controler entries. This library
  40. provides the routines to manage these interrupt controllers
  41. ppc860IntrInit() connects the default demultiplexers, ppc860IntrDeMux() and
  42. ppc860CpmIntrDeMux(), to the external interrupt vector and initializes a table
  43. containing a function pointer and an associated parameter for each interrupt
  44. source. ppc860IntrInit() is called by sysHwInit() from sysLib.c.
  45. The default demultimplexer, ppc860IntrDeMux() detects which peripheral or 
  46. controller has raised an interrupt and calls the associated routine with its 
  47. parameter. If the interrupt comes from the CPM interrupt contoller, the
  48. ppc860CpmIntDeMux() function is called. As ppc860IntrDeMux(), this function
  49. detects which peripheral or controller has raised an interrupt and calls the
  50. associated routine with its parameter.
  51. INCLUDE FILES: drv/intrCtl/ppc860Intr.h, drv/multi/ppc860Siu.h,
  52. drv/multi/ppc860Cpm.h
  53. */
  54. /* includes */
  55. #include "intLib.h"
  56. #include "iv.h"
  57. #include "drv/intrCtl/ppc860Intr.h"
  58. #include "drv/multi/ppc860Siu.h"
  59. #include "drv/multi/ppc860Cpm.h"
  60. /* default SCC relative interrupt priority */
  61. #define CICR_SCCP_DEF (CICR_SCCDP_SCC4 | CICR_SCCCP_SCC3 | 
  62.                          CICR_SCCBP_SCC2 | CICR_SCCAP_SCC1 )
  63. #ifdef  INCLUDE_WINDVIEW
  64. #include "private/funcBindP.h"
  65. #include "private/eventP.h"
  66. LOCAL  int cpmIntNum;
  67. LOCAL  int cpmVecNum;
  68. #endif /* INCLUDE_WINDVIEW */
  69. /* local */
  70. LOCAL INTR_HANDLER intrVecTable[NUM_VEC_MAX]; /*  Intr vector table */
  71. /* forward declarations */
  72. LOCAL void ppc860IntrDeMux (void);
  73. LOCAL void ppc860CpmIntrDeMux (int);
  74. LOCAL STATUS ppc860IntConnect (VOIDFUNCPTR *, VOIDFUNCPTR, int);
  75. LOCAL int ppc860IntEnable (int);
  76. LOCAL int ppc860IntDisable (int);
  77. /*******************************************************************************
  78. *
  79. * ppc860IntrInit - initialize the interrupt manager for the PowerPC 800 series
  80. *
  81. * This routine connects the default demultiplexers, ppc860IntrDeMux() and 
  82. * ppc860CpmIntrDeMux, to the external interrupt vector and associates all 
  83. * interrupt sources with the default interrupt handler.  This routine is
  84. * called by sysHwInit() in sysLib.c.
  85. *
  86. * NOTE: All interrupt from the SIU and CPM unit are enabled, CICR is setup so
  87. * that SCC1 has the highest relative interrupt priority, through SCC4 with the
  88. * lowest.
  89. *
  90. * RETURN : OK or ERROR if the SUI interrupt level to connect the CPM 
  91. * interrupt contoller is wrong.
  92. */
  93. STATUS ppc860IntrInit 
  94.     (
  95.     VOIDFUNCPTR * cpmIntrVec /* Intr level of the CPM Intr ctrl */
  96.     )
  97.     {
  98.     VOIDFUNCPTR defaultVec;      /* INTR3 default vector */
  99.     UINT32 regBase; /* device register base address */
  100.     UINT32 cicrIntLevel; /* CICR interupt level */
  101.     UINT32 simaskIntLevel;
  102.     int vector;
  103.     /* Get the default vector connected to the External Interrupt (0x500) */
  104.     defaultVec = (VOIDFUNCPTR) excVecGet ((FUNCPTR *) _EXC_OFF_INTR);
  105.     /* Connect the interrupt demultiplexer to External Interrupt (0x500) */
  106.     excIntConnect ((VOIDFUNCPTR *) _EXC_OFF_INTR, ppc860IntrDeMux);
  107.     /* Install `system' intConnect routine */
  108.     if (_func_intConnectRtn == NULL)
  109.         _func_intConnectRtn = ppc860IntConnect;
  110.     if (_func_intEnableRtn == NULL)
  111.         _func_intEnableRtn = ppc860IntEnable;
  112.     if (_func_intDisableRtn == NULL)
  113.         _func_intDisableRtn = ppc860IntDisable;
  114.     /* Set all vectors to default handler */
  115.     for (vector = 0; vector < NUM_VEC_MAX; vector++)
  116. intConnect (INUM_TO_IVEC(vector), defaultVec, 0);
  117.     /* Get the CPM interrupt level */
  118.     switch (IVEC_TO_INUM(cpmIntrVec))
  119. {
  120. case IVEC_TO_INUM(IV_LEVEL0): 
  121.     cicrIntLevel = CICR_IRL_LVL0;
  122.     simaskIntLevel = SIMASK_LVM0;
  123.     break; 
  124. case IVEC_TO_INUM(IV_LEVEL1):
  125.     cicrIntLevel = CICR_IRL_LVL1;
  126.     simaskIntLevel = SIMASK_LVM1;
  127.     break; 
  128. case IVEC_TO_INUM(IV_LEVEL2):
  129.     cicrIntLevel = CICR_IRL_LVL2;
  130.     simaskIntLevel = SIMASK_LVM2;
  131.     break; 
  132. case IVEC_TO_INUM(IV_LEVEL3):
  133.     cicrIntLevel = CICR_IRL_LVL3;
  134.     simaskIntLevel = SIMASK_LVM3;
  135.     break; 
  136. case IVEC_TO_INUM(IV_LEVEL4):
  137.     cicrIntLevel = CICR_IRL_LVL4;
  138.     simaskIntLevel = SIMASK_LVM4;
  139.     break; 
  140. case IVEC_TO_INUM(IV_LEVEL5):
  141.     cicrIntLevel = CICR_IRL_LVL5;
  142.     simaskIntLevel = SIMASK_LVM5;
  143.     break; 
  144. case IVEC_TO_INUM(IV_LEVEL6):
  145.     cicrIntLevel = CICR_IRL_LVL6;
  146.     simaskIntLevel = SIMASK_LVM6;
  147.     break; 
  148. case IVEC_TO_INUM(IV_LEVEL7):
  149.     cicrIntLevel = CICR_IRL_LVL7;
  150.     simaskIntLevel = SIMASK_LVM7;
  151.     break; 
  152. default:
  153.     return (ERROR);
  154. }
  155.     /*
  156.      * Connect the CPM interrupt demultiplexer at the level specified by
  157.      * `cpmIntLevel'
  158.      */
  159. #ifdef  INCLUDE_WINDVIEW
  160.     cpmVecNum = IVEC_TO_INUM(cpmIntrVec);
  161. #endif /* INCLUDE_WINDVIEW */
  162.     intConnect (cpmIntrVec, ppc860CpmIntrDeMux, simaskIntLevel);
  163.     /* Get the register base address */
  164.     regBase = vxImmrGet();
  165.     /* 
  166.      * Set the request interrupt level from the CPM and enable CPM interrupt
  167.      * generation.
  168.      */
  169.     * CICR(regBase) = (CICR_SCCP_DEF | cicrIntLevel | CICR_IEN | CICR_HP_MSK);
  170.      
  171.     /* Enable required CPM interrupt */
  172.     * SIMASK(regBase) = simaskIntLevel;
  173.     return (OK);
  174.  
  175.     }
  176. /*******************************************************************************
  177. *
  178. * ppc860IntConnect - connect a routine to an interrupt 
  179. *
  180. * This routine connects any C or assembly routine to one of the multiple 
  181. * sources of interrupts.
  182. *
  183. * The connected routine can be any normal C code, except that it must not 
  184. * invoke certain operating system functions that may block or perform I/O
  185. * operations.
  186. *
  187. * <vector> types are defined in h/drv/intrClt/ppc860Intr.h.
  188. *
  189. * RETURNS: OK, or ERROR if <vector> is unknown.
  190. *
  191. * SEE ALSO: ppc860Intr.h
  192. */
  193. LOCAL STATUS ppc860IntConnect
  194.     (
  195.     VOIDFUNCPTR * vector, /* interrupt vector to attach to */
  196.     VOIDFUNCPTR routine, /* routine to be called */
  197.     int  parameter /* parameter to be passed to routine */
  198.     )
  199.     {
  200.     /* test the vector */
  201.     if (IVEC_TO_INUM(vector) >= NUM_VEC_MAX)
  202. return (ERROR);
  203.     intrVecTable[IVEC_TO_INUM(vector)].vec = routine;
  204.     intrVecTable[IVEC_TO_INUM(vector)].arg = parameter;
  205.     return (OK);
  206.     }
  207. /*******************************************************************************
  208. *
  209. * ppc860IntrDeMux - SIU interrupt demultiplexer 
  210. *
  211. * This routine must be bound to external interrupt exception (vector 0x500). 
  212. * It is used to call the appropriate handler with its argument when an
  213. * interrupt occurs. 
  214. *
  215. * The interrupts are prioritized in the following order:
  216. *
  217. * NOTE: when this function is called the interrupts are still locked. It's
  218. * this function responsability to unlock the interrupt.
  219. *
  220. * RETURNS: N/A
  221. */
  222. LOCAL void ppc860IntrDeMux (void)
  223.     {
  224. #ifdef INCLUDE_WINDVIEW
  225.     UINT32  evtIntNum; /* windview interrupt vector */
  226. #endif /* INCLUDE_WINDVIEW */
  227.     UINT8  intVec; /* interrupt vector */
  228.     UINT32 regBase; /* register Base Address */
  229.     UINT32 intMask; /* current interrupt mask */
  230.     regBase = vxImmrGet();
  231.     /* read the interrupt vector register */
  232.     intVec = (* SIVEC(regBase)) >> 26;
  233. #ifdef  INCLUDE_WINDVIEW
  234.     /* 
  235.      * if it is a cpm interrupt we need to know the corresponding cpm
  236.      * level, that we should get from the CPM demultiplexer. But we
  237.      * need the value here and the value can be read only once. We 
  238.      * save the value here so that once the CPM demultiplexer is called,
  239.      * it will read the value from the global variable cpmIntNum.
  240.      * 
  241.      * Since we do not know the CPM level a priori, we have to leave
  242.      * enough space for the cpm interrupts in the windview list.
  243.      * Therefore, any interrupt number bigger than the CPM level will
  244.      * be increased of 15 so to leave those spots to the corresponding
  245.      * CPM interrupts.
  246.      */
  247.     if (intVec == cpmVecNum)
  248. {
  249. /* acknowledge the interrupt */
  250. *CIVR(regBase) = CIVR_IACK;    
  251. CACHE_PIPE_FLUSH ();
  252. cpmIntNum = * CIVR(regBase) >> 11; 
  253. evtIntNum = cpmIntNum + 32;
  254. }
  255.     else
  256. evtIntNum = intVec;
  257.     WV_EVT_INT_ENT(evtIntNum)
  258. #endif /* INCLUDE_WINDVIEW */
  259.     /* save the current interrupt mask */ 
  260.     intMask = * SIMASK(regBase);
  261.     /* lock all levels inferior to the interrupt detected */
  262.     * SIMASK(regBase) &= (0xffffffff << (32 - intVec));
  263.     /* unlock the interrupt */
  264.     intUnlock (_PPC_MSR_EE);
  265.     /* call the Interrupt Handler */
  266.     intrVecTable[intVec].vec (intrVecTable[intVec].arg);
  267.     /* restore the interrupt mask */
  268.     * SIMASK(regBase) = intMask;
  269.     return;
  270.     }
  271. /*******************************************************************************
  272. *
  273. * ppc860CpmIntrDeMux - CPM interrupt demultiplexer 
  274. *
  275. * This routine must be bound to external interrupt exception (vector 0x500). 
  276. * It is used to call the appropriate handler with its argument when an
  277. * interrupt occurs. 
  278. *
  279. * The interrupts are prioritized in the following order:
  280. *
  281. * RETURNS: N/A
  282. */
  283. LOCAL void ppc860CpmIntrDeMux 
  284.     (
  285.     int simaskLevel
  286.     )
  287.     {
  288.     int intNum; /* interrupt number */
  289.     UINT32 regBase; /* register Base Address */
  290.     UINT32 intOldMask; /* interrupt mask before the interrupt*/
  291.     /* get the device register base address */
  292.     regBase = vxImmrGet();
  293.     /* get the interrupt vector */
  294. #ifdef  INCLUDE_WINDVIEW
  295.     intNum = cpmIntNum; 
  296. #else
  297.     /* acknowledge the interrupt */
  298.     * CIVR(regBase) = CIVR_IACK;
  299.     intNum = * CIVR(regBase) >> 11; 
  300. #endif /* INCLUDE_WINDVIEW */
  301.     /* save the interrupt mask before the interrupt */
  302.     intOldMask = * CIMR(regBase);
  303.     /* lock all levels inferior to the interrupt detected */
  304.     * CIMR(regBase) &= (0xffffffff << (intNum + 1));
  305.     /* enable the CPM interrupt in the SIU controller */
  306.     * SIMASK(regBase) |= simaskLevel;
  307.     /* call the Interrupt Handler */
  308.     intrVecTable[intNum + 32].vec (intrVecTable[intNum + 32].arg);
  309.     /* clear the bit in the CISR */
  310.     * CISR(regBase) = (1 << intNum);
  311.     /* restore the interrupt mask */
  312.     
  313.     * CIMR(regBase) = intOldMask;
  314.     }
  315. /*******************************************************************************
  316. *
  317. * ppc860IntEnable - enable one of the Level or IRQ interrupts into the SIU
  318. *
  319. * This routine will unmask the bit in the SIMASK register corresponding to
  320. * the requested interrupt level.  The interrupt level must be in the range
  321. * of 0 - 31.
  322. * RETURNS: 0, always.
  323. */
  324. LOCAL int ppc860IntEnable
  325.     (
  326.     int intNum /* interrupt level to enable (0 - 31) */
  327.     )
  328.     {
  329.     UINT32 regBase;
  330.     regBase = vxImmrGet();
  331.     if ((intNum >= 0) && (intNum < 32))
  332. * SIMASK(regBase) |= (1 << (31 - intNum));
  333.     return 0;
  334.     }
  335. /*******************************************************************************
  336. *
  337. * ppc860IntDisable - Disable one of the Level or IRQ interrupts into the SIU
  338. *
  339. * This routine will mask the bit in the SIMASK register corresponding to
  340. * the requested interrupt level.  The interrupt level must be in the range
  341. * of 0 - 31.
  342. * RETURNS: 0, always.
  343. */
  344. LOCAL int ppc860IntDisable
  345.     (
  346.     int intNum          /* interrupt level to disable (0 - 31) */
  347.     )
  348.     {
  349.     UINT32 regBase;
  350.     
  351.     regBase = vxImmrGet();
  352.     if ((intNum >= 0) && (intNum < 32))
  353.         * SIMASK(regBase) &= ~(1 << (31 - intNum));
  354.     return 0;
  355.     }