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

VxWorks

开发平台:

C/C++

  1. /* pciIntLib.c - PCI Shared Interrupt support */
  2. /* Copyright 1984-2001 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01f,11oct01,dat  merge from ae 1.1
  8. 01e,19jun00,dat  SPR 31194, new pciIntDisconnect2 routine
  9. 01d,18nov99,dat  partial fix for SPR 28467, pciIntDisconnect fault.
  10. 01c,30sep98, tm  moved PCI_INT_RTN typedef here from private header (SPR 22544)
  11. 01b,04mar98, tm  augmented pciIntConnect/Disconnect to do intConnect also
  12. 01a,20feb98, tm  derived from pciIomapLib.c of ebsa285 BSP v01m
  13. */
  14. /*
  15. DESCRIPTION
  16. This component is PCI Revision 2.1 compliant.
  17. The functions addressed here include:
  18. .IP "   -"
  19. Initialize the library.
  20. .IP "   -"
  21. Connect a shared interrupt handler.
  22. .IP "   -"
  23. Disconnect a shared interrupt handler.
  24. .IP "   -"
  25. Master shared interrupt handler.
  26. .LP
  27. Shared PCI interrupts are supported by three functions: pciInt(),
  28. pciIntConnect(), and pciIntDisconnect2().  pciIntConnect() adds the specified
  29. interrupt handler to the link list and pciIntDisconnect2() removes it from
  30. the link list.  The master interrupt handler pciInt() executes these interrupt
  31. handlers in the link list for a PCI interrupt.  Each interrupt handler must
  32. check the device dependent interrupt status bit to determine the source of
  33. the interrupt, since it simply execute all interrupt handlers in the link
  34. list.  pciInt() should be attached by intConnect() function in the BSP 
  35. initialization with its parameter. The parameter is an vector number associated 
  36. to the PCI interrupt.
  37. */
  38. #include "vxWorks.h"
  39. #include "drv/pci/pciIntLib.h"
  40. #include "dllLib.h"
  41. #include "iv.h"
  42. #include "intLib.h"
  43. #include "stdlib.h"
  44. /*
  45.  * The following defines specify, by default, the maximum number of busses,
  46.  * devices and functions allowed by the PCI 2.1 Specification.
  47.  *
  48.  * Any or all may be overriden by defining them in config.h.
  49.  */
  50. /* macros */
  51. #ifndef INT_NUM_IRQ0
  52. #   define INT_NUM_IRQ0 0
  53. #endif /* INT_NUM_IRQ0 */
  54. #ifndef PCI_INT_BASE
  55. #   define PCI_INT_BASE INT_NUM_IRQ0
  56. #endif /* INT_NUM_IRQ0 */
  57. #ifndef PCI_INT_LINES
  58. #   ifdef PCI_IRQ_LINES /* backward compatibility */
  59. # define PCI_INT_LINES PCI_IRQ_LINES
  60. #   else
  61. # define PCI_INT_LINES 32
  62. #   endif
  63. #endif
  64. /*
  65.  * This maps a system vector to a PCI irq number, in the range
  66.  * 0 to (PCI_INT_LINES - 1)
  67.  */
  68. #ifndef PCI_INT_VECTOR_TO_IRQ
  69. #define PCI_INT_VECTOR_TO_IRQ(vector)
  70. (IVEC_TO_INUM(vector) - PCI_INT_BASE)
  71. #endif /* PCI_INT_VECTOR_TO_IRQ */
  72. /*
  73.  * Provide intConnect via a macro so that an alternate interrupt binding
  74.  * mechanism can be specified
  75.  *
  76.  */
  77. #ifndef PCI_INT_HANDLER_BIND
  78. #define PCI_INT_HANDLER_BIND(vector, routine, param, pResult)
  79.     do {
  80.     IMPORT STATUS intConnect();
  81.     *pResult = intConnect ( (vector),(routine), (int)(param) );
  82.     } while (0)
  83. #endif /* PCI_INT_HANDLER_BIND */
  84. /*
  85.  * Provide an unbind macro to remove an interrupt binding.  The default 
  86.  * is basically a no-op.  This can result in a minor memory leak if there
  87.  * is a lot of pciIntConnect, pciIntDisconnect activity.
  88.  */
  89. #ifndef PCI_INT_HANDLER_UNBIND
  90. #define PCI_INT_HANDLER_UNBIND(vector, routine, param, pResult)
  91.     *pResult = OK;
  92. #endif /* PCI_INT_HANDLER_BIND */
  93. /* typedefs */
  94. typedef struct pciIntRtn
  95.     {
  96.     DL_NODE node; /* double link list */
  97.     VOIDFUNCPTR routine; /* interrupt handler */
  98.     int parameter; /* parameter of the handler */
  99.     } PCI_INT_RTN;
  100. /* globals */
  101. DL_LIST pciIntList[PCI_INT_LINES]; /* linked list of int handlers */
  102. /* locals */
  103. LOCAL STATUS pciIntLibInitStatus = NONE;
  104. /*******************************************************************************
  105. *
  106. * pciIntLibInit - initialize the pciIntLib module
  107. *
  108. * This routine initializes the linked lists used to chain together the PCI 
  109. * interrupt service routines.
  110. *
  111. * RETURNS: OK, or ERROR upon link list failures.
  112. */
  113. STATUS pciIntLibInit (void)
  114.     {
  115.     int ix;
  116.     if (pciIntLibInitStatus != NONE)
  117. return (pciIntLibInitStatus);
  118.     /* Initialize shared interrupt handler chains */
  119.     for (ix = 0; ix < NELEMENTS(pciIntList); ix++)
  120.         dllInit (&pciIntList[ix]);
  121.     return (pciIntLibInitStatus = OK);
  122.     }
  123. /*******************************************************************************
  124. *
  125. * pciInt - interrupt handler for shared PCI interrupt.
  126. *
  127. * This routine executes multiple interrupt handlers for a PCI interrupt.
  128. * Each interrupt handler must check the device dependent interrupt status bit
  129. * to determine the source of the interrupt, since it simply execute all
  130. * interrupt handlers in the link list.  
  131. *
  132. * This is not a user callable routine
  133. *
  134. * RETURNS: N/A
  135. */
  136. VOID pciInt
  137.     (
  138.     int irq /* IRQ associated to the PCI interrupt */
  139.     )
  140.     {
  141.     PCI_INT_RTN *pRtn;
  142.     for (pRtn = (PCI_INT_RTN *)DLL_FIRST (&pciIntList[irq]); pRtn != NULL;
  143.  pRtn = (PCI_INT_RTN *)DLL_NEXT (&pRtn->node))
  144. (* pRtn->routine) (pRtn->parameter);
  145.     }
  146. /*******************************************************************************
  147. *
  148. * pciIntConnect - connect the interrupt handler to the PCI interrupt.
  149. *
  150. * This routine connects an interrupt handler to a shared PCI interrupt vector.
  151. * A link list is created for each shared interrupt used in the system.  It
  152. * is created when the first interrupt handler is attached to the vector.
  153. * Subseqent calls to pciIntConnect just add their routines to the
  154. * linked list for that vector.
  155. *
  156. * RETURNS:
  157. * OK, or ERROR if the interrupt handler cannot be built.
  158. *
  159. */
  160. STATUS pciIntConnect
  161.     (
  162.     VOIDFUNCPTR *vector,        /* interrupt vector to attach to     */
  163.     VOIDFUNCPTR routine,        /* routine to be called              */
  164.     int parameter               /* parameter to be passed to routine */
  165.     )
  166.     {
  167.     int irq = PCI_INT_VECTOR_TO_IRQ (vector);
  168.     PCI_INT_RTN *pRtn;
  169.     int oldLevel;
  170.     STATUS retStatus;
  171.     if (pciIntLibInitStatus != OK)
  172. return ERROR;
  173.     if (irq < 0 || irq >= PCI_INT_LINES)
  174. return ERROR;
  175.     if ((pRtn = (PCI_INT_RTN *)malloc (sizeof (PCI_INT_RTN))) == NULL)
  176.         {
  177.         return ERROR;
  178.         }
  179.     /* If pciIntList[irq] is null, then bind the handler using intConnect */
  180.     if ( DLL_EMPTY(&pciIntList[irq]) )
  181.         {
  182.         PCI_INT_HANDLER_BIND(vector, pciInt, irq , &retStatus );
  183. if (retStatus == ERROR)
  184.     {
  185.             return ERROR;
  186.     }
  187.         }
  188.     pRtn->routine   = routine;
  189.     pRtn->parameter = parameter;
  190.     oldLevel = intLock (); /* LOCK INTERRUPT */
  191.     dllAdd (&pciIntList[irq], &pRtn->node);
  192.     intUnlock (oldLevel); /* UNLOCK INTERRUPT */
  193.     retStatus = ( (DLL_EMPTY(&pciIntList[irq])) ? ERROR : OK );
  194.     return retStatus;
  195.     }
  196. /*******************************************************************************
  197. *
  198. * pciIntDisconnect - disconnect the interrupt handler (OBSOLETE)
  199. *
  200. * This routine disconnects the interrupt handler from the PCI interrupt line.
  201. *
  202. * In a system where one driver and one ISR services multiple devices, this
  203. * routine removes all instances of the ISR because it completely ignores the
  204. * parameter argument used to install the handler.
  205. *
  206. * NOTE: Use of this routine is discouraged and will be obsoleted in the future.
  207. * New code should use the pciIntDisconnect2() routine instead.  
  208. *
  209. * RETURNS:
  210. * OK, or ERROR if the interrupt handler cannot be removed.
  211. *
  212. */
  213. STATUS pciIntDisconnect
  214.     (
  215.     VOIDFUNCPTR *vector,        /* interrupt vector to attach to     */
  216.     VOIDFUNCPTR routine         /* routine to be called              */
  217.     )
  218.     {
  219.     int irq = PCI_INT_VECTOR_TO_IRQ (vector);
  220.     PCI_INT_RTN *pRtn;
  221.     PCI_INT_RTN *pNext;
  222.     int oldLevel;
  223.     STATUS retStatus = ERROR;
  224.     if (pciIntLibInitStatus != OK)
  225. return (ERROR);
  226.     if (irq < 0 || irq >= PCI_INT_LINES)
  227. return ERROR;
  228.     for (pRtn = (PCI_INT_RTN *)DLL_FIRST (&pciIntList[irq]); pRtn != NULL;
  229.  pRtn = pNext)
  230. {
  231. pNext = (PCI_INT_RTN *)DLL_NEXT (&pRtn->node);
  232. if (pRtn->routine == routine)
  233.     {
  234.     oldLevel = intLock (); /* LOCK INTERRUPT */
  235.     dllRemove (&pciIntList[irq], &pRtn->node);
  236.     intUnlock (oldLevel); /* UNLOCK INTERRUPT */
  237.     free ((char *)pRtn);
  238.     /* If the last ISR was just removed, then do intDisconnect */
  239.             if ( DLL_EMPTY(&pciIntList[irq]) )
  240.         {
  241. PCI_INT_HANDLER_UNBIND (vector, pciInt, irq, &retStatus);
  242.         }
  243.     retStatus = OK;
  244.     }
  245. }
  246.     return (retStatus);
  247.     }
  248. /*******************************************************************************
  249. *
  250. * pciIntDisconnect2 - disconnect an interrupt handler from the PCI interrupt.
  251. *
  252. * This routine disconnects a single instance of an interrupt handler from the
  253. * PCI interrupt line.
  254. *
  255. * NOTE: This routine should be used in preference to the original
  256. * pciIntDisconnect() routine.  This routine is compatible with drivers that
  257. * are managing multiple device instances, using the same basic ISR, but with
  258. * different parameters.
  259. *
  260. * RETURNS:
  261. * OK, or ERROR if the interrupt handler cannot be removed.
  262. */
  263. STATUS pciIntDisconnect2
  264.     (
  265.     VOIDFUNCPTR *vector,        /* interrupt vector to attach to     */
  266.     VOIDFUNCPTR routine,        /* routine to be called              */
  267.     int parameter /* routine parameter      */
  268.     )
  269.     {
  270.     int irq = PCI_INT_VECTOR_TO_IRQ(vector);
  271.     PCI_INT_RTN *pRtn;
  272.     PCI_INT_RTN *pNext;
  273.     int oldLevel;
  274.     STATUS retStatus = ERROR;
  275.     if (pciIntLibInitStatus != OK)
  276. return (ERROR);
  277.     if (irq < 0 || irq >= PCI_INT_LINES)
  278. return ERROR;
  279.     for (pRtn = (PCI_INT_RTN *)DLL_FIRST (&pciIntList[irq]); pRtn != NULL;
  280.  pRtn = pNext)
  281. {
  282. pNext = (PCI_INT_RTN *)DLL_NEXT (&pRtn->node);
  283. if (pRtn->routine == routine && pRtn->parameter == parameter)
  284.     {
  285.     oldLevel = intLock (); /* LOCK INTERRUPT */
  286.     dllRemove (&pciIntList[irq], &pRtn->node);
  287.     intUnlock (oldLevel); /* UNLOCK INTERRUPT */
  288.     free ((char *)pRtn);
  289.     /* If the last ISR was just removed, then do intDisconnect */
  290.             if ( DLL_EMPTY(&pciIntList[irq]) )
  291.         {
  292. PCI_INT_HANDLER_UNBIND (vector, pciInt, irq, &retStatus);
  293.         }
  294.     retStatus = OK;
  295.     }
  296. }
  297.     return retStatus;
  298.     }